feat: add unified EVM session payment method#225
Conversation
- Switch escrow from transferWithAuthorization to receiveWithAuthorization (enforces msg.sender == to, preventing mempool signature extraction attacks per EIP-3009 security guidance) - Add security consideration for parameter substitution attack: EIP-3009 signature does not cover channel params (payee, salt, etc), so an attacker can front-run with modified params. Recommend deriving nonce deterministically from channel parameters as mitigation - Fix bibliographic references: add missing co-authors for EIP-3009, EIP-2098, EIP-712; correct EIP-3009 date to 2020-09 - Replace (v, r, s) params with packed bytes signature for interface consistency with settle/close
- topUpWithAuthorization: rename salt->topUpSalt, add from to nonce derivation (keccak256(channelId, additionalDeposit, from, topUpSalt)) - EIP-2098: keep MUST NOT produce, relax to MAY accept compact signatures - authorizedSigner: allow ERC-1271 contract wallets (Safe/4337), not EOA-only - close: document voucher-less forfeit path when cumulativeAmount <= settled - EIP-3009: clarify escrow targets USDC v2.2+ bytes overload only; canonical (v,r,s) tokens not supported Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
|
Directionally looks good -- thanks for putting this together! I think one thing to consider is support for non-EIP3009 tokens via permit or similar. This isn't strictly required at this time, but we should make sure the design will scale to this model without breaking the core interface |
Switch openWithPermit2 and topUpWithPermit2 to permitWitnessTransferFrom, carrying channel parameters (payee, salt, authorizedSigner for open; channelId, topUpSalt for topUp) as a named EIP-712 witness struct. Wallets that render typed data now display these as labeled fields at signing time instead of having them hashed opaquely into a derived nonce. EIP-3009 has no witness mechanism, so it keeps the deterministic-nonce derivation for channel-parameter binding.
|
Two issues that should be fixed before this lands:
Since voucher credentials can omit
The draft correctly notes that EIP-3009 does not bind |
Spec Preview
|
|
cc @clayclaw -- let me know when this is ready fro another review! |
|
+1 on the unified EVM approach. We ship the x402 v2 canonical envelope identically across Base and Tempo (USDC on both) with zero per-chain branching at the HTTP layer, so the design intent of "one session spec, multiple EVM chains" matches what works in production. A few operational notes from running both chains live (AlgoVoi gateway):
Happy to dig into any of these if useful for the spec text. |
Co-authored-by: Cursor <cursoragent@cursor.com>
|
Coming at this from the non-EVM side of the same problem space — AlgoVoi ships AP2 (Agent Payment Protocol) mandates as the Algorand/VOI equivalent of the session intent defined here, so some of the design decisions look familiar. Happy to contribute production observations as this develops. Two points that may be useful as the spec is refined: On EIP-3009 universality. brendanjryan's point is well-placed. On Algorand/VOI we hit the same gap: not all assets support the off-chain-authorisation pattern, so we run a fallback path where the client pre-funds an escrow and the server draws down against it without needing per-call authorisation. Permit2 is the right EVM analogue — worth specifying the fallback path explicitly in the spec rather than leaving it to implementers, otherwise you get fragmentation between EIP-3009-capable and non-capable token deployments. On splits at settlement. Both are refinement points rather than blockers. The domain separator distinction from Tempo's AlgoVoi (chopmob-cloud) — Acquisition enquiries: https://docs.algovoi.co.uk/acquisition |
|
@brendanjryan Thanks, both issues are addressed in the latest draft. Voucher idempotency now runs only after EIP-712 signature and signer verification, and the EIP-3009 channel-parameter binding is now mandatory. @chopmob-cloud Thanks for the production notes, we added explicit In this revision we also split the escrow into a mandatory core and an optional relayed / gasless operations profile for relayer-submitted paths (EIP-3009, Permit2, payee-authorized settle/close), with advertised capabilities aligned to what the escrow actually implements. Settlement amounts must strictly increase: the escrow reverts stale vouchers on-chain, and servers apply the same rule off-chain. Finalized channels stay on record permanently, with a cross-epoch replay section, so reusing the same channelId cannot revive old vouchers against a new deposit. |
Thanks for the AP2 context. We just added non–EIP-3009 funding path with Permit2 in the relayed profile, with feePayerAuthorizations for discovery. We had split / splitBps in an earlier draft but removed them from the unified escrow surface: revenue splits feel better as an implementor extension than core session semantics, especially with extra gas at settle/close that varies by chain. This also adds the settlement complexity. Your push-vs-pull revert point is still a useful note for anyone layering splits on top. Thanks for sharing these notes. |
|
The channel mechanics are well-structured — the deterministic One gap worth addressing before the spec stabilises: the settlement receipt on The pattern that closes this: a terminal state enum ( This is specified in AlgoVoi (chopmob-cloud) — docs.algovoi.co.uk/settlement-attestation |
…ermit2/token prose
brendanjryan
left a comment
There was a problem hiding this comment.
Inline review of two cross-spec consistency issues with the other evm/session specs on paymentauth.org (see comments below).
|
Here is the generic session spec, can you look at the above and flag any deltas or misalignment? |
Thanks. Let me take a look |
Reuse the shared EVM top-level credential type names and replace the separate fee-payer authorization negotiation with methodDetails.credentialTypes, matching the charge intent semantics.
Update the EVM session draft to reference the generic session intent registration, avoid duplicate IANA intent registration, and align receipt semantics so reference remains the stable channel identifier while settlement transaction hashes are reported separately.
We reviewed the generic session intent PR and aligned the EVM session draft where it makes sense. Apart from the IANA cleanup, the main alignment change was to receipt semantics. Change:
One note: we did not change EVM’s |
Thanks for the pointer. The session drafts seem to use a lightweight receipt model today: accounting state plus method-native evidence like txHash. The proposed attestation format looks broader than this EVM session draft, and adding it only here may make EVM diverge from the other session methods. This may fit better as a shared receipt extension across session methods later. |
Summary
Adds the
sessionintent for theevmpayment method, defining unidirectional streaming payment channels for incremental, voucher-based payments on any EVM-compatible chain. Adapts the streaming payment channel mechanism from the Tempo session spec (draft-tempo-session) for general EVM use, with EVM-specific transaction formats, gas models, and domain separators.amount(price per unit, base units),currency(ERC-20 address),recipient(payee address), withmethodDetailsforchainId,escrowContract,feePayer, optionalsplitsopen,topUp,voucher,close) with EIP-712 voucher signatures for off-chain cumulative paymentsPayment-ReceiptwithacceptedCumulative,spent, optionalreference(tx hash on settlement)This is an initial draft, we are actively developing the underlying functionality and will continue refining the spec as implementation progresses. Feedback and discussion are welcome.
Context
This is the second intent defined for the
evmpayment method (afterchargein #213). The session intent follows the Tempo session spec (draft-tempo-session) as the reference design, extending it to work across any EVM-compatible chain.Design decisions
open,openWithAuthorization,settle,topUp,topUpWithAuthorization,close,requestClose,withdraw— covers the full channel lifecycle with both client-funded and server-submitted paths.openWithAuthorization/topUpWithAuthorizationvia EIP-3009feePayer: true, client signs off-chaintransferWithAuthorization; server calls the escrow contract and pays gas. Client never needs native token. Requires EIP-3009 token support.open()+ ERC-4337 support for client-broadcast pathfeePayer: false, client callsapprove() + open()directly or via an EntryPoint-mediated UserOperation. Smart wallets can batch both in a single UserOp.channelIdviakeccak256(payer, payee, token, salt, authorizedSigner, escrow, chainId)topUp(or initialopen) with a voucher update in a single HTTP round-trip — reduces latency when approaching deposit limits.splitRecipients[]+splitBps[]settle()/close()."EVM Payment Channel""Tempo Stream Channel"— the only semantic difference in the voucher signing scheme. Prevents cross-deployment replay.New File
specs/methods/evm/draft-evm-session-00.mdAI Disclosure
This spec was drafted with AI assistance (Claude). All content has been reviewed for technical accuracy, RFC compliance, and alignment with STYLE.md / CONTRIBUTING.md.