diff --git a/docs/RFP-EVIDENCE-MAP.md b/docs/RFP-EVIDENCE-MAP.md new file mode 100644 index 00000000..17dc5bdd --- /dev/null +++ b/docs/RFP-EVIDENCE-MAP.md @@ -0,0 +1,230 @@ +# RFP Evidence Map — Supporting Work for the SCF x402 Facilitator RFP + +> **Purpose.** The Stellar Community Fund (SCF) Build Award +> *"x402 Facilitator with Bazaar Discovery Support"* asks for evidence of relevant +> experience: Soroban contract work, payment-lifeline infrastructure, TTL/rent +> handling on Stellar, and security/interface discipline. This repository is **not** +> the RFP deliverable. It is the prior work that positions the teams behind it to +> deliver the facilitator competently. This document maps what is actually shipped +> here to the RFP's §4 evidence criteria, states plainly what the boundary between +> this repo and the funded deliverable is, and is deliberately honest about maturity. + +--- + +## A. Flag Stale Doc: `RFP-ALIGNMENT.md` + +> [!WARNING] +> **`RFP-ALIGNMENT.md` is STALE. Do not rely on it for SCF evaluation evidence.** + +- `RFP-ALIGNMENT.md` is the legacy gap analysis written **prior to the + `x402-facilitator-stellar` implementation**. It was produced before the + facilitator's contracts, TTL/rent strategy, and the `scheme_upto_stellar.md` + draft existed, so it cannot reflect the current state of either this repository + or the facilitator work. +- At the time this map was written, `RFP-ALIGNMENT.md` is **not present at `main`** + in this repository. It exists only as a historical artifact. +- Anything it says about contract capability, deployment status, or RFP alignment + should be treated as out of date. **This document (`docs/RFP-EVIDENCE-MAP.md`) + supersedes it.** +- For the same reason, do not treat this map as a snapshot that stays true forever: + it describes `main` at commit `4b53779cb8c93adf937d7ef079cff2c9e26d3ed3` and the + deployments recorded in [`DEPLOYMENTS.md`](../DEPLOYMENTS.md). + +--- + +## B. Inventory of Shipped Work + +All artifacts below are in this repository on `main`. Relative links point to the +current source; they are the authoritative record, not this summary. + +### Contracts + +| Artifact | Location | What it is | +|---|---|---| +| `ReceiptAnchor` | [`contracts/receipt-anchor/`](../contracts/receipt-anchor/) | Anchors batched payment receipts as Merkle roots. Verifiably proves *"the agent was charged correctly"* without a trusted API. `anchor_batch` (≤ `MAX_BATCH_SIZE` = 1000), `verify_receipt` / `verify_receipt_by_root` (sorted-pair SHA-256, `MAX_PROOF_LEN` = 10), historical root ring buffer (100), rate-limiting via `min_anchor_interval`, `prune_batches` (contiguous-prefix cursor), public `extend_batch_ttl`. | +| `ReceiptShard` | [`contracts/receipt-shard/`](../contracts/receipt-shard/) | Wasm-optimised Merkle verifier: stack-allocated static proof buffer, pure-Wasm `sha2`, zero guest heap allocations for intermediate hashes, flat memory footprint at every tree depth (#139). | +| `RefundVault` | [`contracts/refund-vault/`](../contracts/refund-vault/) | Policy-bounded refunds over merchant float. Cumulative refunds with a hard `payment_amount` ceiling, refund window measured from `paid_at_ledger`, errors on double-refund (`AlreadyRefunded`) and over-ceiling (`ExceedsPayment`), timelocked `propose_policy`/`execute_policy`, `pause`/`unpause`, two-step admin transfer, public `extend_refund_ttl`. | +| `multisig-account` | [`contracts/multisig-account/`](../contracts/multisig-account/) | Threshold contract account implementing `__check_auth`; usable as the `merchant`/admin for either contract, so privileged calls require N signers with no contract changes. | +| Shared error enum + common crate | [`contracts/common/`](../contracts/common/) | Single `u32`-mapped error enum shared by both contracts (stable values, never renumbered) (#98). | + +### Deployments + +| Artifact | Location | What it is | +|---|---|---| +| Testnet deployment record | [`DEPLOYMENTS.md`](../DEPLOYMENTS.md) | Live contract IDs (`ReceiptAnchor` `CBHRJ…WPRV`, `RefundVault` `CCMBM…HRQA`), deployer/merchant addresses, wasm hashes, and every creation transaction, so the deployment is verifiable without trusting this repo. | +| Machine-readable env | [`deployments/testnet.env`](../deployments/testnet.env) | Generated by [`deploy.sh`](deploy.sh). | +| Deploy script | [`deploy.sh`](../deploy.sh) | Reproducible testnet/futurenet deploys, optional USDC settlement token. | +| Live verifier story | [`DEPLOYMENTS.md#verifying-the-live-deployment-yourself`](../DEPLOYMENTS.md#verifying-the-live-deployment-yourself) | Batch #1 anchored on-chain; read-only on-chain `verify_receipt` commands accept a genuine receipt and reject a forged one, and agree with the TypeScript SDK's sorted-pair convention. | + +Deployed 2026-07-22 on testnet, built for `wasm32v1-none`. Note the precise +version story, stated fully in [§ F](#f-honest-maturity-assessment): +the **live addresses run `0.1.0`** (built with `soroban-sdk` 27.0.0), while the +**repository now pins `soroban-sdk` 27.0.4** and the source is at `0.3.0`. There is +**no mainnet deployment**. + +### Tests + +| Category | Location | +|---|---| +| Unit tests | [`contracts/receipt-anchor/src/test.rs`](../contracts/receipt-anchor/src/test.rs), [`contracts/refund-vault/src/test.rs`](../contracts/refund-vault/src/test.rs) | +| Property-based fuzz suites | [`contracts/receipt-anchor/src/fuzz_test.rs`](../contracts/receipt-anchor/src/fuzz_test.rs), [`contracts/refund-vault/src/fuzz_test.rs`](../contracts/refund-vault/src/fuzz_test.rs) | +| Integration | [`contracts/refund-vault/tests/integration_test.rs`](../contracts/refund-vault/tests/integration_test.rs) | +| Multisig-admin integration | [`contracts/receipt-anchor/tests/multisig_admin_anchor.rs`](../contracts/receipt-anchor/tests/multisig_admin_anchor.rs), [`contracts/refund-vault/tests/multisig_admin_vault.rs`](../contracts/refund-vault/tests/multisig_admin_vault.rs) | +| Re-entrancy tests | [`contracts/refund-vault/src/reentrancy_tests.rs`](../contracts/refund-vault/src/reentrancy_tests.rs) | +| Token-agnostic tests (0- and 2-decimal assets) | [`contracts/refund-vault/src/token_agnostic_tests.rs`](../contracts/refund-vault/src/token_agnostic_tests.rs) | +| Known-answer / vector tests | [`contracts/receipt-anchor/src/vectors.rs`](../contracts/receipt-anchor/src/vectors.rs), [`contracts/refund-vault/src/refund_vectors.rs`](../contracts/refund-vault/src/refund_vectors.rs) | + +Fuzz suites assert invariants after every randomised step: pruning stays a +contiguous prefix, Merkle verification rejects every wrong proof shape, vault +float always equals `deposits − refunds − withdrawals`, and a `payment_ref` can +never be refunded twice. CI runs a bounded budget; longer local profiles are +documented in [`README.md`](../README.md#testing). + +### TTL / rent strategy + +| Artifact | Location | What it is | +|---|---|---| +| Storage & rent audit | [`docs/storage-audit.md`](../docs/storage-audit.md) | Entry-by-entry storage-class analysis (persistent vs temporary), rent costing, and the TTL policy (~30 days ≈ 518,400 ledgers before archival eligibility) for batch and refund records. | +| TTL extension surface | `ReceiptAnchor::extend_batch_ttl`, `RefundVault::extend_refund_ttl` | Public, anyone-callable TTL bumps so active records are not archived. | +| Prune/reclaim paths | `ReceiptAnchor::prune_batches` | Contiguous-prefix pruning to reclaim rent; never removes a middle batch while older ones remain readable. | +| Window-sized guard TTL | [`docs/SECURITY_MODEL.md`](../docs/SECURITY_MODEL.md#replay-attacks) | The double-refund guard's TTL is sized to the merchant's `refund_window_ledgers` (max network TTL when unbounded), so the guard cannot expire while `refund` would still accept a call (#243). | +| Deliberate storage-class choice for `upto` | [`docs/ADR-002-upto-scheme.md`](../docs/ADR-002-upto-scheme.md#storage-ttl-and-rent) | Open `upto` authorizations would be **temporary** storage keyed to their own expiry — a deliberate difference from persistent refund records. | + +### ADRs, events policy, and CI + +| Artifact | Location | What it is | +|---|---|---| +| ADR-001 — sorted-pair Merkle | [`docs/ADR-001-merkle-structure.md`](../docs/ADR-001-merkle-structure.md) | Proof encoding convention (no left/right position bits). | +| ADR-002 — `upto` settlement on Stellar | [`docs/ADR-002-upto-scheme.md`](../docs/ADR-002-upto-scheme.md) + [`docs/scheme_upto_stellar.md`](../docs/scheme_upto_stellar.md) | Draft Stellar `upto` scheme in the upstream x402 format; a direct RFP deliverable link (see [§ E](#e-genuine-connections)). | +| ADR-003 — immutability | [`docs/ADR-003-upgradeability.md`](../docs/ADR-003-upgradeability.md) | Both contracts ship **no** upgrade entry point / `update_current_contract_wasm`; deliberate security property with a written migration runbook. | +| ADR-004 — optional on-chain Bazaar registry | [`docs/ADR-004-bazaar-discovery-registry.md`](../docs/ADR-004-bazaar-discovery-registry.md) | Full design + cost model (commitment hashes, ~240 bytes/entry, per-year rent) for the RFP's optional on-chain registry; recommendation is **DO NOT SHIP** (keep off-chain) (see [§ E](#e-genuine-connections)). | +| Events policy | [`docs/EVENTS.md`](../docs/EVENTS.md) | Event topics/shapes are a stable public interface; any change to a topic tuple is breaking. | +| Threat model | [`docs/SECURITY_MODEL.md`](../docs/SECURITY_MODEL.md) | Trust assumptions, attack vectors/mitigations, balance invariants, audit-readiness pointer to [`docs/AUDIT.md`](../docs/AUDIT.md). | +| CI pipeline | [`.github/workflows/ci.yml`](../.github/workflows/ci.yml) | Changelog + version-matching gate, `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, `cargo test --workspace`, budget-measurement harness, and release wasm builds with **size-budget enforcement** (`.wasm-budget.json`) plus artifact upload. | + +--- + +## C. Mapping to SCF RFP §4 Criteria + +§4 asks for evidence of relevant *capability*. Each row links the criterion to the +concrete shipped artifact, not to a claim. + +| §4 Criterion | Evidence in this repo | Where | +|---|---|---| +| **Soroban contract experience** | Two production-shaped contracts (`ReceiptAnchor`, `RefundVault`) plus `ReceiptShard` and `multisig-account`, pinned to `soroban-sdk` 27.0.4 (`wasm32v1-none`). Shipment-grade traits: admin auth via `require_auth`, `#[contracterror]`/`#[contractevent]` typed surface, `contractmeta` build provenance (`GIT_SHA`, `commit_dirty`) failing loudly when the hash is unresolvable. | `contracts/*`, [`docs/contracts.mdx`](contracts.mdx), [`README.md`](../README.md#contracts) | +| **Payment infrastructure** | Receipt anchoring that lets an agent cryptographically verify a charge with no trusted API in the path; a refund vault holding merchant float with cumulative-refund accounting, a hard `payment_amount` ceiling, a refund window, and double-refund protection. Cross-contract claim pinned by tests: `payment_ref` (refund key) ≡ receipt leaf hash. Vault is SEP-41 token-agnostic (operates in raw integer units, any precision). | `ReceiptAnchor`, `RefundVault`, [`SECURITY_MODEL.md`](../docs/SECURITY_MODEL.md), [`README.md`](../README.md#refundvault) | +| **TTL/rent handling (relevant to §3.5)** | Real, exercised TTL strategy: ~30-day storage TTLs, public `extend_*_ttl` helpers, contiguous-prefix pruning, rent costing in [`storage-audit.md`](../docs/storage-audit.md), the window-sized double-refund guard TTL, and an explicit *temporary*-storage recommendation for `upto` authorizations. This is exactly the "address TTL and rent extension" discipline §3.5 names where an on-chain component is included. | [`docs/storage-audit.md`](../docs/storage-audit.md), [`ADR-002`](../docs/ADR-002-upto-scheme.md#storage-ttl-and-rent), [`ADR-004 §3`](../docs/ADR-004-bazaar-discovery-registry.md#3-ttl-and-rent-extension-strategy-35-compliance), DEPLOYMENTS rent/fee analysis in [`docs/MAINNET_DEPLOYMENT.md`](MAINNET_DEPLOYMENT.md) | +| **Security / interface discipline** | Immutability as a stated property (no upgrade entry point, ADR-003 + migration runbook); shared stable error enum; stable event topic contract (breaking-change policy); fuzz/re-entrancy/token-agnostic test suites; multisig-admin coverage; CI gating on fmt, clippy `-D warnings`, full test run, and wasm size budget. Security-model doc reconciles with audit scope. | [`ADR-003`](../docs/ADR-003-upgradeability.md), [`EVENTS.md`](../docs/EVENTS.md), [`SECURITY_MODEL.md`](../docs/SECURITY_MODEL.md), [`.github/workflows/ci.yml`](../.github/workflows/ci.yml) | + +--- + +## D. Explicit Boundary Definition + +> **Receipt anchoring and refund vaults are NOT x402 `verify`/`settle`.** + +- `ReceiptAnchor` proves a payment *was recorded and charged consistently*. `RefundVault` + executes *policy-bounded refunds of merchant float*. Neither performs the facilitator's + role of cryptographically **verifying an incoming x402 `Authorization`** and + **settling a transfer against it** as a payment processor. +- The **funded deliverable** of the RFP is the **x402 facilitator** (the + `x402-facilitator-stellar` implementation) — an HTTP-facing service (and any + `upto` scheme) that performs `verify`/`settle` on Stellar, with Bazaar discovery + kept off-chain by default. That work is **not in this repository**. +- This repository is therefore **supporting prior work — evidence of capability**, + not the funded deliverable. Positioning it as a component of, a substitute for, or + partial delivery of the facilitator would be inaccurate. +- The inverse connection is also scoped precisely: `upto` authorizations and + facilitator-driven settlement *would* interact with these contracts (see + [`ADR-002 §5`](../docs/ADR-002-upto-scheme.md#5-consequences) open question 5 + on refund interaction), but that interaction is future design, under review — not + shipped integration. + +Shipped, in short: + +| This repo supplies | It does not supply | +|---|---| +| Soroban contract experience on Stellar payment flows | `verify`/`settle` of x402 authorizations | +| TTL/rent handling for persistent & temporary records | The `upto` scheme implementation (drafted, blocked on #64/#65/#66) | +| Evidence of security and interface discipline | The Bazaar discovery catalog (off-chain, in `x402-facilitator-stellar`) | +| A documentable cost model for optional on-chain registries | A deployed, audited facilitator | + +--- + +## E. Genuine Connections + +These are the real, defensible lines from this repo to the RFP — not retrofits. + +1. **The `upto` scheme in ADR-002.** `scheme_upto_stellar.md` was drafted *in the + upstream x402 format* and is an RFP deliverable. Its design (§4: a thin + authorization-binding contract, `authorize`/`settle`) only works if you already + understand Soroban's auth semantics and its **TTL/rent/eviction failure mode** — + which is precisely what this repo has handled for batch and refund records. The + ADR's storage-class analysis for open authorizations directly reuses this repo's + methodology. This is the RFP area where the prior work is *directly* relevant, + not merely adjacent. (`docs/ADR-002-upto-scheme.md`, `docs/scheme_upto_stellar.md`.) + +2. **Optional on-chain registry patterns (ADR-004).** §3.2 of the RFP keeps Bazaar + discovery off-chain by default and allows an optional on-chain Soroban registry. + ADR-004 worked that option to a shipped-cost decision: a commitment-hash data + architecture (~140–240 bytes/entry), registration cost model, **TTL/rent-extension + policy mirroring `extend_batch_ttl`/`extend_refund_ttl`**, and a signed + recommendation to **not** deploy it on-chain while retaining the ADR as the cost + model for evaluation. That is direct, documented RFP analysis. + +3. **Shared decimal / asset semantics.** The facilitator must reason about the assets + x402 settles with (native XLM and SAC-wrapped USDC). `RefundVault` deliberately + performs **no decimal arithmetic** — amounts are raw integer units in the token's + smallest unit, any SEP-41 precision behaves identically, and + `token_agnostic_tests.rs` proves the full lifecycle against 0- and 2-decimal + tokens. The deployment already settles in native XLM SAC and documents the USDC + path. This is shared semantic groundwork with the facilitator's settlement layer. + +4. **Payment-reference coherence.** The claim that a refund is keyed by *exactly the + payment record the agent was given* (`payment_ref` ≡ receipt leaf) is the + accountant's guarantee a metered `upto` flow needs when a payment settles below + its cap — and it is pinned by integration tests, so it is a real, checkable + statement rather than a slide. + +--- + +## F. Honest Maturity Assessment + +State plainly, no gloss: + +- **Unaudited.** No independent security audit has been completed. The repo's own + threat model and audit-readiness docs exist and are self-critical + (`docs/SECURITY_MODEL.md`, `docs/AUDIT.md`), but that is not an audit. +- **Pre-1.0.** Source is at `0.3.0` with breaking changes between 0.1.0 → 0.2.0 → + 0.3.0 (e.g. cumulative-refund `payment_amount` API, #99). Versioning policy is + documented in `docs/RELEASING.md`. +- **Testnet only.** The only live deployments are on **testnet** and they run + **`0.1.0`**, built with `soroban-sdk` 27.0.0. The current source (`0.3.0`, pinned + to `soroban-sdk` 27.0.4) is **not** what is deployed; redeploying would mint new + contract IDs and invalidate the published addresses. There is **no mainnet + deployment**. +- **Immutability cuts both ways.** Deployed binaries are immutable with no upgrade + path (ADR-003). Working as designed, this bounds risk; it also means any defect in + a *deployed* binary is permanent at that address and requires the documented + migrate-and-redeploy runbook. +- **Notional vs shipped.** The `upto` scheme (ADR-002 / `scheme_upto_stellar.md`) is a + **draft design under review**, explicitly blocked on open questions (#64, #65, #66, + sub-invocation semantics, cost measurement). It is not an adopted spec and not + implementation. +- **Known open item.** Whether an *archived* (vs merely expired) `RefundVault` guard + record fails closed or open on a live network is untested against mainnet archival + behaviour — flagged in `docs/SECURITY_MODEL.md` (§ Replay Attacks). Treat as an + audit open item. + +Bottom line for SCF reviewers: this repository is credible **evidence of the +capability the RFP's §4 asks for** — real Soroban contracts on live testnet with a +serious TTL/rent story and disciplined testing — and the origin of the Stellar +`upto` draft that is itself an RFP deliverable. It is **not** a claim of a deployed, +audited, production payment facilitator. + +--- + +*Path of truth: verification commands for everything claimed above are in +[`.github/workflows/ci.yml`](../.github/workflows/ci.yml) (`fmt`, `clippy -D +warnings`, `cargo test --workspace`, wasm build + size budget); deployment record in +[`DEPLOYMENTS.md`](../DEPLOYMENTS.md); commits rotate under this document as `main` +moves.* \ No newline at end of file