Skip to content

docs(x402): spike #206 — hand-roll verdict + proven local EIP-3009 facilitator loop#211

Merged
hellno merged 2 commits into
mainfrom
hellno/x402-facilitator-spike
Jul 7, 2026
Merged

docs(x402): spike #206 — hand-roll verdict + proven local EIP-3009 facilitator loop#211
hellno merged 2 commits into
mainfrom
hellno/x402-facilitator-spike

Conversation

@hellno

@hellno hellno commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Closes the #206 spike. Docs-only: adds a reproducible recipe + the two build decisions #34 needs before it starts. No code, no workspace Cargo.toml/Cargo.lock changes (the spike harness under digest-cmp/ is self-excluded from the deckard workspace via an empty [workspace] table).

What this proves

Q1 — build shape → hand-roll in deckard-core, not x402-types.
A 6-line alloy sol! TransferWithAuthorization (the cow_types.rs precedent) produces the byte-identical EIP-712 typehash, digest, and signature as x402-rs's own type — cross-checked four ways (hand-roll, x402-rs, foundry cast wallet sign, and the deployed USDC contract accepting it on-chain). Pulling x402-chain-eip155 into the #![forbid(unsafe_code)] trust core drags 222 transitive crates (3× rustls, hyper, reqwest, full alloy-provider stack) for zero cryptographic gain. Use x402-rs only as the demo-fixture facilitator binary, never a build dep — as #34 already planned.

Q2 — the fully-local loop works → stay on the Ethereum Sepolia fork.
402 → sign EIP-3009 → facilitator /verify → /settle → on-chain runs end-to-end against the real Circle USDC FiatTokenV2_2 on anvil --fork-url $RPC_URL_SEPOLIA --fork-block-number 10822990, with a self-hosted x402-rs facilitator (eip155:11155111 → fork, no Docker). Asserted: USDC moved, nonce consumed, gas paid by the facilitator (not the buyer), replay rejected. run.sh reproduces it from a cold start.

Spec corrections v2 forced (detailed in the doc, folded into the #34 decision comment)

  • Use protocol v2 (CAIP-2 eip155:11155111); v1 has no network name for Ethereum Sepolia.
  • This USDC's EIP-712 domain name is "USDC", version "2" — not mainnet's "USD Coin". The 402 extra must carry {assetTransferMethod:"eip3009", name:"USDC", version:"2"}.
  • Header parsing (X-Payment v1 / Payment-Required+Payment-Signature v2) is agent-side transport; the facilitator API is plain JSON.
  • Gotcha: don't sign as an anvil default account — several carry EIP-7702 delegation designators on real Sepolia, so USDC's SignatureChecker rejects the EOA signature. Use fresh codeless keys.

Files

Decision comment posted on #34.

…cilitator loop

Standalone spike feeding two build decisions into #34:

Q1 (dep decision): hand-roll the EIP-3009 TransferWithAuthorization in deckard-core
(the cow_types alloy sol! precedent), NOT x402-types. Proven byte-for-byte: hand-roll,
x402-rs, foundry cast, and the deployed USDC contract all agree on typehash/digest/
signature. Pulling x402-chain-eip155 into the trust core = 222 transitive crates (3x
rustls, hyper, reqwest, full alloy-provider stack) for zero cryptographic gain.

Q2 (local loop): PROVEN on anvil --fork-url $RPC_URL_SEPOLIA --fork-block-number 10822990.
Self-hosted x402-rs facilitator (eip155:11155111 -> fork, no Docker) runs 402 -> sign ->
/verify -> /settle end-to-end against real Circle USDC FiatTokenV2_2: USDC moves, nonce
consumed, facilitator pays gas, replay rejected. Go: stay on the Sepolia fork.

Recipe reproduces from a cold start via run.sh given $RPC_URL_SEPOLIA. Spike code
(digest-cmp) is self-excluded from the deckard workspace; no workspace Cargo.toml/lock
changes. Refs #206, feeds #34.
… vector

Per review: the Q1 evidence (byte-identical digests, transcript) and the KAT vector stay;
the throwaway comparison crate is dropped from the repo (it was never a workspace member).
@hellno
hellno merged commit da3c077 into main Jul 7, 2026
5 checks passed
@hellno
hellno deleted the hellno/x402-facilitator-spike branch July 7, 2026 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant