Skip to main content

SealedAuction

The core contract. Every auction record, bid slot, reserve vault, and state transition.

Source: contracts/src/SealedAuction.sol Aeneid address: 0xb41B87f2E58E3f6139d6B6D2323C7AdFd47FC9ee

Storage

nextAuctionId

uint256 public nextAuctionId;

The id of the next auction to be created. First auction has id 1. Enumerate all auctions: for (i = 1; i < nextAuctionId; i++).

auctions(uint256)

mapping(uint256 => Auction) public auctions;

struct Auction {
address seller;
address ipId;
uint256 licenseTermsId;
uint32 reserveUuid; // CDR vault uuid for the sealed reserve
bool reserveHasCiphertext; // true once seller calls submitEncryptedReserve
uint64 deadline;
uint8 state; // 0=Open, 1=Triggered, 2=Settled, 3=ExpiredNoWinner, 4=ExpiredEmpty
uint16 bidCount;
}

Returns the auction record as a tuple in field-declaration order.

There is no plaintext reservePrice field. The reserve is sealed into a CDR vault (reserveUuid) and only revealed at settlement via a signed ReserveReveal struct.

bids(uint256, uint256)

mapping(uint256 => mapping(uint256 => Bid)) public bids;

struct Bid {
address bidder;
uint256 deposit;
uint32 ciphertextUuid;
bool hasCiphertext;
uint64 blockNumber;
uint64 txIndex;
}

bids[auctionId][bidIndex] returns one bid's escrow record. bidIndex ranges from 0 to auctions[auctionId].bidCount - 1.

isTriggered(uint256)

function isTriggered(uint256 auctionId) external view returns (bool);

Returns true if the auction's state is Triggered. Called by AuctionRevealCondition.checkReadCondition as the second gate before CDR validators publish decryption shares.

Structs used at settle

BidReveal

struct BidReveal {
uint256 bidIndex;
uint256 amount;
bytes32 nonce;
bytes signature;
}

One decrypted bid, supplied to settle. The contract re-verifies the signature on-chain; bids that fail verification are silently skipped.

ReserveReveal

struct ReserveReveal {
uint256 amount;
bytes32 nonce;
bytes signature;
}

The decrypted sealed reserve, supplied to settle. The contract recovers the signer using the same BidPayload digest (signer must equal auction.seller).

Functions

createAuction

function createAuction(
address ipId,
uint256 licenseTermsId,
uint64 deadline
) external returns (uint256 auctionId);

Lists a new sealed-bid auction. Callable by anyone; the caller becomes auction.seller.

Allocates the seller-side CDR reserve vault (reserveUuid) and registers it on AuctionRevealCondition with the same two-gate condition that governs bid vaults (deadline elapsed AND auction triggered).

The reserve is sealed: this call creates the vault but does not write ciphertext. The seller calls submitEncryptedReserve separately to seal their price floor. If the seller never submits a reserve, the floor defaults to 0 at settlement (any valid bid can win).

Reverts:

Emits: AuctionCreated

submitEncryptedReserve

function submitEncryptedReserve(
uint256 auctionId,
bytes calldata ciphertext
) external;

Seller writes the TDH2-encrypted reserve payload into the reserve CDR vault. Seller-only; Open state only; before deadline; one write per auction.

Uses the same 149-byte BidPayload format, with bidder = seller address and the inner digest keccak256(abi.encode(auctionId, seller, amount, nonce)).

Reverts:

Emits: EncryptedReserveSubmitted

allocateBidSlot

function allocateBidSlot(
uint256 auctionId,
uint256 deposit
) external returns (uint32 uuid);

First step of the two-call bid flow. Pulls deposit WIP from the caller (transferFrom — caller must have approved the contract). Asks the CDR network for a fresh ciphertextUuid bound to this auction's two-gate read condition. Registers the deadline with AuctionRevealCondition.

Reverts:

Emits: BidSlotAllocated

submitEncryptedBid

function submitEncryptedBid(
uint256 auctionId,
uint32 uuid,
bytes calldata ciphertext
) external;

Second step of the two-call bid flow. Writes the TDH2-encrypted 149-byte BidPayload to the vault identified by uuid. Caller must be the address that called allocateBidSlot for this uuid.

Reverts:

Emits: EncryptedBidSubmitted

trigger

function trigger(uint256 auctionId) external;

Flips the auction from Open to Triggered. Permissionless; anyone can call. This is the second gate that AuctionRevealCondition checks before CDR validators publish decryption shares. Calling trigger is therefore a prerequisite for settlement.

Reverts:

Emits: AuctionTriggered

settle

function settle(
uint256 auctionId,
BidReveal[] calldata reveals,
ReserveReveal calldata reserveReveal
) external;

Settles the auction with the decrypted bid and reserve payloads. Permissionless; in practice only an orchestrator with access to the CDR-decrypted plaintexts can construct a valid call.

The contract performs the following in a single transaction (revert-all; partial settlement is impossible):

  1. Resolves the sealed reserve floor:
    • If reserveHasCiphertext == true, calls BidPayload.recoverSigner on reserveReveal; reverts InvalidReserveReveal if recovered address does not equal auction.seller. Uses the revealed amount as the floor.
    • If no reserve was sealed, floor defaults to 0.
  2. For each BidReveal in reveals:
    • Looks up bids[auctionId][reveal.bidIndex].
    • Calls BidPayload.recoverSigner; skips if recovered address does not equal slot.bidder.
    • Skips if reveal.amount > slot.deposit.
    • Skips if slot.hasCiphertext == false.
  3. Picks the highest valid bid at or above the reserve floor. Ties broken by earliest blockNumber.
  4. Winner path: mints a Story PIL license token to the winner via LicensingModule.mintLicenseTokens; transfers winningAmount WIP to seller; refunds winner's excess deposit; refunds every losing deposit.
  5. No-winner path: refunds all deposits; transitions to ExpiredNoWinner.

Reverts:

Emits: AuctionSettled on the winner path; AuctionExpiredNoWinner if no valid bid cleared the reserve.

State enum

enum State { Open, Triggered, Settled, ExpiredNoWinner, ExpiredEmpty }
ValueUint8Set by
Open0createAuction
Triggered1trigger
Settled2settle (winner found)
ExpiredNoWinner3settle (no bid cleared reserve)
ExpiredEmpty4Reserved state; not currently set by any function

Function reference table

FunctionCallerState required
nextAuctionId (view)anyoneany
auctions(id) (view)anyoneany
bids(id, idx) (view)anyoneany
isTriggered(id) (view)anyone (AuctionRevealCondition)any
createAuction(...)anyone (becomes seller)n/a
submitEncryptedReserve(...)seller onlyOpen, before deadline
allocateBidSlot(...)anyone (becomes bidder)Open, before deadline
submitEncryptedBid(...)slot allocator onlyOpen, before deadline
trigger(id)anyoneOpen, at or after deadline
settle(id, reveals, reserveReveal)anyone (in practice: orchestrator)Triggered

ABI

The full ABI ships with the SDK:

import {sealedAuctionAbi} from '@sealedip/sdk/abi/sealed-auction'

Or find it on Storyscan under the Contract tab.