# VOW

Verifiable Operator Warrants for confidential delegated procurement on STRK20.

Status: the matching VowVault class and contract are verified on Starknet mainnet. A controlled 0.1 STRK mandate was created, funded and fully reserved on that deployment. The reservation is open; Paid and Reclaimed are both zero. No supplier collection, STRK20 note credit, compatibility pass or audit is claimed. Ready X 5.33.9 advertises Wallet API 0.10.3 and returned a real prepared action list; VOW rejected its omitted optional screening suffix locally before any supplier signature or collection transaction. The decoder compatibility patch is under regression verification.

| Live deployment | Starknet mainnet value |
|---|---|
| VowVault | `0x641ca5237870312273ed2cd693372ee49e103d5c585af6185324f3662e15227` |
| Class hash | `0x3c85f692be0a2280bc85fc9802019121a8b52ef4de0db9273c3806f7355ce14` |
| STRK20 pool | `0x40337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a` |
| Deployment account | `0x3f3cc7727c66634967621dc8d4697f1bfd6c29f81757496a4783bf5c90deb89` |

Release gates: **0 of 5 pass.** Deployment, mandate creation, funding and reservation do not satisfy G0 without one genuinely successful destination-bound supplier collection through the live STRK20 pool. G1 cannot be declared complete while G0 is unresolved; G2–G4 also remain open.

The product lets an owner commit one-use purchase permissions, an operator reserve an approved purchase, and the supplier collect into its exact signed STRK20 note. Unused permissions remain unpublished: the chain stores a commitment root, not the supplier list.

## Implemented scope

- `VowVault`: isolated mandates, a 16-slot padded permission commitment tree, operator-signed reservations bounded by the committed cap and available budget, single-use permissions that expiry never re-arms, separate Funded/Reserved/Paid/Reclaimed accounting, revocation that preserves open supplier claims, owner recovery that excludes outstanding reservations, and pool-only destination-bound collection. No upgrade path, no generic external call, no admin sweep of accounted funds.
- `CollectionProbe`: one owner-funded reservation, one fixed supplier claim key, one pinned token/pool, exact received funding, destination-bound claim, and owner recovery after expiry. IDs are fixed to one; this is not VowVault.
- TypeScript claim encoding/signatures, integer amount utilities, a read-only wallet API version probe, and a strict prepared-call decoder pinned to the observed pool class.
- Cairo tests for funding, authorization, rollback, deadlines, recovery, donations, and replay; cross-language claim vectors; selected mutation checks.
- A collection preparation controller and local review page, with pinned-block contract checks, exact-note signature verification, invalidation, bounded waits, and final preparation review. The product claim route adds guarded, journaled wallet submission; the diagnostic workbench does not submit.
- A separate local supplier-key page with encrypted backup, required restore before sharing the key, exact-claim review/signing, and session locking.
- Integer-only test-budget assessment that requires principal, every fee category, and a fresh STRK/USD quote before reporting whether a proposed total fits its cap.
- Read-only collection receipt verification, an exact call/proof submission review, and a durable attempt journal with Web Locks coordination. The collection page can request the exact reviewed wallet call only when a matching, fresh local budget manifest is present; no approved manifest is shipped.
- A local `/claim/:reservationId` VowVault path that reads the reservation and pinned classes before enabling wallet preparation or supplier signature input, plus `/verify/:txHash`, which needs no wallet and requires the exact `ReservationClaimed` event, matching pool deposit, claimed reservation state and token-pull trace. Its preloaded real successful mainnet transaction is an unrelated negative control and is rejected as VOW evidence.
- A block-pinned public mainnet pool observation and its ABI. These reads are not VOW transaction evidence.

See [reproduction instructions](REPRODUCE.md), [compatibility](COMPATIBILITY.md), [threat model](THREAT_MODEL.md), and [claim evidence](evidence/claims.json).

## Public and private

| Information | Visibility |
|---|---|
| Experiment owner, funding amount, token, supplier claim key, deadline | Public on the live mandate and reservation |
| Collection note ID, amount, timing, and helper address | Public if collection occurs; zero collections exist today |
| Supplier signing key | Local; never requested in a URL or RPC call |
| Note ownership privacy | Depends on the actual STRK20 wallet/pool flow; not yet demonstrated by VOW |
| Unused procurement permissions | Not published by the protocol; only the commitment root is on chain |
| Exercised permission, its amount, supplier pseudonym and timing | Public once reserved |

Neither contract has a generic call, upgrade, donation sweep, or public supplier payout function. Because there is no sweep, tokens transferred to the vault outside `fund_mandate` are never counted as budget and are also never recoverable. Pool correctness, token behavior, wallet readiness, screening, and real note ownership remain integration dependencies. Do not fund the experiment before its compatibility and transaction preview are reviewed.

The deployed VowVault class hash and pool can be checked read-only with `npm run verify:vault`. The command rejects any ABI entrypoint outside the exact 14-function allowlist, including any generic drain, arbitrary external-call, root-replacement or upgrade entrypoint. This is a single-provider ABI observation, not an audit or proof that each allowlisted function is correctly implemented. For contract enforcement, `sh scripts/cairo.sh test` runs T-005 signature scope, T-002 proof/recipient binding, T-003 overspend, T-004 single-use and T-011 pool-only negatives against the real Cairo vault logic with synthetic token and pool contracts.

Ready advertises Wallet API 0.10.3, but live collection is still unverified. The probe review page is at `/collection` when running `npm run diagnostic`. Its authorized browser check verified desktop initial-state and invalid-input assertions; mobile checks did not complete; see [milestone evidence](evidence/collection-workbench-checks.json).

Run `npm run app` for the VowVault product routes at `http://127.0.0.1:4319`. `/` states the problem and links the screens, the shipped documents and the verifier. `/owner` builds a permission set locally, shows a preview of exactly what creation publishes and what it withholds before anything is created, downloads the encrypted backup, and unlocks that downloaded file again to prove it restores the previewed root before the creation call is enabled; it always reports Funded, Available, Reserved, Paid and Reclaimed as five separate values. `/operator` unlocks the committed set, checks it against the mandate root already on chain, and reserves one selected permission object; it has no field for a supplier key, token or deadline, and an edited permission object stops matching the committed root. `/verify` preloads the public T-017 negative-control transaction and verifies it without a wallet. The live controlled reservation opens at `/claim/0x45cc6c11f29f5fe7b53eee680c0626324e344af8d021ca7af58a1b1ecf2bb2b`; the page reads its 0.1 STRK amount, token and deadline from chain before wallet preparation and keeps every signature control disabled when Ready preparation fails.

Every write on those routes moves through one explicit state: READY, SIGNING, SUBMITTED, then CONFIRMED, REJECTED, REVERTED or UNKNOWN. A wallet timeout is UNKNOWN, never a retry; a late transaction hash is recorded against the same unresolved attempt so it can be reconciled against its public receipt. The public verifier likewise renders a missing or timed-out RPC fact as UNKNOWN, never as confirmation or contradiction. The shipped manifest pins the verified VowVault, while missing mandate, funding, reservation, proof, or budget prerequisites keep their dependent controls disabled. See [claim and verifier evidence](evidence/vault-claim-verifier-checks.json) and [product screen evidence](evidence/product-screen-checks.json).

Run `npm run supplier` to open the separate supplier tool at `http://127.0.0.1:4318/`. Its empty-state browser check passed. Backup restoration, signing and collection preparation are connected in a synthetic local integration test; the browser test generated no key and entered no secret. See [supplier milestone evidence](evidence/supplier-tool-checks.json).

Deployment-preview tooling builds deterministic UDC calldata and an exact principal-funding batch without signing or network access. It does not estimate fees or authorize spending. See [preview evidence](evidence/deployment-preview-checks.json).

Deployment preflight now reads public account, declaration, UDC, token and pool state at one block, preserving explicit absence separately from RPC failure. The local `/activation` page reads wallet deployment metadata on demand and verifies its derived account address before displaying the public result. Neither tool activates an account or estimates a fee. See [deployment-readiness evidence](evidence/deployment-readiness-checks.json).

The separate Ready setup account `0x5282ba58af3296b7c6bdb51dfb12789cbf4603799e7fc8baef6a9704de1679e` has accepted activation and privacy-registration receipts; it is not the deployment account above. Its owner outflow was 0.055724097349665504 STRK for activation plus 6.1 STRK transferred during **Enable private tokens**, for 6.155724097349665504 STRK total owner outflow. The registration receipt's 2.885883499721302016 STRK network fee was paid by a separate relayer and is not added to the owner total. The 6.1 STRK is an asset transfer into the setup flow, not asserted to be entirely fees; the pool's raw fee value would equal 6 STRK if it is STRK-denominated with 18 decimals, but its denomination and whether it is already represented in that transfer remain unverified.

The recorded deployment account paid 0.064153485960586256 STRK for activation, 25.754981174384634880 STRK for class declaration, and 0.062349799255757888 STRK for vault deployment: 25.881484459600979024 STRK in network fees. The subsequent mandate creation, atomic 0.1 STRK approve-and-fund, and reservation transactions paid another 0.470848776477080800 STRK in network fees. Those three product transactions establish a funded open reservation, but the PRD does not count them as qualifying pool collections. Supplier collection, wallet or prover charges, recovery reserve, and the collection protocol-fee path remain unexecuted or unverified. See the [deployment](evidence/vault-deployment-observation.json), [mandate](evidence/mandate-creation-receipt.json), [funding](evidence/mandate-funding-receipt.json), and [reservation](evidence/reservation-receipt.json) evidence.

The local `/deployment` page derives the predicted address and exact calls from public terms, checks the next declaration, deployment, or funding stage against current chain state, and asks the connected wallet for only that reviewed stage after explicit approval. It persists public recovery records before dispatch and requires exact transaction, receipt, fee, and post-state reconciliation before advancing. Declaration and deployment have completed and are pinned in the product manifest. The controlled mandate, funding and reservation were executed through the terminal with explicit resource bounds; the supplier page has not completed note preparation or collection.

The public presentation is a separate Next.js static export under `web/`. Run `npm ci` and `npm run dev` from that directory to open it at `http://127.0.0.1:4320`; set `NEXT_PUBLIC_VOW_APP_URL` when the functional product is hosted somewhere other than `http://127.0.0.1:4319`. The supplier-key tool remains isolated on its own origin and is never embedded in the presentation shell.

The current worktree checks must be rerun after the compatibility patch freezes. The committed clean-clone evidence predates the live deployment and must be refreshed before release; local test passes do not change the 0-of-5 release-gate result.
