Bid Validation
Every path a bid takes through UmiaValidationHook, from configuration to each revert it can hit
The CCA calls UmiaValidationHook.validate on every bid, and validate is the only way a credential reaches the hook. These charts follow the contract branch by branch, so every revert a bid can hit appears once. Nodes that start with Revert name the error; rounded nodes let the bid through. For the hookData formats and the owner functions in detail, see Validation Hook.
The CCA wraps any revert from the hook as ValidationHookCallFailed(reason), so a failed bid carries the hook's error inside.
Setup and configuration
| Owner call | Effect |
|---|---|
setCCA(cca) | Pairs once and caches the CCA schedule. Later calls are no-ops. |
enableStep / enableStepBatch | Turns enforcement on and sets the step's providers, which are its proof gate. An empty list means no proof gate. |
disableStep / disableStepBatch | Turns enforcement off and clears the step's verify-every-bid flag. |
setStepProviders / setStepProvidersBatch | Replaces a step's providers. |
addStepProviders / removeStepProviders | Adds or removes single providers. Removing one that is absent reverts ProviderNotFound. |
enableStepPermit / disableStepPermit | Turns a step's permit gate on or off. |
setSigner(signer) | Sets the permit signer. address(0) disables every permit. |
setVerifyEveryBid(step, on) | On only before the step starts, with the step enabled and gated. Off at any time. |
setStepMaxBidAmount(step, amount) | Per-wallet zk cap at a step. 0 means no cap. |
setZkGlobalMaxBidAmount(amount) | Auction-wide zk cap. 0 means no cap. Settable before pairing. |
setMaxBidPrice(q96) | Bid price cap, which must sit on the CCA tick grid. 0 means no cap. |
unregister / unregisterBatch | Clears standing registration (see below). |
setIdentityProvider(providerHash, identityProvider) | Permanently assigns a claim hash to its identity namespace. |
clearIdentity(identityHash) | Frees an identity slot shared across recipes in that namespace. |
multicall(calls) | Runs owner calls atomically. Leading with requireStepNotStarted(step) makes a late-mined batch revert. |
Everything except setSigner, setZkGlobalMaxBidAmount, setCCA, setIdentityProvider, clearIdentity and multicall reverts NoCCA before pairing. Each proof hash needs an assigned namespace before a proof for that hash can pass. A namespace must match ^[a-z][a-z0-9_]{0,63}$ or setIdentityProvider reverts InvalidIdentityProvider; assigning the same namespace again is a no-op, and changing it reverts IdentityProviderImmutable.
Validating a bid
On mixed steps, an explicit permit is checked before standing zkTLS registration. A valid permit consumes its nonce and skips zkTLS counters; an invalid permit reverts without falling back to registration. Empty hook data still uses standing registration and its zkTLS caps.
These charts describe newly deployed hooks. Existing immutable hook/auction pairs retain their original behavior, including registration taking precedence over permits on older ordinary mixed steps. The ABI and interface IDs do not identify this fix; confirm the deployed implementation before relying on it. The Hub/API lets each bid select a route; switching after registration requires a fixed hook, not only an app update.
Permit path
Proof path
zk caps
Proof bids and bids covered by standing registration count toward both caps. Permit bids never do: the API enforces permit caps when it signs.
Proof checks
A proof is either a registration proof, sent inline on an ordinary step, or a bid proof, sent inline on a step that verifies every bid. The signed context message tells them apart, so neither can stand in for the other. An identity is the assigned namespace plus the signed extractedParameters JSON, so recipes in the same namespace share one wallet lock.
The hook calls the verifier's read-only validateProof to authenticate the current epoch, claim hash and witness signatures, then receive parsed context fields. The verifier uses Solady JSON traversal with guards for encoding and unique top-level security keys. Duplicate fields (including nested decoys) revert Duplicate context key; nested-only fields revert Nested context key. Escaped JSON keys revert Escaped context key. Identity hashing retains the exact signed object bytes, including whitespace and escapes. Rotation invalidates pending proofs from earlier epochs, while standing registrations continue to apply on ordinary steps.
The parser requires contextAddress to contain exactly 40 hexadecimal digits and providerHash exactly 64, each optionally prefixed by 0x or 0X, and returns them as an address and a bytes32. Invalid characters, shortened values and extra digits revert instead of being coerced or truncated. After authentication, the hook applies auction policy and updates its own state. Bid timestamps are checked before the verifier call; bid replay is checked after context and identity policy. Any failure reverts the whole bid, including identity and proof-consumption writes.
Registration and unregistering
Where credentials come from
On mixed early-bid steps, the user chooses Pass/server permit or zkTLS in the Hub. The user can switch routes between bids, regardless of which was used first. With the updated validation hook, each bid spends only its selected allowance; exhausting a quota does not switch routes automatically. The permit route supplies a fresh amount-bound permit. The zkTLS route supplies a stored registration proof on its first ordinary bid and empty hook data once registered, or a fresh amount/step/nonce-bound proof for every bid when the step enables verify-every-bid.
Views
| View | Answer |
|---|---|
authorizesWithoutCredential(step, user) | False out of range. True on a disabled step. False on a step that verifies every bid. Otherwise isVerified(step, user) when the step has a proof gate, else true only when it has no permit gate. |
isVerified(step, user) | Whether the user is registered at step or an earlier step. |
verifiesEveryBid(step) | The step's verify-every-bid flag. |
isStepEnabled(step) / isStepPermitEnabled(step) / getStepProviders(step) | The step's gates. |
expirationBlock() | End block of the highest gated step, meaning enabled with providers, a permit gate or verify every bid. 0 when no step is gated. |
getSteps() / cca() / signer() / maxBidPrice() | The cached schedule and settings. |
stepMaxBidAmount(step) / zkBidTotal(wallet, step) / zkGlobalMaxBidAmount() / zkGlobalBidTotal() | zk caps and running totals. |
isPermitNonceUsed(nonce) / identityOwner(identityHash) / identityProvider(providerHash) | Burned permit nonces, identity slots and immutable hash-to-namespace assignments. |
requireStepNotStarted(step) | Reverts StepAlreadyStarted once the step has started. |
supportsInterface(id) | CCA validation-hook introspection, IUmiaValidationHook, IMaxBidPriceValidationHook, IGatedValidationHook and IVerifyEveryBidHook. |