You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The flagship: the agent hits HTTP 402, Deckard validates the payment demand against policy, signs an EIP-3009 TransferWithAuthorization (EIP-712), the agent retries and gets the resource — keys never leave the machine, the client pays no gas (the settler does), and the facilitator cannot alter amount or destination (worst case is non-settlement, never theft). Self-custodial, policy-bounded machine payments on Ethereum.
Corrected 2026-07-10 (codebase re-verified): #34 is the x402/MPP linchpin — the whole track (#207/#208/#209/#210) is gated on it. It is a LARGE net-new build but fully unblocked and de-risked: every stated dependency is on main, and spike #206 (PR #211) proved the exact crypto byte-for-byte. Spike-forced corrections and a split/sequencing plan added below.
Ready to start — dependencies all landed (verified 2026-07-10)
The daily-cap + UTC-midnight-rollover ledger — signerd/spend_store.rsSpendStore (reserve/commit/release), daemon.rs current_utc_day()/rollover(). ✔ But note: it is a single global counter keyed by (chain_id, account, day) with committed_wei/reserved_wei. x402 phase 2: exact/EIP-3009 payments on the Ethereum reference path, fully local demo loop #34's per-asset token_budgets is a net-new generalization — the reserve/commit/release pattern is reusable (it is exactly the "signed-but-unsettled counts as spent, retry reuses" primitive), the data structure is new (per-asset keyed).
Spike-forced corrections (from #206 / PR #211 — the spec had these wrong)
Use protocol v2 / CAIP-2 network ids; emit v2, decode v1 and v2.
EIP-712 domain name is "USDC" (version "2"), NOT "USD Coin".
The KAT lives as a JSON fixture (docs/research/x402-spike/eip3009-kat.json) — re-encode it as a Rust #[test] inside this issue (digest 0x89d2449c…, sig 0x3e1236af…).
propose_payment must copy the Send propose auto-allow-within-budget + guardrail-downgrade path (daemon.rs:683), NOT the always-NeedsApproval propose_message path.
Do not sign as an anvil default account (EIP-7702 delegation routes USDC to EIP-1271 and rejects) — the spike run.sh documents the working setup.
The x402-rsfacilitator binary is a demo prerequisite surfaced by demo-check (a just demo sibling process on the fork), never a build dependency.
In scope
deckard-core: hand-rolled EIP-3009 TransferWithAuthorization via alloy sol! mirroring cow_types.rs:26-59 + eip712_signing_hash sign + the Rust KAT. (No wire files — this PR can run in parallel with the browser milestone.)
upto/batch-settlement, Permit2, Base/hosted facilitators, the private Railgun leg + ERC-7710 settlement, general ERC-20 beyond the allowlisted demo asset.
Definition of done
All in-scope items runnable headless; X3–X10 green.
cargo fmt --all --check clean; just check green (both feature configs); cargo test --workspace green.
No new deps (hand-roll the x402 structs — alloy-sol-types is already compiled for cow_types); anything else approved before merge.
Unblocked today. #32 (sign-in) is NOT a blocker (its message seam already shipped — see #32). Sequence the x402 track: #34 → #208 → #209 (+#207 for GUI beats); #210 is a near-free follow-on to #208.
Why
The flagship: the agent hits HTTP 402, Deckard validates the payment demand against policy, signs an EIP-3009
TransferWithAuthorization(EIP-712), the agent retries and gets the resource — keys never leave the machine, the client pays no gas (the settler does), and the facilitator cannot alter amount or destination (worst case is non-settlement, never theft). Self-custodial, policy-bounded machine payments on Ethereum.Canonical scheme spec: https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_evm.md · protocol v2: https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md
Ready to start — dependencies all landed (verified 2026-07-10)
capabilities.rswith a documentedCAP_extension point. ✔deny_reasons.rs+ typed tags. ✔signerd/spend_store.rsSpendStore(reserve/commit/release),daemon.rs current_utc_day()/rollover(). ✔ But note: it is a single global counter keyed by(chain_id, account, day)withcommitted_wei/reserved_wei. x402 phase 2: exact/EIP-3009 payments on the Ethereum reference path, fully local demo loop #34's per-assettoken_budgetsis a net-new generalization — the reserve/commit/release pattern is reusable (it is exactly the "signed-but-unsettled counts as spent, retry reuses" primitive), the data structure is new (per-asset keyed).chain.rs::is_testnet_or_dev+daemon.rs guardrail_active(). ✔Spike-forced corrections (from #206 / PR #211 — the spec had these wrong)
"USDC"(version"2"), NOT"USD Coin".docs/research/x402-spike/eip3009-kat.json) — re-encode it as a Rust#[test]inside this issue (digest0x89d2449c…, sig0x3e1236af…).propose_paymentmust copy the Sendproposeauto-allow-within-budget + guardrail-downgrade path (daemon.rs:683), NOT the always-NeedsApprovalpropose_messagepath.run.shdocuments the working setup.x402-rsfacilitator binary is a demo prerequisite surfaced bydemo-check(ajust demosibling process on the fork), never a build dependency.In scope
deckard-core: hand-rolled EIP-3009TransferWithAuthorizationviaalloy sol!mirroringcow_types.rs:26-59+eip712_signing_hashsign + the Rust KAT. (No wire files — this PR can run in parallel with the browser milestone.)deckard-contract:PaymentRequirementsv1/v2 decode +ProposePayment/SignPaymentwire variants +CAP_X402_EXACT. (Wire files — rebase this on Connections: daemon-held dapp sessions, listed in the app, revocable per site #199'sSignerRequestdelta; land one enum change first, then the other. See Connections: daemon-held dapp sessions, listed in the app, revocable per site #199 "Wire sequencing".)token_budgets(per-tx + daily + spent-today, UTC rollover) +asset_allow(default-deny) +max_validity_secs+evaluate_paymentuntrusted-input checks (asset ∈ allow, amount ≤ budget, payTo rendered, validity ≤ max, network == chain). Any miss → typed Deny (Freeze the Deny-reason vocabulary in deckard-contract #28). Mainnet guardrail unchanged.propose_payment(auto-allow-within-budget + guardrail-downgrade) + per-asset SpendStore + bearer-nonce idempotent retry-reuse.deckard_x402_sign, capability-gated.x402-rsfacilitator on the fork) +demo-checkprobes.Suggested split (3 PRs)
Not in scope
upto/batch-settlement, Permit2, Base/hosted facilitators, the private Railgun leg + ERC-7710 settlement, general ERC-20 beyond the allowlisted demo asset.Definition of done
cargo fmt --all --checkclean;just checkgreen (both feature configs);cargo test --workspacegreen.alloy-sol-typesis already compiled forcow_types); anything else approved before merge.Ordering
Unblocked today. #32 (sign-in) is NOT a blocker (its message seam already shipped — see #32). Sequence the x402 track: #34 → #208 → #209 (+#207 for GUI beats); #210 is a near-free follow-on to #208.