diff --git a/AGENTS.md b/AGENTS.md index 870515e..4dddb6c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,5 +21,5 @@ Features target `development`; promotion is `development -> staging -> main` thr ## Required gates - Web: format check, lint, strict TypeScript, unit/integration tests, Playwright, production build. -- Cairo: `scarb fmt --check`, `scarb build`, `snforge test` in WSL `Ubuntu-24.04`. +- Cairo: `scarb fmt --check`, `scarb build`, `snforge test` in WSL `Ubuntu`. - Security: dependency, secret, static analysis, value-conservation invariants, independent contract review. diff --git a/README.md b/README.md index bfa7634..e558a33 100644 --- a/README.md +++ b/README.md @@ -1,274 +1,78 @@ # CipherBid -[![CipherBid CI](https://github.com/SourceSenseiTheRealOne/cipherbid/actions/workflows/ci.yml/badge.svg)](https://github.com/SourceSenseiTheRealOne/cipherbid/actions/workflows/ci.yml) -[![Deploy Pages](https://github.com/SourceSenseiTheRealOne/cipherbid/actions/workflows/deploy-pages.yml/badge.svg)](https://github.com/SourceSenseiTheRealOne/cipherbid/actions/workflows/deploy-pages.yml) +Funded, sealed-bid NFT auctions on Starknet, with atomic delivery and STRK20 settlement claims. -**Private bids, guaranteed onchain delivery.** +Each bidder locks the same public collateral cap, keeping the transfer amount from exposing the bid. Bids become public during reveal. The highest valid bid wins at the greater of the reserve or second-highest bid, and settlement transfers the escrowed NFT in the same transaction. -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. +**Status:** built for the STRK20 Private Sprint and exercised on Starknet mainnet. The organizer registry lists the project as finished, with demo, video and mainnet requirements satisfied. This is a bounded hackathon deployment, not an audited production service. -[Open the live mainnet auction](https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342) · [Watch the final demo](https://youtu.be/pYZk6KXko7o) · [Read the transaction ledger](docs/evidence/mainnet/transactions.md) · [Use the presentation script](docs/demo-presentation-script.md) +[Live mainnet auction](https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342) · [Demo video](https://youtu.be/pYZk6KXko7o) · [Transaction ledger](docs/evidence/mainnet/transactions.md) · [Submission readback](docs/evidence/submission/hub-status.md) -## The 30-second version +[![CipherBid's settled mainnet auction: token 99 delivered, with a 2 STRK clearing price](docs/assets/auction-preview.png)](https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342) -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. +## Mainnet result -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. +The published auction accepted two bids backed by the same `4 STRK` cap. They revealed `2 STRK` and `4 STRK`; the higher bidder received NFT `99` at a `2 STRK` clearing price. The loser refund, winner surplus and seller proceeds were claimed through STRK20. The recorded final actual and accounted AuctionHouse balances were zero. -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. +The [lifecycle record](docs/evidence/mainnet/auction-lifecycle.md) links each state transition to its receipt. The [deployment manifest](docs/evidence/mainnet/deployment.json) identifies the contracts and class hashes; [`strk20.json`](strk20.json) lists the five qualifying pool-touching transactions. -> **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. +
+Mainnet contract addresses -## Why this is more than a minimal commit/reveal demo +- AuctionHouse: [`0x01b32af8bab712ede82117b8ff1b8866e09798f6c81edc255ffe59dd42e4843e`](https://voyager.online/contract/0x01b32af8bab712ede82117b8ff1b8866e09798f6c81edc255ffe59dd42e4843e) +- DemoERC721: [`0x05c7080c583304469e853e472d46a20448ff82bf9ee4c87a8efabc35f8177e1f`](https://voyager.online/contract/0x05c7080c583304469e853e472d46a20448ff82bf9ee4c87a8efabc35f8177e1f) -| 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 +## Engineering decisions -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. +- Equal collateral prevents the public transfer into the auction contract from disclosing each bid amount. It costs capital efficiency: every accepted bidder funds the full cap. +- The Cairo contract checks pool-only ingress, observed token balances, commitment uniqueness and one-time claims. Settlement is bounded to at most 32 bidders. +- NFT custody begins when the auction is created. Winner selection, price accounting and delivery either complete together or revert. +- A supported wallet owns signing, private-note discovery and proving. Auction credentials exist in active browser memory and password-encrypted recovery files, with import verification before submission. +- The UI validates the deployed class, pool and token before rendering chain state. Transaction confirmation requires the expected receipt, event and state readback. -This is **STRK20-funded sealed bidding with equalized real collateral**. It is not an unfunded hash-only auction, and it does not claim bids remain private after reveal. +[Engineering notes](docs/engineering.md) explain the state machine, commitment binding, failure handling, accounting and privacy limits. -## Verified mainnet deployment +## Stack and layout -| Component | Address / transaction | -| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| AuctionHouse | [`0x01b32af8bab712ede82117b8ff1b8866e09798f6c81edc255ffe59dd42e4843e`](https://voyager.online/contract/0x01b32af8bab712ede82117b8ff1b8866e09798f6c81edc255ffe59dd42e4843e) | -| DemoERC721 | [`0x05c7080c583304469e853e472d46a20448ff82bf9ee4c87a8efabc35f8177e1f`](https://voyager.online/contract/0x05c7080c583304469e853e472d46a20448ff82bf9ee4c87a8efabc35f8177e1f) | -| Demo NFT | Token ID `99` | -| STRK20 pool | `0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a` | -| STRK token | `0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d` | -| AuctionHouse declaration | [`0x552781e5ecb2ab9826474c8395ca5fd2f534ce6155367ab67ae195f5e2c9dc6`](https://voyager.online/tx/0x552781e5ecb2ab9826474c8395ca5fd2f534ce6155367ab67ae195f5e2c9dc6) | -| DemoERC721 declaration | [`0x01efc7df78014f252d346af3b88a5035b002cf005079604f6e3bf9df0f1fa9b`](https://voyager.online/tx/0x01efc7df78014f252d346af3b88a5035b002cf005079604f6e3bf9df0f1fa9b) | - -Deployment readback confirmed the reviewed class hashes, canonical pool and STRK token, a maximum of 32 bidders, and initial deployer ownership of NFT `99`. The [verified lifecycle](docs/evidence/mainnet/auction-lifecycle.md) now proves token `99` was delivered to Bidder B during settlement. See the [deployment evidence](docs/evidence/mainnet/deployment.md) and [machine-readable manifest](docs/evidence/mainnet/deployment.json). - -## Public frontend - -The production frontend is live at [`https://sourcesenseitherealone.github.io/cipherbid/`](https://sourcesenseitherealone.github.io/cipherbid/). Its source-controlled deployment workflow uses immutable action pins, least-privilege token permissions, and only public mainnet configuration. The [`main` deployment, workflow, Pages settings, and public browser routes were independently read back](docs/evidence/submission/pages-deployment.md). - -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 final [2:24 public demo video](https://youtu.be/pYZk6KXko7o) follows this page through equal collateral, the `2/4 STRK` result, private claims, and atomic delivery. The [presentation script](docs/demo-presentation-script.md) remains available for the complete talk track and judge Q&A. - -## 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`, 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 - -```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"] -``` - -## Roadmap: token launch auctions - -The next research direction is to extend CipherBid from one-unit NFT sales to multi-unit token launches. Participants would submit funded sealed demand, reveal after the bidding window, and settle allocations at an onchain clearing price. - -That extension needs a new allocation and settlement contract, including multi-unit accounting and claim rules. It is roadmap work, not functionality claimed by the current verified ERC-721 deployment. - -### Commitment binding - -A bid commitment binds the domain tag, Starknet chain ID, AuctionHouse address, auction ID, bid amount, random nonce, claim handle, and NFT recipient. Recovery material is also bound to network, chain ID, deployment, and auction ID before reveal or claim. - -### Contract invariants - -- Only the configured STRK20 pool may call `privacy_invoke`. -- Ingress is accounted from the helper's actual STRK balance delta. -- Every accepted bidder locks the same cap. -- Bidder count and settlement work are bounded. -- NFT custody is established during auction creation and delivery is part of settlement. -- Claims are one-time and commitment-bound. -- All `u256 → u128` conversions are checked. -- External interactions follow checks-effects-interactions and reentrancy protection. - -## Privacy boundary - -| Public | Private before reveal | -| -------------------------------------------------------- | --------------------------------------------------- | -| Auction terms, NFT, reserve, cap, and deadlines | Bid amount and random bid nonce | -| STRK20 registration and public deposits | Private-note ownership and note-selection witnesses | -| Identical collateral transfer amount | Wallet viewing key and proof witness | -| Bid count and transaction timing | Claim secret | -| Revealed bids, winner, and clearing price | Bidder's main-wallet linkage inside the pool | -| Withdrawals, open-note edges, and direct lifecycle calls | Recovery plaintext outside its active in-memory use | - -Ready X owns private-note discovery, proof generation, signing, and private transaction submission. CipherBid never requests a viewing key or private-note witness. The browser does hold the active bid credential briefly to construct the interaction and encrypt an exportable recovery bundle; plaintext secrets must never enter browser storage, logs, analytics, URLs, clipboard, Git, or a backend. - -## Threat model and limitations - -CipherBid protects the bid amount until reveal and prevents an unfunded winner, but it does not provide perfect anonymity: - -- deposits, withdrawals, open-note amounts, timing, and public account activity remain visible; -- distinctive amounts or tightly timed setup can shrink the anonymity set; -- opening a channel near a public action may create timing linkage; -- every valid reveal makes the bid amount public by design; -- a malicious web page could substitute dapp-built Wallet API actions before the wallet prompt, so users must verify target and amount in Ready X; -- wallet, prover, relayer, RPC, screening, and browser availability remain operational dependencies; -- private balances cannot be verified by the dapp; -- the present contracts and signer configuration are a bounded hackathon demo, not an audited production deployment. - -STRK20's auditor disclosure mechanism can reveal activity under its protocol policy; a viewing key can read but cannot spend funds. - -## Repository layout +| Area | Implementation | +| --- | --- | +| Contracts | Cairo, OpenZeppelin Contracts, Scarb, Starknet Foundry | +| Web | Next.js, React, strict TypeScript, Tailwind CSS | +| Chain access | starknet.js and Starknet Wallet API | +| Verification | Vitest, Testing Library, Playwright, Cairo tests | +| Hosting | Static Next.js export on GitHub Pages | ```text -contracts/ Cairo AuctionHouse and DemoERC721 -web/ Next.js application and Wallet API integration -context/ Product, architecture, security, and stack decisions -docs/evidence/ Secret-free specifications and public readbacks -strk20.json Final verified submission metadata +contracts/ AuctionHouse, ERC-721 demo asset and contract tests +web/ Public chain reader, wallet actions and encrypted recovery +context/ Architecture, product scope and security boundaries +docs/evidence/ Mainnet receipts, deployment records and submission evidence ``` -## Local development - -### Prerequisites +There is no application database, custodial backend, custom prover or custom privacy cryptography. -- Node.js 24 -- pnpm 10 -- Cairo compiler 2.20.0 -- Scarb 2.20.1 -- Starknet Foundry 0.63.0 -- Ready X for real STRK20 wallet flows +## Run locally -### Install and configure +Use Node.js 24 and the pinned package manager. From the repository root: ```bash npx --yes pnpm@10.18.1 --dir web install --frozen-lockfile cd web npx --yes pnpm@10.18.1 exec tsx scripts/configure-mainnet-env.ts \ - --deployment-record ../docs/evidence/mainnet/deployment.json \ - --write -``` - -The configuration command writes only public deployment values and refuses to overwrite an existing `.env.local`. - -### Run - -```bash -cd web -npx --yes pnpm@10.18.1 exec next dev --webpack -p 4110 -``` - -Open: - -- `http://127.0.0.1:4110/` — auction browser -- `http://127.0.0.1:4110/auction?id=1` — public auction reader; ID `1` remains unavailable until a real auction exists -- `http://127.0.0.1:4110/create` — seller creation flow -- `http://127.0.0.1:4110/demo/setup` — Ready X bidder shielding - -### Contract checks - -```bash -cd contracts -scarb fmt --check -scarb build -snforge test -``` - -### Web checks - -```bash -npx --yes pnpm@10.18.1 --dir web format:check -npx --yes pnpm@10.18.1 --dir web lint -npx --yes pnpm@10.18.1 --dir web typecheck -npx --yes pnpm@10.18.1 --dir web test -npx --yes pnpm@10.18.1 --dir web test:e2e -npx --yes pnpm@10.18.1 --dir web pages:verify -npx --yes pnpm@10.18.1 --dir web build -CIPHERBID_PAGES_BUILD=1 npx --yes pnpm@10.18.1 --dir web build -``` - -## Operational scripts - -Mainnet write scripts default to plan-only and require explicit `--execute`: - -```bash -cd web -npx --yes pnpm@10.18.1 run deploy:mainnet -npx --yes pnpm@10.18.1 run auction:preflight:mainnet -npx --yes pnpm@10.18.1 exec tsx scripts/create-mainnet-auction.ts --auction-id + --deployment-record ../docs/evidence/mainnet/deployment.json --write +npx --yes pnpm@10.18.1 exec next dev --webpack --hostname 127.0.0.1 -p 4110 ``` -Do not add `--execute` until the printed plan, signer, network, public bidder readiness, recovery destination, and remaining release budget have been verified. Never commit `.env.local`, wallet state, recovery bundles, runtime evidence, browser state, or signing material. - -## Evidence - -- [Evidence index](docs/evidence/README.md) -- [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) -- [Final public demo video evidence](docs/evidence/submission/demo-video.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) -- [Security invariants](docs/evidence/task-2-4-security-invariants.md) -- [Hackathon requirements matrix](docs/evidence/hackathon-requirements-matrix.md) -- [Sepolia rehearsal](docs/evidence/sepolia/demo-runbook.md) +The configuration command writes public deployment values and refuses to overwrite an existing `.env.local`. Open `http://127.0.0.1:4110/auction?id=1788040057342` to inspect the published auction without connecting a wallet. The homepage demo link always opens the public mainnet site. -`strk20.json` contains two verified contracts, five successful pool-touching CipherBid transactions, the clean-browser-verified auction URL, and the public 2:24 YouTube demo. +[Local development](docs/local-development.md) covers checks, Pages builds, the pinned Cairo toolchain and [unresolved server-side dependency advisories](docs/local-development.md#dependency-advisory-caveat). [CI](https://github.com/SourceSenseiTheRealOne/cipherbid/actions/workflows/ci.yml) runs web and contract gates; [the deployment workflow](.github/workflows/deploy-pages.yml) publishes `main` to the existing `/cipherbid` site. -## Scope +## Limits -The sprint MVP supports one STRK payment token, ERC-721 assets, one-unit Vickrey auctions, and at most 32 bidders. It intentionally excludes a broad marketplace, first-price or multi-unit auctions, ERC-1155, off-chain delivery, user accounts, a database, a custom prover, and custom privacy cryptography. +The implementation supports one-unit ERC-721 auctions paid in STRK. Multi-unit token launches remain research, not shipped functionality. Deposits, timing, equal-cap transfers, revealed bids and open-note edges are public; this does not provide permanent bid secrecy or perfect anonymity. -## License +Wallet, prover, relayer, RPC and screening services remain dependencies. Pool fees can exceed small claims: the recorded demo seller claim paid a `6 STRK` pool fee to recover `2 STRK`, excluding authorization gas. Mainnet execution proves the bounded lifecycle, not economic viability or audited security. Never use funds you cannot afford to lose. -[MIT](LICENSE) +[MIT license](LICENSE) · [Third-party notices](THIRD_PARTY_NOTICES.md) · [Full evidence index](docs/evidence/README.md) diff --git a/context/stack.md b/context/stack.md index b2f1c8c..0737448 100644 --- a/context/stack.md +++ b/context/stack.md @@ -7,6 +7,6 @@ - Cairo, Scarb 2.20.1, Starknet Foundry 0.63.0 - OpenZeppelin Contracts for Cairo 3.0.0 - Vitest, Testing Library, Playwright -- GitHub Actions and Vercel +- GitHub Actions and GitHub Pages (static Next.js export) The original starter pin (Next.js 16.0.8 / React 19.2.1) was rejected after a fresh production audit identified known RSC and later Next.js advisories. Pin dependencies and commit lockfiles. Re-verify STRK20 package, wallet, pool, and provider compatibility before every deployment. diff --git a/docs/assets/auction-preview.png b/docs/assets/auction-preview.png new file mode 100644 index 0000000..e9d5384 Binary files /dev/null and b/docs/assets/auction-preview.png differ diff --git a/docs/engineering.md b/docs/engineering.md new file mode 100644 index 0000000..e34aee6 --- /dev/null +++ b/docs/engineering.md @@ -0,0 +1,61 @@ +# CipherBid engineering notes + +CipherBid implements a one-unit Vickrey auction for ERC-721 assets. Cairo contracts own custody and accounting; the browser reads public state and requests wallet actions. The implemented payment asset is STRK, with a maximum of 32 bidders per auction. + +## Funding without exposing the bid + +A commitment hides a value but does not prove that its author can pay. Escrowing the exact bid funds it, but the token transfer from STRK20 into the helper contract is a public boundary. + +CipherBid accepts the same public cap from every bidder. In the recorded mainnet auction, both participants locked `4 STRK`, then revealed `2 STRK` and `4 STRK`. The bid amount was concealed until reveal without pretending the helper's collateral balance was encrypted. This trades capital efficiency for a simple, enforceable funding rule. + +The [`privacy_invoke` entrypoint](../contracts/src/lib.cairo) accepts only the configured pool. It validates the operation, deadline, bidder bound and uniqueness, then requires the observed STRK balance to equal the previous accounted balance plus the cap before recording ingress. Claims likewise reject balance drift. Unexpected direct token transfers can therefore stop these paths rather than being silently treated as auction collateral. + +## Auction state and atomic delivery + +Creation transfers the NFT into contract custody. During bidding, the contract records commitments and claim handles, not bid amounts. Reveal checks the commitment and recipient during the configured reveal window. After that window, settlement scans the bounded bid set. + +The highest revealed bid wins if it meets the reserve. The clearing price is the greater of the reserve and second-highest revealed bid; an equal highest bid does not replace an earlier accepted winner. If no bid meets the reserve, settlement returns the NFT to the seller. + +Settlement writes the outcome, transfers the NFT and checks the resulting owner in one Starknet transaction. A failed transfer or owner assertion reverts the transaction. This is the precise meaning of atomic delivery, not a guarantee of service availability or audited security. + +The [lifecycle specification](evidence/task-2-3-lifecycle-specification.md) records the phase and deadline rules. The [Cairo implementation](../contracts/src/lib.cairo) is authoritative; the [TypeScript settlement model](../web/src/features/auction/auctionLifecycle.ts) supports client reasoning and tests. + +## Claims and conservation + +Each accepted bidder funds the full cap. A losing bidder can recover that cap; a winner can recover the cap minus the clearing price. The seller's entitlement is the clearing price. The contract binds claims to their handles, checks the claim secret and prevents repeated consumption. Seller proceeds additionally require authorization of the exact open note by the auction's seller. + +Payments return through STRK20 open-note claims. Open-note edges and their amounts are not secret. The economic result also depends on the live pool fee, which the UI reads rather than assuming a fixed rate. + +The [mainnet lifecycle](evidence/mainnet/auction-lifecycle.md) records all three completed claims and zero final actual/accounted house balances. The seller deliberately completed a `2 STRK` claim while the pool charged `6 STRK`; this demonstrated the lifecycle but was economically unfavorable. The historical amount is not a promise about future fees. + +## Credentials and wallet authority + +The [bid commitment](../contracts/src/commitment.cairo) binds chain ID, auction-house address, auction ID, amount, nonce, claim handle and NFT recipient under a domain tag. Recovery credentials also identify the network, deployment, auction and role so that importing a file does not authorize a different auction. + +The wallet keeps signing keys, viewing keys, private notes and proof witnesses. It owns note discovery, proving, signing and submission. The app holds its active bid/claim credentials in browser memory, encrypts a user-downloaded recovery bundle and verifies that it can be imported before submission. It does not put plaintext credentials in browser storage, URLs, logs or a backend. See [recovery bundle validation](../web/src/features/credentials/recoveryBundle.ts). + +That division limits custody exposure but does not remove frontend risk. A compromised page can substitute an action descriptor before the wallet prompt. Users still need to verify the target and value shown by their wallet; strong recovery passwords and possession of the encrypted file also matter. + +## Public reads and confirmation + +The [auction reader](../web/src/features/auction/auctionReader.ts) checks the deployed class hash, configured pool, token and bidder bound. It then reads auction configuration, state, bids and NFT ownership, rejecting a custody mismatch instead of rendering an assumed result. + +The [receipt verifier](../web/src/features/transactions/receiptVerifier.ts) requires successful accepted execution, the expected AuctionHouse event, a pool event where required, and a matching state readback. A timeout is an unconfirmed result, not proof that the transaction failed. The recorded creation flow recovered its public event and NFT custody after a lost RPC response rather than replaying the write. + +Published receipt links are scoped to the known mainnet auction. Current state still comes from RPC. Neither fixture tests nor a static screenshot substitute for the [transaction ledger](evidence/mainnet/transactions.md). + +## Deployment and verification + +Next.js exports the public frontend to GitHub Pages under `/cipherbid`. The deployment workflow publishes only public network configuration. There is no application server or database; the browser talks to public RPC and a supported wallet. The repository name and live URL remain stable because the sprint registry and demo video already reference them. + +The web gates cover formatting, lint, strict types, unit/integration tests, Chromium journeys, a normal production build and the static Pages build. Cairo gates cover formatting, compilation and contract tests. The [security invariants](evidence/task-2-4-security-invariants.md) describe the intended negative cases; [local development](local-development.md) lists commands. + +The [current dependency advisory caveat](local-development.md#dependency-advisory-caveat) records unresolved server-side Next.js/sharp findings separately from the static Pages deployment. Passing tests are not a clean dependency audit. + +Source checks, a browser read and the historical mainnet lifecycle are different evidence. This repository does not claim a third-party audit or production readiness. Multi-unit token launches would need new allocation and settlement contracts and are outside the current deployment. + +## Privacy limits + +Bids are public after reveal. Deposits, withdrawals, timing, bid count, equal collateral, settlement, direct account calls and open-note edges remain observable. Channel setup and distinctive activity can create links between otherwise private actions. STRK20 also has its own screening and selective-disclosure policy. + +Wallet, prover, relayer, screening and RPC availability are external dependencies. No custom prover or privacy cryptography is implemented here. See the [project security context](../context/security.md) and [privacy context](../context/privacy.md) for the complete boundary. diff --git a/docs/evidence/README.md b/docs/evidence/README.md index 1f84814..8c71094 100644 --- a/docs/evidence/README.md +++ b/docs/evidence/README.md @@ -54,6 +54,8 @@ Sepolia evidence is rehearsal evidence only. It does not establish mainnet priva ## Submission controls +The [organizer hub readback](submission/hub-status.md) resolves the earlier indexing-pending status. The hub marks CipherBid finished with demo, video and mainnet requirements satisfied; this does not establish an award. + | Artifact | Scope | | ---------------------------------------------------------------------- | ------------------------------------------------------------------ | | [`hackathon-requirements-matrix.md`](hackathon-requirements-matrix.md) | Official requirement-to-evidence mapping and truthfulness controls | diff --git a/docs/evidence/hackathon-requirements-matrix.md b/docs/evidence/hackathon-requirements-matrix.md index 2b2c5d1..44bebe0 100644 --- a/docs/evidence/hackathon-requirements-matrix.md +++ b/docs/evidence/hackathon-requirements-matrix.md @@ -1,5 +1,7 @@ # CipherBid Official Hackathon Requirement Matrix +Current organizer readback: the hub lists CipherBid as `finished` with demo, video and mainnet requirements satisfied. See [the dated, revision-pinned readback](submission/hub-status.md). This resolves the earlier refresh-pending status; it is not an award claim. + **Status:** Official-source and evidence-routing baseline **Official-source snapshot verified:** 2026-08-27T10:12:47Z @@ -72,11 +74,11 @@ Planned evidence summaries are reviewed, secret-free indexes of public facts. Ra | `TX-04` | Official | If project contracts are listed, each qualifying transaction must carry an event from one of those contracts; touching the pool only through someone else's contract is insufficient.[5] | List the deployed CipherBid auction house and decode its ABI-frozen event from every applicable candidate transaction. | `E-DEPLOY`, `E-TX` | Receipt includes a matching event whose emitter is the listed CipherBid auction-house address. | Satisfied | | `TX-05` | CipherBid control | Applicable listed transactions must emit the lifecycle-specific CipherBid auction-house event and produce the expected state delta. | Both private ingresses must emit the accepted-bid event; the qualifying claim must emit its claim event. Exact event names/selectors are frozen with the final ABI rather than invented here. | `E-TX`, `E-LIFECYCLE` | Emitter, selector, decoded fields, auction ID, and post-state all agree with the expected transition. | Satisfied | | `CONTRACT-01` | Official | `contracts` is optional, but listed deployed addresses are detected and shown with their network.[4][5] | List the verified AuctionHouse and DemoERC721 only after class/config/source identity readback. | `E-DEPLOY`, root `strk20.json` `contracts` | Both addresses exist on mainnet and match the reviewed artifacts/configuration. | Satisfied | -| `DEMO-01` | Official | `demo_url` is optional only when the hub discovers the demo automatically; discovery preference is explicit `strk20.json`, GitHub Pages, repository Website, then latest successful deployment.[4][5] | Set the repository Website and also set `demo_url` for deterministic discovery before closure. | `E-DEMO` | Hub row links to the intended public production demo. | Satisfied; hub refresh pending | +| `DEMO-01` | Official | `demo_url` is optional only when the hub discovers the demo automatically; discovery preference is explicit `strk20.json`, GitHub Pages, repository Website, then latest successful deployment.[4][5] | Set the repository Website and also set `demo_url` for deterministic discovery before closure. | `E-DEMO` | Hub row links to the intended public production demo. | Satisfied (hub readback) | | `PAYOUT-01` | Official | A winning team must provide one payout address.[4] | Designate one public payout address through organizer communication only after operator review. | `E-PAYOUT` | Exactly one address is supplied; no signing or recovery material is disclosed. | Pending organizer request | | `DOC-01` | Official | README coverage should explain what the project does, why privacy is needed, how to run it locally, and the mainnet contract addresses.[5] | The root README documents architecture, exact STRK20 integration, browser-wallet flow, setup, deployment, demo, threat model, privacy boundary, and limitations. | `E-DOCS`, `E-DEPLOY` | A clean checkout can follow setup/build instructions and find verified mainnet addresses. | Satisfied | | `LINK-01` | Official | Every public URL must be link-checked before submission.[5] | Validate repository, demo, video, explorer, contract, transaction, and documentation links from a clean unauthenticated browser/session. | `E-DEMO`, `E-VIDEO`, public evidence | All required URLs return the intended public resource. | Satisfied | -| `INDEX-01` | Official | The hub automatically shows missing demo, video, and mainnet requirements.[4][5] | Treat hub requirements as a final independent readback, not as the source of transaction truth. | Public hub row plus `E-DEMO`, `E-VIDEO`, `E-TX` | Hub reports demo, video, and mainnet requirements satisfied after final refresh. | Pending | +| `INDEX-01` | Official | The hub automatically shows missing demo, video, and mainnet requirements.[4][5] | Treat hub requirements as a final independent readback, not as the source of transaction truth. | Public hub row plus `E-DEMO`, `E-VIDEO`, `E-TX` | Hub reports demo, video, and mainnet requirements satisfied after final refresh. | Satisfied (hub readback) | ## Scoring matrix @@ -125,7 +127,7 @@ CipherBid is submission-ready only when all rows below are true simultaneously: - [x] Canonical seller/two-bidder/observer lifecycle and value conservation are independently verified. - [x] README, setup, threat model, privacy limitations, demo, and mainnet addresses are complete. - [x] All public links and final quality/security gates pass on the exact final commit. -- [ ] The hub reports demo, video, and mainnet requirements satisfied after refresh. +- [x] The hub reports demo, video, and mainnet requirements satisfied after refresh; see the later [dated readback](submission/hub-status.md). - [x] All required evidence is present before **August 31, 2026 at 23:59 UTC**. ## Program facts that are not implementation gates diff --git a/docs/evidence/submission/hub-status.md b/docs/evidence/submission/hub-status.md new file mode 100644 index 0000000..022698c --- /dev/null +++ b/docs/evidence/submission/hub-status.md @@ -0,0 +1,25 @@ +# Organizer hub readback + +Public readback on September 24, 2026, from the STRK20 Private Sprint organizer repository: + +- [Project index at `4c625bec`](https://github.com/starkience/strk20-hackathon/blob/4c625becb6b366ce3c26c7f6dc9b43bd320198f3/projects.json) +- [Registration source](https://github.com/starkience/strk20-hackathon/blob/4c625becb6b366ce3c26c7f6dc9b43bd320198f3/registry.json) + +The entry for `https://github.com/SourceSenseiTheRealOne/cipherbid` reports: + +| Field | Observed value | +| --- | --- | +| Status | `finished` | +| Demo requirement | `true` | +| Video requirement | `true` | +| Mainnet requirement | `true` | +| Verified transactions | `5` | +| Indexed project revision | `13f25cc56ce8a45fa9646365dd923508835f3b16` | +| Demo | `https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342` | +| Video | `https://youtu.be/pYZk6KXko7o` | + +The transaction list contains five unique hashes, each marked `ok`, `pool` and `mine`. They match the qualifying bid and claim transactions in [`strk20.json`](../../../strk20.json) and the [mainnet ledger](../mainnet/transactions.md). + +This later readback resolves the old “hub refresh pending” entries in the [requirements matrix](../hackathon-requirements-matrix.md). It records the organizer's published status; it does not establish prize placement, an audit, production readiness or new blockchain execution. The original August deployment and transaction evidence retains its original dates and identities. + +The public homepage and settled auction were also opened in a clean browser during this review. Both returned HTTP 200 without page errors. The auction displayed sold state, a `2 STRK` clearing price, verified NFT custody and claimed seller proceeds. No wallet was connected and no transaction was submitted. diff --git a/docs/local-development.md b/docs/local-development.md new file mode 100644 index 0000000..9b6aadc --- /dev/null +++ b/docs/local-development.md @@ -0,0 +1,75 @@ +# Local development + +Run commands from the repository root unless a different directory is shown. The public demo uses Starknet mainnet; opening its read-only page does not require a wallet or a private key. + +## Dependency advisory caveat + +The September 24, 2026 production dependency audit reports two critical Next.js advisories and one high sharp advisory in the unchanged lockfile (`next@16.3.2`, `sharp@0.35.3`): + +- [Windows-hosted Next.js server RCE](https://github.com/advisories/GHSA-p293-qw3h-jr36). +- [Next.js AVIF image-optimization RCE](https://github.com/advisories/GHSA-2xp9-vwfh-vxw4). +- [sharp/libheif image-decoding vulnerabilities](https://github.com/advisories/GHSA-rgj7-g3m4-5g8c). + +The public deployment is a static GitHub Pages export, not a Next.js server or image-optimization API. That removes those server endpoints from the hosted architecture; it does not make the dependency audit clean. Do not expose a local Next.js server to the network or process untrusted images with this toolchain. Loopback binding below limits exposure but is not a vulnerability fix. + +The advisories identify Next.js `16.3.3` and sharp `0.35.4` as patched minimums. Upgrade and rerun the full gates in a separate dependency-maintenance change before server deployment; this presentation refresh deliberately preserves package and lockfile identities. + +## Toolchain + +The web package pins pnpm `10.18.1` and expects Node.js 24. CI pins Node.js `24.13.1`. Contract CI pins Scarb `2.20.1`, Starknet Foundry `0.63.0` and Universal Sierra Compiler `2.10.0`; package locks remain committed. + +On Windows, use WSL distro **Ubuntu** for Cairo. Install the pinned tools in that distro and ensure `scarb` and `snforge` are on its PATH before running contract checks. The [CI workflow](../.github/workflows/ci.yml) records the pinned setup and Foundry archive checksum. A Windows Node dependency tree should not be reused as a Linux dependency tree. + +## Install and configure public reads + +```bash +npx --yes pnpm@10.18.1 --dir web install --frozen-lockfile +cd web +npx --yes pnpm@10.18.1 exec tsx scripts/configure-mainnet-env.ts \ + --deployment-record ../docs/evidence/mainnet/deployment.json --write +npx --yes pnpm@10.18.1 exec next dev --webpack --hostname 127.0.0.1 -p 4110 +``` + +The configuration helper writes public addresses, class hash, network and RPC settings. It refuses to overwrite an existing `.env.local`; do not delete an existing configuration to bypass that check. Never add wallet keys or recovery secrets to it. + +Open `http://127.0.0.1:4110/auction?id=1788040057342` for the published mainnet auction. The homepage has a separate arbitrary-auction reader, while its `Open live auction` shortcut opens the canonical public mainnet URL. `/create` and `/demo/setup` contain wallet write flows; do not submit them merely to inspect the project. + +## Web checks + +From the repository root: + +```bash +npx --yes pnpm@10.18.1 --dir web format:check +npx --yes pnpm@10.18.1 --dir web lint +npx --yes pnpm@10.18.1 --dir web typecheck +npx --yes pnpm@10.18.1 --dir web test +npx --yes pnpm@10.18.1 --dir web exec playwright install chromium +npx --yes pnpm@10.18.1 --dir web test:e2e +npx --yes pnpm@10.18.1 --dir web ci:verify +npx --yes pnpm@10.18.1 --dir web pages:verify +npx --yes pnpm@10.18.1 --dir web build +CIPHERBID_PAGES_BUILD=1 npx --yes pnpm@10.18.1 --dir web build +``` + +The last command uses POSIX shell environment syntax, available in Bash, Git Bash and WSL. The Pages build requires the public configuration above. It exports under `/cipherbid` and must be served with that base path. The E2E configuration owns loopback port `4173`, uses its explicit Sepolia test configuration and refuses to reuse an existing server. Stop only a server you own before running it. Browser fixtures do not establish fresh mainnet transaction success. + +## Contract checks + +Inside the Linux/WSL checkout, from the repository root: + +```bash +cd contracts +scarb fmt --check +scarb build +snforge test +``` + +These are local contract gates, not deployment or mainnet execution. Do not change compiler versions to make a presentation-only update pass: source/class identity matters for the existing deployment. + +## Transaction operations + +The deployment and auction-creation tools are separate from public inspection. Their default plan-only mode does not authorize execution. Mainnet writes require fresh human approval of the network, addresses, spend ceiling and expected state before any `--execute` command. + +Ready X was the wallet used for the published lifecycle. Check current wallet capabilities before attempting a new one; public registration or deposit history does not prove a wallet's spendable private balance. Keep signer state and encrypted recovery files outside the repository, and never paste their contents into logs or issues. + +See [the deployment record](evidence/mainnet/deployment.md), [the historical lifecycle](evidence/mainnet/auction-lifecycle.md) and [the evidence index](evidence/README.md). They preserve what was exercised, not an instruction to replay it. diff --git a/web/src/app/page.tsx b/web/src/app/page.tsx index a68dc92..56d876e 100644 --- a/web/src/app/page.tsx +++ b/web/src/app/page.tsx @@ -39,7 +39,10 @@ export default function Home() { Create an auction - + Open live auction diff --git a/web/tests/unit/Home.test.tsx b/web/tests/unit/Home.test.tsx index c17ec91..1ba3918 100644 --- a/web/tests/unit/Home.test.tsx +++ b/web/tests/unit/Home.test.tsx @@ -3,6 +3,15 @@ import { describe, expect, it } from 'vitest' import Home from '@/app/page' describe('CipherBid home', () => { + it('links directly to the verified mainnet auction', () => { + render() + + expect(screen.getByRole('link', { name: 'Open live auction' })).toHaveAttribute( + 'href', + 'https://sourcesenseitherealone.github.io/cipherbid/auction/?id=1788040057342', + ) + }) + it('presents the shipped product routes without mock auction data', () => { render()