From c33e604952e7e19caa6dabf6c4ad50680b3551da Mon Sep 17 00:00:00 2001 From: SourceSensei Date: Mon, 31 Aug 2026 11:07:12 +0100 Subject: [PATCH] feat: publish completed CipherBid lifecycle --- README.md | 108 +++++++++++----- docs/demo-presentation-script.md | 120 ++++++++++++++++++ docs/evidence/README.md | 15 ++- .../evidence/hackathon-requirements-matrix.md | 20 +-- docs/evidence/mainnet/auction-lifecycle.md | 14 +- docs/evidence/mainnet/demo-script.md | 10 +- docs/evidence/mainnet/transactions.md | 12 +- docs/evidence/submission/pages-deployment.md | 2 +- strk20.json | 3 +- web/src/app/globals.css | 7 + web/src/config/verifiedMainnetLifecycle.ts | 12 ++ web/tests/unit/AuctionActions.test.tsx | 2 +- web/tests/unit/designTasteSystem.test.ts | 8 ++ web/tests/unit/verifiedSellerClaim.test.ts | 38 ++++++ 14 files changed, 303 insertions(+), 68 deletions(-) create mode 100644 docs/demo-presentation-script.md create mode 100644 web/tests/unit/verifiedSellerClaim.test.ts diff --git a/README.md b/README.md index ad48bfa..1d6a919 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,32 @@ **Private bids, guaranteed onchain delivery.** -CipherBid is an open-source Vickrey auction house for ERC-721 assets on Starknet. Every bidder escrows the same public STRK collateral cap through STRK20 while committing to a private bid amount. After the bidding window closes, bidders reveal their commitments, the highest valid bidder wins, and the NFT is delivered atomically at the greater of the reserve or second-highest valid bid. +CipherBid is a Vickrey NFT auction on Starknet where every accepted bidder locks the same STRK collateral cap through STRK20. The actual bid stays sealed until reveal. Settlement sends the NFT to the winner at the greater of the reserve or second-highest valid bid, and every refund, surplus, and seller payment returns through private STRK20 claims. -> **Verified mainnet demo:** auction [`1788040057342`](https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342) completed the two-wallet private-bid lifecycle, atomic settlement, and both bidder claims. Bidder B entered `4 STRK`, not the frozen plan's `3 STRK`; this README and the public evidence preserve the actual chain value. +[Open the live mainnet auction](https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342) · [Read the transaction ledger](docs/evidence/mainnet/transactions.md) · [Use the presentation script](docs/demo-presentation-script.md) -## Why equal collateral? +## The 30-second version + +Many auction demos hide a bid with a hash but do not prove the bidder can pay. Escrowing each bidder's exact amount fixes funding but leaks the bid through the public token transfer. + +CipherBid locks the same public `4 STRK` cap for both bidders. Observers see funded bids with equal collateral, but not whether the sealed bid is `2 STRK` or `4 STRK`. After reveal, the contract calculates the Vickrey price, transfers the escrowed NFT in the same settlement transaction, and accounts for every remaining STRK claim. + +Atomic settlement means all-or-nothing delivery. Winner selection, second-price accounting, and the NFT transfer succeed together or the transaction reverts. There is no accepted state where CipherBid records a winner but leaves the NFT with the seller. + +> **Verified mainnet result:** auction [`1788040057342`](https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342) completed two private equal-cap bids, two reveals, second-price settlement, atomic NFT delivery, bidder claims, and the final seller claim. Five published CipherBid transactions touched the canonical STRK20 pool. + +## Why this is more than a minimal commit/reveal demo + +| Minimal commit/reveal demo | CipherBid | +| ------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| A hash can be submitted without funded collateral | Every accepted bid moves the same real STRK cap through the live STRK20 pool | +| Exact escrow can leak the bid before reveal | Equal collateral hides which value at or below the cap was committed | +| Delivery can remain a separate manual step | The NFT enters custody at creation and moves to the winner inside settlement | +| Refunds often use public transfers | Loser refund, winner surplus, and seller proceeds use STRK20 open-note claims | +| Recovery is left outside the demo | Password-encrypted credentials bind to network, contract, auction, role, and claim handle | +| Success is usually shown with local tests | Mainnet receipts, CipherBid events, pool traces, NFT ownership, and zero residual accounting | + +## Why equal collateral matters A STRK20 `privacy_invoke` withdraws tokens from the privacy pool to the helper through a public ERC-20 edge. Escrowing each bidder's variable bid would reveal that amount before the reveal phase. CipherBid therefore locks the same cap for every accepted bidder. The public transfer proves every bid is funded without disclosing whether the sealed bid is `2 STRK`, `4 STRK`, or another value at or below the cap. @@ -35,43 +56,65 @@ The production frontend is live at [`https://sourcesenseitherealone.github.io/ci The exportable live-auction route is `/auction?id=`. It validates one auction ID, reads public Starknet state in the browser, verifies the deployed class/configuration and NFT custody, then renders wallet controls. Ready X still owns private-note discovery, proving, signing, and submission. +The [record-ready presentation script](docs/demo-presentation-script.md) follows this exact page and keeps the explanation under three minutes. `strk20.json.demo_video` stays empty until the updated recording is published and independently checked. + ## Verified mainnet demo The bounded mainnet demo uses one seller, two separate Ready X accounts, and one read-only observer: -| Term | Value | -| ----------------------- | ---------: | -| Reserve | `1 STRK` | -| Equal collateral cap | `4 STRK` | -| Bidder A sealed bid | `2 STRK` | -| Bidder B sealed bid | `4 STRK` | -| Verified winner | Bidder B | -| Verified clearing price | `2 STRK` | -| Loser refund | `4 STRK` | -| Winner surplus | `2 STRK` | -| Seller proceeds | `2 STRK` | -| Bidding window | 10 minutes | -| Reveal window | 5 minutes | +| Term | Value | +| ----------------------- | ----------------: | +| Reserve | `1 STRK` | +| Equal collateral cap | `4 STRK` | +| Bidder A sealed bid | `2 STRK` | +| Bidder B sealed bid | `4 STRK` | +| Verified winner | Bidder B | +| Verified clearing price | `2 STRK` | +| Loser refund | `4 STRK` | +| Winner surplus | `2 STRK` | +| Seller proceeds | `2 STRK`, claimed | +| Final house balance | `0 STRK` | +| Bidding window | 10 minutes | +| Reveal window | 5 minutes | Both bidders shielded `24 STRK` and passed the ten-block maturity gate before the timed auction started. Public readiness verified registration, deposit amount, and maturity only. Ready X remained authoritative for unspent private-note balance. ## Architecture -```text -Seller / public Starknet account - ├─ approves DemoERC721 token 99 - └─ creates auction atomically ─────────────┐ - ▼ -Ready X bidder wallet CipherBid AuctionHouse - ├─ owns viewing key and notes ├─ escrows the NFT - ├─ discovers mature STRK notes ├─ accepts equal 4 STRK collateral - ├─ creates proof ├─ stores Poseidon commitments - └─ submits Wallet API action ───────►├─ verifies reveals - ├─ computes Vickrey clearing price -STRK20 pool ├─ transfers NFT atomically to winner - ├─ screens public deposits └─ authorizes refunds/surplus/proceeds - ├─ verifies private proof - └─ invokes AuctionHouse +```mermaid +flowchart LR + UI["CipherBid web app
public reads and action descriptors"] + Wallet["Ready X
keys, notes, proving, signing"] + RPC["Starknet RPC
state and receipt readback"] + Pool["STRK20 pool
private ingress and claims"] + House["AuctionHouse
NFT custody and Vickrey accounting"] + NFT["ERC-721
token 99"] + Recovery["Encrypted recovery bundle
held by the user"] + + UI -->|read public state| RPC + RPC --> House + UI -->|Wallet API request| Wallet + Wallet -->|private action| Pool + Pool -->|privacy_invoke| House + Wallet -->|standard lifecycle call| House + House -->|custody and settlement| NFT + UI -.->|encrypt and export| Recovery + Recovery -.->|import for reveal or claim| UI +``` + +CipherBid never receives the wallet's viewing key, private notes, proof witness, or signer key. Ready X owns those operations. The web app constructs bounded public descriptors, keeps active auction credentials in memory, encrypts recovery exports, and verifies every submitted transition through public RPC readback. + +## Mainnet user flow + +```mermaid +flowchart TD + A["Seller escrows NFT and creates auction"] --> B["Bidder A and Bidder B each lock the same 4 STRK cap"] + B --> C["Bids remain sealed until the reveal window"] + C --> D["Bidder A reveals 2 STRK; Bidder B reveals 4 STRK"] + D --> E["AuctionHouse selects Bidder B and clears at 2 STRK"] + E --> F["Settlement transfers token 99 to Bidder B"] + F --> G["Loser refund, winner surplus, and seller proceeds return through STRK20"] + G --> H["Final AuctionHouse STRK balance: 0"] ``` ### Commitment binding @@ -205,6 +248,7 @@ Do not add `--execute` until the printed plan, signer, network, public bidder re - [Mainnet deployment](docs/evidence/mainnet/deployment.md) - [Verified mainnet transaction ledger](docs/evidence/mainnet/transactions.md) - [Verified mainnet auction lifecycle](docs/evidence/mainnet/auction-lifecycle.md) +- [Live demo presentation script](docs/demo-presentation-script.md) - [Mainnet release candidate](docs/evidence/mainnet/release-candidate.md) - [Canonical demo matrix](docs/evidence/task-0-demo-matrix.md) - [Lifecycle specification](docs/evidence/task-2-3-lifecycle-specification.md) @@ -212,7 +256,7 @@ Do not add `--execute` until the printed plan, signer, network, public bidder re - [Hackathon requirements matrix](docs/evidence/hackathon-requirements-matrix.md) - [Sepolia rehearsal](docs/evidence/sepolia/demo-runbook.md) -`strk20.json` contains the two verified contracts, four successful pool-touching CipherBid lifecycle transactions, and the clean-browser-verified live auction URL. `demo_video` remains intentionally empty until the maximum-three-minute video is publicly playable and independently checked. +`strk20.json` contains two verified contracts, five successful pool-touching CipherBid transactions, and the clean-browser-verified auction URL. The video field remains empty until the updated recording is public and checked. ## Scope diff --git a/docs/demo-presentation-script.md b/docs/demo-presentation-script.md new file mode 100644 index 0000000..06d53aa --- /dev/null +++ b/docs/demo-presentation-script.md @@ -0,0 +1,120 @@ +# CipherBid live demo presentation script + +**Target length:** about 2 minutes 45 seconds at a natural pace + +**Live page:** https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342 + +## Before recording + +1. Open the live auction in a clean browser window. +2. Set browser zoom to 100%. +3. Keep the page at the top before recording. +4. Do not open recovery files, wallet activity, private balances, or developer tools. +5. Scroll slowly enough that transaction links and values can be read. + +## Talk track + +### 0:00-0:18 - What CipherBid is + +**On screen:** Keep the auction title, `MAINNET`, `SOLD`, and `2/2 bids` visible. + +**Say:** + +> CipherBid is a private-bid Vickrey auction for NFTs on Starknet. It solves two trust problems at once. A hidden bid is useless if the winner cannot pay, and a winning bid is unsafe if NFT delivery still depends on the seller acting later. + +### 0:18-0:42 - The equal-collateral idea + +**On screen:** Scroll to the reserve, collateral cap, and deadline cards. + +**Say:** + +> CipherBid makes every accepted bidder lock the same public collateral cap through STRK20. In this auction both bidders locked 4 STRK, so observers could see that both bids were funded without learning whether either bidder had committed 2 STRK or 4 STRK. + +> The actual bid stayed sealed until the reveal window. This is the main difference from an unfunded hash commitment or variable public escrow. + +### 0:42-1:08 - The verified auction result + +**On screen:** Show the accepted bids and revealed amounts. + +**Say:** + +> This is the completed mainnet auction, not sample data. Bidder A revealed 2 STRK. Bidder B revealed 4 STRK. + +> CipherBid uses a Vickrey rule: the highest valid bidder wins, but pays the greater of the reserve or the second-highest bid. Bidder B therefore won and paid 2 STRK. + +### 1:08-1:36 - The atomic part + +**On screen:** Show token `99`, the current owner, and the Atomic Delivery Receipt. + +**Say:** + +> The seller placed NFT token 99 into AuctionHouse custody when the auction was created. This removes the need to trust the seller after bidding starts. + +> Settlement is atomic, which means all or nothing. The contract selects the winner, records the two-STRK clearing price, and transfers the NFT to Bidder B in one transaction. If the NFT transfer fails, the entire settlement reverts. CipherBid cannot record a successful winner while leaving the NFT with the seller. + +> The page then reads the NFT owner back from Starknet before it says delivery is verified. It does not trust browser state or a wallet success message. + +### 1:36-2:04 - Private claims and conservation + +**On screen:** Show clearing price, seller proceeds, and verified transaction receipts. + +**Say:** + +> The remaining value returned through STRK20 open-note claims. Bidder A received the 4 STRK loser refund. Bidder B received the 2 STRK winner surplus. The seller claimed the 2 STRK clearing price. + +> The seller claim is the fifth qualifying CipherBid transaction that touches the live STRK20 pool. After the claim, the AuctionHouse has zero actual STRK, zero accounted STRK, and no unexplained difference. + +### 2:04-2:28 - What stays private + +**On screen:** Keep the receipt and wallet boundary text visible. + +**Say:** + +> Ready X owns the viewing keys, private notes, proof generation, signing, and submission. CipherBid never asks for a viewing key or private-note witness. Recovery credentials are password-encrypted and held by the user. + +> The privacy claim is precise: bid amounts are sealed until reveal. Deposits, timing, equal collateral, and the final revealed bids are public by design. + +### 2:28-2:40 - Close with the differentiator + +**On screen:** Return to the auction title and `SOLD` status. + +**Say:** + +> CipherBid gives us funded privacy before reveal, all-or-nothing NFT delivery at settlement, private claims afterward, and public receipts anyone can verify. That is what makes it more than a basic commit/reveal auction. + +## Short answers for judge questions + +### Why not use a normal commit/reveal auction? + +A minimal commit/reveal design can accept an unfunded hash. If it escrows each bidder's exact amount, the public transfer can reveal the bid. CipherBid locks one equal cap for every accepted bidder. + +### Why use a Vickrey price? + +The winner pays the second-highest valid bid or the reserve, whichever is greater. In the verified auction, Bidder B revealed 4 STRK but paid 2 STRK. + +### What does atomic delivery mean? + +The AuctionHouse already holds the NFT. Winner selection, clearing-price accounting, and NFT transfer happen inside one settlement transaction. If delivery fails, settlement reverts instead of leaving a recorded winner without the asset. + +### What does STRK20 do here? + +STRK20 provides the private pool path for equal-cap bid ingress and the loser, winner, and seller claims. Ready X handles private-note discovery and proving. + +### Is everything anonymous? + +No. Deposits, timing, equal collateral, reveals, settlement, and open-note edges are public. CipherBid specifically protects the bid amount before reveal and keeps wallet private material out of the app. + +### How do we know delivery and accounting are correct? + +The public page reads the AuctionHouse state, transaction receipts, ERC-721 owner, token balance, and claim-consumed flags from Starknet. The final AuctionHouse actual and accounted STRK balances are both zero. + +### Is this production audited? + +No. It is a bounded, tested mainnet hackathon deployment. The repository documents its threat model and limitations instead of presenting it as a production audit. + +## Public proof links + +- [Live auction](https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342) +- [Verified transaction ledger](evidence/mainnet/transactions.md) +- [Verified lifecycle and value conservation](evidence/mainnet/auction-lifecycle.md) +- [Seller claim transaction](https://starkscan.co/tx/0x24d92390b2f0ca629fe49e4c4355aaa2fe1fbf143bd4ba1e37b80e4575528e) diff --git a/docs/evidence/README.md b/docs/evidence/README.md index 503b4dc..a4824be 100644 --- a/docs/evidence/README.md +++ b/docs/evidence/README.md @@ -9,19 +9,20 @@ This directory contains public, secret-free specifications and verified readback | [`mainnet/deployment.md`](mainnet/deployment.md) | Verified | Mainnet declarations, deployed addresses, successful receipts, class hashes, immutable AuctionHouse config, DemoERC721 ownership, and bounded fee accounting | | [`mainnet/deployment.json`](mainnet/deployment.json) | Verified | Machine-readable public deployment manifest consumed by frontend and auction-plan tooling | | [`mainnet/release-candidate.md`](mainnet/release-candidate.md) | Superseded pre-write freeze plus current status | Approved accounts, protocol addresses, demo economics, pool-fee assumptions, and release stop conditions | -| [`mainnet/transactions.md`](mainnet/transactions.md) | Verified | Eight successful lifecycle receipts; four qualifying pool-touching CipherBid transactions with event and trace checks | -| [`mainnet/auction-lifecycle.md`](mainnet/auction-lifecycle.md) | Verified | Actual 2/4 STRK reveals, Vickrey settlement, NFT delivery, bidder claims, value conservation, and seller-fee deferral | +| [`mainnet/transactions.md`](mainnet/transactions.md) | Verified | Ten canonical lifecycle receipts; five qualifying pool-touching CipherBid transactions with event and trace checks | +| [`mainnet/auction-lifecycle.md`](mainnet/auction-lifecycle.md) | Verified | Actual 2/4 STRK reveals, Vickrey settlement, NFT delivery, all claims, and zero residual value | | [`submission/pages-deployment.md`](submission/pages-deployment.md) | Verified | Durable GitHub Pages settings, exact deployed `main` SHA, successful hosted workflow/deployment, HTTP routes, and clean-browser runtime checks | -The mainnet private lifecycle is verified through both bidder claims. Seller proceeds remain exactly accounted and claimable but were intentionally deferred because the live `6 STRK` pool fee exceeds the `2 STRK` entitlement. +The mainnet lifecycle is verified through both bidder claims and the seller-proceeds claim. Final actual and accounted AuctionHouse STRK balances are zero. ## Prepared recording control -| Artifact | Status | Scope | -| -------------------------------------------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| [`mainnet/demo-script.md`](mainnet/demo-script.md) | Prepared; recording blocked | Maximum-three-minute narration, capture rules, and hard evidence gates bound to the deployed mainnet contracts and actual `2/4 STRK` case | +| Artifact | Status | Scope | +| ------------------------------------------------------------------ | --------------- | ----------------------------------------------------------------------------------------------------------- | +| [`mainnet/demo-script.md`](mainnet/demo-script.md) | Superseded | Earlier maximum-three-minute narration and capture controls for the actual `2/4 STRK` case | +| [`../demo-presentation-script.md`](../demo-presentation-script.md) | Ready to record | Plain-language live-page walkthrough updated for the completed seller claim and final zero-balance readback | -The script is not demo-video evidence. Its hard gate forbids recording or publication until the complete real lifecycle, claims, and Atomic Delivery Receipt are independently verified. +The updated presentation script is ready to record. A new file becomes public video evidence only after Pages deployment and clean playback/duration readback. ## Durable frontend publication diff --git a/docs/evidence/hackathon-requirements-matrix.md b/docs/evidence/hackathon-requirements-matrix.md index a43c0c4..68149a0 100644 --- a/docs/evidence/hackathon-requirements-matrix.md +++ b/docs/evidence/hackathon-requirements-matrix.md @@ -20,14 +20,14 @@ Where this matrix is stricter than the official minimum, the row is labeled **Ci ## Current gate snapshot -| Gate | Current evidence | Status | -| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | -| Registration | [Application PR #178](https://github.com/starkience/strk20-hackathon/pull/178), applied upstream commit [`6895886`](https://github.com/starkience/strk20-hackathon/commit/6895886bd5e31e202306bcff1c2203e2f6369d08), and metadata correction [PR #218](https://github.com/starkience/strk20-hackathon/pull/218), applied as [`18259c8`](https://github.com/starkience/strk20-hackathon/commit/18259c8dfa0408e06226df51c64bc1a9dd75ff54). | Satisfied | -| Public hub entry | [Private Sprint hub](https://strk20.starknet.io/hackathon) renders `SourceSenseiTheRealOne / cipherbid`; the official project index records category `DeFi` and `inspired_by: RFP-08`. | Satisfied | -| Public repository | [SourceSenseiTheRealOne/cipherbid](https://github.com/SourceSenseiTheRealOne/cipherbid) is publicly reachable without authentication. | Satisfied | -| Open-source license | [`LICENSE`](../../LICENSE) is the MIT License and GitHub detects SPDX `MIT`. | Satisfied | -| Mainnet contracts and transactions | Root [`strk20.json`](../../strk20.json) contains two verified contracts, four qualifying pool-touching hashes, and the clean-browser-verified real auction URL. | Satisfied; pending final publication | -| Demo video | `strk20.json.demo_video` remains empty until the ≤3-minute public video passes playback and duration checks. | Pending | +| Gate | Current evidence | Status | +| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | +| Registration | [Application PR #178](https://github.com/starkience/strk20-hackathon/pull/178), applied upstream commit [`6895886`](https://github.com/starkience/strk20-hackathon/commit/6895886bd5e31e202306bcff1c2203e2f6369d08), and metadata correction [PR #218](https://github.com/starkience/strk20-hackathon/pull/218), applied as [`18259c8`](https://github.com/starkience/strk20-hackathon/commit/18259c8dfa0408e06226df51c64bc1a9dd75ff54). | Satisfied | +| Public hub entry | [Private Sprint hub](https://strk20.starknet.io/hackathon) renders `SourceSenseiTheRealOne / cipherbid`; the official project index records category `DeFi` and `inspired_by: RFP-08`. | Satisfied | +| Public repository | [SourceSenseiTheRealOne/cipherbid](https://github.com/SourceSenseiTheRealOne/cipherbid) is publicly reachable without authentication. | Satisfied | +| Open-source license | [`LICENSE`](../../LICENSE) is the MIT License and GitHub detects SPDX `MIT`. | Satisfied | +| Mainnet contracts and transactions | Root [`strk20.json`](../../strk20.json) contains two verified contracts, five qualifying pool-touching hashes, and the clean-browser-verified auction URL. | Satisfied | +| Demo video | `strk20.json.demo_video` remains empty until the ≤3-minute public video passes playback and duration checks. | Pending | ## Evidence destination catalog @@ -65,7 +65,7 @@ Planned evidence summaries are reviewed, secret-free indexes of public facts. Ra | `SUB-01` | Official | The repository state at **August 31, 2026 at 23:59 UTC** is the submission; there is no second submission PR.[4][5] | Freeze and verify the exact final commit before the deadline, then let the hub index the repository. | `E-GATES`, repository commit URL, hub row | Final commit and all required public fields exist before the deadline. | Pending | | `SUB-02` | Official | A live public demo that anyone can open is required to be scored.[4][5] | Publish the production demo without login and verify it in a clean browser. | `E-DEMO`, root `strk20.json` `demo_url` when explicit | Clean-browser route and public URL both succeed. | Satisfied | | `SUB-03` | Official | A public three-minute demo video is required to be scored.[1][4][5] | Record the canonical seller/two-bidder/observer lifecycle and keep the published cut at no more than three minutes. | `E-VIDEO`, root `strk20.json` `demo_video` | URL is public, playable, and duration-verified. | Pending | -| `SUB-04` | Official | Root `strk20.json` must list at least three verified Starknet mainnet transaction hashes.[4][5] | Reserve the minimum slots for Bidder A ingress, Bidder B ingress, and at least one STRK20 claim; add hashes only after all transaction gates pass. | `E-TX`, root `strk20.json` | Array contains at least three unique, verified mainnet hashes. | Satisfied: four unique hashes | +| `SUB-04` | Official | Root `strk20.json` must list at least three verified Starknet mainnet transaction hashes.[4][5] | Publish two private bid ingresses plus winner-surplus, loser-refund, and seller-proceeds claims only after all transaction gates pass. | `E-TX`, root `strk20.json` | Array contains at least three unique, verified mainnet hashes. | Satisfied: five unique hashes | | `TX-01` | Official | Every listed hash must exist on Starknet mainnet.[4][5] | Query an independent RPC/explorer and bind the result to the exact hash/network. | `E-TX` | Mainnet receipt lookup returns the exact candidate hash. | Satisfied | | `TX-02` | Official | Every listed transaction must have succeeded.[4][5] | Require final accepted/succeeded execution; timeout remains unconfirmed and revert is rejected. | `E-TX` | Final receipt is successful, not merely submitted or pending. | Satisfied | | `TX-03` | Official | Every listed transaction must have touched the live STRK20 pool.[4][5] | Decode the trace/receipt and prove interaction with the official mainnet pool address. | `E-TX` | Exact configured live-pool address appears in the transaction execution path. | Satisfied | @@ -96,7 +96,7 @@ If another team depends on published CipherBid work, that may count in CipherBid | `TX-A` | Bidder A private equal-cap ingress | Yes | ABI-frozen accepted-bid event from the listed auction house | Receipt success, pool path, event decode, bid-count/commitment state | `E-TX`, `E-LIFECYCLE`, `strk20.json` | Verified | | `TX-B` | Bidder B private equal-cap ingress | Yes | ABI-frozen accepted-bid event from the listed auction house | Receipt success, pool path, event decode, bid-count/commitment state | `E-TX`, `E-LIFECYCLE`, `strk20.json` | Verified | | `TX-C` | At least one verified STRK20 claim | Yes | ABI-frozen claim event from the listed auction house | Receipt success, pool path, event decode, consumed-claim/accounting state | `E-TX`, `E-LIFECYCLE`, `strk20.json` | Verified: winner surplus | -| `TX-D+` | Additional refund, surplus, or seller claims | Yes when listed for STRK20 scoring | Matching ABI-frozen claim event | Receipt success and claim/value-conservation readback | `E-TX`, `E-LIFECYCLE`; optional `strk20.json` entries | Verified: loser refund; seller deferred | +| `TX-D+` | Additional refund, surplus, or seller claims | Yes when listed for STRK20 scoring | Matching ABI-frozen claim event | Receipt success and claim/value-conservation readback | `E-TX`, `E-LIFECYCLE`; optional `strk20.json` entries | Verified: loser refund and seller claim | Reveal and settlement receipts remain mandatory lifecycle evidence even if they do not touch the pool and therefore are not used among the three qualifying `strk20.json` hashes. diff --git a/docs/evidence/mainnet/auction-lifecycle.md b/docs/evidence/mainnet/auction-lifecycle.md index f2960fb..fd2fae3 100644 --- a/docs/evidence/mainnet/auction-lifecycle.md +++ b/docs/evidence/mainnet/auction-lifecycle.md @@ -1,8 +1,8 @@ # CipherBid verified mainnet auction lifecycle -**Status:** Verified through bidder claims; seller proceeds intentionally remain claimable +**Status:** Fully verified through seller proceeds claim -**Verification time:** `2026-08-29T22:18:12Z` +**Verification time:** `2026-08-31T09:00:38Z` **Live route:** [`https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342`](https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342) @@ -59,7 +59,7 @@ The settlement event and ERC-721 owner readback prove price calculation and NFT | ----------------------- | -------: | ------------------------------------------------------------------------------------------------------------------------------------------ | | Bidder A loser refund | `4 STRK` | Claimed through STRK20 in [`0x7bbe0489…fff15e`](https://starkscan.co/tx/0x7bbe0489702cdc6466b7aa4c262d7d1f34dcabace16e47c5b02cafef7fff15e) | | Bidder B winner surplus | `2 STRK` | Claimed through STRK20 in [`0x4a76360a…ff540d`](https://starkscan.co/tx/0x4a76360a895ce3f984ee7ab704be0e5c2c220c5584ad05704bb338f2fff540d) | -| Seller entitlement | `2 STRK` | Unclaimed and still accounted; intentionally deferred | +| Seller entitlement | `2 STRK` | Claimed through STRK20 in [`0x24d92390…5528e`](https://starkscan.co/tx/0x24d92390b2f0ca629fe49e4c4355aaa2fe1fbf143bd4ba1e37b80e4575528e) | ```text Initial equal-cap collateral: 4 + 4 = 8 STRK @@ -72,13 +72,13 @@ Total allocation: 8 STRK Final readback: ```text -AuctionHouse actual STRK balance: 2 STRK -AuctionHouse accounted balance: 2 STRK -Outstanding seller entitlement: 2 STRK +AuctionHouse actual STRK balance: 0 STRK +AuctionHouse accounted balance: 0 STRK +Outstanding seller entitlement: 0 STRK Unexplained difference: 0 STRK ``` -The live pool fee was `6 STRK` per private operation. Claiming the seller's `2 STRK` would produce a `-4 STRK` result before execution gas, so the seller claim was not submitted. This is an explicit economic deferral, not missing collateral; the exact entitlement remains claimable and both actual and accounted balances agree. +The live pool fee was `6 STRK` per private operation. The seller explicitly completed the `2 STRK` claim despite the `-4 STRK` economic result before public authorization gas. The successful claim emitted `SellerProceedsClaimed`, touched the canonical pool in the execution trace, consumed the seller claim, and reduced both actual and accounted AuctionHouse balances to zero. ## Privacy and custody boundary diff --git a/docs/evidence/mainnet/demo-script.md b/docs/evidence/mainnet/demo-script.md index a59b155..c4ea1a5 100644 --- a/docs/evidence/mainnet/demo-script.md +++ b/docs/evidence/mainnet/demo-script.md @@ -1,7 +1,7 @@ # CipherBid mainnet demo script -**Target duration:** 2:45–2:55 -**Recording status:** Lifecycle verified; record only after the persistent Atomic Delivery Receipt is deployed and clean-browser verified. +**Target duration:** 2:40 maximum +**Recording status:** Superseded for the final claim-complete recording by [`../../demo-presentation-script.md`](../../demo-presentation-script.md). ## Hard recording gate @@ -137,14 +137,14 @@ If any item is missing, stop. Do not use mock hashes, edited balances, rehearsed **Narration:** -> The loser receives four STRK back, the winner can claim the two-STRK surplus, and the seller receives two STRK where current pool fees make the claim economical. Every applicable claim is one-time and read back from chain state. +> The loser received four STRK back, the winner claimed the two-STRK surplus, and the seller claimed the two-STRK clearing price. Every claim is one-time and read back from chain state. **Visible evidence:** - loser refund: `4 STRK` - winner surplus: `2 STRK` -- seller proceeds: `2 STRK`, or an explicit fee-based deferral if uneconomical -- no unexpected collateral remains +- seller proceeds: `2 STRK`, claimed +- AuctionHouse actual and accounted balances: `0 STRK` ## 2:50–2:58 — Close diff --git a/docs/evidence/mainnet/transactions.md b/docs/evidence/mainnet/transactions.md index 7dce988..50fa1e0 100644 --- a/docs/evidence/mainnet/transactions.md +++ b/docs/evidence/mainnet/transactions.md @@ -1,6 +1,6 @@ # CipherBid verified mainnet transactions -**Verification time:** `2026-08-29T22:18:12Z` +**Verification time:** `2026-08-31T09:00:38Z` **Network:** Starknet mainnet (`0x534e5f4d41494e`) @@ -18,10 +18,10 @@ Each row was independently checked against the public RPC by exact hash. Publica 2. finality `ACCEPTED_ON_L2` or stronger; 3. exactly one lifecycle-specific event emitted by the verified AuctionHouse; 4. execution trace contains the AuctionHouse; -5. private bids and bidder claims also contain the canonical STRK20 pool in the execution trace; +5. private bids and all private claims also contain the canonical STRK20 pool in the execution trace; 6. post-state agrees with the decoded transition. -The eight hashes are unique. Starkscan also resolves the four qualifying pool-touching transaction URLs without authentication. Recovery payloads, passwords, claim secrets, bid nonces, viewing keys, notes, proof witnesses, wallet sessions, and raw wallet output are excluded. +The ten canonical lifecycle hashes are unique. The five qualifying private transactions touch the canonical live STRK20 pool. Recovery payloads, passwords, claim secrets, bid nonces, viewing keys, notes, proof witnesses, wallet sessions, and raw wallet output are excluded. ## Lifecycle ledger @@ -35,10 +35,14 @@ The eight hashes are unique. Starkscan also resolves the four qualifying pool-to | Vickrey settlement and atomic NFT delivery | [`0x883f852f…02cbf`](https://starkscan.co/tx/0x883f852f91052cc25dee8e30a7ce04996db7ccaca015d4bb2d5e2826602cbf) | `14066773` / `2026-08-29T22:05:57Z` | `AuctionSettled` | No | Sold; winner index `1`; clearing price `2 STRK`; token `99` owner is Bidder B | | Winner-surplus private claim | [`0x4a76360a…ff540d`](https://starkscan.co/tx/0x4a76360a895ce3f984ee7ab704be0e5c2c220c5584ad05704bb338f2fff540d) | `14066957` / `2026-08-29T22:11:01Z` | `WinnerSurplusClaimed` | **Yes** | `2 STRK` credited through the open-note claim route | | Loser-refund private claim | [`0x7bbe0489…fff15e`](https://starkscan.co/tx/0x7bbe0489702cdc6466b7aa4c262d7d1f34dcabace16e47c5b02cafef7fff15e) | `14067030` / `2026-08-29T22:13:01Z` | `LoserRefundClaimed` | **Yes** | `4 STRK` credited through the open-note claim route | +| Seller open-note authorization | [`0x51e1bb6d…bf933`](https://starkscan.co/tx/0x51e1bb6d0fd7474f7213c744714eb7d2256701b12050763c5ed73ac92ebf933) | `14141273` / `2026-08-31T09:00:11Z` | `SellerProceedsAuthorized` | No | Final authorized note matches the subsequent private claim | +| Seller-proceeds private claim | [`0x24d92390…5528e`](https://starkscan.co/tx/0x24d92390b2f0ca629fe49e4c4355aaa2fe1fbf143bd4ba1e37b80e4575528e) | `14141287` / `2026-08-31T09:00:38Z` | `SellerProceedsClaimed` | **Yes** | `2 STRK` credited; seller claim consumed; actual and accounted house balances are zero | ## Qualifying `strk20.json` transactions -The two bid ingresses and two bidder claims satisfy the strict publication gate: each succeeded on mainnet, touched the canonical live STRK20 pool, emitted its expected event from the listed CipherBid AuctionHouse, and produced the expected readback. Creation, reveals, and settlement support the lifecycle but are not listed as STRK20 transactions because their traces do not touch the pool. +The two bid ingresses and three private claims satisfy the strict publication gate: each succeeded on mainnet, touched the canonical live STRK20 pool, emitted its expected event from the listed CipherBid AuctionHouse, and produced the expected readback. Creation, reveals, settlement, and seller authorization support the lifecycle but are not listed in `strk20.json` because their traces do not touch the pool. + +Several seller-authorization retries succeeded while Ready X lacked enough mature private funds for the pool fee. They only replaced the authorized note and did not claim value. The canonical ledger lists the final effective authorization immediately before the successful private claim. ## Truthful deviation from the frozen plan diff --git a/docs/evidence/submission/pages-deployment.md b/docs/evidence/submission/pages-deployment.md index 0bfab7e..02fcc0e 100644 --- a/docs/evidence/submission/pages-deployment.md +++ b/docs/evidence/submission/pages-deployment.md @@ -57,4 +57,4 @@ The auction route's unavailable state is expected: auction ID `1` has not been c The Pages bundle contains public network/deployment configuration only. Ready X remains responsible for private-note discovery, viewing keys, proof generation, signing, and submission. No signer, recovery payload, bid nonce, claim secret, private note, proof witness, wallet session, or generated runtime evidence is included. -The later paired test verified the real settled auction route and four qualifying pool-touching transactions, which are now represented in `strk20.json`. The video field remains empty until public playback and duration checks pass. +The completed lifecycle verifies five qualifying pool-touching transactions, now represented in `strk20.json`. The video field remains empty until the updated recording passes public playback and duration checks. diff --git a/strk20.json b/strk20.json index bb32d62..09f067c 100644 --- a/strk20.json +++ b/strk20.json @@ -3,7 +3,8 @@ "0x70a5ca96744778f5c7f8d1b9b353deafad4dfcbacb218b28721667a759ce245", "0x52376bbde2b895e5e241b5385baf491293c7fec799d777ad332e3def0677fd4", "0x4a76360a895ce3f984ee7ab704be0e5c2c220c5584ad05704bb338f2fff540d", - "0x7bbe0489702cdc6466b7aa4c262d7d1f34dcabace16e47c5b02cafef7fff15e" + "0x7bbe0489702cdc6466b7aa4c262d7d1f34dcabace16e47c5b02cafef7fff15e", + "0x24d92390b2f0ca629fe49e4c4355aaa2fe1fbf143bd4ba1e37b80e4575528e" ], "contracts": [ "0x01b32af8bab712ede82117b8ff1b8866e09798f6c81edc255ffe59dd42e4843e", diff --git a/web/src/app/globals.css b/web/src/app/globals.css index f0e26dc..301da15 100644 --- a/web/src/app/globals.css +++ b/web/src/app/globals.css @@ -358,6 +358,13 @@ body.cipherbid-root ::selection { min-width: 0; } +.cipherbid-auction-page dd > code { + display: block; + min-width: 0; + overflow-wrap: anywhere; + word-break: break-all; +} + .cipherbid-root [class*='text-[#a8b1ff]'], .cipherbid-root [class*='text-[#d7dcff]'], .cipherbid-root [class*='text-[#aee5c1]'], diff --git a/web/src/config/verifiedMainnetLifecycle.ts b/web/src/config/verifiedMainnetLifecycle.ts index ca23d1c..e38211b 100644 --- a/web/src/config/verifiedMainnetLifecycle.ts +++ b/web/src/config/verifiedMainnetLifecycle.ts @@ -56,6 +56,18 @@ const VERIFIED_MAINNET_RECEIPTS: readonly PublishedReceipt[] = Object.freeze([ finalityStatus: 'ACCEPTED_ON_L2', blockNumber: 14_067_030, }), + Object.freeze({ + label: 'Seller authorization', + transactionHash: '0x51e1bb6d0fd7474f7213c744714eb7d2256701b12050763c5ed73ac92ebf933', + finalityStatus: 'ACCEPTED_ON_L2', + blockNumber: 14_141_273, + }), + Object.freeze({ + label: 'Seller proceeds', + transactionHash: '0x24d92390b2f0ca629fe49e4c4355aaa2fe1fbf143bd4ba1e37b80e4575528e', + finalityStatus: 'ACCEPTED_ON_L2', + blockNumber: 14_141_287, + }), ]) export function verifiedReceiptsForAuction( diff --git a/web/tests/unit/AuctionActions.test.tsx b/web/tests/unit/AuctionActions.test.tsx index c25c392..5d1c356 100644 --- a/web/tests/unit/AuctionActions.test.tsx +++ b/web/tests/unit/AuctionActions.test.tsx @@ -127,7 +127,7 @@ describe('AuctionActions', () => { const { rerender } = render() expect(screen.getByText('Delivery verified')).toBeInTheDocument() - expect(screen.getAllByRole('link')).toHaveLength(8) + expect(screen.getAllByRole('link')).toHaveLength(10) expect( screen.getByRole('link', { name: /Settlement 0x883f852f91052cc25dee8e30a7ce04996db7ccaca015d4bb2d5e2826602cbf/i, diff --git a/web/tests/unit/designTasteSystem.test.ts b/web/tests/unit/designTasteSystem.test.ts index b61563c..497442b 100644 --- a/web/tests/unit/designTasteSystem.test.ts +++ b/web/tests/unit/designTasteSystem.test.ts @@ -42,6 +42,14 @@ describe('CipherBid Taste visual system', () => { ) }) + it('wraps long onchain owner addresses inside their fact card', () => { + const css = source('src/app/globals.css') + + expect(css).toMatch( + /\.cipherbid-auction-page dd > code \{[^}]*overflow-wrap: anywhere;[^}]*word-break: break-all;/s, + ) + }) + it('removes the old purple design literals from the redesigned surface', () => { for (const relativePath of sourceFiles.filter((value) => value !== 'src/app/globals.css')) { expect(source(relativePath), relativePath).not.toMatch(/#6654d9|#7170ff|#a8b1ff/i) diff --git a/web/tests/unit/verifiedSellerClaim.test.ts b/web/tests/unit/verifiedSellerClaim.test.ts new file mode 100644 index 0000000..44d87f7 --- /dev/null +++ b/web/tests/unit/verifiedSellerClaim.test.ts @@ -0,0 +1,38 @@ +import { readFileSync } from 'node:fs' +import path from 'node:path' +import { describe, expect, it } from 'vitest' +import { verifiedReceiptsForAuction } from '@/config/verifiedMainnetLifecycle' + +const sellerClaimHash = '0x24d92390b2f0ca629fe49e4c4355aaa2fe1fbf143bd4ba1e37b80e4575528e' + +describe('verified seller claim publication', () => { + it('publishes the qualifying seller claim once in the STRK20 manifest', () => { + const manifest = JSON.parse(readFileSync(path.resolve(process.cwd(), '..', 'strk20.json'), 'utf8')) as { + transactions: string[] + } + + expect(manifest.transactions).toHaveLength(5) + expect(new Set(manifest.transactions).size).toBe(5) + expect(manifest.transactions.at(-1)).toBe(sellerClaimHash) + }) + + it('ends the canonical receipt ledger with seller authorization and private claim', () => { + const receipts = verifiedReceiptsForAuction('mainnet', '1788040057342') + + expect(receipts).toHaveLength(10) + expect(receipts.slice(-2)).toEqual([ + { + label: 'Seller authorization', + transactionHash: '0x51e1bb6d0fd7474f7213c744714eb7d2256701b12050763c5ed73ac92ebf933', + finalityStatus: 'ACCEPTED_ON_L2', + blockNumber: 14_141_273, + }, + { + label: 'Seller proceeds', + transactionHash: sellerClaimHash, + finalityStatus: 'ACCEPTED_ON_L2', + blockNumber: 14_141_287, + }, + ]) + }) +})