feat(x402): the signed domain follows the 402's network — Arc, Base, Base Sepolia - #44
Merged
Merged
Conversation
…Base Sepolia One EIP-712 domain was signed whatever the 402 said: Base's USDC, "USD Coin" v2, chainId 8453, 0x8335…, with `accepted.asset` always Base's. Against arc.blockrun.ai (eip155:5042, USDC at 0x3600…, domain name "USDC") every payment was a signature over the wrong domain — the facilitator recovered a different signer and answered 401 after the SDK had reported a payment. Same for testnet.blockrun.ai (Base Sepolia, whose USDC is also named "USDC"). EVM_NETWORKS maps a 402's `network` to the SDK's OWN chainId, USDC address and domain; createPaymentPayload signs those. The 402 SELECTS the network and supplies nothing else, so the rule the single constant enforced — a hostile 402's `extra` cannot steer a signature onto another contract — still holds. An unknown network is refused naming what is supported; a 402 whose `asset` is not that network's USDC is refused before signing. Every EVM call site passes the 402's asset through. Verified against arc.blockrun.ai with an unfunded throwaway key: Circle's /verify answers insufficient_funds and recovers the throwaway's own address as payer — the signature verifies on Arc's domain and only the balance is missing. Six new tests pin the domain per network (verifyTypedData against Arc's domain passes, against Base's fails), the refusals, and that `extra` from a 402 is ignored. 365 tests, tsc and eslint clean. 3.16.0.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
One EIP-712 domain was signed whatever the 402 said — Base's USDC ("USD Coin" v2, chainId 8453,
0x8335…), withaccepted.assetalways Base's. Against arc.blockrun.ai (eip155:5042, USDC at0x3600…, domain nameUSDC) every payment was a signature over the wrong domain: the facilitator recovered a different signer and answered 401 after the SDK had reported a payment. Same for testnet.blockrun.ai (Base Sepolia).What
EVM_NETWORKSmaps a 402'snetworkto the SDK's own chainId, USDC address and domain (Base, Arc, Base Sepolia);createPaymentPayloadsigns those.extracannot steer a signature onto another contract) still holds.asset≠ that network's USDC → refused before signing. Every EVM call site passes the 402's asset through.EVM_NETWORKS,evmNetwork(),ARC_CHAIN_ID,USDC_ARC. README "Arc Support" section. 3.16.0.Verified
Against arc.blockrun.ai with an unfunded throwaway key: Circle's
/verifyanswersinsufficient_fundsand recovers the throwaway's own address aspayer— the signature verifies on Arc's domain; only the balance is missing.Six new tests:
verifyTypedDataagainst Arc's domain passes and against Base's fails; Base unchanged; unknown network and asset mismatch refused; a 402'sextraignored. 365 tests, tsc and eslint clean.🤖 Generated with Claude Code