feat(x402): BSC multi-asset payments + Permit2 signing#457
Conversation
The Nansen API now advertises four stablecoins on BNB Smart Chain (U, USD1, USDT, USDC). Two of them (USDT, USDC) predate EIP-3009 on BSC and settle via Uniswap's canonical Permit2 contract instead. - x402-evm: route payment creation on extra.assetTransferMethod — eip3009/absent keeps the existing gasless flow; permit2-exact signs a Permit2 PermitWitnessTransferFrom (nested-struct EIP-712, 3-field Permit2 domain) against the spender contract advertised in the 402. Unsupported methods throw so the fallback loop tries the next entry. The digest implementation is cross-validated against an independent EIP-712 implementation via a fixed test vector. - x402: skip permit2 entries with an actionable message when the wallet has not made the one-time approve(Permit2, ...) for the token (allowance preflight via eth_call); EVM_X402_TOKENS becomes an ordered per-network token list; checkX402Balance takes the asset actually paid with so warnings use the right token and decimals. - api: thread the paid asset through to the balance warning. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| }); | ||
| const data = await resp.json(); | ||
| if (typeof data.result !== 'string') return true; | ||
| return BigInt(data.result) > 0n; |
There was a problem hiding this comment.
Minor: this preflight only detects the zero-allowance case (> 0n), but the skip message below tells users to approve(Permit2, <amount>). A wallet that approved a small finite allowance now exhausted (or below the payment amount) would pass this check and then fail server-side instead of getting the actionable skip message.
Since it fails open on RPC error anyway, the heuristic is defensible — but consider either a one-line comment noting it only catches the never-approved case, or threading the payment amount through to compare allowance >= amount. Non-blocking.
There was a problem hiding this comment.
Good catch — went with the real fix rather than the comment: hasPermit2Allowance now takes the payment amount and compares allowance >= amount, so the exhausted/insufficient-finite-approval case gets the actionable skip message too. Skip message updated to name both cases. Fail-open on RPC error unchanged. Fixed in d02572c.
The preflight only caught the never-approved case (allowance > 0); a finite approval now exhausted or below the payment amount passed the check and failed server-side instead of getting the actionable skip message. Compare allowance >= requirement.amount and say so in the message. Fail-open on RPC errors unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
What
The Nansen API now advertises four stablecoins on BNB Smart Chain — U (United Stables), USD1, USDT, and USDC. This PR makes the CLI able to pay with all of them.
U and USD1 already work with the CLI's existing EIP-3009 flow (the server lists them first for exactly that reason). USDT and USDC on BSC predate EIP-3009, so facilitators settle them through Uniswap's canonical Permit2 contract — which needs a different signature type.
Changes
src/x402-evm.js— Permit2 signing (permit2-exact)extra.assetTransferMethod: absent/eip3009→ existing gasless flow;permit2-exact→ newcreatePermit2ExactPayload; anything else throws so the fallback loop moves to the next accepts entry.PermitWitnessTransferFromagainst the spender contract advertised in the 402 (extra.spenderAddress— never hardcoded), witness bound to the merchant wallet. Nested-struct EIP-712 hashing and the 3-field Permit2 domain are implemented in the repo's existing zero-dependency style.eth_account) over identical input — the two agree byte-for-byte.src/x402.js— allowance preflight + multi-asset registrytoken.approve(PERMIT2_ADDRESS, …)from the payer. Entries are skipped with an actionable message when the allowance is missing, instead of burning a doomed verify round-trip. RPC failures fail open (server decides).EVM_X402_TOKENSbecomes an ordered per-network token list (BSC: U, USD1, USDT, USDC — all 18-decimal BEP-20 deployments); RPC URLs split intoEVM_X402_RPCS.checkX402Balance(network, asset)checks the token actually paid with, so low-balance warnings use the right symbol and decimals.src/api.js— threads the paid asset through to the balance warning.Testing
x402-permit2.test.js(7 tests): reference digest vector, payload wire shape (decimal-string numerics, no EIP-3009 fields), missing-spender error, method routing (permit2-exact / eip3009 / absent / unsupported).Notes
permit2-uptois intentionally unsupported for now — the CLI only uses exact-amount payments.🤖 Generated with Claude Code