State machine
The SealedAuction contract stores each auction's state as a uint8 enum
field. The values are:
| Numeric | Name | UI label |
|---|---|---|
| 0 | Open | Open or Closing if past deadline |
| 1 | Triggered | Settling |
| 2 | Settled | Settled |
| 3 | ExpiredNoWinner | Ended |
| 4 | ExpiredEmpty | Ended |
When reading auctions off-chain via auctions(uint256), the state is the
7th field in the returned tuple (index 6). The full tuple is:
(address seller, address ipId, uint256 licenseTermsId, uint32 reserveUuid, bool reserveHasCiphertext, uint64 deadline, uint8 state, uint16 bidCount).
See SealedAuction.auctions.
Distinguishing "open with countdown" from "open past deadline"
The contract only stores Open for both sub-states. The UI distinguishes them
using the deadline:
const isOpen = state === 'Open' && Number(deadline) > now
const isClosing = state === 'Open' && Number(deadline) <= now
The Closing pill on the marketplace UI is not a separate on-chain state.
It is a derived label that means "the contract is Open but the deadline has
passed and anyone can trigger".
Allowed transitions
Terminal states (Settled, ExpiredNoWinner, ExpiredEmpty) are immutable.
Once an auction reaches a terminal state, no further functions on it succeed.
Permissions per state
| State | createAuction | submitEncryptedReserve | allocateBidSlot | submitEncryptedBid | trigger | settle |
|---|---|---|---|---|---|---|
| (does not exist) | seller ✓ | — | — | — | — | — |
Open (countdown) | — | seller ✓ | anyone ✓ | slot owner ✓ | — | — |
Open (past deadline) | — | reverts | reverts | reverts | anyone ✓ | — |
Triggered | — | reverts | reverts | reverts | reverts | anyone ✓ |
Settled | — | reverts | reverts | reverts | reverts | reverts |
ExpiredNoWinner | — | reverts | reverts | reverts | reverts | reverts |
ExpiredEmpty | — | reverts | reverts | reverts | reverts | reverts |
createAuction always allocates a new auctionId, so it is not gated by an
existing auction's state.
settle() is technically permissionless (no caller check), but the caller
must supply correctly-decrypted reveals. In practice only the CDR orchestrator
has the means to produce reveals at scale.
trigger() requires BOTH gates
trigger() has no caller check beyond the deadline gate. Any address can pay
gas to call it. This is intentional: if the SealedIP-operated orchestrator
goes down, anyone can step in.
Calling trigger() is required for a second reason beyond convenience: it
sets the second gate on AuctionRevealCondition. Validators will not publish
decryption shares until AuctionRevealCondition.checkReadCondition returns
true, which requires:
block.timestamp >= deadline, ANDSealedAuction.isTriggered(auctionId) == true
Neither the passage of time alone nor an explicit trigger call alone is sufficient. Both must hold. This prevents CDR validators from being front-run by a premature trigger.
Per-state behavior summary
Open (countdown running)
The seller can:
- Seal the reserve (
submitEncryptedReserve, once)
Bidders can:
- Allocate new slots (
allocateBidSlot) - Submit ciphertext for slots they own (
submitEncryptedBid)
Nobody can:
- Trigger the auction (deadline not reached)
- Settle the auction (state is not
Triggered)
Open (past deadline)
Nobody can:
- Allocate new slots (
BiddingClosed) - Submit ciphertext (
BiddingClosed) - Submit reserve ciphertext (
BiddingClosed)
Anyone can:
- Trigger the auction (
trigger()succeeds; state goes toTriggeredorExpiredEmpty)
Triggered
Nobody can:
- Allocate slots, submit ciphertext, or re-trigger
Anyone with valid reveals can:
- Call
settle()(state goes toSettledorExpiredNoWinner)
Validators are off-chain, publishing shares to the CDR contract for all vaults registered in this auction (bid vaults plus the reserve vault).
Settled / ExpiredNoWinner / ExpiredEmpty
Nothing further can be done on the auction. It is history.
The PIL license token (in Settled) lives on. Its provenance is fixed and
points to this auction's auctionId and licenseTermsId.
Detecting state changes
For real-time apps, watch these events:
| Event | Marks transition into |
|---|---|
AuctionCreated | Open |
EncryptedReserveSubmitted | (no transition; indicates reserve sealed) |
BidSlotAllocated | (no transition; indicates bidder activity) |
EncryptedBidSubmitted | (no transition; indicates bid sealed) |
AuctionTriggered | Triggered |
AuctionSettled | Settled |
AuctionExpiredNoWinner | ExpiredNoWinner |
AuctionExpiredEmpty | ExpiredEmpty |
See Events reference for full signatures and argument ordering.