Standalone spike for the x402 track (#31 → #32 → #34). Time-boxed; throwaway code; feeds two decisions into #34 before it starts.
Question 1 — build shape: hand-rolled EIP-3009 vs x402-rs (dep decision)
The trust core needs to sign the x402 exact payload: an EIP-3009 TransferWithAuthorization as EIP-712 typed data (from, to, value, validAfter, validBefore, nonce). Two candidate shapes; new deps require explicit approval (DoD rule 4), so decide with evidence:
- Hand-roll the typed data via
alloy sol! in deckard-core — the cow_types precedent (EIP-712 via alloy, KAT-gated against a reference implementation).
- Depend on
x402-types/x402-reqwest (github.com/x402-rs/x402-rs, Apache-2.0, alloy-based, supports v1+v2).
Compare: surface area pulled into the trust core, audit load, serde/wire fit, and who owns header parsing (v1 X-PAYMENT body-JSON vs v2 PAYMENT-REQUIRED/PAYMENT-SIGNATURE base64 headers, CAIP-2 network ids). Default lean: hand-roll in the core, use x402-rs only in demo fixtures — but let the spike overturn it.
Question 2 — prove the fully-local loop on OUR demo world
Neither hosted facilitator serves Ethereum Sepolia (CDP: Base/Polygon/Arbitrum/World/Solana; x402.org testnet: Base Sepolia et al.) — self-hosting is required, and it is architecturally plausible but undocumented upstream. Prove it:
- anvil fork of Ethereum Sepolia (the existing demo world, block 10822990).
- Self-hosted facilitator —
x402-rs facilitator or second-state/x402-facilitator — configured with an eip155:11155111 chain entry pointing at the fork RPC. Note: x402-rs takes a JSON config with per-chain rpc entries keyed by CAIP-2 id (env vars only override values), not RPC_URL_* vars.
- The real Circle USDC on Sepolia (
0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238) — verified on Etherscan as FiatTokenV2_2 with transferWithAuthorization/receiveWithAuthorization/cancelAuthorization — so the fork carries genuine EIP-3009 bytecode.
- Buyer signs with a throwaway key; facilitator
/verify then /settle against the fork; assert the USDC balance moved and the nonce is consumed.
Deliverables
Standalone spike for the x402 track (#31 → #32 → #34). Time-boxed; throwaway code; feeds two decisions into #34 before it starts.
Question 1 — build shape: hand-rolled EIP-3009 vs x402-rs (dep decision)
The trust core needs to sign the x402
exactpayload: an EIP-3009TransferWithAuthorizationas EIP-712 typed data (from, to, value, validAfter, validBefore, nonce). Two candidate shapes; new deps require explicit approval (DoD rule 4), so decide with evidence:alloy sol!indeckard-core— thecow_typesprecedent (EIP-712 via alloy, KAT-gated against a reference implementation).x402-types/x402-reqwest(github.com/x402-rs/x402-rs, Apache-2.0, alloy-based, supports v1+v2).Compare: surface area pulled into the trust core, audit load, serde/wire fit, and who owns header parsing (v1
X-PAYMENTbody-JSON vs v2PAYMENT-REQUIRED/PAYMENT-SIGNATUREbase64 headers, CAIP-2 network ids). Default lean: hand-roll in the core, use x402-rs only in demo fixtures — but let the spike overturn it.Question 2 — prove the fully-local loop on OUR demo world
Neither hosted facilitator serves Ethereum Sepolia (CDP: Base/Polygon/Arbitrum/World/Solana; x402.org testnet: Base Sepolia et al.) — self-hosting is required, and it is architecturally plausible but undocumented upstream. Prove it:
x402-rsfacilitator orsecond-state/x402-facilitator— configured with aneip155:11155111chain entry pointing at the fork RPC. Note: x402-rs takes a JSON config with per-chainrpcentries keyed by CAIP-2 id (env vars only override values), notRPC_URL_*vars.0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238) — verified on Etherscan asFiatTokenV2_2withtransferWithAuthorization/receiveWithAuthorization/cancelAuthorization— so the fork carries genuine EIP-3009 bytecode./verifythen/settleagainst the fork; assert the USDC balance moved and the nonce is consumed.Deliverables
docs/research/.