Skip to main content
x402 pre-verifies a payment signature before settling it on-chain. Pre-verification has to match what the on-chain contract does, so whether a payment succeeds depends on the wallet type and the scheme it is used with. This page lists the supported combinations and explains the ones that do not work.

Why wallet type matters

Code routing

Ethereum signatures originally assumed externally owned accounts (EOAs): a private key signs, ecrecover recovers the address, done. Smart contract wallets do not fit that model, because their address comes from factory deployment parameters rather than a key. EIP-1271 fills the gap with isValidSignature(bytes32 hash, bytes signature), which a contract implements to define its own verification rules. To handle both account types, most on-chain verifiers branch on whether the address has code:
// Code-routing pattern (Permit2, modern ERC-3009 tokens)
if (signer.code.length == 0) {
    // EOA: recover the key
    require(ecrecover(hash, sig) == signer);
} else {
    // Contract account: ask it to verify
    require(IERC1271(signer).isValidSignature(hash, sig) == 0x1626ba7e);
}
x402’s facilitator mirrors whichever rule the target contract uses, so a wallet that would fail on-chain also fails pre-verification. There is no path that reports a payment as valid and then reverts at settlement.

How tokens implement it

Permit2 (permitWitnessTransferFrom) code-routes through its internal SignatureVerification library, so any Permit2 payment from an address with code calls isValidSignature on that address. ERC-3009 tokens vary by version. Circle’s USDC v2.2 added a SignatureChecker that code-routes for transferWithAuthorization. Earlier USDC versions (v1 and the v2.0/2.1 deployments from before 2023) use ecrecover only and never call isValidSignature. Older or simpler ERC-3009 tokens predate smart wallet support and also use ecrecover only. They treat every address as an EOA regardless of code, so smart accounts and 7702-delegated EOAs that need EIP-1271 fail on-chain even when x402 would pass pre-verification.
This page assumes the token code-routes. Before using a token in production, check how its transferWithAuthorization validates signatures: look for a call to isValidSignature or a SignatureChecker. If it only calls ecrecover, wallet types B through E fail on-chain for EIP-3009 flows no matter how x402 is configured.
To confirm a token’s behavior, read its transferWithAuthorization source, call isValidSignature on the token through eth_call with a test signature, or trace a known smart-wallet payment on a block explorer and check for an internal isValidSignature call.

Wallet types

TypeHas code?Signing mechanism
A Plain EOANoRaw ECDSA from the private key
B Deployed smart account (ERC-4337)YesEIP-1271 isValidSignature on the contract
C Counterfactual smart account (ERC-6492)Not yet deployedEIP-1271 after the factory deploys it
D ERC-7702 EOA, permissive delegateYes (delegation)EIP-1271 on the delegate, which accepts raw owner ECDSA
E ERC-7702 EOA, strict delegateYes (delegation)EIP-1271 on the delegate, which requires a wrapped or prefixed format
  • Type B. Permissive means the account’s isValidSignature accepts a raw 65-byte ECDSA signature from the controlling key, which is common for wallets with a default ECDSA validator. An account that requires multisig or non-ECDSA authentication behaves like Type E.
  • Type C. ERC-6492 wraps a signature with factory deployment data so a wallet can authorize a payment before it exists on-chain. x402 deploys the wallet during settlement for the supported flows.
  • Types D and E. ERC-7702 lets an EOA delegate execution to a contract, and that delegate’s isValidSignature decides what counts as valid. A delegate that forwards owner ECDSA through a default validator is permissive; one that requires a validator-prefixed format (as many ERC-7579 accounts do without a fallback) is strict. Which one applies depends on the delegate and its installed validators.

Schemes and asset transfer methods

For batch-settlement, this table covers the deposit that funds a channel. Voucher signing is a separate concern, described after the matrix.
SchemeAsset transfer methodOn-chain verifier
exactEIP-3009 (transferWithAuthorization)Token’s SignatureChecker, typically code-routing
exactPermit2 (permitWitnessTransferFrom)Permit2’s SignatureVerification, code-routing
uptoPermit2 (permitWitnessTransferFrom)Permit2’s SignatureVerification, code-routing
batch-settlementERC-3009 depositToken’s SignatureChecker via ERC3009DepositCollector
batch-settlementPermit2 depositPermit2 via Permit2DepositCollector

Support matrix

The batch-settlement columns describe which wallet can sign the deposit that opens or funds a channel. ✅ Supported. ❌ Not supported (see footnote).
Wallet typeexact EIP-3009exact Permit2upto Permit2batch deposit (ERC-3009)batch deposit (Permit2)
A Plain EOA
B Deployed smart account
C ERC-6492 counterfactual✅ ¹❌ ²❌ ²✅ ³❌ ²
D 7702 + permissive delegate
E 7702 + strict delegate❌ ⁴❌ ⁴❌ ⁴❌ ⁴❌ ⁴
The three Permit2 columns (exact Permit2, upto, batch deposit Permit2) require the payer to hold a Permit2 allowance for the token. The EIP-3009 columns do not. See Permit2 allowance for how each wallet type establishes that allowance.

Footnotes

¹ ERC-6492 counterfactual with exact EIP-3009 Supported with configuration. During verify, x402 validates the inner signature with a single Multicall3 eth_call that deploys the wallet and runs transferWithAuthorization against it in one shot. Settle then deploys the wallet for real and submits transferWithAuthorization, which is itself the definitive check, so there is no second simulation after the deploy. This requires the facilitator to set an allowlist of permitted factory addresses (eip6492AllowedFactories). Arbitrary factory calls are blocked by default to prevent attacker-controlled transaction injection. If a wallet installs its verifying validator lazily rather than in the factory call (some ERC-7579 and Kernel session-key setups deploy with only a root validator), the deployed wallet can reject the inner signature and the on-chain transfer reverts. The wallet now exists, so retrying the payment usually settles, because a deployed wallet can produce a standard ERC-1271 signature. Wallets that install their full validator set during deployment settle on the first attempt. ² ERC-6492 counterfactual with Permit2 (exact, upto, or batch deposit) Not supported. Permit2’s permitWitnessTransferFrom calls isValidSignature on the payer at settlement, and the Permit2 path does not deploy the wallet first. With no code at the address, the call reverts and Permit2 rejects the payment. Permit2 has no counterfactual mechanism, so deploy the wallet before using any Permit2 flow. ³ ERC-6492 counterfactual with batch-settlement ERC-3009 deposit Supported with configuration, the same way as footnote ¹. When the deposit’s ERC-3009 authorization is ERC-6492-wrapped and the payer has no code, the facilitator deploys the wallet through the wrapped factory before submitting deposit. The ERC3009DepositCollector then calls receiveWithAuthorization, which routes to isValidSignature on the deployed wallet. The inner signature is validated during verify by the atomic factory-deploy-plus-deposit Multicall3 eth_call, and the real deposit is the definitive check at settle. This requires an allowlist of factory addresses (eip6492AllowedFactories on Go’s BatchSettlementEvmSchemeConfig, or the eip6492_allowed_factories / eip6492AllowedFactories constructor argument in Python and TypeScript). A deposit payload also carries a voucher, which is verified before the deposit runs. See Batch-settlement vouchers for how the counterfactual case constrains payerAuthorizer. ⁴ ERC-7702 strict delegate with any code-routed scheme Not supported by the default client. When an address has code, the verifier routes to isValidSignature on the delegate, and a strict delegate requires a specific format such as the validator-prefixed bytes used by ERC-7579 accounts with session-key validators. x402 signs with signTypedData, which produces a raw 65-byte ECDSA signature that a strict delegate rejects, so the payment fails on-chain even though signing succeeded. This is the verifier behaving correctly, not an x402 limitation. If you control the delegate, enabling a default ECDSA validator that accepts raw owner signatures turns the wallet into Type D and restores compatibility.

Permit2 allowance

Every Permit2 flow (exact Permit2, upto, and batch-settlement Permit2 deposits) moves funds through the canonical Permit2 contract, which first requires the payer to have approved Permit2 to spend the token. EIP-3009 flows do not, because the token transfer is authorized directly by the signature. A Permit2 payment from a payer with no allowance fails verification with permit2_allowance_required until the allowance exists. There are three ways to establish it:
  • A one-time on-chain approve(Permit2, max) from the payer. An EOA sends the transaction; a smart account does it through its execute(). After this, every later payment skips the step and no extension is needed.
  • The ERC-20 approval gas sponsoring extension. The payer signs an approve transaction and the facilitator broadcasts it, so the payer spends no gas.
  • The EIP-2612 gas sponsoring extension. The payer signs an EIP-2612 permit and the facilitator submits it before pulling funds.
Both gas-sponsoring extensions work only for EOAs and 7702-delegated EOAs. Each signs from the payer’s key: the ERC-20 extension signs a raw approval transaction sent from the payer address, and the EIP-2612 extension signs a permit that permit() recovers with ecrecover. A deployed smart account (ERC-1271) has no key for its own address, so it can use neither extension and must approve Permit2 itself with an on-chain approve through execute().

Batch-settlement vouchers

The matrix covers who can sign the deposit that funds a channel. Authorizing individual charges against that channel is separate: each charge is carried by a voucher that the facilitator verifies on a hot path, so voucher verification is built for speed rather than generality. The channel config’s payerAuthorizer chooses how a voucher is checked. payerAuthorizer set. The contract recovers the signer with ECDSA.recoverCalldata and requires it to equal payerAuthorizer. This is raw ECDSA over the digest and ignores account code, so payerAuthorizer must be an EOA address. A smart account or counterfactual address can never satisfy it, because its address is not recoverable from a signature. payerAuthorizer is address(0). The contract verifies the voucher against payer with SignatureChecker.isValidSignatureNow, which code-routes: EIP-1271 for an address with code, ECDSA otherwise. Choosing a path:
  • Plain EOA payer: either path works.
  • Smart account or 7702 payer: leave payerAuthorizer unset (address(0)) so the voucher routes to the payer’s isValidSignature. A 7702 EOA can instead set payerAuthorizer to its own EOA address, since ECDSA recovery returns the underlying key regardless of the delegation.
  • Counterfactual payer: not supported on either path, because voucher verification never deploys the wallet. With payerAuthorizer set, ECDSA recovers a key that does not match the smart-account address; with address(0), the code-routed check falls back to ecrecover against an address with no code and also fails. Deploy the wallet before opening a channel.
  • A smart-account address as payerAuthorizer never works.
For the counterfactual ERC-3009 deposit in footnote ³, set payerAuthorizer to an EOA you control so the voucher verifies via ECDSA, while the deposit authorization is still signed by (and deploys) the smart wallet.

Determining a wallet’s type

  1. Call eth_getCode(address).
    • Empty or 0x: Type A (plain EOA).
    • Exactly 23 bytes starting with 0xef0100: Type D or E (7702 delegation).
    • Any other non-empty bytecode: Type B (deployed smart account).
  2. For a 7702 address, call isValidSignature(digest, rawECDSASig). A return of 0x1626ba7e means a permissive delegate (Type D); 0xffffffff or a revert means a strict delegate (Type E).
  3. A counterfactual address (Type C) returns empty code, but its signing produces an ERC-6492-wrapped signature, recognizable by the 0x6492...6492 suffix.

Summary

QuestionWhy it matters
Does the address have code?Decides whether the verifier calls isValidSignature (with code) or ecrecover (without).
What does the delegate’s isValidSignature accept?Decides 7702 compatibility for code-routed schemes.
Which scheme is in use?Permit2 never supports counterfactual wallets; the code-routed EIP-3009 flows (exact EIP-3009 and batch-settlement ERC-3009 deposit) do, with an allowlisted factory.
Is it a Permit2 flow?If so, the payer needs a Permit2 allowance. Smart accounts must approve Permit2 themselves; EOAs and 7702 EOAs can use a gas-sponsoring extension.
Is payerAuthorizer set?If so, batch-settlement vouchers use ECDSA only, so the authorizer must be an EOA.