The bids stay sealed. The price does not.
Highest bidder wins and pays the second-highest bid. The price is the only number ever published — not the losing bids, and not the winner's own.
What this guarantees
What is assured: the winner and the clearing price are established by hash-preimage proofs verified on-chain over a bid set the contract froze before any bid could be opened, so the auctioneer cannot misplace any bid it settles, or misreport the price those bids set, without failing a proof. What is not: after sealing, the auctioneer learns every bid amount — it can never publish them or spend anyone's funds, but it knows them, and every bid sits on chain encrypted to the auction's key, readable by anyone who ever holds that key; it can settle without a bid by recording it as forfeited, but a bid it left out that beat the price, whose reveal was posted in time, voids that settlement and takes the auctioneer's bond; and the number of bids, their timing, and the uniform escrow amount are public on-chain.
Watch a full mainnet run
One run on Starknet mainnet, start to finish: list, bid on both rails, seal, settle, collect. Watch on YouTube ↗
The problem
On a public chain a sealed bid has never really been sealed. Either you hand your amount to an auctioneer and trust them not to look, not to leak, and not to insert a bid of their own once they have seen yours — or you use commit–reveal, and every losing bid is published at the end.
Publishing them destroys the thing a sealed auction is for. Your valuation is a business fact; it tells competitors what you will pay, and it is still true at the next auction.
Commit–reveal has a second failure that is less discussed: it locks no money. A bidder who dislikes the result simply never reveals. In a second-price auction one silent bidder moves the price the winner pays, so the mechanism stops producing the outcome it promises.
Vickrey never publishes a losing bid. Collateral is escrowed up front, and a bid that is not revealed in time is settled around, not waited for. The winner and the price are proved from hash chains instead of disclosure. On chain, a losing bid is two hashes and a ciphertext that only the auction’s key opens.
How it works
Pick a level. Two hash anchors go on chain — no amount, no address. The clearing price is proved while every bid stays sealed.
Bid
Pick a level on the ladder. Two hash anchors go on chain — no amount, no address.
Seal
The contract freezes the set and stamps the block. Only then are bids revealed, encrypted to the auctioneer.
- bids arrivetwo hashes and an escrow each
- seal()the set is frozen, the block stamped
- reveals postedonly now, encrypted to the auctioneer
- settle()N+1 witnesses, checked on chain
Settle
N+1 witnesses prove the second price. Not one bid is opened.
What is on chain
A bid is two hashes and an escrow. The escrow is the same for everyone — the top of the ladder — so the amount you send says nothing about the amount you bid. Your address never appears beside a price, and a private-rail bid doesn't carry it at all. Collecting is public for now, so that step does.
- up_anchor
- poseidon chain, ℓ steps
- down_anchor
- poseidon chain, P−1−ℓ steps
- escrow
- the top of the ladder — the same for everyone
- amount
- never in the clear — encrypted to the auctioneer after the seal
- address
- not on a private-rail bid — collecting is public for now
See a settled auction →The full reference — the six properties, the hash-chain construction, and what the STRK20 integration does and does not reveal →
Six properties, and why each is hard
Each of these is a place a straightforward implementation breaks. They are listed because they are checkable, not because they are features.
Bids are real escrowed funds, not promises
What normally goes wrong: Commit-reveal locks nothing. A bidder can commit to a price they cannot pay, and you only find out at the end.
Here: Placing a bid transfers collateral into the contract in the same transaction that records it. A bid that is not funded does not exist.
No amount is readable while bidding is open. The auctioneer reads them only after the set is frozen
What normally goes wrong: Designs with a trusted auctioneer leak every bid to whoever runs the server, from the moment it arrives.
Here: During bidding the chain holds two hashes per bid and nothing else. After `seal()` freezes the set, each bid is posted on chain encrypted to a key the auctioneer made for this auction alone, and the auctioneer learns every exact bid. That ordering is the protection: by then the set cannot change, no bid can be added or dropped, and the clearing price is already fixed by bids nobody could edit. The encrypted bids stay on chain, so anyone who ever obtains that auction's key can read them; the auctioneer is prompted to delete it once the auction is final.
The bid set is frozen before any amount can be read
What normally goes wrong: If the party producing the result picks the set after seeing the contents, they can drop a rival's high bid and claim it never arrived.
Here: `seal()` stamps the block number and freezes the set on-chain. Only afterwards are bids revealed, encrypted to the auctioneer. Leaving out a bid whose reveal was posted in time is provable: that bidder can void the settlement and takes the auctioneer's bond. Sealing is permissionless — the contract checks only that the bid deadline has passed — so an auctioneer cannot stall an auction by refusing to seal it, and any bidder can start the clock themselves.
Losing bids are never published
What normally goes wrong: Every commit-reveal auction ends by publishing all of them. Your valuation is a business fact, and it is still true at the next auction.
Here: Settlement proves the outcome from bounds. The clearing price is revealed because it is the price; every other bid stays on chain only as two hashes and a ciphertext that the auction's key opens.
The outcome is proved, not asserted
What normally goes wrong: Most implementations ask you to trust that the settlement transaction did the arithmetic honestly.
Here: The contract verifies N+1 hash-preimage witnesses: the winner at or above the clearing level, the runner-up exactly at it, everyone else at or below. A false outcome cannot produce them.
A silent bidder is settled around, not waited for
What normally goes wrong: In commit-reveal, a bidder who dislikes the result simply never reveals — and in a second-price auction one silent bidder moves the price the winner pays.
Here: Settlement needs no cooperation from a bidder whose reveal was not posted in the reveal window: their bid is marked forfeited and the auction completes without them. What they get back depends on where the bid sat — at or below the clearing price, they redeem the escrow afterwards with a late loser-side proof built from their seed; above it, redeem_forfeit cannot return it.
Live auctions
Every auction on Starknet mainnet, in every state. No wallet needed to read any of it — the bid amounts are not hidden from you, they are not on the chain at all.
Before you bid
Every answer here agrees with the trust statement — including the ones that are unflattering.
What is a Vickrey auction?
The highest bidder wins and pays the second-highest bid. That makes bidding your true valuation the dominant strategy — shading your bid gains you nothing. It has been the theoretically optimal design since 1961.
How can the bids be sealed and the price still be proved?
A bid publishes two hash chains rather than an amount. Revealing a link of one proves “at or above this level”; the other proves “at or below”. The winner, the runner-up and everyone else each prove one bound, and together those pin the second price without opening a single bid.
What does the auctioneer learn, and when?
Nothing while bidding is open: no amount has been posted anywhere. Once the contract freezes the bid set, each bid is posted on chain encrypted to a key the auctioneer made for this auction, and from that moment the auctioneer knows every amount. It can never publish them, prove a false outcome, or spend anyone’s funds. But it knows them, and that is the honest limit of what this design gives you. The encrypted bids stay on chain, so anyone who ever obtains that key can read them; the auctioneer is prompted to delete it once the auction is final.
What happens if a bid isn't revealed?
After the seal, Vickrey’s relay posts each bid’s encrypted reveal, and you can post it yourself if the relay doesn’t. A bid whose reveal is not posted in the reveal window is settled around, not waited for: it is marked forfeit and left out of the ranking. If it was at or below the clearing price, its owner can reclaim the escrow after the auction finalizes; above it, the escrow cannot be redeemed.
What does it cost to bid?
Through the privacy pool: a flat pool fee per operation — 6 STRK on mainnet, read live from the pool rather than set by us — plus the escrow, which comes back. A bid placed directly on the contract costs gas alone; the amount stays sealed, but your address is public.
What can be auctioned?
An amount of a token, one NFT, or something off chain. Tokens and NFTs are held by the contract from listing. An NFT goes to a public address the winner names, because the privacy pool can’t hold NFTs. An off-chain lot is held by nobody: you are trusting the seller to deliver, and if you reject delivery, your payment does not come back — it is destroyed, along with the seller’s bond.
Is this audited? Is it on mainnet?
Nothing has been audited. The contracts run on Starknet mainnet, and the earlier version stays readable on the site. The README carries the honest status of every piece.