You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@x402/evm

Package Overview
Dependencies
Maintainers
2
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@x402/evm - npm Package Compare versions

Comparing version
2.6.0
to
2.7.0
+550
dist/cjs/permit2-U9Zolx3O.d.ts
import { SchemeNetworkClient, PaymentRequirements, PaymentPayloadContext, PaymentPayloadResult } from '@x402/core/types';
import { C as ClientEvmSigner } from './signer-D912R4mq.js';
type ExactEvmSchemeConfig = {
rpcUrl?: string;
};
type ExactEvmSchemeConfigByChainId = Record<number, ExactEvmSchemeConfig>;
type ExactEvmSchemeOptions = ExactEvmSchemeConfig | ExactEvmSchemeConfigByChainId;
/**
* EVM client implementation for the Exact payment scheme.
* Supports both EIP-3009 (transferWithAuthorization) and Permit2 flows.
*
* Routes to the appropriate authorization method based on
* `requirements.extra.assetTransferMethod`. Defaults to EIP-3009
* for backward compatibility with older facilitators.
*
* When the server advertises `eip2612GasSponsoring` and the asset transfer
* method is `permit2`, the scheme automatically signs an EIP-2612 permit
* if the user lacks Permit2 approval. This requires `readContract` on the signer.
*/
declare class ExactEvmScheme implements SchemeNetworkClient {
private readonly signer;
private readonly options?;
readonly scheme = "exact";
/**
* Creates a new ExactEvmClient instance.
*
* @param signer - The EVM signer for client operations.
* Base flow only requires `address` + `signTypedData`.
* Extension enrichment (EIP-2612 / ERC-20 approval sponsoring) additionally
* requires optional capabilities like `readContract` and tx signing helpers.
* @param options - Optional RPC configuration used to backfill extension capabilities.
*/
constructor(signer: ClientEvmSigner, options?: ExactEvmSchemeOptions | undefined);
/**
* Creates a payment payload for the Exact scheme.
* Routes to EIP-3009 or Permit2 based on requirements.extra.assetTransferMethod.
*
* For Permit2 flows, if the server advertises `eip2612GasSponsoring` and the
* signer supports `readContract`, automatically signs an EIP-2612 permit
* when Permit2 allowance is insufficient.
*
* @param x402Version - The x402 protocol version
* @param paymentRequirements - The payment requirements
* @param context - Optional context with server-declared extensions
* @returns Promise resolving to a payment payload result (with optional extensions)
*/
createPaymentPayload(x402Version: number, paymentRequirements: PaymentRequirements, context?: PaymentPayloadContext): Promise<PaymentPayloadResult>;
/**
* Attempts to sign an EIP-2612 permit for gasless Permit2 approval.
*
* Returns extension data if:
* 1. Server advertises eip2612GasSponsoring
* 2. Signer has readContract capability
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param result - The payment payload result from the scheme
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for EIP-2612 gas sponsoring, or undefined if not applicable
*/
private trySignEip2612Permit;
/**
* Attempts to sign an ERC-20 approval transaction for gasless Permit2 approval.
*
* This is the fallback path when the token does not support EIP-2612. The client
* signs (but does not broadcast) a raw `approve(Permit2, MaxUint256)` transaction.
* The facilitator broadcasts it atomically before settling.
*
* Returns extension data if:
* 1. Server advertises erc20ApprovalGasSponsoring
* 2. Signer has signTransaction + getTransactionCount capabilities
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param _result - The payment payload result from the scheme (unused)
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for ERC-20 approval gas sponsoring, or undefined if not applicable
*/
private trySignErc20Approval;
}
declare const authorizationTypes: {
readonly TransferWithAuthorization: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}];
};
/**
* Permit2 EIP-712 types for signing PermitWitnessTransferFrom.
* Must match the exact format expected by the Permit2 contract.
* Note: Types must be in ALPHABETICAL order after the primary type (TokenPermissions < Witness).
*/
declare const permit2WitnessTypes: {
readonly PermitWitnessTransferFrom: readonly [{
readonly name: "permitted";
readonly type: "TokenPermissions";
}, {
readonly name: "spender";
readonly type: "address";
}, {
readonly name: "nonce";
readonly type: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
}, {
readonly name: "witness";
readonly type: "Witness";
}];
readonly TokenPermissions: readonly [{
readonly name: "token";
readonly type: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
}];
readonly Witness: readonly [{
readonly name: "to";
readonly type: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}];
};
declare const eip3009ABI: readonly [{
readonly inputs: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}, {
readonly name: "v";
readonly type: "uint8";
}, {
readonly name: "r";
readonly type: "bytes32";
}, {
readonly name: "s";
readonly type: "bytes32";
}];
readonly name: "transferWithAuthorization";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}, {
readonly name: "signature";
readonly type: "bytes";
}];
readonly name: "transferWithAuthorization";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly name: "account";
readonly type: "address";
}];
readonly name: "balanceOf";
readonly outputs: readonly [{
readonly name: "";
readonly type: "uint256";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [];
readonly name: "version";
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [];
readonly name: "name";
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly name: "authorizer";
readonly type: "address";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}];
readonly name: "authorizationState";
readonly outputs: readonly [{
readonly name: "";
readonly type: "bool";
}];
readonly stateMutability: "view";
readonly type: "function";
}];
/** ERC-20 allowance(address,address) ABI for checking spender approval. */
declare const erc20AllowanceAbi: readonly [{
readonly type: "function";
readonly name: "allowance";
readonly inputs: readonly [{
readonly name: "owner";
readonly type: "address";
}, {
readonly name: "spender";
readonly type: "address";
}];
readonly outputs: readonly [{
readonly type: "uint256";
}];
readonly stateMutability: "view";
}];
/**
* Canonical Permit2 contract address.
* Same address on all EVM chains via CREATE2 deployment.
*
* @see https://github.com/Uniswap/permit2
*/
declare const PERMIT2_ADDRESS: "0x000000000022D473030F116dDEE9F6B43aC78BA3";
/**
* x402ExactPermit2Proxy contract address.
* Vanity address: 0x4020...0001 for easy recognition.
* This address is deterministic based on:
* - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)
* - Vanity-mined salt for prefix 0x4020 and suffix 0001
* - Contract bytecode + constructor args (PERMIT2_ADDRESS)
*/
declare const x402ExactPermit2ProxyAddress: "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";
/**
* x402UptoPermit2Proxy contract address.
* Vanity address: 0x4020...0002 for easy recognition.
* This address is deterministic based on:
* - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)
* - Vanity-mined salt for prefix 0x4020 and suffix 0002
* - Contract bytecode + constructor args (PERMIT2_ADDRESS)
*/
declare const x402UptoPermit2ProxyAddress: "0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002";
/**
* x402ExactPermit2Proxy ABI - settle function for exact payment scheme.
*/
declare const x402ExactPermit2ProxyABI: readonly [{
readonly type: "function";
readonly name: "PERMIT2";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "address";
readonly internalType: "contract ISignatureTransfer";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "WITNESS_TYPEHASH";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "bytes32";
readonly internalType: "bytes32";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "WITNESS_TYPE_STRING";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
readonly internalType: "string";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "settle";
readonly inputs: readonly [{
readonly name: "permit";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.PermitTransferFrom";
readonly components: readonly [{
readonly name: "permitted";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.TokenPermissions";
readonly components: readonly [{
readonly name: "token";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "nonce";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "owner";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "witness";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.Witness";
readonly components: readonly [{
readonly name: "to";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "signature";
readonly type: "bytes";
readonly internalType: "bytes";
}];
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
}, {
readonly type: "function";
readonly name: "settleWithPermit";
readonly inputs: readonly [{
readonly name: "permit2612";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.EIP2612Permit";
readonly components: readonly [{
readonly name: "value";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "r";
readonly type: "bytes32";
readonly internalType: "bytes32";
}, {
readonly name: "s";
readonly type: "bytes32";
readonly internalType: "bytes32";
}, {
readonly name: "v";
readonly type: "uint8";
readonly internalType: "uint8";
}];
}, {
readonly name: "permit";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.PermitTransferFrom";
readonly components: readonly [{
readonly name: "permitted";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.TokenPermissions";
readonly components: readonly [{
readonly name: "token";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "nonce";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "owner";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "witness";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.Witness";
readonly components: readonly [{
readonly name: "to";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "signature";
readonly type: "bytes";
readonly internalType: "bytes";
}];
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
}, {
readonly type: "event";
readonly name: "Settled";
readonly inputs: readonly [];
readonly anonymous: false;
}, {
readonly type: "event";
readonly name: "SettledWithPermit";
readonly inputs: readonly [];
readonly anonymous: false;
}, {
readonly type: "error";
readonly name: "InvalidAmount";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidDestination";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidOwner";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidPermit2Address";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "PaymentTooEarly";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "Permit2612AmountMismatch";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "ReentrancyGuardReentrantCall";
readonly inputs: readonly [];
}];
/**
* Creates transaction data to approve Permit2 to spend tokens.
* The user sends this transaction (paying gas) before using Permit2 flow.
*
* @param tokenAddress - The ERC20 token contract address
* @returns Transaction data to send for approval
*
* @example
* ```typescript
* const tx = createPermit2ApprovalTx("0x...");
* await walletClient.sendTransaction({
* to: tx.to,
* data: tx.data,
* });
* ```
*/
declare function createPermit2ApprovalTx(tokenAddress: `0x${string}`): {
to: `0x${string}`;
data: `0x${string}`;
};
/**
* Parameters for checking Permit2 allowance.
* Application provides these to check if approval is needed.
*/
interface Permit2AllowanceParams {
tokenAddress: `0x${string}`;
ownerAddress: `0x${string}`;
}
/**
* Returns contract read parameters for checking Permit2 allowance.
* Use with a public client to check if the user has approved Permit2.
*
* @param params - The allowance check parameters
* @returns Contract read parameters for checking allowance
*
* @example
* ```typescript
* const readParams = getPermit2AllowanceReadParams({
* tokenAddress: "0x...",
* ownerAddress: "0x...",
* });
*
* const allowance = await publicClient.readContract(readParams);
* const needsApproval = allowance < requiredAmount;
* ```
*/
declare function getPermit2AllowanceReadParams(params: Permit2AllowanceParams): {
address: `0x${string}`;
abi: typeof erc20AllowanceAbi;
functionName: "allowance";
args: [`0x${string}`, `0x${string}`];
};
export { ExactEvmScheme as E, type Permit2AllowanceParams as P, PERMIT2_ADDRESS as a, x402UptoPermit2ProxyAddress as b, createPermit2ApprovalTx as c, authorizationTypes as d, erc20AllowanceAbi as e, eip3009ABI as f, getPermit2AllowanceReadParams as g, x402ExactPermit2ProxyABI as h, type ExactEvmSchemeOptions as i, type ExactEvmSchemeConfig as j, type ExactEvmSchemeConfigByChainId as k, permit2WitnessTypes as p, x402ExactPermit2ProxyAddress as x };
/**
* ClientEvmSigner - Used by x402 clients to sign payment authorizations.
*
* Typically a viem WalletClient extended with publicActions:
* ```typescript
* const client = createWalletClient({
* account: privateKeyToAccount('0x...'),
* chain: baseSepolia,
* transport: http(),
* }).extend(publicActions);
* ```
*
* Or composed via `toClientEvmSigner(account, publicClient)`.
*/
type ClientEvmSigner = {
readonly address: `0x${string}`;
signTypedData(message: {
domain: Record<string, unknown>;
types: Record<string, unknown>;
primaryType: string;
message: Record<string, unknown>;
}): Promise<`0x${string}`>;
/**
* Optional on-chain reads.
* Required only for extension enrichment (EIP-2612 / ERC-20 approval).
*/
readContract?(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
/**
* Optional: Signs a raw EIP-1559 transaction without broadcasting.
* Required for ERC-20 approval gas sponsoring when the token lacks EIP-2612.
*/
signTransaction?(args: {
to: `0x${string}`;
data: `0x${string}`;
nonce: number;
gas: bigint;
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
chainId: number;
}): Promise<`0x${string}`>;
/**
* Optional: Gets the current transaction count (nonce) for an address.
* Required for ERC-20 approval gas sponsoring.
*/
getTransactionCount?(args: {
address: `0x${string}`;
}): Promise<number>;
/**
* Optional: Estimates current gas fees per gas.
* Required for ERC-20 approval gas sponsoring.
*/
estimateFeesPerGas?(): Promise<{
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
}>;
};
/**
* FacilitatorEvmSigner - Used by x402 facilitators to verify and settle payments
* This is typically a viem PublicClient + WalletClient combination that can
* read contract state, verify signatures, write transactions, and wait for receipts
*
* Supports multiple addresses for load balancing, key rotation, and high availability
*/
type FacilitatorEvmSigner = {
/**
* Get all addresses this facilitator can use for signing
* Enables dynamic address selection for load balancing and key rotation
*/
getAddresses(): readonly `0x${string}`[];
readContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
verifyTypedData(args: {
address: `0x${string}`;
domain: Record<string, unknown>;
types: Record<string, unknown>;
primaryType: string;
message: Record<string, unknown>;
signature: `0x${string}`;
}): Promise<boolean>;
writeContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args: readonly unknown[];
/** Optional gas limit. When provided, skips eth_estimateGas simulation. */
gas?: bigint;
}): Promise<`0x${string}`>;
sendTransaction(args: {
to: `0x${string}`;
data: `0x${string}`;
}): Promise<`0x${string}`>;
waitForTransactionReceipt(args: {
hash: `0x${string}`;
}): Promise<{
status: string;
}>;
getCode(args: {
address: `0x${string}`;
}): Promise<`0x${string}` | undefined>;
};
/**
* Composes a ClientEvmSigner from a local account and a public client.
*
* Use this when your signer (e.g., `privateKeyToAccount`) doesn't have
* `readContract`. The `publicClient` provides the on-chain read capability.
*
* Alternatively, use a WalletClient extended with publicActions directly:
* ```typescript
* const signer = createWalletClient({
* account: privateKeyToAccount('0x...'),
* chain: baseSepolia,
* transport: http(),
* }).extend(publicActions);
* ```
*
* @param signer - A signer with `address` and `signTypedData` (and optionally `readContract`)
* @param publicClient - A client with optional read/nonce/fee helpers
* @param publicClient.readContract - The readContract method from the public client
* @param publicClient.getTransactionCount - Optional getTransactionCount for ERC-20 approval
* @param publicClient.estimateFeesPerGas - Optional estimateFeesPerGas for ERC-20 approval
* @returns A ClientEvmSigner with any available optional capabilities
*
* @example
* ```typescript
* const account = privateKeyToAccount("0x...");
* const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
* const signer = toClientEvmSigner(account, publicClient);
* ```
*/
declare function toClientEvmSigner(signer: Omit<ClientEvmSigner, "readContract"> & {
readContract?: ClientEvmSigner["readContract"];
}, publicClient?: {
readContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
getTransactionCount?(args: {
address: `0x${string}`;
}): Promise<number>;
estimateFeesPerGas?(): Promise<{
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
}>;
}): ClientEvmSigner;
/**
* Converts a viem client with single address to a FacilitatorEvmSigner
* Wraps the single address in a getAddresses() function for compatibility
*
* @param client - The client to convert (must have 'address' property)
* @returns FacilitatorEvmSigner with getAddresses() support
*/
declare function toFacilitatorEvmSigner(client: Omit<FacilitatorEvmSigner, "getAddresses"> & {
address: `0x${string}`;
}): FacilitatorEvmSigner;
export { type ClientEvmSigner as C, type FacilitatorEvmSigner as F, toFacilitatorEvmSigner as a, toClientEvmSigner as t };
// src/exact/extensions.ts
var EIP2612_GAS_SPONSORING_KEY = "eip2612GasSponsoring";
var ERC20_APPROVAL_GAS_SPONSORING_KEY = "erc20ApprovalGasSponsoring";
var ERC20_APPROVAL_GAS_SPONSORING_VERSION = "1";
function _extractInfo(payload, extensionKey) {
const extensions = payload.extensions;
if (!extensions) return null;
const extension = extensions[extensionKey];
if (!extension?.info) return null;
return extension.info;
}
function extractEip2612GasSponsoringInfo(payload) {
const info = _extractInfo(payload, EIP2612_GAS_SPONSORING_KEY);
if (!info) return null;
if (!info.from || !info.asset || !info.spender || !info.amount || !info.nonce || !info.deadline || !info.signature || !info.version) {
return null;
}
return info;
}
function validateEip2612GasSponsoringInfo(info) {
const addressPattern = /^0x[a-fA-F0-9]{40}$/;
const numericPattern = /^[0-9]+$/;
const hexPattern = /^0x[a-fA-F0-9]+$/;
const versionPattern = /^[0-9]+(\.[0-9]+)*$/;
return addressPattern.test(info.from) && addressPattern.test(info.asset) && addressPattern.test(info.spender) && numericPattern.test(info.amount) && numericPattern.test(info.nonce) && numericPattern.test(info.deadline) && hexPattern.test(info.signature) && versionPattern.test(info.version);
}
function extractErc20ApprovalGasSponsoringInfo(payload) {
const info = _extractInfo(payload, ERC20_APPROVAL_GAS_SPONSORING_KEY);
if (!info) return null;
if (!info.from || !info.asset || !info.spender || !info.amount || !info.signedTransaction || !info.version) {
return null;
}
return info;
}
function validateErc20ApprovalGasSponsoringInfo(info) {
const addressPattern = /^0x[a-fA-F0-9]{40}$/;
const numericPattern = /^[0-9]+$/;
const hexPattern = /^0x[a-fA-F0-9]+$/;
const versionPattern = /^[0-9]+(\.[0-9]+)*$/;
return addressPattern.test(info.from) && addressPattern.test(info.asset) && addressPattern.test(info.spender) && numericPattern.test(info.amount) && hexPattern.test(info.signedTransaction) && versionPattern.test(info.version);
}
function resolveErc20ApprovalExtensionSigner(extension, network) {
if (!extension) return void 0;
return extension.signerForNetwork?.(network) ?? extension.signer;
}
export {
EIP2612_GAS_SPONSORING_KEY,
ERC20_APPROVAL_GAS_SPONSORING_KEY,
ERC20_APPROVAL_GAS_SPONSORING_VERSION,
extractEip2612GasSponsoringInfo,
validateEip2612GasSponsoringInfo,
extractErc20ApprovalGasSponsoringInfo,
validateErc20ApprovalGasSponsoringInfo,
resolveErc20ApprovalExtensionSigner
};
//# sourceMappingURL=chunk-GD4MKCN7.mjs.map
{"version":3,"sources":["../../src/exact/extensions.ts"],"sourcesContent":["import type { PaymentPayload } from \"@x402/core/types\";\nimport type { FacilitatorEvmSigner } from \"../signer\";\n\nexport const EIP2612_GAS_SPONSORING_KEY = \"eip2612GasSponsoring\" as const;\nexport const ERC20_APPROVAL_GAS_SPONSORING_KEY = \"erc20ApprovalGasSponsoring\" as const;\nexport const ERC20_APPROVAL_GAS_SPONSORING_VERSION = \"1\" as const;\n\nexport interface Eip2612GasSponsoringInfo {\n [key: string]: unknown;\n from: string;\n asset: string;\n spender: string;\n amount: string;\n nonce: string;\n deadline: string;\n signature: string;\n version: string;\n}\n\nexport interface Erc20ApprovalGasSponsoringInfo {\n [key: string]: unknown;\n from: `0x${string}`;\n asset: `0x${string}`;\n spender: `0x${string}`;\n amount: string;\n signedTransaction: `0x${string}`;\n version: string;\n}\n\n/**\n * A single transaction to be executed by the signer.\n * - `0x${string}`: a pre-signed serialized transaction (broadcast as-is via sendRawTransaction)\n * - `{ to, data, gas? }`: an unsigned call intent (signer signs and broadcasts)\n */\nexport type TransactionRequest =\n | `0x${string}`\n | { to: `0x${string}`; data: `0x${string}`; gas?: bigint };\n\nexport type Erc20ApprovalGasSponsoringSigner = FacilitatorEvmSigner & {\n sendTransactions(transactions: TransactionRequest[]): Promise<`0x${string}`[]>;\n simulateTransactions?(transactions: TransactionRequest[]): Promise<boolean>;\n};\n\nexport interface Erc20ApprovalGasSponsoringFacilitatorExtension {\n key: typeof ERC20_APPROVAL_GAS_SPONSORING_KEY;\n signer?: Erc20ApprovalGasSponsoringSigner;\n signerForNetwork?: (network: string) => Erc20ApprovalGasSponsoringSigner | undefined;\n}\n\n/**\n * Extracts a typed `info` payload from an extension entry.\n *\n * @param payload - Payment payload containing optional extensions.\n * @param extensionKey - Extension key to extract.\n * @returns The extension `info` object when present; otherwise null.\n */\nfunction _extractInfo(\n payload: PaymentPayload,\n extensionKey: string,\n): Record<string, unknown> | null {\n const extensions = payload.extensions;\n if (!extensions) return null;\n const extension = extensions[extensionKey] as { info?: Record<string, unknown> } | undefined;\n if (!extension?.info) return null;\n return extension.info;\n}\n\n/**\n * Extracts and validates required EIP-2612 gas sponsoring fields.\n *\n * @param payload - Payment payload returned by the client scheme.\n * @returns Parsed EIP-2612 gas sponsoring info when available and complete.\n */\nexport function extractEip2612GasSponsoringInfo(\n payload: PaymentPayload,\n): Eip2612GasSponsoringInfo | null {\n const info = _extractInfo(payload, EIP2612_GAS_SPONSORING_KEY);\n if (!info) return null;\n if (\n !info.from ||\n !info.asset ||\n !info.spender ||\n !info.amount ||\n !info.nonce ||\n !info.deadline ||\n !info.signature ||\n !info.version\n ) {\n return null;\n }\n return info as unknown as Eip2612GasSponsoringInfo;\n}\n\n/**\n * Validates the structure and formatting of EIP-2612 sponsoring info.\n *\n * @param info - EIP-2612 extension info to validate.\n * @returns True when all required fields match expected patterns.\n */\nexport function validateEip2612GasSponsoringInfo(info: Eip2612GasSponsoringInfo): boolean {\n const addressPattern = /^0x[a-fA-F0-9]{40}$/;\n const numericPattern = /^[0-9]+$/;\n const hexPattern = /^0x[a-fA-F0-9]+$/;\n const versionPattern = /^[0-9]+(\\.[0-9]+)*$/;\n return (\n addressPattern.test(info.from) &&\n addressPattern.test(info.asset) &&\n addressPattern.test(info.spender) &&\n numericPattern.test(info.amount) &&\n numericPattern.test(info.nonce) &&\n numericPattern.test(info.deadline) &&\n hexPattern.test(info.signature) &&\n versionPattern.test(info.version)\n );\n}\n\n/**\n * Extracts and validates required ERC-20 approval sponsoring fields.\n *\n * @param payload - Payment payload returned by the client scheme.\n * @returns Parsed ERC-20 approval sponsoring info when available and complete.\n */\nexport function extractErc20ApprovalGasSponsoringInfo(\n payload: PaymentPayload,\n): Erc20ApprovalGasSponsoringInfo | null {\n const info = _extractInfo(payload, ERC20_APPROVAL_GAS_SPONSORING_KEY);\n if (!info) return null;\n if (\n !info.from ||\n !info.asset ||\n !info.spender ||\n !info.amount ||\n !info.signedTransaction ||\n !info.version\n ) {\n return null;\n }\n return info as unknown as Erc20ApprovalGasSponsoringInfo;\n}\n\n/**\n * Validates the structure and formatting of ERC-20 approval sponsoring info.\n *\n * @param info - ERC-20 approval extension info to validate.\n * @returns True when all required fields match expected patterns.\n */\nexport function validateErc20ApprovalGasSponsoringInfo(\n info: Erc20ApprovalGasSponsoringInfo,\n): boolean {\n const addressPattern = /^0x[a-fA-F0-9]{40}$/;\n const numericPattern = /^[0-9]+$/;\n const hexPattern = /^0x[a-fA-F0-9]+$/;\n const versionPattern = /^[0-9]+(\\.[0-9]+)*$/;\n return (\n addressPattern.test(info.from) &&\n addressPattern.test(info.asset) &&\n addressPattern.test(info.spender) &&\n numericPattern.test(info.amount) &&\n hexPattern.test(info.signedTransaction) &&\n versionPattern.test(info.version)\n );\n}\n\n/**\n * Resolves the ERC-20 approval extension signer for a specific network.\n *\n * @param extension - Optional facilitator extension config.\n * @param network - CAIP-2 network identifier.\n * @returns A network-specific signer when available, else the default signer.\n */\nexport function resolveErc20ApprovalExtensionSigner(\n extension: Erc20ApprovalGasSponsoringFacilitatorExtension | undefined,\n network: string,\n): Erc20ApprovalGasSponsoringSigner | undefined {\n if (!extension) return undefined;\n return extension.signerForNetwork?.(network) ?? extension.signer;\n}\n"],"mappings":";AAGO,IAAM,6BAA6B;AACnC,IAAM,oCAAoC;AAC1C,IAAM,wCAAwC;AAmDrD,SAAS,aACP,SACA,cACgC;AAChC,QAAM,aAAa,QAAQ;AAC3B,MAAI,CAAC,WAAY,QAAO;AACxB,QAAM,YAAY,WAAW,YAAY;AACzC,MAAI,CAAC,WAAW,KAAM,QAAO;AAC7B,SAAO,UAAU;AACnB;AAQO,SAAS,gCACd,SACiC;AACjC,QAAM,OAAO,aAAa,SAAS,0BAA0B;AAC7D,MAAI,CAAC,KAAM,QAAO;AAClB,MACE,CAAC,KAAK,QACN,CAAC,KAAK,SACN,CAAC,KAAK,WACN,CAAC,KAAK,UACN,CAAC,KAAK,SACN,CAAC,KAAK,YACN,CAAC,KAAK,aACN,CAAC,KAAK,SACN;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAQO,SAAS,iCAAiC,MAAyC;AACxF,QAAM,iBAAiB;AACvB,QAAM,iBAAiB;AACvB,QAAM,aAAa;AACnB,QAAM,iBAAiB;AACvB,SACE,eAAe,KAAK,KAAK,IAAI,KAC7B,eAAe,KAAK,KAAK,KAAK,KAC9B,eAAe,KAAK,KAAK,OAAO,KAChC,eAAe,KAAK,KAAK,MAAM,KAC/B,eAAe,KAAK,KAAK,KAAK,KAC9B,eAAe,KAAK,KAAK,QAAQ,KACjC,WAAW,KAAK,KAAK,SAAS,KAC9B,eAAe,KAAK,KAAK,OAAO;AAEpC;AAQO,SAAS,sCACd,SACuC;AACvC,QAAM,OAAO,aAAa,SAAS,iCAAiC;AACpE,MAAI,CAAC,KAAM,QAAO;AAClB,MACE,CAAC,KAAK,QACN,CAAC,KAAK,SACN,CAAC,KAAK,WACN,CAAC,KAAK,UACN,CAAC,KAAK,qBACN,CAAC,KAAK,SACN;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAQO,SAAS,uCACd,MACS;AACT,QAAM,iBAAiB;AACvB,QAAM,iBAAiB;AACvB,QAAM,aAAa;AACnB,QAAM,iBAAiB;AACvB,SACE,eAAe,KAAK,KAAK,IAAI,KAC7B,eAAe,KAAK,KAAK,KAAK,KAC9B,eAAe,KAAK,KAAK,OAAO,KAChC,eAAe,KAAK,KAAK,MAAM,KAC/B,WAAW,KAAK,KAAK,iBAAiB,KACtC,eAAe,KAAK,KAAK,OAAO;AAEpC;AASO,SAAS,oCACd,WACA,SAC8C;AAC9C,MAAI,CAAC,UAAW,QAAO;AACvB,SAAO,UAAU,mBAAmB,OAAO,KAAK,UAAU;AAC5D;","names":[]}
// src/exact/v1/client/scheme.ts
import { getAddress } from "viem";
// src/constants.ts
var authorizationTypes = {
TransferWithAuthorization: [
{ name: "from", type: "address" },
{ name: "to", type: "address" },
{ name: "value", type: "uint256" },
{ name: "validAfter", type: "uint256" },
{ name: "validBefore", type: "uint256" },
{ name: "nonce", type: "bytes32" }
]
};
var permit2WitnessTypes = {
PermitWitnessTransferFrom: [
{ name: "permitted", type: "TokenPermissions" },
{ name: "spender", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
{ name: "witness", type: "Witness" }
],
TokenPermissions: [
{ name: "token", type: "address" },
{ name: "amount", type: "uint256" }
],
Witness: [
{ name: "to", type: "address" },
{ name: "validAfter", type: "uint256" }
]
};
var eip3009ABI = [
{
inputs: [
{ name: "from", type: "address" },
{ name: "to", type: "address" },
{ name: "value", type: "uint256" },
{ name: "validAfter", type: "uint256" },
{ name: "validBefore", type: "uint256" },
{ name: "nonce", type: "bytes32" },
{ name: "v", type: "uint8" },
{ name: "r", type: "bytes32" },
{ name: "s", type: "bytes32" }
],
name: "transferWithAuthorization",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ name: "from", type: "address" },
{ name: "to", type: "address" },
{ name: "value", type: "uint256" },
{ name: "validAfter", type: "uint256" },
{ name: "validBefore", type: "uint256" },
{ name: "nonce", type: "bytes32" },
{ name: "signature", type: "bytes" }
],
name: "transferWithAuthorization",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [{ name: "account", type: "address" }],
name: "balanceOf",
outputs: [{ name: "", type: "uint256" }],
stateMutability: "view",
type: "function"
},
{
inputs: [],
name: "version",
outputs: [{ name: "", type: "string" }],
stateMutability: "view",
type: "function"
},
{
inputs: [],
name: "name",
outputs: [{ name: "", type: "string" }],
stateMutability: "view",
type: "function"
},
{
inputs: [
{ name: "authorizer", type: "address" },
{ name: "nonce", type: "bytes32" }
],
name: "authorizationState",
outputs: [{ name: "", type: "bool" }],
stateMutability: "view",
type: "function"
}
];
var eip2612PermitTypes = {
Permit: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" }
]
};
var eip2612NoncesAbi = [
{
type: "function",
name: "nonces",
inputs: [{ name: "owner", type: "address" }],
outputs: [{ type: "uint256" }],
stateMutability: "view"
}
];
var erc20ApproveAbi = [
{
type: "function",
name: "approve",
inputs: [
{ name: "spender", type: "address" },
{ name: "amount", type: "uint256" }
],
outputs: [{ type: "bool" }],
stateMutability: "nonpayable"
}
];
var erc20AllowanceAbi = [
{
type: "function",
name: "allowance",
inputs: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" }
],
outputs: [{ type: "uint256" }],
stateMutability: "view"
}
];
var ERC20_APPROVE_GAS_LIMIT = 70000n;
var DEFAULT_MAX_FEE_PER_GAS = 1000000000n;
var DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100000000n;
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
var x402ExactPermit2ProxyAddress = "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";
var x402UptoPermit2ProxyAddress = "0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002";
var permit2WitnessABIComponents = [
{ name: "to", type: "address", internalType: "address" },
{ name: "validAfter", type: "uint256", internalType: "uint256" }
];
var x402ExactPermit2ProxyABI = [
{
type: "function",
name: "PERMIT2",
inputs: [],
outputs: [{ name: "", type: "address", internalType: "contract ISignatureTransfer" }],
stateMutability: "view"
},
{
type: "function",
name: "WITNESS_TYPEHASH",
inputs: [],
outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
stateMutability: "view"
},
{
type: "function",
name: "WITNESS_TYPE_STRING",
inputs: [],
outputs: [{ name: "", type: "string", internalType: "string" }],
stateMutability: "view"
},
{
type: "function",
name: "settle",
inputs: [
{
name: "permit",
type: "tuple",
internalType: "struct ISignatureTransfer.PermitTransferFrom",
components: [
{
name: "permitted",
type: "tuple",
internalType: "struct ISignatureTransfer.TokenPermissions",
components: [
{ name: "token", type: "address", internalType: "address" },
{ name: "amount", type: "uint256", internalType: "uint256" }
]
},
{ name: "nonce", type: "uint256", internalType: "uint256" },
{ name: "deadline", type: "uint256", internalType: "uint256" }
]
},
{ name: "owner", type: "address", internalType: "address" },
{
name: "witness",
type: "tuple",
internalType: "struct x402ExactPermit2Proxy.Witness",
components: permit2WitnessABIComponents
},
{ name: "signature", type: "bytes", internalType: "bytes" }
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "settleWithPermit",
inputs: [
{
name: "permit2612",
type: "tuple",
internalType: "struct x402ExactPermit2Proxy.EIP2612Permit",
components: [
{ name: "value", type: "uint256", internalType: "uint256" },
{ name: "deadline", type: "uint256", internalType: "uint256" },
{ name: "r", type: "bytes32", internalType: "bytes32" },
{ name: "s", type: "bytes32", internalType: "bytes32" },
{ name: "v", type: "uint8", internalType: "uint8" }
]
},
{
name: "permit",
type: "tuple",
internalType: "struct ISignatureTransfer.PermitTransferFrom",
components: [
{
name: "permitted",
type: "tuple",
internalType: "struct ISignatureTransfer.TokenPermissions",
components: [
{ name: "token", type: "address", internalType: "address" },
{ name: "amount", type: "uint256", internalType: "uint256" }
]
},
{ name: "nonce", type: "uint256", internalType: "uint256" },
{ name: "deadline", type: "uint256", internalType: "uint256" }
]
},
{ name: "owner", type: "address", internalType: "address" },
{
name: "witness",
type: "tuple",
internalType: "struct x402ExactPermit2Proxy.Witness",
components: permit2WitnessABIComponents
},
{ name: "signature", type: "bytes", internalType: "bytes" }
],
outputs: [],
stateMutability: "nonpayable"
},
{ type: "event", name: "Settled", inputs: [], anonymous: false },
{ type: "event", name: "SettledWithPermit", inputs: [], anonymous: false },
{ type: "error", name: "InvalidAmount", inputs: [] },
{ type: "error", name: "InvalidDestination", inputs: [] },
{ type: "error", name: "InvalidOwner", inputs: [] },
{ type: "error", name: "InvalidPermit2Address", inputs: [] },
{ type: "error", name: "PaymentTooEarly", inputs: [] },
{ type: "error", name: "Permit2612AmountMismatch", inputs: [] },
{ type: "error", name: "ReentrancyGuardReentrantCall", inputs: [] }
];
// src/utils.ts
import { toHex } from "viem";
function getEvmChainId(network) {
if (network.startsWith("eip155:")) {
const idStr = network.split(":")[1];
const chainId = parseInt(idStr, 10);
if (isNaN(chainId)) {
throw new Error(`Invalid CAIP-2 chain ID: ${network}`);
}
return chainId;
}
throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);
}
function getCrypto() {
const cryptoObj = globalThis.crypto;
if (!cryptoObj) {
throw new Error("Crypto API not available");
}
return cryptoObj;
}
function createNonce() {
return toHex(getCrypto().getRandomValues(new Uint8Array(32)));
}
function createPermit2Nonce() {
const randomBytes = getCrypto().getRandomValues(new Uint8Array(32));
return BigInt(toHex(randomBytes)).toString();
}
// src/exact/v1/client/scheme.ts
var ExactEvmSchemeV1 = class {
/**
* Creates a new ExactEvmClientV1 instance.
*
* @param signer - The EVM signer for client operations
*/
constructor(signer) {
this.signer = signer;
this.scheme = "exact";
}
/**
* Creates a payment payload for the Exact scheme (V1).
*
* @param x402Version - The x402 protocol version
* @param paymentRequirements - The payment requirements
* @returns Promise resolving to a payment payload
*/
async createPaymentPayload(x402Version, paymentRequirements) {
const selectedV1 = paymentRequirements;
const nonce = createNonce();
const now = Math.floor(Date.now() / 1e3);
const authorization = {
from: this.signer.address,
to: getAddress(selectedV1.payTo),
value: selectedV1.maxAmountRequired,
validAfter: (now - 600).toString(),
// 10 minutes before
validBefore: (now + selectedV1.maxTimeoutSeconds).toString(),
nonce
};
const signature = await this.signAuthorization(authorization, selectedV1);
const payload = {
authorization,
signature
};
return {
x402Version,
scheme: selectedV1.scheme,
network: selectedV1.network,
payload
};
}
/**
* Sign the EIP-3009 authorization using EIP-712
*
* @param authorization - The authorization to sign
* @param requirements - The payment requirements
* @returns Promise resolving to the signature
*/
async signAuthorization(authorization, requirements) {
const chainId = getEvmChainIdV1(requirements.network);
if (!requirements.extra?.name || !requirements.extra?.version) {
throw new Error(
`EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`
);
}
const { name, version } = requirements.extra;
const domain = {
name,
version,
chainId,
verifyingContract: getAddress(requirements.asset)
};
const message = {
from: getAddress(authorization.from),
to: getAddress(authorization.to),
value: BigInt(authorization.value),
validAfter: BigInt(authorization.validAfter),
validBefore: BigInt(authorization.validBefore),
nonce: authorization.nonce
};
return await this.signer.signTypedData({
domain,
types: authorizationTypes,
primaryType: "TransferWithAuthorization",
message
});
}
};
// src/exact/v1/facilitator/scheme.ts
import { getAddress as getAddress3, isAddressEqual, parseErc6492Signature as parseErc6492Signature2 } from "viem";
// src/exact/facilitator/errors.ts
var ErrInvalidScheme = "invalid_exact_evm_scheme";
var ErrNetworkMismatch = "invalid_exact_evm_network_mismatch";
var ErrMissingEip712Domain = "invalid_exact_evm_missing_eip712_domain";
var ErrRecipientMismatch = "invalid_exact_evm_recipient_mismatch";
var ErrInvalidSignature = "invalid_exact_evm_signature";
var ErrValidBeforeExpired = "invalid_exact_evm_payload_authorization_valid_before";
var ErrValidAfterInFuture = "invalid_exact_evm_payload_authorization_valid_after";
var ErrInvalidAuthorizationValue = "invalid_exact_evm_authorization_value";
var ErrUndeployedSmartWallet = "invalid_exact_evm_payload_undeployed_smart_wallet";
var ErrTransactionFailed = "invalid_exact_evm_transaction_failed";
var ErrEip3009TokenNameMismatch = "invalid_exact_evm_token_name_mismatch";
var ErrEip3009TokenVersionMismatch = "invalid_exact_evm_token_version_mismatch";
var ErrEip3009NotSupported = "invalid_exact_evm_eip3009_not_supported";
var ErrEip3009NonceAlreadyUsed = "invalid_exact_evm_nonce_already_used";
var ErrEip3009InsufficientBalance = "invalid_exact_evm_insufficient_balance";
var ErrEip3009SimulationFailed = "invalid_exact_evm_transaction_simulation_failed";
var ErrPermit2InvalidSpender = "invalid_permit2_spender";
var ErrPermit2RecipientMismatch = "invalid_permit2_recipient_mismatch";
var ErrPermit2DeadlineExpired = "permit2_deadline_expired";
var ErrPermit2NotYetValid = "permit2_not_yet_valid";
var ErrPermit2AmountMismatch = "permit2_amount_mismatch";
var ErrPermit2TokenMismatch = "permit2_token_mismatch";
var ErrPermit2InvalidSignature = "invalid_permit2_signature";
var ErrPermit2AllowanceRequired = "permit2_allowance_required";
var ErrPermit2SimulationFailed = "permit2_simulation_failed";
var ErrPermit2InsufficientBalance = "permit2_insufficient_balance";
var ErrPermit2ProxyNotDeployed = "permit2_proxy_not_deployed";
var ErrPermit2InvalidAmount = "permit2_invalid_amount";
var ErrPermit2InvalidDestination = "permit2_invalid_destination";
var ErrPermit2InvalidOwner = "permit2_invalid_owner";
var ErrPermit2PaymentTooEarly = "permit2_payment_too_early";
var ErrPermit2InvalidNonce = "permit2_invalid_nonce";
var ErrPermit2612AmountMismatch = "permit2_2612_amount_mismatch";
var ErrErc20ApprovalInsufficientEthForGas = "erc20_approval_insufficient_eth_for_gas";
var ErrErc20ApprovalInvalidFormat = "invalid_erc20_approval_extension_format";
var ErrErc20ApprovalFromMismatch = "erc20_approval_from_mismatch";
var ErrErc20ApprovalAssetMismatch = "erc20_approval_asset_mismatch";
var ErrErc20ApprovalSpenderNotPermit2 = "erc20_approval_spender_not_permit2";
var ErrErc20ApprovalTxWrongTarget = "erc20_approval_tx_wrong_target";
var ErrErc20ApprovalTxWrongSelector = "erc20_approval_tx_wrong_selector";
var ErrErc20ApprovalTxWrongSpender = "erc20_approval_tx_wrong_spender";
var ErrErc20ApprovalTxInvalidCalldata = "erc20_approval_tx_invalid_calldata";
var ErrErc20ApprovalTxSignerMismatch = "erc20_approval_tx_signer_mismatch";
var ErrErc20ApprovalTxInvalidSignature = "erc20_approval_tx_invalid_signature";
var ErrErc20ApprovalTxParseFailed = "erc20_approval_tx_parse_failed";
var ErrErc20ApprovalTxFailed = "erc20_approval_tx_failed";
var ErrInvalidEip2612ExtensionFormat = "invalid_eip2612_extension_format";
var ErrEip2612FromMismatch = "eip2612_from_mismatch";
var ErrEip2612AssetMismatch = "eip2612_asset_mismatch";
var ErrEip2612SpenderNotPermit2 = "eip2612_spender_not_permit2";
var ErrEip2612DeadlineExpired = "eip2612_deadline_expired";
var ErrUnsupportedPayloadType = "unsupported_payload_type";
var ErrInvalidTransactionState = "invalid_transaction_state";
// src/exact/facilitator/eip3009-utils.ts
import { encodeFunctionData as encodeFunctionData2, getAddress as getAddress2, parseErc6492Signature, parseSignature } from "viem";
// src/multicall.ts
import { encodeFunctionData, decodeFunctionResult } from "viem";
var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
var multicall3GetEthBalanceAbi = [
{
name: "getEthBalance",
inputs: [{ name: "addr", type: "address" }],
outputs: [{ name: "balance", type: "uint256" }],
stateMutability: "view",
type: "function"
}
];
var multicall3ABI = [
{
inputs: [
{ name: "requireSuccess", type: "bool" },
{
name: "calls",
type: "tuple[]",
components: [
{ name: "target", type: "address" },
{ name: "callData", type: "bytes" }
]
}
],
name: "tryAggregate",
outputs: [
{
name: "returnData",
type: "tuple[]",
components: [
{ name: "success", type: "bool" },
{ name: "returnData", type: "bytes" }
]
}
],
stateMutability: "payable",
type: "function"
}
];
async function multicall(readContract, calls) {
const aggregateCalls = calls.map((call) => {
if ("callData" in call) {
return { target: call.address, callData: call.callData };
}
const callData = encodeFunctionData({
abi: call.abi,
functionName: call.functionName,
args: call.args
});
return { target: call.address, callData };
});
const rawResults = await readContract({
address: MULTICALL3_ADDRESS,
abi: multicall3ABI,
functionName: "tryAggregate",
args: [false, aggregateCalls]
});
return rawResults.map((raw, i) => {
if (!raw.success) {
return {
status: "failure",
error: new Error(`multicall: call reverted (returnData: ${raw.returnData})`)
};
}
const call = calls[i];
if ("callData" in call) {
return { status: "success", result: void 0 };
}
try {
const decoded = decodeFunctionResult({
abi: call.abi,
functionName: call.functionName,
data: raw.returnData
});
return { status: "success", result: decoded };
} catch (err) {
return {
status: "failure",
error: err instanceof Error ? err : new Error(String(err))
};
}
});
}
// src/exact/facilitator/eip3009-utils.ts
async function simulateEip3009Transfer(signer, erc20Address, payload, eip6492Deployment) {
const auth = payload.authorization;
const transferArgs = [
getAddress2(auth.from),
getAddress2(auth.to),
BigInt(auth.value),
BigInt(auth.validAfter),
BigInt(auth.validBefore),
auth.nonce
];
if (eip6492Deployment) {
const { signature: innerSignature } = parseErc6492Signature(payload.signature);
const transferCalldata = encodeFunctionData2({
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [...transferArgs, innerSignature]
});
try {
const results = await multicall(signer.readContract.bind(signer), [
{
address: getAddress2(eip6492Deployment.factoryAddress),
callData: eip6492Deployment.factoryCalldata
},
{
address: erc20Address,
callData: transferCalldata
}
]);
return results[1]?.status === "success";
} catch {
return false;
}
}
const sig = payload.signature;
const sigLength = sig.startsWith("0x") ? sig.length - 2 : sig.length;
const isECDSA = sigLength === 130;
try {
if (isECDSA) {
const parsedSig = parseSignature(sig);
await signer.readContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
...transferArgs,
parsedSig.v ?? parsedSig.yParity,
parsedSig.r,
parsedSig.s
]
});
} else {
await signer.readContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [...transferArgs, sig]
});
}
return true;
} catch {
return false;
}
}
async function diagnoseEip3009SimulationFailure(signer, erc20Address, payload, requirements, amountRequired) {
const payer = payload.authorization.from;
const diagnosticCalls = [
{
address: erc20Address,
abi: eip3009ABI,
functionName: "balanceOf",
args: [payload.authorization.from]
},
{
address: erc20Address,
abi: eip3009ABI,
functionName: "name"
},
{
address: erc20Address,
abi: eip3009ABI,
functionName: "version"
},
{
address: erc20Address,
abi: eip3009ABI,
functionName: "authorizationState",
args: [payload.authorization.from, payload.authorization.nonce]
}
];
try {
const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
const [balanceResult, nameResult, versionResult, authStateResult] = results;
if (authStateResult.status === "failure") {
return { isValid: false, invalidReason: ErrEip3009NotSupported, payer };
}
if (authStateResult.status === "success" && authStateResult.result === true) {
return { isValid: false, invalidReason: ErrEip3009NonceAlreadyUsed, payer };
}
if (nameResult.status === "success" && requirements.extra?.name && nameResult.result !== requirements.extra.name) {
return { isValid: false, invalidReason: ErrEip3009TokenNameMismatch, payer };
}
if (versionResult.status === "success" && requirements.extra?.version && versionResult.result !== requirements.extra.version) {
return { isValid: false, invalidReason: ErrEip3009TokenVersionMismatch, payer };
}
if (balanceResult.status === "success") {
const balance = balanceResult.result;
if (balance < BigInt(amountRequired)) {
return {
isValid: false,
invalidReason: ErrEip3009InsufficientBalance,
payer
};
}
}
} catch {
}
return { isValid: false, invalidReason: ErrEip3009SimulationFailed, payer };
}
async function executeTransferWithAuthorization(signer, erc20Address, payload) {
const { signature } = parseErc6492Signature(payload.signature);
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isECDSA = signatureLength === 130;
const auth = payload.authorization;
const baseArgs = [
getAddress2(auth.from),
getAddress2(auth.to),
BigInt(auth.value),
BigInt(auth.validAfter),
BigInt(auth.validBefore),
auth.nonce
];
if (isECDSA) {
const parsedSig = parseSignature(signature);
return signer.writeContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
...baseArgs,
parsedSig.v || parsedSig.yParity,
parsedSig.r,
parsedSig.s
]
});
}
return signer.writeContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [...baseArgs, signature]
});
}
// src/exact/v1/facilitator/scheme.ts
var ExactEvmSchemeV12 = class {
/**
* Creates a new ExactEvmFacilitatorV1 instance.
*
* @param signer - The EVM signer for facilitator operations
* @param config - Optional configuration for the facilitator
*/
constructor(signer, config) {
this.signer = signer;
this.scheme = "exact";
this.caipFamily = "eip155:*";
this.config = {
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,
simulateInSettle: config?.simulateInSettle ?? false
};
}
/**
* Get mechanism-specific extra data for the supported kinds endpoint.
* For EVM, no extra data is needed.
*
* @param _ - The network identifier (unused for EVM)
* @returns undefined (EVM has no extra data)
*/
getExtra(_) {
return void 0;
}
/**
* Get signer addresses used by this facilitator.
* Returns all addresses this facilitator can use for signing/settling transactions.
*
* @param _ - The network identifier (unused for EVM, addresses are network-agnostic)
* @returns Array of facilitator wallet addresses
*/
getSigners(_) {
return [...this.signer.getAddresses()];
}
/**
* Verifies a payment payload (V1).
*
* @param payload - The payment payload to verify
* @param requirements - The payment requirements
* @returns Promise resolving to verification response
*/
async verify(payload, requirements) {
return this._verify(payload, requirements);
}
/**
* Settles a payment by executing the transfer (V1).
*
* @param payload - The payment payload to settle
* @param requirements - The payment requirements
* @returns Promise resolving to settlement response
*/
async settle(payload, requirements) {
const payloadV1 = payload;
const exactEvmPayload = payload.payload;
const valid = await this._verify(payload, requirements, {
simulate: this.config.simulateInSettle ?? false
});
if (!valid.isValid) {
return {
success: false,
network: payloadV1.network,
transaction: "",
errorReason: valid.invalidReason ?? ErrInvalidScheme,
payer: exactEvmPayload.authorization.from
};
}
try {
const { address: factoryAddress, data: factoryCalldata } = parseErc6492Signature2(
exactEvmPayload.signature
);
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !isAddressEqual(factoryAddress, "0x0000000000000000000000000000000000000000")) {
const payerAddress = exactEvmPayload.authorization.from;
const bytecode = await this.signer.getCode({ address: payerAddress });
if (!bytecode || bytecode === "0x") {
const deployTx = await this.signer.sendTransaction({
to: factoryAddress,
data: factoryCalldata
});
await this.signer.waitForTransactionReceipt({ hash: deployTx });
}
}
const tx = await executeTransferWithAuthorization(
this.signer,
getAddress3(requirements.asset),
exactEvmPayload
);
const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
if (receipt.status !== "success") {
return {
success: false,
errorReason: ErrTransactionFailed,
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
return {
success: true,
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
} catch (error) {
return {
success: false,
errorReason: error instanceof Error ? error.message : ErrTransactionFailed,
transaction: "",
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
}
/**
* Internal verify with optional simulation control.
*
* @param payload - The payment payload to verify
* @param requirements - The payment requirements
* @param options - Verification options (e.g. simulate)
* @returns Promise resolving to verification response
*/
async _verify(payload, requirements, options) {
const requirementsV1 = requirements;
const payloadV1 = payload;
const exactEvmPayload = payload.payload;
const payer = exactEvmPayload.authorization.from;
let eip6492Deployment;
if (payloadV1.scheme !== "exact" || requirements.scheme !== "exact") {
return {
isValid: false,
invalidReason: ErrInvalidScheme,
payer
};
}
let chainId;
try {
chainId = getEvmChainIdV1(payloadV1.network);
} catch {
return {
isValid: false,
invalidReason: ErrNetworkMismatch,
payer
};
}
if (!requirements.extra?.name || !requirements.extra?.version) {
return {
isValid: false,
invalidReason: ErrMissingEip712Domain,
payer
};
}
const { name, version } = requirements.extra;
const erc20Address = getAddress3(requirements.asset);
if (payloadV1.network !== requirements.network) {
return {
isValid: false,
invalidReason: ErrNetworkMismatch,
payer
};
}
const permitTypedData = {
types: authorizationTypes,
primaryType: "TransferWithAuthorization",
domain: {
name,
version,
chainId,
verifyingContract: erc20Address
},
message: {
from: exactEvmPayload.authorization.from,
to: exactEvmPayload.authorization.to,
value: BigInt(exactEvmPayload.authorization.value),
validAfter: BigInt(exactEvmPayload.authorization.validAfter),
validBefore: BigInt(exactEvmPayload.authorization.validBefore),
nonce: exactEvmPayload.authorization.nonce
}
};
let isValid = false;
try {
isValid = await this.signer.verifyTypedData({
address: payer,
...permitTypedData,
signature: exactEvmPayload.signature
});
} catch {
isValid = false;
}
const signature = exactEvmPayload.signature;
const sigLen = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const erc6492Data = parseErc6492Signature2(signature);
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !isAddressEqual(erc6492Data.address, "0x0000000000000000000000000000000000000000");
if (hasDeploymentInfo) {
eip6492Deployment = {
factoryAddress: erc6492Data.address,
factoryCalldata: erc6492Data.data
};
}
if (!isValid) {
const isSmartWallet = sigLen > 130;
if (!isSmartWallet) {
return {
isValid: false,
invalidReason: ErrInvalidSignature,
payer
};
}
const bytecode = await this.signer.getCode({ address: payer });
const isDeployed = bytecode && bytecode !== "0x";
if (!isDeployed && !hasDeploymentInfo) {
return {
isValid: false,
invalidReason: ErrUndeployedSmartWallet,
payer
};
}
}
if (getAddress3(exactEvmPayload.authorization.to) !== getAddress3(requirements.payTo)) {
return {
isValid: false,
invalidReason: ErrRecipientMismatch,
payer
};
}
const now = Math.floor(Date.now() / 1e3);
if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {
return {
isValid: false,
invalidReason: ErrValidBeforeExpired,
payer
};
}
if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {
return {
isValid: false,
invalidReason: ErrValidAfterInFuture,
payer
};
}
if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {
return {
isValid: false,
invalidReason: ErrInvalidAuthorizationValue,
payer
};
}
if (options?.simulate !== false) {
const simulationSucceeded = await simulateEip3009Transfer(
this.signer,
erc20Address,
exactEvmPayload,
eip6492Deployment
);
if (!simulationSucceeded) {
return diagnoseEip3009SimulationFailure(
this.signer,
erc20Address,
exactEvmPayload,
requirements,
requirementsV1.maxAmountRequired
);
}
}
return {
isValid: true,
invalidReason: void 0,
payer
};
}
};
// src/v1/index.ts
var EVM_NETWORK_CHAIN_ID_MAP = {
ethereum: 1,
sepolia: 11155111,
abstract: 2741,
"abstract-testnet": 11124,
"base-sepolia": 84532,
base: 8453,
"avalanche-fuji": 43113,
avalanche: 43114,
iotex: 4689,
sei: 1329,
"sei-testnet": 1328,
polygon: 137,
"polygon-amoy": 80002,
peaq: 3338,
story: 1514,
educhain: 41923,
"skale-base-sepolia": 324705682,
megaeth: 4326,
monad: 143
};
var NETWORKS = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);
function getEvmChainIdV1(network) {
const chainId = EVM_NETWORK_CHAIN_ID_MAP[network];
if (!chainId) {
throw new Error(`Unsupported v1 network: ${network}`);
}
return chainId;
}
export {
authorizationTypes,
permit2WitnessTypes,
eip3009ABI,
eip2612PermitTypes,
eip2612NoncesAbi,
erc20ApproveAbi,
erc20AllowanceAbi,
ERC20_APPROVE_GAS_LIMIT,
DEFAULT_MAX_FEE_PER_GAS,
DEFAULT_MAX_PRIORITY_FEE_PER_GAS,
PERMIT2_ADDRESS,
x402ExactPermit2ProxyAddress,
x402UptoPermit2ProxyAddress,
x402ExactPermit2ProxyABI,
getEvmChainId,
createNonce,
createPermit2Nonce,
ErrInvalidScheme,
ErrNetworkMismatch,
ErrMissingEip712Domain,
ErrRecipientMismatch,
ErrInvalidSignature,
ErrValidBeforeExpired,
ErrValidAfterInFuture,
ErrInvalidAuthorizationValue,
ErrUndeployedSmartWallet,
ErrTransactionFailed,
ErrPermit2InvalidSpender,
ErrPermit2RecipientMismatch,
ErrPermit2DeadlineExpired,
ErrPermit2NotYetValid,
ErrPermit2AmountMismatch,
ErrPermit2TokenMismatch,
ErrPermit2InvalidSignature,
ErrPermit2AllowanceRequired,
ErrPermit2SimulationFailed,
ErrPermit2InsufficientBalance,
ErrPermit2ProxyNotDeployed,
ErrPermit2InvalidAmount,
ErrPermit2InvalidDestination,
ErrPermit2InvalidOwner,
ErrPermit2PaymentTooEarly,
ErrPermit2InvalidNonce,
ErrPermit2612AmountMismatch,
ErrErc20ApprovalInsufficientEthForGas,
ErrErc20ApprovalInvalidFormat,
ErrErc20ApprovalFromMismatch,
ErrErc20ApprovalAssetMismatch,
ErrErc20ApprovalSpenderNotPermit2,
ErrErc20ApprovalTxWrongTarget,
ErrErc20ApprovalTxWrongSelector,
ErrErc20ApprovalTxWrongSpender,
ErrErc20ApprovalTxInvalidCalldata,
ErrErc20ApprovalTxSignerMismatch,
ErrErc20ApprovalTxInvalidSignature,
ErrErc20ApprovalTxParseFailed,
ErrErc20ApprovalTxFailed,
ErrInvalidEip2612ExtensionFormat,
ErrEip2612FromMismatch,
ErrEip2612AssetMismatch,
ErrEip2612SpenderNotPermit2,
ErrEip2612DeadlineExpired,
ErrUnsupportedPayloadType,
ErrInvalidTransactionState,
MULTICALL3_ADDRESS,
multicall3GetEthBalanceAbi,
multicall,
simulateEip3009Transfer,
diagnoseEip3009SimulationFailure,
executeTransferWithAuthorization,
ExactEvmSchemeV12 as ExactEvmSchemeV1,
EVM_NETWORK_CHAIN_ID_MAP,
NETWORKS,
getEvmChainIdV1,
ExactEvmSchemeV1 as ExactEvmSchemeV12
};
//# sourceMappingURL=chunk-IZEI7JTG.mjs.map

Sorry, the diff of this file is too big to display

import {
EIP2612_GAS_SPONSORING_KEY,
ERC20_APPROVAL_GAS_SPONSORING_KEY,
ERC20_APPROVAL_GAS_SPONSORING_VERSION
} from "./chunk-GD4MKCN7.mjs";
import {
DEFAULT_MAX_FEE_PER_GAS,
DEFAULT_MAX_PRIORITY_FEE_PER_GAS,
ERC20_APPROVE_GAS_LIMIT,
ExactEvmSchemeV12 as ExactEvmSchemeV1,
NETWORKS,
PERMIT2_ADDRESS,
authorizationTypes,
createNonce,
createPermit2Nonce,
eip2612NoncesAbi,
eip2612PermitTypes,
erc20AllowanceAbi,
erc20ApproveAbi,
getEvmChainId,
permit2WitnessTypes,
x402ExactPermit2ProxyAddress
} from "./chunk-IZEI7JTG.mjs";
// src/exact/client/scheme.ts
import { getAddress as getAddress5 } from "viem";
// src/exact/client/eip3009.ts
import { getAddress } from "viem";
async function createEIP3009Payload(signer, x402Version, paymentRequirements) {
const nonce = createNonce();
const now = Math.floor(Date.now() / 1e3);
const authorization = {
from: signer.address,
to: getAddress(paymentRequirements.payTo),
value: paymentRequirements.amount,
validAfter: (now - 600).toString(),
validBefore: (now + paymentRequirements.maxTimeoutSeconds).toString(),
nonce
};
const signature = await signEIP3009Authorization(signer, authorization, paymentRequirements);
const payload = {
authorization,
signature
};
return {
x402Version,
payload
};
}
async function signEIP3009Authorization(signer, authorization, requirements) {
const chainId = getEvmChainId(requirements.network);
if (!requirements.extra?.name || !requirements.extra?.version) {
throw new Error(
`EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`
);
}
const { name, version } = requirements.extra;
const domain = {
name,
version,
chainId,
verifyingContract: getAddress(requirements.asset)
};
const message = {
from: getAddress(authorization.from),
to: getAddress(authorization.to),
value: BigInt(authorization.value),
validAfter: BigInt(authorization.validAfter),
validBefore: BigInt(authorization.validBefore),
nonce: authorization.nonce
};
return await signer.signTypedData({
domain,
types: authorizationTypes,
primaryType: "TransferWithAuthorization",
message
});
}
// src/exact/client/permit2.ts
import { encodeFunctionData, getAddress as getAddress2 } from "viem";
var MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
async function createPermit2Payload(signer, x402Version, paymentRequirements) {
const now = Math.floor(Date.now() / 1e3);
const nonce = createPermit2Nonce();
const validAfter = (now - 600).toString();
const deadline = (now + paymentRequirements.maxTimeoutSeconds).toString();
const permit2Authorization = {
from: signer.address,
permitted: {
token: getAddress2(paymentRequirements.asset),
amount: paymentRequirements.amount
},
spender: x402ExactPermit2ProxyAddress,
nonce,
deadline,
witness: {
to: getAddress2(paymentRequirements.payTo),
validAfter
}
};
const signature = await signPermit2Authorization(
signer,
permit2Authorization,
paymentRequirements
);
const payload = {
signature,
permit2Authorization
};
return {
x402Version,
payload
};
}
async function signPermit2Authorization(signer, permit2Authorization, requirements) {
const chainId = getEvmChainId(requirements.network);
const domain = {
name: "Permit2",
chainId,
verifyingContract: PERMIT2_ADDRESS
};
const message = {
permitted: {
token: getAddress2(permit2Authorization.permitted.token),
amount: BigInt(permit2Authorization.permitted.amount)
},
spender: getAddress2(permit2Authorization.spender),
nonce: BigInt(permit2Authorization.nonce),
deadline: BigInt(permit2Authorization.deadline),
witness: {
to: getAddress2(permit2Authorization.witness.to),
validAfter: BigInt(permit2Authorization.witness.validAfter)
}
};
return await signer.signTypedData({
domain,
types: permit2WitnessTypes,
primaryType: "PermitWitnessTransferFrom",
message
});
}
function createPermit2ApprovalTx(tokenAddress) {
const data = encodeFunctionData({
abi: erc20ApproveAbi,
functionName: "approve",
args: [PERMIT2_ADDRESS, MAX_UINT256]
});
return {
to: getAddress2(tokenAddress),
data
};
}
function getPermit2AllowanceReadParams(params) {
return {
address: getAddress2(params.tokenAddress),
abi: erc20AllowanceAbi,
functionName: "allowance",
args: [getAddress2(params.ownerAddress), PERMIT2_ADDRESS]
};
}
// src/exact/client/eip2612.ts
import { getAddress as getAddress3 } from "viem";
async function signEip2612Permit(signer, tokenAddress, tokenName, tokenVersion, chainId, deadline, permittedAmount) {
const owner = signer.address;
const spender = getAddress3(PERMIT2_ADDRESS);
const nonce = await signer.readContract({
address: tokenAddress,
abi: eip2612NoncesAbi,
functionName: "nonces",
args: [owner]
});
const domain = {
name: tokenName,
version: tokenVersion,
chainId,
verifyingContract: tokenAddress
};
const approvalAmount = BigInt(permittedAmount);
const message = {
owner,
spender,
value: approvalAmount,
nonce,
deadline: BigInt(deadline)
};
const signature = await signer.signTypedData({
domain,
types: eip2612PermitTypes,
primaryType: "Permit",
message
});
return {
from: owner,
asset: tokenAddress,
spender,
amount: approvalAmount.toString(),
nonce: nonce.toString(),
deadline,
signature,
version: "1"
};
}
// src/exact/client/erc20approval.ts
import { encodeFunctionData as encodeFunctionData2, getAddress as getAddress4, maxUint256 } from "viem";
async function signErc20ApprovalTransaction(signer, tokenAddress, chainId) {
const from = signer.address;
const spender = getAddress4(PERMIT2_ADDRESS);
const data = encodeFunctionData2({
abi: erc20ApproveAbi,
functionName: "approve",
args: [spender, maxUint256]
});
const nonce = await signer.getTransactionCount({ address: from });
let maxFeePerGas;
let maxPriorityFeePerGas;
try {
const fees = await signer.estimateFeesPerGas?.();
if (!fees) {
throw new Error("no fee estimates available");
}
maxFeePerGas = fees.maxFeePerGas;
maxPriorityFeePerGas = fees.maxPriorityFeePerGas;
} catch {
maxFeePerGas = DEFAULT_MAX_FEE_PER_GAS;
maxPriorityFeePerGas = DEFAULT_MAX_PRIORITY_FEE_PER_GAS;
}
const signedTransaction = await signer.signTransaction({
to: tokenAddress,
data,
nonce,
gas: ERC20_APPROVE_GAS_LIMIT,
maxFeePerGas,
maxPriorityFeePerGas,
chainId
});
return {
from,
asset: tokenAddress,
spender,
amount: maxUint256.toString(),
signedTransaction,
version: ERC20_APPROVAL_GAS_SPONSORING_VERSION
};
}
// src/exact/client/rpc.ts
import { createPublicClient, http } from "viem";
var rpcClientCache = /* @__PURE__ */ new Map();
function isConfigByChainId(options) {
const keys = Object.keys(options);
return keys.length > 0 && keys.every((key) => /^\d+$/.test(key));
}
function getRpcClient(rpcUrl) {
const existing = rpcClientCache.get(rpcUrl);
if (existing) {
return existing;
}
const client = createPublicClient({
transport: http(rpcUrl)
});
rpcClientCache.set(rpcUrl, client);
return client;
}
function resolveRpcUrl(network, options) {
if (!options) {
return void 0;
}
if (isConfigByChainId(options)) {
const chainId = getEvmChainId(network);
const optionsByChainId = options;
return optionsByChainId[chainId]?.rpcUrl;
}
return options.rpcUrl;
}
function resolveExtensionRpcCapabilities(network, signer, options) {
const capabilities = {
signTransaction: signer.signTransaction,
readContract: signer.readContract,
getTransactionCount: signer.getTransactionCount,
estimateFeesPerGas: signer.estimateFeesPerGas
};
const needsRpcBackfill = !capabilities.readContract || !capabilities.getTransactionCount || !capabilities.estimateFeesPerGas;
if (!needsRpcBackfill) {
return capabilities;
}
const rpcUrl = resolveRpcUrl(network, options);
if (!rpcUrl) {
return capabilities;
}
const rpcClient = getRpcClient(rpcUrl);
if (!capabilities.readContract) {
capabilities.readContract = (args) => rpcClient.readContract(args);
}
if (!capabilities.getTransactionCount) {
capabilities.getTransactionCount = async (args) => rpcClient.getTransactionCount({ address: args.address });
}
if (!capabilities.estimateFeesPerGas) {
capabilities.estimateFeesPerGas = async () => rpcClient.estimateFeesPerGas();
}
return capabilities;
}
// src/exact/client/scheme.ts
var ExactEvmScheme = class {
/**
* Creates a new ExactEvmClient instance.
*
* @param signer - The EVM signer for client operations.
* Base flow only requires `address` + `signTypedData`.
* Extension enrichment (EIP-2612 / ERC-20 approval sponsoring) additionally
* requires optional capabilities like `readContract` and tx signing helpers.
* @param options - Optional RPC configuration used to backfill extension capabilities.
*/
constructor(signer, options) {
this.signer = signer;
this.options = options;
this.scheme = "exact";
}
/**
* Creates a payment payload for the Exact scheme.
* Routes to EIP-3009 or Permit2 based on requirements.extra.assetTransferMethod.
*
* For Permit2 flows, if the server advertises `eip2612GasSponsoring` and the
* signer supports `readContract`, automatically signs an EIP-2612 permit
* when Permit2 allowance is insufficient.
*
* @param x402Version - The x402 protocol version
* @param paymentRequirements - The payment requirements
* @param context - Optional context with server-declared extensions
* @returns Promise resolving to a payment payload result (with optional extensions)
*/
async createPaymentPayload(x402Version, paymentRequirements, context) {
const assetTransferMethod = paymentRequirements.extra?.assetTransferMethod ?? "eip3009";
if (assetTransferMethod === "permit2") {
const result = await createPermit2Payload(this.signer, x402Version, paymentRequirements);
const eip2612Extensions = await this.trySignEip2612Permit(
paymentRequirements,
result,
context
);
if (eip2612Extensions) {
return {
...result,
extensions: eip2612Extensions
};
}
const erc20Extensions = await this.trySignErc20Approval(paymentRequirements, result, context);
if (erc20Extensions) {
return {
...result,
extensions: erc20Extensions
};
}
return result;
}
return createEIP3009Payload(this.signer, x402Version, paymentRequirements);
}
/**
* Attempts to sign an EIP-2612 permit for gasless Permit2 approval.
*
* Returns extension data if:
* 1. Server advertises eip2612GasSponsoring
* 2. Signer has readContract capability
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param result - The payment payload result from the scheme
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for EIP-2612 gas sponsoring, or undefined if not applicable
*/
async trySignEip2612Permit(requirements, result, context) {
const capabilities = resolveExtensionRpcCapabilities(
requirements.network,
this.signer,
this.options
);
if (!capabilities.readContract) {
return void 0;
}
if (!context?.extensions?.[EIP2612_GAS_SPONSORING_KEY]) {
return void 0;
}
const tokenName = requirements.extra?.name;
const tokenVersion = requirements.extra?.version;
if (!tokenName || !tokenVersion) {
return void 0;
}
const chainId = getEvmChainId(requirements.network);
const tokenAddress = getAddress5(requirements.asset);
try {
const allowance = await capabilities.readContract({
address: tokenAddress,
abi: erc20AllowanceAbi,
functionName: "allowance",
args: [this.signer.address, PERMIT2_ADDRESS]
});
if (allowance >= BigInt(requirements.amount)) {
return void 0;
}
} catch {
}
const permit2Auth = result.payload?.permit2Authorization;
const deadline = permit2Auth?.deadline ?? Math.floor(Date.now() / 1e3 + requirements.maxTimeoutSeconds).toString();
const info = await signEip2612Permit(
{
address: this.signer.address,
signTypedData: (msg) => this.signer.signTypedData(msg),
readContract: capabilities.readContract
},
tokenAddress,
tokenName,
tokenVersion,
chainId,
deadline,
requirements.amount
);
return {
[EIP2612_GAS_SPONSORING_KEY]: { info }
};
}
/**
* Attempts to sign an ERC-20 approval transaction for gasless Permit2 approval.
*
* This is the fallback path when the token does not support EIP-2612. The client
* signs (but does not broadcast) a raw `approve(Permit2, MaxUint256)` transaction.
* The facilitator broadcasts it atomically before settling.
*
* Returns extension data if:
* 1. Server advertises erc20ApprovalGasSponsoring
* 2. Signer has signTransaction + getTransactionCount capabilities
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param _result - The payment payload result from the scheme (unused)
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for ERC-20 approval gas sponsoring, or undefined if not applicable
*/
async trySignErc20Approval(requirements, _result, context) {
const capabilities = resolveExtensionRpcCapabilities(
requirements.network,
this.signer,
this.options
);
if (!capabilities.readContract) {
return void 0;
}
if (!context?.extensions?.[ERC20_APPROVAL_GAS_SPONSORING_KEY]) {
return void 0;
}
if (!capabilities.signTransaction || !capabilities.getTransactionCount) {
return void 0;
}
const chainId = getEvmChainId(requirements.network);
const tokenAddress = getAddress5(requirements.asset);
try {
const allowance = await capabilities.readContract({
address: tokenAddress,
abi: erc20AllowanceAbi,
functionName: "allowance",
args: [this.signer.address, PERMIT2_ADDRESS]
});
if (allowance >= BigInt(requirements.amount)) {
return void 0;
}
} catch {
}
const info = await signErc20ApprovalTransaction(
{
address: this.signer.address,
signTransaction: capabilities.signTransaction,
getTransactionCount: capabilities.getTransactionCount,
estimateFeesPerGas: capabilities.estimateFeesPerGas
},
tokenAddress,
chainId
);
return {
[ERC20_APPROVAL_GAS_SPONSORING_KEY]: { info }
};
}
};
// src/exact/client/register.ts
function registerExactEvmScheme(client, config) {
const evmScheme = new ExactEvmScheme(config.signer, config.schemeOptions);
if (config.networks && config.networks.length > 0) {
config.networks.forEach((network) => {
client.register(network, evmScheme);
});
} else {
client.register("eip155:*", evmScheme);
}
NETWORKS.forEach((network) => {
client.registerV1(network, new ExactEvmSchemeV1(config.signer));
});
if (config.policies) {
config.policies.forEach((policy) => {
client.registerPolicy(policy);
});
}
return client;
}
export {
createPermit2ApprovalTx,
getPermit2AllowanceReadParams,
ExactEvmScheme,
registerExactEvmScheme
};
//# sourceMappingURL=chunk-WJWNS4G4.mjs.map
{"version":3,"sources":["../../src/exact/client/scheme.ts","../../src/exact/client/eip3009.ts","../../src/exact/client/permit2.ts","../../src/exact/client/eip2612.ts","../../src/exact/client/erc20approval.ts","../../src/exact/client/rpc.ts","../../src/exact/client/register.ts"],"sourcesContent":["import {\n SchemeNetworkClient,\n PaymentRequirements,\n PaymentPayloadResult,\n PaymentPayloadContext,\n} from \"@x402/core/types\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport { AssetTransferMethod } from \"../../types\";\nimport { PERMIT2_ADDRESS, erc20AllowanceAbi } from \"../../constants\";\nimport { getAddress } from \"viem\";\nimport { getEvmChainId } from \"../../utils\";\nimport { EIP2612_GAS_SPONSORING_KEY, ERC20_APPROVAL_GAS_SPONSORING_KEY } from \"../extensions\";\nimport { createEIP3009Payload } from \"./eip3009\";\nimport { createPermit2Payload } from \"./permit2\";\nimport { signEip2612Permit } from \"./eip2612\";\nimport { signErc20ApprovalTransaction } from \"./erc20approval\";\nimport { ExactEvmSchemeOptions, resolveExtensionRpcCapabilities } from \"./rpc\";\n\n/**\n * EVM client implementation for the Exact payment scheme.\n * Supports both EIP-3009 (transferWithAuthorization) and Permit2 flows.\n *\n * Routes to the appropriate authorization method based on\n * `requirements.extra.assetTransferMethod`. Defaults to EIP-3009\n * for backward compatibility with older facilitators.\n *\n * When the server advertises `eip2612GasSponsoring` and the asset transfer\n * method is `permit2`, the scheme automatically signs an EIP-2612 permit\n * if the user lacks Permit2 approval. This requires `readContract` on the signer.\n */\nexport class ExactEvmScheme implements SchemeNetworkClient {\n readonly scheme = \"exact\";\n\n /**\n * Creates a new ExactEvmClient instance.\n *\n * @param signer - The EVM signer for client operations.\n * Base flow only requires `address` + `signTypedData`.\n * Extension enrichment (EIP-2612 / ERC-20 approval sponsoring) additionally\n * requires optional capabilities like `readContract` and tx signing helpers.\n * @param options - Optional RPC configuration used to backfill extension capabilities.\n */\n constructor(\n private readonly signer: ClientEvmSigner,\n private readonly options?: ExactEvmSchemeOptions,\n ) {}\n\n /**\n * Creates a payment payload for the Exact scheme.\n * Routes to EIP-3009 or Permit2 based on requirements.extra.assetTransferMethod.\n *\n * For Permit2 flows, if the server advertises `eip2612GasSponsoring` and the\n * signer supports `readContract`, automatically signs an EIP-2612 permit\n * when Permit2 allowance is insufficient.\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @param context - Optional context with server-declared extensions\n * @returns Promise resolving to a payment payload result (with optional extensions)\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n context?: PaymentPayloadContext,\n ): Promise<PaymentPayloadResult> {\n const assetTransferMethod =\n (paymentRequirements.extra?.assetTransferMethod as AssetTransferMethod) ?? \"eip3009\";\n\n if (assetTransferMethod === \"permit2\") {\n const result = await createPermit2Payload(this.signer, x402Version, paymentRequirements);\n\n const eip2612Extensions = await this.trySignEip2612Permit(\n paymentRequirements,\n result,\n context,\n );\n\n if (eip2612Extensions) {\n return {\n ...result,\n extensions: eip2612Extensions,\n };\n }\n\n const erc20Extensions = await this.trySignErc20Approval(paymentRequirements, result, context);\n if (erc20Extensions) {\n return {\n ...result,\n extensions: erc20Extensions,\n };\n }\n\n return result;\n }\n\n return createEIP3009Payload(this.signer, x402Version, paymentRequirements);\n }\n\n /**\n * Attempts to sign an EIP-2612 permit for gasless Permit2 approval.\n *\n * Returns extension data if:\n * 1. Server advertises eip2612GasSponsoring\n * 2. Signer has readContract capability\n * 3. Current Permit2 allowance is insufficient\n *\n * Returns undefined if the extension should not be used.\n *\n * @param requirements - The payment requirements from the server\n * @param result - The payment payload result from the scheme\n * @param context - Optional context containing server extensions and metadata\n * @returns Extension data for EIP-2612 gas sponsoring, or undefined if not applicable\n */\n private async trySignEip2612Permit(\n requirements: PaymentRequirements,\n result: PaymentPayloadResult,\n context?: PaymentPayloadContext,\n ): Promise<Record<string, unknown> | undefined> {\n const capabilities = resolveExtensionRpcCapabilities(\n requirements.network,\n this.signer,\n this.options,\n );\n\n if (!capabilities.readContract) {\n return undefined;\n }\n\n if (!context?.extensions?.[EIP2612_GAS_SPONSORING_KEY]) {\n return undefined;\n }\n\n const tokenName = requirements.extra?.name as string | undefined;\n const tokenVersion = requirements.extra?.version as string | undefined;\n if (!tokenName || !tokenVersion) {\n return undefined;\n }\n\n const chainId = getEvmChainId(requirements.network);\n const tokenAddress = getAddress(requirements.asset) as `0x${string}`;\n\n try {\n const allowance = (await capabilities.readContract({\n address: tokenAddress,\n abi: erc20AllowanceAbi,\n functionName: \"allowance\",\n args: [this.signer.address, PERMIT2_ADDRESS],\n })) as bigint;\n\n if (allowance >= BigInt(requirements.amount)) {\n return undefined;\n }\n } catch {\n // Allowance check failed, proceed with signing\n }\n\n const permit2Auth = result.payload?.permit2Authorization as Record<string, unknown> | undefined;\n const deadline =\n (permit2Auth?.deadline as string) ??\n Math.floor(Date.now() / 1000 + requirements.maxTimeoutSeconds).toString();\n\n const info = await signEip2612Permit(\n {\n address: this.signer.address,\n signTypedData: msg => this.signer.signTypedData(msg),\n readContract: capabilities.readContract,\n },\n tokenAddress,\n tokenName,\n tokenVersion,\n chainId,\n deadline,\n requirements.amount,\n );\n\n return {\n [EIP2612_GAS_SPONSORING_KEY]: { info },\n };\n }\n\n /**\n * Attempts to sign an ERC-20 approval transaction for gasless Permit2 approval.\n *\n * This is the fallback path when the token does not support EIP-2612. The client\n * signs (but does not broadcast) a raw `approve(Permit2, MaxUint256)` transaction.\n * The facilitator broadcasts it atomically before settling.\n *\n * Returns extension data if:\n * 1. Server advertises erc20ApprovalGasSponsoring\n * 2. Signer has signTransaction + getTransactionCount capabilities\n * 3. Current Permit2 allowance is insufficient\n *\n * Returns undefined if the extension should not be used.\n *\n * @param requirements - The payment requirements from the server\n * @param _result - The payment payload result from the scheme (unused)\n * @param context - Optional context containing server extensions and metadata\n * @returns Extension data for ERC-20 approval gas sponsoring, or undefined if not applicable\n */\n private async trySignErc20Approval(\n requirements: PaymentRequirements,\n _result: PaymentPayloadResult,\n context?: PaymentPayloadContext,\n ): Promise<Record<string, unknown> | undefined> {\n const capabilities = resolveExtensionRpcCapabilities(\n requirements.network,\n this.signer,\n this.options,\n );\n\n if (!capabilities.readContract) {\n return undefined;\n }\n\n if (!context?.extensions?.[ERC20_APPROVAL_GAS_SPONSORING_KEY]) {\n return undefined;\n }\n\n if (!capabilities.signTransaction || !capabilities.getTransactionCount) {\n return undefined;\n }\n\n const chainId = getEvmChainId(requirements.network);\n const tokenAddress = getAddress(requirements.asset) as `0x${string}`;\n\n try {\n const allowance = (await capabilities.readContract({\n address: tokenAddress,\n abi: erc20AllowanceAbi,\n functionName: \"allowance\",\n args: [this.signer.address, PERMIT2_ADDRESS],\n })) as bigint;\n\n if (allowance >= BigInt(requirements.amount)) {\n return undefined;\n }\n } catch {\n // Allowance check failed, proceed with signing\n }\n\n const info = await signErc20ApprovalTransaction(\n {\n address: this.signer.address,\n signTransaction: capabilities.signTransaction,\n getTransactionCount: capabilities.getTransactionCount,\n estimateFeesPerGas: capabilities.estimateFeesPerGas,\n },\n tokenAddress,\n chainId,\n );\n\n return {\n [ERC20_APPROVAL_GAS_SPONSORING_KEY]: { info },\n };\n }\n}\n","import { PaymentRequirements, PaymentPayloadResult } from \"@x402/core/types\";\nimport { getAddress } from \"viem\";\nimport { authorizationTypes } from \"../../constants\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport { ExactEIP3009Payload } from \"../../types\";\nimport { createNonce, getEvmChainId } from \"../../utils\";\n\n/**\n * Creates an EIP-3009 (transferWithAuthorization) payload.\n *\n * @param signer - The EVM signer for client operations\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload result\n */\nexport async function createEIP3009Payload(\n signer: ClientEvmSigner,\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n): Promise<PaymentPayloadResult> {\n const nonce = createNonce();\n const now = Math.floor(Date.now() / 1000);\n\n const authorization: ExactEIP3009Payload[\"authorization\"] = {\n from: signer.address,\n to: getAddress(paymentRequirements.payTo),\n value: paymentRequirements.amount,\n validAfter: (now - 600).toString(),\n validBefore: (now + paymentRequirements.maxTimeoutSeconds).toString(),\n nonce,\n };\n\n const signature = await signEIP3009Authorization(signer, authorization, paymentRequirements);\n\n const payload: ExactEIP3009Payload = {\n authorization,\n signature,\n };\n\n return {\n x402Version,\n payload,\n };\n}\n\n/**\n * Sign the EIP-3009 authorization using EIP-712.\n *\n * @param signer - The EVM signer\n * @param authorization - The authorization to sign\n * @param requirements - The payment requirements\n * @returns Promise resolving to the signature\n */\nasync function signEIP3009Authorization(\n signer: ClientEvmSigner,\n authorization: ExactEIP3009Payload[\"authorization\"],\n requirements: PaymentRequirements,\n): Promise<`0x${string}`> {\n const chainId = getEvmChainId(requirements.network);\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`,\n );\n }\n\n const { name, version } = requirements.extra;\n\n const domain = {\n name,\n version,\n chainId,\n verifyingContract: getAddress(requirements.asset),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return await signer.signTypedData({\n domain,\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\",\n message,\n });\n}\n","import { PaymentRequirements, PaymentPayloadResult } from \"@x402/core/types\";\nimport { encodeFunctionData, getAddress } from \"viem\";\nimport {\n permit2WitnessTypes,\n PERMIT2_ADDRESS,\n x402ExactPermit2ProxyAddress,\n erc20ApproveAbi,\n erc20AllowanceAbi,\n} from \"../../constants\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport { ExactPermit2Payload } from \"../../types\";\nimport { createPermit2Nonce, getEvmChainId } from \"../../utils\";\n\n/** Maximum uint256 value for unlimited approval. */\nconst MAX_UINT256 = BigInt(\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\");\n\n/**\n * Creates a Permit2 payload using the x402Permit2Proxy witness pattern.\n * The spender is set to x402Permit2Proxy, which enforces that funds\n * can only be sent to the witness.to address.\n *\n * @param signer - The EVM signer for client operations\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload result\n */\nexport async function createPermit2Payload(\n signer: ClientEvmSigner,\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n): Promise<PaymentPayloadResult> {\n const now = Math.floor(Date.now() / 1000);\n const nonce = createPermit2Nonce();\n\n // Lower time bound - allow some clock skew\n const validAfter = (now - 600).toString();\n // Upper time bound is enforced by Permit2's deadline field\n const deadline = (now + paymentRequirements.maxTimeoutSeconds).toString();\n\n const permit2Authorization: ExactPermit2Payload[\"permit2Authorization\"] = {\n from: signer.address,\n permitted: {\n token: getAddress(paymentRequirements.asset),\n amount: paymentRequirements.amount,\n },\n spender: x402ExactPermit2ProxyAddress,\n nonce,\n deadline,\n witness: {\n to: getAddress(paymentRequirements.payTo),\n validAfter,\n },\n };\n\n const signature = await signPermit2Authorization(\n signer,\n permit2Authorization,\n paymentRequirements,\n );\n\n const payload: ExactPermit2Payload = {\n signature,\n permit2Authorization,\n };\n\n return {\n x402Version,\n payload,\n };\n}\n\n/**\n * Sign the Permit2 authorization using EIP-712 with witness data.\n * The signature authorizes the x402Permit2Proxy to transfer tokens on behalf of the signer.\n *\n * @param signer - The EVM signer\n * @param permit2Authorization - The Permit2 authorization parameters\n * @param requirements - The payment requirements\n * @returns Promise resolving to the signature\n */\nasync function signPermit2Authorization(\n signer: ClientEvmSigner,\n permit2Authorization: ExactPermit2Payload[\"permit2Authorization\"],\n requirements: PaymentRequirements,\n): Promise<`0x${string}`> {\n const chainId = getEvmChainId(requirements.network);\n\n const domain = {\n name: \"Permit2\",\n chainId,\n verifyingContract: PERMIT2_ADDRESS,\n };\n\n const message = {\n permitted: {\n token: getAddress(permit2Authorization.permitted.token),\n amount: BigInt(permit2Authorization.permitted.amount),\n },\n spender: getAddress(permit2Authorization.spender),\n nonce: BigInt(permit2Authorization.nonce),\n deadline: BigInt(permit2Authorization.deadline),\n witness: {\n to: getAddress(permit2Authorization.witness.to),\n validAfter: BigInt(permit2Authorization.witness.validAfter),\n },\n };\n\n return await signer.signTypedData({\n domain,\n types: permit2WitnessTypes,\n primaryType: \"PermitWitnessTransferFrom\",\n message,\n });\n}\n\n/**\n * Creates transaction data to approve Permit2 to spend tokens.\n * The user sends this transaction (paying gas) before using Permit2 flow.\n *\n * @param tokenAddress - The ERC20 token contract address\n * @returns Transaction data to send for approval\n *\n * @example\n * ```typescript\n * const tx = createPermit2ApprovalTx(\"0x...\");\n * await walletClient.sendTransaction({\n * to: tx.to,\n * data: tx.data,\n * });\n * ```\n */\nexport function createPermit2ApprovalTx(tokenAddress: `0x${string}`): {\n to: `0x${string}`;\n data: `0x${string}`;\n} {\n const data = encodeFunctionData({\n abi: erc20ApproveAbi,\n functionName: \"approve\",\n args: [PERMIT2_ADDRESS, MAX_UINT256],\n });\n\n return {\n to: getAddress(tokenAddress),\n data,\n };\n}\n\n/**\n * Parameters for checking Permit2 allowance.\n * Application provides these to check if approval is needed.\n */\nexport interface Permit2AllowanceParams {\n tokenAddress: `0x${string}`;\n ownerAddress: `0x${string}`;\n}\n\n/**\n * Returns contract read parameters for checking Permit2 allowance.\n * Use with a public client to check if the user has approved Permit2.\n *\n * @param params - The allowance check parameters\n * @returns Contract read parameters for checking allowance\n *\n * @example\n * ```typescript\n * const readParams = getPermit2AllowanceReadParams({\n * tokenAddress: \"0x...\",\n * ownerAddress: \"0x...\",\n * });\n *\n * const allowance = await publicClient.readContract(readParams);\n * const needsApproval = allowance < requiredAmount;\n * ```\n */\nexport function getPermit2AllowanceReadParams(params: Permit2AllowanceParams): {\n address: `0x${string}`;\n abi: typeof erc20AllowanceAbi;\n functionName: \"allowance\";\n args: [`0x${string}`, `0x${string}`];\n} {\n return {\n address: getAddress(params.tokenAddress),\n abi: erc20AllowanceAbi,\n functionName: \"allowance\",\n args: [getAddress(params.ownerAddress), PERMIT2_ADDRESS],\n };\n}\n","import { getAddress } from \"viem\";\nimport { eip2612PermitTypes, eip2612NoncesAbi, PERMIT2_ADDRESS } from \"../../constants\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport type { Eip2612GasSponsoringInfo } from \"../extensions\";\n\nexport type Eip2612PermitSigner = Pick<ClientEvmSigner, \"address\" | \"signTypedData\"> & {\n readContract: NonNullable<ClientEvmSigner[\"readContract\"]>;\n};\n\n/**\n * Signs an EIP-2612 permit authorizing the Permit2 contract to spend tokens.\n *\n * This creates a gasless off-chain signature that the facilitator can submit\n * on-chain via `x402Permit2Proxy.settleWithPermit()`.\n *\n * The `permittedAmount` must match the Permit2 `permitted.amount` exactly, as the\n * proxy contract enforces `permit2612.value == permittedAmount`.\n *\n * @param signer - The client EVM signer (must support readContract for nonce query)\n * @param tokenAddress - The ERC-20 token contract address\n * @param tokenName - The token name (from paymentRequirements.extra.name)\n * @param tokenVersion - The token version (from paymentRequirements.extra.version)\n * @param chainId - The chain ID\n * @param deadline - The deadline for the permit (unix timestamp as string)\n * @param permittedAmount - The Permit2 permitted amount (must match exactly)\n * @returns The EIP-2612 gas sponsoring info object\n */\nexport async function signEip2612Permit(\n signer: Eip2612PermitSigner,\n tokenAddress: `0x${string}`,\n tokenName: string,\n tokenVersion: string,\n chainId: number,\n deadline: string,\n permittedAmount: string,\n): Promise<Eip2612GasSponsoringInfo> {\n const owner = signer.address;\n const spender = getAddress(PERMIT2_ADDRESS);\n\n // Query the current EIP-2612 nonce from the token contract\n const nonce = (await signer.readContract({\n address: tokenAddress,\n abi: eip2612NoncesAbi,\n functionName: \"nonces\",\n args: [owner],\n })) as bigint;\n\n // Construct EIP-712 domain for the token's permit function\n const domain = {\n name: tokenName,\n version: tokenVersion,\n chainId,\n verifyingContract: tokenAddress,\n };\n\n const approvalAmount = BigInt(permittedAmount);\n\n const message = {\n owner,\n spender,\n value: approvalAmount,\n nonce,\n deadline: BigInt(deadline),\n };\n\n // Sign the EIP-2612 permit\n const signature = await signer.signTypedData({\n domain,\n types: eip2612PermitTypes,\n primaryType: \"Permit\",\n message,\n });\n\n return {\n from: owner,\n asset: tokenAddress,\n spender,\n amount: approvalAmount.toString(),\n nonce: nonce.toString(),\n deadline,\n signature,\n version: \"1\",\n };\n}\n","import { encodeFunctionData, getAddress, maxUint256 } from \"viem\";\nimport {\n PERMIT2_ADDRESS,\n erc20ApproveAbi,\n ERC20_APPROVE_GAS_LIMIT,\n DEFAULT_MAX_FEE_PER_GAS,\n DEFAULT_MAX_PRIORITY_FEE_PER_GAS,\n} from \"../../constants\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport {\n ERC20_APPROVAL_GAS_SPONSORING_VERSION,\n type Erc20ApprovalGasSponsoringInfo,\n} from \"../extensions\";\n\nexport type Erc20ApprovalTxSigner = Pick<ClientEvmSigner, \"address\"> & {\n signTransaction: NonNullable<ClientEvmSigner[\"signTransaction\"]>;\n getTransactionCount: NonNullable<ClientEvmSigner[\"getTransactionCount\"]>;\n estimateFeesPerGas?: NonNullable<ClientEvmSigner[\"estimateFeesPerGas\"]>;\n};\n\n/**\n * Signs an EIP-1559 `approve(Permit2, MaxUint256)` transaction for the given token.\n *\n * The signed transaction is NOT broadcast here — the facilitator broadcasts it\n * atomically before settling the Permit2 payment. This enables Permit2 payments\n * for generic ERC-20 tokens that do NOT implement EIP-2612.\n *\n * Always approves MaxUint256 regardless of the payment amount.\n *\n * @param signer - The client EVM signer (must support signTransaction, getTransactionCount)\n * @param tokenAddress - The ERC-20 token contract address\n * @param chainId - The chain ID\n * @returns The ERC-20 approval gas sponsoring info object\n */\nexport async function signErc20ApprovalTransaction(\n signer: Erc20ApprovalTxSigner,\n tokenAddress: `0x${string}`,\n chainId: number,\n): Promise<Erc20ApprovalGasSponsoringInfo> {\n const from = signer.address;\n const spender = getAddress(PERMIT2_ADDRESS);\n\n // Encode approve(PERMIT2_ADDRESS, MaxUint256) calldata\n const data = encodeFunctionData({\n abi: erc20ApproveAbi,\n functionName: \"approve\",\n args: [spender, maxUint256],\n });\n\n // Get current nonce for the sender\n const nonce = await signer.getTransactionCount({ address: from });\n\n // Get current fee estimates, with fallback values\n let maxFeePerGas: bigint;\n let maxPriorityFeePerGas: bigint;\n try {\n const fees = await signer.estimateFeesPerGas?.();\n if (!fees) {\n throw new Error(\"no fee estimates available\");\n }\n maxFeePerGas = fees.maxFeePerGas;\n maxPriorityFeePerGas = fees.maxPriorityFeePerGas;\n } catch {\n maxFeePerGas = DEFAULT_MAX_FEE_PER_GAS;\n maxPriorityFeePerGas = DEFAULT_MAX_PRIORITY_FEE_PER_GAS;\n }\n\n // Sign the EIP-1559 transaction (not broadcast)\n const signedTransaction = await signer.signTransaction({\n to: tokenAddress,\n data,\n nonce,\n gas: ERC20_APPROVE_GAS_LIMIT,\n maxFeePerGas,\n maxPriorityFeePerGas,\n chainId,\n });\n\n return {\n from,\n asset: tokenAddress,\n spender,\n amount: maxUint256.toString(),\n signedTransaction,\n version: ERC20_APPROVAL_GAS_SPONSORING_VERSION,\n };\n}\n","import { createPublicClient, http } from \"viem\";\nimport type { ClientEvmSigner } from \"../../signer\";\nimport { getEvmChainId } from \"../../utils\";\n\nexport type ExactEvmSchemeConfig = {\n rpcUrl?: string;\n};\n\nexport type ExactEvmSchemeConfigByChainId = Record<number, ExactEvmSchemeConfig>;\n\nexport type ExactEvmSchemeOptions = ExactEvmSchemeConfig | ExactEvmSchemeConfigByChainId;\n\ntype ExtensionRpcCapabilities = Pick<\n ClientEvmSigner,\n \"readContract\" | \"signTransaction\" | \"getTransactionCount\" | \"estimateFeesPerGas\"\n>;\n\nconst rpcClientCache = new Map<string, ReturnType<typeof createPublicClient>>();\n\n/**\n * Determines whether scheme options are keyed by numeric chain id.\n *\n * @param options - Exact EVM scheme options provided by the client.\n * @returns True when options are a chainId-to-config mapping.\n */\nfunction isConfigByChainId(\n options: ExactEvmSchemeOptions,\n): options is ExactEvmSchemeConfigByChainId {\n const keys = Object.keys(options);\n return keys.length > 0 && keys.every(key => /^\\d+$/.test(key));\n}\n\n/**\n * Returns a cached viem public client for a specific RPC URL.\n *\n * @param rpcUrl - The RPC endpoint URL used to construct the client.\n * @returns A cached or newly created viem public client instance.\n */\nfunction getRpcClient(rpcUrl: string): ReturnType<typeof createPublicClient> {\n const existing = rpcClientCache.get(rpcUrl);\n if (existing) {\n return existing;\n }\n\n const client = createPublicClient({\n transport: http(rpcUrl),\n });\n rpcClientCache.set(rpcUrl, client);\n return client;\n}\n\n/**\n * Resolves the RPC URL for a given CAIP-2 network from scheme options.\n *\n * @param network - CAIP-2 network identifier.\n * @param options - Optional scheme configuration (single config or chain map).\n * @returns The configured RPC URL for the network, if available.\n */\nexport function resolveRpcUrl(\n network: string,\n options?: ExactEvmSchemeOptions,\n): string | undefined {\n if (!options) {\n return undefined;\n }\n\n if (isConfigByChainId(options)) {\n const chainId = getEvmChainId(network);\n const optionsByChainId = options as ExactEvmSchemeConfigByChainId;\n return optionsByChainId[chainId]?.rpcUrl;\n }\n\n return (options as ExactEvmSchemeConfig).rpcUrl;\n}\n\n/**\n * Resolves extension RPC capabilities from signer methods and optional RPC backfill.\n *\n * @param network - CAIP-2 network identifier for chain resolution.\n * @param signer - Client signer with optional RPC-like methods.\n * @param options - Optional scheme configuration used for RPC backfill.\n * @returns The best available capability set for extension enrichment flows.\n */\nexport function resolveExtensionRpcCapabilities(\n network: string,\n signer: ClientEvmSigner,\n options?: ExactEvmSchemeOptions,\n): ExtensionRpcCapabilities {\n const capabilities: ExtensionRpcCapabilities = {\n signTransaction: signer.signTransaction,\n readContract: signer.readContract,\n getTransactionCount: signer.getTransactionCount,\n estimateFeesPerGas: signer.estimateFeesPerGas,\n };\n\n const needsRpcBackfill =\n !capabilities.readContract ||\n !capabilities.getTransactionCount ||\n !capabilities.estimateFeesPerGas;\n if (!needsRpcBackfill) {\n return capabilities;\n }\n\n const rpcUrl = resolveRpcUrl(network, options);\n if (!rpcUrl) {\n return capabilities;\n }\n const rpcClient = getRpcClient(rpcUrl);\n if (!capabilities.readContract) {\n capabilities.readContract = args => rpcClient.readContract(args as never) as Promise<unknown>;\n }\n if (!capabilities.getTransactionCount) {\n capabilities.getTransactionCount = async args =>\n rpcClient.getTransactionCount({ address: args.address });\n }\n if (!capabilities.estimateFeesPerGas) {\n capabilities.estimateFeesPerGas = async () => rpcClient.estimateFeesPerGas();\n }\n\n return capabilities;\n}\n","import { x402Client, SelectPaymentRequirements, PaymentPolicy } from \"@x402/core/client\";\nimport { Network } from \"@x402/core/types\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport { ExactEvmScheme } from \"./scheme\";\nimport { ExactEvmSchemeOptions } from \"./rpc\";\nimport { ExactEvmSchemeV1 } from \"../v1/client/scheme\";\nimport { NETWORKS } from \"../../v1\";\n\n/**\n * Configuration options for registering EVM schemes to an x402Client\n */\nexport interface EvmClientConfig {\n /**\n * The EVM signer to use for creating payment payloads\n */\n signer: ClientEvmSigner;\n\n /**\n * Optional payment requirements selector function\n * If not provided, uses the default selector (first available option)\n */\n paymentRequirementsSelector?: SelectPaymentRequirements;\n\n /**\n * Optional policies to apply to the client\n */\n policies?: PaymentPolicy[];\n\n /**\n * Optional Exact EVM client scheme options.\n * Supports either a single config ({ rpcUrl }) or per-chain configs\n * keyed by EVM chain ID ({ 8453: { rpcUrl: \"...\" } }).\n */\n schemeOptions?: ExactEvmSchemeOptions;\n\n /**\n * Optional specific networks to register.\n * If not provided, registers wildcard support (eip155:*).\n */\n networks?: Network[];\n}\n\n/**\n * Registers EVM exact payment schemes to an x402Client instance.\n *\n * This function registers:\n * - V2: eip155:* wildcard scheme with ExactEvmScheme (or specific networks if provided)\n * - V1: All supported EVM networks with ExactEvmSchemeV1\n *\n * @param client - The x402Client instance to register schemes to\n * @param config - Configuration for EVM client registration\n * @returns The client instance for chaining\n *\n * @example\n * ```typescript\n * import { registerExactEvmScheme } from \"@x402/evm/exact/client/register\";\n * import { x402Client } from \"@x402/core/client\";\n * import { privateKeyToAccount } from \"viem/accounts\";\n *\n * const account = privateKeyToAccount(\"0x...\");\n * const client = new x402Client();\n * registerExactEvmScheme(client, { signer: account });\n * ```\n */\nexport function registerExactEvmScheme(client: x402Client, config: EvmClientConfig): x402Client {\n const evmScheme = new ExactEvmScheme(config.signer, config.schemeOptions);\n\n // Register V2 scheme\n // EIP-2612 gas sponsoring is handled internally by the scheme when the\n // server advertises support - no separate extension registration needed.\n if (config.networks && config.networks.length > 0) {\n // Register specific networks\n config.networks.forEach(network => {\n client.register(network, evmScheme);\n });\n } else {\n // Register wildcard for all EVM chains\n client.register(\"eip155:*\", evmScheme);\n }\n\n // Register all V1 networks\n NETWORKS.forEach(network => {\n client.registerV1(network as Network, new ExactEvmSchemeV1(config.signer));\n });\n\n // Apply policies if provided\n if (config.policies) {\n config.policies.forEach(policy => {\n client.registerPolicy(policy);\n });\n }\n\n return client;\n}\n"],"mappings":"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","names":["getAddress","getAddress","getAddress","getAddress","getAddress","encodeFunctionData","getAddress","getAddress","encodeFunctionData","getAddress"]}
import { SchemeNetworkClient, PaymentRequirements, PaymentPayloadContext, PaymentPayloadResult } from '@x402/core/types';
import { C as ClientEvmSigner } from './signer-D912R4mq.mjs';
type ExactEvmSchemeConfig = {
rpcUrl?: string;
};
type ExactEvmSchemeConfigByChainId = Record<number, ExactEvmSchemeConfig>;
type ExactEvmSchemeOptions = ExactEvmSchemeConfig | ExactEvmSchemeConfigByChainId;
/**
* EVM client implementation for the Exact payment scheme.
* Supports both EIP-3009 (transferWithAuthorization) and Permit2 flows.
*
* Routes to the appropriate authorization method based on
* `requirements.extra.assetTransferMethod`. Defaults to EIP-3009
* for backward compatibility with older facilitators.
*
* When the server advertises `eip2612GasSponsoring` and the asset transfer
* method is `permit2`, the scheme automatically signs an EIP-2612 permit
* if the user lacks Permit2 approval. This requires `readContract` on the signer.
*/
declare class ExactEvmScheme implements SchemeNetworkClient {
private readonly signer;
private readonly options?;
readonly scheme = "exact";
/**
* Creates a new ExactEvmClient instance.
*
* @param signer - The EVM signer for client operations.
* Base flow only requires `address` + `signTypedData`.
* Extension enrichment (EIP-2612 / ERC-20 approval sponsoring) additionally
* requires optional capabilities like `readContract` and tx signing helpers.
* @param options - Optional RPC configuration used to backfill extension capabilities.
*/
constructor(signer: ClientEvmSigner, options?: ExactEvmSchemeOptions | undefined);
/**
* Creates a payment payload for the Exact scheme.
* Routes to EIP-3009 or Permit2 based on requirements.extra.assetTransferMethod.
*
* For Permit2 flows, if the server advertises `eip2612GasSponsoring` and the
* signer supports `readContract`, automatically signs an EIP-2612 permit
* when Permit2 allowance is insufficient.
*
* @param x402Version - The x402 protocol version
* @param paymentRequirements - The payment requirements
* @param context - Optional context with server-declared extensions
* @returns Promise resolving to a payment payload result (with optional extensions)
*/
createPaymentPayload(x402Version: number, paymentRequirements: PaymentRequirements, context?: PaymentPayloadContext): Promise<PaymentPayloadResult>;
/**
* Attempts to sign an EIP-2612 permit for gasless Permit2 approval.
*
* Returns extension data if:
* 1. Server advertises eip2612GasSponsoring
* 2. Signer has readContract capability
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param result - The payment payload result from the scheme
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for EIP-2612 gas sponsoring, or undefined if not applicable
*/
private trySignEip2612Permit;
/**
* Attempts to sign an ERC-20 approval transaction for gasless Permit2 approval.
*
* This is the fallback path when the token does not support EIP-2612. The client
* signs (but does not broadcast) a raw `approve(Permit2, MaxUint256)` transaction.
* The facilitator broadcasts it atomically before settling.
*
* Returns extension data if:
* 1. Server advertises erc20ApprovalGasSponsoring
* 2. Signer has signTransaction + getTransactionCount capabilities
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param _result - The payment payload result from the scheme (unused)
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for ERC-20 approval gas sponsoring, or undefined if not applicable
*/
private trySignErc20Approval;
}
declare const authorizationTypes: {
readonly TransferWithAuthorization: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}];
};
/**
* Permit2 EIP-712 types for signing PermitWitnessTransferFrom.
* Must match the exact format expected by the Permit2 contract.
* Note: Types must be in ALPHABETICAL order after the primary type (TokenPermissions < Witness).
*/
declare const permit2WitnessTypes: {
readonly PermitWitnessTransferFrom: readonly [{
readonly name: "permitted";
readonly type: "TokenPermissions";
}, {
readonly name: "spender";
readonly type: "address";
}, {
readonly name: "nonce";
readonly type: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
}, {
readonly name: "witness";
readonly type: "Witness";
}];
readonly TokenPermissions: readonly [{
readonly name: "token";
readonly type: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
}];
readonly Witness: readonly [{
readonly name: "to";
readonly type: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}];
};
declare const eip3009ABI: readonly [{
readonly inputs: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}, {
readonly name: "v";
readonly type: "uint8";
}, {
readonly name: "r";
readonly type: "bytes32";
}, {
readonly name: "s";
readonly type: "bytes32";
}];
readonly name: "transferWithAuthorization";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}, {
readonly name: "signature";
readonly type: "bytes";
}];
readonly name: "transferWithAuthorization";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly name: "account";
readonly type: "address";
}];
readonly name: "balanceOf";
readonly outputs: readonly [{
readonly name: "";
readonly type: "uint256";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [];
readonly name: "version";
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [];
readonly name: "name";
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly name: "authorizer";
readonly type: "address";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}];
readonly name: "authorizationState";
readonly outputs: readonly [{
readonly name: "";
readonly type: "bool";
}];
readonly stateMutability: "view";
readonly type: "function";
}];
/** ERC-20 allowance(address,address) ABI for checking spender approval. */
declare const erc20AllowanceAbi: readonly [{
readonly type: "function";
readonly name: "allowance";
readonly inputs: readonly [{
readonly name: "owner";
readonly type: "address";
}, {
readonly name: "spender";
readonly type: "address";
}];
readonly outputs: readonly [{
readonly type: "uint256";
}];
readonly stateMutability: "view";
}];
/**
* Canonical Permit2 contract address.
* Same address on all EVM chains via CREATE2 deployment.
*
* @see https://github.com/Uniswap/permit2
*/
declare const PERMIT2_ADDRESS: "0x000000000022D473030F116dDEE9F6B43aC78BA3";
/**
* x402ExactPermit2Proxy contract address.
* Vanity address: 0x4020...0001 for easy recognition.
* This address is deterministic based on:
* - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)
* - Vanity-mined salt for prefix 0x4020 and suffix 0001
* - Contract bytecode + constructor args (PERMIT2_ADDRESS)
*/
declare const x402ExactPermit2ProxyAddress: "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";
/**
* x402UptoPermit2Proxy contract address.
* Vanity address: 0x4020...0002 for easy recognition.
* This address is deterministic based on:
* - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)
* - Vanity-mined salt for prefix 0x4020 and suffix 0002
* - Contract bytecode + constructor args (PERMIT2_ADDRESS)
*/
declare const x402UptoPermit2ProxyAddress: "0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002";
/**
* x402ExactPermit2Proxy ABI - settle function for exact payment scheme.
*/
declare const x402ExactPermit2ProxyABI: readonly [{
readonly type: "function";
readonly name: "PERMIT2";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "address";
readonly internalType: "contract ISignatureTransfer";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "WITNESS_TYPEHASH";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "bytes32";
readonly internalType: "bytes32";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "WITNESS_TYPE_STRING";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
readonly internalType: "string";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "settle";
readonly inputs: readonly [{
readonly name: "permit";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.PermitTransferFrom";
readonly components: readonly [{
readonly name: "permitted";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.TokenPermissions";
readonly components: readonly [{
readonly name: "token";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "nonce";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "owner";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "witness";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.Witness";
readonly components: readonly [{
readonly name: "to";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "signature";
readonly type: "bytes";
readonly internalType: "bytes";
}];
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
}, {
readonly type: "function";
readonly name: "settleWithPermit";
readonly inputs: readonly [{
readonly name: "permit2612";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.EIP2612Permit";
readonly components: readonly [{
readonly name: "value";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "r";
readonly type: "bytes32";
readonly internalType: "bytes32";
}, {
readonly name: "s";
readonly type: "bytes32";
readonly internalType: "bytes32";
}, {
readonly name: "v";
readonly type: "uint8";
readonly internalType: "uint8";
}];
}, {
readonly name: "permit";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.PermitTransferFrom";
readonly components: readonly [{
readonly name: "permitted";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.TokenPermissions";
readonly components: readonly [{
readonly name: "token";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "nonce";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "owner";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "witness";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.Witness";
readonly components: readonly [{
readonly name: "to";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "signature";
readonly type: "bytes";
readonly internalType: "bytes";
}];
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
}, {
readonly type: "event";
readonly name: "Settled";
readonly inputs: readonly [];
readonly anonymous: false;
}, {
readonly type: "event";
readonly name: "SettledWithPermit";
readonly inputs: readonly [];
readonly anonymous: false;
}, {
readonly type: "error";
readonly name: "InvalidAmount";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidDestination";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidOwner";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidPermit2Address";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "PaymentTooEarly";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "Permit2612AmountMismatch";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "ReentrancyGuardReentrantCall";
readonly inputs: readonly [];
}];
/**
* Creates transaction data to approve Permit2 to spend tokens.
* The user sends this transaction (paying gas) before using Permit2 flow.
*
* @param tokenAddress - The ERC20 token contract address
* @returns Transaction data to send for approval
*
* @example
* ```typescript
* const tx = createPermit2ApprovalTx("0x...");
* await walletClient.sendTransaction({
* to: tx.to,
* data: tx.data,
* });
* ```
*/
declare function createPermit2ApprovalTx(tokenAddress: `0x${string}`): {
to: `0x${string}`;
data: `0x${string}`;
};
/**
* Parameters for checking Permit2 allowance.
* Application provides these to check if approval is needed.
*/
interface Permit2AllowanceParams {
tokenAddress: `0x${string}`;
ownerAddress: `0x${string}`;
}
/**
* Returns contract read parameters for checking Permit2 allowance.
* Use with a public client to check if the user has approved Permit2.
*
* @param params - The allowance check parameters
* @returns Contract read parameters for checking allowance
*
* @example
* ```typescript
* const readParams = getPermit2AllowanceReadParams({
* tokenAddress: "0x...",
* ownerAddress: "0x...",
* });
*
* const allowance = await publicClient.readContract(readParams);
* const needsApproval = allowance < requiredAmount;
* ```
*/
declare function getPermit2AllowanceReadParams(params: Permit2AllowanceParams): {
address: `0x${string}`;
abi: typeof erc20AllowanceAbi;
functionName: "allowance";
args: [`0x${string}`, `0x${string}`];
};
export { ExactEvmScheme as E, type Permit2AllowanceParams as P, PERMIT2_ADDRESS as a, x402UptoPermit2ProxyAddress as b, createPermit2ApprovalTx as c, authorizationTypes as d, erc20AllowanceAbi as e, eip3009ABI as f, getPermit2AllowanceReadParams as g, x402ExactPermit2ProxyABI as h, type ExactEvmSchemeOptions as i, type ExactEvmSchemeConfig as j, type ExactEvmSchemeConfigByChainId as k, permit2WitnessTypes as p, x402ExactPermit2ProxyAddress as x };
/**
* ClientEvmSigner - Used by x402 clients to sign payment authorizations.
*
* Typically a viem WalletClient extended with publicActions:
* ```typescript
* const client = createWalletClient({
* account: privateKeyToAccount('0x...'),
* chain: baseSepolia,
* transport: http(),
* }).extend(publicActions);
* ```
*
* Or composed via `toClientEvmSigner(account, publicClient)`.
*/
type ClientEvmSigner = {
readonly address: `0x${string}`;
signTypedData(message: {
domain: Record<string, unknown>;
types: Record<string, unknown>;
primaryType: string;
message: Record<string, unknown>;
}): Promise<`0x${string}`>;
/**
* Optional on-chain reads.
* Required only for extension enrichment (EIP-2612 / ERC-20 approval).
*/
readContract?(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
/**
* Optional: Signs a raw EIP-1559 transaction without broadcasting.
* Required for ERC-20 approval gas sponsoring when the token lacks EIP-2612.
*/
signTransaction?(args: {
to: `0x${string}`;
data: `0x${string}`;
nonce: number;
gas: bigint;
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
chainId: number;
}): Promise<`0x${string}`>;
/**
* Optional: Gets the current transaction count (nonce) for an address.
* Required for ERC-20 approval gas sponsoring.
*/
getTransactionCount?(args: {
address: `0x${string}`;
}): Promise<number>;
/**
* Optional: Estimates current gas fees per gas.
* Required for ERC-20 approval gas sponsoring.
*/
estimateFeesPerGas?(): Promise<{
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
}>;
};
/**
* FacilitatorEvmSigner - Used by x402 facilitators to verify and settle payments
* This is typically a viem PublicClient + WalletClient combination that can
* read contract state, verify signatures, write transactions, and wait for receipts
*
* Supports multiple addresses for load balancing, key rotation, and high availability
*/
type FacilitatorEvmSigner = {
/**
* Get all addresses this facilitator can use for signing
* Enables dynamic address selection for load balancing and key rotation
*/
getAddresses(): readonly `0x${string}`[];
readContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
verifyTypedData(args: {
address: `0x${string}`;
domain: Record<string, unknown>;
types: Record<string, unknown>;
primaryType: string;
message: Record<string, unknown>;
signature: `0x${string}`;
}): Promise<boolean>;
writeContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args: readonly unknown[];
/** Optional gas limit. When provided, skips eth_estimateGas simulation. */
gas?: bigint;
}): Promise<`0x${string}`>;
sendTransaction(args: {
to: `0x${string}`;
data: `0x${string}`;
}): Promise<`0x${string}`>;
waitForTransactionReceipt(args: {
hash: `0x${string}`;
}): Promise<{
status: string;
}>;
getCode(args: {
address: `0x${string}`;
}): Promise<`0x${string}` | undefined>;
};
/**
* Composes a ClientEvmSigner from a local account and a public client.
*
* Use this when your signer (e.g., `privateKeyToAccount`) doesn't have
* `readContract`. The `publicClient` provides the on-chain read capability.
*
* Alternatively, use a WalletClient extended with publicActions directly:
* ```typescript
* const signer = createWalletClient({
* account: privateKeyToAccount('0x...'),
* chain: baseSepolia,
* transport: http(),
* }).extend(publicActions);
* ```
*
* @param signer - A signer with `address` and `signTypedData` (and optionally `readContract`)
* @param publicClient - A client with optional read/nonce/fee helpers
* @param publicClient.readContract - The readContract method from the public client
* @param publicClient.getTransactionCount - Optional getTransactionCount for ERC-20 approval
* @param publicClient.estimateFeesPerGas - Optional estimateFeesPerGas for ERC-20 approval
* @returns A ClientEvmSigner with any available optional capabilities
*
* @example
* ```typescript
* const account = privateKeyToAccount("0x...");
* const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
* const signer = toClientEvmSigner(account, publicClient);
* ```
*/
declare function toClientEvmSigner(signer: Omit<ClientEvmSigner, "readContract"> & {
readContract?: ClientEvmSigner["readContract"];
}, publicClient?: {
readContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
getTransactionCount?(args: {
address: `0x${string}`;
}): Promise<number>;
estimateFeesPerGas?(): Promise<{
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
}>;
}): ClientEvmSigner;
/**
* Converts a viem client with single address to a FacilitatorEvmSigner
* Wraps the single address in a getAddresses() function for compatibility
*
* @param client - The client to convert (must have 'address' property)
* @returns FacilitatorEvmSigner with getAddresses() support
*/
declare function toFacilitatorEvmSigner(client: Omit<FacilitatorEvmSigner, "getAddresses"> & {
address: `0x${string}`;
}): FacilitatorEvmSigner;
export { type ClientEvmSigner as C, type FacilitatorEvmSigner as F, toFacilitatorEvmSigner as a, toClientEvmSigner as t };
+12
-5

@@ -1,5 +0,6 @@

export { E as ExactEvmScheme, P as Permit2AllowanceParams, c as createPermit2ApprovalTx, e as erc20AllowanceAbi, g as getPermit2AllowanceReadParams } from '../../permit2-DHAq6FTe.js';
import { i as ExactEvmSchemeOptions } from '../../permit2-U9Zolx3O.js';
export { E as ExactEvmScheme, j as ExactEvmSchemeConfig, k as ExactEvmSchemeConfigByChainId, P as Permit2AllowanceParams, c as createPermit2ApprovalTx, e as erc20AllowanceAbi, g as getPermit2AllowanceReadParams } from '../../permit2-U9Zolx3O.js';
import { x402Client, SelectPaymentRequirements, PaymentPolicy } from '@x402/core/client';
import { Network } from '@x402/core/types';
import { C as ClientEvmSigner } from '../../signer-DC81R8wQ.js';
import { C as ClientEvmSigner } from '../../signer-D912R4mq.js';

@@ -24,5 +25,11 @@ /**

/**
* Optional specific networks to register
* If not provided, registers wildcard support (eip155:*)
* Optional Exact EVM client scheme options.
* Supports either a single config ({ rpcUrl }) or per-chain configs
* keyed by EVM chain ID ({ 8453: { rpcUrl: "..." } }).
*/
schemeOptions?: ExactEvmSchemeOptions;
/**
* Optional specific networks to register.
* If not provided, registers wildcard support (eip155:*).
*/
networks?: Network[];

@@ -54,2 +61,2 @@ }

export { type EvmClientConfig, registerExactEvmScheme };
export { type EvmClientConfig, ExactEvmSchemeOptions, registerExactEvmScheme };

@@ -31,5 +31,2 @@ "use strict";

// src/exact/client/scheme.ts
var import_extensions2 = require("@x402/extensions");
// src/constants.ts

@@ -112,3 +109,3 @@ var authorizationTypes = {

// src/exact/client/scheme.ts
var import_viem6 = require("viem");
var import_viem7 = require("viem");

@@ -143,2 +140,7 @@ // src/utils.ts

// src/exact/extensions.ts
var EIP2612_GAS_SPONSORING_KEY = "eip2612GasSponsoring";
var ERC20_APPROVAL_GAS_SPONSORING_KEY = "erc20ApprovalGasSponsoring";
var ERC20_APPROVAL_GAS_SPONSORING_VERSION = "1";
// src/exact/client/eip3009.ts

@@ -325,3 +327,2 @@ var import_viem2 = require("viem");

var import_viem5 = require("viem");
var import_extensions = require("@x402/extensions");
async function signErc20ApprovalTransaction(signer, tokenAddress, chainId) {

@@ -339,3 +340,6 @@ const from = signer.address;

try {
const fees = await signer.estimateFeesPerGas();
const fees = await signer.estimateFeesPerGas?.();
if (!fees) {
throw new Error("no fee estimates available");
}
maxFeePerGas = fees.maxFeePerGas;

@@ -362,6 +366,63 @@ maxPriorityFeePerGas = fees.maxPriorityFeePerGas;

signedTransaction,
version: import_extensions.ERC20_APPROVAL_GAS_SPONSORING_VERSION
version: ERC20_APPROVAL_GAS_SPONSORING_VERSION
};
}
// src/exact/client/rpc.ts
var import_viem6 = require("viem");
var rpcClientCache = /* @__PURE__ */ new Map();
function isConfigByChainId(options) {
const keys = Object.keys(options);
return keys.length > 0 && keys.every((key) => /^\d+$/.test(key));
}
function getRpcClient(rpcUrl) {
const existing = rpcClientCache.get(rpcUrl);
if (existing) {
return existing;
}
const client = (0, import_viem6.createPublicClient)({
transport: (0, import_viem6.http)(rpcUrl)
});
rpcClientCache.set(rpcUrl, client);
return client;
}
function resolveRpcUrl(network, options) {
if (!options) {
return void 0;
}
if (isConfigByChainId(options)) {
const chainId = getEvmChainId(network);
const optionsByChainId = options;
return optionsByChainId[chainId]?.rpcUrl;
}
return options.rpcUrl;
}
function resolveExtensionRpcCapabilities(network, signer, options) {
const capabilities = {
signTransaction: signer.signTransaction,
readContract: signer.readContract,
getTransactionCount: signer.getTransactionCount,
estimateFeesPerGas: signer.estimateFeesPerGas
};
const needsRpcBackfill = !capabilities.readContract || !capabilities.getTransactionCount || !capabilities.estimateFeesPerGas;
if (!needsRpcBackfill) {
return capabilities;
}
const rpcUrl = resolveRpcUrl(network, options);
if (!rpcUrl) {
return capabilities;
}
const rpcClient = getRpcClient(rpcUrl);
if (!capabilities.readContract) {
capabilities.readContract = (args) => rpcClient.readContract(args);
}
if (!capabilities.getTransactionCount) {
capabilities.getTransactionCount = async (args) => rpcClient.getTransactionCount({ address: args.address });
}
if (!capabilities.estimateFeesPerGas) {
capabilities.estimateFeesPerGas = async () => rpcClient.estimateFeesPerGas();
}
return capabilities;
}
// src/exact/client/scheme.ts

@@ -373,7 +434,10 @@ var ExactEvmScheme = class {

* @param signer - The EVM signer for client operations.
* Must support `readContract` for EIP-2612 gas sponsoring.
* Use `createWalletClient(...).extend(publicActions)` or `toClientEvmSigner(account, publicClient)`.
* Base flow only requires `address` + `signTypedData`.
* Extension enrichment (EIP-2612 / ERC-20 approval sponsoring) additionally
* requires optional capabilities like `readContract` and tx signing helpers.
* @param options - Optional RPC configuration used to backfill extension capabilities.
*/
constructor(signer) {
constructor(signer, options) {
this.signer = signer;
this.options = options;
this.scheme = "exact";

@@ -436,5 +500,13 @@ }

async trySignEip2612Permit(requirements, result, context) {
if (!context?.extensions?.[import_extensions2.EIP2612_GAS_SPONSORING.key]) {
const capabilities = resolveExtensionRpcCapabilities(
requirements.network,
this.signer,
this.options
);
if (!capabilities.readContract) {
return void 0;
}
if (!context?.extensions?.[EIP2612_GAS_SPONSORING_KEY]) {
return void 0;
}
const tokenName = requirements.extra?.name;

@@ -446,5 +518,5 @@ const tokenVersion = requirements.extra?.version;

const chainId = getEvmChainId(requirements.network);
const tokenAddress = (0, import_viem6.getAddress)(requirements.asset);
const tokenAddress = (0, import_viem7.getAddress)(requirements.asset);
try {
const allowance = await this.signer.readContract({
const allowance = await capabilities.readContract({
address: tokenAddress,

@@ -463,3 +535,7 @@ abi: erc20AllowanceAbi,

const info = await signEip2612Permit(
this.signer,
{
address: this.signer.address,
signTypedData: (msg) => this.signer.signTypedData(msg),
readContract: capabilities.readContract
},
tokenAddress,

@@ -473,3 +549,3 @@ tokenName,

return {
[import_extensions2.EIP2612_GAS_SPONSORING.key]: { info }
[EIP2612_GAS_SPONSORING_KEY]: { info }
};

@@ -497,12 +573,20 @@ }

async trySignErc20Approval(requirements, _result, context) {
if (!context?.extensions?.[import_extensions2.ERC20_APPROVAL_GAS_SPONSORING.key]) {
const capabilities = resolveExtensionRpcCapabilities(
requirements.network,
this.signer,
this.options
);
if (!capabilities.readContract) {
return void 0;
}
if (!this.signer.signTransaction || !this.signer.getTransactionCount) {
if (!context?.extensions?.[ERC20_APPROVAL_GAS_SPONSORING_KEY]) {
return void 0;
}
if (!capabilities.signTransaction || !capabilities.getTransactionCount) {
return void 0;
}
const chainId = getEvmChainId(requirements.network);
const tokenAddress = (0, import_viem6.getAddress)(requirements.asset);
const tokenAddress = (0, import_viem7.getAddress)(requirements.asset);
try {
const allowance = await this.signer.readContract({
const allowance = await capabilities.readContract({
address: tokenAddress,

@@ -518,5 +602,14 @@ abi: erc20AllowanceAbi,

}
const info = await signErc20ApprovalTransaction(this.signer, tokenAddress, chainId);
const info = await signErc20ApprovalTransaction(
{
address: this.signer.address,
signTransaction: capabilities.signTransaction,
getTransactionCount: capabilities.getTransactionCount,
estimateFeesPerGas: capabilities.estimateFeesPerGas
},
tokenAddress,
chainId
);
return {
[import_extensions2.ERC20_APPROVAL_GAS_SPONSORING.key]: { info }
[ERC20_APPROVAL_GAS_SPONSORING_KEY]: { info }
};

@@ -527,7 +620,13 @@ }

// src/exact/v1/client/scheme.ts
var import_viem8 = require("viem");
var import_viem11 = require("viem");
// src/exact/v1/facilitator/scheme.ts
var import_viem7 = require("viem");
var import_viem10 = require("viem");
// src/exact/facilitator/eip3009-utils.ts
var import_viem9 = require("viem");
// src/multicall.ts
var import_viem8 = require("viem");
// src/v1/index.ts

@@ -588,3 +687,3 @@ var EVM_NETWORK_CHAIN_ID_MAP = {

from: this.signer.address,
to: (0, import_viem8.getAddress)(selectedV1.payTo),
to: (0, import_viem11.getAddress)(selectedV1.payTo),
value: selectedV1.maxAmountRequired,

@@ -627,7 +726,7 @@ validAfter: (now - 600).toString(),

chainId,
verifyingContract: (0, import_viem8.getAddress)(requirements.asset)
verifyingContract: (0, import_viem11.getAddress)(requirements.asset)
};
const message = {
from: (0, import_viem8.getAddress)(authorization.from),
to: (0, import_viem8.getAddress)(authorization.to),
from: (0, import_viem11.getAddress)(authorization.from),
to: (0, import_viem11.getAddress)(authorization.to),
value: BigInt(authorization.value),

@@ -649,3 +748,3 @@ validAfter: BigInt(authorization.validAfter),

function registerExactEvmScheme(client, config) {
const evmScheme = new ExactEvmScheme(config.signer);
const evmScheme = new ExactEvmScheme(config.signer, config.schemeOptions);
if (config.networks && config.networks.length > 0) {

@@ -652,0 +751,0 @@ config.networks.forEach((network) => {

import { SchemeNetworkFacilitator, PaymentPayload, PaymentRequirements, FacilitatorContext, VerifyResponse, SettleResponse, Network } from '@x402/core/types';
import { F as FacilitatorEvmSigner } from '../../signer-DC81R8wQ.js';
import { F as FacilitatorEvmSigner } from '../../signer-D912R4mq.js';
import { x402Facilitator } from '@x402/core/facilitator';

@@ -13,2 +13,8 @@

deployERC4337WithEIP6492?: boolean;
/**
* If enabled, run on-chain simulation during settle's re-verify.
*
* @default false
*/
simulateInSettle?: boolean;
}

@@ -87,2 +93,8 @@ /**

deployERC4337WithEIP6492?: boolean;
/**
* If enabled, reruns on-chain simulation during settle's re-verify.
*
* @default false
*/
simulateInSettle?: boolean;
}

@@ -89,0 +101,0 @@ /**

@@ -34,3 +34,3 @@ "use strict";

// src/exact/facilitator/eip3009.ts
var import_viem2 = require("viem");
var import_viem4 = require("viem");

@@ -111,2 +111,19 @@ // src/constants.ts

type: "function"
},
{
inputs: [],
name: "name",
outputs: [{ name: "", type: "string" }],
stateMutability: "view",
type: "function"
},
{
inputs: [
{ name: "authorizer", type: "address" },
{ name: "nonce", type: "bytes32" }
],
name: "authorizationState",
outputs: [{ name: "", type: "bool" }],
stateMutability: "view",
type: "function"
}

@@ -138,2 +155,4 @@ ];

];
var ERC20_APPROVE_GAS_LIMIT = 70000n;
var DEFAULT_MAX_FEE_PER_GAS = 1000000000n;
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";

@@ -272,9 +291,307 @@ var x402ExactPermit2ProxyAddress = "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";

// src/exact/facilitator/errors.ts
var ErrInvalidScheme = "invalid_exact_evm_scheme";
var ErrNetworkMismatch = "invalid_exact_evm_network_mismatch";
var ErrMissingEip712Domain = "invalid_exact_evm_missing_eip712_domain";
var ErrRecipientMismatch = "invalid_exact_evm_recipient_mismatch";
var ErrInvalidSignature = "invalid_exact_evm_signature";
var ErrValidBeforeExpired = "invalid_exact_evm_payload_authorization_valid_before";
var ErrValidAfterInFuture = "invalid_exact_evm_payload_authorization_valid_after";
var ErrInvalidAuthorizationValue = "invalid_exact_evm_authorization_value";
var ErrUndeployedSmartWallet = "invalid_exact_evm_payload_undeployed_smart_wallet";
var ErrTransactionFailed = "invalid_exact_evm_transaction_failed";
var ErrEip3009TokenNameMismatch = "invalid_exact_evm_token_name_mismatch";
var ErrEip3009TokenVersionMismatch = "invalid_exact_evm_token_version_mismatch";
var ErrEip3009NotSupported = "invalid_exact_evm_eip3009_not_supported";
var ErrEip3009NonceAlreadyUsed = "invalid_exact_evm_nonce_already_used";
var ErrEip3009InsufficientBalance = "invalid_exact_evm_insufficient_balance";
var ErrEip3009SimulationFailed = "invalid_exact_evm_transaction_simulation_failed";
var ErrPermit2InvalidSpender = "invalid_permit2_spender";
var ErrPermit2RecipientMismatch = "invalid_permit2_recipient_mismatch";
var ErrPermit2DeadlineExpired = "permit2_deadline_expired";
var ErrPermit2NotYetValid = "permit2_not_yet_valid";
var ErrPermit2AmountMismatch = "permit2_amount_mismatch";
var ErrPermit2TokenMismatch = "permit2_token_mismatch";
var ErrPermit2InvalidSignature = "invalid_permit2_signature";
var ErrPermit2AllowanceRequired = "permit2_allowance_required";
var ErrPermit2SimulationFailed = "permit2_simulation_failed";
var ErrPermit2InsufficientBalance = "permit2_insufficient_balance";
var ErrPermit2ProxyNotDeployed = "permit2_proxy_not_deployed";
var ErrPermit2InvalidAmount = "permit2_invalid_amount";
var ErrPermit2InvalidDestination = "permit2_invalid_destination";
var ErrPermit2InvalidOwner = "permit2_invalid_owner";
var ErrPermit2PaymentTooEarly = "permit2_payment_too_early";
var ErrPermit2InvalidNonce = "permit2_invalid_nonce";
var ErrPermit2612AmountMismatch = "permit2_2612_amount_mismatch";
var ErrErc20ApprovalInsufficientEthForGas = "erc20_approval_insufficient_eth_for_gas";
var ErrErc20ApprovalInvalidFormat = "invalid_erc20_approval_extension_format";
var ErrErc20ApprovalFromMismatch = "erc20_approval_from_mismatch";
var ErrErc20ApprovalAssetMismatch = "erc20_approval_asset_mismatch";
var ErrErc20ApprovalSpenderNotPermit2 = "erc20_approval_spender_not_permit2";
var ErrErc20ApprovalTxWrongTarget = "erc20_approval_tx_wrong_target";
var ErrErc20ApprovalTxWrongSelector = "erc20_approval_tx_wrong_selector";
var ErrErc20ApprovalTxWrongSpender = "erc20_approval_tx_wrong_spender";
var ErrErc20ApprovalTxInvalidCalldata = "erc20_approval_tx_invalid_calldata";
var ErrErc20ApprovalTxSignerMismatch = "erc20_approval_tx_signer_mismatch";
var ErrErc20ApprovalTxInvalidSignature = "erc20_approval_tx_invalid_signature";
var ErrErc20ApprovalTxParseFailed = "erc20_approval_tx_parse_failed";
var ErrErc20ApprovalTxFailed = "erc20_approval_tx_failed";
var ErrInvalidEip2612ExtensionFormat = "invalid_eip2612_extension_format";
var ErrEip2612FromMismatch = "eip2612_from_mismatch";
var ErrEip2612AssetMismatch = "eip2612_asset_mismatch";
var ErrEip2612SpenderNotPermit2 = "eip2612_spender_not_permit2";
var ErrEip2612DeadlineExpired = "eip2612_deadline_expired";
var ErrUnsupportedPayloadType = "unsupported_payload_type";
var ErrInvalidTransactionState = "invalid_transaction_state";
// src/exact/facilitator/eip3009-utils.ts
var import_viem3 = require("viem");
// src/multicall.ts
var import_viem2 = require("viem");
var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
var multicall3GetEthBalanceAbi = [
{
name: "getEthBalance",
inputs: [{ name: "addr", type: "address" }],
outputs: [{ name: "balance", type: "uint256" }],
stateMutability: "view",
type: "function"
}
];
var multicall3ABI = [
{
inputs: [
{ name: "requireSuccess", type: "bool" },
{
name: "calls",
type: "tuple[]",
components: [
{ name: "target", type: "address" },
{ name: "callData", type: "bytes" }
]
}
],
name: "tryAggregate",
outputs: [
{
name: "returnData",
type: "tuple[]",
components: [
{ name: "success", type: "bool" },
{ name: "returnData", type: "bytes" }
]
}
],
stateMutability: "payable",
type: "function"
}
];
async function multicall(readContract, calls) {
const aggregateCalls = calls.map((call) => {
if ("callData" in call) {
return { target: call.address, callData: call.callData };
}
const callData = (0, import_viem2.encodeFunctionData)({
abi: call.abi,
functionName: call.functionName,
args: call.args
});
return { target: call.address, callData };
});
const rawResults = await readContract({
address: MULTICALL3_ADDRESS,
abi: multicall3ABI,
functionName: "tryAggregate",
args: [false, aggregateCalls]
});
return rawResults.map((raw, i) => {
if (!raw.success) {
return {
status: "failure",
error: new Error(`multicall: call reverted (returnData: ${raw.returnData})`)
};
}
const call = calls[i];
if ("callData" in call) {
return { status: "success", result: void 0 };
}
try {
const decoded = (0, import_viem2.decodeFunctionResult)({
abi: call.abi,
functionName: call.functionName,
data: raw.returnData
});
return { status: "success", result: decoded };
} catch (err) {
return {
status: "failure",
error: err instanceof Error ? err : new Error(String(err))
};
}
});
}
// src/exact/facilitator/eip3009-utils.ts
async function simulateEip3009Transfer(signer, erc20Address, payload, eip6492Deployment) {
const auth = payload.authorization;
const transferArgs = [
(0, import_viem3.getAddress)(auth.from),
(0, import_viem3.getAddress)(auth.to),
BigInt(auth.value),
BigInt(auth.validAfter),
BigInt(auth.validBefore),
auth.nonce
];
if (eip6492Deployment) {
const { signature: innerSignature } = (0, import_viem3.parseErc6492Signature)(payload.signature);
const transferCalldata = (0, import_viem3.encodeFunctionData)({
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [...transferArgs, innerSignature]
});
try {
const results = await multicall(signer.readContract.bind(signer), [
{
address: (0, import_viem3.getAddress)(eip6492Deployment.factoryAddress),
callData: eip6492Deployment.factoryCalldata
},
{
address: erc20Address,
callData: transferCalldata
}
]);
return results[1]?.status === "success";
} catch {
return false;
}
}
const sig = payload.signature;
const sigLength = sig.startsWith("0x") ? sig.length - 2 : sig.length;
const isECDSA = sigLength === 130;
try {
if (isECDSA) {
const parsedSig = (0, import_viem3.parseSignature)(sig);
await signer.readContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
...transferArgs,
parsedSig.v ?? parsedSig.yParity,
parsedSig.r,
parsedSig.s
]
});
} else {
await signer.readContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [...transferArgs, sig]
});
}
return true;
} catch {
return false;
}
}
async function diagnoseEip3009SimulationFailure(signer, erc20Address, payload, requirements, amountRequired) {
const payer = payload.authorization.from;
const diagnosticCalls = [
{
address: erc20Address,
abi: eip3009ABI,
functionName: "balanceOf",
args: [payload.authorization.from]
},
{
address: erc20Address,
abi: eip3009ABI,
functionName: "name"
},
{
address: erc20Address,
abi: eip3009ABI,
functionName: "version"
},
{
address: erc20Address,
abi: eip3009ABI,
functionName: "authorizationState",
args: [payload.authorization.from, payload.authorization.nonce]
}
];
try {
const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
const [balanceResult, nameResult, versionResult, authStateResult] = results;
if (authStateResult.status === "failure") {
return { isValid: false, invalidReason: ErrEip3009NotSupported, payer };
}
if (authStateResult.status === "success" && authStateResult.result === true) {
return { isValid: false, invalidReason: ErrEip3009NonceAlreadyUsed, payer };
}
if (nameResult.status === "success" && requirements.extra?.name && nameResult.result !== requirements.extra.name) {
return { isValid: false, invalidReason: ErrEip3009TokenNameMismatch, payer };
}
if (versionResult.status === "success" && requirements.extra?.version && versionResult.result !== requirements.extra.version) {
return { isValid: false, invalidReason: ErrEip3009TokenVersionMismatch, payer };
}
if (balanceResult.status === "success") {
const balance = balanceResult.result;
if (balance < BigInt(amountRequired)) {
return {
isValid: false,
invalidReason: ErrEip3009InsufficientBalance,
payer
};
}
}
} catch {
}
return { isValid: false, invalidReason: ErrEip3009SimulationFailed, payer };
}
async function executeTransferWithAuthorization(signer, erc20Address, payload) {
const { signature } = (0, import_viem3.parseErc6492Signature)(payload.signature);
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isECDSA = signatureLength === 130;
const auth = payload.authorization;
const baseArgs = [
(0, import_viem3.getAddress)(auth.from),
(0, import_viem3.getAddress)(auth.to),
BigInt(auth.value),
BigInt(auth.validAfter),
BigInt(auth.validBefore),
auth.nonce
];
if (isECDSA) {
const parsedSig = (0, import_viem3.parseSignature)(signature);
return signer.writeContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
...baseArgs,
parsedSig.v || parsedSig.yParity,
parsedSig.r,
parsedSig.s
]
});
}
return signer.writeContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [...baseArgs, signature]
});
}
// src/exact/facilitator/eip3009.ts
async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
async function verifyEIP3009(signer, payload, requirements, eip3009Payload, options) {
const payer = eip3009Payload.authorization.from;
let eip6492Deployment;
if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
return {
isValid: false,
invalidReason: "unsupported_scheme",
invalidReason: ErrInvalidScheme,
payer

@@ -286,3 +603,3 @@ };

isValid: false,
invalidReason: "missing_eip712_domain",
invalidReason: ErrMissingEip712Domain,
payer

@@ -292,7 +609,7 @@ };

const { name, version } = requirements.extra;
const erc20Address = (0, import_viem2.getAddress)(requirements.asset);
const erc20Address = (0, import_viem4.getAddress)(requirements.asset);
if (payload.accepted.network !== requirements.network) {
return {
isValid: false,
invalidReason: "network_mismatch",
invalidReason: ErrNetworkMismatch,
payer

@@ -319,4 +636,5 @@ };

};
let isValid = false;
try {
const recoveredAddress = await signer.verifyTypedData({
isValid = await signer.verifyTypedData({
address: eip3009Payload.authorization.from,

@@ -326,37 +644,30 @@ ...permitTypedData,

});
if (!recoveredAddress) {
} catch {
isValid = false;
}
const signature = eip3009Payload.signature;
const sigLen = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const erc6492Data = (0, import_viem4.parseErc6492Signature)(signature);
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem4.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
if (hasDeploymentInfo) {
eip6492Deployment = {
factoryAddress: erc6492Data.address,
factoryCalldata: erc6492Data.data
};
}
if (!isValid) {
const isSmartWallet = sigLen > 130;
if (!isSmartWallet) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
invalidReason: ErrInvalidSignature,
payer
};
}
} catch {
const signature = eip3009Payload.signature;
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isSmartWallet = signatureLength > 130;
if (isSmartWallet) {
const payerAddress = eip3009Payload.authorization.from;
const bytecode = await signer.getCode({ address: payerAddress });
if (!bytecode || bytecode === "0x") {
const erc6492Data = (0, import_viem2.parseErc6492Signature)(signature);
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem2.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
if (!hasDeploymentInfo) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
payer: payerAddress
};
}
} else {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
payer
};
}
} else {
const bytecode = await signer.getCode({ address: payer });
const isDeployed = bytecode && bytecode !== "0x";
if (!isDeployed && !hasDeploymentInfo) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
invalidReason: ErrUndeployedSmartWallet,
payer

@@ -366,6 +677,6 @@ };

}
if ((0, import_viem2.getAddress)(eip3009Payload.authorization.to) !== (0, import_viem2.getAddress)(requirements.payTo)) {
if ((0, import_viem4.getAddress)(eip3009Payload.authorization.to) !== (0, import_viem4.getAddress)(requirements.payTo)) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
invalidReason: ErrRecipientMismatch,
payer

@@ -378,3 +689,3 @@ };

isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
invalidReason: ErrValidBeforeExpired,
payer

@@ -386,30 +697,30 @@ };

isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
invalidReason: ErrValidAfterInFuture,
payer
};
}
try {
const balance = await signer.readContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "balanceOf",
args: [eip3009Payload.authorization.from]
});
if (BigInt(balance) < BigInt(requirements.amount)) {
return {
isValid: false,
invalidReason: "insufficient_funds",
invalidMessage: `Insufficient funds to complete the payment. Required: ${requirements.amount} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
payer
};
}
} catch {
}
if (BigInt(eip3009Payload.authorization.value) !== BigInt(requirements.amount)) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_value_mismatch",
invalidReason: ErrInvalidAuthorizationValue,
payer
};
}
if (options?.simulate !== false) {
const simulationSucceeded = await simulateEip3009Transfer(
signer,
erc20Address,
eip3009Payload,
eip6492Deployment
);
if (!simulationSucceeded) {
return diagnoseEip3009SimulationFailure(
signer,
erc20Address,
eip3009Payload,
requirements,
requirements.amount
);
}
}
return {

@@ -423,3 +734,5 @@ isValid: true,

const payer = eip3009Payload.authorization.from;
const valid = await verifyEIP3009(signer, payload, requirements, eip3009Payload);
const valid = await verifyEIP3009(signer, payload, requirements, eip3009Payload, {
simulate: config.simulateInSettle ?? false
});
if (!valid.isValid) {

@@ -430,3 +743,3 @@ return {

transaction: "",
errorReason: valid.invalidReason ?? "invalid_scheme",
errorReason: valid.invalidReason ?? ErrInvalidScheme,
payer

@@ -436,5 +749,6 @@ };

try {
const parseResult = (0, import_viem2.parseErc6492Signature)(eip3009Payload.signature);
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
if (config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem2.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
const { address: factoryAddress, data: factoryCalldata } = (0, import_viem4.parseErc6492Signature)(
eip3009Payload.signature
);
if (config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem4.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
const bytecode = await signer.getCode({ address: payer });

@@ -449,39 +763,7 @@ if (!bytecode || bytecode === "0x") {

}
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isECDSA = signatureLength === 130;
let tx;
if (isECDSA) {
const parsedSig = (0, import_viem2.parseSignature)(signature);
tx = await signer.writeContract({
address: (0, import_viem2.getAddress)(requirements.asset),
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
(0, import_viem2.getAddress)(eip3009Payload.authorization.from),
(0, import_viem2.getAddress)(eip3009Payload.authorization.to),
BigInt(eip3009Payload.authorization.value),
BigInt(eip3009Payload.authorization.validAfter),
BigInt(eip3009Payload.authorization.validBefore),
eip3009Payload.authorization.nonce,
parsedSig.v || parsedSig.yParity,
parsedSig.r,
parsedSig.s
]
});
} else {
tx = await signer.writeContract({
address: (0, import_viem2.getAddress)(requirements.asset),
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
(0, import_viem2.getAddress)(eip3009Payload.authorization.from),
(0, import_viem2.getAddress)(eip3009Payload.authorization.to),
BigInt(eip3009Payload.authorization.value),
BigInt(eip3009Payload.authorization.validAfter),
BigInt(eip3009Payload.authorization.validBefore),
eip3009Payload.authorization.nonce,
signature
]
});
}
const tx = await executeTransferWithAuthorization(
signer,
(0, import_viem4.getAddress)(requirements.asset),
eip3009Payload
);
const receipt = await signer.waitForTransactionReceipt({ hash: tx });

@@ -491,3 +773,3 @@ if (receipt.status !== "success") {

success: false,
errorReason: "invalid_transaction_state",
errorReason: ErrTransactionFailed,
transaction: tx,

@@ -507,3 +789,3 @@ network: payload.accepted.network,

success: false,
errorReason: "transaction_failed",
errorReason: ErrTransactionFailed,
transaction: "",

@@ -516,32 +798,55 @@ network: payload.accepted.network,

// src/exact/extensions.ts
var EIP2612_GAS_SPONSORING_KEY = "eip2612GasSponsoring";
var ERC20_APPROVAL_GAS_SPONSORING_KEY = "erc20ApprovalGasSponsoring";
function _extractInfo(payload, extensionKey) {
const extensions = payload.extensions;
if (!extensions) return null;
const extension = extensions[extensionKey];
if (!extension?.info) return null;
return extension.info;
}
function extractEip2612GasSponsoringInfo(payload) {
const info = _extractInfo(payload, EIP2612_GAS_SPONSORING_KEY);
if (!info) return null;
if (!info.from || !info.asset || !info.spender || !info.amount || !info.nonce || !info.deadline || !info.signature || !info.version) {
return null;
}
return info;
}
function validateEip2612GasSponsoringInfo(info) {
const addressPattern = /^0x[a-fA-F0-9]{40}$/;
const numericPattern = /^[0-9]+$/;
const hexPattern = /^0x[a-fA-F0-9]+$/;
const versionPattern = /^[0-9]+(\.[0-9]+)*$/;
return addressPattern.test(info.from) && addressPattern.test(info.asset) && addressPattern.test(info.spender) && numericPattern.test(info.amount) && numericPattern.test(info.nonce) && numericPattern.test(info.deadline) && hexPattern.test(info.signature) && versionPattern.test(info.version);
}
function extractErc20ApprovalGasSponsoringInfo(payload) {
const info = _extractInfo(payload, ERC20_APPROVAL_GAS_SPONSORING_KEY);
if (!info) return null;
if (!info.from || !info.asset || !info.spender || !info.amount || !info.signedTransaction || !info.version) {
return null;
}
return info;
}
function validateErc20ApprovalGasSponsoringInfo(info) {
const addressPattern = /^0x[a-fA-F0-9]{40}$/;
const numericPattern = /^[0-9]+$/;
const hexPattern = /^0x[a-fA-F0-9]+$/;
const versionPattern = /^[0-9]+(\.[0-9]+)*$/;
return addressPattern.test(info.from) && addressPattern.test(info.asset) && addressPattern.test(info.spender) && numericPattern.test(info.amount) && hexPattern.test(info.signedTransaction) && versionPattern.test(info.version);
}
function resolveErc20ApprovalExtensionSigner(extension, network) {
if (!extension) return void 0;
return extension.signerForNetwork?.(network) ?? extension.signer;
}
// src/exact/facilitator/permit2.ts
var import_extensions2 = require("@x402/extensions");
var import_viem4 = require("viem");
var import_viem7 = require("viem");
// src/exact/facilitator/errors.ts
var ErrPermit2InvalidSignature = "invalid_permit2_signature";
var ErrPermit2InvalidAmount = "permit2_invalid_amount";
var ErrPermit2InvalidDestination = "permit2_invalid_destination";
var ErrPermit2InvalidOwner = "permit2_invalid_owner";
var ErrPermit2PaymentTooEarly = "permit2_payment_too_early";
var ErrPermit2InvalidNonce = "permit2_invalid_nonce";
var ErrPermit2612AmountMismatch = "permit2_2612_amount_mismatch";
var ErrErc20ApprovalInvalidFormat = "invalid_erc20_approval_extension_format";
var ErrErc20ApprovalFromMismatch = "erc20_approval_from_mismatch";
var ErrErc20ApprovalAssetMismatch = "erc20_approval_asset_mismatch";
var ErrErc20ApprovalSpenderNotPermit2 = "erc20_approval_spender_not_permit2";
var ErrErc20ApprovalTxWrongTarget = "erc20_approval_tx_wrong_target";
var ErrErc20ApprovalTxWrongSelector = "erc20_approval_tx_wrong_selector";
var ErrErc20ApprovalTxWrongSpender = "erc20_approval_tx_wrong_spender";
var ErrErc20ApprovalTxInvalidCalldata = "erc20_approval_tx_invalid_calldata";
var ErrErc20ApprovalTxSignerMismatch = "erc20_approval_tx_signer_mismatch";
var ErrErc20ApprovalTxInvalidSignature = "erc20_approval_tx_invalid_signature";
var ErrErc20ApprovalTxParseFailed = "erc20_approval_tx_parse_failed";
// src/exact/facilitator/erc20approval.ts
var import_viem3 = require("viem");
var import_extensions = require("@x402/extensions");
var import_viem5 = require("viem");
var APPROVE_SELECTOR = "0x095ea7b3";
async function validateErc20ApprovalForPayment(info, payer, tokenAddress) {
if (!(0, import_extensions.validateErc20ApprovalGasSponsoringInfo)(info)) {
if (!validateErc20ApprovalGasSponsoringInfo(info)) {
return {

@@ -553,3 +858,3 @@ isValid: false,

}
if ((0, import_viem3.getAddress)(info.from) !== (0, import_viem3.getAddress)(payer)) {
if ((0, import_viem5.getAddress)(info.from) !== (0, import_viem5.getAddress)(payer)) {
return {

@@ -561,3 +866,3 @@ isValid: false,

}
if ((0, import_viem3.getAddress)(info.asset) !== tokenAddress) {
if ((0, import_viem5.getAddress)(info.asset) !== tokenAddress) {
return {

@@ -569,3 +874,3 @@ isValid: false,

}
if ((0, import_viem3.getAddress)(info.spender) !== (0, import_viem3.getAddress)(PERMIT2_ADDRESS)) {
if ((0, import_viem5.getAddress)(info.spender) !== (0, import_viem5.getAddress)(PERMIT2_ADDRESS)) {
return {

@@ -579,4 +884,4 @@ isValid: false,

const serializedTx = info.signedTransaction;
const tx = (0, import_viem3.parseTransaction)(serializedTx);
if (!tx.to || (0, import_viem3.getAddress)(tx.to) !== tokenAddress) {
const tx = (0, import_viem5.parseTransaction)(serializedTx);
if (!tx.to || (0, import_viem5.getAddress)(tx.to) !== tokenAddress) {
return {

@@ -597,8 +902,8 @@ isValid: false,

try {
const decoded = (0, import_viem3.decodeFunctionData)({
const decoded = (0, import_viem5.decodeFunctionData)({
abi: erc20ApproveAbi,
data
});
const calldataSpender = (0, import_viem3.getAddress)(decoded.args[0]);
if (calldataSpender !== (0, import_viem3.getAddress)(PERMIT2_ADDRESS)) {
const calldataSpender = (0, import_viem5.getAddress)(decoded.args[0]);
if (calldataSpender !== (0, import_viem5.getAddress)(PERMIT2_ADDRESS)) {
return {

@@ -618,6 +923,6 @@ isValid: false,

try {
const recoveredAddress = await (0, import_viem3.recoverTransactionAddress)({
const recoveredAddress = await (0, import_viem5.recoverTransactionAddress)({
serializedTransaction: serializedTx
});
if ((0, import_viem3.getAddress)(recoveredAddress) !== (0, import_viem3.getAddress)(payer)) {
if ((0, import_viem5.getAddress)(recoveredAddress) !== (0, import_viem5.getAddress)(payer)) {
return {

@@ -646,4 +951,253 @@ isValid: false,

// src/exact/facilitator/permit2-utils.ts
var import_viem6 = require("viem");
async function simulatePermit2Settle(signer, permit2Payload) {
try {
await signer.readContract({
address: x402ExactPermit2ProxyAddress,
abi: x402ExactPermit2ProxyABI,
functionName: "settle",
args: buildPermit2SettleArgs(permit2Payload)
});
return true;
} catch {
return false;
}
}
function splitEip2612Signature(signature) {
const sig = signature.startsWith("0x") ? signature.slice(2) : signature;
if (sig.length !== 130) {
throw new Error(
`invalid EIP-2612 signature length: expected 65 bytes (130 hex chars), got ${sig.length / 2} bytes`
);
}
const r = `0x${sig.slice(0, 64)}`;
const s = `0x${sig.slice(64, 128)}`;
const v = parseInt(sig.slice(128, 130), 16);
return { v, r, s };
}
function buildPermit2SettleArgs(permit2Payload) {
return [
{
permitted: {
token: (0, import_viem6.getAddress)(permit2Payload.permit2Authorization.permitted.token),
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
},
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
},
(0, import_viem6.getAddress)(permit2Payload.permit2Authorization.from),
{
to: (0, import_viem6.getAddress)(permit2Payload.permit2Authorization.witness.to),
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
},
permit2Payload.signature
];
}
function encodePermit2SettleCalldata(permit2Payload) {
return (0, import_viem6.encodeFunctionData)({
abi: x402ExactPermit2ProxyABI,
functionName: "settle",
args: buildPermit2SettleArgs(permit2Payload)
});
}
async function simulatePermit2SettleWithPermit(signer, permit2Payload, eip2612Info) {
try {
const { v, r, s } = splitEip2612Signature(eip2612Info.signature);
await signer.readContract({
address: x402ExactPermit2ProxyAddress,
abi: x402ExactPermit2ProxyABI,
functionName: "settleWithPermit",
args: [
{
value: BigInt(eip2612Info.amount),
deadline: BigInt(eip2612Info.deadline),
r,
s,
v
},
...buildPermit2SettleArgs(permit2Payload)
]
});
return true;
} catch {
return false;
}
}
async function diagnosePermit2SimulationFailure(signer, tokenAddress, permit2Payload, amountRequired) {
const payer = permit2Payload.permit2Authorization.from;
const diagnosticCalls = [
{
address: x402ExactPermit2ProxyAddress,
abi: x402ExactPermit2ProxyABI,
functionName: "PERMIT2"
},
{
address: tokenAddress,
abi: eip3009ABI,
functionName: "balanceOf",
args: [payer]
},
{
address: tokenAddress,
abi: erc20AllowanceAbi,
functionName: "allowance",
args: [payer, PERMIT2_ADDRESS]
}
];
try {
const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
const [proxyResult, balanceResult, allowanceResult] = results;
if (proxyResult.status === "failure") {
return { isValid: false, invalidReason: ErrPermit2ProxyNotDeployed, payer };
}
if (balanceResult.status === "success") {
const balance = balanceResult.result;
if (balance < BigInt(amountRequired)) {
return { isValid: false, invalidReason: ErrPermit2InsufficientBalance, payer };
}
}
if (allowanceResult.status === "success") {
const allowance = allowanceResult.result;
if (allowance < BigInt(amountRequired)) {
return { isValid: false, invalidReason: ErrPermit2AllowanceRequired, payer };
}
}
} catch {
}
return { isValid: false, invalidReason: ErrPermit2SimulationFailed, payer };
}
async function checkPermit2Prerequisites(signer, tokenAddress, payer, amountRequired) {
const diagnosticCalls = [
{
address: x402ExactPermit2ProxyAddress,
abi: x402ExactPermit2ProxyABI,
functionName: "PERMIT2"
},
{
address: tokenAddress,
abi: eip3009ABI,
functionName: "balanceOf",
args: [payer]
},
{
address: MULTICALL3_ADDRESS,
abi: multicall3GetEthBalanceAbi,
functionName: "getEthBalance",
args: [payer]
}
];
try {
const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
const [proxyResult, balanceResult, ethBalanceResult] = results;
if (proxyResult.status === "failure") {
return { isValid: false, invalidReason: ErrPermit2ProxyNotDeployed, payer };
}
if (balanceResult.status === "success") {
const balance = balanceResult.result;
if (balance < BigInt(amountRequired)) {
return { isValid: false, invalidReason: ErrPermit2InsufficientBalance, payer };
}
}
if (ethBalanceResult.status === "success") {
const minEthForApprovalGas = ERC20_APPROVE_GAS_LIMIT * DEFAULT_MAX_FEE_PER_GAS;
const ethBalance = ethBalanceResult.result;
if (ethBalance < minEthForApprovalGas) {
return {
isValid: false,
invalidReason: ErrErc20ApprovalInsufficientEthForGas,
payer
};
}
}
} catch {
}
return { isValid: true, invalidReason: void 0, payer };
}
async function simulatePermit2SettleWithErc20Approval(extensionSigner, permit2Payload, erc20Info) {
if (!extensionSigner.simulateTransactions) {
return false;
}
try {
const settleData = encodePermit2SettleCalldata(permit2Payload);
return await extensionSigner.simulateTransactions([
erc20Info.signedTransaction,
{ to: x402ExactPermit2ProxyAddress, data: settleData, gas: BigInt(3e5) }
]);
} catch {
return false;
}
}
async function waitAndReturn(signer, tx, payload, payer) {
const receipt = await signer.waitForTransactionReceipt({ hash: tx });
if (receipt.status !== "success") {
return {
success: false,
errorReason: ErrInvalidTransactionState,
transaction: tx,
network: payload.accepted.network,
payer
};
}
return {
success: true,
transaction: tx,
network: payload.accepted.network,
payer
};
}
function mapSettleError(error, payload, payer) {
let errorReason = ErrTransactionFailed;
if (error instanceof Error) {
const message = error.message;
if (message.includes("Permit2612AmountMismatch")) {
errorReason = ErrPermit2612AmountMismatch;
} else if (message.includes("InvalidAmount")) {
errorReason = ErrPermit2InvalidAmount;
} else if (message.includes("InvalidDestination")) {
errorReason = ErrPermit2InvalidDestination;
} else if (message.includes("InvalidOwner")) {
errorReason = ErrPermit2InvalidOwner;
} else if (message.includes("PaymentTooEarly")) {
errorReason = ErrPermit2PaymentTooEarly;
} else if (message.includes("InvalidSignature") || message.includes("SignatureExpired")) {
errorReason = ErrPermit2InvalidSignature;
} else if (message.includes("InvalidNonce")) {
errorReason = ErrPermit2InvalidNonce;
} else if (message.includes("erc20_approval_tx_failed")) {
errorReason = ErrErc20ApprovalTxFailed;
} else {
errorReason = `${ErrTransactionFailed}: ${message.slice(0, 500)}`;
}
}
return {
success: false,
errorReason,
transaction: "",
network: payload.accepted.network,
payer
};
}
function validateEip2612PermitForPayment(info, payer, tokenAddress) {
if (!validateEip2612GasSponsoringInfo(info)) {
return { isValid: false, invalidReason: ErrInvalidEip2612ExtensionFormat };
}
if ((0, import_viem6.getAddress)(info.from) !== (0, import_viem6.getAddress)(payer)) {
return { isValid: false, invalidReason: ErrEip2612FromMismatch };
}
if ((0, import_viem6.getAddress)(info.asset) !== tokenAddress) {
return { isValid: false, invalidReason: ErrEip2612AssetMismatch };
}
if ((0, import_viem6.getAddress)(info.spender) !== (0, import_viem6.getAddress)(PERMIT2_ADDRESS)) {
return { isValid: false, invalidReason: ErrEip2612SpenderNotPermit2 };
}
const now = Math.floor(Date.now() / 1e3);
if (BigInt(info.deadline) < BigInt(now + 6)) {
return { isValid: false, invalidReason: ErrEip2612DeadlineExpired };
}
return { isValid: true };
}
// src/exact/facilitator/permit2.ts
async function verifyPermit2(signer, payload, requirements, permit2Payload, context) {
async function verifyPermit2(signer, payload, requirements, permit2Payload, context, options) {
const payer = permit2Payload.permit2Authorization.from;

@@ -653,3 +1207,3 @@ if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {

isValid: false,
invalidReason: "unsupported_scheme",
invalidReason: ErrUnsupportedPayloadType,
payer

@@ -661,3 +1215,3 @@ };

isValid: false,
invalidReason: "network_mismatch",
invalidReason: ErrNetworkMismatch,
payer

@@ -667,14 +1221,14 @@ };

const chainId = getEvmChainId(requirements.network);
const tokenAddress = (0, import_viem4.getAddress)(requirements.asset);
if ((0, import_viem4.getAddress)(permit2Payload.permit2Authorization.spender) !== (0, import_viem4.getAddress)(x402ExactPermit2ProxyAddress)) {
const tokenAddress = (0, import_viem7.getAddress)(requirements.asset);
if ((0, import_viem7.getAddress)(permit2Payload.permit2Authorization.spender) !== (0, import_viem7.getAddress)(x402ExactPermit2ProxyAddress)) {
return {
isValid: false,
invalidReason: "invalid_permit2_spender",
invalidReason: ErrPermit2InvalidSpender,
payer
};
}
if ((0, import_viem4.getAddress)(permit2Payload.permit2Authorization.witness.to) !== (0, import_viem4.getAddress)(requirements.payTo)) {
if ((0, import_viem7.getAddress)(permit2Payload.permit2Authorization.witness.to) !== (0, import_viem7.getAddress)(requirements.payTo)) {
return {
isValid: false,
invalidReason: "invalid_permit2_recipient_mismatch",
invalidReason: ErrPermit2RecipientMismatch,
payer

@@ -687,3 +1241,3 @@ };

isValid: false,
invalidReason: "permit2_deadline_expired",
invalidReason: ErrPermit2DeadlineExpired,
payer

@@ -695,3 +1249,3 @@ };

isValid: false,
invalidReason: "permit2_not_yet_valid",
invalidReason: ErrPermit2NotYetValid,
payer

@@ -703,10 +1257,10 @@ };

isValid: false,
invalidReason: "permit2_amount_mismatch",
invalidReason: ErrPermit2AmountMismatch,
payer
};
}
if ((0, import_viem4.getAddress)(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
if ((0, import_viem7.getAddress)(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
return {
isValid: false,
invalidReason: "permit2_token_mismatch",
invalidReason: ErrPermit2TokenMismatch,
payer

@@ -725,10 +1279,10 @@ };

permitted: {
token: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.permitted.token),
token: (0, import_viem7.getAddress)(permit2Payload.permit2Authorization.permitted.token),
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
},
spender: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.spender),
spender: (0, import_viem7.getAddress)(permit2Payload.permit2Authorization.spender),
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
deadline: BigInt(permit2Payload.permit2Authorization.deadline),
witness: {
to: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.witness.to),
to: (0, import_viem7.getAddress)(permit2Payload.permit2Authorization.witness.to),
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)

@@ -738,4 +1292,5 @@ }

};
let signatureValid = false;
try {
const isValid = await signer.verifyTypedData({
signatureValid = await signer.verifyTypedData({
address: payer,

@@ -745,97 +1300,85 @@ ...permit2TypedData,

});
if (!isValid) {
} catch {
signatureValid = false;
}
if (!signatureValid) {
const bytecode = await signer.getCode({ address: payer });
const isDeployedContract = bytecode && bytecode !== "0x";
if (!isDeployedContract) {
return {
isValid: false,
invalidReason: "invalid_permit2_signature",
invalidReason: ErrPermit2InvalidSignature,
payer
};
}
} catch {
return {
isValid: false,
invalidReason: "invalid_permit2_signature",
payer
};
}
const allowanceResult = await _verifyPermit2Allowance(
signer,
payload,
requirements,
payer,
tokenAddress,
context
);
if (allowanceResult) {
return allowanceResult;
if (options?.simulate === false) {
return { isValid: true, invalidReason: void 0, payer };
}
try {
const balance = await signer.readContract({
address: tokenAddress,
abi: eip3009ABI,
functionName: "balanceOf",
args: [payer]
});
if (balance < BigInt(requirements.amount)) {
return {
isValid: false,
invalidReason: "insufficient_funds",
invalidMessage: `Insufficient funds to complete the payment. Required: ${requirements.amount} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
payer
};
const eip2612Info = extractEip2612GasSponsoringInfo(payload);
if (eip2612Info) {
const fieldResult = validateEip2612PermitForPayment(eip2612Info, payer, tokenAddress);
if (!fieldResult.isValid) {
return { isValid: false, invalidReason: fieldResult.invalidReason, payer };
}
} catch {
const simOk2 = await simulatePermit2SettleWithPermit(signer, permit2Payload, eip2612Info);
if (!simOk2) {
return diagnosePermit2SimulationFailure(
signer,
tokenAddress,
permit2Payload,
requirements.amount
);
}
return { isValid: true, invalidReason: void 0, payer };
}
return {
isValid: true,
invalidReason: void 0,
payer
};
}
async function _verifyPermit2Allowance(signer, payload, requirements, payer, tokenAddress, context) {
try {
const allowance = await signer.readContract({
address: tokenAddress,
abi: erc20AllowanceAbi,
functionName: "allowance",
args: [payer, PERMIT2_ADDRESS]
});
if (allowance >= BigInt(requirements.amount)) {
return null;
}
const eip2612Info = (0, import_extensions2.extractEip2612GasSponsoringInfo)(payload);
if (eip2612Info) {
const result = validateEip2612PermitForPayment(eip2612Info, payer, tokenAddress);
if (!result.isValid) {
return { isValid: false, invalidReason: result.invalidReason, payer };
const erc20GasSponsorshipExtension = context?.getExtension(
ERC20_APPROVAL_GAS_SPONSORING_KEY
);
if (erc20GasSponsorshipExtension) {
const erc20Info = extractErc20ApprovalGasSponsoringInfo(payload);
if (erc20Info) {
const fieldResult = await validateErc20ApprovalForPayment(erc20Info, payer, tokenAddress);
if (!fieldResult.isValid) {
return { isValid: false, invalidReason: fieldResult.invalidReason, payer };
}
return null;
}
const erc20GasSponsorshipExtension = context?.getExtension(
import_extensions2.ERC20_APPROVAL_GAS_SPONSORING.key
);
if (erc20GasSponsorshipExtension) {
const erc20Info = (0, import_extensions2.extractErc20ApprovalGasSponsoringInfo)(payload);
if (erc20Info) {
const result = await validateErc20ApprovalForPayment(erc20Info, payer, tokenAddress);
if (!result.isValid) {
return { isValid: false, invalidReason: result.invalidReason, payer };
const extensionSigner = resolveErc20ApprovalExtensionSigner(
erc20GasSponsorshipExtension,
requirements.network
);
if (extensionSigner?.simulateTransactions) {
const simOk2 = await simulatePermit2SettleWithErc20Approval(
extensionSigner,
permit2Payload,
erc20Info
);
if (!simOk2) {
return diagnosePermit2SimulationFailure(
signer,
tokenAddress,
permit2Payload,
requirements.amount
);
}
return null;
return { isValid: true, invalidReason: void 0, payer };
}
return checkPermit2Prerequisites(signer, tokenAddress, payer, requirements.amount);
}
return { isValid: false, invalidReason: "permit2_allowance_required", payer };
} catch {
const eip2612Info = (0, import_extensions2.extractEip2612GasSponsoringInfo)(payload);
if (eip2612Info) {
const result = validateEip2612PermitForPayment(eip2612Info, payer, tokenAddress);
if (!result.isValid) {
return { isValid: false, invalidReason: result.invalidReason, payer };
}
}
return null;
}
const simOk = await simulatePermit2Settle(signer, permit2Payload);
if (!simOk) {
return diagnosePermit2SimulationFailure(
signer,
tokenAddress,
permit2Payload,
requirements.amount
);
}
return { isValid: true, invalidReason: void 0, payer };
}
async function settlePermit2(signer, payload, requirements, permit2Payload, context) {
async function settlePermit2(signer, payload, requirements, permit2Payload, context, config) {
const payer = permit2Payload.permit2Authorization.from;
const valid = await verifyPermit2(signer, payload, requirements, permit2Payload, context);
const valid = await verifyPermit2(signer, payload, requirements, permit2Payload, context, {
simulate: config?.simulateInSettle ?? false
});
if (!valid.isValid) {

@@ -846,22 +1389,21 @@ return {

transaction: "",
errorReason: valid.invalidReason ?? "invalid_scheme",
errorReason: valid.invalidReason ?? ErrInvalidScheme,
payer
};
}
const eip2612Info = (0, import_extensions2.extractEip2612GasSponsoringInfo)(payload);
const eip2612Info = extractEip2612GasSponsoringInfo(payload);
if (eip2612Info) {
return _settlePermit2WithEIP2612(signer, payload, permit2Payload, eip2612Info);
}
const erc20Info = (0, import_extensions2.extractErc20ApprovalGasSponsoringInfo)(payload);
const erc20Info = extractErc20ApprovalGasSponsoringInfo(payload);
if (erc20Info) {
const erc20GasSponsorshipExtension = context?.getExtension(
import_extensions2.ERC20_APPROVAL_GAS_SPONSORING.key
ERC20_APPROVAL_GAS_SPONSORING_KEY
);
if (erc20GasSponsorshipExtension?.signer) {
return _settlePermit2WithERC20Approval(
erc20GasSponsorshipExtension.signer,
payload,
permit2Payload,
erc20Info
);
const extensionSigner = resolveErc20ApprovalExtensionSigner(
erc20GasSponsorshipExtension,
payload.accepted.network
);
if (extensionSigner) {
return _settlePermit2WithERC20Approval(extensionSigner, payload, permit2Payload, erc20Info);
}

@@ -887,21 +1429,8 @@ }

},
{
permitted: {
token: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.permitted.token),
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
},
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
},
(0, import_viem4.getAddress)(payer),
{
to: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.witness.to),
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
},
permit2Payload.signature
...buildPermit2SettleArgs(permit2Payload)
]
});
return _waitAndReturn(signer, tx, payload, payer);
return waitAndReturn(signer, tx, payload, payer);
} catch (error) {
return _mapSettleError(error, payload, payer);
return mapSettleError(error, payload, payer);
}

@@ -912,41 +1441,11 @@ }

try {
const approvalTxHash = await extensionSigner.sendRawTransaction({
serializedTransaction: erc20Info.signedTransaction
});
const approvalReceipt = await extensionSigner.waitForTransactionReceipt({
hash: approvalTxHash
});
if (approvalReceipt.status !== "success") {
return {
success: false,
errorReason: "erc20_approval_tx_failed",
transaction: approvalTxHash,
network: payload.accepted.network,
payer
};
}
const tx = await extensionSigner.writeContract({
address: x402ExactPermit2ProxyAddress,
abi: x402ExactPermit2ProxyABI,
functionName: "settle",
args: [
{
permitted: {
token: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.permitted.token),
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
},
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
},
(0, import_viem4.getAddress)(payer),
{
to: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.witness.to),
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
},
permit2Payload.signature
]
});
return _waitAndReturn(extensionSigner, tx, payload, payer);
const settleData = encodePermit2SettleCalldata(permit2Payload);
const txHashes = await extensionSigner.sendTransactions([
erc20Info.signedTransaction,
{ to: x402ExactPermit2ProxyAddress, data: settleData, gas: BigInt(3e5) }
]);
const settleTxHash = txHashes[txHashes.length - 1];
return waitAndReturn(extensionSigner, settleTxHash, payload, payer);
} catch (error) {
return _mapSettleError(error, payload, payer);
return mapSettleError(error, payload, payer);
}

@@ -961,103 +1460,9 @@ }

functionName: "settle",
args: [
{
permitted: {
token: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.permitted.token),
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
},
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
},
(0, import_viem4.getAddress)(payer),
{
to: (0, import_viem4.getAddress)(permit2Payload.permit2Authorization.witness.to),
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
},
permit2Payload.signature
]
args: buildPermit2SettleArgs(permit2Payload)
});
return _waitAndReturn(signer, tx, payload, payer);
return waitAndReturn(signer, tx, payload, payer);
} catch (error) {
return _mapSettleError(error, payload, payer);
return mapSettleError(error, payload, payer);
}
}
async function _waitAndReturn(signer, tx, payload, payer) {
const receipt = await signer.waitForTransactionReceipt({ hash: tx });
if (receipt.status !== "success") {
return {
success: false,
errorReason: "invalid_transaction_state",
transaction: tx,
network: payload.accepted.network,
payer
};
}
return {
success: true,
transaction: tx,
network: payload.accepted.network,
payer
};
}
function _mapSettleError(error, payload, payer) {
let errorReason = "transaction_failed";
if (error instanceof Error) {
const message = error.message;
if (message.includes("Permit2612AmountMismatch")) {
errorReason = ErrPermit2612AmountMismatch;
} else if (message.includes("InvalidAmount")) {
errorReason = ErrPermit2InvalidAmount;
} else if (message.includes("InvalidDestination")) {
errorReason = ErrPermit2InvalidDestination;
} else if (message.includes("InvalidOwner")) {
errorReason = ErrPermit2InvalidOwner;
} else if (message.includes("PaymentTooEarly")) {
errorReason = ErrPermit2PaymentTooEarly;
} else if (message.includes("InvalidSignature") || message.includes("SignatureExpired")) {
errorReason = ErrPermit2InvalidSignature;
} else if (message.includes("InvalidNonce")) {
errorReason = ErrPermit2InvalidNonce;
} else {
errorReason = `transaction_failed: ${message.slice(0, 500)}`;
}
}
return {
success: false,
errorReason,
transaction: "",
network: payload.accepted.network,
payer
};
}
function validateEip2612PermitForPayment(info, payer, tokenAddress) {
if (!(0, import_extensions2.validateEip2612GasSponsoringInfo)(info)) {
return { isValid: false, invalidReason: "invalid_eip2612_extension_format" };
}
if ((0, import_viem4.getAddress)(info.from) !== (0, import_viem4.getAddress)(payer)) {
return { isValid: false, invalidReason: "eip2612_from_mismatch" };
}
if ((0, import_viem4.getAddress)(info.asset) !== tokenAddress) {
return { isValid: false, invalidReason: "eip2612_asset_mismatch" };
}
if ((0, import_viem4.getAddress)(info.spender) !== (0, import_viem4.getAddress)(PERMIT2_ADDRESS)) {
return { isValid: false, invalidReason: "eip2612_spender_not_permit2" };
}
const now = Math.floor(Date.now() / 1e3);
if (BigInt(info.deadline) < BigInt(now + 6)) {
return { isValid: false, invalidReason: "eip2612_deadline_expired" };
}
return { isValid: true };
}
function splitEip2612Signature(signature) {
const sig = signature.startsWith("0x") ? signature.slice(2) : signature;
if (sig.length !== 130) {
throw new Error(
`invalid EIP-2612 signature length: expected 65 bytes (130 hex chars), got ${sig.length / 2} bytes`
);
}
const r = `0x${sig.slice(0, 64)}`;
const s = `0x${sig.slice(64, 128)}`;
const v = parseInt(sig.slice(128, 130), 16);
return { v, r, s };
}

@@ -1077,3 +1482,4 @@ // src/exact/facilitator/scheme.ts

this.config = {
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,
simulateInSettle: config?.simulateInSettle ?? false
};

@@ -1109,3 +1515,4 @@ }

const rawPayload = payload.payload;
if (isPermit2Payload(rawPayload)) {
const isPermit2 = isPermit2Payload(rawPayload);
if (isPermit2) {
return verifyPermit2(this.signer, payload, requirements, rawPayload, context);

@@ -1126,4 +1533,7 @@ }

const rawPayload = payload.payload;
if (isPermit2Payload(rawPayload)) {
return settlePermit2(this.signer, payload, requirements, rawPayload, context);
const isPermit2 = isPermit2Payload(rawPayload);
if (isPermit2) {
return settlePermit2(this.signer, payload, requirements, rawPayload, context, {
simulateInSettle: this.config.simulateInSettle
});
}

@@ -1136,6 +1546,6 @@ const eip3009Payload = rawPayload;

// src/exact/v1/facilitator/scheme.ts
var import_viem6 = require("viem");
var import_viem9 = require("viem");
// src/exact/v1/client/scheme.ts
var import_viem5 = require("viem");
var import_viem8 = require("viem");

@@ -1186,3 +1596,4 @@ // src/v1/index.ts

this.config = {
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,
simulateInSettle: config?.simulateInSettle ?? false
};

@@ -1218,10 +1629,91 @@ }

async verify(payload, requirements) {
return this._verify(payload, requirements);
}
/**
* Settles a payment by executing the transfer (V1).
*
* @param payload - The payment payload to settle
* @param requirements - The payment requirements
* @returns Promise resolving to settlement response
*/
async settle(payload, requirements) {
const payloadV1 = payload;
const exactEvmPayload = payload.payload;
const valid = await this._verify(payload, requirements, {
simulate: this.config.simulateInSettle ?? false
});
if (!valid.isValid) {
return {
success: false,
network: payloadV1.network,
transaction: "",
errorReason: valid.invalidReason ?? ErrInvalidScheme,
payer: exactEvmPayload.authorization.from
};
}
try {
const { address: factoryAddress, data: factoryCalldata } = (0, import_viem9.parseErc6492Signature)(
exactEvmPayload.signature
);
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem9.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
const payerAddress = exactEvmPayload.authorization.from;
const bytecode = await this.signer.getCode({ address: payerAddress });
if (!bytecode || bytecode === "0x") {
const deployTx = await this.signer.sendTransaction({
to: factoryAddress,
data: factoryCalldata
});
await this.signer.waitForTransactionReceipt({ hash: deployTx });
}
}
const tx = await executeTransferWithAuthorization(
this.signer,
(0, import_viem9.getAddress)(requirements.asset),
exactEvmPayload
);
const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
if (receipt.status !== "success") {
return {
success: false,
errorReason: ErrTransactionFailed,
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
return {
success: true,
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
} catch (error) {
return {
success: false,
errorReason: error instanceof Error ? error.message : ErrTransactionFailed,
transaction: "",
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
}
/**
* Internal verify with optional simulation control.
*
* @param payload - The payment payload to verify
* @param requirements - The payment requirements
* @param options - Verification options (e.g. simulate)
* @returns Promise resolving to verification response
*/
async _verify(payload, requirements, options) {
const requirementsV1 = requirements;
const payloadV1 = payload;
const exactEvmPayload = payload.payload;
const payer = exactEvmPayload.authorization.from;
let eip6492Deployment;
if (payloadV1.scheme !== "exact" || requirements.scheme !== "exact") {
return {
isValid: false,
invalidReason: "unsupported_scheme",
payer: exactEvmPayload.authorization.from
invalidReason: ErrInvalidScheme,
payer
};

@@ -1235,4 +1727,4 @@ }

isValid: false,
invalidReason: `invalid_network`,
payer: exactEvmPayload.authorization.from
invalidReason: ErrNetworkMismatch,
payer
};

@@ -1243,13 +1735,13 @@ }

isValid: false,
invalidReason: "missing_eip712_domain",
payer: exactEvmPayload.authorization.from
invalidReason: ErrMissingEip712Domain,
payer
};
}
const { name, version } = requirements.extra;
const erc20Address = (0, import_viem6.getAddress)(requirements.asset);
const erc20Address = (0, import_viem9.getAddress)(requirements.asset);
if (payloadV1.network !== requirements.network) {
return {
isValid: false,
invalidReason: "network_mismatch",
payer: exactEvmPayload.authorization.from
invalidReason: ErrNetworkMismatch,
payer
};

@@ -1275,52 +1767,46 @@ }

};
let isValid = false;
try {
const recoveredAddress = await this.signer.verifyTypedData({
address: exactEvmPayload.authorization.from,
isValid = await this.signer.verifyTypedData({
address: payer,
...permitTypedData,
signature: exactEvmPayload.signature
});
if (!recoveredAddress) {
} catch {
isValid = false;
}
const signature = exactEvmPayload.signature;
const sigLen = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const erc6492Data = (0, import_viem9.parseErc6492Signature)(signature);
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem9.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
if (hasDeploymentInfo) {
eip6492Deployment = {
factoryAddress: erc6492Data.address,
factoryCalldata: erc6492Data.data
};
}
if (!isValid) {
const isSmartWallet = sigLen > 130;
if (!isSmartWallet) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
payer: exactEvmPayload.authorization.from
invalidReason: ErrInvalidSignature,
payer
};
}
} catch {
const signature = exactEvmPayload.signature;
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isSmartWallet = signatureLength > 130;
if (isSmartWallet) {
const payerAddress = exactEvmPayload.authorization.from;
const bytecode = await this.signer.getCode({ address: payerAddress });
if (!bytecode || bytecode === "0x") {
const erc6492Data = (0, import_viem6.parseErc6492Signature)(signature);
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem6.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
if (!hasDeploymentInfo) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
payer: payerAddress
};
}
} else {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
payer: exactEvmPayload.authorization.from
};
}
} else {
const bytecode = await this.signer.getCode({ address: payer });
const isDeployed = bytecode && bytecode !== "0x";
if (!isDeployed && !hasDeploymentInfo) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
payer: exactEvmPayload.authorization.from
invalidReason: ErrUndeployedSmartWallet,
payer
};
}
}
if ((0, import_viem6.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem6.getAddress)(requirements.payTo)) {
if ((0, import_viem9.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem9.getAddress)(requirements.payTo)) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
payer: exactEvmPayload.authorization.from
invalidReason: ErrRecipientMismatch,
payer
};

@@ -1332,4 +1818,4 @@ }

isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
payer: exactEvmPayload.authorization.from
invalidReason: ErrValidBeforeExpired,
payer
};

@@ -1340,143 +1826,36 @@ }

isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
payer: exactEvmPayload.authorization.from
invalidReason: ErrValidAfterInFuture,
payer
};
}
try {
const balance = await this.signer.readContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "balanceOf",
args: [exactEvmPayload.authorization.from]
});
if (BigInt(balance) < BigInt(requirementsV1.maxAmountRequired)) {
return {
isValid: false,
invalidReason: "insufficient_funds",
invalidMessage: `Insufficient funds to complete the payment. Required: ${requirementsV1.maxAmountRequired} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
payer: exactEvmPayload.authorization.from
};
}
} catch {
}
if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_value_mismatch",
payer: exactEvmPayload.authorization.from
invalidReason: ErrInvalidAuthorizationValue,
payer
};
}
if (options?.simulate !== false) {
const simulationSucceeded = await simulateEip3009Transfer(
this.signer,
erc20Address,
exactEvmPayload,
eip6492Deployment
);
if (!simulationSucceeded) {
return diagnoseEip3009SimulationFailure(
this.signer,
erc20Address,
exactEvmPayload,
requirements,
requirementsV1.maxAmountRequired
);
}
}
return {
isValid: true,
invalidReason: void 0,
payer: exactEvmPayload.authorization.from
payer
};
}
/**
* Settles a payment by executing the transfer (V1).
*
* @param payload - The payment payload to settle
* @param requirements - The payment requirements
* @returns Promise resolving to settlement response
*/
async settle(payload, requirements) {
const payloadV1 = payload;
const exactEvmPayload = payload.payload;
const valid = await this.verify(payload, requirements);
if (!valid.isValid) {
return {
success: false,
network: payloadV1.network,
transaction: "",
errorReason: valid.invalidReason ?? "invalid_scheme",
payer: exactEvmPayload.authorization.from
};
}
try {
const parseResult = (0, import_viem6.parseErc6492Signature)(exactEvmPayload.signature);
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem6.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
const payerAddress = exactEvmPayload.authorization.from;
const bytecode = await this.signer.getCode({ address: payerAddress });
if (!bytecode || bytecode === "0x") {
try {
console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);
const deployTx = await this.signer.sendTransaction({
to: factoryAddress,
data: factoryCalldata
});
await this.signer.waitForTransactionReceipt({ hash: deployTx });
console.log(`Successfully deployed smart wallet for ${payerAddress}`);
} catch (deployError) {
console.error("Smart wallet deployment failed:", deployError);
throw deployError;
}
} else {
console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);
}
}
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isECDSA = signatureLength === 130;
let tx;
if (isECDSA) {
const parsedSig = (0, import_viem6.parseSignature)(signature);
tx = await this.signer.writeContract({
address: (0, import_viem6.getAddress)(requirements.asset),
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
(0, import_viem6.getAddress)(exactEvmPayload.authorization.from),
(0, import_viem6.getAddress)(exactEvmPayload.authorization.to),
BigInt(exactEvmPayload.authorization.value),
BigInt(exactEvmPayload.authorization.validAfter),
BigInt(exactEvmPayload.authorization.validBefore),
exactEvmPayload.authorization.nonce,
parsedSig.v || parsedSig.yParity,
parsedSig.r,
parsedSig.s
]
});
} else {
tx = await this.signer.writeContract({
address: (0, import_viem6.getAddress)(requirements.asset),
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
(0, import_viem6.getAddress)(exactEvmPayload.authorization.from),
(0, import_viem6.getAddress)(exactEvmPayload.authorization.to),
BigInt(exactEvmPayload.authorization.value),
BigInt(exactEvmPayload.authorization.validAfter),
BigInt(exactEvmPayload.authorization.validBefore),
exactEvmPayload.authorization.nonce,
signature
]
});
}
const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
if (receipt.status !== "success") {
return {
success: false,
errorReason: "invalid_transaction_state",
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
return {
success: true,
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
} catch (error) {
console.error("Failed to settle transaction:", error);
return {
success: false,
errorReason: "transaction_failed",
transaction: "",
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
}
};

@@ -1489,3 +1868,4 @@

new ExactEvmScheme(config.signer, {
deployERC4337WithEIP6492: config.deployERC4337WithEIP6492
deployERC4337WithEIP6492: config.deployERC4337WithEIP6492,
simulateInSettle: config.simulateInSettle
})

@@ -1496,3 +1876,4 @@ );

new ExactEvmSchemeV12(config.signer, {
deployERC4337WithEIP6492: config.deployERC4337WithEIP6492
deployERC4337WithEIP6492: config.deployERC4337WithEIP6492,
simulateInSettle: config.simulateInSettle
})

@@ -1499,0 +1880,0 @@ );

import { SchemeNetworkClient, PaymentRequirements, PaymentPayload, Network } from '@x402/core/types';
import { C as ClientEvmSigner } from '../../../signer-DC81R8wQ.js';
import { C as ClientEvmSigner } from '../../../signer-D912R4mq.js';

@@ -4,0 +4,0 @@ /**

@@ -28,3 +28,3 @@ "use strict";

// src/exact/v1/client/scheme.ts
var import_viem3 = require("viem");
var import_viem5 = require("viem");

@@ -57,2 +57,8 @@ // src/constants.ts

// src/exact/v1/facilitator/scheme.ts
var import_viem4 = require("viem");
// src/exact/facilitator/eip3009-utils.ts
var import_viem3 = require("viem");
// src/multicall.ts
var import_viem2 = require("viem");

@@ -115,3 +121,3 @@

from: this.signer.address,
to: (0, import_viem3.getAddress)(selectedV1.payTo),
to: (0, import_viem5.getAddress)(selectedV1.payTo),
value: selectedV1.maxAmountRequired,

@@ -154,7 +160,7 @@ validAfter: (now - 600).toString(),

chainId,
verifyingContract: (0, import_viem3.getAddress)(requirements.asset)
verifyingContract: (0, import_viem5.getAddress)(requirements.asset)
};
const message = {
from: (0, import_viem3.getAddress)(authorization.from),
to: (0, import_viem3.getAddress)(authorization.to),
from: (0, import_viem5.getAddress)(authorization.from),
to: (0, import_viem5.getAddress)(authorization.to),
value: BigInt(authorization.value),

@@ -161,0 +167,0 @@ validAfter: BigInt(authorization.validAfter),

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../../../../src/exact/v1/client/index.ts","../../../../../src/exact/v1/client/scheme.ts","../../../../../src/constants.ts","../../../../../src/utils.ts","../../../../../src/exact/v1/facilitator/scheme.ts","../../../../../src/v1/index.ts"],"sourcesContent":["export { ExactEvmSchemeV1 } from \"./scheme\";\n","import {\n Network,\n PaymentPayload,\n PaymentRequirements,\n SchemeNetworkClient,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress } from \"viem\";\nimport { authorizationTypes } from \"../../../constants\";\nimport { ClientEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { createNonce } from \"../../../utils\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\n\n/**\n * EVM client implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkClient {\n readonly scheme = \"exact\";\n\n /**\n * Creates a new ExactEvmClientV1 instance.\n *\n * @param signer - The EVM signer for client operations\n */\n constructor(private readonly signer: ClientEvmSigner) {}\n\n /**\n * Creates a payment payload for the Exact scheme (V1).\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n ): Promise<\n Pick<PaymentPayload, \"x402Version\" | \"payload\"> & { scheme: string; network: Network }\n > {\n const selectedV1 = paymentRequirements as unknown as PaymentRequirementsV1;\n const nonce = createNonce();\n const now = Math.floor(Date.now() / 1000);\n\n const authorization: ExactEvmPayloadV1[\"authorization\"] = {\n from: this.signer.address,\n to: getAddress(selectedV1.payTo),\n value: selectedV1.maxAmountRequired,\n validAfter: (now - 600).toString(), // 10 minutes before\n validBefore: (now + selectedV1.maxTimeoutSeconds).toString(),\n nonce,\n };\n\n // Sign the authorization\n const signature = await this.signAuthorization(authorization, selectedV1);\n\n const payload: ExactEvmPayloadV1 = {\n authorization,\n signature,\n };\n\n return {\n x402Version,\n scheme: selectedV1.scheme,\n network: selectedV1.network,\n payload,\n };\n }\n\n /**\n * Sign the EIP-3009 authorization using EIP-712\n *\n * @param authorization - The authorization to sign\n * @param requirements - The payment requirements\n * @returns Promise resolving to the signature\n */\n private async signAuthorization(\n authorization: ExactEvmPayloadV1[\"authorization\"],\n requirements: PaymentRequirementsV1,\n ): Promise<`0x${string}`> {\n const chainId = getEvmChainIdV1(requirements.network as EvmNetworkV1);\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`,\n );\n }\n\n const { name, version } = requirements.extra;\n\n const domain = {\n name,\n version,\n chainId,\n verifyingContract: getAddress(requirements.asset),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return await this.signer.signTypedData({\n domain,\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\",\n message,\n });\n }\n}\n","// EIP-3009 TransferWithAuthorization types for EIP-712 signing\nexport const authorizationTypes = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\n/**\n * Permit2 EIP-712 types for signing PermitWitnessTransferFrom.\n * Must match the exact format expected by the Permit2 contract.\n * Note: Types must be in ALPHABETICAL order after the primary type (TokenPermissions < Witness).\n */\nexport const permit2WitnessTypes = {\n PermitWitnessTransferFrom: [\n { name: \"permitted\", type: \"TokenPermissions\" },\n { name: \"spender\", type: \"address\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n { name: \"witness\", type: \"Witness\" },\n ],\n TokenPermissions: [\n { name: \"token\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n Witness: [\n { name: \"to\", type: \"address\" },\n { name: \"validAfter\", type: \"uint256\" },\n ],\n} as const;\n\n// EIP3009 ABI for transferWithAuthorization function\nexport const eip3009ABI = [\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"v\", type: \"uint8\" },\n { name: \"r\", type: \"bytes32\" },\n { name: \"s\", type: \"bytes32\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"signature\", type: \"bytes\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [{ name: \"account\", type: \"address\" }],\n name: \"balanceOf\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"version\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/**\n * EIP-2612 Permit EIP-712 types for signing token.permit().\n */\nexport const eip2612PermitTypes = {\n Permit: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * EIP-2612 nonces ABI for querying current nonce.\n */\nexport const eip2612NoncesAbi = [\n {\n type: \"function\",\n name: \"nonces\",\n inputs: [{ name: \"owner\", type: \"address\" }],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** ERC-20 approve(address,uint256) ABI for encoding/decoding approval calldata. */\nexport const erc20ApproveAbi = [\n {\n type: \"function\",\n name: \"approve\",\n inputs: [\n { name: \"spender\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n outputs: [{ type: \"bool\" }],\n stateMutability: \"nonpayable\",\n },\n] as const;\n\n/** ERC-20 allowance(address,address) ABI for checking spender approval. */\nexport const erc20AllowanceAbi = [\n {\n type: \"function\",\n name: \"allowance\",\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n ],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** Gas limit for a standard ERC-20 approve() transaction. */\nexport const ERC20_APPROVE_GAS_LIMIT = 70_000n;\n\n/** Fallback max fee per gas (1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_FEE_PER_GAS = 1_000_000_000n;\n\n/** Fallback max priority fee per gas (0.1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100_000_000n;\n\n/**\n * Canonical Permit2 contract address.\n * Same address on all EVM chains via CREATE2 deployment.\n *\n * @see https://github.com/Uniswap/permit2\n */\nexport const PERMIT2_ADDRESS = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\" as const;\n\n/**\n * x402ExactPermit2Proxy contract address.\n * Vanity address: 0x4020...0001 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0001\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402ExactPermit2ProxyAddress = \"0x402085c248EeA27D92E8b30b2C58ed07f9E20001\" as const;\n\n/**\n * x402UptoPermit2Proxy contract address.\n * Vanity address: 0x4020...0002 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0002\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402UptoPermit2ProxyAddress = \"0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002\" as const;\n\n/**\n * Shared ABI components for the Permit2 witness tuple.\n * Used in both x402ExactPermit2ProxyABI and x402UptoPermit2ProxyABI to keep them in sync.\n * The upto contract's witness struct is identical to exact (both remove 'extra' post-audit).\n */\nconst permit2WitnessABIComponents = [\n { name: \"to\", type: \"address\", internalType: \"address\" },\n { name: \"validAfter\", type: \"uint256\", internalType: \"uint256\" },\n] as const;\n\n/**\n * x402UptoPermit2Proxy ABI - settle function for upto payment scheme (variable amounts).\n * Updated post-audit: 'extra' removed from witness struct, 'initialize()' removed (now\n * a constructor arg), and error names aligned with x402ExactPermit2Proxy.\n */\nexport const x402UptoPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n\n/**\n * x402ExactPermit2Proxy ABI - settle function for exact payment scheme.\n */\nexport const x402ExactPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n","import { toHex } from \"viem\";\n\n/**\n * Extract chain ID from a CAIP-2 network identifier (eip155:CHAIN_ID).\n *\n * @param network - The network identifier in CAIP-2 format (e.g., \"eip155:8453\")\n * @returns The numeric chain ID\n * @throws Error if the network format is invalid\n */\nexport function getEvmChainId(network: string): number {\n if (network.startsWith(\"eip155:\")) {\n const idStr = network.split(\":\")[1];\n const chainId = parseInt(idStr, 10);\n if (isNaN(chainId)) {\n throw new Error(`Invalid CAIP-2 chain ID: ${network}`);\n }\n return chainId;\n }\n\n throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);\n}\n\n/**\n * Get the crypto object from the global scope.\n *\n * @returns The crypto object\n * @throws Error if crypto API is not available\n */\nfunction getCrypto(): Crypto {\n const cryptoObj = globalThis.crypto as Crypto | undefined;\n if (!cryptoObj) {\n throw new Error(\"Crypto API not available\");\n }\n return cryptoObj;\n}\n\n/**\n * Create a random 32-byte nonce for EIP-3009 authorization.\n *\n * @returns A hex-encoded 32-byte nonce\n */\nexport function createNonce(): `0x${string}` {\n return toHex(getCrypto().getRandomValues(new Uint8Array(32)));\n}\n\n/**\n * Creates a random 256-bit nonce for Permit2.\n * Permit2 uses uint256 nonces (not bytes32 like EIP-3009).\n *\n * @returns A string representation of the random nonce\n */\nexport function createPermit2Nonce(): string {\n const randomBytes = getCrypto().getRandomValues(new Uint8Array(32));\n return BigInt(toHex(randomBytes)).toString();\n}\n","import {\n PaymentPayload,\n PaymentPayloadV1,\n PaymentRequirements,\n SchemeNetworkFacilitator,\n SettleResponse,\n VerifyResponse,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress, Hex, isAddressEqual, parseErc6492Signature, parseSignature } from \"viem\";\nimport { authorizationTypes, eip3009ABI } from \"../../../constants\";\nimport { FacilitatorEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\n\nexport interface ExactEvmSchemeV1Config {\n /**\n * If enabled, the facilitator will deploy ERC-4337 smart wallets\n * via EIP-6492 when encountering undeployed contract signatures.\n *\n * @default false\n */\n deployERC4337WithEIP6492?: boolean;\n}\n\n/**\n * EVM facilitator implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkFacilitator {\n readonly scheme = \"exact\";\n readonly caipFamily = \"eip155:*\";\n private readonly config: Required<ExactEvmSchemeV1Config>;\n\n /**\n * Creates a new ExactEvmFacilitatorV1 instance.\n *\n * @param signer - The EVM signer for facilitator operations\n * @param config - Optional configuration for the facilitator\n */\n constructor(\n private readonly signer: FacilitatorEvmSigner,\n config?: ExactEvmSchemeV1Config,\n ) {\n this.config = {\n deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,\n };\n }\n\n /**\n * Get mechanism-specific extra data for the supported kinds endpoint.\n * For EVM, no extra data is needed.\n *\n * @param _ - The network identifier (unused for EVM)\n * @returns undefined (EVM has no extra data)\n */\n getExtra(_: string): Record<string, unknown> | undefined {\n return undefined;\n }\n\n /**\n * Get signer addresses used by this facilitator.\n * Returns all addresses this facilitator can use for signing/settling transactions.\n *\n * @param _ - The network identifier (unused for EVM, addresses are network-agnostic)\n * @returns Array of facilitator wallet addresses\n */\n getSigners(_: string): string[] {\n return [...this.signer.getAddresses()];\n }\n\n /**\n * Verifies a payment payload (V1).\n *\n * @param payload - The payment payload to verify\n * @param requirements - The payment requirements\n * @returns Promise resolving to verification response\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n const requirementsV1 = requirements as unknown as PaymentRequirementsV1;\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n\n // Verify scheme matches\n if (payloadV1.scheme !== \"exact\" || requirements.scheme !== \"exact\") {\n return {\n isValid: false,\n invalidReason: \"unsupported_scheme\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Get chain configuration\n let chainId: number;\n try {\n chainId = getEvmChainIdV1(payloadV1.network as EvmNetworkV1);\n } catch {\n return {\n isValid: false,\n invalidReason: `invalid_network`,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n return {\n isValid: false,\n invalidReason: \"missing_eip712_domain\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n const { name, version } = requirements.extra;\n const erc20Address = getAddress(requirements.asset);\n\n // Verify network matches\n if (payloadV1.network !== requirements.network) {\n return {\n isValid: false,\n invalidReason: \"network_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Build typed data for signature verification\n const permitTypedData = {\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\" as const,\n domain: {\n name,\n version,\n chainId,\n verifyingContract: erc20Address,\n },\n message: {\n from: exactEvmPayload.authorization.from,\n to: exactEvmPayload.authorization.to,\n value: BigInt(exactEvmPayload.authorization.value),\n validAfter: BigInt(exactEvmPayload.authorization.validAfter),\n validBefore: BigInt(exactEvmPayload.authorization.validBefore),\n nonce: exactEvmPayload.authorization.nonce,\n },\n };\n\n // Verify signature\n try {\n const recoveredAddress = await this.signer.verifyTypedData({\n address: exactEvmPayload.authorization.from,\n ...permitTypedData,\n signature: exactEvmPayload.signature!,\n });\n\n if (!recoveredAddress) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n } catch {\n // Signature verification failed - could be an undeployed smart wallet\n // Check if smart wallet is deployed\n const signature = exactEvmPayload.signature!;\n const signatureLength = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n const isSmartWallet = signatureLength > 130; // 65 bytes = 130 hex chars for EOA\n\n if (isSmartWallet) {\n const payerAddress = exactEvmPayload.authorization.from;\n const bytecode = await this.signer.getCode({ address: payerAddress });\n\n if (!bytecode || bytecode === \"0x\") {\n // Wallet is not deployed. Check if it's EIP-6492 with deployment info.\n // EIP-6492 signatures contain factory address and calldata needed for deployment.\n // Non-EIP-6492 undeployed wallets cannot succeed (no way to deploy them).\n const erc6492Data = parseErc6492Signature(signature);\n const hasDeploymentInfo =\n erc6492Data.address &&\n erc6492Data.data &&\n !isAddressEqual(erc6492Data.address, \"0x0000000000000000000000000000000000000000\");\n\n if (!hasDeploymentInfo) {\n // Non-EIP-6492 undeployed smart wallet - will always fail at settlement\n // since EIP-3009 requires on-chain EIP-1271 validation\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_undeployed_smart_wallet\",\n payer: payerAddress,\n };\n }\n // EIP-6492 signature with deployment info - allow through\n // Facilitators with sponsored deployment support can handle this in settle()\n } else {\n // Wallet is deployed but signature still failed - invalid signature\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n } else {\n // EOA signature failed\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n }\n\n // Verify payment recipient matches\n if (getAddress(exactEvmPayload.authorization.to) !== getAddress(requirements.payTo)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_recipient_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Verify validBefore is in the future (with 6 second buffer for block time)\n const now = Math.floor(Date.now() / 1000);\n if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_valid_before\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Verify validAfter is not in the future\n if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_valid_after\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Check balance\n try {\n const balance = (await this.signer.readContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"balanceOf\",\n args: [exactEvmPayload.authorization.from],\n })) as bigint;\n\n if (BigInt(balance) < BigInt(requirementsV1.maxAmountRequired)) {\n return {\n isValid: false,\n invalidReason: \"insufficient_funds\",\n invalidMessage: `Insufficient funds to complete the payment. Required: ${requirementsV1.maxAmountRequired} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,\n payer: exactEvmPayload.authorization.from,\n };\n }\n } catch {\n // If we can't check balance, continue with other validations\n }\n\n // Verify amount exactly matches requirements\n if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_value_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n return {\n isValid: true,\n invalidReason: undefined,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n /**\n * Settles a payment by executing the transfer (V1).\n *\n * @param payload - The payment payload to settle\n * @param requirements - The payment requirements\n * @returns Promise resolving to settlement response\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n\n // Re-verify before settling\n const valid = await this.verify(payload, requirements);\n if (!valid.isValid) {\n return {\n success: false,\n network: payloadV1.network,\n transaction: \"\",\n errorReason: valid.invalidReason ?? \"invalid_scheme\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n try {\n // Parse ERC-6492 signature if applicable\n const parseResult = parseErc6492Signature(exactEvmPayload.signature!);\n const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;\n\n // Deploy ERC-4337 smart wallet via EIP-6492 if configured and needed\n if (\n this.config.deployERC4337WithEIP6492 &&\n factoryAddress &&\n factoryCalldata &&\n !isAddressEqual(factoryAddress, \"0x0000000000000000000000000000000000000000\")\n ) {\n // Check if smart wallet is already deployed\n const payerAddress = exactEvmPayload.authorization.from;\n const bytecode = await this.signer.getCode({ address: payerAddress });\n\n if (!bytecode || bytecode === \"0x\") {\n // Wallet not deployed - attempt deployment\n try {\n console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);\n\n // Send the factory calldata directly as a transaction\n // The factoryCalldata already contains the complete encoded function call\n const deployTx = await this.signer.sendTransaction({\n to: factoryAddress as Hex,\n data: factoryCalldata as Hex,\n });\n\n // Wait for deployment transaction\n await this.signer.waitForTransactionReceipt({ hash: deployTx });\n console.log(`Successfully deployed smart wallet for ${payerAddress}`);\n } catch (deployError) {\n console.error(\"Smart wallet deployment failed:\", deployError);\n // Deployment failed - cannot proceed\n throw deployError;\n }\n } else {\n console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);\n }\n }\n\n // Determine if this is an ECDSA signature (EOA) or smart wallet signature\n // ECDSA signatures are exactly 65 bytes (130 hex chars without 0x)\n const signatureLength = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n const isECDSA = signatureLength === 130;\n\n let tx: Hex;\n if (isECDSA) {\n // For EOA wallets, parse signature into v, r, s and use that overload\n const parsedSig = parseSignature(signature);\n\n tx = await this.signer.writeContract({\n address: getAddress(requirements.asset),\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n getAddress(exactEvmPayload.authorization.from),\n getAddress(exactEvmPayload.authorization.to),\n BigInt(exactEvmPayload.authorization.value),\n BigInt(exactEvmPayload.authorization.validAfter),\n BigInt(exactEvmPayload.authorization.validBefore),\n exactEvmPayload.authorization.nonce,\n (parsedSig.v as number | undefined) || parsedSig.yParity,\n parsedSig.r,\n parsedSig.s,\n ],\n });\n } else {\n // For smart wallets, use the bytes signature overload\n // The signature contains WebAuthn/P256 or other ERC-1271 compatible signature data\n tx = await this.signer.writeContract({\n address: getAddress(requirements.asset),\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n getAddress(exactEvmPayload.authorization.from),\n getAddress(exactEvmPayload.authorization.to),\n BigInt(exactEvmPayload.authorization.value),\n BigInt(exactEvmPayload.authorization.validAfter),\n BigInt(exactEvmPayload.authorization.validBefore),\n exactEvmPayload.authorization.nonce,\n signature,\n ],\n });\n }\n\n // Wait for transaction confirmation\n const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });\n\n if (receipt.status !== \"success\") {\n return {\n success: false,\n errorReason: \"invalid_transaction_state\",\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n return {\n success: true,\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n } catch (error) {\n console.error(\"Failed to settle transaction:\", error);\n return {\n success: false,\n errorReason: \"transaction_failed\",\n transaction: \"\",\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n }\n}\n","export { ExactEvmSchemeV1 } from \"../exact/v1\";\n\nexport const EVM_NETWORK_CHAIN_ID_MAP = {\n ethereum: 1,\n sepolia: 11155111,\n abstract: 2741,\n \"abstract-testnet\": 11124,\n \"base-sepolia\": 84532,\n base: 8453,\n \"avalanche-fuji\": 43113,\n avalanche: 43114,\n iotex: 4689,\n sei: 1329,\n \"sei-testnet\": 1328,\n polygon: 137,\n \"polygon-amoy\": 80002,\n peaq: 3338,\n story: 1514,\n educhain: 41923,\n \"skale-base-sepolia\": 324705682,\n megaeth: 4326,\n monad: 143,\n} as const;\n\nexport type EvmNetworkV1 = keyof typeof EVM_NETWORK_CHAIN_ID_MAP;\n\nexport const NETWORKS: string[] = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);\n\n/**\n * Extract chain ID from a v1 legacy network name.\n *\n * @param network - The v1 network name (e.g., \"base-sepolia\", \"polygon\")\n * @returns The numeric chain ID\n * @throws Error if the network name is not a known v1 network\n */\nexport function getEvmChainIdV1(network: string): number {\n const chainId = EVM_NETWORK_CHAIN_ID_MAP[network as EvmNetworkV1];\n if (!chainId) {\n throw new Error(`Unsupported v1 network: ${network}`);\n }\n return chainId;\n}\n"],"mappings":"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","names":["import_viem","import_viem"]}
{"version":3,"sources":["../../../../../src/exact/v1/client/index.ts","../../../../../src/exact/v1/client/scheme.ts","../../../../../src/constants.ts","../../../../../src/utils.ts","../../../../../src/exact/v1/facilitator/scheme.ts","../../../../../src/exact/facilitator/eip3009-utils.ts","../../../../../src/multicall.ts","../../../../../src/v1/index.ts"],"sourcesContent":["export { ExactEvmSchemeV1 } from \"./scheme\";\n","import {\n Network,\n PaymentPayload,\n PaymentRequirements,\n SchemeNetworkClient,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress } from \"viem\";\nimport { authorizationTypes } from \"../../../constants\";\nimport { ClientEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { createNonce } from \"../../../utils\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\n\n/**\n * EVM client implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkClient {\n readonly scheme = \"exact\";\n\n /**\n * Creates a new ExactEvmClientV1 instance.\n *\n * @param signer - The EVM signer for client operations\n */\n constructor(private readonly signer: ClientEvmSigner) {}\n\n /**\n * Creates a payment payload for the Exact scheme (V1).\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n ): Promise<\n Pick<PaymentPayload, \"x402Version\" | \"payload\"> & { scheme: string; network: Network }\n > {\n const selectedV1 = paymentRequirements as unknown as PaymentRequirementsV1;\n const nonce = createNonce();\n const now = Math.floor(Date.now() / 1000);\n\n const authorization: ExactEvmPayloadV1[\"authorization\"] = {\n from: this.signer.address,\n to: getAddress(selectedV1.payTo),\n value: selectedV1.maxAmountRequired,\n validAfter: (now - 600).toString(), // 10 minutes before\n validBefore: (now + selectedV1.maxTimeoutSeconds).toString(),\n nonce,\n };\n\n // Sign the authorization\n const signature = await this.signAuthorization(authorization, selectedV1);\n\n const payload: ExactEvmPayloadV1 = {\n authorization,\n signature,\n };\n\n return {\n x402Version,\n scheme: selectedV1.scheme,\n network: selectedV1.network,\n payload,\n };\n }\n\n /**\n * Sign the EIP-3009 authorization using EIP-712\n *\n * @param authorization - The authorization to sign\n * @param requirements - The payment requirements\n * @returns Promise resolving to the signature\n */\n private async signAuthorization(\n authorization: ExactEvmPayloadV1[\"authorization\"],\n requirements: PaymentRequirementsV1,\n ): Promise<`0x${string}`> {\n const chainId = getEvmChainIdV1(requirements.network as EvmNetworkV1);\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`,\n );\n }\n\n const { name, version } = requirements.extra;\n\n const domain = {\n name,\n version,\n chainId,\n verifyingContract: getAddress(requirements.asset),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return await this.signer.signTypedData({\n domain,\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\",\n message,\n });\n }\n}\n","// EIP-3009 TransferWithAuthorization types for EIP-712 signing\nexport const authorizationTypes = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\n/**\n * Permit2 EIP-712 types for signing PermitWitnessTransferFrom.\n * Must match the exact format expected by the Permit2 contract.\n * Note: Types must be in ALPHABETICAL order after the primary type (TokenPermissions < Witness).\n */\nexport const permit2WitnessTypes = {\n PermitWitnessTransferFrom: [\n { name: \"permitted\", type: \"TokenPermissions\" },\n { name: \"spender\", type: \"address\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n { name: \"witness\", type: \"Witness\" },\n ],\n TokenPermissions: [\n { name: \"token\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n Witness: [\n { name: \"to\", type: \"address\" },\n { name: \"validAfter\", type: \"uint256\" },\n ],\n} as const;\n\n// EIP3009 ABI for transferWithAuthorization function\nexport const eip3009ABI = [\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"v\", type: \"uint8\" },\n { name: \"r\", type: \"bytes32\" },\n { name: \"s\", type: \"bytes32\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"signature\", type: \"bytes\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [{ name: \"account\", type: \"address\" }],\n name: \"balanceOf\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"version\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"name\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"authorizer\", type: \"address\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n name: \"authorizationState\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/**\n * EIP-2612 Permit EIP-712 types for signing token.permit().\n */\nexport const eip2612PermitTypes = {\n Permit: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * EIP-2612 nonces ABI for querying current nonce.\n */\nexport const eip2612NoncesAbi = [\n {\n type: \"function\",\n name: \"nonces\",\n inputs: [{ name: \"owner\", type: \"address\" }],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** ERC-20 approve(address,uint256) ABI for encoding/decoding approval calldata. */\nexport const erc20ApproveAbi = [\n {\n type: \"function\",\n name: \"approve\",\n inputs: [\n { name: \"spender\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n outputs: [{ type: \"bool\" }],\n stateMutability: \"nonpayable\",\n },\n] as const;\n\n/** ERC-20 allowance(address,address) ABI for checking spender approval. */\nexport const erc20AllowanceAbi = [\n {\n type: \"function\",\n name: \"allowance\",\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n ],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** Gas limit for a standard ERC-20 approve() transaction. */\nexport const ERC20_APPROVE_GAS_LIMIT = 70_000n;\n\n/** Fallback max fee per gas (1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_FEE_PER_GAS = 1_000_000_000n;\n\n/** Fallback max priority fee per gas (0.1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100_000_000n;\n\n/**\n * Canonical Permit2 contract address.\n * Same address on all EVM chains via CREATE2 deployment.\n *\n * @see https://github.com/Uniswap/permit2\n */\nexport const PERMIT2_ADDRESS = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\" as const;\n\n/**\n * x402ExactPermit2Proxy contract address.\n * Vanity address: 0x4020...0001 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0001\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402ExactPermit2ProxyAddress = \"0x402085c248EeA27D92E8b30b2C58ed07f9E20001\" as const;\n\n/**\n * x402UptoPermit2Proxy contract address.\n * Vanity address: 0x4020...0002 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0002\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402UptoPermit2ProxyAddress = \"0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002\" as const;\n\n/**\n * Shared ABI components for the Permit2 witness tuple.\n * Used in both x402ExactPermit2ProxyABI and x402UptoPermit2ProxyABI to keep them in sync.\n * The upto contract's witness struct is identical to exact (both remove 'extra' post-audit).\n */\nconst permit2WitnessABIComponents = [\n { name: \"to\", type: \"address\", internalType: \"address\" },\n { name: \"validAfter\", type: \"uint256\", internalType: \"uint256\" },\n] as const;\n\n/**\n * x402UptoPermit2Proxy ABI - settle function for upto payment scheme (variable amounts).\n * Updated post-audit: 'extra' removed from witness struct, 'initialize()' removed (now\n * a constructor arg), and error names aligned with x402ExactPermit2Proxy.\n */\nexport const x402UptoPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n\n/**\n * x402ExactPermit2Proxy ABI - settle function for exact payment scheme.\n */\nexport const x402ExactPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n","import { toHex } from \"viem\";\n\n/**\n * Extract chain ID from a CAIP-2 network identifier (eip155:CHAIN_ID).\n *\n * @param network - The network identifier in CAIP-2 format (e.g., \"eip155:8453\")\n * @returns The numeric chain ID\n * @throws Error if the network format is invalid\n */\nexport function getEvmChainId(network: string): number {\n if (network.startsWith(\"eip155:\")) {\n const idStr = network.split(\":\")[1];\n const chainId = parseInt(idStr, 10);\n if (isNaN(chainId)) {\n throw new Error(`Invalid CAIP-2 chain ID: ${network}`);\n }\n return chainId;\n }\n\n throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);\n}\n\n/**\n * Get the crypto object from the global scope.\n *\n * @returns The crypto object\n * @throws Error if crypto API is not available\n */\nfunction getCrypto(): Crypto {\n const cryptoObj = globalThis.crypto as Crypto | undefined;\n if (!cryptoObj) {\n throw new Error(\"Crypto API not available\");\n }\n return cryptoObj;\n}\n\n/**\n * Create a random 32-byte nonce for EIP-3009 authorization.\n *\n * @returns A hex-encoded 32-byte nonce\n */\nexport function createNonce(): `0x${string}` {\n return toHex(getCrypto().getRandomValues(new Uint8Array(32)));\n}\n\n/**\n * Creates a random 256-bit nonce for Permit2.\n * Permit2 uses uint256 nonces (not bytes32 like EIP-3009).\n *\n * @returns A string representation of the random nonce\n */\nexport function createPermit2Nonce(): string {\n const randomBytes = getCrypto().getRandomValues(new Uint8Array(32));\n return BigInt(toHex(randomBytes)).toString();\n}\n","import {\n PaymentPayload,\n PaymentPayloadV1,\n PaymentRequirements,\n SchemeNetworkFacilitator,\n SettleResponse,\n VerifyResponse,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress, Hex, isAddressEqual, parseErc6492Signature } from \"viem\";\nimport { authorizationTypes } from \"../../../constants\";\nimport { FacilitatorEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\nimport * as Errors from \"../../facilitator/errors\";\nimport {\n diagnoseEip3009SimulationFailure,\n executeTransferWithAuthorization,\n simulateEip3009Transfer,\n} from \"../../facilitator/eip3009-utils\";\n\nexport interface VerifyV1Options {\n /** Run onchain simulation. Defaults to true. */\n simulate?: boolean;\n}\n\nexport interface ExactEvmSchemeV1Config {\n /**\n * If enabled, the facilitator will deploy ERC-4337 smart wallets\n * via EIP-6492 when encountering undeployed contract signatures.\n *\n * @default false\n */\n deployERC4337WithEIP6492?: boolean;\n /**\n * If enabled, simulates transaction before settling. Defaults to false, ie only simulate during verify.\n *\n * @default false\n */\n simulateInSettle?: boolean;\n}\n\n/**\n * EVM facilitator implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkFacilitator {\n readonly scheme = \"exact\";\n readonly caipFamily = \"eip155:*\";\n private readonly config: Required<ExactEvmSchemeV1Config>;\n\n /**\n * Creates a new ExactEvmFacilitatorV1 instance.\n *\n * @param signer - The EVM signer for facilitator operations\n * @param config - Optional configuration for the facilitator\n */\n constructor(\n private readonly signer: FacilitatorEvmSigner,\n config?: ExactEvmSchemeV1Config,\n ) {\n this.config = {\n deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,\n simulateInSettle: config?.simulateInSettle ?? false,\n };\n }\n\n /**\n * Get mechanism-specific extra data for the supported kinds endpoint.\n * For EVM, no extra data is needed.\n *\n * @param _ - The network identifier (unused for EVM)\n * @returns undefined (EVM has no extra data)\n */\n getExtra(_: string): Record<string, unknown> | undefined {\n return undefined;\n }\n\n /**\n * Get signer addresses used by this facilitator.\n * Returns all addresses this facilitator can use for signing/settling transactions.\n *\n * @param _ - The network identifier (unused for EVM, addresses are network-agnostic)\n * @returns Array of facilitator wallet addresses\n */\n getSigners(_: string): string[] {\n return [...this.signer.getAddresses()];\n }\n\n /**\n * Verifies a payment payload (V1).\n *\n * @param payload - The payment payload to verify\n * @param requirements - The payment requirements\n * @returns Promise resolving to verification response\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n return this._verify(payload, requirements);\n }\n\n /**\n * Settles a payment by executing the transfer (V1).\n *\n * @param payload - The payment payload to settle\n * @param requirements - The payment requirements\n * @returns Promise resolving to settlement response\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n\n // Re-verify before settling\n const valid = await this._verify(payload, requirements, {\n simulate: this.config.simulateInSettle ?? false,\n });\n if (!valid.isValid) {\n return {\n success: false,\n network: payloadV1.network,\n transaction: \"\",\n errorReason: valid.invalidReason ?? Errors.ErrInvalidScheme,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n try {\n // Parse ERC-6492 signature if applicable (for optional deployment)\n const { address: factoryAddress, data: factoryCalldata } = parseErc6492Signature(\n exactEvmPayload.signature!,\n );\n\n // Deploy ERC-4337 smart wallet via EIP-6492 if configured and needed\n if (\n this.config.deployERC4337WithEIP6492 &&\n factoryAddress &&\n factoryCalldata &&\n !isAddressEqual(factoryAddress, \"0x0000000000000000000000000000000000000000\")\n ) {\n // Check if smart wallet is already deployed\n const payerAddress = exactEvmPayload.authorization.from;\n const bytecode = await this.signer.getCode({ address: payerAddress });\n\n if (!bytecode || bytecode === \"0x\") {\n // Send the factory calldata directly as a transaction\n // The factoryCalldata already contains the complete encoded function call\n const deployTx = await this.signer.sendTransaction({\n to: factoryAddress as Hex,\n data: factoryCalldata as Hex,\n });\n\n // Wait for deployment transaction\n await this.signer.waitForTransactionReceipt({ hash: deployTx });\n }\n }\n\n const tx = await executeTransferWithAuthorization(\n this.signer,\n getAddress(requirements.asset),\n exactEvmPayload,\n );\n\n // Wait for transaction confirmation\n const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });\n\n if (receipt.status !== \"success\") {\n return {\n success: false,\n errorReason: Errors.ErrTransactionFailed,\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n return {\n success: true,\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n } catch (error) {\n return {\n success: false,\n errorReason: error instanceof Error ? error.message : Errors.ErrTransactionFailed,\n transaction: \"\",\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n }\n\n /**\n * Internal verify with optional simulation control.\n *\n * @param payload - The payment payload to verify\n * @param requirements - The payment requirements\n * @param options - Verification options (e.g. simulate)\n * @returns Promise resolving to verification response\n */\n private async _verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n options?: VerifyV1Options,\n ): Promise<VerifyResponse> {\n const requirementsV1 = requirements as unknown as PaymentRequirementsV1;\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n const payer = exactEvmPayload.authorization.from;\n let eip6492Deployment:\n | { factoryAddress: `0x${string}`; factoryCalldata: `0x${string}` }\n | undefined;\n\n // Verify scheme matches\n if (payloadV1.scheme !== \"exact\" || requirements.scheme !== \"exact\") {\n return {\n isValid: false,\n invalidReason: Errors.ErrInvalidScheme,\n payer,\n };\n }\n\n // Get chain configuration\n let chainId: number;\n try {\n chainId = getEvmChainIdV1(payloadV1.network as EvmNetworkV1);\n } catch {\n return {\n isValid: false,\n invalidReason: Errors.ErrNetworkMismatch,\n payer,\n };\n }\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n return {\n isValid: false,\n invalidReason: Errors.ErrMissingEip712Domain,\n payer,\n };\n }\n\n const { name, version } = requirements.extra;\n const erc20Address = getAddress(requirements.asset);\n\n // Verify network matches\n if (payloadV1.network !== requirements.network) {\n return {\n isValid: false,\n invalidReason: Errors.ErrNetworkMismatch,\n payer,\n };\n }\n\n // Build typed data for signature verification\n const permitTypedData = {\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\" as const,\n domain: {\n name,\n version,\n chainId,\n verifyingContract: erc20Address,\n },\n message: {\n from: exactEvmPayload.authorization.from,\n to: exactEvmPayload.authorization.to,\n value: BigInt(exactEvmPayload.authorization.value),\n validAfter: BigInt(exactEvmPayload.authorization.validAfter),\n validBefore: BigInt(exactEvmPayload.authorization.validBefore),\n nonce: exactEvmPayload.authorization.nonce,\n },\n };\n\n // Verify signature (flatten EIP-6492 handling out of catch block)\n let isValid = false;\n try {\n isValid = await this.signer.verifyTypedData({\n address: payer,\n ...permitTypedData,\n signature: exactEvmPayload.signature!,\n });\n } catch {\n isValid = false;\n }\n\n const signature = exactEvmPayload.signature!;\n const sigLen = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n\n // Extract EIP-6492 deployment info (factory address + calldata) if present\n const erc6492Data = parseErc6492Signature(signature);\n const hasDeploymentInfo =\n erc6492Data.address &&\n erc6492Data.data &&\n !isAddressEqual(erc6492Data.address, \"0x0000000000000000000000000000000000000000\");\n\n if (hasDeploymentInfo) {\n eip6492Deployment = {\n factoryAddress: erc6492Data.address!,\n factoryCalldata: erc6492Data.data!,\n };\n }\n\n if (!isValid) {\n const isSmartWallet = sigLen > 130; // 65 bytes = 130 hex chars for EOA\n\n if (!isSmartWallet) {\n return {\n isValid: false,\n invalidReason: Errors.ErrInvalidSignature,\n payer,\n };\n }\n\n const bytecode = await this.signer.getCode({ address: payer });\n const isDeployed = bytecode && bytecode !== \"0x\";\n\n if (!isDeployed && !hasDeploymentInfo) {\n return {\n isValid: false,\n invalidReason: Errors.ErrUndeployedSmartWallet,\n payer,\n };\n }\n }\n\n // Verify payment recipient matches\n if (getAddress(exactEvmPayload.authorization.to) !== getAddress(requirements.payTo)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrRecipientMismatch,\n payer,\n };\n }\n\n // Verify validBefore is in the future (with 6 second buffer for block time)\n const now = Math.floor(Date.now() / 1000);\n if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrValidBeforeExpired,\n payer,\n };\n }\n\n // Verify validAfter is not in the future\n if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrValidAfterInFuture,\n payer,\n };\n }\n\n // Verify amount exactly matches requirements\n if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrInvalidAuthorizationValue,\n payer,\n };\n }\n\n // Transaction simulation\n if (options?.simulate !== false) {\n const simulationSucceeded = await simulateEip3009Transfer(\n this.signer,\n erc20Address,\n exactEvmPayload,\n eip6492Deployment,\n );\n if (!simulationSucceeded) {\n return diagnoseEip3009SimulationFailure(\n this.signer,\n erc20Address,\n exactEvmPayload,\n requirements,\n requirementsV1.maxAmountRequired,\n );\n }\n }\n\n return {\n isValid: true,\n invalidReason: undefined,\n payer,\n };\n }\n}\n","import { PaymentRequirements, VerifyResponse } from \"@x402/core/types\";\nimport { encodeFunctionData, getAddress, Hex, parseErc6492Signature, parseSignature } from \"viem\";\nimport { eip3009ABI } from \"../../constants\";\nimport { multicall, ContractCall, RawContractCall } from \"../../multicall\";\nimport { FacilitatorEvmSigner } from \"../../signer\";\nimport { ExactEIP3009Payload } from \"../../types\";\nimport * as Errors from \"./errors\";\n\nexport interface Eip6492Deployment {\n factoryAddress: `0x${string}`;\n factoryCalldata: `0x${string}`;\n}\n\n/**\n * Simulates transferWithAuthorization via eth_call.\n * Returns true if simulation succeeded, false if it failed.\n *\n * @param signer - EVM signer for contract reads\n * @param erc20Address - ERC-20 token contract address\n * @param payload - EIP-3009 transfer authorization payload\n * @param eip6492Deployment - Optional EIP-6492 factory info for undeployed smart wallets\n *\n * @returns true if simulation succeeded, false if it failed\n */\nexport async function simulateEip3009Transfer(\n signer: FacilitatorEvmSigner,\n erc20Address: `0x${string}`,\n payload: ExactEIP3009Payload,\n eip6492Deployment?: Eip6492Deployment,\n): Promise<boolean> {\n const auth = payload.authorization;\n const transferArgs = [\n getAddress(auth.from),\n getAddress(auth.to),\n BigInt(auth.value),\n BigInt(auth.validAfter),\n BigInt(auth.validBefore),\n auth.nonce,\n ] as const;\n\n if (eip6492Deployment) {\n const { signature: innerSignature } = parseErc6492Signature(payload.signature!);\n const transferCalldata = encodeFunctionData({\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [...transferArgs, innerSignature],\n });\n\n try {\n const results = await multicall(signer.readContract.bind(signer), [\n {\n address: getAddress(eip6492Deployment.factoryAddress),\n callData: eip6492Deployment.factoryCalldata,\n } satisfies RawContractCall,\n {\n address: erc20Address,\n callData: transferCalldata,\n } satisfies RawContractCall,\n ]);\n\n return results[1]?.status === \"success\";\n } catch {\n return false;\n }\n }\n\n const sig = payload.signature!;\n const sigLength = sig.startsWith(\"0x\") ? sig.length - 2 : sig.length;\n const isECDSA = sigLength === 130;\n\n try {\n if (isECDSA) {\n const parsedSig = parseSignature(sig);\n await signer.readContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n ...transferArgs,\n (parsedSig.v as number | undefined) ?? parsedSig.yParity,\n parsedSig.r,\n parsedSig.s,\n ],\n });\n } else {\n await signer.readContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [...transferArgs, sig],\n });\n }\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * After simulation fails, runs a single diagnostic multicall to determine the most specific error reason.\n * Checks balanceOf, name, version and authorizationState in one RPC round-trip.\n *\n * @param signer - EVM signer used for the payment\n * @param erc20Address - Address of the ERC-20 token contract\n * @param payload - The EIP-3009 transfer authorization payload\n * @param requirements - Payment requirements to validate against\n * @param amountRequired - Required amount for the payment (balance check)\n *\n * @returns Promise resolving to the verification result with validity and optional invalid reason\n */\nexport async function diagnoseEip3009SimulationFailure(\n signer: FacilitatorEvmSigner,\n erc20Address: `0x${string}`,\n payload: ExactEIP3009Payload,\n requirements: PaymentRequirements,\n amountRequired: string,\n): Promise<VerifyResponse> {\n const payer = payload.authorization.from;\n\n const diagnosticCalls: ContractCall[] = [\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"balanceOf\",\n args: [payload.authorization.from],\n },\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"name\",\n },\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"version\",\n },\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"authorizationState\",\n args: [payload.authorization.from, payload.authorization.nonce],\n },\n ];\n\n try {\n const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);\n\n const [balanceResult, nameResult, versionResult, authStateResult] = results;\n\n if (authStateResult.status === \"failure\") {\n return { isValid: false, invalidReason: Errors.ErrEip3009NotSupported, payer };\n }\n\n if (authStateResult.status === \"success\" && authStateResult.result === true) {\n return { isValid: false, invalidReason: Errors.ErrEip3009NonceAlreadyUsed, payer };\n }\n\n if (\n nameResult.status === \"success\" &&\n requirements.extra?.name &&\n nameResult.result !== requirements.extra.name\n ) {\n return { isValid: false, invalidReason: Errors.ErrEip3009TokenNameMismatch, payer };\n }\n\n if (\n versionResult.status === \"success\" &&\n requirements.extra?.version &&\n versionResult.result !== requirements.extra.version\n ) {\n return { isValid: false, invalidReason: Errors.ErrEip3009TokenVersionMismatch, payer };\n }\n\n if (balanceResult.status === \"success\") {\n const balance = balanceResult.result as bigint;\n if (balance < BigInt(amountRequired)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrEip3009InsufficientBalance,\n payer,\n };\n }\n }\n } catch {\n // Diagnostic multicall failed — fall through to generic error\n }\n\n return { isValid: false, invalidReason: Errors.ErrEip3009SimulationFailed, payer };\n}\n\n/**\n * Executes transferWithAuthorization onchain.\n *\n * @param signer - EVM signer for contract writes\n * @param erc20Address - ERC-20 token contract address\n * @param payload - EIP-3009 transfer authorization payload\n *\n * @returns Transaction hash\n */\nexport async function executeTransferWithAuthorization(\n signer: FacilitatorEvmSigner,\n erc20Address: `0x${string}`,\n payload: ExactEIP3009Payload,\n): Promise<Hex> {\n const { signature } = parseErc6492Signature(payload.signature!);\n const signatureLength = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n const isECDSA = signatureLength === 130;\n\n const auth = payload.authorization;\n const baseArgs = [\n getAddress(auth.from),\n getAddress(auth.to),\n BigInt(auth.value),\n BigInt(auth.validAfter),\n BigInt(auth.validBefore),\n auth.nonce,\n ] as const;\n\n if (isECDSA) {\n const parsedSig = parseSignature(signature);\n return signer.writeContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n ...baseArgs,\n (parsedSig.v as number | undefined) || parsedSig.yParity,\n parsedSig.r,\n parsedSig.s,\n ],\n });\n }\n\n return signer.writeContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [...baseArgs, signature],\n });\n}\n","import { encodeFunctionData, decodeFunctionResult } from \"viem\";\n\n/**\n * Multicall3 contract address.\n * Same address on all EVM chains via CREATE2 deployment.\n *\n * @see https://github.com/mds1/multicall\n */\nexport const MULTICALL3_ADDRESS = \"0xcA11bde05977b3631167028862bE2a173976CA11\" as const;\n\n/** Multicall3 getEthBalance ABI for querying native token balance. */\nexport const multicall3GetEthBalanceAbi = [\n {\n name: \"getEthBalance\",\n inputs: [{ name: \"addr\", type: \"address\" }],\n outputs: [{ name: \"balance\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/** Multicall3 tryAggregate ABI for batching calls. */\nconst multicall3ABI = [\n {\n inputs: [\n { name: \"requireSuccess\", type: \"bool\" },\n {\n name: \"calls\",\n type: \"tuple[]\",\n components: [\n { name: \"target\", type: \"address\" },\n { name: \"callData\", type: \"bytes\" },\n ],\n },\n ],\n name: \"tryAggregate\",\n outputs: [\n {\n name: \"returnData\",\n type: \"tuple[]\",\n components: [\n { name: \"success\", type: \"bool\" },\n { name: \"returnData\", type: \"bytes\" },\n ],\n },\n ],\n stateMutability: \"payable\",\n type: \"function\",\n },\n] as const;\n\nexport type ContractCall = {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n};\n\nexport type RawContractCall = {\n address: `0x${string}`;\n callData: `0x${string}`;\n};\n\nexport type MulticallSuccess = { status: \"success\"; result: unknown };\nexport type MulticallFailure = { status: \"failure\"; error: Error };\nexport type MulticallResult = MulticallSuccess | MulticallFailure;\n\n/**\n * Batches contract calls via Multicall3 `tryAggregate(false, ...)`.\n *\n * Accepts a mix of typed ContractCall (ABI-encoded + decoded) and\n * RawContractCall (pre-encoded calldata, no decoding) entries.\n * Raw calls are useful for the EIP-6492 factory deployment case\n * where calldata is pre-encoded with no ABI available.\n */\ntype ReadContractFn = (args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n}) => Promise<unknown>;\n\n/**\n * Executes multiple contract read calls in a single RPC round-trip using Multicall3.\n *\n * @param readContract - Function that performs a single contract read (e.g. viem readContract)\n * @param calls - Array of contract calls to batch (ContractCall or RawContractCall)\n * @returns A promise that resolves to an array of decoded results, one per call\n */\nexport async function multicall(\n readContract: ReadContractFn,\n calls: ReadonlyArray<ContractCall | RawContractCall>,\n): Promise<MulticallResult[]> {\n const aggregateCalls = calls.map(call => {\n if (\"callData\" in call) {\n return { target: call.address, callData: call.callData };\n }\n const callData = encodeFunctionData({\n abi: call.abi,\n functionName: call.functionName,\n args: call.args as unknown[],\n });\n return { target: call.address, callData };\n });\n\n const rawResults = (await readContract({\n address: MULTICALL3_ADDRESS,\n abi: multicall3ABI,\n functionName: \"tryAggregate\",\n args: [false, aggregateCalls],\n })) as { success: boolean; returnData: `0x${string}` }[];\n\n return rawResults.map((raw, i) => {\n if (!raw.success) {\n return {\n status: \"failure\" as const,\n error: new Error(`multicall: call reverted (returnData: ${raw.returnData})`),\n };\n }\n\n const call = calls[i];\n if (\"callData\" in call) {\n return { status: \"success\" as const, result: undefined };\n }\n\n try {\n const decoded = decodeFunctionResult({\n abi: call.abi,\n functionName: call.functionName,\n data: raw.returnData,\n });\n return { status: \"success\" as const, result: decoded };\n } catch (err) {\n return {\n status: \"failure\" as const,\n error: err instanceof Error ? err : new Error(String(err)),\n };\n }\n });\n}\n","export { ExactEvmSchemeV1 } from \"../exact/v1\";\n\nexport const EVM_NETWORK_CHAIN_ID_MAP = {\n ethereum: 1,\n sepolia: 11155111,\n abstract: 2741,\n \"abstract-testnet\": 11124,\n \"base-sepolia\": 84532,\n base: 8453,\n \"avalanche-fuji\": 43113,\n avalanche: 43114,\n iotex: 4689,\n sei: 1329,\n \"sei-testnet\": 1328,\n polygon: 137,\n \"polygon-amoy\": 80002,\n peaq: 3338,\n story: 1514,\n educhain: 41923,\n \"skale-base-sepolia\": 324705682,\n megaeth: 4326,\n monad: 143,\n} as const;\n\nexport type EvmNetworkV1 = keyof typeof EVM_NETWORK_CHAIN_ID_MAP;\n\nexport const NETWORKS: string[] = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);\n\n/**\n * Extract chain ID from a v1 legacy network name.\n *\n * @param network - The v1 network name (e.g., \"base-sepolia\", \"polygon\")\n * @returns The numeric chain ID\n * @throws Error if the network name is not a known v1 network\n */\nexport function getEvmChainIdV1(network: string): number {\n const chainId = EVM_NETWORK_CHAIN_ID_MAP[network as EvmNetworkV1];\n if (!chainId) {\n throw new Error(`Unsupported v1 network: ${network}`);\n }\n return chainId;\n}\n"],"mappings":"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","names":["import_viem","import_viem","import_viem","import_viem"]}
import { SchemeNetworkFacilitator, PaymentPayload, PaymentRequirements, VerifyResponse, SettleResponse } from '@x402/core/types';
import { F as FacilitatorEvmSigner } from '../../../signer-DC81R8wQ.js';
import { F as FacilitatorEvmSigner } from '../../../signer-D912R4mq.js';

@@ -12,2 +12,8 @@ interface ExactEvmSchemeV1Config {

deployERC4337WithEIP6492?: boolean;
/**
* If enabled, simulates transaction before settling. Defaults to false, ie only simulate during verify.
*
* @default false
*/
simulateInSettle?: boolean;
}

@@ -61,4 +67,13 @@ /**

settle(payload: PaymentPayload, requirements: PaymentRequirements): Promise<SettleResponse>;
/**
* Internal verify with optional simulation control.
*
* @param payload - The payment payload to verify
* @param requirements - The payment requirements
* @param options - Verification options (e.g. simulate)
* @returns Promise resolving to verification response
*/
private _verify;
}
export { ExactEvmSchemeV1, type ExactEvmSchemeV1Config };

@@ -28,3 +28,3 @@ "use strict";

// src/exact/v1/facilitator/scheme.ts
var import_viem3 = require("viem");
var import_viem5 = require("viem");

@@ -88,2 +88,19 @@ // src/constants.ts

type: "function"
},
{
inputs: [],
name: "name",
outputs: [{ name: "", type: "string" }],
stateMutability: "view",
type: "function"
},
{
inputs: [
{ name: "authorizer", type: "address" },
{ name: "nonce", type: "bytes32" }
],
name: "authorizationState",
outputs: [{ name: "", type: "bool" }],
stateMutability: "view",
type: "function"
}

@@ -129,2 +146,253 @@ ];

// src/exact/facilitator/errors.ts
var ErrInvalidScheme = "invalid_exact_evm_scheme";
var ErrNetworkMismatch = "invalid_exact_evm_network_mismatch";
var ErrMissingEip712Domain = "invalid_exact_evm_missing_eip712_domain";
var ErrRecipientMismatch = "invalid_exact_evm_recipient_mismatch";
var ErrInvalidSignature = "invalid_exact_evm_signature";
var ErrValidBeforeExpired = "invalid_exact_evm_payload_authorization_valid_before";
var ErrValidAfterInFuture = "invalid_exact_evm_payload_authorization_valid_after";
var ErrInvalidAuthorizationValue = "invalid_exact_evm_authorization_value";
var ErrUndeployedSmartWallet = "invalid_exact_evm_payload_undeployed_smart_wallet";
var ErrTransactionFailed = "invalid_exact_evm_transaction_failed";
var ErrEip3009TokenNameMismatch = "invalid_exact_evm_token_name_mismatch";
var ErrEip3009TokenVersionMismatch = "invalid_exact_evm_token_version_mismatch";
var ErrEip3009NotSupported = "invalid_exact_evm_eip3009_not_supported";
var ErrEip3009NonceAlreadyUsed = "invalid_exact_evm_nonce_already_used";
var ErrEip3009InsufficientBalance = "invalid_exact_evm_insufficient_balance";
var ErrEip3009SimulationFailed = "invalid_exact_evm_transaction_simulation_failed";
// src/exact/facilitator/eip3009-utils.ts
var import_viem4 = require("viem");
// src/multicall.ts
var import_viem3 = require("viem");
var MULTICALL3_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976CA11";
var multicall3ABI = [
{
inputs: [
{ name: "requireSuccess", type: "bool" },
{
name: "calls",
type: "tuple[]",
components: [
{ name: "target", type: "address" },
{ name: "callData", type: "bytes" }
]
}
],
name: "tryAggregate",
outputs: [
{
name: "returnData",
type: "tuple[]",
components: [
{ name: "success", type: "bool" },
{ name: "returnData", type: "bytes" }
]
}
],
stateMutability: "payable",
type: "function"
}
];
async function multicall(readContract, calls) {
const aggregateCalls = calls.map((call) => {
if ("callData" in call) {
return { target: call.address, callData: call.callData };
}
const callData = (0, import_viem3.encodeFunctionData)({
abi: call.abi,
functionName: call.functionName,
args: call.args
});
return { target: call.address, callData };
});
const rawResults = await readContract({
address: MULTICALL3_ADDRESS,
abi: multicall3ABI,
functionName: "tryAggregate",
args: [false, aggregateCalls]
});
return rawResults.map((raw, i) => {
if (!raw.success) {
return {
status: "failure",
error: new Error(`multicall: call reverted (returnData: ${raw.returnData})`)
};
}
const call = calls[i];
if ("callData" in call) {
return { status: "success", result: void 0 };
}
try {
const decoded = (0, import_viem3.decodeFunctionResult)({
abi: call.abi,
functionName: call.functionName,
data: raw.returnData
});
return { status: "success", result: decoded };
} catch (err) {
return {
status: "failure",
error: err instanceof Error ? err : new Error(String(err))
};
}
});
}
// src/exact/facilitator/eip3009-utils.ts
async function simulateEip3009Transfer(signer, erc20Address, payload, eip6492Deployment) {
const auth = payload.authorization;
const transferArgs = [
(0, import_viem4.getAddress)(auth.from),
(0, import_viem4.getAddress)(auth.to),
BigInt(auth.value),
BigInt(auth.validAfter),
BigInt(auth.validBefore),
auth.nonce
];
if (eip6492Deployment) {
const { signature: innerSignature } = (0, import_viem4.parseErc6492Signature)(payload.signature);
const transferCalldata = (0, import_viem4.encodeFunctionData)({
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [...transferArgs, innerSignature]
});
try {
const results = await multicall(signer.readContract.bind(signer), [
{
address: (0, import_viem4.getAddress)(eip6492Deployment.factoryAddress),
callData: eip6492Deployment.factoryCalldata
},
{
address: erc20Address,
callData: transferCalldata
}
]);
return results[1]?.status === "success";
} catch {
return false;
}
}
const sig = payload.signature;
const sigLength = sig.startsWith("0x") ? sig.length - 2 : sig.length;
const isECDSA = sigLength === 130;
try {
if (isECDSA) {
const parsedSig = (0, import_viem4.parseSignature)(sig);
await signer.readContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
...transferArgs,
parsedSig.v ?? parsedSig.yParity,
parsedSig.r,
parsedSig.s
]
});
} else {
await signer.readContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [...transferArgs, sig]
});
}
return true;
} catch {
return false;
}
}
async function diagnoseEip3009SimulationFailure(signer, erc20Address, payload, requirements, amountRequired) {
const payer = payload.authorization.from;
const diagnosticCalls = [
{
address: erc20Address,
abi: eip3009ABI,
functionName: "balanceOf",
args: [payload.authorization.from]
},
{
address: erc20Address,
abi: eip3009ABI,
functionName: "name"
},
{
address: erc20Address,
abi: eip3009ABI,
functionName: "version"
},
{
address: erc20Address,
abi: eip3009ABI,
functionName: "authorizationState",
args: [payload.authorization.from, payload.authorization.nonce]
}
];
try {
const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
const [balanceResult, nameResult, versionResult, authStateResult] = results;
if (authStateResult.status === "failure") {
return { isValid: false, invalidReason: ErrEip3009NotSupported, payer };
}
if (authStateResult.status === "success" && authStateResult.result === true) {
return { isValid: false, invalidReason: ErrEip3009NonceAlreadyUsed, payer };
}
if (nameResult.status === "success" && requirements.extra?.name && nameResult.result !== requirements.extra.name) {
return { isValid: false, invalidReason: ErrEip3009TokenNameMismatch, payer };
}
if (versionResult.status === "success" && requirements.extra?.version && versionResult.result !== requirements.extra.version) {
return { isValid: false, invalidReason: ErrEip3009TokenVersionMismatch, payer };
}
if (balanceResult.status === "success") {
const balance = balanceResult.result;
if (balance < BigInt(amountRequired)) {
return {
isValid: false,
invalidReason: ErrEip3009InsufficientBalance,
payer
};
}
}
} catch {
}
return { isValid: false, invalidReason: ErrEip3009SimulationFailed, payer };
}
async function executeTransferWithAuthorization(signer, erc20Address, payload) {
const { signature } = (0, import_viem4.parseErc6492Signature)(payload.signature);
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isECDSA = signatureLength === 130;
const auth = payload.authorization;
const baseArgs = [
(0, import_viem4.getAddress)(auth.from),
(0, import_viem4.getAddress)(auth.to),
BigInt(auth.value),
BigInt(auth.validAfter),
BigInt(auth.validBefore),
auth.nonce
];
if (isECDSA) {
const parsedSig = (0, import_viem4.parseSignature)(signature);
return signer.writeContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
...baseArgs,
parsedSig.v || parsedSig.yParity,
parsedSig.r,
parsedSig.s
]
});
}
return signer.writeContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [...baseArgs, signature]
});
}
// src/exact/v1/facilitator/scheme.ts

@@ -143,3 +411,4 @@ var ExactEvmSchemeV12 = class {

this.config = {
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,
simulateInSettle: config?.simulateInSettle ?? false
};

@@ -175,10 +444,91 @@ }

async verify(payload, requirements) {
return this._verify(payload, requirements);
}
/**
* Settles a payment by executing the transfer (V1).
*
* @param payload - The payment payload to settle
* @param requirements - The payment requirements
* @returns Promise resolving to settlement response
*/
async settle(payload, requirements) {
const payloadV1 = payload;
const exactEvmPayload = payload.payload;
const valid = await this._verify(payload, requirements, {
simulate: this.config.simulateInSettle ?? false
});
if (!valid.isValid) {
return {
success: false,
network: payloadV1.network,
transaction: "",
errorReason: valid.invalidReason ?? ErrInvalidScheme,
payer: exactEvmPayload.authorization.from
};
}
try {
const { address: factoryAddress, data: factoryCalldata } = (0, import_viem5.parseErc6492Signature)(
exactEvmPayload.signature
);
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem5.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
const payerAddress = exactEvmPayload.authorization.from;
const bytecode = await this.signer.getCode({ address: payerAddress });
if (!bytecode || bytecode === "0x") {
const deployTx = await this.signer.sendTransaction({
to: factoryAddress,
data: factoryCalldata
});
await this.signer.waitForTransactionReceipt({ hash: deployTx });
}
}
const tx = await executeTransferWithAuthorization(
this.signer,
(0, import_viem5.getAddress)(requirements.asset),
exactEvmPayload
);
const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
if (receipt.status !== "success") {
return {
success: false,
errorReason: ErrTransactionFailed,
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
return {
success: true,
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
} catch (error) {
return {
success: false,
errorReason: error instanceof Error ? error.message : ErrTransactionFailed,
transaction: "",
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
}
/**
* Internal verify with optional simulation control.
*
* @param payload - The payment payload to verify
* @param requirements - The payment requirements
* @param options - Verification options (e.g. simulate)
* @returns Promise resolving to verification response
*/
async _verify(payload, requirements, options) {
const requirementsV1 = requirements;
const payloadV1 = payload;
const exactEvmPayload = payload.payload;
const payer = exactEvmPayload.authorization.from;
let eip6492Deployment;
if (payloadV1.scheme !== "exact" || requirements.scheme !== "exact") {
return {
isValid: false,
invalidReason: "unsupported_scheme",
payer: exactEvmPayload.authorization.from
invalidReason: ErrInvalidScheme,
payer
};

@@ -192,4 +542,4 @@ }

isValid: false,
invalidReason: `invalid_network`,
payer: exactEvmPayload.authorization.from
invalidReason: ErrNetworkMismatch,
payer
};

@@ -200,13 +550,13 @@ }

isValid: false,
invalidReason: "missing_eip712_domain",
payer: exactEvmPayload.authorization.from
invalidReason: ErrMissingEip712Domain,
payer
};
}
const { name, version } = requirements.extra;
const erc20Address = (0, import_viem3.getAddress)(requirements.asset);
const erc20Address = (0, import_viem5.getAddress)(requirements.asset);
if (payloadV1.network !== requirements.network) {
return {
isValid: false,
invalidReason: "network_mismatch",
payer: exactEvmPayload.authorization.from
invalidReason: ErrNetworkMismatch,
payer
};

@@ -232,52 +582,46 @@ }

};
let isValid = false;
try {
const recoveredAddress = await this.signer.verifyTypedData({
address: exactEvmPayload.authorization.from,
isValid = await this.signer.verifyTypedData({
address: payer,
...permitTypedData,
signature: exactEvmPayload.signature
});
if (!recoveredAddress) {
} catch {
isValid = false;
}
const signature = exactEvmPayload.signature;
const sigLen = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const erc6492Data = (0, import_viem5.parseErc6492Signature)(signature);
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem5.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
if (hasDeploymentInfo) {
eip6492Deployment = {
factoryAddress: erc6492Data.address,
factoryCalldata: erc6492Data.data
};
}
if (!isValid) {
const isSmartWallet = sigLen > 130;
if (!isSmartWallet) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
payer: exactEvmPayload.authorization.from
invalidReason: ErrInvalidSignature,
payer
};
}
} catch {
const signature = exactEvmPayload.signature;
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isSmartWallet = signatureLength > 130;
if (isSmartWallet) {
const payerAddress = exactEvmPayload.authorization.from;
const bytecode = await this.signer.getCode({ address: payerAddress });
if (!bytecode || bytecode === "0x") {
const erc6492Data = (0, import_viem3.parseErc6492Signature)(signature);
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !(0, import_viem3.isAddressEqual)(erc6492Data.address, "0x0000000000000000000000000000000000000000");
if (!hasDeploymentInfo) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
payer: payerAddress
};
}
} else {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
payer: exactEvmPayload.authorization.from
};
}
} else {
const bytecode = await this.signer.getCode({ address: payer });
const isDeployed = bytecode && bytecode !== "0x";
if (!isDeployed && !hasDeploymentInfo) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
payer: exactEvmPayload.authorization.from
invalidReason: ErrUndeployedSmartWallet,
payer
};
}
}
if ((0, import_viem3.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem3.getAddress)(requirements.payTo)) {
if ((0, import_viem5.getAddress)(exactEvmPayload.authorization.to) !== (0, import_viem5.getAddress)(requirements.payTo)) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
payer: exactEvmPayload.authorization.from
invalidReason: ErrRecipientMismatch,
payer
};

@@ -289,4 +633,4 @@ }

isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
payer: exactEvmPayload.authorization.from
invalidReason: ErrValidBeforeExpired,
payer
};

@@ -297,143 +641,36 @@ }

isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
payer: exactEvmPayload.authorization.from
invalidReason: ErrValidAfterInFuture,
payer
};
}
try {
const balance = await this.signer.readContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "balanceOf",
args: [exactEvmPayload.authorization.from]
});
if (BigInt(balance) < BigInt(requirementsV1.maxAmountRequired)) {
return {
isValid: false,
invalidReason: "insufficient_funds",
invalidMessage: `Insufficient funds to complete the payment. Required: ${requirementsV1.maxAmountRequired} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
payer: exactEvmPayload.authorization.from
};
}
} catch {
}
if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_value_mismatch",
payer: exactEvmPayload.authorization.from
invalidReason: ErrInvalidAuthorizationValue,
payer
};
}
if (options?.simulate !== false) {
const simulationSucceeded = await simulateEip3009Transfer(
this.signer,
erc20Address,
exactEvmPayload,
eip6492Deployment
);
if (!simulationSucceeded) {
return diagnoseEip3009SimulationFailure(
this.signer,
erc20Address,
exactEvmPayload,
requirements,
requirementsV1.maxAmountRequired
);
}
}
return {
isValid: true,
invalidReason: void 0,
payer: exactEvmPayload.authorization.from
payer
};
}
/**
* Settles a payment by executing the transfer (V1).
*
* @param payload - The payment payload to settle
* @param requirements - The payment requirements
* @returns Promise resolving to settlement response
*/
async settle(payload, requirements) {
const payloadV1 = payload;
const exactEvmPayload = payload.payload;
const valid = await this.verify(payload, requirements);
if (!valid.isValid) {
return {
success: false,
network: payloadV1.network,
transaction: "",
errorReason: valid.invalidReason ?? "invalid_scheme",
payer: exactEvmPayload.authorization.from
};
}
try {
const parseResult = (0, import_viem3.parseErc6492Signature)(exactEvmPayload.signature);
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !(0, import_viem3.isAddressEqual)(factoryAddress, "0x0000000000000000000000000000000000000000")) {
const payerAddress = exactEvmPayload.authorization.from;
const bytecode = await this.signer.getCode({ address: payerAddress });
if (!bytecode || bytecode === "0x") {
try {
console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);
const deployTx = await this.signer.sendTransaction({
to: factoryAddress,
data: factoryCalldata
});
await this.signer.waitForTransactionReceipt({ hash: deployTx });
console.log(`Successfully deployed smart wallet for ${payerAddress}`);
} catch (deployError) {
console.error("Smart wallet deployment failed:", deployError);
throw deployError;
}
} else {
console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);
}
}
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isECDSA = signatureLength === 130;
let tx;
if (isECDSA) {
const parsedSig = (0, import_viem3.parseSignature)(signature);
tx = await this.signer.writeContract({
address: (0, import_viem3.getAddress)(requirements.asset),
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
(0, import_viem3.getAddress)(exactEvmPayload.authorization.from),
(0, import_viem3.getAddress)(exactEvmPayload.authorization.to),
BigInt(exactEvmPayload.authorization.value),
BigInt(exactEvmPayload.authorization.validAfter),
BigInt(exactEvmPayload.authorization.validBefore),
exactEvmPayload.authorization.nonce,
parsedSig.v || parsedSig.yParity,
parsedSig.r,
parsedSig.s
]
});
} else {
tx = await this.signer.writeContract({
address: (0, import_viem3.getAddress)(requirements.asset),
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
(0, import_viem3.getAddress)(exactEvmPayload.authorization.from),
(0, import_viem3.getAddress)(exactEvmPayload.authorization.to),
BigInt(exactEvmPayload.authorization.value),
BigInt(exactEvmPayload.authorization.validAfter),
BigInt(exactEvmPayload.authorization.validBefore),
exactEvmPayload.authorization.nonce,
signature
]
});
}
const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
if (receipt.status !== "success") {
return {
success: false,
errorReason: "invalid_transaction_state",
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
return {
success: true,
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
} catch (error) {
console.error("Failed to settle transaction:", error);
return {
success: false,
errorReason: "transaction_failed",
transaction: "",
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
}
};

@@ -440,0 +677,0 @@ // Annotate the CommonJS export names for ESM import in node:

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../../../../src/exact/v1/facilitator/index.ts","../../../../../src/exact/v1/facilitator/scheme.ts","../../../../../src/constants.ts","../../../../../src/exact/v1/client/scheme.ts","../../../../../src/utils.ts","../../../../../src/v1/index.ts"],"sourcesContent":["export { ExactEvmSchemeV1 } from \"./scheme\";\nexport type { ExactEvmSchemeV1Config } from \"./scheme\";\n","import {\n PaymentPayload,\n PaymentPayloadV1,\n PaymentRequirements,\n SchemeNetworkFacilitator,\n SettleResponse,\n VerifyResponse,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress, Hex, isAddressEqual, parseErc6492Signature, parseSignature } from \"viem\";\nimport { authorizationTypes, eip3009ABI } from \"../../../constants\";\nimport { FacilitatorEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\n\nexport interface ExactEvmSchemeV1Config {\n /**\n * If enabled, the facilitator will deploy ERC-4337 smart wallets\n * via EIP-6492 when encountering undeployed contract signatures.\n *\n * @default false\n */\n deployERC4337WithEIP6492?: boolean;\n}\n\n/**\n * EVM facilitator implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkFacilitator {\n readonly scheme = \"exact\";\n readonly caipFamily = \"eip155:*\";\n private readonly config: Required<ExactEvmSchemeV1Config>;\n\n /**\n * Creates a new ExactEvmFacilitatorV1 instance.\n *\n * @param signer - The EVM signer for facilitator operations\n * @param config - Optional configuration for the facilitator\n */\n constructor(\n private readonly signer: FacilitatorEvmSigner,\n config?: ExactEvmSchemeV1Config,\n ) {\n this.config = {\n deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,\n };\n }\n\n /**\n * Get mechanism-specific extra data for the supported kinds endpoint.\n * For EVM, no extra data is needed.\n *\n * @param _ - The network identifier (unused for EVM)\n * @returns undefined (EVM has no extra data)\n */\n getExtra(_: string): Record<string, unknown> | undefined {\n return undefined;\n }\n\n /**\n * Get signer addresses used by this facilitator.\n * Returns all addresses this facilitator can use for signing/settling transactions.\n *\n * @param _ - The network identifier (unused for EVM, addresses are network-agnostic)\n * @returns Array of facilitator wallet addresses\n */\n getSigners(_: string): string[] {\n return [...this.signer.getAddresses()];\n }\n\n /**\n * Verifies a payment payload (V1).\n *\n * @param payload - The payment payload to verify\n * @param requirements - The payment requirements\n * @returns Promise resolving to verification response\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n const requirementsV1 = requirements as unknown as PaymentRequirementsV1;\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n\n // Verify scheme matches\n if (payloadV1.scheme !== \"exact\" || requirements.scheme !== \"exact\") {\n return {\n isValid: false,\n invalidReason: \"unsupported_scheme\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Get chain configuration\n let chainId: number;\n try {\n chainId = getEvmChainIdV1(payloadV1.network as EvmNetworkV1);\n } catch {\n return {\n isValid: false,\n invalidReason: `invalid_network`,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n return {\n isValid: false,\n invalidReason: \"missing_eip712_domain\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n const { name, version } = requirements.extra;\n const erc20Address = getAddress(requirements.asset);\n\n // Verify network matches\n if (payloadV1.network !== requirements.network) {\n return {\n isValid: false,\n invalidReason: \"network_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Build typed data for signature verification\n const permitTypedData = {\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\" as const,\n domain: {\n name,\n version,\n chainId,\n verifyingContract: erc20Address,\n },\n message: {\n from: exactEvmPayload.authorization.from,\n to: exactEvmPayload.authorization.to,\n value: BigInt(exactEvmPayload.authorization.value),\n validAfter: BigInt(exactEvmPayload.authorization.validAfter),\n validBefore: BigInt(exactEvmPayload.authorization.validBefore),\n nonce: exactEvmPayload.authorization.nonce,\n },\n };\n\n // Verify signature\n try {\n const recoveredAddress = await this.signer.verifyTypedData({\n address: exactEvmPayload.authorization.from,\n ...permitTypedData,\n signature: exactEvmPayload.signature!,\n });\n\n if (!recoveredAddress) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n } catch {\n // Signature verification failed - could be an undeployed smart wallet\n // Check if smart wallet is deployed\n const signature = exactEvmPayload.signature!;\n const signatureLength = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n const isSmartWallet = signatureLength > 130; // 65 bytes = 130 hex chars for EOA\n\n if (isSmartWallet) {\n const payerAddress = exactEvmPayload.authorization.from;\n const bytecode = await this.signer.getCode({ address: payerAddress });\n\n if (!bytecode || bytecode === \"0x\") {\n // Wallet is not deployed. Check if it's EIP-6492 with deployment info.\n // EIP-6492 signatures contain factory address and calldata needed for deployment.\n // Non-EIP-6492 undeployed wallets cannot succeed (no way to deploy them).\n const erc6492Data = parseErc6492Signature(signature);\n const hasDeploymentInfo =\n erc6492Data.address &&\n erc6492Data.data &&\n !isAddressEqual(erc6492Data.address, \"0x0000000000000000000000000000000000000000\");\n\n if (!hasDeploymentInfo) {\n // Non-EIP-6492 undeployed smart wallet - will always fail at settlement\n // since EIP-3009 requires on-chain EIP-1271 validation\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_undeployed_smart_wallet\",\n payer: payerAddress,\n };\n }\n // EIP-6492 signature with deployment info - allow through\n // Facilitators with sponsored deployment support can handle this in settle()\n } else {\n // Wallet is deployed but signature still failed - invalid signature\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n } else {\n // EOA signature failed\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n }\n\n // Verify payment recipient matches\n if (getAddress(exactEvmPayload.authorization.to) !== getAddress(requirements.payTo)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_recipient_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Verify validBefore is in the future (with 6 second buffer for block time)\n const now = Math.floor(Date.now() / 1000);\n if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_valid_before\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Verify validAfter is not in the future\n if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_valid_after\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Check balance\n try {\n const balance = (await this.signer.readContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"balanceOf\",\n args: [exactEvmPayload.authorization.from],\n })) as bigint;\n\n if (BigInt(balance) < BigInt(requirementsV1.maxAmountRequired)) {\n return {\n isValid: false,\n invalidReason: \"insufficient_funds\",\n invalidMessage: `Insufficient funds to complete the payment. Required: ${requirementsV1.maxAmountRequired} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,\n payer: exactEvmPayload.authorization.from,\n };\n }\n } catch {\n // If we can't check balance, continue with other validations\n }\n\n // Verify amount exactly matches requirements\n if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_value_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n return {\n isValid: true,\n invalidReason: undefined,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n /**\n * Settles a payment by executing the transfer (V1).\n *\n * @param payload - The payment payload to settle\n * @param requirements - The payment requirements\n * @returns Promise resolving to settlement response\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n\n // Re-verify before settling\n const valid = await this.verify(payload, requirements);\n if (!valid.isValid) {\n return {\n success: false,\n network: payloadV1.network,\n transaction: \"\",\n errorReason: valid.invalidReason ?? \"invalid_scheme\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n try {\n // Parse ERC-6492 signature if applicable\n const parseResult = parseErc6492Signature(exactEvmPayload.signature!);\n const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;\n\n // Deploy ERC-4337 smart wallet via EIP-6492 if configured and needed\n if (\n this.config.deployERC4337WithEIP6492 &&\n factoryAddress &&\n factoryCalldata &&\n !isAddressEqual(factoryAddress, \"0x0000000000000000000000000000000000000000\")\n ) {\n // Check if smart wallet is already deployed\n const payerAddress = exactEvmPayload.authorization.from;\n const bytecode = await this.signer.getCode({ address: payerAddress });\n\n if (!bytecode || bytecode === \"0x\") {\n // Wallet not deployed - attempt deployment\n try {\n console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);\n\n // Send the factory calldata directly as a transaction\n // The factoryCalldata already contains the complete encoded function call\n const deployTx = await this.signer.sendTransaction({\n to: factoryAddress as Hex,\n data: factoryCalldata as Hex,\n });\n\n // Wait for deployment transaction\n await this.signer.waitForTransactionReceipt({ hash: deployTx });\n console.log(`Successfully deployed smart wallet for ${payerAddress}`);\n } catch (deployError) {\n console.error(\"Smart wallet deployment failed:\", deployError);\n // Deployment failed - cannot proceed\n throw deployError;\n }\n } else {\n console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);\n }\n }\n\n // Determine if this is an ECDSA signature (EOA) or smart wallet signature\n // ECDSA signatures are exactly 65 bytes (130 hex chars without 0x)\n const signatureLength = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n const isECDSA = signatureLength === 130;\n\n let tx: Hex;\n if (isECDSA) {\n // For EOA wallets, parse signature into v, r, s and use that overload\n const parsedSig = parseSignature(signature);\n\n tx = await this.signer.writeContract({\n address: getAddress(requirements.asset),\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n getAddress(exactEvmPayload.authorization.from),\n getAddress(exactEvmPayload.authorization.to),\n BigInt(exactEvmPayload.authorization.value),\n BigInt(exactEvmPayload.authorization.validAfter),\n BigInt(exactEvmPayload.authorization.validBefore),\n exactEvmPayload.authorization.nonce,\n (parsedSig.v as number | undefined) || parsedSig.yParity,\n parsedSig.r,\n parsedSig.s,\n ],\n });\n } else {\n // For smart wallets, use the bytes signature overload\n // The signature contains WebAuthn/P256 or other ERC-1271 compatible signature data\n tx = await this.signer.writeContract({\n address: getAddress(requirements.asset),\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n getAddress(exactEvmPayload.authorization.from),\n getAddress(exactEvmPayload.authorization.to),\n BigInt(exactEvmPayload.authorization.value),\n BigInt(exactEvmPayload.authorization.validAfter),\n BigInt(exactEvmPayload.authorization.validBefore),\n exactEvmPayload.authorization.nonce,\n signature,\n ],\n });\n }\n\n // Wait for transaction confirmation\n const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });\n\n if (receipt.status !== \"success\") {\n return {\n success: false,\n errorReason: \"invalid_transaction_state\",\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n return {\n success: true,\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n } catch (error) {\n console.error(\"Failed to settle transaction:\", error);\n return {\n success: false,\n errorReason: \"transaction_failed\",\n transaction: \"\",\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n }\n}\n","// EIP-3009 TransferWithAuthorization types for EIP-712 signing\nexport const authorizationTypes = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\n/**\n * Permit2 EIP-712 types for signing PermitWitnessTransferFrom.\n * Must match the exact format expected by the Permit2 contract.\n * Note: Types must be in ALPHABETICAL order after the primary type (TokenPermissions < Witness).\n */\nexport const permit2WitnessTypes = {\n PermitWitnessTransferFrom: [\n { name: \"permitted\", type: \"TokenPermissions\" },\n { name: \"spender\", type: \"address\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n { name: \"witness\", type: \"Witness\" },\n ],\n TokenPermissions: [\n { name: \"token\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n Witness: [\n { name: \"to\", type: \"address\" },\n { name: \"validAfter\", type: \"uint256\" },\n ],\n} as const;\n\n// EIP3009 ABI for transferWithAuthorization function\nexport const eip3009ABI = [\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"v\", type: \"uint8\" },\n { name: \"r\", type: \"bytes32\" },\n { name: \"s\", type: \"bytes32\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"signature\", type: \"bytes\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [{ name: \"account\", type: \"address\" }],\n name: \"balanceOf\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"version\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/**\n * EIP-2612 Permit EIP-712 types for signing token.permit().\n */\nexport const eip2612PermitTypes = {\n Permit: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * EIP-2612 nonces ABI for querying current nonce.\n */\nexport const eip2612NoncesAbi = [\n {\n type: \"function\",\n name: \"nonces\",\n inputs: [{ name: \"owner\", type: \"address\" }],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** ERC-20 approve(address,uint256) ABI for encoding/decoding approval calldata. */\nexport const erc20ApproveAbi = [\n {\n type: \"function\",\n name: \"approve\",\n inputs: [\n { name: \"spender\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n outputs: [{ type: \"bool\" }],\n stateMutability: \"nonpayable\",\n },\n] as const;\n\n/** ERC-20 allowance(address,address) ABI for checking spender approval. */\nexport const erc20AllowanceAbi = [\n {\n type: \"function\",\n name: \"allowance\",\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n ],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** Gas limit for a standard ERC-20 approve() transaction. */\nexport const ERC20_APPROVE_GAS_LIMIT = 70_000n;\n\n/** Fallback max fee per gas (1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_FEE_PER_GAS = 1_000_000_000n;\n\n/** Fallback max priority fee per gas (0.1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100_000_000n;\n\n/**\n * Canonical Permit2 contract address.\n * Same address on all EVM chains via CREATE2 deployment.\n *\n * @see https://github.com/Uniswap/permit2\n */\nexport const PERMIT2_ADDRESS = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\" as const;\n\n/**\n * x402ExactPermit2Proxy contract address.\n * Vanity address: 0x4020...0001 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0001\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402ExactPermit2ProxyAddress = \"0x402085c248EeA27D92E8b30b2C58ed07f9E20001\" as const;\n\n/**\n * x402UptoPermit2Proxy contract address.\n * Vanity address: 0x4020...0002 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0002\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402UptoPermit2ProxyAddress = \"0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002\" as const;\n\n/**\n * Shared ABI components for the Permit2 witness tuple.\n * Used in both x402ExactPermit2ProxyABI and x402UptoPermit2ProxyABI to keep them in sync.\n * The upto contract's witness struct is identical to exact (both remove 'extra' post-audit).\n */\nconst permit2WitnessABIComponents = [\n { name: \"to\", type: \"address\", internalType: \"address\" },\n { name: \"validAfter\", type: \"uint256\", internalType: \"uint256\" },\n] as const;\n\n/**\n * x402UptoPermit2Proxy ABI - settle function for upto payment scheme (variable amounts).\n * Updated post-audit: 'extra' removed from witness struct, 'initialize()' removed (now\n * a constructor arg), and error names aligned with x402ExactPermit2Proxy.\n */\nexport const x402UptoPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n\n/**\n * x402ExactPermit2Proxy ABI - settle function for exact payment scheme.\n */\nexport const x402ExactPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n","import {\n Network,\n PaymentPayload,\n PaymentRequirements,\n SchemeNetworkClient,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress } from \"viem\";\nimport { authorizationTypes } from \"../../../constants\";\nimport { ClientEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { createNonce } from \"../../../utils\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\n\n/**\n * EVM client implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkClient {\n readonly scheme = \"exact\";\n\n /**\n * Creates a new ExactEvmClientV1 instance.\n *\n * @param signer - The EVM signer for client operations\n */\n constructor(private readonly signer: ClientEvmSigner) {}\n\n /**\n * Creates a payment payload for the Exact scheme (V1).\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n ): Promise<\n Pick<PaymentPayload, \"x402Version\" | \"payload\"> & { scheme: string; network: Network }\n > {\n const selectedV1 = paymentRequirements as unknown as PaymentRequirementsV1;\n const nonce = createNonce();\n const now = Math.floor(Date.now() / 1000);\n\n const authorization: ExactEvmPayloadV1[\"authorization\"] = {\n from: this.signer.address,\n to: getAddress(selectedV1.payTo),\n value: selectedV1.maxAmountRequired,\n validAfter: (now - 600).toString(), // 10 minutes before\n validBefore: (now + selectedV1.maxTimeoutSeconds).toString(),\n nonce,\n };\n\n // Sign the authorization\n const signature = await this.signAuthorization(authorization, selectedV1);\n\n const payload: ExactEvmPayloadV1 = {\n authorization,\n signature,\n };\n\n return {\n x402Version,\n scheme: selectedV1.scheme,\n network: selectedV1.network,\n payload,\n };\n }\n\n /**\n * Sign the EIP-3009 authorization using EIP-712\n *\n * @param authorization - The authorization to sign\n * @param requirements - The payment requirements\n * @returns Promise resolving to the signature\n */\n private async signAuthorization(\n authorization: ExactEvmPayloadV1[\"authorization\"],\n requirements: PaymentRequirementsV1,\n ): Promise<`0x${string}`> {\n const chainId = getEvmChainIdV1(requirements.network as EvmNetworkV1);\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`,\n );\n }\n\n const { name, version } = requirements.extra;\n\n const domain = {\n name,\n version,\n chainId,\n verifyingContract: getAddress(requirements.asset),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return await this.signer.signTypedData({\n domain,\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\",\n message,\n });\n }\n}\n","import { toHex } from \"viem\";\n\n/**\n * Extract chain ID from a CAIP-2 network identifier (eip155:CHAIN_ID).\n *\n * @param network - The network identifier in CAIP-2 format (e.g., \"eip155:8453\")\n * @returns The numeric chain ID\n * @throws Error if the network format is invalid\n */\nexport function getEvmChainId(network: string): number {\n if (network.startsWith(\"eip155:\")) {\n const idStr = network.split(\":\")[1];\n const chainId = parseInt(idStr, 10);\n if (isNaN(chainId)) {\n throw new Error(`Invalid CAIP-2 chain ID: ${network}`);\n }\n return chainId;\n }\n\n throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);\n}\n\n/**\n * Get the crypto object from the global scope.\n *\n * @returns The crypto object\n * @throws Error if crypto API is not available\n */\nfunction getCrypto(): Crypto {\n const cryptoObj = globalThis.crypto as Crypto | undefined;\n if (!cryptoObj) {\n throw new Error(\"Crypto API not available\");\n }\n return cryptoObj;\n}\n\n/**\n * Create a random 32-byte nonce for EIP-3009 authorization.\n *\n * @returns A hex-encoded 32-byte nonce\n */\nexport function createNonce(): `0x${string}` {\n return toHex(getCrypto().getRandomValues(new Uint8Array(32)));\n}\n\n/**\n * Creates a random 256-bit nonce for Permit2.\n * Permit2 uses uint256 nonces (not bytes32 like EIP-3009).\n *\n * @returns A string representation of the random nonce\n */\nexport function createPermit2Nonce(): string {\n const randomBytes = getCrypto().getRandomValues(new Uint8Array(32));\n return BigInt(toHex(randomBytes)).toString();\n}\n","export { ExactEvmSchemeV1 } from \"../exact/v1\";\n\nexport const EVM_NETWORK_CHAIN_ID_MAP = {\n ethereum: 1,\n sepolia: 11155111,\n abstract: 2741,\n \"abstract-testnet\": 11124,\n \"base-sepolia\": 84532,\n base: 8453,\n \"avalanche-fuji\": 43113,\n avalanche: 43114,\n iotex: 4689,\n sei: 1329,\n \"sei-testnet\": 1328,\n polygon: 137,\n \"polygon-amoy\": 80002,\n peaq: 3338,\n story: 1514,\n educhain: 41923,\n \"skale-base-sepolia\": 324705682,\n megaeth: 4326,\n monad: 143,\n} as const;\n\nexport type EvmNetworkV1 = keyof typeof EVM_NETWORK_CHAIN_ID_MAP;\n\nexport const NETWORKS: string[] = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);\n\n/**\n * Extract chain ID from a v1 legacy network name.\n *\n * @param network - The v1 network name (e.g., \"base-sepolia\", \"polygon\")\n * @returns The numeric chain ID\n * @throws Error if the network name is not a known v1 network\n */\nexport function getEvmChainIdV1(network: string): number {\n const chainId = EVM_NETWORK_CHAIN_ID_MAP[network as EvmNetworkV1];\n if (!chainId) {\n throw new Error(`Unsupported v1 network: ${network}`);\n }\n return chainId;\n}\n"],"mappings":"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","names":["ExactEvmSchemeV1","import_viem","import_viem","ExactEvmSchemeV1"]}
{"version":3,"sources":["../../../../../src/exact/v1/facilitator/index.ts","../../../../../src/exact/v1/facilitator/scheme.ts","../../../../../src/constants.ts","../../../../../src/exact/v1/client/scheme.ts","../../../../../src/utils.ts","../../../../../src/v1/index.ts","../../../../../src/exact/facilitator/errors.ts","../../../../../src/exact/facilitator/eip3009-utils.ts","../../../../../src/multicall.ts"],"sourcesContent":["export { ExactEvmSchemeV1 } from \"./scheme\";\nexport type { ExactEvmSchemeV1Config } from \"./scheme\";\n","import {\n PaymentPayload,\n PaymentPayloadV1,\n PaymentRequirements,\n SchemeNetworkFacilitator,\n SettleResponse,\n VerifyResponse,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress, Hex, isAddressEqual, parseErc6492Signature } from \"viem\";\nimport { authorizationTypes } from \"../../../constants\";\nimport { FacilitatorEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\nimport * as Errors from \"../../facilitator/errors\";\nimport {\n diagnoseEip3009SimulationFailure,\n executeTransferWithAuthorization,\n simulateEip3009Transfer,\n} from \"../../facilitator/eip3009-utils\";\n\nexport interface VerifyV1Options {\n /** Run onchain simulation. Defaults to true. */\n simulate?: boolean;\n}\n\nexport interface ExactEvmSchemeV1Config {\n /**\n * If enabled, the facilitator will deploy ERC-4337 smart wallets\n * via EIP-6492 when encountering undeployed contract signatures.\n *\n * @default false\n */\n deployERC4337WithEIP6492?: boolean;\n /**\n * If enabled, simulates transaction before settling. Defaults to false, ie only simulate during verify.\n *\n * @default false\n */\n simulateInSettle?: boolean;\n}\n\n/**\n * EVM facilitator implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkFacilitator {\n readonly scheme = \"exact\";\n readonly caipFamily = \"eip155:*\";\n private readonly config: Required<ExactEvmSchemeV1Config>;\n\n /**\n * Creates a new ExactEvmFacilitatorV1 instance.\n *\n * @param signer - The EVM signer for facilitator operations\n * @param config - Optional configuration for the facilitator\n */\n constructor(\n private readonly signer: FacilitatorEvmSigner,\n config?: ExactEvmSchemeV1Config,\n ) {\n this.config = {\n deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,\n simulateInSettle: config?.simulateInSettle ?? false,\n };\n }\n\n /**\n * Get mechanism-specific extra data for the supported kinds endpoint.\n * For EVM, no extra data is needed.\n *\n * @param _ - The network identifier (unused for EVM)\n * @returns undefined (EVM has no extra data)\n */\n getExtra(_: string): Record<string, unknown> | undefined {\n return undefined;\n }\n\n /**\n * Get signer addresses used by this facilitator.\n * Returns all addresses this facilitator can use for signing/settling transactions.\n *\n * @param _ - The network identifier (unused for EVM, addresses are network-agnostic)\n * @returns Array of facilitator wallet addresses\n */\n getSigners(_: string): string[] {\n return [...this.signer.getAddresses()];\n }\n\n /**\n * Verifies a payment payload (V1).\n *\n * @param payload - The payment payload to verify\n * @param requirements - The payment requirements\n * @returns Promise resolving to verification response\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n return this._verify(payload, requirements);\n }\n\n /**\n * Settles a payment by executing the transfer (V1).\n *\n * @param payload - The payment payload to settle\n * @param requirements - The payment requirements\n * @returns Promise resolving to settlement response\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n\n // Re-verify before settling\n const valid = await this._verify(payload, requirements, {\n simulate: this.config.simulateInSettle ?? false,\n });\n if (!valid.isValid) {\n return {\n success: false,\n network: payloadV1.network,\n transaction: \"\",\n errorReason: valid.invalidReason ?? Errors.ErrInvalidScheme,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n try {\n // Parse ERC-6492 signature if applicable (for optional deployment)\n const { address: factoryAddress, data: factoryCalldata } = parseErc6492Signature(\n exactEvmPayload.signature!,\n );\n\n // Deploy ERC-4337 smart wallet via EIP-6492 if configured and needed\n if (\n this.config.deployERC4337WithEIP6492 &&\n factoryAddress &&\n factoryCalldata &&\n !isAddressEqual(factoryAddress, \"0x0000000000000000000000000000000000000000\")\n ) {\n // Check if smart wallet is already deployed\n const payerAddress = exactEvmPayload.authorization.from;\n const bytecode = await this.signer.getCode({ address: payerAddress });\n\n if (!bytecode || bytecode === \"0x\") {\n // Send the factory calldata directly as a transaction\n // The factoryCalldata already contains the complete encoded function call\n const deployTx = await this.signer.sendTransaction({\n to: factoryAddress as Hex,\n data: factoryCalldata as Hex,\n });\n\n // Wait for deployment transaction\n await this.signer.waitForTransactionReceipt({ hash: deployTx });\n }\n }\n\n const tx = await executeTransferWithAuthorization(\n this.signer,\n getAddress(requirements.asset),\n exactEvmPayload,\n );\n\n // Wait for transaction confirmation\n const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });\n\n if (receipt.status !== \"success\") {\n return {\n success: false,\n errorReason: Errors.ErrTransactionFailed,\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n return {\n success: true,\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n } catch (error) {\n return {\n success: false,\n errorReason: error instanceof Error ? error.message : Errors.ErrTransactionFailed,\n transaction: \"\",\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n }\n\n /**\n * Internal verify with optional simulation control.\n *\n * @param payload - The payment payload to verify\n * @param requirements - The payment requirements\n * @param options - Verification options (e.g. simulate)\n * @returns Promise resolving to verification response\n */\n private async _verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n options?: VerifyV1Options,\n ): Promise<VerifyResponse> {\n const requirementsV1 = requirements as unknown as PaymentRequirementsV1;\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n const payer = exactEvmPayload.authorization.from;\n let eip6492Deployment:\n | { factoryAddress: `0x${string}`; factoryCalldata: `0x${string}` }\n | undefined;\n\n // Verify scheme matches\n if (payloadV1.scheme !== \"exact\" || requirements.scheme !== \"exact\") {\n return {\n isValid: false,\n invalidReason: Errors.ErrInvalidScheme,\n payer,\n };\n }\n\n // Get chain configuration\n let chainId: number;\n try {\n chainId = getEvmChainIdV1(payloadV1.network as EvmNetworkV1);\n } catch {\n return {\n isValid: false,\n invalidReason: Errors.ErrNetworkMismatch,\n payer,\n };\n }\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n return {\n isValid: false,\n invalidReason: Errors.ErrMissingEip712Domain,\n payer,\n };\n }\n\n const { name, version } = requirements.extra;\n const erc20Address = getAddress(requirements.asset);\n\n // Verify network matches\n if (payloadV1.network !== requirements.network) {\n return {\n isValid: false,\n invalidReason: Errors.ErrNetworkMismatch,\n payer,\n };\n }\n\n // Build typed data for signature verification\n const permitTypedData = {\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\" as const,\n domain: {\n name,\n version,\n chainId,\n verifyingContract: erc20Address,\n },\n message: {\n from: exactEvmPayload.authorization.from,\n to: exactEvmPayload.authorization.to,\n value: BigInt(exactEvmPayload.authorization.value),\n validAfter: BigInt(exactEvmPayload.authorization.validAfter),\n validBefore: BigInt(exactEvmPayload.authorization.validBefore),\n nonce: exactEvmPayload.authorization.nonce,\n },\n };\n\n // Verify signature (flatten EIP-6492 handling out of catch block)\n let isValid = false;\n try {\n isValid = await this.signer.verifyTypedData({\n address: payer,\n ...permitTypedData,\n signature: exactEvmPayload.signature!,\n });\n } catch {\n isValid = false;\n }\n\n const signature = exactEvmPayload.signature!;\n const sigLen = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n\n // Extract EIP-6492 deployment info (factory address + calldata) if present\n const erc6492Data = parseErc6492Signature(signature);\n const hasDeploymentInfo =\n erc6492Data.address &&\n erc6492Data.data &&\n !isAddressEqual(erc6492Data.address, \"0x0000000000000000000000000000000000000000\");\n\n if (hasDeploymentInfo) {\n eip6492Deployment = {\n factoryAddress: erc6492Data.address!,\n factoryCalldata: erc6492Data.data!,\n };\n }\n\n if (!isValid) {\n const isSmartWallet = sigLen > 130; // 65 bytes = 130 hex chars for EOA\n\n if (!isSmartWallet) {\n return {\n isValid: false,\n invalidReason: Errors.ErrInvalidSignature,\n payer,\n };\n }\n\n const bytecode = await this.signer.getCode({ address: payer });\n const isDeployed = bytecode && bytecode !== \"0x\";\n\n if (!isDeployed && !hasDeploymentInfo) {\n return {\n isValid: false,\n invalidReason: Errors.ErrUndeployedSmartWallet,\n payer,\n };\n }\n }\n\n // Verify payment recipient matches\n if (getAddress(exactEvmPayload.authorization.to) !== getAddress(requirements.payTo)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrRecipientMismatch,\n payer,\n };\n }\n\n // Verify validBefore is in the future (with 6 second buffer for block time)\n const now = Math.floor(Date.now() / 1000);\n if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrValidBeforeExpired,\n payer,\n };\n }\n\n // Verify validAfter is not in the future\n if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrValidAfterInFuture,\n payer,\n };\n }\n\n // Verify amount exactly matches requirements\n if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrInvalidAuthorizationValue,\n payer,\n };\n }\n\n // Transaction simulation\n if (options?.simulate !== false) {\n const simulationSucceeded = await simulateEip3009Transfer(\n this.signer,\n erc20Address,\n exactEvmPayload,\n eip6492Deployment,\n );\n if (!simulationSucceeded) {\n return diagnoseEip3009SimulationFailure(\n this.signer,\n erc20Address,\n exactEvmPayload,\n requirements,\n requirementsV1.maxAmountRequired,\n );\n }\n }\n\n return {\n isValid: true,\n invalidReason: undefined,\n payer,\n };\n }\n}\n","// EIP-3009 TransferWithAuthorization types for EIP-712 signing\nexport const authorizationTypes = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\n/**\n * Permit2 EIP-712 types for signing PermitWitnessTransferFrom.\n * Must match the exact format expected by the Permit2 contract.\n * Note: Types must be in ALPHABETICAL order after the primary type (TokenPermissions < Witness).\n */\nexport const permit2WitnessTypes = {\n PermitWitnessTransferFrom: [\n { name: \"permitted\", type: \"TokenPermissions\" },\n { name: \"spender\", type: \"address\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n { name: \"witness\", type: \"Witness\" },\n ],\n TokenPermissions: [\n { name: \"token\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n Witness: [\n { name: \"to\", type: \"address\" },\n { name: \"validAfter\", type: \"uint256\" },\n ],\n} as const;\n\n// EIP3009 ABI for transferWithAuthorization function\nexport const eip3009ABI = [\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"v\", type: \"uint8\" },\n { name: \"r\", type: \"bytes32\" },\n { name: \"s\", type: \"bytes32\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"signature\", type: \"bytes\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [{ name: \"account\", type: \"address\" }],\n name: \"balanceOf\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"version\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"name\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"authorizer\", type: \"address\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n name: \"authorizationState\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/**\n * EIP-2612 Permit EIP-712 types for signing token.permit().\n */\nexport const eip2612PermitTypes = {\n Permit: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * EIP-2612 nonces ABI for querying current nonce.\n */\nexport const eip2612NoncesAbi = [\n {\n type: \"function\",\n name: \"nonces\",\n inputs: [{ name: \"owner\", type: \"address\" }],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** ERC-20 approve(address,uint256) ABI for encoding/decoding approval calldata. */\nexport const erc20ApproveAbi = [\n {\n type: \"function\",\n name: \"approve\",\n inputs: [\n { name: \"spender\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n outputs: [{ type: \"bool\" }],\n stateMutability: \"nonpayable\",\n },\n] as const;\n\n/** ERC-20 allowance(address,address) ABI for checking spender approval. */\nexport const erc20AllowanceAbi = [\n {\n type: \"function\",\n name: \"allowance\",\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n ],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** Gas limit for a standard ERC-20 approve() transaction. */\nexport const ERC20_APPROVE_GAS_LIMIT = 70_000n;\n\n/** Fallback max fee per gas (1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_FEE_PER_GAS = 1_000_000_000n;\n\n/** Fallback max priority fee per gas (0.1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100_000_000n;\n\n/**\n * Canonical Permit2 contract address.\n * Same address on all EVM chains via CREATE2 deployment.\n *\n * @see https://github.com/Uniswap/permit2\n */\nexport const PERMIT2_ADDRESS = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\" as const;\n\n/**\n * x402ExactPermit2Proxy contract address.\n * Vanity address: 0x4020...0001 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0001\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402ExactPermit2ProxyAddress = \"0x402085c248EeA27D92E8b30b2C58ed07f9E20001\" as const;\n\n/**\n * x402UptoPermit2Proxy contract address.\n * Vanity address: 0x4020...0002 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0002\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402UptoPermit2ProxyAddress = \"0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002\" as const;\n\n/**\n * Shared ABI components for the Permit2 witness tuple.\n * Used in both x402ExactPermit2ProxyABI and x402UptoPermit2ProxyABI to keep them in sync.\n * The upto contract's witness struct is identical to exact (both remove 'extra' post-audit).\n */\nconst permit2WitnessABIComponents = [\n { name: \"to\", type: \"address\", internalType: \"address\" },\n { name: \"validAfter\", type: \"uint256\", internalType: \"uint256\" },\n] as const;\n\n/**\n * x402UptoPermit2Proxy ABI - settle function for upto payment scheme (variable amounts).\n * Updated post-audit: 'extra' removed from witness struct, 'initialize()' removed (now\n * a constructor arg), and error names aligned with x402ExactPermit2Proxy.\n */\nexport const x402UptoPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n\n/**\n * x402ExactPermit2Proxy ABI - settle function for exact payment scheme.\n */\nexport const x402ExactPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n","import {\n Network,\n PaymentPayload,\n PaymentRequirements,\n SchemeNetworkClient,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress } from \"viem\";\nimport { authorizationTypes } from \"../../../constants\";\nimport { ClientEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { createNonce } from \"../../../utils\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\n\n/**\n * EVM client implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkClient {\n readonly scheme = \"exact\";\n\n /**\n * Creates a new ExactEvmClientV1 instance.\n *\n * @param signer - The EVM signer for client operations\n */\n constructor(private readonly signer: ClientEvmSigner) {}\n\n /**\n * Creates a payment payload for the Exact scheme (V1).\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n ): Promise<\n Pick<PaymentPayload, \"x402Version\" | \"payload\"> & { scheme: string; network: Network }\n > {\n const selectedV1 = paymentRequirements as unknown as PaymentRequirementsV1;\n const nonce = createNonce();\n const now = Math.floor(Date.now() / 1000);\n\n const authorization: ExactEvmPayloadV1[\"authorization\"] = {\n from: this.signer.address,\n to: getAddress(selectedV1.payTo),\n value: selectedV1.maxAmountRequired,\n validAfter: (now - 600).toString(), // 10 minutes before\n validBefore: (now + selectedV1.maxTimeoutSeconds).toString(),\n nonce,\n };\n\n // Sign the authorization\n const signature = await this.signAuthorization(authorization, selectedV1);\n\n const payload: ExactEvmPayloadV1 = {\n authorization,\n signature,\n };\n\n return {\n x402Version,\n scheme: selectedV1.scheme,\n network: selectedV1.network,\n payload,\n };\n }\n\n /**\n * Sign the EIP-3009 authorization using EIP-712\n *\n * @param authorization - The authorization to sign\n * @param requirements - The payment requirements\n * @returns Promise resolving to the signature\n */\n private async signAuthorization(\n authorization: ExactEvmPayloadV1[\"authorization\"],\n requirements: PaymentRequirementsV1,\n ): Promise<`0x${string}`> {\n const chainId = getEvmChainIdV1(requirements.network as EvmNetworkV1);\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`,\n );\n }\n\n const { name, version } = requirements.extra;\n\n const domain = {\n name,\n version,\n chainId,\n verifyingContract: getAddress(requirements.asset),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return await this.signer.signTypedData({\n domain,\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\",\n message,\n });\n }\n}\n","import { toHex } from \"viem\";\n\n/**\n * Extract chain ID from a CAIP-2 network identifier (eip155:CHAIN_ID).\n *\n * @param network - The network identifier in CAIP-2 format (e.g., \"eip155:8453\")\n * @returns The numeric chain ID\n * @throws Error if the network format is invalid\n */\nexport function getEvmChainId(network: string): number {\n if (network.startsWith(\"eip155:\")) {\n const idStr = network.split(\":\")[1];\n const chainId = parseInt(idStr, 10);\n if (isNaN(chainId)) {\n throw new Error(`Invalid CAIP-2 chain ID: ${network}`);\n }\n return chainId;\n }\n\n throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);\n}\n\n/**\n * Get the crypto object from the global scope.\n *\n * @returns The crypto object\n * @throws Error if crypto API is not available\n */\nfunction getCrypto(): Crypto {\n const cryptoObj = globalThis.crypto as Crypto | undefined;\n if (!cryptoObj) {\n throw new Error(\"Crypto API not available\");\n }\n return cryptoObj;\n}\n\n/**\n * Create a random 32-byte nonce for EIP-3009 authorization.\n *\n * @returns A hex-encoded 32-byte nonce\n */\nexport function createNonce(): `0x${string}` {\n return toHex(getCrypto().getRandomValues(new Uint8Array(32)));\n}\n\n/**\n * Creates a random 256-bit nonce for Permit2.\n * Permit2 uses uint256 nonces (not bytes32 like EIP-3009).\n *\n * @returns A string representation of the random nonce\n */\nexport function createPermit2Nonce(): string {\n const randomBytes = getCrypto().getRandomValues(new Uint8Array(32));\n return BigInt(toHex(randomBytes)).toString();\n}\n","export { ExactEvmSchemeV1 } from \"../exact/v1\";\n\nexport const EVM_NETWORK_CHAIN_ID_MAP = {\n ethereum: 1,\n sepolia: 11155111,\n abstract: 2741,\n \"abstract-testnet\": 11124,\n \"base-sepolia\": 84532,\n base: 8453,\n \"avalanche-fuji\": 43113,\n avalanche: 43114,\n iotex: 4689,\n sei: 1329,\n \"sei-testnet\": 1328,\n polygon: 137,\n \"polygon-amoy\": 80002,\n peaq: 3338,\n story: 1514,\n educhain: 41923,\n \"skale-base-sepolia\": 324705682,\n megaeth: 4326,\n monad: 143,\n} as const;\n\nexport type EvmNetworkV1 = keyof typeof EVM_NETWORK_CHAIN_ID_MAP;\n\nexport const NETWORKS: string[] = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);\n\n/**\n * Extract chain ID from a v1 legacy network name.\n *\n * @param network - The v1 network name (e.g., \"base-sepolia\", \"polygon\")\n * @returns The numeric chain ID\n * @throws Error if the network name is not a known v1 network\n */\nexport function getEvmChainIdV1(network: string): number {\n const chainId = EVM_NETWORK_CHAIN_ID_MAP[network as EvmNetworkV1];\n if (!chainId) {\n throw new Error(`Unsupported v1 network: ${network}`);\n }\n return chainId;\n}\n","/**\n * Named error reason constants for the exact EVM facilitator.\n *\n * These strings must be character-for-character identical to the Go constants in\n * go/mechanisms/evm/exact/facilitator/errors.go to maintain cross-SDK parity.\n */\n\nexport const ErrInvalidScheme = \"invalid_exact_evm_scheme\";\nexport const ErrNetworkMismatch = \"invalid_exact_evm_network_mismatch\";\nexport const ErrMissingEip712Domain = \"invalid_exact_evm_missing_eip712_domain\";\nexport const ErrRecipientMismatch = \"invalid_exact_evm_recipient_mismatch\";\nexport const ErrInvalidSignature = \"invalid_exact_evm_signature\";\nexport const ErrValidBeforeExpired = \"invalid_exact_evm_payload_authorization_valid_before\";\nexport const ErrValidAfterInFuture = \"invalid_exact_evm_payload_authorization_valid_after\";\nexport const ErrInvalidAuthorizationValue = \"invalid_exact_evm_authorization_value\";\nexport const ErrUndeployedSmartWallet = \"invalid_exact_evm_payload_undeployed_smart_wallet\";\nexport const ErrTransactionFailed = \"invalid_exact_evm_transaction_failed\";\n\n// EIP-3009 verify errors\nexport const ErrEip3009TokenNameMismatch = \"invalid_exact_evm_token_name_mismatch\";\nexport const ErrEip3009TokenVersionMismatch = \"invalid_exact_evm_token_version_mismatch\";\nexport const ErrEip3009NotSupported = \"invalid_exact_evm_eip3009_not_supported\";\nexport const ErrEip3009NonceAlreadyUsed = \"invalid_exact_evm_nonce_already_used\";\nexport const ErrEip3009InsufficientBalance = \"invalid_exact_evm_insufficient_balance\";\nexport const ErrEip3009SimulationFailed = \"invalid_exact_evm_transaction_simulation_failed\";\n\n// Permit2 verify errors\nexport const ErrPermit2InvalidSpender = \"invalid_permit2_spender\";\nexport const ErrPermit2RecipientMismatch = \"invalid_permit2_recipient_mismatch\";\nexport const ErrPermit2DeadlineExpired = \"permit2_deadline_expired\";\nexport const ErrPermit2NotYetValid = \"permit2_not_yet_valid\";\nexport const ErrPermit2AmountMismatch = \"permit2_amount_mismatch\";\nexport const ErrPermit2TokenMismatch = \"permit2_token_mismatch\";\nexport const ErrPermit2InvalidSignature = \"invalid_permit2_signature\";\nexport const ErrPermit2AllowanceRequired = \"permit2_allowance_required\";\nexport const ErrPermit2SimulationFailed = \"permit2_simulation_failed\";\nexport const ErrPermit2InsufficientBalance = \"permit2_insufficient_balance\";\nexport const ErrPermit2ProxyNotDeployed = \"permit2_proxy_not_deployed\";\n\n// Permit2 settle errors (from contract reverts)\nexport const ErrPermit2InvalidAmount = \"permit2_invalid_amount\";\nexport const ErrPermit2InvalidDestination = \"permit2_invalid_destination\";\nexport const ErrPermit2InvalidOwner = \"permit2_invalid_owner\";\nexport const ErrPermit2PaymentTooEarly = \"permit2_payment_too_early\";\nexport const ErrPermit2InvalidNonce = \"permit2_invalid_nonce\";\nexport const ErrPermit2612AmountMismatch = \"permit2_2612_amount_mismatch\";\n\n// ERC-20 approval gas sponsoring verify errors\nexport const ErrErc20ApprovalInsufficientEthForGas = \"erc20_approval_insufficient_eth_for_gas\";\nexport const ErrErc20ApprovalInvalidFormat = \"invalid_erc20_approval_extension_format\";\nexport const ErrErc20ApprovalFromMismatch = \"erc20_approval_from_mismatch\";\nexport const ErrErc20ApprovalAssetMismatch = \"erc20_approval_asset_mismatch\";\nexport const ErrErc20ApprovalSpenderNotPermit2 = \"erc20_approval_spender_not_permit2\";\nexport const ErrErc20ApprovalTxWrongTarget = \"erc20_approval_tx_wrong_target\";\nexport const ErrErc20ApprovalTxWrongSelector = \"erc20_approval_tx_wrong_selector\";\nexport const ErrErc20ApprovalTxWrongSpender = \"erc20_approval_tx_wrong_spender\";\nexport const ErrErc20ApprovalTxInvalidCalldata = \"erc20_approval_tx_invalid_calldata\";\nexport const ErrErc20ApprovalTxSignerMismatch = \"erc20_approval_tx_signer_mismatch\";\nexport const ErrErc20ApprovalTxInvalidSignature = \"erc20_approval_tx_invalid_signature\";\nexport const ErrErc20ApprovalTxParseFailed = \"erc20_approval_tx_parse_failed\";\nexport const ErrErc20ApprovalTxFailed = \"erc20_approval_tx_failed\";\n\n// EIP-2612 gas sponsoring verify errors\nexport const ErrInvalidEip2612ExtensionFormat = \"invalid_eip2612_extension_format\";\nexport const ErrEip2612FromMismatch = \"eip2612_from_mismatch\";\nexport const ErrEip2612AssetMismatch = \"eip2612_asset_mismatch\";\nexport const ErrEip2612SpenderNotPermit2 = \"eip2612_spender_not_permit2\";\nexport const ErrEip2612DeadlineExpired = \"eip2612_deadline_expired\";\n\n// Shared settle errors\nexport const ErrUnsupportedPayloadType = \"unsupported_payload_type\";\nexport const ErrInvalidTransactionState = \"invalid_transaction_state\";\n","import { PaymentRequirements, VerifyResponse } from \"@x402/core/types\";\nimport { encodeFunctionData, getAddress, Hex, parseErc6492Signature, parseSignature } from \"viem\";\nimport { eip3009ABI } from \"../../constants\";\nimport { multicall, ContractCall, RawContractCall } from \"../../multicall\";\nimport { FacilitatorEvmSigner } from \"../../signer\";\nimport { ExactEIP3009Payload } from \"../../types\";\nimport * as Errors from \"./errors\";\n\nexport interface Eip6492Deployment {\n factoryAddress: `0x${string}`;\n factoryCalldata: `0x${string}`;\n}\n\n/**\n * Simulates transferWithAuthorization via eth_call.\n * Returns true if simulation succeeded, false if it failed.\n *\n * @param signer - EVM signer for contract reads\n * @param erc20Address - ERC-20 token contract address\n * @param payload - EIP-3009 transfer authorization payload\n * @param eip6492Deployment - Optional EIP-6492 factory info for undeployed smart wallets\n *\n * @returns true if simulation succeeded, false if it failed\n */\nexport async function simulateEip3009Transfer(\n signer: FacilitatorEvmSigner,\n erc20Address: `0x${string}`,\n payload: ExactEIP3009Payload,\n eip6492Deployment?: Eip6492Deployment,\n): Promise<boolean> {\n const auth = payload.authorization;\n const transferArgs = [\n getAddress(auth.from),\n getAddress(auth.to),\n BigInt(auth.value),\n BigInt(auth.validAfter),\n BigInt(auth.validBefore),\n auth.nonce,\n ] as const;\n\n if (eip6492Deployment) {\n const { signature: innerSignature } = parseErc6492Signature(payload.signature!);\n const transferCalldata = encodeFunctionData({\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [...transferArgs, innerSignature],\n });\n\n try {\n const results = await multicall(signer.readContract.bind(signer), [\n {\n address: getAddress(eip6492Deployment.factoryAddress),\n callData: eip6492Deployment.factoryCalldata,\n } satisfies RawContractCall,\n {\n address: erc20Address,\n callData: transferCalldata,\n } satisfies RawContractCall,\n ]);\n\n return results[1]?.status === \"success\";\n } catch {\n return false;\n }\n }\n\n const sig = payload.signature!;\n const sigLength = sig.startsWith(\"0x\") ? sig.length - 2 : sig.length;\n const isECDSA = sigLength === 130;\n\n try {\n if (isECDSA) {\n const parsedSig = parseSignature(sig);\n await signer.readContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n ...transferArgs,\n (parsedSig.v as number | undefined) ?? parsedSig.yParity,\n parsedSig.r,\n parsedSig.s,\n ],\n });\n } else {\n await signer.readContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [...transferArgs, sig],\n });\n }\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * After simulation fails, runs a single diagnostic multicall to determine the most specific error reason.\n * Checks balanceOf, name, version and authorizationState in one RPC round-trip.\n *\n * @param signer - EVM signer used for the payment\n * @param erc20Address - Address of the ERC-20 token contract\n * @param payload - The EIP-3009 transfer authorization payload\n * @param requirements - Payment requirements to validate against\n * @param amountRequired - Required amount for the payment (balance check)\n *\n * @returns Promise resolving to the verification result with validity and optional invalid reason\n */\nexport async function diagnoseEip3009SimulationFailure(\n signer: FacilitatorEvmSigner,\n erc20Address: `0x${string}`,\n payload: ExactEIP3009Payload,\n requirements: PaymentRequirements,\n amountRequired: string,\n): Promise<VerifyResponse> {\n const payer = payload.authorization.from;\n\n const diagnosticCalls: ContractCall[] = [\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"balanceOf\",\n args: [payload.authorization.from],\n },\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"name\",\n },\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"version\",\n },\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"authorizationState\",\n args: [payload.authorization.from, payload.authorization.nonce],\n },\n ];\n\n try {\n const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);\n\n const [balanceResult, nameResult, versionResult, authStateResult] = results;\n\n if (authStateResult.status === \"failure\") {\n return { isValid: false, invalidReason: Errors.ErrEip3009NotSupported, payer };\n }\n\n if (authStateResult.status === \"success\" && authStateResult.result === true) {\n return { isValid: false, invalidReason: Errors.ErrEip3009NonceAlreadyUsed, payer };\n }\n\n if (\n nameResult.status === \"success\" &&\n requirements.extra?.name &&\n nameResult.result !== requirements.extra.name\n ) {\n return { isValid: false, invalidReason: Errors.ErrEip3009TokenNameMismatch, payer };\n }\n\n if (\n versionResult.status === \"success\" &&\n requirements.extra?.version &&\n versionResult.result !== requirements.extra.version\n ) {\n return { isValid: false, invalidReason: Errors.ErrEip3009TokenVersionMismatch, payer };\n }\n\n if (balanceResult.status === \"success\") {\n const balance = balanceResult.result as bigint;\n if (balance < BigInt(amountRequired)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrEip3009InsufficientBalance,\n payer,\n };\n }\n }\n } catch {\n // Diagnostic multicall failed — fall through to generic error\n }\n\n return { isValid: false, invalidReason: Errors.ErrEip3009SimulationFailed, payer };\n}\n\n/**\n * Executes transferWithAuthorization onchain.\n *\n * @param signer - EVM signer for contract writes\n * @param erc20Address - ERC-20 token contract address\n * @param payload - EIP-3009 transfer authorization payload\n *\n * @returns Transaction hash\n */\nexport async function executeTransferWithAuthorization(\n signer: FacilitatorEvmSigner,\n erc20Address: `0x${string}`,\n payload: ExactEIP3009Payload,\n): Promise<Hex> {\n const { signature } = parseErc6492Signature(payload.signature!);\n const signatureLength = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n const isECDSA = signatureLength === 130;\n\n const auth = payload.authorization;\n const baseArgs = [\n getAddress(auth.from),\n getAddress(auth.to),\n BigInt(auth.value),\n BigInt(auth.validAfter),\n BigInt(auth.validBefore),\n auth.nonce,\n ] as const;\n\n if (isECDSA) {\n const parsedSig = parseSignature(signature);\n return signer.writeContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n ...baseArgs,\n (parsedSig.v as number | undefined) || parsedSig.yParity,\n parsedSig.r,\n parsedSig.s,\n ],\n });\n }\n\n return signer.writeContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [...baseArgs, signature],\n });\n}\n","import { encodeFunctionData, decodeFunctionResult } from \"viem\";\n\n/**\n * Multicall3 contract address.\n * Same address on all EVM chains via CREATE2 deployment.\n *\n * @see https://github.com/mds1/multicall\n */\nexport const MULTICALL3_ADDRESS = \"0xcA11bde05977b3631167028862bE2a173976CA11\" as const;\n\n/** Multicall3 getEthBalance ABI for querying native token balance. */\nexport const multicall3GetEthBalanceAbi = [\n {\n name: \"getEthBalance\",\n inputs: [{ name: \"addr\", type: \"address\" }],\n outputs: [{ name: \"balance\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/** Multicall3 tryAggregate ABI for batching calls. */\nconst multicall3ABI = [\n {\n inputs: [\n { name: \"requireSuccess\", type: \"bool\" },\n {\n name: \"calls\",\n type: \"tuple[]\",\n components: [\n { name: \"target\", type: \"address\" },\n { name: \"callData\", type: \"bytes\" },\n ],\n },\n ],\n name: \"tryAggregate\",\n outputs: [\n {\n name: \"returnData\",\n type: \"tuple[]\",\n components: [\n { name: \"success\", type: \"bool\" },\n { name: \"returnData\", type: \"bytes\" },\n ],\n },\n ],\n stateMutability: \"payable\",\n type: \"function\",\n },\n] as const;\n\nexport type ContractCall = {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n};\n\nexport type RawContractCall = {\n address: `0x${string}`;\n callData: `0x${string}`;\n};\n\nexport type MulticallSuccess = { status: \"success\"; result: unknown };\nexport type MulticallFailure = { status: \"failure\"; error: Error };\nexport type MulticallResult = MulticallSuccess | MulticallFailure;\n\n/**\n * Batches contract calls via Multicall3 `tryAggregate(false, ...)`.\n *\n * Accepts a mix of typed ContractCall (ABI-encoded + decoded) and\n * RawContractCall (pre-encoded calldata, no decoding) entries.\n * Raw calls are useful for the EIP-6492 factory deployment case\n * where calldata is pre-encoded with no ABI available.\n */\ntype ReadContractFn = (args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n}) => Promise<unknown>;\n\n/**\n * Executes multiple contract read calls in a single RPC round-trip using Multicall3.\n *\n * @param readContract - Function that performs a single contract read (e.g. viem readContract)\n * @param calls - Array of contract calls to batch (ContractCall or RawContractCall)\n * @returns A promise that resolves to an array of decoded results, one per call\n */\nexport async function multicall(\n readContract: ReadContractFn,\n calls: ReadonlyArray<ContractCall | RawContractCall>,\n): Promise<MulticallResult[]> {\n const aggregateCalls = calls.map(call => {\n if (\"callData\" in call) {\n return { target: call.address, callData: call.callData };\n }\n const callData = encodeFunctionData({\n abi: call.abi,\n functionName: call.functionName,\n args: call.args as unknown[],\n });\n return { target: call.address, callData };\n });\n\n const rawResults = (await readContract({\n address: MULTICALL3_ADDRESS,\n abi: multicall3ABI,\n functionName: \"tryAggregate\",\n args: [false, aggregateCalls],\n })) as { success: boolean; returnData: `0x${string}` }[];\n\n return rawResults.map((raw, i) => {\n if (!raw.success) {\n return {\n status: \"failure\" as const,\n error: new Error(`multicall: call reverted (returnData: ${raw.returnData})`),\n };\n }\n\n const call = calls[i];\n if (\"callData\" in call) {\n return { status: \"success\" as const, result: undefined };\n }\n\n try {\n const decoded = decodeFunctionResult({\n abi: call.abi,\n functionName: call.functionName,\n data: raw.returnData,\n });\n return { status: \"success\" as const, result: decoded };\n } catch (err) {\n return {\n status: \"failure\" as const,\n error: err instanceof Error ? err : new Error(String(err)),\n };\n }\n });\n}\n"],"mappings":"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","names":["ExactEvmSchemeV1","import_viem","import_viem","import_viem","import_viem","ExactEvmSchemeV1"]}

@@ -1,3 +0,3 @@

export { E as ExactEvmScheme, a as PERMIT2_ADDRESS, P as Permit2AllowanceParams, d as authorizationTypes, c as createPermit2ApprovalTx, f as eip3009ABI, e as erc20AllowanceAbi, g as getPermit2AllowanceReadParams, p as permit2WitnessTypes, h as x402ExactPermit2ProxyABI, x as x402ExactPermit2ProxyAddress, b as x402UptoPermit2ProxyAddress } from './permit2-DHAq6FTe.js';
export { C as ClientEvmSigner, F as FacilitatorEvmSigner, t as toClientEvmSigner, a as toFacilitatorEvmSigner } from './signer-DC81R8wQ.js';
export { E as ExactEvmScheme, a as PERMIT2_ADDRESS, P as Permit2AllowanceParams, d as authorizationTypes, c as createPermit2ApprovalTx, f as eip3009ABI, e as erc20AllowanceAbi, g as getPermit2AllowanceReadParams, p as permit2WitnessTypes, h as x402ExactPermit2ProxyABI, x as x402ExactPermit2ProxyAddress, b as x402UptoPermit2ProxyAddress } from './permit2-U9Zolx3O.js';
export { C as ClientEvmSigner, F as FacilitatorEvmSigner, t as toClientEvmSigner, a as toFacilitatorEvmSigner } from './signer-D912R4mq.js';
import '@x402/core/types';

@@ -4,0 +4,0 @@

@@ -41,5 +41,2 @@ "use strict";

// src/exact/client/scheme.ts
var import_extensions2 = require("@x402/extensions");
// src/constants.ts

@@ -119,2 +116,19 @@ var authorizationTypes = {

type: "function"
},
{
inputs: [],
name: "name",
outputs: [{ name: "", type: "string" }],
stateMutability: "view",
type: "function"
},
{
inputs: [
{ name: "authorizer", type: "address" },
{ name: "nonce", type: "bytes32" }
],
name: "authorizationState",
outputs: [{ name: "", type: "bool" }],
stateMutability: "view",
type: "function"
}

@@ -288,3 +302,3 @@ ];

// src/exact/client/scheme.ts
var import_viem6 = require("viem");
var import_viem7 = require("viem");

@@ -319,2 +333,7 @@ // src/utils.ts

// src/exact/extensions.ts
var EIP2612_GAS_SPONSORING_KEY = "eip2612GasSponsoring";
var ERC20_APPROVAL_GAS_SPONSORING_KEY = "erc20ApprovalGasSponsoring";
var ERC20_APPROVAL_GAS_SPONSORING_VERSION = "1";
// src/exact/client/eip3009.ts

@@ -501,3 +520,2 @@ var import_viem2 = require("viem");

var import_viem5 = require("viem");
var import_extensions = require("@x402/extensions");
async function signErc20ApprovalTransaction(signer, tokenAddress, chainId) {

@@ -515,3 +533,6 @@ const from = signer.address;

try {
const fees = await signer.estimateFeesPerGas();
const fees = await signer.estimateFeesPerGas?.();
if (!fees) {
throw new Error("no fee estimates available");
}
maxFeePerGas = fees.maxFeePerGas;

@@ -538,6 +559,63 @@ maxPriorityFeePerGas = fees.maxPriorityFeePerGas;

signedTransaction,
version: import_extensions.ERC20_APPROVAL_GAS_SPONSORING_VERSION
version: ERC20_APPROVAL_GAS_SPONSORING_VERSION
};
}
// src/exact/client/rpc.ts
var import_viem6 = require("viem");
var rpcClientCache = /* @__PURE__ */ new Map();
function isConfigByChainId(options) {
const keys = Object.keys(options);
return keys.length > 0 && keys.every((key) => /^\d+$/.test(key));
}
function getRpcClient(rpcUrl) {
const existing = rpcClientCache.get(rpcUrl);
if (existing) {
return existing;
}
const client = (0, import_viem6.createPublicClient)({
transport: (0, import_viem6.http)(rpcUrl)
});
rpcClientCache.set(rpcUrl, client);
return client;
}
function resolveRpcUrl(network, options) {
if (!options) {
return void 0;
}
if (isConfigByChainId(options)) {
const chainId = getEvmChainId(network);
const optionsByChainId = options;
return optionsByChainId[chainId]?.rpcUrl;
}
return options.rpcUrl;
}
function resolveExtensionRpcCapabilities(network, signer, options) {
const capabilities = {
signTransaction: signer.signTransaction,
readContract: signer.readContract,
getTransactionCount: signer.getTransactionCount,
estimateFeesPerGas: signer.estimateFeesPerGas
};
const needsRpcBackfill = !capabilities.readContract || !capabilities.getTransactionCount || !capabilities.estimateFeesPerGas;
if (!needsRpcBackfill) {
return capabilities;
}
const rpcUrl = resolveRpcUrl(network, options);
if (!rpcUrl) {
return capabilities;
}
const rpcClient = getRpcClient(rpcUrl);
if (!capabilities.readContract) {
capabilities.readContract = (args) => rpcClient.readContract(args);
}
if (!capabilities.getTransactionCount) {
capabilities.getTransactionCount = async (args) => rpcClient.getTransactionCount({ address: args.address });
}
if (!capabilities.estimateFeesPerGas) {
capabilities.estimateFeesPerGas = async () => rpcClient.estimateFeesPerGas();
}
return capabilities;
}
// src/exact/client/scheme.ts

@@ -549,7 +627,10 @@ var ExactEvmScheme = class {

* @param signer - The EVM signer for client operations.
* Must support `readContract` for EIP-2612 gas sponsoring.
* Use `createWalletClient(...).extend(publicActions)` or `toClientEvmSigner(account, publicClient)`.
* Base flow only requires `address` + `signTypedData`.
* Extension enrichment (EIP-2612 / ERC-20 approval sponsoring) additionally
* requires optional capabilities like `readContract` and tx signing helpers.
* @param options - Optional RPC configuration used to backfill extension capabilities.
*/
constructor(signer) {
constructor(signer, options) {
this.signer = signer;
this.options = options;
this.scheme = "exact";

@@ -612,5 +693,13 @@ }

async trySignEip2612Permit(requirements, result, context) {
if (!context?.extensions?.[import_extensions2.EIP2612_GAS_SPONSORING.key]) {
const capabilities = resolveExtensionRpcCapabilities(
requirements.network,
this.signer,
this.options
);
if (!capabilities.readContract) {
return void 0;
}
if (!context?.extensions?.[EIP2612_GAS_SPONSORING_KEY]) {
return void 0;
}
const tokenName = requirements.extra?.name;

@@ -622,5 +711,5 @@ const tokenVersion = requirements.extra?.version;

const chainId = getEvmChainId(requirements.network);
const tokenAddress = (0, import_viem6.getAddress)(requirements.asset);
const tokenAddress = (0, import_viem7.getAddress)(requirements.asset);
try {
const allowance = await this.signer.readContract({
const allowance = await capabilities.readContract({
address: tokenAddress,

@@ -639,3 +728,7 @@ abi: erc20AllowanceAbi,

const info = await signEip2612Permit(
this.signer,
{
address: this.signer.address,
signTypedData: (msg) => this.signer.signTypedData(msg),
readContract: capabilities.readContract
},
tokenAddress,

@@ -649,3 +742,3 @@ tokenName,

return {
[import_extensions2.EIP2612_GAS_SPONSORING.key]: { info }
[EIP2612_GAS_SPONSORING_KEY]: { info }
};

@@ -673,12 +766,20 @@ }

async trySignErc20Approval(requirements, _result, context) {
if (!context?.extensions?.[import_extensions2.ERC20_APPROVAL_GAS_SPONSORING.key]) {
const capabilities = resolveExtensionRpcCapabilities(
requirements.network,
this.signer,
this.options
);
if (!capabilities.readContract) {
return void 0;
}
if (!this.signer.signTransaction || !this.signer.getTransactionCount) {
if (!context?.extensions?.[ERC20_APPROVAL_GAS_SPONSORING_KEY]) {
return void 0;
}
if (!capabilities.signTransaction || !capabilities.getTransactionCount) {
return void 0;
}
const chainId = getEvmChainId(requirements.network);
const tokenAddress = (0, import_viem6.getAddress)(requirements.asset);
const tokenAddress = (0, import_viem7.getAddress)(requirements.asset);
try {
const allowance = await this.signer.readContract({
const allowance = await capabilities.readContract({
address: tokenAddress,

@@ -694,5 +795,14 @@ abi: erc20AllowanceAbi,

}
const info = await signErc20ApprovalTransaction(this.signer, tokenAddress, chainId);
const info = await signErc20ApprovalTransaction(
{
address: this.signer.address,
signTransaction: capabilities.signTransaction,
getTransactionCount: capabilities.getTransactionCount,
estimateFeesPerGas: capabilities.estimateFeesPerGas
},
tokenAddress,
chainId
);
return {
[import_extensions2.ERC20_APPROVAL_GAS_SPONSORING.key]: { info }
[ERC20_APPROVAL_GAS_SPONSORING_KEY]: { info }
};

@@ -703,7 +813,13 @@ }

// src/exact/v1/client/scheme.ts
var import_viem8 = require("viem");
var import_viem11 = require("viem");
// src/exact/v1/facilitator/scheme.ts
var import_viem7 = require("viem");
var import_viem10 = require("viem");
// src/exact/facilitator/eip3009-utils.ts
var import_viem9 = require("viem");
// src/multicall.ts
var import_viem8 = require("viem");
// src/v1/index.ts

@@ -736,12 +852,9 @@ var EVM_NETWORK_CHAIN_ID_MAP = {

const readContract = signer.readContract ?? publicClient?.readContract.bind(publicClient);
if (!readContract) {
throw new Error(
"toClientEvmSigner requires either a signer with readContract or a publicClient. Use createWalletClient(...).extend(publicActions) or pass a publicClient."
);
}
const result = {
address: signer.address,
signTypedData: (msg) => signer.signTypedData(msg),
readContract
signTypedData: (msg) => signer.signTypedData(msg)
};
if (readContract) {
result.readContract = readContract;
}
const signTransaction = signer.signTransaction;

@@ -748,0 +861,0 @@ if (signTransaction) {

export { ExactEvmSchemeV1 } from '../exact/v1/client/index.js';
import '@x402/core/types';
import '../signer-DC81R8wQ.js';
import '../signer-D912R4mq.js';

@@ -5,0 +5,0 @@ declare const EVM_NETWORK_CHAIN_ID_MAP: {

@@ -140,2 +140,8 @@ "use strict";

// src/exact/v1/facilitator/scheme.ts
var import_viem5 = require("viem");
// src/exact/facilitator/eip3009-utils.ts
var import_viem4 = require("viem");
// src/multicall.ts
var import_viem3 = require("viem");

@@ -142,0 +148,0 @@

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../../src/v1/index.ts","../../../src/exact/v1/client/scheme.ts","../../../src/constants.ts","../../../src/utils.ts","../../../src/exact/v1/facilitator/scheme.ts"],"sourcesContent":["export { ExactEvmSchemeV1 } from \"../exact/v1\";\n\nexport const EVM_NETWORK_CHAIN_ID_MAP = {\n ethereum: 1,\n sepolia: 11155111,\n abstract: 2741,\n \"abstract-testnet\": 11124,\n \"base-sepolia\": 84532,\n base: 8453,\n \"avalanche-fuji\": 43113,\n avalanche: 43114,\n iotex: 4689,\n sei: 1329,\n \"sei-testnet\": 1328,\n polygon: 137,\n \"polygon-amoy\": 80002,\n peaq: 3338,\n story: 1514,\n educhain: 41923,\n \"skale-base-sepolia\": 324705682,\n megaeth: 4326,\n monad: 143,\n} as const;\n\nexport type EvmNetworkV1 = keyof typeof EVM_NETWORK_CHAIN_ID_MAP;\n\nexport const NETWORKS: string[] = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);\n\n/**\n * Extract chain ID from a v1 legacy network name.\n *\n * @param network - The v1 network name (e.g., \"base-sepolia\", \"polygon\")\n * @returns The numeric chain ID\n * @throws Error if the network name is not a known v1 network\n */\nexport function getEvmChainIdV1(network: string): number {\n const chainId = EVM_NETWORK_CHAIN_ID_MAP[network as EvmNetworkV1];\n if (!chainId) {\n throw new Error(`Unsupported v1 network: ${network}`);\n }\n return chainId;\n}\n","import {\n Network,\n PaymentPayload,\n PaymentRequirements,\n SchemeNetworkClient,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress } from \"viem\";\nimport { authorizationTypes } from \"../../../constants\";\nimport { ClientEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { createNonce } from \"../../../utils\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\n\n/**\n * EVM client implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkClient {\n readonly scheme = \"exact\";\n\n /**\n * Creates a new ExactEvmClientV1 instance.\n *\n * @param signer - The EVM signer for client operations\n */\n constructor(private readonly signer: ClientEvmSigner) {}\n\n /**\n * Creates a payment payload for the Exact scheme (V1).\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n ): Promise<\n Pick<PaymentPayload, \"x402Version\" | \"payload\"> & { scheme: string; network: Network }\n > {\n const selectedV1 = paymentRequirements as unknown as PaymentRequirementsV1;\n const nonce = createNonce();\n const now = Math.floor(Date.now() / 1000);\n\n const authorization: ExactEvmPayloadV1[\"authorization\"] = {\n from: this.signer.address,\n to: getAddress(selectedV1.payTo),\n value: selectedV1.maxAmountRequired,\n validAfter: (now - 600).toString(), // 10 minutes before\n validBefore: (now + selectedV1.maxTimeoutSeconds).toString(),\n nonce,\n };\n\n // Sign the authorization\n const signature = await this.signAuthorization(authorization, selectedV1);\n\n const payload: ExactEvmPayloadV1 = {\n authorization,\n signature,\n };\n\n return {\n x402Version,\n scheme: selectedV1.scheme,\n network: selectedV1.network,\n payload,\n };\n }\n\n /**\n * Sign the EIP-3009 authorization using EIP-712\n *\n * @param authorization - The authorization to sign\n * @param requirements - The payment requirements\n * @returns Promise resolving to the signature\n */\n private async signAuthorization(\n authorization: ExactEvmPayloadV1[\"authorization\"],\n requirements: PaymentRequirementsV1,\n ): Promise<`0x${string}`> {\n const chainId = getEvmChainIdV1(requirements.network as EvmNetworkV1);\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`,\n );\n }\n\n const { name, version } = requirements.extra;\n\n const domain = {\n name,\n version,\n chainId,\n verifyingContract: getAddress(requirements.asset),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return await this.signer.signTypedData({\n domain,\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\",\n message,\n });\n }\n}\n","// EIP-3009 TransferWithAuthorization types for EIP-712 signing\nexport const authorizationTypes = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\n/**\n * Permit2 EIP-712 types for signing PermitWitnessTransferFrom.\n * Must match the exact format expected by the Permit2 contract.\n * Note: Types must be in ALPHABETICAL order after the primary type (TokenPermissions < Witness).\n */\nexport const permit2WitnessTypes = {\n PermitWitnessTransferFrom: [\n { name: \"permitted\", type: \"TokenPermissions\" },\n { name: \"spender\", type: \"address\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n { name: \"witness\", type: \"Witness\" },\n ],\n TokenPermissions: [\n { name: \"token\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n Witness: [\n { name: \"to\", type: \"address\" },\n { name: \"validAfter\", type: \"uint256\" },\n ],\n} as const;\n\n// EIP3009 ABI for transferWithAuthorization function\nexport const eip3009ABI = [\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"v\", type: \"uint8\" },\n { name: \"r\", type: \"bytes32\" },\n { name: \"s\", type: \"bytes32\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"signature\", type: \"bytes\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [{ name: \"account\", type: \"address\" }],\n name: \"balanceOf\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"version\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/**\n * EIP-2612 Permit EIP-712 types for signing token.permit().\n */\nexport const eip2612PermitTypes = {\n Permit: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * EIP-2612 nonces ABI for querying current nonce.\n */\nexport const eip2612NoncesAbi = [\n {\n type: \"function\",\n name: \"nonces\",\n inputs: [{ name: \"owner\", type: \"address\" }],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** ERC-20 approve(address,uint256) ABI for encoding/decoding approval calldata. */\nexport const erc20ApproveAbi = [\n {\n type: \"function\",\n name: \"approve\",\n inputs: [\n { name: \"spender\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n outputs: [{ type: \"bool\" }],\n stateMutability: \"nonpayable\",\n },\n] as const;\n\n/** ERC-20 allowance(address,address) ABI for checking spender approval. */\nexport const erc20AllowanceAbi = [\n {\n type: \"function\",\n name: \"allowance\",\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n ],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** Gas limit for a standard ERC-20 approve() transaction. */\nexport const ERC20_APPROVE_GAS_LIMIT = 70_000n;\n\n/** Fallback max fee per gas (1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_FEE_PER_GAS = 1_000_000_000n;\n\n/** Fallback max priority fee per gas (0.1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100_000_000n;\n\n/**\n * Canonical Permit2 contract address.\n * Same address on all EVM chains via CREATE2 deployment.\n *\n * @see https://github.com/Uniswap/permit2\n */\nexport const PERMIT2_ADDRESS = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\" as const;\n\n/**\n * x402ExactPermit2Proxy contract address.\n * Vanity address: 0x4020...0001 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0001\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402ExactPermit2ProxyAddress = \"0x402085c248EeA27D92E8b30b2C58ed07f9E20001\" as const;\n\n/**\n * x402UptoPermit2Proxy contract address.\n * Vanity address: 0x4020...0002 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0002\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402UptoPermit2ProxyAddress = \"0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002\" as const;\n\n/**\n * Shared ABI components for the Permit2 witness tuple.\n * Used in both x402ExactPermit2ProxyABI and x402UptoPermit2ProxyABI to keep them in sync.\n * The upto contract's witness struct is identical to exact (both remove 'extra' post-audit).\n */\nconst permit2WitnessABIComponents = [\n { name: \"to\", type: \"address\", internalType: \"address\" },\n { name: \"validAfter\", type: \"uint256\", internalType: \"uint256\" },\n] as const;\n\n/**\n * x402UptoPermit2Proxy ABI - settle function for upto payment scheme (variable amounts).\n * Updated post-audit: 'extra' removed from witness struct, 'initialize()' removed (now\n * a constructor arg), and error names aligned with x402ExactPermit2Proxy.\n */\nexport const x402UptoPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n\n/**\n * x402ExactPermit2Proxy ABI - settle function for exact payment scheme.\n */\nexport const x402ExactPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n","import { toHex } from \"viem\";\n\n/**\n * Extract chain ID from a CAIP-2 network identifier (eip155:CHAIN_ID).\n *\n * @param network - The network identifier in CAIP-2 format (e.g., \"eip155:8453\")\n * @returns The numeric chain ID\n * @throws Error if the network format is invalid\n */\nexport function getEvmChainId(network: string): number {\n if (network.startsWith(\"eip155:\")) {\n const idStr = network.split(\":\")[1];\n const chainId = parseInt(idStr, 10);\n if (isNaN(chainId)) {\n throw new Error(`Invalid CAIP-2 chain ID: ${network}`);\n }\n return chainId;\n }\n\n throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);\n}\n\n/**\n * Get the crypto object from the global scope.\n *\n * @returns The crypto object\n * @throws Error if crypto API is not available\n */\nfunction getCrypto(): Crypto {\n const cryptoObj = globalThis.crypto as Crypto | undefined;\n if (!cryptoObj) {\n throw new Error(\"Crypto API not available\");\n }\n return cryptoObj;\n}\n\n/**\n * Create a random 32-byte nonce for EIP-3009 authorization.\n *\n * @returns A hex-encoded 32-byte nonce\n */\nexport function createNonce(): `0x${string}` {\n return toHex(getCrypto().getRandomValues(new Uint8Array(32)));\n}\n\n/**\n * Creates a random 256-bit nonce for Permit2.\n * Permit2 uses uint256 nonces (not bytes32 like EIP-3009).\n *\n * @returns A string representation of the random nonce\n */\nexport function createPermit2Nonce(): string {\n const randomBytes = getCrypto().getRandomValues(new Uint8Array(32));\n return BigInt(toHex(randomBytes)).toString();\n}\n","import {\n PaymentPayload,\n PaymentPayloadV1,\n PaymentRequirements,\n SchemeNetworkFacilitator,\n SettleResponse,\n VerifyResponse,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress, Hex, isAddressEqual, parseErc6492Signature, parseSignature } from \"viem\";\nimport { authorizationTypes, eip3009ABI } from \"../../../constants\";\nimport { FacilitatorEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\n\nexport interface ExactEvmSchemeV1Config {\n /**\n * If enabled, the facilitator will deploy ERC-4337 smart wallets\n * via EIP-6492 when encountering undeployed contract signatures.\n *\n * @default false\n */\n deployERC4337WithEIP6492?: boolean;\n}\n\n/**\n * EVM facilitator implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkFacilitator {\n readonly scheme = \"exact\";\n readonly caipFamily = \"eip155:*\";\n private readonly config: Required<ExactEvmSchemeV1Config>;\n\n /**\n * Creates a new ExactEvmFacilitatorV1 instance.\n *\n * @param signer - The EVM signer for facilitator operations\n * @param config - Optional configuration for the facilitator\n */\n constructor(\n private readonly signer: FacilitatorEvmSigner,\n config?: ExactEvmSchemeV1Config,\n ) {\n this.config = {\n deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,\n };\n }\n\n /**\n * Get mechanism-specific extra data for the supported kinds endpoint.\n * For EVM, no extra data is needed.\n *\n * @param _ - The network identifier (unused for EVM)\n * @returns undefined (EVM has no extra data)\n */\n getExtra(_: string): Record<string, unknown> | undefined {\n return undefined;\n }\n\n /**\n * Get signer addresses used by this facilitator.\n * Returns all addresses this facilitator can use for signing/settling transactions.\n *\n * @param _ - The network identifier (unused for EVM, addresses are network-agnostic)\n * @returns Array of facilitator wallet addresses\n */\n getSigners(_: string): string[] {\n return [...this.signer.getAddresses()];\n }\n\n /**\n * Verifies a payment payload (V1).\n *\n * @param payload - The payment payload to verify\n * @param requirements - The payment requirements\n * @returns Promise resolving to verification response\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n const requirementsV1 = requirements as unknown as PaymentRequirementsV1;\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n\n // Verify scheme matches\n if (payloadV1.scheme !== \"exact\" || requirements.scheme !== \"exact\") {\n return {\n isValid: false,\n invalidReason: \"unsupported_scheme\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Get chain configuration\n let chainId: number;\n try {\n chainId = getEvmChainIdV1(payloadV1.network as EvmNetworkV1);\n } catch {\n return {\n isValid: false,\n invalidReason: `invalid_network`,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n return {\n isValid: false,\n invalidReason: \"missing_eip712_domain\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n const { name, version } = requirements.extra;\n const erc20Address = getAddress(requirements.asset);\n\n // Verify network matches\n if (payloadV1.network !== requirements.network) {\n return {\n isValid: false,\n invalidReason: \"network_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Build typed data for signature verification\n const permitTypedData = {\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\" as const,\n domain: {\n name,\n version,\n chainId,\n verifyingContract: erc20Address,\n },\n message: {\n from: exactEvmPayload.authorization.from,\n to: exactEvmPayload.authorization.to,\n value: BigInt(exactEvmPayload.authorization.value),\n validAfter: BigInt(exactEvmPayload.authorization.validAfter),\n validBefore: BigInt(exactEvmPayload.authorization.validBefore),\n nonce: exactEvmPayload.authorization.nonce,\n },\n };\n\n // Verify signature\n try {\n const recoveredAddress = await this.signer.verifyTypedData({\n address: exactEvmPayload.authorization.from,\n ...permitTypedData,\n signature: exactEvmPayload.signature!,\n });\n\n if (!recoveredAddress) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n } catch {\n // Signature verification failed - could be an undeployed smart wallet\n // Check if smart wallet is deployed\n const signature = exactEvmPayload.signature!;\n const signatureLength = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n const isSmartWallet = signatureLength > 130; // 65 bytes = 130 hex chars for EOA\n\n if (isSmartWallet) {\n const payerAddress = exactEvmPayload.authorization.from;\n const bytecode = await this.signer.getCode({ address: payerAddress });\n\n if (!bytecode || bytecode === \"0x\") {\n // Wallet is not deployed. Check if it's EIP-6492 with deployment info.\n // EIP-6492 signatures contain factory address and calldata needed for deployment.\n // Non-EIP-6492 undeployed wallets cannot succeed (no way to deploy them).\n const erc6492Data = parseErc6492Signature(signature);\n const hasDeploymentInfo =\n erc6492Data.address &&\n erc6492Data.data &&\n !isAddressEqual(erc6492Data.address, \"0x0000000000000000000000000000000000000000\");\n\n if (!hasDeploymentInfo) {\n // Non-EIP-6492 undeployed smart wallet - will always fail at settlement\n // since EIP-3009 requires on-chain EIP-1271 validation\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_undeployed_smart_wallet\",\n payer: payerAddress,\n };\n }\n // EIP-6492 signature with deployment info - allow through\n // Facilitators with sponsored deployment support can handle this in settle()\n } else {\n // Wallet is deployed but signature still failed - invalid signature\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n } else {\n // EOA signature failed\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n }\n\n // Verify payment recipient matches\n if (getAddress(exactEvmPayload.authorization.to) !== getAddress(requirements.payTo)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_recipient_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Verify validBefore is in the future (with 6 second buffer for block time)\n const now = Math.floor(Date.now() / 1000);\n if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_valid_before\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Verify validAfter is not in the future\n if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_valid_after\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Check balance\n try {\n const balance = (await this.signer.readContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"balanceOf\",\n args: [exactEvmPayload.authorization.from],\n })) as bigint;\n\n if (BigInt(balance) < BigInt(requirementsV1.maxAmountRequired)) {\n return {\n isValid: false,\n invalidReason: \"insufficient_funds\",\n invalidMessage: `Insufficient funds to complete the payment. Required: ${requirementsV1.maxAmountRequired} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,\n payer: exactEvmPayload.authorization.from,\n };\n }\n } catch {\n // If we can't check balance, continue with other validations\n }\n\n // Verify amount exactly matches requirements\n if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_value_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n return {\n isValid: true,\n invalidReason: undefined,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n /**\n * Settles a payment by executing the transfer (V1).\n *\n * @param payload - The payment payload to settle\n * @param requirements - The payment requirements\n * @returns Promise resolving to settlement response\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n\n // Re-verify before settling\n const valid = await this.verify(payload, requirements);\n if (!valid.isValid) {\n return {\n success: false,\n network: payloadV1.network,\n transaction: \"\",\n errorReason: valid.invalidReason ?? \"invalid_scheme\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n try {\n // Parse ERC-6492 signature if applicable\n const parseResult = parseErc6492Signature(exactEvmPayload.signature!);\n const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;\n\n // Deploy ERC-4337 smart wallet via EIP-6492 if configured and needed\n if (\n this.config.deployERC4337WithEIP6492 &&\n factoryAddress &&\n factoryCalldata &&\n !isAddressEqual(factoryAddress, \"0x0000000000000000000000000000000000000000\")\n ) {\n // Check if smart wallet is already deployed\n const payerAddress = exactEvmPayload.authorization.from;\n const bytecode = await this.signer.getCode({ address: payerAddress });\n\n if (!bytecode || bytecode === \"0x\") {\n // Wallet not deployed - attempt deployment\n try {\n console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);\n\n // Send the factory calldata directly as a transaction\n // The factoryCalldata already contains the complete encoded function call\n const deployTx = await this.signer.sendTransaction({\n to: factoryAddress as Hex,\n data: factoryCalldata as Hex,\n });\n\n // Wait for deployment transaction\n await this.signer.waitForTransactionReceipt({ hash: deployTx });\n console.log(`Successfully deployed smart wallet for ${payerAddress}`);\n } catch (deployError) {\n console.error(\"Smart wallet deployment failed:\", deployError);\n // Deployment failed - cannot proceed\n throw deployError;\n }\n } else {\n console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);\n }\n }\n\n // Determine if this is an ECDSA signature (EOA) or smart wallet signature\n // ECDSA signatures are exactly 65 bytes (130 hex chars without 0x)\n const signatureLength = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n const isECDSA = signatureLength === 130;\n\n let tx: Hex;\n if (isECDSA) {\n // For EOA wallets, parse signature into v, r, s and use that overload\n const parsedSig = parseSignature(signature);\n\n tx = await this.signer.writeContract({\n address: getAddress(requirements.asset),\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n getAddress(exactEvmPayload.authorization.from),\n getAddress(exactEvmPayload.authorization.to),\n BigInt(exactEvmPayload.authorization.value),\n BigInt(exactEvmPayload.authorization.validAfter),\n BigInt(exactEvmPayload.authorization.validBefore),\n exactEvmPayload.authorization.nonce,\n (parsedSig.v as number | undefined) || parsedSig.yParity,\n parsedSig.r,\n parsedSig.s,\n ],\n });\n } else {\n // For smart wallets, use the bytes signature overload\n // The signature contains WebAuthn/P256 or other ERC-1271 compatible signature data\n tx = await this.signer.writeContract({\n address: getAddress(requirements.asset),\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n getAddress(exactEvmPayload.authorization.from),\n getAddress(exactEvmPayload.authorization.to),\n BigInt(exactEvmPayload.authorization.value),\n BigInt(exactEvmPayload.authorization.validAfter),\n BigInt(exactEvmPayload.authorization.validBefore),\n exactEvmPayload.authorization.nonce,\n signature,\n ],\n });\n }\n\n // Wait for transaction confirmation\n const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });\n\n if (receipt.status !== \"success\") {\n return {\n success: false,\n errorReason: \"invalid_transaction_state\",\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n return {\n success: true,\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n } catch (error) {\n console.error(\"Failed to settle transaction:\", error);\n return {\n success: false,\n errorReason: \"transaction_failed\",\n transaction: \"\",\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n }\n}\n"],"mappings":"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","names":["import_viem","import_viem"]}
{"version":3,"sources":["../../../src/v1/index.ts","../../../src/exact/v1/client/scheme.ts","../../../src/constants.ts","../../../src/utils.ts","../../../src/exact/v1/facilitator/scheme.ts","../../../src/exact/facilitator/eip3009-utils.ts","../../../src/multicall.ts"],"sourcesContent":["export { ExactEvmSchemeV1 } from \"../exact/v1\";\n\nexport const EVM_NETWORK_CHAIN_ID_MAP = {\n ethereum: 1,\n sepolia: 11155111,\n abstract: 2741,\n \"abstract-testnet\": 11124,\n \"base-sepolia\": 84532,\n base: 8453,\n \"avalanche-fuji\": 43113,\n avalanche: 43114,\n iotex: 4689,\n sei: 1329,\n \"sei-testnet\": 1328,\n polygon: 137,\n \"polygon-amoy\": 80002,\n peaq: 3338,\n story: 1514,\n educhain: 41923,\n \"skale-base-sepolia\": 324705682,\n megaeth: 4326,\n monad: 143,\n} as const;\n\nexport type EvmNetworkV1 = keyof typeof EVM_NETWORK_CHAIN_ID_MAP;\n\nexport const NETWORKS: string[] = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);\n\n/**\n * Extract chain ID from a v1 legacy network name.\n *\n * @param network - The v1 network name (e.g., \"base-sepolia\", \"polygon\")\n * @returns The numeric chain ID\n * @throws Error if the network name is not a known v1 network\n */\nexport function getEvmChainIdV1(network: string): number {\n const chainId = EVM_NETWORK_CHAIN_ID_MAP[network as EvmNetworkV1];\n if (!chainId) {\n throw new Error(`Unsupported v1 network: ${network}`);\n }\n return chainId;\n}\n","import {\n Network,\n PaymentPayload,\n PaymentRequirements,\n SchemeNetworkClient,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress } from \"viem\";\nimport { authorizationTypes } from \"../../../constants\";\nimport { ClientEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { createNonce } from \"../../../utils\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\n\n/**\n * EVM client implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkClient {\n readonly scheme = \"exact\";\n\n /**\n * Creates a new ExactEvmClientV1 instance.\n *\n * @param signer - The EVM signer for client operations\n */\n constructor(private readonly signer: ClientEvmSigner) {}\n\n /**\n * Creates a payment payload for the Exact scheme (V1).\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n ): Promise<\n Pick<PaymentPayload, \"x402Version\" | \"payload\"> & { scheme: string; network: Network }\n > {\n const selectedV1 = paymentRequirements as unknown as PaymentRequirementsV1;\n const nonce = createNonce();\n const now = Math.floor(Date.now() / 1000);\n\n const authorization: ExactEvmPayloadV1[\"authorization\"] = {\n from: this.signer.address,\n to: getAddress(selectedV1.payTo),\n value: selectedV1.maxAmountRequired,\n validAfter: (now - 600).toString(), // 10 minutes before\n validBefore: (now + selectedV1.maxTimeoutSeconds).toString(),\n nonce,\n };\n\n // Sign the authorization\n const signature = await this.signAuthorization(authorization, selectedV1);\n\n const payload: ExactEvmPayloadV1 = {\n authorization,\n signature,\n };\n\n return {\n x402Version,\n scheme: selectedV1.scheme,\n network: selectedV1.network,\n payload,\n };\n }\n\n /**\n * Sign the EIP-3009 authorization using EIP-712\n *\n * @param authorization - The authorization to sign\n * @param requirements - The payment requirements\n * @returns Promise resolving to the signature\n */\n private async signAuthorization(\n authorization: ExactEvmPayloadV1[\"authorization\"],\n requirements: PaymentRequirementsV1,\n ): Promise<`0x${string}`> {\n const chainId = getEvmChainIdV1(requirements.network as EvmNetworkV1);\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`,\n );\n }\n\n const { name, version } = requirements.extra;\n\n const domain = {\n name,\n version,\n chainId,\n verifyingContract: getAddress(requirements.asset),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return await this.signer.signTypedData({\n domain,\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\",\n message,\n });\n }\n}\n","// EIP-3009 TransferWithAuthorization types for EIP-712 signing\nexport const authorizationTypes = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\n/**\n * Permit2 EIP-712 types for signing PermitWitnessTransferFrom.\n * Must match the exact format expected by the Permit2 contract.\n * Note: Types must be in ALPHABETICAL order after the primary type (TokenPermissions < Witness).\n */\nexport const permit2WitnessTypes = {\n PermitWitnessTransferFrom: [\n { name: \"permitted\", type: \"TokenPermissions\" },\n { name: \"spender\", type: \"address\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n { name: \"witness\", type: \"Witness\" },\n ],\n TokenPermissions: [\n { name: \"token\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n Witness: [\n { name: \"to\", type: \"address\" },\n { name: \"validAfter\", type: \"uint256\" },\n ],\n} as const;\n\n// EIP3009 ABI for transferWithAuthorization function\nexport const eip3009ABI = [\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"v\", type: \"uint8\" },\n { name: \"r\", type: \"bytes32\" },\n { name: \"s\", type: \"bytes32\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"signature\", type: \"bytes\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [{ name: \"account\", type: \"address\" }],\n name: \"balanceOf\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"version\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"name\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"authorizer\", type: \"address\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n name: \"authorizationState\",\n outputs: [{ name: \"\", type: \"bool\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/**\n * EIP-2612 Permit EIP-712 types for signing token.permit().\n */\nexport const eip2612PermitTypes = {\n Permit: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * EIP-2612 nonces ABI for querying current nonce.\n */\nexport const eip2612NoncesAbi = [\n {\n type: \"function\",\n name: \"nonces\",\n inputs: [{ name: \"owner\", type: \"address\" }],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** ERC-20 approve(address,uint256) ABI for encoding/decoding approval calldata. */\nexport const erc20ApproveAbi = [\n {\n type: \"function\",\n name: \"approve\",\n inputs: [\n { name: \"spender\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n outputs: [{ type: \"bool\" }],\n stateMutability: \"nonpayable\",\n },\n] as const;\n\n/** ERC-20 allowance(address,address) ABI for checking spender approval. */\nexport const erc20AllowanceAbi = [\n {\n type: \"function\",\n name: \"allowance\",\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n ],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** Gas limit for a standard ERC-20 approve() transaction. */\nexport const ERC20_APPROVE_GAS_LIMIT = 70_000n;\n\n/** Fallback max fee per gas (1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_FEE_PER_GAS = 1_000_000_000n;\n\n/** Fallback max priority fee per gas (0.1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100_000_000n;\n\n/**\n * Canonical Permit2 contract address.\n * Same address on all EVM chains via CREATE2 deployment.\n *\n * @see https://github.com/Uniswap/permit2\n */\nexport const PERMIT2_ADDRESS = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\" as const;\n\n/**\n * x402ExactPermit2Proxy contract address.\n * Vanity address: 0x4020...0001 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0001\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402ExactPermit2ProxyAddress = \"0x402085c248EeA27D92E8b30b2C58ed07f9E20001\" as const;\n\n/**\n * x402UptoPermit2Proxy contract address.\n * Vanity address: 0x4020...0002 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0002\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402UptoPermit2ProxyAddress = \"0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002\" as const;\n\n/**\n * Shared ABI components for the Permit2 witness tuple.\n * Used in both x402ExactPermit2ProxyABI and x402UptoPermit2ProxyABI to keep them in sync.\n * The upto contract's witness struct is identical to exact (both remove 'extra' post-audit).\n */\nconst permit2WitnessABIComponents = [\n { name: \"to\", type: \"address\", internalType: \"address\" },\n { name: \"validAfter\", type: \"uint256\", internalType: \"uint256\" },\n] as const;\n\n/**\n * x402UptoPermit2Proxy ABI - settle function for upto payment scheme (variable amounts).\n * Updated post-audit: 'extra' removed from witness struct, 'initialize()' removed (now\n * a constructor arg), and error names aligned with x402ExactPermit2Proxy.\n */\nexport const x402UptoPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n\n/**\n * x402ExactPermit2Proxy ABI - settle function for exact payment scheme.\n */\nexport const x402ExactPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n","import { toHex } from \"viem\";\n\n/**\n * Extract chain ID from a CAIP-2 network identifier (eip155:CHAIN_ID).\n *\n * @param network - The network identifier in CAIP-2 format (e.g., \"eip155:8453\")\n * @returns The numeric chain ID\n * @throws Error if the network format is invalid\n */\nexport function getEvmChainId(network: string): number {\n if (network.startsWith(\"eip155:\")) {\n const idStr = network.split(\":\")[1];\n const chainId = parseInt(idStr, 10);\n if (isNaN(chainId)) {\n throw new Error(`Invalid CAIP-2 chain ID: ${network}`);\n }\n return chainId;\n }\n\n throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);\n}\n\n/**\n * Get the crypto object from the global scope.\n *\n * @returns The crypto object\n * @throws Error if crypto API is not available\n */\nfunction getCrypto(): Crypto {\n const cryptoObj = globalThis.crypto as Crypto | undefined;\n if (!cryptoObj) {\n throw new Error(\"Crypto API not available\");\n }\n return cryptoObj;\n}\n\n/**\n * Create a random 32-byte nonce for EIP-3009 authorization.\n *\n * @returns A hex-encoded 32-byte nonce\n */\nexport function createNonce(): `0x${string}` {\n return toHex(getCrypto().getRandomValues(new Uint8Array(32)));\n}\n\n/**\n * Creates a random 256-bit nonce for Permit2.\n * Permit2 uses uint256 nonces (not bytes32 like EIP-3009).\n *\n * @returns A string representation of the random nonce\n */\nexport function createPermit2Nonce(): string {\n const randomBytes = getCrypto().getRandomValues(new Uint8Array(32));\n return BigInt(toHex(randomBytes)).toString();\n}\n","import {\n PaymentPayload,\n PaymentPayloadV1,\n PaymentRequirements,\n SchemeNetworkFacilitator,\n SettleResponse,\n VerifyResponse,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress, Hex, isAddressEqual, parseErc6492Signature } from \"viem\";\nimport { authorizationTypes } from \"../../../constants\";\nimport { FacilitatorEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\nimport * as Errors from \"../../facilitator/errors\";\nimport {\n diagnoseEip3009SimulationFailure,\n executeTransferWithAuthorization,\n simulateEip3009Transfer,\n} from \"../../facilitator/eip3009-utils\";\n\nexport interface VerifyV1Options {\n /** Run onchain simulation. Defaults to true. */\n simulate?: boolean;\n}\n\nexport interface ExactEvmSchemeV1Config {\n /**\n * If enabled, the facilitator will deploy ERC-4337 smart wallets\n * via EIP-6492 when encountering undeployed contract signatures.\n *\n * @default false\n */\n deployERC4337WithEIP6492?: boolean;\n /**\n * If enabled, simulates transaction before settling. Defaults to false, ie only simulate during verify.\n *\n * @default false\n */\n simulateInSettle?: boolean;\n}\n\n/**\n * EVM facilitator implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkFacilitator {\n readonly scheme = \"exact\";\n readonly caipFamily = \"eip155:*\";\n private readonly config: Required<ExactEvmSchemeV1Config>;\n\n /**\n * Creates a new ExactEvmFacilitatorV1 instance.\n *\n * @param signer - The EVM signer for facilitator operations\n * @param config - Optional configuration for the facilitator\n */\n constructor(\n private readonly signer: FacilitatorEvmSigner,\n config?: ExactEvmSchemeV1Config,\n ) {\n this.config = {\n deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,\n simulateInSettle: config?.simulateInSettle ?? false,\n };\n }\n\n /**\n * Get mechanism-specific extra data for the supported kinds endpoint.\n * For EVM, no extra data is needed.\n *\n * @param _ - The network identifier (unused for EVM)\n * @returns undefined (EVM has no extra data)\n */\n getExtra(_: string): Record<string, unknown> | undefined {\n return undefined;\n }\n\n /**\n * Get signer addresses used by this facilitator.\n * Returns all addresses this facilitator can use for signing/settling transactions.\n *\n * @param _ - The network identifier (unused for EVM, addresses are network-agnostic)\n * @returns Array of facilitator wallet addresses\n */\n getSigners(_: string): string[] {\n return [...this.signer.getAddresses()];\n }\n\n /**\n * Verifies a payment payload (V1).\n *\n * @param payload - The payment payload to verify\n * @param requirements - The payment requirements\n * @returns Promise resolving to verification response\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n return this._verify(payload, requirements);\n }\n\n /**\n * Settles a payment by executing the transfer (V1).\n *\n * @param payload - The payment payload to settle\n * @param requirements - The payment requirements\n * @returns Promise resolving to settlement response\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n\n // Re-verify before settling\n const valid = await this._verify(payload, requirements, {\n simulate: this.config.simulateInSettle ?? false,\n });\n if (!valid.isValid) {\n return {\n success: false,\n network: payloadV1.network,\n transaction: \"\",\n errorReason: valid.invalidReason ?? Errors.ErrInvalidScheme,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n try {\n // Parse ERC-6492 signature if applicable (for optional deployment)\n const { address: factoryAddress, data: factoryCalldata } = parseErc6492Signature(\n exactEvmPayload.signature!,\n );\n\n // Deploy ERC-4337 smart wallet via EIP-6492 if configured and needed\n if (\n this.config.deployERC4337WithEIP6492 &&\n factoryAddress &&\n factoryCalldata &&\n !isAddressEqual(factoryAddress, \"0x0000000000000000000000000000000000000000\")\n ) {\n // Check if smart wallet is already deployed\n const payerAddress = exactEvmPayload.authorization.from;\n const bytecode = await this.signer.getCode({ address: payerAddress });\n\n if (!bytecode || bytecode === \"0x\") {\n // Send the factory calldata directly as a transaction\n // The factoryCalldata already contains the complete encoded function call\n const deployTx = await this.signer.sendTransaction({\n to: factoryAddress as Hex,\n data: factoryCalldata as Hex,\n });\n\n // Wait for deployment transaction\n await this.signer.waitForTransactionReceipt({ hash: deployTx });\n }\n }\n\n const tx = await executeTransferWithAuthorization(\n this.signer,\n getAddress(requirements.asset),\n exactEvmPayload,\n );\n\n // Wait for transaction confirmation\n const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });\n\n if (receipt.status !== \"success\") {\n return {\n success: false,\n errorReason: Errors.ErrTransactionFailed,\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n return {\n success: true,\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n } catch (error) {\n return {\n success: false,\n errorReason: error instanceof Error ? error.message : Errors.ErrTransactionFailed,\n transaction: \"\",\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n }\n\n /**\n * Internal verify with optional simulation control.\n *\n * @param payload - The payment payload to verify\n * @param requirements - The payment requirements\n * @param options - Verification options (e.g. simulate)\n * @returns Promise resolving to verification response\n */\n private async _verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n options?: VerifyV1Options,\n ): Promise<VerifyResponse> {\n const requirementsV1 = requirements as unknown as PaymentRequirementsV1;\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n const payer = exactEvmPayload.authorization.from;\n let eip6492Deployment:\n | { factoryAddress: `0x${string}`; factoryCalldata: `0x${string}` }\n | undefined;\n\n // Verify scheme matches\n if (payloadV1.scheme !== \"exact\" || requirements.scheme !== \"exact\") {\n return {\n isValid: false,\n invalidReason: Errors.ErrInvalidScheme,\n payer,\n };\n }\n\n // Get chain configuration\n let chainId: number;\n try {\n chainId = getEvmChainIdV1(payloadV1.network as EvmNetworkV1);\n } catch {\n return {\n isValid: false,\n invalidReason: Errors.ErrNetworkMismatch,\n payer,\n };\n }\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n return {\n isValid: false,\n invalidReason: Errors.ErrMissingEip712Domain,\n payer,\n };\n }\n\n const { name, version } = requirements.extra;\n const erc20Address = getAddress(requirements.asset);\n\n // Verify network matches\n if (payloadV1.network !== requirements.network) {\n return {\n isValid: false,\n invalidReason: Errors.ErrNetworkMismatch,\n payer,\n };\n }\n\n // Build typed data for signature verification\n const permitTypedData = {\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\" as const,\n domain: {\n name,\n version,\n chainId,\n verifyingContract: erc20Address,\n },\n message: {\n from: exactEvmPayload.authorization.from,\n to: exactEvmPayload.authorization.to,\n value: BigInt(exactEvmPayload.authorization.value),\n validAfter: BigInt(exactEvmPayload.authorization.validAfter),\n validBefore: BigInt(exactEvmPayload.authorization.validBefore),\n nonce: exactEvmPayload.authorization.nonce,\n },\n };\n\n // Verify signature (flatten EIP-6492 handling out of catch block)\n let isValid = false;\n try {\n isValid = await this.signer.verifyTypedData({\n address: payer,\n ...permitTypedData,\n signature: exactEvmPayload.signature!,\n });\n } catch {\n isValid = false;\n }\n\n const signature = exactEvmPayload.signature!;\n const sigLen = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n\n // Extract EIP-6492 deployment info (factory address + calldata) if present\n const erc6492Data = parseErc6492Signature(signature);\n const hasDeploymentInfo =\n erc6492Data.address &&\n erc6492Data.data &&\n !isAddressEqual(erc6492Data.address, \"0x0000000000000000000000000000000000000000\");\n\n if (hasDeploymentInfo) {\n eip6492Deployment = {\n factoryAddress: erc6492Data.address!,\n factoryCalldata: erc6492Data.data!,\n };\n }\n\n if (!isValid) {\n const isSmartWallet = sigLen > 130; // 65 bytes = 130 hex chars for EOA\n\n if (!isSmartWallet) {\n return {\n isValid: false,\n invalidReason: Errors.ErrInvalidSignature,\n payer,\n };\n }\n\n const bytecode = await this.signer.getCode({ address: payer });\n const isDeployed = bytecode && bytecode !== \"0x\";\n\n if (!isDeployed && !hasDeploymentInfo) {\n return {\n isValid: false,\n invalidReason: Errors.ErrUndeployedSmartWallet,\n payer,\n };\n }\n }\n\n // Verify payment recipient matches\n if (getAddress(exactEvmPayload.authorization.to) !== getAddress(requirements.payTo)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrRecipientMismatch,\n payer,\n };\n }\n\n // Verify validBefore is in the future (with 6 second buffer for block time)\n const now = Math.floor(Date.now() / 1000);\n if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrValidBeforeExpired,\n payer,\n };\n }\n\n // Verify validAfter is not in the future\n if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrValidAfterInFuture,\n payer,\n };\n }\n\n // Verify amount exactly matches requirements\n if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrInvalidAuthorizationValue,\n payer,\n };\n }\n\n // Transaction simulation\n if (options?.simulate !== false) {\n const simulationSucceeded = await simulateEip3009Transfer(\n this.signer,\n erc20Address,\n exactEvmPayload,\n eip6492Deployment,\n );\n if (!simulationSucceeded) {\n return diagnoseEip3009SimulationFailure(\n this.signer,\n erc20Address,\n exactEvmPayload,\n requirements,\n requirementsV1.maxAmountRequired,\n );\n }\n }\n\n return {\n isValid: true,\n invalidReason: undefined,\n payer,\n };\n }\n}\n","import { PaymentRequirements, VerifyResponse } from \"@x402/core/types\";\nimport { encodeFunctionData, getAddress, Hex, parseErc6492Signature, parseSignature } from \"viem\";\nimport { eip3009ABI } from \"../../constants\";\nimport { multicall, ContractCall, RawContractCall } from \"../../multicall\";\nimport { FacilitatorEvmSigner } from \"../../signer\";\nimport { ExactEIP3009Payload } from \"../../types\";\nimport * as Errors from \"./errors\";\n\nexport interface Eip6492Deployment {\n factoryAddress: `0x${string}`;\n factoryCalldata: `0x${string}`;\n}\n\n/**\n * Simulates transferWithAuthorization via eth_call.\n * Returns true if simulation succeeded, false if it failed.\n *\n * @param signer - EVM signer for contract reads\n * @param erc20Address - ERC-20 token contract address\n * @param payload - EIP-3009 transfer authorization payload\n * @param eip6492Deployment - Optional EIP-6492 factory info for undeployed smart wallets\n *\n * @returns true if simulation succeeded, false if it failed\n */\nexport async function simulateEip3009Transfer(\n signer: FacilitatorEvmSigner,\n erc20Address: `0x${string}`,\n payload: ExactEIP3009Payload,\n eip6492Deployment?: Eip6492Deployment,\n): Promise<boolean> {\n const auth = payload.authorization;\n const transferArgs = [\n getAddress(auth.from),\n getAddress(auth.to),\n BigInt(auth.value),\n BigInt(auth.validAfter),\n BigInt(auth.validBefore),\n auth.nonce,\n ] as const;\n\n if (eip6492Deployment) {\n const { signature: innerSignature } = parseErc6492Signature(payload.signature!);\n const transferCalldata = encodeFunctionData({\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [...transferArgs, innerSignature],\n });\n\n try {\n const results = await multicall(signer.readContract.bind(signer), [\n {\n address: getAddress(eip6492Deployment.factoryAddress),\n callData: eip6492Deployment.factoryCalldata,\n } satisfies RawContractCall,\n {\n address: erc20Address,\n callData: transferCalldata,\n } satisfies RawContractCall,\n ]);\n\n return results[1]?.status === \"success\";\n } catch {\n return false;\n }\n }\n\n const sig = payload.signature!;\n const sigLength = sig.startsWith(\"0x\") ? sig.length - 2 : sig.length;\n const isECDSA = sigLength === 130;\n\n try {\n if (isECDSA) {\n const parsedSig = parseSignature(sig);\n await signer.readContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n ...transferArgs,\n (parsedSig.v as number | undefined) ?? parsedSig.yParity,\n parsedSig.r,\n parsedSig.s,\n ],\n });\n } else {\n await signer.readContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [...transferArgs, sig],\n });\n }\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * After simulation fails, runs a single diagnostic multicall to determine the most specific error reason.\n * Checks balanceOf, name, version and authorizationState in one RPC round-trip.\n *\n * @param signer - EVM signer used for the payment\n * @param erc20Address - Address of the ERC-20 token contract\n * @param payload - The EIP-3009 transfer authorization payload\n * @param requirements - Payment requirements to validate against\n * @param amountRequired - Required amount for the payment (balance check)\n *\n * @returns Promise resolving to the verification result with validity and optional invalid reason\n */\nexport async function diagnoseEip3009SimulationFailure(\n signer: FacilitatorEvmSigner,\n erc20Address: `0x${string}`,\n payload: ExactEIP3009Payload,\n requirements: PaymentRequirements,\n amountRequired: string,\n): Promise<VerifyResponse> {\n const payer = payload.authorization.from;\n\n const diagnosticCalls: ContractCall[] = [\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"balanceOf\",\n args: [payload.authorization.from],\n },\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"name\",\n },\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"version\",\n },\n {\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"authorizationState\",\n args: [payload.authorization.from, payload.authorization.nonce],\n },\n ];\n\n try {\n const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);\n\n const [balanceResult, nameResult, versionResult, authStateResult] = results;\n\n if (authStateResult.status === \"failure\") {\n return { isValid: false, invalidReason: Errors.ErrEip3009NotSupported, payer };\n }\n\n if (authStateResult.status === \"success\" && authStateResult.result === true) {\n return { isValid: false, invalidReason: Errors.ErrEip3009NonceAlreadyUsed, payer };\n }\n\n if (\n nameResult.status === \"success\" &&\n requirements.extra?.name &&\n nameResult.result !== requirements.extra.name\n ) {\n return { isValid: false, invalidReason: Errors.ErrEip3009TokenNameMismatch, payer };\n }\n\n if (\n versionResult.status === \"success\" &&\n requirements.extra?.version &&\n versionResult.result !== requirements.extra.version\n ) {\n return { isValid: false, invalidReason: Errors.ErrEip3009TokenVersionMismatch, payer };\n }\n\n if (balanceResult.status === \"success\") {\n const balance = balanceResult.result as bigint;\n if (balance < BigInt(amountRequired)) {\n return {\n isValid: false,\n invalidReason: Errors.ErrEip3009InsufficientBalance,\n payer,\n };\n }\n }\n } catch {\n // Diagnostic multicall failed — fall through to generic error\n }\n\n return { isValid: false, invalidReason: Errors.ErrEip3009SimulationFailed, payer };\n}\n\n/**\n * Executes transferWithAuthorization onchain.\n *\n * @param signer - EVM signer for contract writes\n * @param erc20Address - ERC-20 token contract address\n * @param payload - EIP-3009 transfer authorization payload\n *\n * @returns Transaction hash\n */\nexport async function executeTransferWithAuthorization(\n signer: FacilitatorEvmSigner,\n erc20Address: `0x${string}`,\n payload: ExactEIP3009Payload,\n): Promise<Hex> {\n const { signature } = parseErc6492Signature(payload.signature!);\n const signatureLength = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n const isECDSA = signatureLength === 130;\n\n const auth = payload.authorization;\n const baseArgs = [\n getAddress(auth.from),\n getAddress(auth.to),\n BigInt(auth.value),\n BigInt(auth.validAfter),\n BigInt(auth.validBefore),\n auth.nonce,\n ] as const;\n\n if (isECDSA) {\n const parsedSig = parseSignature(signature);\n return signer.writeContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n ...baseArgs,\n (parsedSig.v as number | undefined) || parsedSig.yParity,\n parsedSig.r,\n parsedSig.s,\n ],\n });\n }\n\n return signer.writeContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [...baseArgs, signature],\n });\n}\n","import { encodeFunctionData, decodeFunctionResult } from \"viem\";\n\n/**\n * Multicall3 contract address.\n * Same address on all EVM chains via CREATE2 deployment.\n *\n * @see https://github.com/mds1/multicall\n */\nexport const MULTICALL3_ADDRESS = \"0xcA11bde05977b3631167028862bE2a173976CA11\" as const;\n\n/** Multicall3 getEthBalance ABI for querying native token balance. */\nexport const multicall3GetEthBalanceAbi = [\n {\n name: \"getEthBalance\",\n inputs: [{ name: \"addr\", type: \"address\" }],\n outputs: [{ name: \"balance\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/** Multicall3 tryAggregate ABI for batching calls. */\nconst multicall3ABI = [\n {\n inputs: [\n { name: \"requireSuccess\", type: \"bool\" },\n {\n name: \"calls\",\n type: \"tuple[]\",\n components: [\n { name: \"target\", type: \"address\" },\n { name: \"callData\", type: \"bytes\" },\n ],\n },\n ],\n name: \"tryAggregate\",\n outputs: [\n {\n name: \"returnData\",\n type: \"tuple[]\",\n components: [\n { name: \"success\", type: \"bool\" },\n { name: \"returnData\", type: \"bytes\" },\n ],\n },\n ],\n stateMutability: \"payable\",\n type: \"function\",\n },\n] as const;\n\nexport type ContractCall = {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n};\n\nexport type RawContractCall = {\n address: `0x${string}`;\n callData: `0x${string}`;\n};\n\nexport type MulticallSuccess = { status: \"success\"; result: unknown };\nexport type MulticallFailure = { status: \"failure\"; error: Error };\nexport type MulticallResult = MulticallSuccess | MulticallFailure;\n\n/**\n * Batches contract calls via Multicall3 `tryAggregate(false, ...)`.\n *\n * Accepts a mix of typed ContractCall (ABI-encoded + decoded) and\n * RawContractCall (pre-encoded calldata, no decoding) entries.\n * Raw calls are useful for the EIP-6492 factory deployment case\n * where calldata is pre-encoded with no ABI available.\n */\ntype ReadContractFn = (args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n}) => Promise<unknown>;\n\n/**\n * Executes multiple contract read calls in a single RPC round-trip using Multicall3.\n *\n * @param readContract - Function that performs a single contract read (e.g. viem readContract)\n * @param calls - Array of contract calls to batch (ContractCall or RawContractCall)\n * @returns A promise that resolves to an array of decoded results, one per call\n */\nexport async function multicall(\n readContract: ReadContractFn,\n calls: ReadonlyArray<ContractCall | RawContractCall>,\n): Promise<MulticallResult[]> {\n const aggregateCalls = calls.map(call => {\n if (\"callData\" in call) {\n return { target: call.address, callData: call.callData };\n }\n const callData = encodeFunctionData({\n abi: call.abi,\n functionName: call.functionName,\n args: call.args as unknown[],\n });\n return { target: call.address, callData };\n });\n\n const rawResults = (await readContract({\n address: MULTICALL3_ADDRESS,\n abi: multicall3ABI,\n functionName: \"tryAggregate\",\n args: [false, aggregateCalls],\n })) as { success: boolean; returnData: `0x${string}` }[];\n\n return rawResults.map((raw, i) => {\n if (!raw.success) {\n return {\n status: \"failure\" as const,\n error: new Error(`multicall: call reverted (returnData: ${raw.returnData})`),\n };\n }\n\n const call = calls[i];\n if (\"callData\" in call) {\n return { status: \"success\" as const, result: undefined };\n }\n\n try {\n const decoded = decodeFunctionResult({\n abi: call.abi,\n functionName: call.functionName,\n data: raw.returnData,\n });\n return { status: \"success\" as const, result: decoded };\n } catch (err) {\n return {\n status: \"failure\" as const,\n error: err instanceof Error ? err : new Error(String(err)),\n };\n }\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACOA,IAAAA,eAA2B;;;ACNpB,IAAM,qBAAqB;AAAA,EAChC,2BAA2B;AAAA,IACzB,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IAChC,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,IAC9B,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,IACjC,EAAE,MAAM,cAAc,MAAM,UAAU;AAAA,IACtC,EAAE,MAAM,eAAe,MAAM,UAAU;AAAA,IACvC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,EACnC;AACF;;;ACVA,kBAAsB;AA4BtB,SAAS,YAAoB;AAC3B,QAAM,YAAY,WAAW;AAC7B,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,0BAA0B;AAAA,EAC5C;AACA,SAAO;AACT;AAOO,SAAS,cAA6B;AAC3C,aAAO,mBAAM,UAAU,EAAE,gBAAgB,IAAI,WAAW,EAAE,CAAC,CAAC;AAC9D;;;AF1BO,IAAM,mBAAN,MAAsD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ3D,YAA6B,QAAyB;AAAzB;AAP7B,SAAS,SAAS;AAAA,EAOqC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASvD,MAAM,qBACJ,aACA,qBAGA;AACA,UAAM,aAAa;AACnB,UAAM,QAAQ,YAAY;AAC1B,UAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAExC,UAAM,gBAAoD;AAAA,MACxD,MAAM,KAAK,OAAO;AAAA,MAClB,QAAI,yBAAW,WAAW,KAAK;AAAA,MAC/B,OAAO,WAAW;AAAA,MAClB,aAAa,MAAM,KAAK,SAAS;AAAA;AAAA,MACjC,cAAc,MAAM,WAAW,mBAAmB,SAAS;AAAA,MAC3D;AAAA,IACF;AAGA,UAAM,YAAY,MAAM,KAAK,kBAAkB,eAAe,UAAU;AAExE,UAAM,UAA6B;AAAA,MACjC;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA,QAAQ,WAAW;AAAA,MACnB,SAAS,WAAW;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,kBACZ,eACA,cACwB;AACxB,UAAM,UAAU,gBAAgB,aAAa,OAAuB;AAEpE,QAAI,CAAC,aAAa,OAAO,QAAQ,CAAC,aAAa,OAAO,SAAS;AAC7D,YAAM,IAAI;AAAA,QACR,4FAA4F,aAAa,KAAK;AAAA,MAChH;AAAA,IACF;AAEA,UAAM,EAAE,MAAM,QAAQ,IAAI,aAAa;AAEvC,UAAM,SAAS;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,uBAAmB,yBAAW,aAAa,KAAK;AAAA,IAClD;AAEA,UAAM,UAAU;AAAA,MACd,UAAM,yBAAW,cAAc,IAAI;AAAA,MACnC,QAAI,yBAAW,cAAc,EAAE;AAAA,MAC/B,OAAO,OAAO,cAAc,KAAK;AAAA,MACjC,YAAY,OAAO,cAAc,UAAU;AAAA,MAC3C,aAAa,OAAO,cAAc,WAAW;AAAA,MAC7C,OAAO,cAAc;AAAA,IACvB;AAEA,WAAO,MAAM,KAAK,OAAO,cAAc;AAAA,MACrC;AAAA,MACA,OAAO;AAAA,MACP,aAAa;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;AGxGA,IAAAC,eAAuE;;;ACRvE,IAAAC,eAA2F;;;ACD3F,IAAAC,eAAyD;;;ANElD,IAAM,2BAA2B;AAAA,EACtC,UAAU;AAAA,EACV,SAAS;AAAA,EACT,UAAU;AAAA,EACV,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,MAAM;AAAA,EACN,kBAAkB;AAAA,EAClB,WAAW;AAAA,EACX,OAAO;AAAA,EACP,KAAK;AAAA,EACL,eAAe;AAAA,EACf,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,sBAAsB;AAAA,EACtB,SAAS;AAAA,EACT,OAAO;AACT;AAIO,IAAM,WAAqB,OAAO,KAAK,wBAAwB;AAS/D,SAAS,gBAAgB,SAAyB;AACvD,QAAM,UAAU,yBAAyB,OAAuB;AAChE,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,2BAA2B,OAAO,EAAE;AAAA,EACtD;AACA,SAAO;AACT;","names":["import_viem","import_viem","import_viem","import_viem"]}

@@ -1,5 +0,6 @@

export { E as ExactEvmScheme, P as Permit2AllowanceParams, c as createPermit2ApprovalTx, e as erc20AllowanceAbi, g as getPermit2AllowanceReadParams } from '../../permit2-BuAhWvNC.mjs';
import { i as ExactEvmSchemeOptions } from '../../permit2-Bbh3a8_h.mjs';
export { E as ExactEvmScheme, j as ExactEvmSchemeConfig, k as ExactEvmSchemeConfigByChainId, P as Permit2AllowanceParams, c as createPermit2ApprovalTx, e as erc20AllowanceAbi, g as getPermit2AllowanceReadParams } from '../../permit2-Bbh3a8_h.mjs';
import { x402Client, SelectPaymentRequirements, PaymentPolicy } from '@x402/core/client';
import { Network } from '@x402/core/types';
import { C as ClientEvmSigner } from '../../signer-DC81R8wQ.mjs';
import { C as ClientEvmSigner } from '../../signer-D912R4mq.mjs';

@@ -24,5 +25,11 @@ /**

/**
* Optional specific networks to register
* If not provided, registers wildcard support (eip155:*)
* Optional Exact EVM client scheme options.
* Supports either a single config ({ rpcUrl }) or per-chain configs
* keyed by EVM chain ID ({ 8453: { rpcUrl: "..." } }).
*/
schemeOptions?: ExactEvmSchemeOptions;
/**
* Optional specific networks to register.
* If not provided, registers wildcard support (eip155:*).
*/
networks?: Network[];

@@ -54,2 +61,2 @@ }

export { type EvmClientConfig, registerExactEvmScheme };
export { type EvmClientConfig, ExactEvmSchemeOptions, registerExactEvmScheme };

@@ -6,6 +6,7 @@ import {

registerExactEvmScheme
} from "../../chunk-LBIJBD7Q.mjs";
} from "../../chunk-WJWNS4G4.mjs";
import "../../chunk-GD4MKCN7.mjs";
import {
erc20AllowanceAbi
} from "../../chunk-XL6IFXCP.mjs";
} from "../../chunk-IZEI7JTG.mjs";
export {

@@ -12,0 +13,0 @@ ExactEvmScheme,

import { SchemeNetworkFacilitator, PaymentPayload, PaymentRequirements, FacilitatorContext, VerifyResponse, SettleResponse, Network } from '@x402/core/types';
import { F as FacilitatorEvmSigner } from '../../signer-DC81R8wQ.mjs';
import { F as FacilitatorEvmSigner } from '../../signer-D912R4mq.mjs';
import { x402Facilitator } from '@x402/core/facilitator';

@@ -13,2 +13,8 @@

deployERC4337WithEIP6492?: boolean;
/**
* If enabled, run on-chain simulation during settle's re-verify.
*
* @default false
*/
simulateInSettle?: boolean;
}

@@ -87,2 +93,8 @@ /**

deployERC4337WithEIP6492?: boolean;
/**
* If enabled, reruns on-chain simulation during settle's re-verify.
*
* @default false
*/
simulateInSettle?: boolean;
}

@@ -89,0 +101,0 @@ /**

@@ -5,23 +5,87 @@ import {

import {
ERC20_APPROVAL_GAS_SPONSORING_KEY,
extractEip2612GasSponsoringInfo,
extractErc20ApprovalGasSponsoringInfo,
resolveErc20ApprovalExtensionSigner,
validateEip2612GasSponsoringInfo,
validateErc20ApprovalGasSponsoringInfo
} from "../../chunk-GD4MKCN7.mjs";
import {
DEFAULT_MAX_FEE_PER_GAS,
ERC20_APPROVE_GAS_LIMIT,
ErrEip2612AssetMismatch,
ErrEip2612DeadlineExpired,
ErrEip2612FromMismatch,
ErrEip2612SpenderNotPermit2,
ErrErc20ApprovalAssetMismatch,
ErrErc20ApprovalFromMismatch,
ErrErc20ApprovalInsufficientEthForGas,
ErrErc20ApprovalInvalidFormat,
ErrErc20ApprovalSpenderNotPermit2,
ErrErc20ApprovalTxFailed,
ErrErc20ApprovalTxInvalidCalldata,
ErrErc20ApprovalTxInvalidSignature,
ErrErc20ApprovalTxParseFailed,
ErrErc20ApprovalTxSignerMismatch,
ErrErc20ApprovalTxWrongSelector,
ErrErc20ApprovalTxWrongSpender,
ErrErc20ApprovalTxWrongTarget,
ErrInvalidAuthorizationValue,
ErrInvalidEip2612ExtensionFormat,
ErrInvalidScheme,
ErrInvalidSignature,
ErrInvalidTransactionState,
ErrMissingEip712Domain,
ErrNetworkMismatch,
ErrPermit2612AmountMismatch,
ErrPermit2AllowanceRequired,
ErrPermit2AmountMismatch,
ErrPermit2DeadlineExpired,
ErrPermit2InsufficientBalance,
ErrPermit2InvalidAmount,
ErrPermit2InvalidDestination,
ErrPermit2InvalidNonce,
ErrPermit2InvalidOwner,
ErrPermit2InvalidSignature,
ErrPermit2InvalidSpender,
ErrPermit2NotYetValid,
ErrPermit2PaymentTooEarly,
ErrPermit2ProxyNotDeployed,
ErrPermit2RecipientMismatch,
ErrPermit2SimulationFailed,
ErrPermit2TokenMismatch,
ErrRecipientMismatch,
ErrTransactionFailed,
ErrUndeployedSmartWallet,
ErrUnsupportedPayloadType,
ErrValidAfterInFuture,
ErrValidBeforeExpired,
ExactEvmSchemeV1,
MULTICALL3_ADDRESS,
NETWORKS,
PERMIT2_ADDRESS,
authorizationTypes,
diagnoseEip3009SimulationFailure,
eip3009ABI,
erc20AllowanceAbi,
erc20ApproveAbi,
executeTransferWithAuthorization,
getEvmChainId,
multicall,
multicall3GetEthBalanceAbi,
permit2WitnessTypes,
simulateEip3009Transfer,
x402ExactPermit2ProxyABI,
x402ExactPermit2ProxyAddress
} from "../../chunk-XL6IFXCP.mjs";
} from "../../chunk-IZEI7JTG.mjs";
// src/exact/facilitator/eip3009.ts
import { getAddress, isAddressEqual, parseErc6492Signature, parseSignature } from "viem";
async function verifyEIP3009(signer, payload, requirements, eip3009Payload) {
import { getAddress, isAddressEqual, parseErc6492Signature } from "viem";
async function verifyEIP3009(signer, payload, requirements, eip3009Payload, options) {
const payer = eip3009Payload.authorization.from;
let eip6492Deployment;
if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {
return {
isValid: false,
invalidReason: "unsupported_scheme",
invalidReason: ErrInvalidScheme,
payer

@@ -33,3 +97,3 @@ };

isValid: false,
invalidReason: "missing_eip712_domain",
invalidReason: ErrMissingEip712Domain,
payer

@@ -43,3 +107,3 @@ };

isValid: false,
invalidReason: "network_mismatch",
invalidReason: ErrNetworkMismatch,
payer

@@ -66,4 +130,5 @@ };

};
let isValid = false;
try {
const recoveredAddress = await signer.verifyTypedData({
isValid = await signer.verifyTypedData({
address: eip3009Payload.authorization.from,

@@ -73,37 +138,30 @@ ...permitTypedData,

});
if (!recoveredAddress) {
} catch {
isValid = false;
}
const signature = eip3009Payload.signature;
const sigLen = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const erc6492Data = parseErc6492Signature(signature);
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !isAddressEqual(erc6492Data.address, "0x0000000000000000000000000000000000000000");
if (hasDeploymentInfo) {
eip6492Deployment = {
factoryAddress: erc6492Data.address,
factoryCalldata: erc6492Data.data
};
}
if (!isValid) {
const isSmartWallet = sigLen > 130;
if (!isSmartWallet) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
invalidReason: ErrInvalidSignature,
payer
};
}
} catch {
const signature = eip3009Payload.signature;
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isSmartWallet = signatureLength > 130;
if (isSmartWallet) {
const payerAddress = eip3009Payload.authorization.from;
const bytecode = await signer.getCode({ address: payerAddress });
if (!bytecode || bytecode === "0x") {
const erc6492Data = parseErc6492Signature(signature);
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !isAddressEqual(erc6492Data.address, "0x0000000000000000000000000000000000000000");
if (!hasDeploymentInfo) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
payer: payerAddress
};
}
} else {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
payer
};
}
} else {
const bytecode = await signer.getCode({ address: payer });
const isDeployed = bytecode && bytecode !== "0x";
if (!isDeployed && !hasDeploymentInfo) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
invalidReason: ErrUndeployedSmartWallet,
payer

@@ -116,3 +174,3 @@ };

isValid: false,
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
invalidReason: ErrRecipientMismatch,
payer

@@ -125,3 +183,3 @@ };

isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
invalidReason: ErrValidBeforeExpired,
payer

@@ -133,30 +191,30 @@ };

isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
invalidReason: ErrValidAfterInFuture,
payer
};
}
try {
const balance = await signer.readContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "balanceOf",
args: [eip3009Payload.authorization.from]
});
if (BigInt(balance) < BigInt(requirements.amount)) {
return {
isValid: false,
invalidReason: "insufficient_funds",
invalidMessage: `Insufficient funds to complete the payment. Required: ${requirements.amount} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
payer
};
}
} catch {
}
if (BigInt(eip3009Payload.authorization.value) !== BigInt(requirements.amount)) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_value_mismatch",
invalidReason: ErrInvalidAuthorizationValue,
payer
};
}
if (options?.simulate !== false) {
const simulationSucceeded = await simulateEip3009Transfer(
signer,
erc20Address,
eip3009Payload,
eip6492Deployment
);
if (!simulationSucceeded) {
return diagnoseEip3009SimulationFailure(
signer,
erc20Address,
eip3009Payload,
requirements,
requirements.amount
);
}
}
return {

@@ -170,3 +228,5 @@ isValid: true,

const payer = eip3009Payload.authorization.from;
const valid = await verifyEIP3009(signer, payload, requirements, eip3009Payload);
const valid = await verifyEIP3009(signer, payload, requirements, eip3009Payload, {
simulate: config.simulateInSettle ?? false
});
if (!valid.isValid) {

@@ -177,3 +237,3 @@ return {

transaction: "",
errorReason: valid.invalidReason ?? "invalid_scheme",
errorReason: valid.invalidReason ?? ErrInvalidScheme,
payer

@@ -183,4 +243,5 @@ };

try {
const parseResult = parseErc6492Signature(eip3009Payload.signature);
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
const { address: factoryAddress, data: factoryCalldata } = parseErc6492Signature(
eip3009Payload.signature
);
if (config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !isAddressEqual(factoryAddress, "0x0000000000000000000000000000000000000000")) {

@@ -196,39 +257,7 @@ const bytecode = await signer.getCode({ address: payer });

}
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isECDSA = signatureLength === 130;
let tx;
if (isECDSA) {
const parsedSig = parseSignature(signature);
tx = await signer.writeContract({
address: getAddress(requirements.asset),
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
getAddress(eip3009Payload.authorization.from),
getAddress(eip3009Payload.authorization.to),
BigInt(eip3009Payload.authorization.value),
BigInt(eip3009Payload.authorization.validAfter),
BigInt(eip3009Payload.authorization.validBefore),
eip3009Payload.authorization.nonce,
parsedSig.v || parsedSig.yParity,
parsedSig.r,
parsedSig.s
]
});
} else {
tx = await signer.writeContract({
address: getAddress(requirements.asset),
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
getAddress(eip3009Payload.authorization.from),
getAddress(eip3009Payload.authorization.to),
BigInt(eip3009Payload.authorization.value),
BigInt(eip3009Payload.authorization.validAfter),
BigInt(eip3009Payload.authorization.validBefore),
eip3009Payload.authorization.nonce,
signature
]
});
}
const tx = await executeTransferWithAuthorization(
signer,
getAddress(requirements.asset),
eip3009Payload
);
const receipt = await signer.waitForTransactionReceipt({ hash: tx });

@@ -238,3 +267,3 @@ if (receipt.status !== "success") {

success: false,
errorReason: "invalid_transaction_state",
errorReason: ErrTransactionFailed,
transaction: tx,

@@ -254,3 +283,3 @@ network: payload.accepted.network,

success: false,
errorReason: "transaction_failed",
errorReason: ErrTransactionFailed,
transaction: "",

@@ -264,30 +293,4 @@ network: payload.accepted.network,

// src/exact/facilitator/permit2.ts
import {
extractEip2612GasSponsoringInfo,
validateEip2612GasSponsoringInfo,
extractErc20ApprovalGasSponsoringInfo,
ERC20_APPROVAL_GAS_SPONSORING
} from "@x402/extensions";
import { getAddress as getAddress3 } from "viem";
import { getAddress as getAddress4 } from "viem";
// src/exact/facilitator/errors.ts
var ErrPermit2InvalidSignature = "invalid_permit2_signature";
var ErrPermit2InvalidAmount = "permit2_invalid_amount";
var ErrPermit2InvalidDestination = "permit2_invalid_destination";
var ErrPermit2InvalidOwner = "permit2_invalid_owner";
var ErrPermit2PaymentTooEarly = "permit2_payment_too_early";
var ErrPermit2InvalidNonce = "permit2_invalid_nonce";
var ErrPermit2612AmountMismatch = "permit2_2612_amount_mismatch";
var ErrErc20ApprovalInvalidFormat = "invalid_erc20_approval_extension_format";
var ErrErc20ApprovalFromMismatch = "erc20_approval_from_mismatch";
var ErrErc20ApprovalAssetMismatch = "erc20_approval_asset_mismatch";
var ErrErc20ApprovalSpenderNotPermit2 = "erc20_approval_spender_not_permit2";
var ErrErc20ApprovalTxWrongTarget = "erc20_approval_tx_wrong_target";
var ErrErc20ApprovalTxWrongSelector = "erc20_approval_tx_wrong_selector";
var ErrErc20ApprovalTxWrongSpender = "erc20_approval_tx_wrong_spender";
var ErrErc20ApprovalTxInvalidCalldata = "erc20_approval_tx_invalid_calldata";
var ErrErc20ApprovalTxSignerMismatch = "erc20_approval_tx_signer_mismatch";
var ErrErc20ApprovalTxInvalidSignature = "erc20_approval_tx_invalid_signature";
var ErrErc20ApprovalTxParseFailed = "erc20_approval_tx_parse_failed";
// src/exact/facilitator/erc20approval.ts

@@ -300,5 +303,2 @@ import {

} from "viem";
import {
validateErc20ApprovalGasSponsoringInfo
} from "@x402/extensions";
var APPROVE_SELECTOR = "0x095ea7b3";

@@ -400,4 +400,253 @@ async function validateErc20ApprovalForPayment(info, payer, tokenAddress) {

// src/exact/facilitator/permit2-utils.ts
import { encodeFunctionData, getAddress as getAddress3 } from "viem";
async function simulatePermit2Settle(signer, permit2Payload) {
try {
await signer.readContract({
address: x402ExactPermit2ProxyAddress,
abi: x402ExactPermit2ProxyABI,
functionName: "settle",
args: buildPermit2SettleArgs(permit2Payload)
});
return true;
} catch {
return false;
}
}
function splitEip2612Signature(signature) {
const sig = signature.startsWith("0x") ? signature.slice(2) : signature;
if (sig.length !== 130) {
throw new Error(
`invalid EIP-2612 signature length: expected 65 bytes (130 hex chars), got ${sig.length / 2} bytes`
);
}
const r = `0x${sig.slice(0, 64)}`;
const s = `0x${sig.slice(64, 128)}`;
const v = parseInt(sig.slice(128, 130), 16);
return { v, r, s };
}
function buildPermit2SettleArgs(permit2Payload) {
return [
{
permitted: {
token: getAddress3(permit2Payload.permit2Authorization.permitted.token),
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
},
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
},
getAddress3(permit2Payload.permit2Authorization.from),
{
to: getAddress3(permit2Payload.permit2Authorization.witness.to),
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
},
permit2Payload.signature
];
}
function encodePermit2SettleCalldata(permit2Payload) {
return encodeFunctionData({
abi: x402ExactPermit2ProxyABI,
functionName: "settle",
args: buildPermit2SettleArgs(permit2Payload)
});
}
async function simulatePermit2SettleWithPermit(signer, permit2Payload, eip2612Info) {
try {
const { v, r, s } = splitEip2612Signature(eip2612Info.signature);
await signer.readContract({
address: x402ExactPermit2ProxyAddress,
abi: x402ExactPermit2ProxyABI,
functionName: "settleWithPermit",
args: [
{
value: BigInt(eip2612Info.amount),
deadline: BigInt(eip2612Info.deadline),
r,
s,
v
},
...buildPermit2SettleArgs(permit2Payload)
]
});
return true;
} catch {
return false;
}
}
async function diagnosePermit2SimulationFailure(signer, tokenAddress, permit2Payload, amountRequired) {
const payer = permit2Payload.permit2Authorization.from;
const diagnosticCalls = [
{
address: x402ExactPermit2ProxyAddress,
abi: x402ExactPermit2ProxyABI,
functionName: "PERMIT2"
},
{
address: tokenAddress,
abi: eip3009ABI,
functionName: "balanceOf",
args: [payer]
},
{
address: tokenAddress,
abi: erc20AllowanceAbi,
functionName: "allowance",
args: [payer, PERMIT2_ADDRESS]
}
];
try {
const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
const [proxyResult, balanceResult, allowanceResult] = results;
if (proxyResult.status === "failure") {
return { isValid: false, invalidReason: ErrPermit2ProxyNotDeployed, payer };
}
if (balanceResult.status === "success") {
const balance = balanceResult.result;
if (balance < BigInt(amountRequired)) {
return { isValid: false, invalidReason: ErrPermit2InsufficientBalance, payer };
}
}
if (allowanceResult.status === "success") {
const allowance = allowanceResult.result;
if (allowance < BigInt(amountRequired)) {
return { isValid: false, invalidReason: ErrPermit2AllowanceRequired, payer };
}
}
} catch {
}
return { isValid: false, invalidReason: ErrPermit2SimulationFailed, payer };
}
async function checkPermit2Prerequisites(signer, tokenAddress, payer, amountRequired) {
const diagnosticCalls = [
{
address: x402ExactPermit2ProxyAddress,
abi: x402ExactPermit2ProxyABI,
functionName: "PERMIT2"
},
{
address: tokenAddress,
abi: eip3009ABI,
functionName: "balanceOf",
args: [payer]
},
{
address: MULTICALL3_ADDRESS,
abi: multicall3GetEthBalanceAbi,
functionName: "getEthBalance",
args: [payer]
}
];
try {
const results = await multicall(signer.readContract.bind(signer), diagnosticCalls);
const [proxyResult, balanceResult, ethBalanceResult] = results;
if (proxyResult.status === "failure") {
return { isValid: false, invalidReason: ErrPermit2ProxyNotDeployed, payer };
}
if (balanceResult.status === "success") {
const balance = balanceResult.result;
if (balance < BigInt(amountRequired)) {
return { isValid: false, invalidReason: ErrPermit2InsufficientBalance, payer };
}
}
if (ethBalanceResult.status === "success") {
const minEthForApprovalGas = ERC20_APPROVE_GAS_LIMIT * DEFAULT_MAX_FEE_PER_GAS;
const ethBalance = ethBalanceResult.result;
if (ethBalance < minEthForApprovalGas) {
return {
isValid: false,
invalidReason: ErrErc20ApprovalInsufficientEthForGas,
payer
};
}
}
} catch {
}
return { isValid: true, invalidReason: void 0, payer };
}
async function simulatePermit2SettleWithErc20Approval(extensionSigner, permit2Payload, erc20Info) {
if (!extensionSigner.simulateTransactions) {
return false;
}
try {
const settleData = encodePermit2SettleCalldata(permit2Payload);
return await extensionSigner.simulateTransactions([
erc20Info.signedTransaction,
{ to: x402ExactPermit2ProxyAddress, data: settleData, gas: BigInt(3e5) }
]);
} catch {
return false;
}
}
async function waitAndReturn(signer, tx, payload, payer) {
const receipt = await signer.waitForTransactionReceipt({ hash: tx });
if (receipt.status !== "success") {
return {
success: false,
errorReason: ErrInvalidTransactionState,
transaction: tx,
network: payload.accepted.network,
payer
};
}
return {
success: true,
transaction: tx,
network: payload.accepted.network,
payer
};
}
function mapSettleError(error, payload, payer) {
let errorReason = ErrTransactionFailed;
if (error instanceof Error) {
const message = error.message;
if (message.includes("Permit2612AmountMismatch")) {
errorReason = ErrPermit2612AmountMismatch;
} else if (message.includes("InvalidAmount")) {
errorReason = ErrPermit2InvalidAmount;
} else if (message.includes("InvalidDestination")) {
errorReason = ErrPermit2InvalidDestination;
} else if (message.includes("InvalidOwner")) {
errorReason = ErrPermit2InvalidOwner;
} else if (message.includes("PaymentTooEarly")) {
errorReason = ErrPermit2PaymentTooEarly;
} else if (message.includes("InvalidSignature") || message.includes("SignatureExpired")) {
errorReason = ErrPermit2InvalidSignature;
} else if (message.includes("InvalidNonce")) {
errorReason = ErrPermit2InvalidNonce;
} else if (message.includes("erc20_approval_tx_failed")) {
errorReason = ErrErc20ApprovalTxFailed;
} else {
errorReason = `${ErrTransactionFailed}: ${message.slice(0, 500)}`;
}
}
return {
success: false,
errorReason,
transaction: "",
network: payload.accepted.network,
payer
};
}
function validateEip2612PermitForPayment(info, payer, tokenAddress) {
if (!validateEip2612GasSponsoringInfo(info)) {
return { isValid: false, invalidReason: ErrInvalidEip2612ExtensionFormat };
}
if (getAddress3(info.from) !== getAddress3(payer)) {
return { isValid: false, invalidReason: ErrEip2612FromMismatch };
}
if (getAddress3(info.asset) !== tokenAddress) {
return { isValid: false, invalidReason: ErrEip2612AssetMismatch };
}
if (getAddress3(info.spender) !== getAddress3(PERMIT2_ADDRESS)) {
return { isValid: false, invalidReason: ErrEip2612SpenderNotPermit2 };
}
const now = Math.floor(Date.now() / 1e3);
if (BigInt(info.deadline) < BigInt(now + 6)) {
return { isValid: false, invalidReason: ErrEip2612DeadlineExpired };
}
return { isValid: true };
}
// src/exact/facilitator/permit2.ts
async function verifyPermit2(signer, payload, requirements, permit2Payload, context) {
async function verifyPermit2(signer, payload, requirements, permit2Payload, context, options) {
const payer = permit2Payload.permit2Authorization.from;

@@ -407,3 +656,3 @@ if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") {

isValid: false,
invalidReason: "unsupported_scheme",
invalidReason: ErrUnsupportedPayloadType,
payer

@@ -415,3 +664,3 @@ };

isValid: false,
invalidReason: "network_mismatch",
invalidReason: ErrNetworkMismatch,
payer

@@ -421,14 +670,14 @@ };

const chainId = getEvmChainId(requirements.network);
const tokenAddress = getAddress3(requirements.asset);
if (getAddress3(permit2Payload.permit2Authorization.spender) !== getAddress3(x402ExactPermit2ProxyAddress)) {
const tokenAddress = getAddress4(requirements.asset);
if (getAddress4(permit2Payload.permit2Authorization.spender) !== getAddress4(x402ExactPermit2ProxyAddress)) {
return {
isValid: false,
invalidReason: "invalid_permit2_spender",
invalidReason: ErrPermit2InvalidSpender,
payer
};
}
if (getAddress3(permit2Payload.permit2Authorization.witness.to) !== getAddress3(requirements.payTo)) {
if (getAddress4(permit2Payload.permit2Authorization.witness.to) !== getAddress4(requirements.payTo)) {
return {
isValid: false,
invalidReason: "invalid_permit2_recipient_mismatch",
invalidReason: ErrPermit2RecipientMismatch,
payer

@@ -441,3 +690,3 @@ };

isValid: false,
invalidReason: "permit2_deadline_expired",
invalidReason: ErrPermit2DeadlineExpired,
payer

@@ -449,3 +698,3 @@ };

isValid: false,
invalidReason: "permit2_not_yet_valid",
invalidReason: ErrPermit2NotYetValid,
payer

@@ -457,10 +706,10 @@ };

isValid: false,
invalidReason: "permit2_amount_mismatch",
invalidReason: ErrPermit2AmountMismatch,
payer
};
}
if (getAddress3(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
if (getAddress4(permit2Payload.permit2Authorization.permitted.token) !== tokenAddress) {
return {
isValid: false,
invalidReason: "permit2_token_mismatch",
invalidReason: ErrPermit2TokenMismatch,
payer

@@ -479,10 +728,10 @@ };

permitted: {
token: getAddress3(permit2Payload.permit2Authorization.permitted.token),
token: getAddress4(permit2Payload.permit2Authorization.permitted.token),
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
},
spender: getAddress3(permit2Payload.permit2Authorization.spender),
spender: getAddress4(permit2Payload.permit2Authorization.spender),
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
deadline: BigInt(permit2Payload.permit2Authorization.deadline),
witness: {
to: getAddress3(permit2Payload.permit2Authorization.witness.to),
to: getAddress4(permit2Payload.permit2Authorization.witness.to),
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)

@@ -492,4 +741,5 @@ }

};
let signatureValid = false;
try {
const isValid = await signer.verifyTypedData({
signatureValid = await signer.verifyTypedData({
address: payer,

@@ -499,97 +749,85 @@ ...permit2TypedData,

});
if (!isValid) {
} catch {
signatureValid = false;
}
if (!signatureValid) {
const bytecode = await signer.getCode({ address: payer });
const isDeployedContract = bytecode && bytecode !== "0x";
if (!isDeployedContract) {
return {
isValid: false,
invalidReason: "invalid_permit2_signature",
invalidReason: ErrPermit2InvalidSignature,
payer
};
}
} catch {
return {
isValid: false,
invalidReason: "invalid_permit2_signature",
payer
};
}
const allowanceResult = await _verifyPermit2Allowance(
signer,
payload,
requirements,
payer,
tokenAddress,
context
);
if (allowanceResult) {
return allowanceResult;
if (options?.simulate === false) {
return { isValid: true, invalidReason: void 0, payer };
}
try {
const balance = await signer.readContract({
address: tokenAddress,
abi: eip3009ABI,
functionName: "balanceOf",
args: [payer]
});
if (balance < BigInt(requirements.amount)) {
return {
isValid: false,
invalidReason: "insufficient_funds",
invalidMessage: `Insufficient funds to complete the payment. Required: ${requirements.amount} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
payer
};
const eip2612Info = extractEip2612GasSponsoringInfo(payload);
if (eip2612Info) {
const fieldResult = validateEip2612PermitForPayment(eip2612Info, payer, tokenAddress);
if (!fieldResult.isValid) {
return { isValid: false, invalidReason: fieldResult.invalidReason, payer };
}
} catch {
const simOk2 = await simulatePermit2SettleWithPermit(signer, permit2Payload, eip2612Info);
if (!simOk2) {
return diagnosePermit2SimulationFailure(
signer,
tokenAddress,
permit2Payload,
requirements.amount
);
}
return { isValid: true, invalidReason: void 0, payer };
}
return {
isValid: true,
invalidReason: void 0,
payer
};
}
async function _verifyPermit2Allowance(signer, payload, requirements, payer, tokenAddress, context) {
try {
const allowance = await signer.readContract({
address: tokenAddress,
abi: erc20AllowanceAbi,
functionName: "allowance",
args: [payer, PERMIT2_ADDRESS]
});
if (allowance >= BigInt(requirements.amount)) {
return null;
}
const eip2612Info = extractEip2612GasSponsoringInfo(payload);
if (eip2612Info) {
const result = validateEip2612PermitForPayment(eip2612Info, payer, tokenAddress);
if (!result.isValid) {
return { isValid: false, invalidReason: result.invalidReason, payer };
const erc20GasSponsorshipExtension = context?.getExtension(
ERC20_APPROVAL_GAS_SPONSORING_KEY
);
if (erc20GasSponsorshipExtension) {
const erc20Info = extractErc20ApprovalGasSponsoringInfo(payload);
if (erc20Info) {
const fieldResult = await validateErc20ApprovalForPayment(erc20Info, payer, tokenAddress);
if (!fieldResult.isValid) {
return { isValid: false, invalidReason: fieldResult.invalidReason, payer };
}
return null;
}
const erc20GasSponsorshipExtension = context?.getExtension(
ERC20_APPROVAL_GAS_SPONSORING.key
);
if (erc20GasSponsorshipExtension) {
const erc20Info = extractErc20ApprovalGasSponsoringInfo(payload);
if (erc20Info) {
const result = await validateErc20ApprovalForPayment(erc20Info, payer, tokenAddress);
if (!result.isValid) {
return { isValid: false, invalidReason: result.invalidReason, payer };
const extensionSigner = resolveErc20ApprovalExtensionSigner(
erc20GasSponsorshipExtension,
requirements.network
);
if (extensionSigner?.simulateTransactions) {
const simOk2 = await simulatePermit2SettleWithErc20Approval(
extensionSigner,
permit2Payload,
erc20Info
);
if (!simOk2) {
return diagnosePermit2SimulationFailure(
signer,
tokenAddress,
permit2Payload,
requirements.amount
);
}
return null;
return { isValid: true, invalidReason: void 0, payer };
}
return checkPermit2Prerequisites(signer, tokenAddress, payer, requirements.amount);
}
return { isValid: false, invalidReason: "permit2_allowance_required", payer };
} catch {
const eip2612Info = extractEip2612GasSponsoringInfo(payload);
if (eip2612Info) {
const result = validateEip2612PermitForPayment(eip2612Info, payer, tokenAddress);
if (!result.isValid) {
return { isValid: false, invalidReason: result.invalidReason, payer };
}
}
return null;
}
const simOk = await simulatePermit2Settle(signer, permit2Payload);
if (!simOk) {
return diagnosePermit2SimulationFailure(
signer,
tokenAddress,
permit2Payload,
requirements.amount
);
}
return { isValid: true, invalidReason: void 0, payer };
}
async function settlePermit2(signer, payload, requirements, permit2Payload, context) {
async function settlePermit2(signer, payload, requirements, permit2Payload, context, config) {
const payer = permit2Payload.permit2Authorization.from;
const valid = await verifyPermit2(signer, payload, requirements, permit2Payload, context);
const valid = await verifyPermit2(signer, payload, requirements, permit2Payload, context, {
simulate: config?.simulateInSettle ?? false
});
if (!valid.isValid) {

@@ -600,3 +838,3 @@ return {

transaction: "",
errorReason: valid.invalidReason ?? "invalid_scheme",
errorReason: valid.invalidReason ?? ErrInvalidScheme,
payer

@@ -612,11 +850,10 @@ };

const erc20GasSponsorshipExtension = context?.getExtension(
ERC20_APPROVAL_GAS_SPONSORING.key
ERC20_APPROVAL_GAS_SPONSORING_KEY
);
if (erc20GasSponsorshipExtension?.signer) {
return _settlePermit2WithERC20Approval(
erc20GasSponsorshipExtension.signer,
payload,
permit2Payload,
erc20Info
);
const extensionSigner = resolveErc20ApprovalExtensionSigner(
erc20GasSponsorshipExtension,
payload.accepted.network
);
if (extensionSigner) {
return _settlePermit2WithERC20Approval(extensionSigner, payload, permit2Payload, erc20Info);
}

@@ -642,21 +879,8 @@ }

},
{
permitted: {
token: getAddress3(permit2Payload.permit2Authorization.permitted.token),
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
},
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
},
getAddress3(payer),
{
to: getAddress3(permit2Payload.permit2Authorization.witness.to),
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
},
permit2Payload.signature
...buildPermit2SettleArgs(permit2Payload)
]
});
return _waitAndReturn(signer, tx, payload, payer);
return waitAndReturn(signer, tx, payload, payer);
} catch (error) {
return _mapSettleError(error, payload, payer);
return mapSettleError(error, payload, payer);
}

@@ -667,41 +891,11 @@ }

try {
const approvalTxHash = await extensionSigner.sendRawTransaction({
serializedTransaction: erc20Info.signedTransaction
});
const approvalReceipt = await extensionSigner.waitForTransactionReceipt({
hash: approvalTxHash
});
if (approvalReceipt.status !== "success") {
return {
success: false,
errorReason: "erc20_approval_tx_failed",
transaction: approvalTxHash,
network: payload.accepted.network,
payer
};
}
const tx = await extensionSigner.writeContract({
address: x402ExactPermit2ProxyAddress,
abi: x402ExactPermit2ProxyABI,
functionName: "settle",
args: [
{
permitted: {
token: getAddress3(permit2Payload.permit2Authorization.permitted.token),
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
},
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
},
getAddress3(payer),
{
to: getAddress3(permit2Payload.permit2Authorization.witness.to),
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
},
permit2Payload.signature
]
});
return _waitAndReturn(extensionSigner, tx, payload, payer);
const settleData = encodePermit2SettleCalldata(permit2Payload);
const txHashes = await extensionSigner.sendTransactions([
erc20Info.signedTransaction,
{ to: x402ExactPermit2ProxyAddress, data: settleData, gas: BigInt(3e5) }
]);
const settleTxHash = txHashes[txHashes.length - 1];
return waitAndReturn(extensionSigner, settleTxHash, payload, payer);
} catch (error) {
return _mapSettleError(error, payload, payer);
return mapSettleError(error, payload, payer);
}

@@ -716,103 +910,9 @@ }

functionName: "settle",
args: [
{
permitted: {
token: getAddress3(permit2Payload.permit2Authorization.permitted.token),
amount: BigInt(permit2Payload.permit2Authorization.permitted.amount)
},
nonce: BigInt(permit2Payload.permit2Authorization.nonce),
deadline: BigInt(permit2Payload.permit2Authorization.deadline)
},
getAddress3(payer),
{
to: getAddress3(permit2Payload.permit2Authorization.witness.to),
validAfter: BigInt(permit2Payload.permit2Authorization.witness.validAfter)
},
permit2Payload.signature
]
args: buildPermit2SettleArgs(permit2Payload)
});
return _waitAndReturn(signer, tx, payload, payer);
return waitAndReturn(signer, tx, payload, payer);
} catch (error) {
return _mapSettleError(error, payload, payer);
return mapSettleError(error, payload, payer);
}
}
async function _waitAndReturn(signer, tx, payload, payer) {
const receipt = await signer.waitForTransactionReceipt({ hash: tx });
if (receipt.status !== "success") {
return {
success: false,
errorReason: "invalid_transaction_state",
transaction: tx,
network: payload.accepted.network,
payer
};
}
return {
success: true,
transaction: tx,
network: payload.accepted.network,
payer
};
}
function _mapSettleError(error, payload, payer) {
let errorReason = "transaction_failed";
if (error instanceof Error) {
const message = error.message;
if (message.includes("Permit2612AmountMismatch")) {
errorReason = ErrPermit2612AmountMismatch;
} else if (message.includes("InvalidAmount")) {
errorReason = ErrPermit2InvalidAmount;
} else if (message.includes("InvalidDestination")) {
errorReason = ErrPermit2InvalidDestination;
} else if (message.includes("InvalidOwner")) {
errorReason = ErrPermit2InvalidOwner;
} else if (message.includes("PaymentTooEarly")) {
errorReason = ErrPermit2PaymentTooEarly;
} else if (message.includes("InvalidSignature") || message.includes("SignatureExpired")) {
errorReason = ErrPermit2InvalidSignature;
} else if (message.includes("InvalidNonce")) {
errorReason = ErrPermit2InvalidNonce;
} else {
errorReason = `transaction_failed: ${message.slice(0, 500)}`;
}
}
return {
success: false,
errorReason,
transaction: "",
network: payload.accepted.network,
payer
};
}
function validateEip2612PermitForPayment(info, payer, tokenAddress) {
if (!validateEip2612GasSponsoringInfo(info)) {
return { isValid: false, invalidReason: "invalid_eip2612_extension_format" };
}
if (getAddress3(info.from) !== getAddress3(payer)) {
return { isValid: false, invalidReason: "eip2612_from_mismatch" };
}
if (getAddress3(info.asset) !== tokenAddress) {
return { isValid: false, invalidReason: "eip2612_asset_mismatch" };
}
if (getAddress3(info.spender) !== getAddress3(PERMIT2_ADDRESS)) {
return { isValid: false, invalidReason: "eip2612_spender_not_permit2" };
}
const now = Math.floor(Date.now() / 1e3);
if (BigInt(info.deadline) < BigInt(now + 6)) {
return { isValid: false, invalidReason: "eip2612_deadline_expired" };
}
return { isValid: true };
}
function splitEip2612Signature(signature) {
const sig = signature.startsWith("0x") ? signature.slice(2) : signature;
if (sig.length !== 130) {
throw new Error(
`invalid EIP-2612 signature length: expected 65 bytes (130 hex chars), got ${sig.length / 2} bytes`
);
}
const r = `0x${sig.slice(0, 64)}`;
const s = `0x${sig.slice(64, 128)}`;
const v = parseInt(sig.slice(128, 130), 16);
return { v, r, s };
}

@@ -832,3 +932,4 @@ // src/exact/facilitator/scheme.ts

this.config = {
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,
simulateInSettle: config?.simulateInSettle ?? false
};

@@ -864,3 +965,4 @@ }

const rawPayload = payload.payload;
if (isPermit2Payload(rawPayload)) {
const isPermit2 = isPermit2Payload(rawPayload);
if (isPermit2) {
return verifyPermit2(this.signer, payload, requirements, rawPayload, context);

@@ -881,4 +983,7 @@ }

const rawPayload = payload.payload;
if (isPermit2Payload(rawPayload)) {
return settlePermit2(this.signer, payload, requirements, rawPayload, context);
const isPermit2 = isPermit2Payload(rawPayload);
if (isPermit2) {
return settlePermit2(this.signer, payload, requirements, rawPayload, context, {
simulateInSettle: this.config.simulateInSettle
});
}

@@ -895,3 +1000,4 @@ const eip3009Payload = rawPayload;

new ExactEvmScheme(config.signer, {
deployERC4337WithEIP6492: config.deployERC4337WithEIP6492
deployERC4337WithEIP6492: config.deployERC4337WithEIP6492,
simulateInSettle: config.simulateInSettle
})

@@ -902,3 +1008,4 @@ );

new ExactEvmSchemeV1(config.signer, {
deployERC4337WithEIP6492: config.deployERC4337WithEIP6492
deployERC4337WithEIP6492: config.deployERC4337WithEIP6492,
simulateInSettle: config.simulateInSettle
})

@@ -905,0 +1012,0 @@ );

import { SchemeNetworkClient, PaymentRequirements, PaymentPayload, Network } from '@x402/core/types';
import { C as ClientEvmSigner } from '../../../signer-DC81R8wQ.mjs';
import { C as ClientEvmSigner } from '../../../signer-D912R4mq.mjs';

@@ -4,0 +4,0 @@ /**

import {
ExactEvmSchemeV12 as ExactEvmSchemeV1
} from "../../../chunk-XL6IFXCP.mjs";
} from "../../../chunk-IZEI7JTG.mjs";
export {

@@ -5,0 +5,0 @@ ExactEvmSchemeV1

import { SchemeNetworkFacilitator, PaymentPayload, PaymentRequirements, VerifyResponse, SettleResponse } from '@x402/core/types';
import { F as FacilitatorEvmSigner } from '../../../signer-DC81R8wQ.mjs';
import { F as FacilitatorEvmSigner } from '../../../signer-D912R4mq.mjs';

@@ -12,2 +12,8 @@ interface ExactEvmSchemeV1Config {

deployERC4337WithEIP6492?: boolean;
/**
* If enabled, simulates transaction before settling. Defaults to false, ie only simulate during verify.
*
* @default false
*/
simulateInSettle?: boolean;
}

@@ -61,4 +67,13 @@ /**

settle(payload: PaymentPayload, requirements: PaymentRequirements): Promise<SettleResponse>;
/**
* Internal verify with optional simulation control.
*
* @param payload - The payment payload to verify
* @param requirements - The payment requirements
* @param options - Verification options (e.g. simulate)
* @returns Promise resolving to verification response
*/
private _verify;
}
export { ExactEvmSchemeV1, type ExactEvmSchemeV1Config };
import {
ExactEvmSchemeV1
} from "../../../chunk-XL6IFXCP.mjs";
} from "../../../chunk-IZEI7JTG.mjs";
export {

@@ -5,0 +5,0 @@ ExactEvmSchemeV1

@@ -1,3 +0,3 @@

export { E as ExactEvmScheme, a as PERMIT2_ADDRESS, P as Permit2AllowanceParams, d as authorizationTypes, c as createPermit2ApprovalTx, f as eip3009ABI, e as erc20AllowanceAbi, g as getPermit2AllowanceReadParams, p as permit2WitnessTypes, h as x402ExactPermit2ProxyABI, x as x402ExactPermit2ProxyAddress, b as x402UptoPermit2ProxyAddress } from './permit2-BuAhWvNC.mjs';
export { C as ClientEvmSigner, F as FacilitatorEvmSigner, t as toClientEvmSigner, a as toFacilitatorEvmSigner } from './signer-DC81R8wQ.mjs';
export { E as ExactEvmScheme, a as PERMIT2_ADDRESS, P as Permit2AllowanceParams, d as authorizationTypes, c as createPermit2ApprovalTx, f as eip3009ABI, e as erc20AllowanceAbi, g as getPermit2AllowanceReadParams, p as permit2WitnessTypes, h as x402ExactPermit2ProxyABI, x as x402ExactPermit2ProxyAddress, b as x402UptoPermit2ProxyAddress } from './permit2-Bbh3a8_h.mjs';
export { C as ClientEvmSigner, F as FacilitatorEvmSigner, t as toClientEvmSigner, a as toFacilitatorEvmSigner } from './signer-D912R4mq.mjs';
import '@x402/core/types';

@@ -4,0 +4,0 @@

@@ -5,3 +5,3 @@ import {

getPermit2AllowanceReadParams
} from "./chunk-LBIJBD7Q.mjs";
} from "./chunk-WJWNS4G4.mjs";
import {

@@ -11,2 +11,3 @@ isEIP3009Payload,

} from "./chunk-TKN5V2BV.mjs";
import "./chunk-GD4MKCN7.mjs";
import {

@@ -21,3 +22,3 @@ PERMIT2_ADDRESS,

x402UptoPermit2ProxyAddress
} from "./chunk-XL6IFXCP.mjs";
} from "./chunk-IZEI7JTG.mjs";

@@ -27,12 +28,9 @@ // src/signer.ts

const readContract = signer.readContract ?? publicClient?.readContract.bind(publicClient);
if (!readContract) {
throw new Error(
"toClientEvmSigner requires either a signer with readContract or a publicClient. Use createWalletClient(...).extend(publicActions) or pass a publicClient."
);
}
const result = {
address: signer.address,
signTypedData: (msg) => signer.signTypedData(msg),
readContract
signTypedData: (msg) => signer.signTypedData(msg)
};
if (readContract) {
result.readContract = readContract;
}
const signTransaction = signer.signTransaction;

@@ -39,0 +37,0 @@ if (signTransaction) {

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../src/signer.ts"],"sourcesContent":["/**\n * ClientEvmSigner - Used by x402 clients to sign payment authorizations.\n *\n * Typically a viem WalletClient extended with publicActions:\n * ```typescript\n * const client = createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: baseSepolia,\n * transport: http(),\n * }).extend(publicActions);\n * ```\n *\n * Or composed via `toClientEvmSigner(account, publicClient)`.\n */\nexport type ClientEvmSigner = {\n readonly address: `0x${string}`;\n signTypedData(message: {\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<`0x${string}`>;\n readContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n }): Promise<unknown>;\n /**\n * Optional: Signs a raw EIP-1559 transaction without broadcasting.\n * Required for ERC-20 approval gas sponsoring when the token lacks EIP-2612.\n */\n signTransaction?(args: {\n to: `0x${string}`;\n data: `0x${string}`;\n nonce: number;\n gas: bigint;\n maxFeePerGas: bigint;\n maxPriorityFeePerGas: bigint;\n chainId: number;\n }): Promise<`0x${string}`>;\n /**\n * Optional: Gets the current transaction count (nonce) for an address.\n * Required for ERC-20 approval gas sponsoring.\n */\n getTransactionCount?(args: { address: `0x${string}` }): Promise<number>;\n /**\n * Optional: Estimates current gas fees per gas.\n * Required for ERC-20 approval gas sponsoring.\n */\n estimateFeesPerGas?(): Promise<{ maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }>;\n};\n\n/**\n * FacilitatorEvmSigner - Used by x402 facilitators to verify and settle payments\n * This is typically a viem PublicClient + WalletClient combination that can\n * read contract state, verify signatures, write transactions, and wait for receipts\n *\n * Supports multiple addresses for load balancing, key rotation, and high availability\n */\nexport type FacilitatorEvmSigner = {\n /**\n * Get all addresses this facilitator can use for signing\n * Enables dynamic address selection for load balancing and key rotation\n */\n getAddresses(): readonly `0x${string}`[];\n\n readContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n }): Promise<unknown>;\n verifyTypedData(args: {\n address: `0x${string}`;\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n primaryType: string;\n message: Record<string, unknown>;\n signature: `0x${string}`;\n }): Promise<boolean>;\n writeContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args: readonly unknown[];\n }): Promise<`0x${string}`>;\n sendTransaction(args: { to: `0x${string}`; data: `0x${string}` }): Promise<`0x${string}`>;\n waitForTransactionReceipt(args: { hash: `0x${string}` }): Promise<{ status: string }>;\n getCode(args: { address: `0x${string}` }): Promise<`0x${string}` | undefined>;\n};\n\n/**\n * Composes a ClientEvmSigner from a local account and a public client.\n *\n * Use this when your signer (e.g., `privateKeyToAccount`) doesn't have\n * `readContract`. The `publicClient` provides the on-chain read capability.\n *\n * Alternatively, use a WalletClient extended with publicActions directly:\n * ```typescript\n * const signer = createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: baseSepolia,\n * transport: http(),\n * }).extend(publicActions);\n * ```\n *\n * @param signer - A signer with `address` and `signTypedData` (and optionally `readContract`)\n * @param publicClient - A client with `readContract` (required if signer lacks it)\n * @param publicClient.readContract - The readContract method from the public client\n * @param publicClient.getTransactionCount - Optional getTransactionCount for ERC-20 approval\n * @param publicClient.estimateFeesPerGas - Optional estimateFeesPerGas for ERC-20 approval\n * @returns A complete ClientEvmSigner\n *\n * @example\n * ```typescript\n * const account = privateKeyToAccount(\"0x...\");\n * const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });\n * const signer = toClientEvmSigner(account, publicClient);\n * ```\n */\nexport function toClientEvmSigner(\n signer: Omit<ClientEvmSigner, \"readContract\"> & {\n readContract?: ClientEvmSigner[\"readContract\"];\n },\n publicClient?: {\n readContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n }): Promise<unknown>;\n getTransactionCount?(args: { address: `0x${string}` }): Promise<number>;\n estimateFeesPerGas?(): Promise<{ maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }>;\n },\n): ClientEvmSigner {\n const readContract = signer.readContract ?? publicClient?.readContract.bind(publicClient);\n\n if (!readContract) {\n throw new Error(\n \"toClientEvmSigner requires either a signer with readContract or a publicClient. \" +\n \"Use createWalletClient(...).extend(publicActions) or pass a publicClient.\",\n );\n }\n\n const result: ClientEvmSigner = {\n address: signer.address,\n signTypedData: msg => signer.signTypedData(msg),\n readContract,\n };\n\n // Forward optional capabilities from signer or publicClient\n const signTransaction = signer.signTransaction;\n if (signTransaction) {\n result.signTransaction = args => signTransaction(args);\n }\n\n const getTransactionCount =\n signer.getTransactionCount ?? publicClient?.getTransactionCount?.bind(publicClient);\n if (getTransactionCount) {\n result.getTransactionCount = args => getTransactionCount(args);\n }\n\n const estimateFeesPerGas =\n signer.estimateFeesPerGas ?? publicClient?.estimateFeesPerGas?.bind(publicClient);\n if (estimateFeesPerGas) {\n result.estimateFeesPerGas = () => estimateFeesPerGas();\n }\n\n return result;\n}\n\n/**\n * Converts a viem client with single address to a FacilitatorEvmSigner\n * Wraps the single address in a getAddresses() function for compatibility\n *\n * @param client - The client to convert (must have 'address' property)\n * @returns FacilitatorEvmSigner with getAddresses() support\n */\nexport function toFacilitatorEvmSigner(\n client: Omit<FacilitatorEvmSigner, \"getAddresses\"> & { address: `0x${string}` },\n): FacilitatorEvmSigner {\n return {\n ...client,\n getAddresses: () => [client.address],\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAyHO,SAAS,kBACd,QAGA,cAUiB;AACjB,QAAM,eAAe,OAAO,gBAAgB,cAAc,aAAa,KAAK,YAAY;AAExF,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,QAAM,SAA0B;AAAA,IAC9B,SAAS,OAAO;AAAA,IAChB,eAAe,SAAO,OAAO,cAAc,GAAG;AAAA,IAC9C;AAAA,EACF;AAGA,QAAM,kBAAkB,OAAO;AAC/B,MAAI,iBAAiB;AACnB,WAAO,kBAAkB,UAAQ,gBAAgB,IAAI;AAAA,EACvD;AAEA,QAAM,sBACJ,OAAO,uBAAuB,cAAc,qBAAqB,KAAK,YAAY;AACpF,MAAI,qBAAqB;AACvB,WAAO,sBAAsB,UAAQ,oBAAoB,IAAI;AAAA,EAC/D;AAEA,QAAM,qBACJ,OAAO,sBAAsB,cAAc,oBAAoB,KAAK,YAAY;AAClF,MAAI,oBAAoB;AACtB,WAAO,qBAAqB,MAAM,mBAAmB;AAAA,EACvD;AAEA,SAAO;AACT;AASO,SAAS,uBACd,QACsB;AACtB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,cAAc,MAAM,CAAC,OAAO,OAAO;AAAA,EACrC;AACF;","names":[]}
{"version":3,"sources":["../../src/signer.ts"],"sourcesContent":["/**\n * ClientEvmSigner - Used by x402 clients to sign payment authorizations.\n *\n * Typically a viem WalletClient extended with publicActions:\n * ```typescript\n * const client = createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: baseSepolia,\n * transport: http(),\n * }).extend(publicActions);\n * ```\n *\n * Or composed via `toClientEvmSigner(account, publicClient)`.\n */\nexport type ClientEvmSigner = {\n readonly address: `0x${string}`;\n signTypedData(message: {\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<`0x${string}`>;\n /**\n * Optional on-chain reads.\n * Required only for extension enrichment (EIP-2612 / ERC-20 approval).\n */\n readContract?(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n }): Promise<unknown>;\n /**\n * Optional: Signs a raw EIP-1559 transaction without broadcasting.\n * Required for ERC-20 approval gas sponsoring when the token lacks EIP-2612.\n */\n signTransaction?(args: {\n to: `0x${string}`;\n data: `0x${string}`;\n nonce: number;\n gas: bigint;\n maxFeePerGas: bigint;\n maxPriorityFeePerGas: bigint;\n chainId: number;\n }): Promise<`0x${string}`>;\n /**\n * Optional: Gets the current transaction count (nonce) for an address.\n * Required for ERC-20 approval gas sponsoring.\n */\n getTransactionCount?(args: { address: `0x${string}` }): Promise<number>;\n /**\n * Optional: Estimates current gas fees per gas.\n * Required for ERC-20 approval gas sponsoring.\n */\n estimateFeesPerGas?(): Promise<{ maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }>;\n};\n\n/**\n * FacilitatorEvmSigner - Used by x402 facilitators to verify and settle payments\n * This is typically a viem PublicClient + WalletClient combination that can\n * read contract state, verify signatures, write transactions, and wait for receipts\n *\n * Supports multiple addresses for load balancing, key rotation, and high availability\n */\nexport type FacilitatorEvmSigner = {\n /**\n * Get all addresses this facilitator can use for signing\n * Enables dynamic address selection for load balancing and key rotation\n */\n getAddresses(): readonly `0x${string}`[];\n\n readContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n }): Promise<unknown>;\n verifyTypedData(args: {\n address: `0x${string}`;\n domain: Record<string, unknown>;\n types: Record<string, unknown>;\n primaryType: string;\n message: Record<string, unknown>;\n signature: `0x${string}`;\n }): Promise<boolean>;\n writeContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args: readonly unknown[];\n /** Optional gas limit. When provided, skips eth_estimateGas simulation. */\n gas?: bigint;\n }): Promise<`0x${string}`>;\n sendTransaction(args: { to: `0x${string}`; data: `0x${string}` }): Promise<`0x${string}`>;\n waitForTransactionReceipt(args: { hash: `0x${string}` }): Promise<{ status: string }>;\n getCode(args: { address: `0x${string}` }): Promise<`0x${string}` | undefined>;\n};\n\n/**\n * Composes a ClientEvmSigner from a local account and a public client.\n *\n * Use this when your signer (e.g., `privateKeyToAccount`) doesn't have\n * `readContract`. The `publicClient` provides the on-chain read capability.\n *\n * Alternatively, use a WalletClient extended with publicActions directly:\n * ```typescript\n * const signer = createWalletClient({\n * account: privateKeyToAccount('0x...'),\n * chain: baseSepolia,\n * transport: http(),\n * }).extend(publicActions);\n * ```\n *\n * @param signer - A signer with `address` and `signTypedData` (and optionally `readContract`)\n * @param publicClient - A client with optional read/nonce/fee helpers\n * @param publicClient.readContract - The readContract method from the public client\n * @param publicClient.getTransactionCount - Optional getTransactionCount for ERC-20 approval\n * @param publicClient.estimateFeesPerGas - Optional estimateFeesPerGas for ERC-20 approval\n * @returns A ClientEvmSigner with any available optional capabilities\n *\n * @example\n * ```typescript\n * const account = privateKeyToAccount(\"0x...\");\n * const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });\n * const signer = toClientEvmSigner(account, publicClient);\n * ```\n */\nexport function toClientEvmSigner(\n signer: Omit<ClientEvmSigner, \"readContract\"> & {\n readContract?: ClientEvmSigner[\"readContract\"];\n },\n publicClient?: {\n readContract(args: {\n address: `0x${string}`;\n abi: readonly unknown[];\n functionName: string;\n args?: readonly unknown[];\n }): Promise<unknown>;\n getTransactionCount?(args: { address: `0x${string}` }): Promise<number>;\n estimateFeesPerGas?(): Promise<{ maxFeePerGas: bigint; maxPriorityFeePerGas: bigint }>;\n },\n): ClientEvmSigner {\n const readContract = signer.readContract ?? publicClient?.readContract.bind(publicClient);\n\n const result: ClientEvmSigner = {\n address: signer.address,\n signTypedData: msg => signer.signTypedData(msg),\n };\n\n if (readContract) {\n result.readContract = readContract;\n }\n\n // Forward optional capabilities from signer or publicClient\n const signTransaction = signer.signTransaction;\n if (signTransaction) {\n result.signTransaction = args => signTransaction(args);\n }\n\n const getTransactionCount =\n signer.getTransactionCount ?? publicClient?.getTransactionCount?.bind(publicClient);\n if (getTransactionCount) {\n result.getTransactionCount = args => getTransactionCount(args);\n }\n\n const estimateFeesPerGas =\n signer.estimateFeesPerGas ?? publicClient?.estimateFeesPerGas?.bind(publicClient);\n if (estimateFeesPerGas) {\n result.estimateFeesPerGas = () => estimateFeesPerGas();\n }\n\n return result;\n}\n\n/**\n * Converts a viem client with single address to a FacilitatorEvmSigner\n * Wraps the single address in a getAddresses() function for compatibility\n *\n * @param client - The client to convert (must have 'address' property)\n * @returns FacilitatorEvmSigner with getAddresses() support\n */\nexport function toFacilitatorEvmSigner(\n client: Omit<FacilitatorEvmSigner, \"getAddresses\"> & { address: `0x${string}` },\n): FacilitatorEvmSigner {\n return {\n ...client,\n getAddresses: () => [client.address],\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA+HO,SAAS,kBACd,QAGA,cAUiB;AACjB,QAAM,eAAe,OAAO,gBAAgB,cAAc,aAAa,KAAK,YAAY;AAExF,QAAM,SAA0B;AAAA,IAC9B,SAAS,OAAO;AAAA,IAChB,eAAe,SAAO,OAAO,cAAc,GAAG;AAAA,EAChD;AAEA,MAAI,cAAc;AAChB,WAAO,eAAe;AAAA,EACxB;AAGA,QAAM,kBAAkB,OAAO;AAC/B,MAAI,iBAAiB;AACnB,WAAO,kBAAkB,UAAQ,gBAAgB,IAAI;AAAA,EACvD;AAEA,QAAM,sBACJ,OAAO,uBAAuB,cAAc,qBAAqB,KAAK,YAAY;AACpF,MAAI,qBAAqB;AACvB,WAAO,sBAAsB,UAAQ,oBAAoB,IAAI;AAAA,EAC/D;AAEA,QAAM,qBACJ,OAAO,sBAAsB,cAAc,oBAAoB,KAAK,YAAY;AAClF,MAAI,oBAAoB;AACtB,WAAO,qBAAqB,MAAM,mBAAmB;AAAA,EACvD;AAEA,SAAO;AACT;AASO,SAAS,uBACd,QACsB;AACtB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,cAAc,MAAM,CAAC,OAAO,OAAO;AAAA,EACrC;AACF;","names":[]}
export { ExactEvmSchemeV1 } from '../exact/v1/client/index.mjs';
import '@x402/core/types';
import '../signer-DC81R8wQ.mjs';
import '../signer-D912R4mq.mjs';

@@ -5,0 +5,0 @@ declare const EVM_NETWORK_CHAIN_ID_MAP: {

@@ -6,3 +6,3 @@ import {

getEvmChainIdV1
} from "../chunk-XL6IFXCP.mjs";
} from "../chunk-IZEI7JTG.mjs";
export {

@@ -9,0 +9,0 @@ EVM_NETWORK_CHAIN_ID_MAP,

{
"name": "@x402/evm",
"version": "2.6.0",
"version": "2.7.0",
"main": "./dist/cjs/index.js",

@@ -38,4 +38,3 @@ "module": "./dist/esm/index.js",

"zod": "^3.24.2",
"@x402/core": "~2.6.0",
"@x402/extensions": "~2.6.0"
"@x402/core": "~2.7.0"
},

@@ -42,0 +41,0 @@ "exports": {

@@ -128,2 +128,26 @@ # @x402/evm

### Extension RPC Configuration (Optional)
`ExactEvmClient` only requires signer support for `address` + `signTypedData`.
Permit2 extension enrichment (EIP-2612 / ERC-20 approval gas sponsoring) can
optionally use explicit RPC config when signer read/fee helpers are unavailable.
No chain-default RPC fallback is applied by the SDK.
```typescript
// Per-network explicit registration
const client = new x402Client()
.register("eip155:137", new ExactEvmClient(signer, { rpcUrl: polygonRpcUrl }))
.register("eip155:8453", new ExactEvmClient(signer, { rpcUrl: baseRpcUrl }));
// Wildcard registration with chain-id keyed config map
const wildcardClient = new x402Client().register(
"eip155:*",
new ExactEvmClient(signer, {
137: { rpcUrl: polygonRpcUrl },
8453: { rpcUrl: baseRpcUrl },
}),
);
```
### 3. Using Config (Flexible)

@@ -130,0 +154,0 @@

import { SchemeNetworkClient, PaymentRequirements, PaymentPayloadContext, PaymentPayloadResult } from '@x402/core/types';
import { C as ClientEvmSigner } from './signer-DC81R8wQ.js';
/**
* EVM client implementation for the Exact payment scheme.
* Supports both EIP-3009 (transferWithAuthorization) and Permit2 flows.
*
* Routes to the appropriate authorization method based on
* `requirements.extra.assetTransferMethod`. Defaults to EIP-3009
* for backward compatibility with older facilitators.
*
* When the server advertises `eip2612GasSponsoring` and the asset transfer
* method is `permit2`, the scheme automatically signs an EIP-2612 permit
* if the user lacks Permit2 approval. This requires `readContract` on the signer.
*/
declare class ExactEvmScheme implements SchemeNetworkClient {
private readonly signer;
readonly scheme = "exact";
/**
* Creates a new ExactEvmClient instance.
*
* @param signer - The EVM signer for client operations.
* Must support `readContract` for EIP-2612 gas sponsoring.
* Use `createWalletClient(...).extend(publicActions)` or `toClientEvmSigner(account, publicClient)`.
*/
constructor(signer: ClientEvmSigner);
/**
* Creates a payment payload for the Exact scheme.
* Routes to EIP-3009 or Permit2 based on requirements.extra.assetTransferMethod.
*
* For Permit2 flows, if the server advertises `eip2612GasSponsoring` and the
* signer supports `readContract`, automatically signs an EIP-2612 permit
* when Permit2 allowance is insufficient.
*
* @param x402Version - The x402 protocol version
* @param paymentRequirements - The payment requirements
* @param context - Optional context with server-declared extensions
* @returns Promise resolving to a payment payload result (with optional extensions)
*/
createPaymentPayload(x402Version: number, paymentRequirements: PaymentRequirements, context?: PaymentPayloadContext): Promise<PaymentPayloadResult>;
/**
* Attempts to sign an EIP-2612 permit for gasless Permit2 approval.
*
* Returns extension data if:
* 1. Server advertises eip2612GasSponsoring
* 2. Signer has readContract capability
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param result - The payment payload result from the scheme
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for EIP-2612 gas sponsoring, or undefined if not applicable
*/
private trySignEip2612Permit;
/**
* Attempts to sign an ERC-20 approval transaction for gasless Permit2 approval.
*
* This is the fallback path when the token does not support EIP-2612. The client
* signs (but does not broadcast) a raw `approve(Permit2, MaxUint256)` transaction.
* The facilitator broadcasts it atomically before settling.
*
* Returns extension data if:
* 1. Server advertises erc20ApprovalGasSponsoring
* 2. Signer has signTransaction + getTransactionCount capabilities
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param _result - The payment payload result from the scheme (unused)
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for ERC-20 approval gas sponsoring, or undefined if not applicable
*/
private trySignErc20Approval;
}
declare const authorizationTypes: {
readonly TransferWithAuthorization: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}];
};
/**
* Permit2 EIP-712 types for signing PermitWitnessTransferFrom.
* Must match the exact format expected by the Permit2 contract.
* Note: Types must be in ALPHABETICAL order after the primary type (TokenPermissions < Witness).
*/
declare const permit2WitnessTypes: {
readonly PermitWitnessTransferFrom: readonly [{
readonly name: "permitted";
readonly type: "TokenPermissions";
}, {
readonly name: "spender";
readonly type: "address";
}, {
readonly name: "nonce";
readonly type: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
}, {
readonly name: "witness";
readonly type: "Witness";
}];
readonly TokenPermissions: readonly [{
readonly name: "token";
readonly type: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
}];
readonly Witness: readonly [{
readonly name: "to";
readonly type: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}];
};
declare const eip3009ABI: readonly [{
readonly inputs: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}, {
readonly name: "v";
readonly type: "uint8";
}, {
readonly name: "r";
readonly type: "bytes32";
}, {
readonly name: "s";
readonly type: "bytes32";
}];
readonly name: "transferWithAuthorization";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}, {
readonly name: "signature";
readonly type: "bytes";
}];
readonly name: "transferWithAuthorization";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly name: "account";
readonly type: "address";
}];
readonly name: "balanceOf";
readonly outputs: readonly [{
readonly name: "";
readonly type: "uint256";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [];
readonly name: "version";
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
}];
readonly stateMutability: "view";
readonly type: "function";
}];
/** ERC-20 allowance(address,address) ABI for checking spender approval. */
declare const erc20AllowanceAbi: readonly [{
readonly type: "function";
readonly name: "allowance";
readonly inputs: readonly [{
readonly name: "owner";
readonly type: "address";
}, {
readonly name: "spender";
readonly type: "address";
}];
readonly outputs: readonly [{
readonly type: "uint256";
}];
readonly stateMutability: "view";
}];
/**
* Canonical Permit2 contract address.
* Same address on all EVM chains via CREATE2 deployment.
*
* @see https://github.com/Uniswap/permit2
*/
declare const PERMIT2_ADDRESS: "0x000000000022D473030F116dDEE9F6B43aC78BA3";
/**
* x402ExactPermit2Proxy contract address.
* Vanity address: 0x4020...0001 for easy recognition.
* This address is deterministic based on:
* - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)
* - Vanity-mined salt for prefix 0x4020 and suffix 0001
* - Contract bytecode + constructor args (PERMIT2_ADDRESS)
*/
declare const x402ExactPermit2ProxyAddress: "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";
/**
* x402UptoPermit2Proxy contract address.
* Vanity address: 0x4020...0002 for easy recognition.
* This address is deterministic based on:
* - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)
* - Vanity-mined salt for prefix 0x4020 and suffix 0002
* - Contract bytecode + constructor args (PERMIT2_ADDRESS)
*/
declare const x402UptoPermit2ProxyAddress: "0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002";
/**
* x402ExactPermit2Proxy ABI - settle function for exact payment scheme.
*/
declare const x402ExactPermit2ProxyABI: readonly [{
readonly type: "function";
readonly name: "PERMIT2";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "address";
readonly internalType: "contract ISignatureTransfer";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "WITNESS_TYPEHASH";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "bytes32";
readonly internalType: "bytes32";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "WITNESS_TYPE_STRING";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
readonly internalType: "string";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "settle";
readonly inputs: readonly [{
readonly name: "permit";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.PermitTransferFrom";
readonly components: readonly [{
readonly name: "permitted";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.TokenPermissions";
readonly components: readonly [{
readonly name: "token";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "nonce";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "owner";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "witness";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.Witness";
readonly components: readonly [{
readonly name: "to";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "signature";
readonly type: "bytes";
readonly internalType: "bytes";
}];
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
}, {
readonly type: "function";
readonly name: "settleWithPermit";
readonly inputs: readonly [{
readonly name: "permit2612";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.EIP2612Permit";
readonly components: readonly [{
readonly name: "value";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "r";
readonly type: "bytes32";
readonly internalType: "bytes32";
}, {
readonly name: "s";
readonly type: "bytes32";
readonly internalType: "bytes32";
}, {
readonly name: "v";
readonly type: "uint8";
readonly internalType: "uint8";
}];
}, {
readonly name: "permit";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.PermitTransferFrom";
readonly components: readonly [{
readonly name: "permitted";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.TokenPermissions";
readonly components: readonly [{
readonly name: "token";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "nonce";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "owner";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "witness";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.Witness";
readonly components: readonly [{
readonly name: "to";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "signature";
readonly type: "bytes";
readonly internalType: "bytes";
}];
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
}, {
readonly type: "event";
readonly name: "Settled";
readonly inputs: readonly [];
readonly anonymous: false;
}, {
readonly type: "event";
readonly name: "SettledWithPermit";
readonly inputs: readonly [];
readonly anonymous: false;
}, {
readonly type: "error";
readonly name: "InvalidAmount";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidDestination";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidOwner";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidPermit2Address";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "PaymentTooEarly";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "Permit2612AmountMismatch";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "ReentrancyGuardReentrantCall";
readonly inputs: readonly [];
}];
/**
* Creates transaction data to approve Permit2 to spend tokens.
* The user sends this transaction (paying gas) before using Permit2 flow.
*
* @param tokenAddress - The ERC20 token contract address
* @returns Transaction data to send for approval
*
* @example
* ```typescript
* const tx = createPermit2ApprovalTx("0x...");
* await walletClient.sendTransaction({
* to: tx.to,
* data: tx.data,
* });
* ```
*/
declare function createPermit2ApprovalTx(tokenAddress: `0x${string}`): {
to: `0x${string}`;
data: `0x${string}`;
};
/**
* Parameters for checking Permit2 allowance.
* Application provides these to check if approval is needed.
*/
interface Permit2AllowanceParams {
tokenAddress: `0x${string}`;
ownerAddress: `0x${string}`;
}
/**
* Returns contract read parameters for checking Permit2 allowance.
* Use with a public client to check if the user has approved Permit2.
*
* @param params - The allowance check parameters
* @returns Contract read parameters for checking allowance
*
* @example
* ```typescript
* const readParams = getPermit2AllowanceReadParams({
* tokenAddress: "0x...",
* ownerAddress: "0x...",
* });
*
* const allowance = await publicClient.readContract(readParams);
* const needsApproval = allowance < requiredAmount;
* ```
*/
declare function getPermit2AllowanceReadParams(params: Permit2AllowanceParams): {
address: `0x${string}`;
abi: typeof erc20AllowanceAbi;
functionName: "allowance";
args: [`0x${string}`, `0x${string}`];
};
export { ExactEvmScheme as E, type Permit2AllowanceParams as P, PERMIT2_ADDRESS as a, x402UptoPermit2ProxyAddress as b, createPermit2ApprovalTx as c, authorizationTypes as d, erc20AllowanceAbi as e, eip3009ABI as f, getPermit2AllowanceReadParams as g, x402ExactPermit2ProxyABI as h, permit2WitnessTypes as p, x402ExactPermit2ProxyAddress as x };
/**
* ClientEvmSigner - Used by x402 clients to sign payment authorizations.
*
* Typically a viem WalletClient extended with publicActions:
* ```typescript
* const client = createWalletClient({
* account: privateKeyToAccount('0x...'),
* chain: baseSepolia,
* transport: http(),
* }).extend(publicActions);
* ```
*
* Or composed via `toClientEvmSigner(account, publicClient)`.
*/
type ClientEvmSigner = {
readonly address: `0x${string}`;
signTypedData(message: {
domain: Record<string, unknown>;
types: Record<string, unknown>;
primaryType: string;
message: Record<string, unknown>;
}): Promise<`0x${string}`>;
readContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
/**
* Optional: Signs a raw EIP-1559 transaction without broadcasting.
* Required for ERC-20 approval gas sponsoring when the token lacks EIP-2612.
*/
signTransaction?(args: {
to: `0x${string}`;
data: `0x${string}`;
nonce: number;
gas: bigint;
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
chainId: number;
}): Promise<`0x${string}`>;
/**
* Optional: Gets the current transaction count (nonce) for an address.
* Required for ERC-20 approval gas sponsoring.
*/
getTransactionCount?(args: {
address: `0x${string}`;
}): Promise<number>;
/**
* Optional: Estimates current gas fees per gas.
* Required for ERC-20 approval gas sponsoring.
*/
estimateFeesPerGas?(): Promise<{
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
}>;
};
/**
* FacilitatorEvmSigner - Used by x402 facilitators to verify and settle payments
* This is typically a viem PublicClient + WalletClient combination that can
* read contract state, verify signatures, write transactions, and wait for receipts
*
* Supports multiple addresses for load balancing, key rotation, and high availability
*/
type FacilitatorEvmSigner = {
/**
* Get all addresses this facilitator can use for signing
* Enables dynamic address selection for load balancing and key rotation
*/
getAddresses(): readonly `0x${string}`[];
readContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
verifyTypedData(args: {
address: `0x${string}`;
domain: Record<string, unknown>;
types: Record<string, unknown>;
primaryType: string;
message: Record<string, unknown>;
signature: `0x${string}`;
}): Promise<boolean>;
writeContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args: readonly unknown[];
}): Promise<`0x${string}`>;
sendTransaction(args: {
to: `0x${string}`;
data: `0x${string}`;
}): Promise<`0x${string}`>;
waitForTransactionReceipt(args: {
hash: `0x${string}`;
}): Promise<{
status: string;
}>;
getCode(args: {
address: `0x${string}`;
}): Promise<`0x${string}` | undefined>;
};
/**
* Composes a ClientEvmSigner from a local account and a public client.
*
* Use this when your signer (e.g., `privateKeyToAccount`) doesn't have
* `readContract`. The `publicClient` provides the on-chain read capability.
*
* Alternatively, use a WalletClient extended with publicActions directly:
* ```typescript
* const signer = createWalletClient({
* account: privateKeyToAccount('0x...'),
* chain: baseSepolia,
* transport: http(),
* }).extend(publicActions);
* ```
*
* @param signer - A signer with `address` and `signTypedData` (and optionally `readContract`)
* @param publicClient - A client with `readContract` (required if signer lacks it)
* @param publicClient.readContract - The readContract method from the public client
* @param publicClient.getTransactionCount - Optional getTransactionCount for ERC-20 approval
* @param publicClient.estimateFeesPerGas - Optional estimateFeesPerGas for ERC-20 approval
* @returns A complete ClientEvmSigner
*
* @example
* ```typescript
* const account = privateKeyToAccount("0x...");
* const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
* const signer = toClientEvmSigner(account, publicClient);
* ```
*/
declare function toClientEvmSigner(signer: Omit<ClientEvmSigner, "readContract"> & {
readContract?: ClientEvmSigner["readContract"];
}, publicClient?: {
readContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
getTransactionCount?(args: {
address: `0x${string}`;
}): Promise<number>;
estimateFeesPerGas?(): Promise<{
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
}>;
}): ClientEvmSigner;
/**
* Converts a viem client with single address to a FacilitatorEvmSigner
* Wraps the single address in a getAddresses() function for compatibility
*
* @param client - The client to convert (must have 'address' property)
* @returns FacilitatorEvmSigner with getAddresses() support
*/
declare function toFacilitatorEvmSigner(client: Omit<FacilitatorEvmSigner, "getAddresses"> & {
address: `0x${string}`;
}): FacilitatorEvmSigner;
export { type ClientEvmSigner as C, type FacilitatorEvmSigner as F, toFacilitatorEvmSigner as a, toClientEvmSigner as t };
import {
DEFAULT_MAX_FEE_PER_GAS,
DEFAULT_MAX_PRIORITY_FEE_PER_GAS,
ERC20_APPROVE_GAS_LIMIT,
ExactEvmSchemeV12 as ExactEvmSchemeV1,
NETWORKS,
PERMIT2_ADDRESS,
authorizationTypes,
createNonce,
createPermit2Nonce,
eip2612NoncesAbi,
eip2612PermitTypes,
erc20AllowanceAbi,
erc20ApproveAbi,
getEvmChainId,
permit2WitnessTypes,
x402ExactPermit2ProxyAddress
} from "./chunk-XL6IFXCP.mjs";
// src/exact/client/scheme.ts
import { EIP2612_GAS_SPONSORING, ERC20_APPROVAL_GAS_SPONSORING } from "@x402/extensions";
import { getAddress as getAddress5 } from "viem";
// src/exact/client/eip3009.ts
import { getAddress } from "viem";
async function createEIP3009Payload(signer, x402Version, paymentRequirements) {
const nonce = createNonce();
const now = Math.floor(Date.now() / 1e3);
const authorization = {
from: signer.address,
to: getAddress(paymentRequirements.payTo),
value: paymentRequirements.amount,
validAfter: (now - 600).toString(),
validBefore: (now + paymentRequirements.maxTimeoutSeconds).toString(),
nonce
};
const signature = await signEIP3009Authorization(signer, authorization, paymentRequirements);
const payload = {
authorization,
signature
};
return {
x402Version,
payload
};
}
async function signEIP3009Authorization(signer, authorization, requirements) {
const chainId = getEvmChainId(requirements.network);
if (!requirements.extra?.name || !requirements.extra?.version) {
throw new Error(
`EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`
);
}
const { name, version } = requirements.extra;
const domain = {
name,
version,
chainId,
verifyingContract: getAddress(requirements.asset)
};
const message = {
from: getAddress(authorization.from),
to: getAddress(authorization.to),
value: BigInt(authorization.value),
validAfter: BigInt(authorization.validAfter),
validBefore: BigInt(authorization.validBefore),
nonce: authorization.nonce
};
return await signer.signTypedData({
domain,
types: authorizationTypes,
primaryType: "TransferWithAuthorization",
message
});
}
// src/exact/client/permit2.ts
import { encodeFunctionData, getAddress as getAddress2 } from "viem";
var MAX_UINT256 = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
async function createPermit2Payload(signer, x402Version, paymentRequirements) {
const now = Math.floor(Date.now() / 1e3);
const nonce = createPermit2Nonce();
const validAfter = (now - 600).toString();
const deadline = (now + paymentRequirements.maxTimeoutSeconds).toString();
const permit2Authorization = {
from: signer.address,
permitted: {
token: getAddress2(paymentRequirements.asset),
amount: paymentRequirements.amount
},
spender: x402ExactPermit2ProxyAddress,
nonce,
deadline,
witness: {
to: getAddress2(paymentRequirements.payTo),
validAfter
}
};
const signature = await signPermit2Authorization(
signer,
permit2Authorization,
paymentRequirements
);
const payload = {
signature,
permit2Authorization
};
return {
x402Version,
payload
};
}
async function signPermit2Authorization(signer, permit2Authorization, requirements) {
const chainId = getEvmChainId(requirements.network);
const domain = {
name: "Permit2",
chainId,
verifyingContract: PERMIT2_ADDRESS
};
const message = {
permitted: {
token: getAddress2(permit2Authorization.permitted.token),
amount: BigInt(permit2Authorization.permitted.amount)
},
spender: getAddress2(permit2Authorization.spender),
nonce: BigInt(permit2Authorization.nonce),
deadline: BigInt(permit2Authorization.deadline),
witness: {
to: getAddress2(permit2Authorization.witness.to),
validAfter: BigInt(permit2Authorization.witness.validAfter)
}
};
return await signer.signTypedData({
domain,
types: permit2WitnessTypes,
primaryType: "PermitWitnessTransferFrom",
message
});
}
function createPermit2ApprovalTx(tokenAddress) {
const data = encodeFunctionData({
abi: erc20ApproveAbi,
functionName: "approve",
args: [PERMIT2_ADDRESS, MAX_UINT256]
});
return {
to: getAddress2(tokenAddress),
data
};
}
function getPermit2AllowanceReadParams(params) {
return {
address: getAddress2(params.tokenAddress),
abi: erc20AllowanceAbi,
functionName: "allowance",
args: [getAddress2(params.ownerAddress), PERMIT2_ADDRESS]
};
}
// src/exact/client/eip2612.ts
import { getAddress as getAddress3 } from "viem";
async function signEip2612Permit(signer, tokenAddress, tokenName, tokenVersion, chainId, deadline, permittedAmount) {
const owner = signer.address;
const spender = getAddress3(PERMIT2_ADDRESS);
const nonce = await signer.readContract({
address: tokenAddress,
abi: eip2612NoncesAbi,
functionName: "nonces",
args: [owner]
});
const domain = {
name: tokenName,
version: tokenVersion,
chainId,
verifyingContract: tokenAddress
};
const approvalAmount = BigInt(permittedAmount);
const message = {
owner,
spender,
value: approvalAmount,
nonce,
deadline: BigInt(deadline)
};
const signature = await signer.signTypedData({
domain,
types: eip2612PermitTypes,
primaryType: "Permit",
message
});
return {
from: owner,
asset: tokenAddress,
spender,
amount: approvalAmount.toString(),
nonce: nonce.toString(),
deadline,
signature,
version: "1"
};
}
// src/exact/client/erc20approval.ts
import { encodeFunctionData as encodeFunctionData2, getAddress as getAddress4, maxUint256 } from "viem";
import {
ERC20_APPROVAL_GAS_SPONSORING_VERSION
} from "@x402/extensions";
async function signErc20ApprovalTransaction(signer, tokenAddress, chainId) {
const from = signer.address;
const spender = getAddress4(PERMIT2_ADDRESS);
const data = encodeFunctionData2({
abi: erc20ApproveAbi,
functionName: "approve",
args: [spender, maxUint256]
});
const nonce = await signer.getTransactionCount({ address: from });
let maxFeePerGas;
let maxPriorityFeePerGas;
try {
const fees = await signer.estimateFeesPerGas();
maxFeePerGas = fees.maxFeePerGas;
maxPriorityFeePerGas = fees.maxPriorityFeePerGas;
} catch {
maxFeePerGas = DEFAULT_MAX_FEE_PER_GAS;
maxPriorityFeePerGas = DEFAULT_MAX_PRIORITY_FEE_PER_GAS;
}
const signedTransaction = await signer.signTransaction({
to: tokenAddress,
data,
nonce,
gas: ERC20_APPROVE_GAS_LIMIT,
maxFeePerGas,
maxPriorityFeePerGas,
chainId
});
return {
from,
asset: tokenAddress,
spender,
amount: maxUint256.toString(),
signedTransaction,
version: ERC20_APPROVAL_GAS_SPONSORING_VERSION
};
}
// src/exact/client/scheme.ts
var ExactEvmScheme = class {
/**
* Creates a new ExactEvmClient instance.
*
* @param signer - The EVM signer for client operations.
* Must support `readContract` for EIP-2612 gas sponsoring.
* Use `createWalletClient(...).extend(publicActions)` or `toClientEvmSigner(account, publicClient)`.
*/
constructor(signer) {
this.signer = signer;
this.scheme = "exact";
}
/**
* Creates a payment payload for the Exact scheme.
* Routes to EIP-3009 or Permit2 based on requirements.extra.assetTransferMethod.
*
* For Permit2 flows, if the server advertises `eip2612GasSponsoring` and the
* signer supports `readContract`, automatically signs an EIP-2612 permit
* when Permit2 allowance is insufficient.
*
* @param x402Version - The x402 protocol version
* @param paymentRequirements - The payment requirements
* @param context - Optional context with server-declared extensions
* @returns Promise resolving to a payment payload result (with optional extensions)
*/
async createPaymentPayload(x402Version, paymentRequirements, context) {
const assetTransferMethod = paymentRequirements.extra?.assetTransferMethod ?? "eip3009";
if (assetTransferMethod === "permit2") {
const result = await createPermit2Payload(this.signer, x402Version, paymentRequirements);
const eip2612Extensions = await this.trySignEip2612Permit(
paymentRequirements,
result,
context
);
if (eip2612Extensions) {
return {
...result,
extensions: eip2612Extensions
};
}
const erc20Extensions = await this.trySignErc20Approval(paymentRequirements, result, context);
if (erc20Extensions) {
return {
...result,
extensions: erc20Extensions
};
}
return result;
}
return createEIP3009Payload(this.signer, x402Version, paymentRequirements);
}
/**
* Attempts to sign an EIP-2612 permit for gasless Permit2 approval.
*
* Returns extension data if:
* 1. Server advertises eip2612GasSponsoring
* 2. Signer has readContract capability
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param result - The payment payload result from the scheme
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for EIP-2612 gas sponsoring, or undefined if not applicable
*/
async trySignEip2612Permit(requirements, result, context) {
if (!context?.extensions?.[EIP2612_GAS_SPONSORING.key]) {
return void 0;
}
const tokenName = requirements.extra?.name;
const tokenVersion = requirements.extra?.version;
if (!tokenName || !tokenVersion) {
return void 0;
}
const chainId = getEvmChainId(requirements.network);
const tokenAddress = getAddress5(requirements.asset);
try {
const allowance = await this.signer.readContract({
address: tokenAddress,
abi: erc20AllowanceAbi,
functionName: "allowance",
args: [this.signer.address, PERMIT2_ADDRESS]
});
if (allowance >= BigInt(requirements.amount)) {
return void 0;
}
} catch {
}
const permit2Auth = result.payload?.permit2Authorization;
const deadline = permit2Auth?.deadline ?? Math.floor(Date.now() / 1e3 + requirements.maxTimeoutSeconds).toString();
const info = await signEip2612Permit(
this.signer,
tokenAddress,
tokenName,
tokenVersion,
chainId,
deadline,
requirements.amount
);
return {
[EIP2612_GAS_SPONSORING.key]: { info }
};
}
/**
* Attempts to sign an ERC-20 approval transaction for gasless Permit2 approval.
*
* This is the fallback path when the token does not support EIP-2612. The client
* signs (but does not broadcast) a raw `approve(Permit2, MaxUint256)` transaction.
* The facilitator broadcasts it atomically before settling.
*
* Returns extension data if:
* 1. Server advertises erc20ApprovalGasSponsoring
* 2. Signer has signTransaction + getTransactionCount capabilities
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param _result - The payment payload result from the scheme (unused)
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for ERC-20 approval gas sponsoring, or undefined if not applicable
*/
async trySignErc20Approval(requirements, _result, context) {
if (!context?.extensions?.[ERC20_APPROVAL_GAS_SPONSORING.key]) {
return void 0;
}
if (!this.signer.signTransaction || !this.signer.getTransactionCount) {
return void 0;
}
const chainId = getEvmChainId(requirements.network);
const tokenAddress = getAddress5(requirements.asset);
try {
const allowance = await this.signer.readContract({
address: tokenAddress,
abi: erc20AllowanceAbi,
functionName: "allowance",
args: [this.signer.address, PERMIT2_ADDRESS]
});
if (allowance >= BigInt(requirements.amount)) {
return void 0;
}
} catch {
}
const info = await signErc20ApprovalTransaction(this.signer, tokenAddress, chainId);
return {
[ERC20_APPROVAL_GAS_SPONSORING.key]: { info }
};
}
};
// src/exact/client/register.ts
function registerExactEvmScheme(client, config) {
const evmScheme = new ExactEvmScheme(config.signer);
if (config.networks && config.networks.length > 0) {
config.networks.forEach((network) => {
client.register(network, evmScheme);
});
} else {
client.register("eip155:*", evmScheme);
}
NETWORKS.forEach((network) => {
client.registerV1(network, new ExactEvmSchemeV1(config.signer));
});
if (config.policies) {
config.policies.forEach((policy) => {
client.registerPolicy(policy);
});
}
return client;
}
export {
createPermit2ApprovalTx,
getPermit2AllowanceReadParams,
ExactEvmScheme,
registerExactEvmScheme
};
//# sourceMappingURL=chunk-LBIJBD7Q.mjs.map
{"version":3,"sources":["../../src/exact/client/scheme.ts","../../src/exact/client/eip3009.ts","../../src/exact/client/permit2.ts","../../src/exact/client/eip2612.ts","../../src/exact/client/erc20approval.ts","../../src/exact/client/register.ts"],"sourcesContent":["import {\n PaymentRequirements,\n SchemeNetworkClient,\n PaymentPayloadResult,\n PaymentPayloadContext,\n} from \"@x402/core/types\";\nimport { EIP2612_GAS_SPONSORING, ERC20_APPROVAL_GAS_SPONSORING } from \"@x402/extensions\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport { AssetTransferMethod } from \"../../types\";\nimport { PERMIT2_ADDRESS, erc20AllowanceAbi } from \"../../constants\";\nimport { getAddress } from \"viem\";\nimport { getEvmChainId } from \"../../utils\";\nimport { createEIP3009Payload } from \"./eip3009\";\nimport { createPermit2Payload } from \"./permit2\";\nimport { signEip2612Permit } from \"./eip2612\";\nimport { signErc20ApprovalTransaction } from \"./erc20approval\";\n\n/**\n * EVM client implementation for the Exact payment scheme.\n * Supports both EIP-3009 (transferWithAuthorization) and Permit2 flows.\n *\n * Routes to the appropriate authorization method based on\n * `requirements.extra.assetTransferMethod`. Defaults to EIP-3009\n * for backward compatibility with older facilitators.\n *\n * When the server advertises `eip2612GasSponsoring` and the asset transfer\n * method is `permit2`, the scheme automatically signs an EIP-2612 permit\n * if the user lacks Permit2 approval. This requires `readContract` on the signer.\n */\nexport class ExactEvmScheme implements SchemeNetworkClient {\n readonly scheme = \"exact\";\n\n /**\n * Creates a new ExactEvmClient instance.\n *\n * @param signer - The EVM signer for client operations.\n * Must support `readContract` for EIP-2612 gas sponsoring.\n * Use `createWalletClient(...).extend(publicActions)` or `toClientEvmSigner(account, publicClient)`.\n */\n constructor(private readonly signer: ClientEvmSigner) {}\n\n /**\n * Creates a payment payload for the Exact scheme.\n * Routes to EIP-3009 or Permit2 based on requirements.extra.assetTransferMethod.\n *\n * For Permit2 flows, if the server advertises `eip2612GasSponsoring` and the\n * signer supports `readContract`, automatically signs an EIP-2612 permit\n * when Permit2 allowance is insufficient.\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @param context - Optional context with server-declared extensions\n * @returns Promise resolving to a payment payload result (with optional extensions)\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n context?: PaymentPayloadContext,\n ): Promise<PaymentPayloadResult> {\n const assetTransferMethod =\n (paymentRequirements.extra?.assetTransferMethod as AssetTransferMethod) ?? \"eip3009\";\n\n if (assetTransferMethod === \"permit2\") {\n const result = await createPermit2Payload(this.signer, x402Version, paymentRequirements);\n\n // Check if EIP-2612 gas sponsoring is advertised and we can handle it\n const eip2612Extensions = await this.trySignEip2612Permit(\n paymentRequirements,\n result,\n context,\n );\n\n if (eip2612Extensions) {\n return {\n ...result,\n extensions: eip2612Extensions,\n };\n }\n\n // EIP-2612 not applicable — try ERC-20 approval gas sponsoring as fallback\n const erc20Extensions = await this.trySignErc20Approval(paymentRequirements, result, context);\n if (erc20Extensions) {\n return {\n ...result,\n extensions: erc20Extensions,\n };\n }\n\n return result;\n }\n\n return createEIP3009Payload(this.signer, x402Version, paymentRequirements);\n }\n\n /**\n * Attempts to sign an EIP-2612 permit for gasless Permit2 approval.\n *\n * Returns extension data if:\n * 1. Server advertises eip2612GasSponsoring\n * 2. Signer has readContract capability\n * 3. Current Permit2 allowance is insufficient\n *\n * Returns undefined if the extension should not be used.\n *\n * @param requirements - The payment requirements from the server\n * @param result - The payment payload result from the scheme\n * @param context - Optional context containing server extensions and metadata\n * @returns Extension data for EIP-2612 gas sponsoring, or undefined if not applicable\n */\n private async trySignEip2612Permit(\n requirements: PaymentRequirements,\n result: PaymentPayloadResult,\n context?: PaymentPayloadContext,\n ): Promise<Record<string, unknown> | undefined> {\n // Check if server advertises eip2612GasSponsoring\n if (!context?.extensions?.[EIP2612_GAS_SPONSORING.key]) {\n return undefined;\n }\n\n // Check that required token metadata is available\n const tokenName = requirements.extra?.name as string | undefined;\n const tokenVersion = requirements.extra?.version as string | undefined;\n if (!tokenName || !tokenVersion) {\n return undefined;\n }\n\n const chainId = getEvmChainId(requirements.network);\n const tokenAddress = getAddress(requirements.asset) as `0x${string}`;\n\n // Check if user already has sufficient Permit2 allowance\n try {\n const allowance = (await this.signer.readContract({\n address: tokenAddress,\n abi: erc20AllowanceAbi,\n functionName: \"allowance\",\n args: [this.signer.address, PERMIT2_ADDRESS],\n })) as bigint;\n\n if (allowance >= BigInt(requirements.amount)) {\n return undefined; // Already approved, no need for EIP-2612\n }\n } catch {\n // If we can't check allowance, proceed with EIP-2612 signing\n }\n\n // Use the same deadline as the Permit2 authorization\n const permit2Auth = result.payload?.permit2Authorization as Record<string, unknown> | undefined;\n const deadline =\n (permit2Auth?.deadline as string) ??\n Math.floor(Date.now() / 1000 + requirements.maxTimeoutSeconds).toString();\n\n // Sign the EIP-2612 permit with the exact Permit2 permitted amount\n // (the contract enforces permit2612.value == permit.permitted.amount)\n const info = await signEip2612Permit(\n this.signer,\n tokenAddress,\n tokenName,\n tokenVersion,\n chainId,\n deadline,\n requirements.amount,\n );\n\n return {\n [EIP2612_GAS_SPONSORING.key]: { info },\n };\n }\n\n /**\n * Attempts to sign an ERC-20 approval transaction for gasless Permit2 approval.\n *\n * This is the fallback path when the token does not support EIP-2612. The client\n * signs (but does not broadcast) a raw `approve(Permit2, MaxUint256)` transaction.\n * The facilitator broadcasts it atomically before settling.\n *\n * Returns extension data if:\n * 1. Server advertises erc20ApprovalGasSponsoring\n * 2. Signer has signTransaction + getTransactionCount capabilities\n * 3. Current Permit2 allowance is insufficient\n *\n * Returns undefined if the extension should not be used.\n *\n * @param requirements - The payment requirements from the server\n * @param _result - The payment payload result from the scheme (unused)\n * @param context - Optional context containing server extensions and metadata\n * @returns Extension data for ERC-20 approval gas sponsoring, or undefined if not applicable\n */\n private async trySignErc20Approval(\n requirements: PaymentRequirements,\n _result: PaymentPayloadResult,\n context?: PaymentPayloadContext,\n ): Promise<Record<string, unknown> | undefined> {\n // Check if server advertises erc20ApprovalGasSponsoring\n if (!context?.extensions?.[ERC20_APPROVAL_GAS_SPONSORING.key]) {\n return undefined;\n }\n\n // Check that signer has the required capabilities for signing raw transactions\n if (!this.signer.signTransaction || !this.signer.getTransactionCount) {\n return undefined;\n }\n\n const chainId = getEvmChainId(requirements.network);\n const tokenAddress = getAddress(requirements.asset) as `0x${string}`;\n\n // Check if user already has sufficient Permit2 allowance\n try {\n const allowance = (await this.signer.readContract({\n address: tokenAddress,\n abi: erc20AllowanceAbi,\n functionName: \"allowance\",\n args: [this.signer.address, PERMIT2_ADDRESS],\n })) as bigint;\n\n if (allowance >= BigInt(requirements.amount)) {\n return undefined; // Already approved, no need for ERC-20 approval tx\n }\n } catch {\n // If we can't check allowance, proceed with signing\n }\n\n // Sign the approve(Permit2, MaxUint256) transaction\n const info = await signErc20ApprovalTransaction(this.signer, tokenAddress, chainId);\n\n return {\n [ERC20_APPROVAL_GAS_SPONSORING.key]: { info },\n };\n }\n}\n","import { PaymentRequirements, PaymentPayloadResult } from \"@x402/core/types\";\nimport { getAddress } from \"viem\";\nimport { authorizationTypes } from \"../../constants\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport { ExactEIP3009Payload } from \"../../types\";\nimport { createNonce, getEvmChainId } from \"../../utils\";\n\n/**\n * Creates an EIP-3009 (transferWithAuthorization) payload.\n *\n * @param signer - The EVM signer for client operations\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload result\n */\nexport async function createEIP3009Payload(\n signer: ClientEvmSigner,\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n): Promise<PaymentPayloadResult> {\n const nonce = createNonce();\n const now = Math.floor(Date.now() / 1000);\n\n const authorization: ExactEIP3009Payload[\"authorization\"] = {\n from: signer.address,\n to: getAddress(paymentRequirements.payTo),\n value: paymentRequirements.amount,\n validAfter: (now - 600).toString(),\n validBefore: (now + paymentRequirements.maxTimeoutSeconds).toString(),\n nonce,\n };\n\n const signature = await signEIP3009Authorization(signer, authorization, paymentRequirements);\n\n const payload: ExactEIP3009Payload = {\n authorization,\n signature,\n };\n\n return {\n x402Version,\n payload,\n };\n}\n\n/**\n * Sign the EIP-3009 authorization using EIP-712.\n *\n * @param signer - The EVM signer\n * @param authorization - The authorization to sign\n * @param requirements - The payment requirements\n * @returns Promise resolving to the signature\n */\nasync function signEIP3009Authorization(\n signer: ClientEvmSigner,\n authorization: ExactEIP3009Payload[\"authorization\"],\n requirements: PaymentRequirements,\n): Promise<`0x${string}`> {\n const chainId = getEvmChainId(requirements.network);\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`,\n );\n }\n\n const { name, version } = requirements.extra;\n\n const domain = {\n name,\n version,\n chainId,\n verifyingContract: getAddress(requirements.asset),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return await signer.signTypedData({\n domain,\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\",\n message,\n });\n}\n","import { PaymentRequirements, PaymentPayloadResult } from \"@x402/core/types\";\nimport { encodeFunctionData, getAddress } from \"viem\";\nimport {\n permit2WitnessTypes,\n PERMIT2_ADDRESS,\n x402ExactPermit2ProxyAddress,\n erc20ApproveAbi,\n erc20AllowanceAbi,\n} from \"../../constants\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport { ExactPermit2Payload } from \"../../types\";\nimport { createPermit2Nonce, getEvmChainId } from \"../../utils\";\n\n/** Maximum uint256 value for unlimited approval. */\nconst MAX_UINT256 = BigInt(\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\");\n\n/**\n * Creates a Permit2 payload using the x402Permit2Proxy witness pattern.\n * The spender is set to x402Permit2Proxy, which enforces that funds\n * can only be sent to the witness.to address.\n *\n * @param signer - The EVM signer for client operations\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload result\n */\nexport async function createPermit2Payload(\n signer: ClientEvmSigner,\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n): Promise<PaymentPayloadResult> {\n const now = Math.floor(Date.now() / 1000);\n const nonce = createPermit2Nonce();\n\n // Lower time bound - allow some clock skew\n const validAfter = (now - 600).toString();\n // Upper time bound is enforced by Permit2's deadline field\n const deadline = (now + paymentRequirements.maxTimeoutSeconds).toString();\n\n const permit2Authorization: ExactPermit2Payload[\"permit2Authorization\"] = {\n from: signer.address,\n permitted: {\n token: getAddress(paymentRequirements.asset),\n amount: paymentRequirements.amount,\n },\n spender: x402ExactPermit2ProxyAddress,\n nonce,\n deadline,\n witness: {\n to: getAddress(paymentRequirements.payTo),\n validAfter,\n },\n };\n\n const signature = await signPermit2Authorization(\n signer,\n permit2Authorization,\n paymentRequirements,\n );\n\n const payload: ExactPermit2Payload = {\n signature,\n permit2Authorization,\n };\n\n return {\n x402Version,\n payload,\n };\n}\n\n/**\n * Sign the Permit2 authorization using EIP-712 with witness data.\n * The signature authorizes the x402Permit2Proxy to transfer tokens on behalf of the signer.\n *\n * @param signer - The EVM signer\n * @param permit2Authorization - The Permit2 authorization parameters\n * @param requirements - The payment requirements\n * @returns Promise resolving to the signature\n */\nasync function signPermit2Authorization(\n signer: ClientEvmSigner,\n permit2Authorization: ExactPermit2Payload[\"permit2Authorization\"],\n requirements: PaymentRequirements,\n): Promise<`0x${string}`> {\n const chainId = getEvmChainId(requirements.network);\n\n const domain = {\n name: \"Permit2\",\n chainId,\n verifyingContract: PERMIT2_ADDRESS,\n };\n\n const message = {\n permitted: {\n token: getAddress(permit2Authorization.permitted.token),\n amount: BigInt(permit2Authorization.permitted.amount),\n },\n spender: getAddress(permit2Authorization.spender),\n nonce: BigInt(permit2Authorization.nonce),\n deadline: BigInt(permit2Authorization.deadline),\n witness: {\n to: getAddress(permit2Authorization.witness.to),\n validAfter: BigInt(permit2Authorization.witness.validAfter),\n },\n };\n\n return await signer.signTypedData({\n domain,\n types: permit2WitnessTypes,\n primaryType: \"PermitWitnessTransferFrom\",\n message,\n });\n}\n\n/**\n * Creates transaction data to approve Permit2 to spend tokens.\n * The user sends this transaction (paying gas) before using Permit2 flow.\n *\n * @param tokenAddress - The ERC20 token contract address\n * @returns Transaction data to send for approval\n *\n * @example\n * ```typescript\n * const tx = createPermit2ApprovalTx(\"0x...\");\n * await walletClient.sendTransaction({\n * to: tx.to,\n * data: tx.data,\n * });\n * ```\n */\nexport function createPermit2ApprovalTx(tokenAddress: `0x${string}`): {\n to: `0x${string}`;\n data: `0x${string}`;\n} {\n const data = encodeFunctionData({\n abi: erc20ApproveAbi,\n functionName: \"approve\",\n args: [PERMIT2_ADDRESS, MAX_UINT256],\n });\n\n return {\n to: getAddress(tokenAddress),\n data,\n };\n}\n\n/**\n * Parameters for checking Permit2 allowance.\n * Application provides these to check if approval is needed.\n */\nexport interface Permit2AllowanceParams {\n tokenAddress: `0x${string}`;\n ownerAddress: `0x${string}`;\n}\n\n/**\n * Returns contract read parameters for checking Permit2 allowance.\n * Use with a public client to check if the user has approved Permit2.\n *\n * @param params - The allowance check parameters\n * @returns Contract read parameters for checking allowance\n *\n * @example\n * ```typescript\n * const readParams = getPermit2AllowanceReadParams({\n * tokenAddress: \"0x...\",\n * ownerAddress: \"0x...\",\n * });\n *\n * const allowance = await publicClient.readContract(readParams);\n * const needsApproval = allowance < requiredAmount;\n * ```\n */\nexport function getPermit2AllowanceReadParams(params: Permit2AllowanceParams): {\n address: `0x${string}`;\n abi: typeof erc20AllowanceAbi;\n functionName: \"allowance\";\n args: [`0x${string}`, `0x${string}`];\n} {\n return {\n address: getAddress(params.tokenAddress),\n abi: erc20AllowanceAbi,\n functionName: \"allowance\",\n args: [getAddress(params.ownerAddress), PERMIT2_ADDRESS],\n };\n}\n","import { getAddress } from \"viem\";\nimport type { Eip2612GasSponsoringInfo } from \"@x402/extensions\";\nimport { eip2612PermitTypes, eip2612NoncesAbi, PERMIT2_ADDRESS } from \"../../constants\";\nimport { ClientEvmSigner } from \"../../signer\";\n\n/**\n * Signs an EIP-2612 permit authorizing the Permit2 contract to spend tokens.\n *\n * This creates a gasless off-chain signature that the facilitator can submit\n * on-chain via `x402Permit2Proxy.settleWithPermit()`.\n *\n * The `permittedAmount` must match the Permit2 `permitted.amount` exactly, as the\n * proxy contract enforces `permit2612.value == permittedAmount`.\n *\n * @param signer - The client EVM signer (must support readContract for nonce query)\n * @param tokenAddress - The ERC-20 token contract address\n * @param tokenName - The token name (from paymentRequirements.extra.name)\n * @param tokenVersion - The token version (from paymentRequirements.extra.version)\n * @param chainId - The chain ID\n * @param deadline - The deadline for the permit (unix timestamp as string)\n * @param permittedAmount - The Permit2 permitted amount (must match exactly)\n * @returns The EIP-2612 gas sponsoring info object\n */\nexport async function signEip2612Permit(\n signer: ClientEvmSigner,\n tokenAddress: `0x${string}`,\n tokenName: string,\n tokenVersion: string,\n chainId: number,\n deadline: string,\n permittedAmount: string,\n): Promise<Eip2612GasSponsoringInfo> {\n const owner = signer.address;\n const spender = getAddress(PERMIT2_ADDRESS);\n\n // Query the current EIP-2612 nonce from the token contract\n const nonce = (await signer.readContract({\n address: tokenAddress,\n abi: eip2612NoncesAbi,\n functionName: \"nonces\",\n args: [owner],\n })) as bigint;\n\n // Construct EIP-712 domain for the token's permit function\n const domain = {\n name: tokenName,\n version: tokenVersion,\n chainId,\n verifyingContract: tokenAddress,\n };\n\n const approvalAmount = BigInt(permittedAmount);\n\n const message = {\n owner,\n spender,\n value: approvalAmount,\n nonce,\n deadline: BigInt(deadline),\n };\n\n // Sign the EIP-2612 permit\n const signature = await signer.signTypedData({\n domain,\n types: eip2612PermitTypes,\n primaryType: \"Permit\",\n message,\n });\n\n return {\n from: owner,\n asset: tokenAddress,\n spender,\n amount: approvalAmount.toString(),\n nonce: nonce.toString(),\n deadline,\n signature,\n version: \"1\",\n };\n}\n","import { encodeFunctionData, getAddress, maxUint256 } from \"viem\";\nimport {\n ERC20_APPROVAL_GAS_SPONSORING_VERSION,\n type Erc20ApprovalGasSponsoringInfo,\n} from \"@x402/extensions\";\nimport {\n PERMIT2_ADDRESS,\n erc20ApproveAbi,\n ERC20_APPROVE_GAS_LIMIT,\n DEFAULT_MAX_FEE_PER_GAS,\n DEFAULT_MAX_PRIORITY_FEE_PER_GAS,\n} from \"../../constants\";\nimport { ClientEvmSigner } from \"../../signer\";\n\n/**\n * Signs an EIP-1559 `approve(Permit2, MaxUint256)` transaction for the given token.\n *\n * The signed transaction is NOT broadcast here — the facilitator broadcasts it\n * atomically before settling the Permit2 payment. This enables Permit2 payments\n * for generic ERC-20 tokens that do NOT implement EIP-2612.\n *\n * Always approves MaxUint256 regardless of the payment amount.\n *\n * @param signer - The client EVM signer (must support signTransaction, getTransactionCount)\n * @param tokenAddress - The ERC-20 token contract address\n * @param chainId - The chain ID\n * @returns The ERC-20 approval gas sponsoring info object\n */\nexport async function signErc20ApprovalTransaction(\n signer: ClientEvmSigner,\n tokenAddress: `0x${string}`,\n chainId: number,\n): Promise<Erc20ApprovalGasSponsoringInfo> {\n const from = signer.address;\n const spender = getAddress(PERMIT2_ADDRESS);\n\n // Encode approve(PERMIT2_ADDRESS, MaxUint256) calldata\n const data = encodeFunctionData({\n abi: erc20ApproveAbi,\n functionName: \"approve\",\n args: [spender, maxUint256],\n });\n\n // Get current nonce for the sender\n const nonce = await signer.getTransactionCount!({ address: from });\n\n // Get current fee estimates, with fallback values\n let maxFeePerGas: bigint;\n let maxPriorityFeePerGas: bigint;\n try {\n const fees = await signer.estimateFeesPerGas!();\n maxFeePerGas = fees.maxFeePerGas;\n maxPriorityFeePerGas = fees.maxPriorityFeePerGas;\n } catch {\n maxFeePerGas = DEFAULT_MAX_FEE_PER_GAS;\n maxPriorityFeePerGas = DEFAULT_MAX_PRIORITY_FEE_PER_GAS;\n }\n\n // Sign the EIP-1559 transaction (not broadcast)\n const signedTransaction = await signer.signTransaction!({\n to: tokenAddress,\n data,\n nonce,\n gas: ERC20_APPROVE_GAS_LIMIT,\n maxFeePerGas,\n maxPriorityFeePerGas,\n chainId,\n });\n\n return {\n from,\n asset: tokenAddress,\n spender,\n amount: maxUint256.toString(),\n signedTransaction,\n version: ERC20_APPROVAL_GAS_SPONSORING_VERSION,\n };\n}\n","import { x402Client, SelectPaymentRequirements, PaymentPolicy } from \"@x402/core/client\";\nimport { Network } from \"@x402/core/types\";\nimport { ClientEvmSigner } from \"../../signer\";\nimport { ExactEvmScheme } from \"./scheme\";\nimport { ExactEvmSchemeV1 } from \"../v1/client/scheme\";\nimport { NETWORKS } from \"../../v1\";\n\n/**\n * Configuration options for registering EVM schemes to an x402Client\n */\nexport interface EvmClientConfig {\n /**\n * The EVM signer to use for creating payment payloads\n */\n signer: ClientEvmSigner;\n\n /**\n * Optional payment requirements selector function\n * If not provided, uses the default selector (first available option)\n */\n paymentRequirementsSelector?: SelectPaymentRequirements;\n\n /**\n * Optional policies to apply to the client\n */\n policies?: PaymentPolicy[];\n\n /**\n * Optional specific networks to register\n * If not provided, registers wildcard support (eip155:*)\n */\n networks?: Network[];\n}\n\n/**\n * Registers EVM exact payment schemes to an x402Client instance.\n *\n * This function registers:\n * - V2: eip155:* wildcard scheme with ExactEvmScheme (or specific networks if provided)\n * - V1: All supported EVM networks with ExactEvmSchemeV1\n *\n * @param client - The x402Client instance to register schemes to\n * @param config - Configuration for EVM client registration\n * @returns The client instance for chaining\n *\n * @example\n * ```typescript\n * import { registerExactEvmScheme } from \"@x402/evm/exact/client/register\";\n * import { x402Client } from \"@x402/core/client\";\n * import { privateKeyToAccount } from \"viem/accounts\";\n *\n * const account = privateKeyToAccount(\"0x...\");\n * const client = new x402Client();\n * registerExactEvmScheme(client, { signer: account });\n * ```\n */\nexport function registerExactEvmScheme(client: x402Client, config: EvmClientConfig): x402Client {\n const evmScheme = new ExactEvmScheme(config.signer);\n\n // Register V2 scheme\n // EIP-2612 gas sponsoring is handled internally by the scheme when the\n // server advertises support - no separate extension registration needed.\n if (config.networks && config.networks.length > 0) {\n // Register specific networks\n config.networks.forEach(network => {\n client.register(network, evmScheme);\n });\n } else {\n // Register wildcard for all EVM chains\n client.register(\"eip155:*\", evmScheme);\n }\n\n // Register all V1 networks\n NETWORKS.forEach(network => {\n client.registerV1(network as Network, new ExactEvmSchemeV1(config.signer));\n });\n\n // Apply policies if provided\n if (config.policies) {\n config.policies.forEach(policy => {\n client.registerPolicy(policy);\n });\n }\n\n return client;\n}\n"],"mappings":"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","names":["getAddress","getAddress","getAddress","getAddress","getAddress","encodeFunctionData","getAddress","getAddress","encodeFunctionData","getAddress"]}
// src/exact/v1/client/scheme.ts
import { getAddress } from "viem";
// src/constants.ts
var authorizationTypes = {
TransferWithAuthorization: [
{ name: "from", type: "address" },
{ name: "to", type: "address" },
{ name: "value", type: "uint256" },
{ name: "validAfter", type: "uint256" },
{ name: "validBefore", type: "uint256" },
{ name: "nonce", type: "bytes32" }
]
};
var permit2WitnessTypes = {
PermitWitnessTransferFrom: [
{ name: "permitted", type: "TokenPermissions" },
{ name: "spender", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" },
{ name: "witness", type: "Witness" }
],
TokenPermissions: [
{ name: "token", type: "address" },
{ name: "amount", type: "uint256" }
],
Witness: [
{ name: "to", type: "address" },
{ name: "validAfter", type: "uint256" }
]
};
var eip3009ABI = [
{
inputs: [
{ name: "from", type: "address" },
{ name: "to", type: "address" },
{ name: "value", type: "uint256" },
{ name: "validAfter", type: "uint256" },
{ name: "validBefore", type: "uint256" },
{ name: "nonce", type: "bytes32" },
{ name: "v", type: "uint8" },
{ name: "r", type: "bytes32" },
{ name: "s", type: "bytes32" }
],
name: "transferWithAuthorization",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ name: "from", type: "address" },
{ name: "to", type: "address" },
{ name: "value", type: "uint256" },
{ name: "validAfter", type: "uint256" },
{ name: "validBefore", type: "uint256" },
{ name: "nonce", type: "bytes32" },
{ name: "signature", type: "bytes" }
],
name: "transferWithAuthorization",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [{ name: "account", type: "address" }],
name: "balanceOf",
outputs: [{ name: "", type: "uint256" }],
stateMutability: "view",
type: "function"
},
{
inputs: [],
name: "version",
outputs: [{ name: "", type: "string" }],
stateMutability: "view",
type: "function"
}
];
var eip2612PermitTypes = {
Permit: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" },
{ name: "value", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "deadline", type: "uint256" }
]
};
var eip2612NoncesAbi = [
{
type: "function",
name: "nonces",
inputs: [{ name: "owner", type: "address" }],
outputs: [{ type: "uint256" }],
stateMutability: "view"
}
];
var erc20ApproveAbi = [
{
type: "function",
name: "approve",
inputs: [
{ name: "spender", type: "address" },
{ name: "amount", type: "uint256" }
],
outputs: [{ type: "bool" }],
stateMutability: "nonpayable"
}
];
var erc20AllowanceAbi = [
{
type: "function",
name: "allowance",
inputs: [
{ name: "owner", type: "address" },
{ name: "spender", type: "address" }
],
outputs: [{ type: "uint256" }],
stateMutability: "view"
}
];
var ERC20_APPROVE_GAS_LIMIT = 70000n;
var DEFAULT_MAX_FEE_PER_GAS = 1000000000n;
var DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100000000n;
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
var x402ExactPermit2ProxyAddress = "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";
var x402UptoPermit2ProxyAddress = "0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002";
var permit2WitnessABIComponents = [
{ name: "to", type: "address", internalType: "address" },
{ name: "validAfter", type: "uint256", internalType: "uint256" }
];
var x402ExactPermit2ProxyABI = [
{
type: "function",
name: "PERMIT2",
inputs: [],
outputs: [{ name: "", type: "address", internalType: "contract ISignatureTransfer" }],
stateMutability: "view"
},
{
type: "function",
name: "WITNESS_TYPEHASH",
inputs: [],
outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
stateMutability: "view"
},
{
type: "function",
name: "WITNESS_TYPE_STRING",
inputs: [],
outputs: [{ name: "", type: "string", internalType: "string" }],
stateMutability: "view"
},
{
type: "function",
name: "settle",
inputs: [
{
name: "permit",
type: "tuple",
internalType: "struct ISignatureTransfer.PermitTransferFrom",
components: [
{
name: "permitted",
type: "tuple",
internalType: "struct ISignatureTransfer.TokenPermissions",
components: [
{ name: "token", type: "address", internalType: "address" },
{ name: "amount", type: "uint256", internalType: "uint256" }
]
},
{ name: "nonce", type: "uint256", internalType: "uint256" },
{ name: "deadline", type: "uint256", internalType: "uint256" }
]
},
{ name: "owner", type: "address", internalType: "address" },
{
name: "witness",
type: "tuple",
internalType: "struct x402ExactPermit2Proxy.Witness",
components: permit2WitnessABIComponents
},
{ name: "signature", type: "bytes", internalType: "bytes" }
],
outputs: [],
stateMutability: "nonpayable"
},
{
type: "function",
name: "settleWithPermit",
inputs: [
{
name: "permit2612",
type: "tuple",
internalType: "struct x402ExactPermit2Proxy.EIP2612Permit",
components: [
{ name: "value", type: "uint256", internalType: "uint256" },
{ name: "deadline", type: "uint256", internalType: "uint256" },
{ name: "r", type: "bytes32", internalType: "bytes32" },
{ name: "s", type: "bytes32", internalType: "bytes32" },
{ name: "v", type: "uint8", internalType: "uint8" }
]
},
{
name: "permit",
type: "tuple",
internalType: "struct ISignatureTransfer.PermitTransferFrom",
components: [
{
name: "permitted",
type: "tuple",
internalType: "struct ISignatureTransfer.TokenPermissions",
components: [
{ name: "token", type: "address", internalType: "address" },
{ name: "amount", type: "uint256", internalType: "uint256" }
]
},
{ name: "nonce", type: "uint256", internalType: "uint256" },
{ name: "deadline", type: "uint256", internalType: "uint256" }
]
},
{ name: "owner", type: "address", internalType: "address" },
{
name: "witness",
type: "tuple",
internalType: "struct x402ExactPermit2Proxy.Witness",
components: permit2WitnessABIComponents
},
{ name: "signature", type: "bytes", internalType: "bytes" }
],
outputs: [],
stateMutability: "nonpayable"
},
{ type: "event", name: "Settled", inputs: [], anonymous: false },
{ type: "event", name: "SettledWithPermit", inputs: [], anonymous: false },
{ type: "error", name: "InvalidAmount", inputs: [] },
{ type: "error", name: "InvalidDestination", inputs: [] },
{ type: "error", name: "InvalidOwner", inputs: [] },
{ type: "error", name: "InvalidPermit2Address", inputs: [] },
{ type: "error", name: "PaymentTooEarly", inputs: [] },
{ type: "error", name: "Permit2612AmountMismatch", inputs: [] },
{ type: "error", name: "ReentrancyGuardReentrantCall", inputs: [] }
];
// src/utils.ts
import { toHex } from "viem";
function getEvmChainId(network) {
if (network.startsWith("eip155:")) {
const idStr = network.split(":")[1];
const chainId = parseInt(idStr, 10);
if (isNaN(chainId)) {
throw new Error(`Invalid CAIP-2 chain ID: ${network}`);
}
return chainId;
}
throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);
}
function getCrypto() {
const cryptoObj = globalThis.crypto;
if (!cryptoObj) {
throw new Error("Crypto API not available");
}
return cryptoObj;
}
function createNonce() {
return toHex(getCrypto().getRandomValues(new Uint8Array(32)));
}
function createPermit2Nonce() {
const randomBytes = getCrypto().getRandomValues(new Uint8Array(32));
return BigInt(toHex(randomBytes)).toString();
}
// src/exact/v1/client/scheme.ts
var ExactEvmSchemeV1 = class {
/**
* Creates a new ExactEvmClientV1 instance.
*
* @param signer - The EVM signer for client operations
*/
constructor(signer) {
this.signer = signer;
this.scheme = "exact";
}
/**
* Creates a payment payload for the Exact scheme (V1).
*
* @param x402Version - The x402 protocol version
* @param paymentRequirements - The payment requirements
* @returns Promise resolving to a payment payload
*/
async createPaymentPayload(x402Version, paymentRequirements) {
const selectedV1 = paymentRequirements;
const nonce = createNonce();
const now = Math.floor(Date.now() / 1e3);
const authorization = {
from: this.signer.address,
to: getAddress(selectedV1.payTo),
value: selectedV1.maxAmountRequired,
validAfter: (now - 600).toString(),
// 10 minutes before
validBefore: (now + selectedV1.maxTimeoutSeconds).toString(),
nonce
};
const signature = await this.signAuthorization(authorization, selectedV1);
const payload = {
authorization,
signature
};
return {
x402Version,
scheme: selectedV1.scheme,
network: selectedV1.network,
payload
};
}
/**
* Sign the EIP-3009 authorization using EIP-712
*
* @param authorization - The authorization to sign
* @param requirements - The payment requirements
* @returns Promise resolving to the signature
*/
async signAuthorization(authorization, requirements) {
const chainId = getEvmChainIdV1(requirements.network);
if (!requirements.extra?.name || !requirements.extra?.version) {
throw new Error(
`EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`
);
}
const { name, version } = requirements.extra;
const domain = {
name,
version,
chainId,
verifyingContract: getAddress(requirements.asset)
};
const message = {
from: getAddress(authorization.from),
to: getAddress(authorization.to),
value: BigInt(authorization.value),
validAfter: BigInt(authorization.validAfter),
validBefore: BigInt(authorization.validBefore),
nonce: authorization.nonce
};
return await this.signer.signTypedData({
domain,
types: authorizationTypes,
primaryType: "TransferWithAuthorization",
message
});
}
};
// src/exact/v1/facilitator/scheme.ts
import { getAddress as getAddress2, isAddressEqual, parseErc6492Signature, parseSignature } from "viem";
var ExactEvmSchemeV12 = class {
/**
* Creates a new ExactEvmFacilitatorV1 instance.
*
* @param signer - The EVM signer for facilitator operations
* @param config - Optional configuration for the facilitator
*/
constructor(signer, config) {
this.signer = signer;
this.scheme = "exact";
this.caipFamily = "eip155:*";
this.config = {
deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false
};
}
/**
* Get mechanism-specific extra data for the supported kinds endpoint.
* For EVM, no extra data is needed.
*
* @param _ - The network identifier (unused for EVM)
* @returns undefined (EVM has no extra data)
*/
getExtra(_) {
return void 0;
}
/**
* Get signer addresses used by this facilitator.
* Returns all addresses this facilitator can use for signing/settling transactions.
*
* @param _ - The network identifier (unused for EVM, addresses are network-agnostic)
* @returns Array of facilitator wallet addresses
*/
getSigners(_) {
return [...this.signer.getAddresses()];
}
/**
* Verifies a payment payload (V1).
*
* @param payload - The payment payload to verify
* @param requirements - The payment requirements
* @returns Promise resolving to verification response
*/
async verify(payload, requirements) {
const requirementsV1 = requirements;
const payloadV1 = payload;
const exactEvmPayload = payload.payload;
if (payloadV1.scheme !== "exact" || requirements.scheme !== "exact") {
return {
isValid: false,
invalidReason: "unsupported_scheme",
payer: exactEvmPayload.authorization.from
};
}
let chainId;
try {
chainId = getEvmChainIdV1(payloadV1.network);
} catch {
return {
isValid: false,
invalidReason: `invalid_network`,
payer: exactEvmPayload.authorization.from
};
}
if (!requirements.extra?.name || !requirements.extra?.version) {
return {
isValid: false,
invalidReason: "missing_eip712_domain",
payer: exactEvmPayload.authorization.from
};
}
const { name, version } = requirements.extra;
const erc20Address = getAddress2(requirements.asset);
if (payloadV1.network !== requirements.network) {
return {
isValid: false,
invalidReason: "network_mismatch",
payer: exactEvmPayload.authorization.from
};
}
const permitTypedData = {
types: authorizationTypes,
primaryType: "TransferWithAuthorization",
domain: {
name,
version,
chainId,
verifyingContract: erc20Address
},
message: {
from: exactEvmPayload.authorization.from,
to: exactEvmPayload.authorization.to,
value: BigInt(exactEvmPayload.authorization.value),
validAfter: BigInt(exactEvmPayload.authorization.validAfter),
validBefore: BigInt(exactEvmPayload.authorization.validBefore),
nonce: exactEvmPayload.authorization.nonce
}
};
try {
const recoveredAddress = await this.signer.verifyTypedData({
address: exactEvmPayload.authorization.from,
...permitTypedData,
signature: exactEvmPayload.signature
});
if (!recoveredAddress) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
payer: exactEvmPayload.authorization.from
};
}
} catch {
const signature = exactEvmPayload.signature;
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isSmartWallet = signatureLength > 130;
if (isSmartWallet) {
const payerAddress = exactEvmPayload.authorization.from;
const bytecode = await this.signer.getCode({ address: payerAddress });
if (!bytecode || bytecode === "0x") {
const erc6492Data = parseErc6492Signature(signature);
const hasDeploymentInfo = erc6492Data.address && erc6492Data.data && !isAddressEqual(erc6492Data.address, "0x0000000000000000000000000000000000000000");
if (!hasDeploymentInfo) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_undeployed_smart_wallet",
payer: payerAddress
};
}
} else {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
payer: exactEvmPayload.authorization.from
};
}
} else {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_signature",
payer: exactEvmPayload.authorization.from
};
}
}
if (getAddress2(exactEvmPayload.authorization.to) !== getAddress2(requirements.payTo)) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_recipient_mismatch",
payer: exactEvmPayload.authorization.from
};
}
const now = Math.floor(Date.now() / 1e3);
if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_valid_before",
payer: exactEvmPayload.authorization.from
};
}
if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_valid_after",
payer: exactEvmPayload.authorization.from
};
}
try {
const balance = await this.signer.readContract({
address: erc20Address,
abi: eip3009ABI,
functionName: "balanceOf",
args: [exactEvmPayload.authorization.from]
});
if (BigInt(balance) < BigInt(requirementsV1.maxAmountRequired)) {
return {
isValid: false,
invalidReason: "insufficient_funds",
invalidMessage: `Insufficient funds to complete the payment. Required: ${requirementsV1.maxAmountRequired} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,
payer: exactEvmPayload.authorization.from
};
}
} catch {
}
if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {
return {
isValid: false,
invalidReason: "invalid_exact_evm_payload_authorization_value_mismatch",
payer: exactEvmPayload.authorization.from
};
}
return {
isValid: true,
invalidReason: void 0,
payer: exactEvmPayload.authorization.from
};
}
/**
* Settles a payment by executing the transfer (V1).
*
* @param payload - The payment payload to settle
* @param requirements - The payment requirements
* @returns Promise resolving to settlement response
*/
async settle(payload, requirements) {
const payloadV1 = payload;
const exactEvmPayload = payload.payload;
const valid = await this.verify(payload, requirements);
if (!valid.isValid) {
return {
success: false,
network: payloadV1.network,
transaction: "",
errorReason: valid.invalidReason ?? "invalid_scheme",
payer: exactEvmPayload.authorization.from
};
}
try {
const parseResult = parseErc6492Signature(exactEvmPayload.signature);
const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;
if (this.config.deployERC4337WithEIP6492 && factoryAddress && factoryCalldata && !isAddressEqual(factoryAddress, "0x0000000000000000000000000000000000000000")) {
const payerAddress = exactEvmPayload.authorization.from;
const bytecode = await this.signer.getCode({ address: payerAddress });
if (!bytecode || bytecode === "0x") {
try {
console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);
const deployTx = await this.signer.sendTransaction({
to: factoryAddress,
data: factoryCalldata
});
await this.signer.waitForTransactionReceipt({ hash: deployTx });
console.log(`Successfully deployed smart wallet for ${payerAddress}`);
} catch (deployError) {
console.error("Smart wallet deployment failed:", deployError);
throw deployError;
}
} else {
console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);
}
}
const signatureLength = signature.startsWith("0x") ? signature.length - 2 : signature.length;
const isECDSA = signatureLength === 130;
let tx;
if (isECDSA) {
const parsedSig = parseSignature(signature);
tx = await this.signer.writeContract({
address: getAddress2(requirements.asset),
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
getAddress2(exactEvmPayload.authorization.from),
getAddress2(exactEvmPayload.authorization.to),
BigInt(exactEvmPayload.authorization.value),
BigInt(exactEvmPayload.authorization.validAfter),
BigInt(exactEvmPayload.authorization.validBefore),
exactEvmPayload.authorization.nonce,
parsedSig.v || parsedSig.yParity,
parsedSig.r,
parsedSig.s
]
});
} else {
tx = await this.signer.writeContract({
address: getAddress2(requirements.asset),
abi: eip3009ABI,
functionName: "transferWithAuthorization",
args: [
getAddress2(exactEvmPayload.authorization.from),
getAddress2(exactEvmPayload.authorization.to),
BigInt(exactEvmPayload.authorization.value),
BigInt(exactEvmPayload.authorization.validAfter),
BigInt(exactEvmPayload.authorization.validBefore),
exactEvmPayload.authorization.nonce,
signature
]
});
}
const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });
if (receipt.status !== "success") {
return {
success: false,
errorReason: "invalid_transaction_state",
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
return {
success: true,
transaction: tx,
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
} catch (error) {
console.error("Failed to settle transaction:", error);
return {
success: false,
errorReason: "transaction_failed",
transaction: "",
network: payloadV1.network,
payer: exactEvmPayload.authorization.from
};
}
}
};
// src/v1/index.ts
var EVM_NETWORK_CHAIN_ID_MAP = {
ethereum: 1,
sepolia: 11155111,
abstract: 2741,
"abstract-testnet": 11124,
"base-sepolia": 84532,
base: 8453,
"avalanche-fuji": 43113,
avalanche: 43114,
iotex: 4689,
sei: 1329,
"sei-testnet": 1328,
polygon: 137,
"polygon-amoy": 80002,
peaq: 3338,
story: 1514,
educhain: 41923,
"skale-base-sepolia": 324705682,
megaeth: 4326,
monad: 143
};
var NETWORKS = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);
function getEvmChainIdV1(network) {
const chainId = EVM_NETWORK_CHAIN_ID_MAP[network];
if (!chainId) {
throw new Error(`Unsupported v1 network: ${network}`);
}
return chainId;
}
export {
authorizationTypes,
permit2WitnessTypes,
eip3009ABI,
eip2612PermitTypes,
eip2612NoncesAbi,
erc20ApproveAbi,
erc20AllowanceAbi,
ERC20_APPROVE_GAS_LIMIT,
DEFAULT_MAX_FEE_PER_GAS,
DEFAULT_MAX_PRIORITY_FEE_PER_GAS,
PERMIT2_ADDRESS,
x402ExactPermit2ProxyAddress,
x402UptoPermit2ProxyAddress,
x402ExactPermit2ProxyABI,
getEvmChainId,
createNonce,
createPermit2Nonce,
ExactEvmSchemeV12 as ExactEvmSchemeV1,
EVM_NETWORK_CHAIN_ID_MAP,
NETWORKS,
getEvmChainIdV1,
ExactEvmSchemeV1 as ExactEvmSchemeV12
};
//# sourceMappingURL=chunk-XL6IFXCP.mjs.map
{"version":3,"sources":["../../src/exact/v1/client/scheme.ts","../../src/constants.ts","../../src/utils.ts","../../src/exact/v1/facilitator/scheme.ts","../../src/v1/index.ts"],"sourcesContent":["import {\n Network,\n PaymentPayload,\n PaymentRequirements,\n SchemeNetworkClient,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress } from \"viem\";\nimport { authorizationTypes } from \"../../../constants\";\nimport { ClientEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { createNonce } from \"../../../utils\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\n\n/**\n * EVM client implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkClient {\n readonly scheme = \"exact\";\n\n /**\n * Creates a new ExactEvmClientV1 instance.\n *\n * @param signer - The EVM signer for client operations\n */\n constructor(private readonly signer: ClientEvmSigner) {}\n\n /**\n * Creates a payment payload for the Exact scheme (V1).\n *\n * @param x402Version - The x402 protocol version\n * @param paymentRequirements - The payment requirements\n * @returns Promise resolving to a payment payload\n */\n async createPaymentPayload(\n x402Version: number,\n paymentRequirements: PaymentRequirements,\n ): Promise<\n Pick<PaymentPayload, \"x402Version\" | \"payload\"> & { scheme: string; network: Network }\n > {\n const selectedV1 = paymentRequirements as unknown as PaymentRequirementsV1;\n const nonce = createNonce();\n const now = Math.floor(Date.now() / 1000);\n\n const authorization: ExactEvmPayloadV1[\"authorization\"] = {\n from: this.signer.address,\n to: getAddress(selectedV1.payTo),\n value: selectedV1.maxAmountRequired,\n validAfter: (now - 600).toString(), // 10 minutes before\n validBefore: (now + selectedV1.maxTimeoutSeconds).toString(),\n nonce,\n };\n\n // Sign the authorization\n const signature = await this.signAuthorization(authorization, selectedV1);\n\n const payload: ExactEvmPayloadV1 = {\n authorization,\n signature,\n };\n\n return {\n x402Version,\n scheme: selectedV1.scheme,\n network: selectedV1.network,\n payload,\n };\n }\n\n /**\n * Sign the EIP-3009 authorization using EIP-712\n *\n * @param authorization - The authorization to sign\n * @param requirements - The payment requirements\n * @returns Promise resolving to the signature\n */\n private async signAuthorization(\n authorization: ExactEvmPayloadV1[\"authorization\"],\n requirements: PaymentRequirementsV1,\n ): Promise<`0x${string}`> {\n const chainId = getEvmChainIdV1(requirements.network as EvmNetworkV1);\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n throw new Error(\n `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${requirements.asset}`,\n );\n }\n\n const { name, version } = requirements.extra;\n\n const domain = {\n name,\n version,\n chainId,\n verifyingContract: getAddress(requirements.asset),\n };\n\n const message = {\n from: getAddress(authorization.from),\n to: getAddress(authorization.to),\n value: BigInt(authorization.value),\n validAfter: BigInt(authorization.validAfter),\n validBefore: BigInt(authorization.validBefore),\n nonce: authorization.nonce,\n };\n\n return await this.signer.signTypedData({\n domain,\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\",\n message,\n });\n }\n}\n","// EIP-3009 TransferWithAuthorization types for EIP-712 signing\nexport const authorizationTypes = {\n TransferWithAuthorization: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n ],\n} as const;\n\n/**\n * Permit2 EIP-712 types for signing PermitWitnessTransferFrom.\n * Must match the exact format expected by the Permit2 contract.\n * Note: Types must be in ALPHABETICAL order after the primary type (TokenPermissions < Witness).\n */\nexport const permit2WitnessTypes = {\n PermitWitnessTransferFrom: [\n { name: \"permitted\", type: \"TokenPermissions\" },\n { name: \"spender\", type: \"address\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n { name: \"witness\", type: \"Witness\" },\n ],\n TokenPermissions: [\n { name: \"token\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n Witness: [\n { name: \"to\", type: \"address\" },\n { name: \"validAfter\", type: \"uint256\" },\n ],\n} as const;\n\n// EIP3009 ABI for transferWithAuthorization function\nexport const eip3009ABI = [\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"v\", type: \"uint8\" },\n { name: \"r\", type: \"bytes32\" },\n { name: \"s\", type: \"bytes32\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [\n { name: \"from\", type: \"address\" },\n { name: \"to\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"validAfter\", type: \"uint256\" },\n { name: \"validBefore\", type: \"uint256\" },\n { name: \"nonce\", type: \"bytes32\" },\n { name: \"signature\", type: \"bytes\" },\n ],\n name: \"transferWithAuthorization\",\n outputs: [],\n stateMutability: \"nonpayable\",\n type: \"function\",\n },\n {\n inputs: [{ name: \"account\", type: \"address\" }],\n name: \"balanceOf\",\n outputs: [{ name: \"\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n {\n inputs: [],\n name: \"version\",\n outputs: [{ name: \"\", type: \"string\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n/**\n * EIP-2612 Permit EIP-712 types for signing token.permit().\n */\nexport const eip2612PermitTypes = {\n Permit: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n { name: \"value\", type: \"uint256\" },\n { name: \"nonce\", type: \"uint256\" },\n { name: \"deadline\", type: \"uint256\" },\n ],\n} as const;\n\n/**\n * EIP-2612 nonces ABI for querying current nonce.\n */\nexport const eip2612NoncesAbi = [\n {\n type: \"function\",\n name: \"nonces\",\n inputs: [{ name: \"owner\", type: \"address\" }],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** ERC-20 approve(address,uint256) ABI for encoding/decoding approval calldata. */\nexport const erc20ApproveAbi = [\n {\n type: \"function\",\n name: \"approve\",\n inputs: [\n { name: \"spender\", type: \"address\" },\n { name: \"amount\", type: \"uint256\" },\n ],\n outputs: [{ type: \"bool\" }],\n stateMutability: \"nonpayable\",\n },\n] as const;\n\n/** ERC-20 allowance(address,address) ABI for checking spender approval. */\nexport const erc20AllowanceAbi = [\n {\n type: \"function\",\n name: \"allowance\",\n inputs: [\n { name: \"owner\", type: \"address\" },\n { name: \"spender\", type: \"address\" },\n ],\n outputs: [{ type: \"uint256\" }],\n stateMutability: \"view\",\n },\n] as const;\n\n/** Gas limit for a standard ERC-20 approve() transaction. */\nexport const ERC20_APPROVE_GAS_LIMIT = 70_000n;\n\n/** Fallback max fee per gas (1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_FEE_PER_GAS = 1_000_000_000n;\n\n/** Fallback max priority fee per gas (0.1 gwei) when fee estimation fails. */\nexport const DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100_000_000n;\n\n/**\n * Canonical Permit2 contract address.\n * Same address on all EVM chains via CREATE2 deployment.\n *\n * @see https://github.com/Uniswap/permit2\n */\nexport const PERMIT2_ADDRESS = \"0x000000000022D473030F116dDEE9F6B43aC78BA3\" as const;\n\n/**\n * x402ExactPermit2Proxy contract address.\n * Vanity address: 0x4020...0001 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0001\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402ExactPermit2ProxyAddress = \"0x402085c248EeA27D92E8b30b2C58ed07f9E20001\" as const;\n\n/**\n * x402UptoPermit2Proxy contract address.\n * Vanity address: 0x4020...0002 for easy recognition.\n * This address is deterministic based on:\n * - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)\n * - Vanity-mined salt for prefix 0x4020 and suffix 0002\n * - Contract bytecode + constructor args (PERMIT2_ADDRESS)\n */\nexport const x402UptoPermit2ProxyAddress = \"0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002\" as const;\n\n/**\n * Shared ABI components for the Permit2 witness tuple.\n * Used in both x402ExactPermit2ProxyABI and x402UptoPermit2ProxyABI to keep them in sync.\n * The upto contract's witness struct is identical to exact (both remove 'extra' post-audit).\n */\nconst permit2WitnessABIComponents = [\n { name: \"to\", type: \"address\", internalType: \"address\" },\n { name: \"validAfter\", type: \"uint256\", internalType: \"uint256\" },\n] as const;\n\n/**\n * x402UptoPermit2Proxy ABI - settle function for upto payment scheme (variable amounts).\n * Updated post-audit: 'extra' removed from witness struct, 'initialize()' removed (now\n * a constructor arg), and error names aligned with x402ExactPermit2Proxy.\n */\nexport const x402UptoPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402UptoPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n\n/**\n * x402ExactPermit2Proxy ABI - settle function for exact payment scheme.\n */\nexport const x402ExactPermit2ProxyABI = [\n {\n type: \"function\",\n name: \"PERMIT2\",\n inputs: [],\n outputs: [{ name: \"\", type: \"address\", internalType: \"contract ISignatureTransfer\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPEHASH\",\n inputs: [],\n outputs: [{ name: \"\", type: \"bytes32\", internalType: \"bytes32\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"WITNESS_TYPE_STRING\",\n inputs: [],\n outputs: [{ name: \"\", type: \"string\", internalType: \"string\" }],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"settle\",\n inputs: [\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"settleWithPermit\",\n inputs: [\n {\n name: \"permit2612\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.EIP2612Permit\",\n components: [\n { name: \"value\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"r\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"s\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"v\", type: \"uint8\", internalType: \"uint8\" },\n ],\n },\n {\n name: \"permit\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.PermitTransferFrom\",\n components: [\n {\n name: \"permitted\",\n type: \"tuple\",\n internalType: \"struct ISignatureTransfer.TokenPermissions\",\n components: [\n { name: \"token\", type: \"address\", internalType: \"address\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"nonce\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"deadline\", type: \"uint256\", internalType: \"uint256\" },\n ],\n },\n { name: \"owner\", type: \"address\", internalType: \"address\" },\n {\n name: \"witness\",\n type: \"tuple\",\n internalType: \"struct x402ExactPermit2Proxy.Witness\",\n components: permit2WitnessABIComponents,\n },\n { name: \"signature\", type: \"bytes\", internalType: \"bytes\" },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n { type: \"event\", name: \"Settled\", inputs: [], anonymous: false },\n { type: \"event\", name: \"SettledWithPermit\", inputs: [], anonymous: false },\n { type: \"error\", name: \"InvalidAmount\", inputs: [] },\n { type: \"error\", name: \"InvalidDestination\", inputs: [] },\n { type: \"error\", name: \"InvalidOwner\", inputs: [] },\n { type: \"error\", name: \"InvalidPermit2Address\", inputs: [] },\n { type: \"error\", name: \"PaymentTooEarly\", inputs: [] },\n { type: \"error\", name: \"Permit2612AmountMismatch\", inputs: [] },\n { type: \"error\", name: \"ReentrancyGuardReentrantCall\", inputs: [] },\n] as const;\n","import { toHex } from \"viem\";\n\n/**\n * Extract chain ID from a CAIP-2 network identifier (eip155:CHAIN_ID).\n *\n * @param network - The network identifier in CAIP-2 format (e.g., \"eip155:8453\")\n * @returns The numeric chain ID\n * @throws Error if the network format is invalid\n */\nexport function getEvmChainId(network: string): number {\n if (network.startsWith(\"eip155:\")) {\n const idStr = network.split(\":\")[1];\n const chainId = parseInt(idStr, 10);\n if (isNaN(chainId)) {\n throw new Error(`Invalid CAIP-2 chain ID: ${network}`);\n }\n return chainId;\n }\n\n throw new Error(`Unsupported network format: ${network} (expected eip155:CHAIN_ID)`);\n}\n\n/**\n * Get the crypto object from the global scope.\n *\n * @returns The crypto object\n * @throws Error if crypto API is not available\n */\nfunction getCrypto(): Crypto {\n const cryptoObj = globalThis.crypto as Crypto | undefined;\n if (!cryptoObj) {\n throw new Error(\"Crypto API not available\");\n }\n return cryptoObj;\n}\n\n/**\n * Create a random 32-byte nonce for EIP-3009 authorization.\n *\n * @returns A hex-encoded 32-byte nonce\n */\nexport function createNonce(): `0x${string}` {\n return toHex(getCrypto().getRandomValues(new Uint8Array(32)));\n}\n\n/**\n * Creates a random 256-bit nonce for Permit2.\n * Permit2 uses uint256 nonces (not bytes32 like EIP-3009).\n *\n * @returns A string representation of the random nonce\n */\nexport function createPermit2Nonce(): string {\n const randomBytes = getCrypto().getRandomValues(new Uint8Array(32));\n return BigInt(toHex(randomBytes)).toString();\n}\n","import {\n PaymentPayload,\n PaymentPayloadV1,\n PaymentRequirements,\n SchemeNetworkFacilitator,\n SettleResponse,\n VerifyResponse,\n} from \"@x402/core/types\";\nimport { PaymentRequirementsV1 } from \"@x402/core/types/v1\";\nimport { getAddress, Hex, isAddressEqual, parseErc6492Signature, parseSignature } from \"viem\";\nimport { authorizationTypes, eip3009ABI } from \"../../../constants\";\nimport { FacilitatorEvmSigner } from \"../../../signer\";\nimport { ExactEvmPayloadV1 } from \"../../../types\";\nimport { EvmNetworkV1, getEvmChainIdV1 } from \"../../../v1\";\n\nexport interface ExactEvmSchemeV1Config {\n /**\n * If enabled, the facilitator will deploy ERC-4337 smart wallets\n * via EIP-6492 when encountering undeployed contract signatures.\n *\n * @default false\n */\n deployERC4337WithEIP6492?: boolean;\n}\n\n/**\n * EVM facilitator implementation for the Exact payment scheme (V1).\n */\nexport class ExactEvmSchemeV1 implements SchemeNetworkFacilitator {\n readonly scheme = \"exact\";\n readonly caipFamily = \"eip155:*\";\n private readonly config: Required<ExactEvmSchemeV1Config>;\n\n /**\n * Creates a new ExactEvmFacilitatorV1 instance.\n *\n * @param signer - The EVM signer for facilitator operations\n * @param config - Optional configuration for the facilitator\n */\n constructor(\n private readonly signer: FacilitatorEvmSigner,\n config?: ExactEvmSchemeV1Config,\n ) {\n this.config = {\n deployERC4337WithEIP6492: config?.deployERC4337WithEIP6492 ?? false,\n };\n }\n\n /**\n * Get mechanism-specific extra data for the supported kinds endpoint.\n * For EVM, no extra data is needed.\n *\n * @param _ - The network identifier (unused for EVM)\n * @returns undefined (EVM has no extra data)\n */\n getExtra(_: string): Record<string, unknown> | undefined {\n return undefined;\n }\n\n /**\n * Get signer addresses used by this facilitator.\n * Returns all addresses this facilitator can use for signing/settling transactions.\n *\n * @param _ - The network identifier (unused for EVM, addresses are network-agnostic)\n * @returns Array of facilitator wallet addresses\n */\n getSigners(_: string): string[] {\n return [...this.signer.getAddresses()];\n }\n\n /**\n * Verifies a payment payload (V1).\n *\n * @param payload - The payment payload to verify\n * @param requirements - The payment requirements\n * @returns Promise resolving to verification response\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n const requirementsV1 = requirements as unknown as PaymentRequirementsV1;\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n\n // Verify scheme matches\n if (payloadV1.scheme !== \"exact\" || requirements.scheme !== \"exact\") {\n return {\n isValid: false,\n invalidReason: \"unsupported_scheme\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Get chain configuration\n let chainId: number;\n try {\n chainId = getEvmChainIdV1(payloadV1.network as EvmNetworkV1);\n } catch {\n return {\n isValid: false,\n invalidReason: `invalid_network`,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n if (!requirements.extra?.name || !requirements.extra?.version) {\n return {\n isValid: false,\n invalidReason: \"missing_eip712_domain\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n const { name, version } = requirements.extra;\n const erc20Address = getAddress(requirements.asset);\n\n // Verify network matches\n if (payloadV1.network !== requirements.network) {\n return {\n isValid: false,\n invalidReason: \"network_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Build typed data for signature verification\n const permitTypedData = {\n types: authorizationTypes,\n primaryType: \"TransferWithAuthorization\" as const,\n domain: {\n name,\n version,\n chainId,\n verifyingContract: erc20Address,\n },\n message: {\n from: exactEvmPayload.authorization.from,\n to: exactEvmPayload.authorization.to,\n value: BigInt(exactEvmPayload.authorization.value),\n validAfter: BigInt(exactEvmPayload.authorization.validAfter),\n validBefore: BigInt(exactEvmPayload.authorization.validBefore),\n nonce: exactEvmPayload.authorization.nonce,\n },\n };\n\n // Verify signature\n try {\n const recoveredAddress = await this.signer.verifyTypedData({\n address: exactEvmPayload.authorization.from,\n ...permitTypedData,\n signature: exactEvmPayload.signature!,\n });\n\n if (!recoveredAddress) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n } catch {\n // Signature verification failed - could be an undeployed smart wallet\n // Check if smart wallet is deployed\n const signature = exactEvmPayload.signature!;\n const signatureLength = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n const isSmartWallet = signatureLength > 130; // 65 bytes = 130 hex chars for EOA\n\n if (isSmartWallet) {\n const payerAddress = exactEvmPayload.authorization.from;\n const bytecode = await this.signer.getCode({ address: payerAddress });\n\n if (!bytecode || bytecode === \"0x\") {\n // Wallet is not deployed. Check if it's EIP-6492 with deployment info.\n // EIP-6492 signatures contain factory address and calldata needed for deployment.\n // Non-EIP-6492 undeployed wallets cannot succeed (no way to deploy them).\n const erc6492Data = parseErc6492Signature(signature);\n const hasDeploymentInfo =\n erc6492Data.address &&\n erc6492Data.data &&\n !isAddressEqual(erc6492Data.address, \"0x0000000000000000000000000000000000000000\");\n\n if (!hasDeploymentInfo) {\n // Non-EIP-6492 undeployed smart wallet - will always fail at settlement\n // since EIP-3009 requires on-chain EIP-1271 validation\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_undeployed_smart_wallet\",\n payer: payerAddress,\n };\n }\n // EIP-6492 signature with deployment info - allow through\n // Facilitators with sponsored deployment support can handle this in settle()\n } else {\n // Wallet is deployed but signature still failed - invalid signature\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n } else {\n // EOA signature failed\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_signature\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n }\n\n // Verify payment recipient matches\n if (getAddress(exactEvmPayload.authorization.to) !== getAddress(requirements.payTo)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_recipient_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Verify validBefore is in the future (with 6 second buffer for block time)\n const now = Math.floor(Date.now() / 1000);\n if (BigInt(exactEvmPayload.authorization.validBefore) < BigInt(now + 6)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_valid_before\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Verify validAfter is not in the future\n if (BigInt(exactEvmPayload.authorization.validAfter) > BigInt(now)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_valid_after\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n // Check balance\n try {\n const balance = (await this.signer.readContract({\n address: erc20Address,\n abi: eip3009ABI,\n functionName: \"balanceOf\",\n args: [exactEvmPayload.authorization.from],\n })) as bigint;\n\n if (BigInt(balance) < BigInt(requirementsV1.maxAmountRequired)) {\n return {\n isValid: false,\n invalidReason: \"insufficient_funds\",\n invalidMessage: `Insufficient funds to complete the payment. Required: ${requirementsV1.maxAmountRequired} ${requirements.asset}, Available: ${balance.toString()} ${requirements.asset}. Please add funds to your wallet and try again.`,\n payer: exactEvmPayload.authorization.from,\n };\n }\n } catch {\n // If we can't check balance, continue with other validations\n }\n\n // Verify amount exactly matches requirements\n if (BigInt(exactEvmPayload.authorization.value) !== BigInt(requirementsV1.maxAmountRequired)) {\n return {\n isValid: false,\n invalidReason: \"invalid_exact_evm_payload_authorization_value_mismatch\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n return {\n isValid: true,\n invalidReason: undefined,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n /**\n * Settles a payment by executing the transfer (V1).\n *\n * @param payload - The payment payload to settle\n * @param requirements - The payment requirements\n * @returns Promise resolving to settlement response\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n const payloadV1 = payload as unknown as PaymentPayloadV1;\n const exactEvmPayload = payload.payload as ExactEvmPayloadV1;\n\n // Re-verify before settling\n const valid = await this.verify(payload, requirements);\n if (!valid.isValid) {\n return {\n success: false,\n network: payloadV1.network,\n transaction: \"\",\n errorReason: valid.invalidReason ?? \"invalid_scheme\",\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n try {\n // Parse ERC-6492 signature if applicable\n const parseResult = parseErc6492Signature(exactEvmPayload.signature!);\n const { signature, address: factoryAddress, data: factoryCalldata } = parseResult;\n\n // Deploy ERC-4337 smart wallet via EIP-6492 if configured and needed\n if (\n this.config.deployERC4337WithEIP6492 &&\n factoryAddress &&\n factoryCalldata &&\n !isAddressEqual(factoryAddress, \"0x0000000000000000000000000000000000000000\")\n ) {\n // Check if smart wallet is already deployed\n const payerAddress = exactEvmPayload.authorization.from;\n const bytecode = await this.signer.getCode({ address: payerAddress });\n\n if (!bytecode || bytecode === \"0x\") {\n // Wallet not deployed - attempt deployment\n try {\n console.log(`Deploying ERC-4337 smart wallet for ${payerAddress} via EIP-6492`);\n\n // Send the factory calldata directly as a transaction\n // The factoryCalldata already contains the complete encoded function call\n const deployTx = await this.signer.sendTransaction({\n to: factoryAddress as Hex,\n data: factoryCalldata as Hex,\n });\n\n // Wait for deployment transaction\n await this.signer.waitForTransactionReceipt({ hash: deployTx });\n console.log(`Successfully deployed smart wallet for ${payerAddress}`);\n } catch (deployError) {\n console.error(\"Smart wallet deployment failed:\", deployError);\n // Deployment failed - cannot proceed\n throw deployError;\n }\n } else {\n console.log(`Smart wallet for ${payerAddress} already deployed, skipping deployment`);\n }\n }\n\n // Determine if this is an ECDSA signature (EOA) or smart wallet signature\n // ECDSA signatures are exactly 65 bytes (130 hex chars without 0x)\n const signatureLength = signature.startsWith(\"0x\") ? signature.length - 2 : signature.length;\n const isECDSA = signatureLength === 130;\n\n let tx: Hex;\n if (isECDSA) {\n // For EOA wallets, parse signature into v, r, s and use that overload\n const parsedSig = parseSignature(signature);\n\n tx = await this.signer.writeContract({\n address: getAddress(requirements.asset),\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n getAddress(exactEvmPayload.authorization.from),\n getAddress(exactEvmPayload.authorization.to),\n BigInt(exactEvmPayload.authorization.value),\n BigInt(exactEvmPayload.authorization.validAfter),\n BigInt(exactEvmPayload.authorization.validBefore),\n exactEvmPayload.authorization.nonce,\n (parsedSig.v as number | undefined) || parsedSig.yParity,\n parsedSig.r,\n parsedSig.s,\n ],\n });\n } else {\n // For smart wallets, use the bytes signature overload\n // The signature contains WebAuthn/P256 or other ERC-1271 compatible signature data\n tx = await this.signer.writeContract({\n address: getAddress(requirements.asset),\n abi: eip3009ABI,\n functionName: \"transferWithAuthorization\",\n args: [\n getAddress(exactEvmPayload.authorization.from),\n getAddress(exactEvmPayload.authorization.to),\n BigInt(exactEvmPayload.authorization.value),\n BigInt(exactEvmPayload.authorization.validAfter),\n BigInt(exactEvmPayload.authorization.validBefore),\n exactEvmPayload.authorization.nonce,\n signature,\n ],\n });\n }\n\n // Wait for transaction confirmation\n const receipt = await this.signer.waitForTransactionReceipt({ hash: tx });\n\n if (receipt.status !== \"success\") {\n return {\n success: false,\n errorReason: \"invalid_transaction_state\",\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n\n return {\n success: true,\n transaction: tx,\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n } catch (error) {\n console.error(\"Failed to settle transaction:\", error);\n return {\n success: false,\n errorReason: \"transaction_failed\",\n transaction: \"\",\n network: payloadV1.network,\n payer: exactEvmPayload.authorization.from,\n };\n }\n }\n}\n","export { ExactEvmSchemeV1 } from \"../exact/v1\";\n\nexport const EVM_NETWORK_CHAIN_ID_MAP = {\n ethereum: 1,\n sepolia: 11155111,\n abstract: 2741,\n \"abstract-testnet\": 11124,\n \"base-sepolia\": 84532,\n base: 8453,\n \"avalanche-fuji\": 43113,\n avalanche: 43114,\n iotex: 4689,\n sei: 1329,\n \"sei-testnet\": 1328,\n polygon: 137,\n \"polygon-amoy\": 80002,\n peaq: 3338,\n story: 1514,\n educhain: 41923,\n \"skale-base-sepolia\": 324705682,\n megaeth: 4326,\n monad: 143,\n} as const;\n\nexport type EvmNetworkV1 = keyof typeof EVM_NETWORK_CHAIN_ID_MAP;\n\nexport const NETWORKS: string[] = Object.keys(EVM_NETWORK_CHAIN_ID_MAP);\n\n/**\n * Extract chain ID from a v1 legacy network name.\n *\n * @param network - The v1 network name (e.g., \"base-sepolia\", \"polygon\")\n * @returns The numeric chain ID\n * @throws Error if the network name is not a known v1 network\n */\nexport function getEvmChainIdV1(network: string): number {\n const chainId = EVM_NETWORK_CHAIN_ID_MAP[network as EvmNetworkV1];\n if (!chainId) {\n throw new Error(`Unsupported v1 network: ${network}`);\n }\n return chainId;\n}\n"],"mappings":"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","names":["getAddress","ExactEvmSchemeV1","getAddress"]}
import { SchemeNetworkClient, PaymentRequirements, PaymentPayloadContext, PaymentPayloadResult } from '@x402/core/types';
import { C as ClientEvmSigner } from './signer-DC81R8wQ.mjs';
/**
* EVM client implementation for the Exact payment scheme.
* Supports both EIP-3009 (transferWithAuthorization) and Permit2 flows.
*
* Routes to the appropriate authorization method based on
* `requirements.extra.assetTransferMethod`. Defaults to EIP-3009
* for backward compatibility with older facilitators.
*
* When the server advertises `eip2612GasSponsoring` and the asset transfer
* method is `permit2`, the scheme automatically signs an EIP-2612 permit
* if the user lacks Permit2 approval. This requires `readContract` on the signer.
*/
declare class ExactEvmScheme implements SchemeNetworkClient {
private readonly signer;
readonly scheme = "exact";
/**
* Creates a new ExactEvmClient instance.
*
* @param signer - The EVM signer for client operations.
* Must support `readContract` for EIP-2612 gas sponsoring.
* Use `createWalletClient(...).extend(publicActions)` or `toClientEvmSigner(account, publicClient)`.
*/
constructor(signer: ClientEvmSigner);
/**
* Creates a payment payload for the Exact scheme.
* Routes to EIP-3009 or Permit2 based on requirements.extra.assetTransferMethod.
*
* For Permit2 flows, if the server advertises `eip2612GasSponsoring` and the
* signer supports `readContract`, automatically signs an EIP-2612 permit
* when Permit2 allowance is insufficient.
*
* @param x402Version - The x402 protocol version
* @param paymentRequirements - The payment requirements
* @param context - Optional context with server-declared extensions
* @returns Promise resolving to a payment payload result (with optional extensions)
*/
createPaymentPayload(x402Version: number, paymentRequirements: PaymentRequirements, context?: PaymentPayloadContext): Promise<PaymentPayloadResult>;
/**
* Attempts to sign an EIP-2612 permit for gasless Permit2 approval.
*
* Returns extension data if:
* 1. Server advertises eip2612GasSponsoring
* 2. Signer has readContract capability
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param result - The payment payload result from the scheme
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for EIP-2612 gas sponsoring, or undefined if not applicable
*/
private trySignEip2612Permit;
/**
* Attempts to sign an ERC-20 approval transaction for gasless Permit2 approval.
*
* This is the fallback path when the token does not support EIP-2612. The client
* signs (but does not broadcast) a raw `approve(Permit2, MaxUint256)` transaction.
* The facilitator broadcasts it atomically before settling.
*
* Returns extension data if:
* 1. Server advertises erc20ApprovalGasSponsoring
* 2. Signer has signTransaction + getTransactionCount capabilities
* 3. Current Permit2 allowance is insufficient
*
* Returns undefined if the extension should not be used.
*
* @param requirements - The payment requirements from the server
* @param _result - The payment payload result from the scheme (unused)
* @param context - Optional context containing server extensions and metadata
* @returns Extension data for ERC-20 approval gas sponsoring, or undefined if not applicable
*/
private trySignErc20Approval;
}
declare const authorizationTypes: {
readonly TransferWithAuthorization: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}];
};
/**
* Permit2 EIP-712 types for signing PermitWitnessTransferFrom.
* Must match the exact format expected by the Permit2 contract.
* Note: Types must be in ALPHABETICAL order after the primary type (TokenPermissions < Witness).
*/
declare const permit2WitnessTypes: {
readonly PermitWitnessTransferFrom: readonly [{
readonly name: "permitted";
readonly type: "TokenPermissions";
}, {
readonly name: "spender";
readonly type: "address";
}, {
readonly name: "nonce";
readonly type: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
}, {
readonly name: "witness";
readonly type: "Witness";
}];
readonly TokenPermissions: readonly [{
readonly name: "token";
readonly type: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
}];
readonly Witness: readonly [{
readonly name: "to";
readonly type: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}];
};
declare const eip3009ABI: readonly [{
readonly inputs: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}, {
readonly name: "v";
readonly type: "uint8";
}, {
readonly name: "r";
readonly type: "bytes32";
}, {
readonly name: "s";
readonly type: "bytes32";
}];
readonly name: "transferWithAuthorization";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly name: "from";
readonly type: "address";
}, {
readonly name: "to";
readonly type: "address";
}, {
readonly name: "value";
readonly type: "uint256";
}, {
readonly name: "validAfter";
readonly type: "uint256";
}, {
readonly name: "validBefore";
readonly type: "uint256";
}, {
readonly name: "nonce";
readonly type: "bytes32";
}, {
readonly name: "signature";
readonly type: "bytes";
}];
readonly name: "transferWithAuthorization";
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
readonly type: "function";
}, {
readonly inputs: readonly [{
readonly name: "account";
readonly type: "address";
}];
readonly name: "balanceOf";
readonly outputs: readonly [{
readonly name: "";
readonly type: "uint256";
}];
readonly stateMutability: "view";
readonly type: "function";
}, {
readonly inputs: readonly [];
readonly name: "version";
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
}];
readonly stateMutability: "view";
readonly type: "function";
}];
/** ERC-20 allowance(address,address) ABI for checking spender approval. */
declare const erc20AllowanceAbi: readonly [{
readonly type: "function";
readonly name: "allowance";
readonly inputs: readonly [{
readonly name: "owner";
readonly type: "address";
}, {
readonly name: "spender";
readonly type: "address";
}];
readonly outputs: readonly [{
readonly type: "uint256";
}];
readonly stateMutability: "view";
}];
/**
* Canonical Permit2 contract address.
* Same address on all EVM chains via CREATE2 deployment.
*
* @see https://github.com/Uniswap/permit2
*/
declare const PERMIT2_ADDRESS: "0x000000000022D473030F116dDEE9F6B43aC78BA3";
/**
* x402ExactPermit2Proxy contract address.
* Vanity address: 0x4020...0001 for easy recognition.
* This address is deterministic based on:
* - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)
* - Vanity-mined salt for prefix 0x4020 and suffix 0001
* - Contract bytecode + constructor args (PERMIT2_ADDRESS)
*/
declare const x402ExactPermit2ProxyAddress: "0x402085c248EeA27D92E8b30b2C58ed07f9E20001";
/**
* x402UptoPermit2Proxy contract address.
* Vanity address: 0x4020...0002 for easy recognition.
* This address is deterministic based on:
* - Arachnid's deterministic deployer (0x4e59b44847b379578588920cA78FbF26c0B4956C)
* - Vanity-mined salt for prefix 0x4020 and suffix 0002
* - Contract bytecode + constructor args (PERMIT2_ADDRESS)
*/
declare const x402UptoPermit2ProxyAddress: "0x402039b3d6E6BEC5A02c2C9fd937ac17A6940002";
/**
* x402ExactPermit2Proxy ABI - settle function for exact payment scheme.
*/
declare const x402ExactPermit2ProxyABI: readonly [{
readonly type: "function";
readonly name: "PERMIT2";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "address";
readonly internalType: "contract ISignatureTransfer";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "WITNESS_TYPEHASH";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "bytes32";
readonly internalType: "bytes32";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "WITNESS_TYPE_STRING";
readonly inputs: readonly [];
readonly outputs: readonly [{
readonly name: "";
readonly type: "string";
readonly internalType: "string";
}];
readonly stateMutability: "view";
}, {
readonly type: "function";
readonly name: "settle";
readonly inputs: readonly [{
readonly name: "permit";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.PermitTransferFrom";
readonly components: readonly [{
readonly name: "permitted";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.TokenPermissions";
readonly components: readonly [{
readonly name: "token";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "nonce";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "owner";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "witness";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.Witness";
readonly components: readonly [{
readonly name: "to";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "signature";
readonly type: "bytes";
readonly internalType: "bytes";
}];
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
}, {
readonly type: "function";
readonly name: "settleWithPermit";
readonly inputs: readonly [{
readonly name: "permit2612";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.EIP2612Permit";
readonly components: readonly [{
readonly name: "value";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "r";
readonly type: "bytes32";
readonly internalType: "bytes32";
}, {
readonly name: "s";
readonly type: "bytes32";
readonly internalType: "bytes32";
}, {
readonly name: "v";
readonly type: "uint8";
readonly internalType: "uint8";
}];
}, {
readonly name: "permit";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.PermitTransferFrom";
readonly components: readonly [{
readonly name: "permitted";
readonly type: "tuple";
readonly internalType: "struct ISignatureTransfer.TokenPermissions";
readonly components: readonly [{
readonly name: "token";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "amount";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "nonce";
readonly type: "uint256";
readonly internalType: "uint256";
}, {
readonly name: "deadline";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "owner";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "witness";
readonly type: "tuple";
readonly internalType: "struct x402ExactPermit2Proxy.Witness";
readonly components: readonly [{
readonly name: "to";
readonly type: "address";
readonly internalType: "address";
}, {
readonly name: "validAfter";
readonly type: "uint256";
readonly internalType: "uint256";
}];
}, {
readonly name: "signature";
readonly type: "bytes";
readonly internalType: "bytes";
}];
readonly outputs: readonly [];
readonly stateMutability: "nonpayable";
}, {
readonly type: "event";
readonly name: "Settled";
readonly inputs: readonly [];
readonly anonymous: false;
}, {
readonly type: "event";
readonly name: "SettledWithPermit";
readonly inputs: readonly [];
readonly anonymous: false;
}, {
readonly type: "error";
readonly name: "InvalidAmount";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidDestination";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidOwner";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "InvalidPermit2Address";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "PaymentTooEarly";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "Permit2612AmountMismatch";
readonly inputs: readonly [];
}, {
readonly type: "error";
readonly name: "ReentrancyGuardReentrantCall";
readonly inputs: readonly [];
}];
/**
* Creates transaction data to approve Permit2 to spend tokens.
* The user sends this transaction (paying gas) before using Permit2 flow.
*
* @param tokenAddress - The ERC20 token contract address
* @returns Transaction data to send for approval
*
* @example
* ```typescript
* const tx = createPermit2ApprovalTx("0x...");
* await walletClient.sendTransaction({
* to: tx.to,
* data: tx.data,
* });
* ```
*/
declare function createPermit2ApprovalTx(tokenAddress: `0x${string}`): {
to: `0x${string}`;
data: `0x${string}`;
};
/**
* Parameters for checking Permit2 allowance.
* Application provides these to check if approval is needed.
*/
interface Permit2AllowanceParams {
tokenAddress: `0x${string}`;
ownerAddress: `0x${string}`;
}
/**
* Returns contract read parameters for checking Permit2 allowance.
* Use with a public client to check if the user has approved Permit2.
*
* @param params - The allowance check parameters
* @returns Contract read parameters for checking allowance
*
* @example
* ```typescript
* const readParams = getPermit2AllowanceReadParams({
* tokenAddress: "0x...",
* ownerAddress: "0x...",
* });
*
* const allowance = await publicClient.readContract(readParams);
* const needsApproval = allowance < requiredAmount;
* ```
*/
declare function getPermit2AllowanceReadParams(params: Permit2AllowanceParams): {
address: `0x${string}`;
abi: typeof erc20AllowanceAbi;
functionName: "allowance";
args: [`0x${string}`, `0x${string}`];
};
export { ExactEvmScheme as E, type Permit2AllowanceParams as P, PERMIT2_ADDRESS as a, x402UptoPermit2ProxyAddress as b, createPermit2ApprovalTx as c, authorizationTypes as d, erc20AllowanceAbi as e, eip3009ABI as f, getPermit2AllowanceReadParams as g, x402ExactPermit2ProxyABI as h, permit2WitnessTypes as p, x402ExactPermit2ProxyAddress as x };
/**
* ClientEvmSigner - Used by x402 clients to sign payment authorizations.
*
* Typically a viem WalletClient extended with publicActions:
* ```typescript
* const client = createWalletClient({
* account: privateKeyToAccount('0x...'),
* chain: baseSepolia,
* transport: http(),
* }).extend(publicActions);
* ```
*
* Or composed via `toClientEvmSigner(account, publicClient)`.
*/
type ClientEvmSigner = {
readonly address: `0x${string}`;
signTypedData(message: {
domain: Record<string, unknown>;
types: Record<string, unknown>;
primaryType: string;
message: Record<string, unknown>;
}): Promise<`0x${string}`>;
readContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
/**
* Optional: Signs a raw EIP-1559 transaction without broadcasting.
* Required for ERC-20 approval gas sponsoring when the token lacks EIP-2612.
*/
signTransaction?(args: {
to: `0x${string}`;
data: `0x${string}`;
nonce: number;
gas: bigint;
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
chainId: number;
}): Promise<`0x${string}`>;
/**
* Optional: Gets the current transaction count (nonce) for an address.
* Required for ERC-20 approval gas sponsoring.
*/
getTransactionCount?(args: {
address: `0x${string}`;
}): Promise<number>;
/**
* Optional: Estimates current gas fees per gas.
* Required for ERC-20 approval gas sponsoring.
*/
estimateFeesPerGas?(): Promise<{
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
}>;
};
/**
* FacilitatorEvmSigner - Used by x402 facilitators to verify and settle payments
* This is typically a viem PublicClient + WalletClient combination that can
* read contract state, verify signatures, write transactions, and wait for receipts
*
* Supports multiple addresses for load balancing, key rotation, and high availability
*/
type FacilitatorEvmSigner = {
/**
* Get all addresses this facilitator can use for signing
* Enables dynamic address selection for load balancing and key rotation
*/
getAddresses(): readonly `0x${string}`[];
readContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
verifyTypedData(args: {
address: `0x${string}`;
domain: Record<string, unknown>;
types: Record<string, unknown>;
primaryType: string;
message: Record<string, unknown>;
signature: `0x${string}`;
}): Promise<boolean>;
writeContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args: readonly unknown[];
}): Promise<`0x${string}`>;
sendTransaction(args: {
to: `0x${string}`;
data: `0x${string}`;
}): Promise<`0x${string}`>;
waitForTransactionReceipt(args: {
hash: `0x${string}`;
}): Promise<{
status: string;
}>;
getCode(args: {
address: `0x${string}`;
}): Promise<`0x${string}` | undefined>;
};
/**
* Composes a ClientEvmSigner from a local account and a public client.
*
* Use this when your signer (e.g., `privateKeyToAccount`) doesn't have
* `readContract`. The `publicClient` provides the on-chain read capability.
*
* Alternatively, use a WalletClient extended with publicActions directly:
* ```typescript
* const signer = createWalletClient({
* account: privateKeyToAccount('0x...'),
* chain: baseSepolia,
* transport: http(),
* }).extend(publicActions);
* ```
*
* @param signer - A signer with `address` and `signTypedData` (and optionally `readContract`)
* @param publicClient - A client with `readContract` (required if signer lacks it)
* @param publicClient.readContract - The readContract method from the public client
* @param publicClient.getTransactionCount - Optional getTransactionCount for ERC-20 approval
* @param publicClient.estimateFeesPerGas - Optional estimateFeesPerGas for ERC-20 approval
* @returns A complete ClientEvmSigner
*
* @example
* ```typescript
* const account = privateKeyToAccount("0x...");
* const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
* const signer = toClientEvmSigner(account, publicClient);
* ```
*/
declare function toClientEvmSigner(signer: Omit<ClientEvmSigner, "readContract"> & {
readContract?: ClientEvmSigner["readContract"];
}, publicClient?: {
readContract(args: {
address: `0x${string}`;
abi: readonly unknown[];
functionName: string;
args?: readonly unknown[];
}): Promise<unknown>;
getTransactionCount?(args: {
address: `0x${string}`;
}): Promise<number>;
estimateFeesPerGas?(): Promise<{
maxFeePerGas: bigint;
maxPriorityFeePerGas: bigint;
}>;
}): ClientEvmSigner;
/**
* Converts a viem client with single address to a FacilitatorEvmSigner
* Wraps the single address in a getAddresses() function for compatibility
*
* @param client - The client to convert (must have 'address' property)
* @returns FacilitatorEvmSigner with getAddresses() support
*/
declare function toFacilitatorEvmSigner(client: Omit<FacilitatorEvmSigner, "getAddresses"> & {
address: `0x${string}`;
}): FacilitatorEvmSigner;
export { type ClientEvmSigner as C, type FacilitatorEvmSigner as F, toFacilitatorEvmSigner as a, toClientEvmSigner as t };

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display