Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 230 additions & 0 deletions docs/RFP-EVIDENCE-MAP.md
Original file line number Diff line number Diff line change
@@ -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.*
Loading