A Vickrey auction — highest bidder wins, pays the second-highest bid — has been the theoretically right way to sell one thing since 1961, and has never worked on a public chain. Sealing the bids meant trusting an auctioneer; revealing them at the end destroyed the privacy the mechanism depends on.
This one settles with a proof. The winner and the clearing price are established on-chain from hash-chain witnesses, and the losing bids are never published — not even the winner's own bid.
Open the live auctions · How it works · Source
stateDiagram-v2
direction LR
[*] --> Open: create_auction
Open --> Sealed: seal
Sealed --> Settled: settle
Settled --> Finalized: finalize
Settled --> Cancelled: dispute succeeds
Sealed --> Cancelled: abandon
Finalized --> [*]: claim lot and refunds
Cancelled --> [*]: refunds, everyone whole
create_auction escrows the lot and the auctioneer's bond. Bids arrive as two hashes
and escrowed collateral — no amount, no address. seal
freezes the set before any seed is sent, so the auctioneer cannot choose the set after
seeing its contents. Settlement moves no money; it opens a dispute window, which is
the only time a wrong outcome can be challenged.
abandon is the timeout. A sealed auction otherwise has one way out — settlement, which
only the auctioneer can perform — so without it an auctioneer who walked away would lock
every bidder's collateral permanently. It forfeits the bond to the bidders.
flowchart LR
W["Bidder's wallet<br/>shielded balance"] -->|"one proved transaction"| P["STRK20 pool"]
P -->|withdraw collateral| A["AuctionAnonymizer<br/><i>our contract</i>"]
A -->|place_bid| S["SealedBidAuction<br/><i>our contract</i>"]
A -.->|"emits Routed"| E1["auction_id<br/>operation"]
S -.->|"emits BidPlaced"| E2["two hash anchors<br/>claim handle"]
S -->|"refund · surplus · lot"| A
A -->|"OpenNoteDeposit"| P
No bidder address ever crosses that boundary — the auction sees only the helper, and every way value returns is credited as a private note inside the pool.
Routed deliberately carries only the auction id and the operation. Not the
note_id, which would let an observer tie a private note to an auction action. Not the
bid index, which the auction already emits. Not any amount.
Each is a place a straightforward implementation breaks.
- Bids are real escrowed funds, not promises
- Sealed from everyone, including the auctioneer
- The bid set is frozen before any amount can be read
- Losing bids are never published — only the clearing price
- The outcome is proved, not asserted
- Refusing to reveal cannot grief the auction
→ Each one, with why it is hard and how it works
Built for the STRK20 Private Sprint (RFP-08).
| Contracts | Cairo 2.14, 80 tests, deployed and exercised on Sepolia |
| Interface | Live at vickrey.0xo.in — public rail working, no wallet needed to read anything |
| Mainnet | Not yet declared. Class hashes are frozen and the deployment is scripted |
| Audited | No. The anonymizer in particular is app-team code that handles funds mid-transaction |
The repository states what did not ship and why, including a defect found by audit and the reasoning for the fix that was not applied.
