@dexterai/x402 1.9.2 → 1.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/index.cjs +14 -5
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.d.cts +5 -5
- package/dist/adapters/index.d.ts +5 -5
- package/dist/adapters/index.js +14 -5
- package/dist/adapters/index.js.map +1 -1
- package/dist/client/index.cjs +60 -24
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +22 -8
- package/dist/client/index.d.ts +22 -8
- package/dist/client/index.js +59 -24
- package/dist/client/index.js.map +1 -1
- package/dist/react/index.cjs +63 -30
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +10 -5
- package/dist/react/index.d.ts +10 -5
- package/dist/react/index.js +63 -30
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +36 -10
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +48 -14
- package/dist/server/index.d.ts +48 -14
- package/dist/server/index.js +35 -10
- package/dist/server/index.js.map +1 -1
- package/dist/{solana-CfHuiW2H.d.cts → solana-BcOfK6Eq.d.cts} +2 -2
- package/dist/{solana-kZcwbUK9.d.ts → solana-Cxr5byPa.d.ts} +2 -2
- package/dist/{sponsored-access-H1EX6zpi.d.ts → sponsored-access-Br6YPA-m.d.cts} +20 -2
- package/dist/{sponsored-access-BCB2CxdG.d.cts → sponsored-access-D1_mINs4.d.ts} +20 -2
- package/dist/{types-ENcnkof8.d.ts → types-BIHhO2-I.d.ts} +1 -1
- package/dist/{types-DmqH9yD8.d.cts → types-CfKflCZO.d.cts} +1 -1
- package/dist/{types-BQvaF8lB.d.cts → types-CjLMR7qs.d.cts} +1 -1
- package/dist/{types-BQvaF8lB.d.ts → types-CjLMR7qs.d.ts} +1 -1
- package/dist/utils/index.cjs +8 -6
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js +8 -6
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
package/dist/adapters/index.cjs
CHANGED
|
@@ -131,8 +131,11 @@ var SolanaAdapter = class {
|
|
|
131
131
|
const account = await (0, import_spl_token.getAccount)(connection, ata, void 0, programId);
|
|
132
132
|
const decimals = accept.extra?.decimals ?? 6;
|
|
133
133
|
return Number(account.amount) / Math.pow(10, decimals);
|
|
134
|
-
} catch {
|
|
135
|
-
|
|
134
|
+
} catch (err) {
|
|
135
|
+
if (err && typeof err === "object" && "name" in err && (err.name === "TokenAccountNotFoundError" || err.name === "TokenInvalidAccountOwnerError")) {
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
throw err;
|
|
136
139
|
}
|
|
137
140
|
}
|
|
138
141
|
async buildTransaction(accept, wallet, rpcUrl) {
|
|
@@ -360,15 +363,21 @@ var EvmAdapter = class {
|
|
|
360
363
|
]
|
|
361
364
|
})
|
|
362
365
|
});
|
|
366
|
+
if (!response.ok) {
|
|
367
|
+
throw new Error(`RPC request failed: ${response.status}`);
|
|
368
|
+
}
|
|
363
369
|
const result = await response.json();
|
|
364
|
-
if (result.error
|
|
370
|
+
if (result.error) {
|
|
371
|
+
throw new Error(`RPC error: ${JSON.stringify(result.error)}`);
|
|
372
|
+
}
|
|
373
|
+
if (!result.result || result.result === "0x") {
|
|
365
374
|
return 0;
|
|
366
375
|
}
|
|
367
376
|
const balance = BigInt(result.result);
|
|
368
377
|
const decimals = accept.extra?.decimals ?? 6;
|
|
369
378
|
return Number(balance) / Math.pow(10, decimals);
|
|
370
|
-
} catch {
|
|
371
|
-
|
|
379
|
+
} catch (err) {
|
|
380
|
+
throw err;
|
|
372
381
|
}
|
|
373
382
|
}
|
|
374
383
|
encodeBalanceOf(address) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/index.ts","../../src/adapters/solana.ts","../../src/adapters/evm.ts"],"sourcesContent":["/**\n * Chain Adapters\n *\n * x402 v2 is designed to be chain-agnostic. Each adapter handles\n * the specifics of transaction building and signing for its chain.\n *\n * @example\n * ```typescript\n * import { createSolanaAdapter, createEvmAdapter } from '@dexterai/x402/adapters';\n *\n * const adapters = [\n * createSolanaAdapter(),\n * createEvmAdapter(),\n * ];\n *\n * // Find adapter for a network\n * const adapter = adapters.find(a => a.canHandle('eip155:8453'));\n * ```\n */\n\nimport { createSolanaAdapter as _createSolanaAdapter } from './solana';\nimport { createEvmAdapter as _createEvmAdapter } from './evm';\nimport { USDC_ADDRESSES as _USDC_ADDRESSES } from './evm';\n\n// Types\nexport type {\n ChainAdapter,\n AdapterConfig,\n SignedTransaction,\n GenericWallet,\n WalletSet,\n BalanceInfo,\n} from './types';\n\n// Solana\nexport {\n SolanaAdapter,\n createSolanaAdapter,\n isSolanaWallet,\n SOLANA_MAINNET,\n SOLANA_DEVNET,\n SOLANA_TESTNET,\n} from './solana';\nexport type { SolanaWallet } from './solana';\n\n// EVM\nexport {\n EvmAdapter,\n createEvmAdapter,\n isEvmWallet,\n BASE_MAINNET,\n BASE_SEPOLIA,\n ARBITRUM_ONE,\n POLYGON,\n OPTIMISM,\n AVALANCHE,\n SKALE_BASE,\n SKALE_BASE_SEPOLIA,\n ETHEREUM_MAINNET,\n USDC_ADDRESSES,\n} from './evm';\nexport type { EvmWallet } from './evm';\n\n/**\n * Check if an asset address is a known USDC contract (any chain).\n * Single source of truth for decimal inference in the client.\n */\nexport function isKnownUSDC(asset: string): boolean {\n // Solana mints\n if (asset === 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v') return true; // mainnet\n if (asset === '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU') return true; // devnet\n // All EVM USDC addresses (case-insensitive for EVM)\n const lc = asset.toLowerCase();\n for (const addr of Object.values(_USDC_ADDRESSES)) {\n if (addr.toLowerCase() === lc) return true;\n }\n return false;\n}\n\n/**\n * Create all default adapters\n */\nexport function createDefaultAdapters(verbose = false) {\n return [\n _createSolanaAdapter({ verbose }),\n _createEvmAdapter({ verbose }),\n ];\n}\n\n/**\n * Find adapter that can handle a network\n */\nexport function findAdapter(\n adapters: import('./types').ChainAdapter[],\n network: string\n): import('./types').ChainAdapter | undefined {\n return adapters.find(adapter => adapter.canHandle(network));\n}\n\n\n\n","/**\n * Solana Chain Adapter\n *\n * Implements the ChainAdapter interface for Solana networks.\n * Handles transaction building, signing, and balance queries.\n */\n\nimport {\n PublicKey,\n Connection,\n TransactionMessage,\n VersionedTransaction,\n ComputeBudgetProgram,\n type TransactionInstruction,\n} from '@solana/web3.js';\nimport {\n getAssociatedTokenAddress,\n getAccount,\n createTransferCheckedInstruction,\n getMint,\n TOKEN_PROGRAM_ID,\n TOKEN_2022_PROGRAM_ID,\n} from '@solana/spl-token';\nimport type { ChainAdapter, AdapterConfig, SignedTransaction } from './types';\nimport type { PaymentAccept } from '../types';\n\n/**\n * CAIP-2 network identifiers for Solana\n */\nexport const SOLANA_MAINNET = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';\nexport const SOLANA_DEVNET = 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1';\nexport const SOLANA_TESTNET = 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z';\n\n/**\n * Default RPC URLs\n * Mainnet uses Dexter's RPC proxy for reliability and zero-config setup\n */\nconst DEFAULT_RPC_URLS: Record<string, string> = {\n [SOLANA_MAINNET]: 'https://api.dexter.cash/api/solana/rpc',\n [SOLANA_DEVNET]: 'https://api.devnet.solana.com',\n [SOLANA_TESTNET]: 'https://api.testnet.solana.com',\n};\n\n/**\n * Dexter policy-safe compute budget settings\n */\nconst DEFAULT_COMPUTE_UNIT_LIMIT = 12_000;\nconst DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;\n\n/**\n * Solana wallet interface (compatible with @solana/wallet-adapter)\n */\nexport interface SolanaWallet {\n publicKey: { toBase58(): string } | null;\n signTransaction<T>(tx: T): Promise<T>;\n}\n\n/**\n * Check if an object is a valid Solana wallet\n */\nexport function isSolanaWallet(wallet: unknown): wallet is SolanaWallet {\n if (!wallet || typeof wallet !== 'object') return false;\n const w = wallet as Record<string, unknown>;\n return (\n 'publicKey' in w &&\n 'signTransaction' in w &&\n typeof w.signTransaction === 'function'\n );\n}\n\n/**\n * Solana Chain Adapter\n */\nexport class SolanaAdapter implements ChainAdapter {\n readonly name = 'Solana';\n readonly networks = [SOLANA_MAINNET, SOLANA_DEVNET, SOLANA_TESTNET];\n\n private config: AdapterConfig;\n private log: (...args: unknown[]) => void;\n\n constructor(config: AdapterConfig = {}) {\n this.config = config;\n this.log = config.verbose\n ? console.log.bind(console, '[x402:solana]')\n : () => {};\n }\n\n canHandle(network: string): boolean {\n // Handle both exact CAIP-2 and legacy formats\n if (this.networks.includes(network)) return true;\n // Legacy format support\n if (network === 'solana') return true;\n if (network === 'solana-devnet') return true;\n if (network === 'solana-testnet') return true;\n // Check if it starts with 'solana:'\n if (network.startsWith('solana:')) return true;\n return false;\n }\n\n getDefaultRpcUrl(network: string): string {\n // Check custom config first\n if (this.config.rpcUrls?.[network]) {\n return this.config.rpcUrls[network];\n }\n // Check defaults\n if (DEFAULT_RPC_URLS[network]) {\n return DEFAULT_RPC_URLS[network];\n }\n // Normalize legacy networks\n if (network === 'solana') return DEFAULT_RPC_URLS[SOLANA_MAINNET];\n if (network === 'solana-devnet') return DEFAULT_RPC_URLS[SOLANA_DEVNET];\n if (network === 'solana-testnet') return DEFAULT_RPC_URLS[SOLANA_TESTNET];\n // Default to mainnet\n return DEFAULT_RPC_URLS[SOLANA_MAINNET];\n }\n\n getAddress(wallet: unknown): string | null {\n if (!isSolanaWallet(wallet)) return null;\n return wallet.publicKey?.toBase58() ?? null;\n }\n\n isConnected(wallet: unknown): boolean {\n if (!isSolanaWallet(wallet)) return false;\n return wallet.publicKey !== null;\n }\n\n async getBalance(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<number> {\n if (!isSolanaWallet(wallet) || !wallet.publicKey) {\n return 0;\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n const connection = new Connection(url, 'confirmed');\n const userPubkey = new PublicKey(wallet.publicKey.toBase58());\n const mintPubkey = new PublicKey(accept.asset);\n\n try {\n // Determine token program\n const mintInfo = await connection.getAccountInfo(mintPubkey, 'confirmed');\n const programId =\n mintInfo?.owner.toBase58() === TOKEN_2022_PROGRAM_ID.toBase58()\n ? TOKEN_2022_PROGRAM_ID\n : TOKEN_PROGRAM_ID;\n\n const ata = await getAssociatedTokenAddress(\n mintPubkey,\n userPubkey,\n false,\n programId\n );\n\n const account = await getAccount(connection, ata, undefined, programId);\n const decimals = accept.extra?.decimals ?? 6;\n return Number(account.amount) / Math.pow(10, decimals);\n } catch {\n // Token account doesn't exist\n return 0;\n }\n }\n\n async buildTransaction(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<SignedTransaction> {\n if (!isSolanaWallet(wallet)) {\n throw new Error('Invalid Solana wallet');\n }\n if (!wallet.publicKey) {\n throw new Error('Wallet not connected');\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n const connection = new Connection(url, 'confirmed');\n const userPubkey = new PublicKey(wallet.publicKey.toBase58());\n\n // Extract required fields — amount is the v2 spec field, maxAmountRequired is v1 fallback\n const { payTo, asset, extra } = accept;\n const amount = accept.amount ?? accept.maxAmountRequired;\n if (!amount) {\n throw new Error('Missing amount in payment requirements');\n }\n\n if (!extra?.feePayer) {\n throw new Error('Missing feePayer in payment requirements');\n }\n // Note: decimals is optional - we fetch from mint on-chain if not provided\n\n const feePayerPubkey = new PublicKey(extra.feePayer);\n const mintPubkey = new PublicKey(asset);\n const destinationPubkey = new PublicKey(payTo);\n\n this.log('Building transaction:', {\n from: userPubkey.toBase58(),\n to: payTo,\n amount,\n asset,\n feePayer: extra.feePayer,\n });\n\n // Build instructions\n const instructions: TransactionInstruction[] = [];\n\n // 1. ComputeBudget: Set compute unit limit\n instructions.push(\n ComputeBudgetProgram.setComputeUnitLimit({\n units: DEFAULT_COMPUTE_UNIT_LIMIT,\n })\n );\n\n // 2. ComputeBudget: Set compute unit price\n instructions.push(\n ComputeBudgetProgram.setComputeUnitPrice({\n microLamports: DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS,\n })\n );\n\n // 3. Determine token program\n const mintInfo = await connection.getAccountInfo(mintPubkey, 'confirmed');\n if (!mintInfo) {\n throw new Error(`Token mint ${asset} not found`);\n }\n\n const programId =\n mintInfo.owner.toBase58() === TOKEN_2022_PROGRAM_ID.toBase58()\n ? TOKEN_2022_PROGRAM_ID\n : TOKEN_PROGRAM_ID;\n\n // Fetch mint to get decimals (required for TransferChecked)\n const mint = await getMint(connection, mintPubkey, undefined, programId);\n if (typeof extra?.decimals === 'number' && mint.decimals !== extra.decimals) {\n this.log(\n `Decimals mismatch: requirements say ${extra.decimals}, mint says ${mint.decimals}`\n );\n }\n\n // Derive Associated Token Accounts\n const sourceAta = await getAssociatedTokenAddress(\n mintPubkey,\n userPubkey,\n false,\n programId\n );\n const destinationAta = await getAssociatedTokenAddress(\n mintPubkey,\n destinationPubkey,\n false,\n programId\n );\n\n // Verify source ATA exists\n const sourceAtaInfo = await connection.getAccountInfo(sourceAta, 'confirmed');\n if (!sourceAtaInfo) {\n throw new Error(\n `No token account found for ${asset}. Please ensure you have USDC in your wallet.`\n );\n }\n\n // Verify destination ATA exists\n const destAtaInfo = await connection.getAccountInfo(destinationAta, 'confirmed');\n if (!destAtaInfo) {\n throw new Error(\n `Seller token account not found. The seller (${payTo}) must have a USDC account.`\n );\n }\n\n // 4. TransferChecked instruction\n const amountBigInt = BigInt(amount);\n instructions.push(\n createTransferCheckedInstruction(\n sourceAta,\n mintPubkey,\n destinationAta,\n userPubkey,\n amountBigInt,\n mint.decimals,\n [],\n programId\n )\n );\n\n // Get recent blockhash\n const { blockhash } = await connection.getLatestBlockhash('confirmed');\n\n // Compile to V0 message (feePayer is facilitator)\n const message = new TransactionMessage({\n payerKey: feePayerPubkey,\n recentBlockhash: blockhash,\n instructions,\n }).compileToV0Message();\n\n // Create and sign transaction\n const transaction = new VersionedTransaction(message);\n const signedTx = await wallet.signTransaction(transaction);\n\n this.log('Transaction signed successfully');\n\n return {\n serialized: Buffer.from(signedTx.serialize()).toString('base64'),\n };\n }\n}\n\n/**\n * Create a Solana adapter instance\n */\nexport function createSolanaAdapter(config?: AdapterConfig): SolanaAdapter {\n return new SolanaAdapter(config);\n}\n\n\n\n","/**\n * EVM Chain Adapter\n *\n * Implements the ChainAdapter interface for EVM networks (Base, Ethereum, Arbitrum, etc.)\n * Uses EIP-712 typed data signing for x402 v2 payments.\n */\n\nimport type { ChainAdapter, AdapterConfig, SignedTransaction } from './types';\nimport type { PaymentAccept } from '../types';\n\n/**\n * CAIP-2 network identifiers for EVM chains.\n * Mirrors dexter-facilitator/src/config/chains.ts — update both when adding chains.\n */\nexport const BASE_MAINNET = 'eip155:8453';\nexport const BASE_SEPOLIA = 'eip155:84532';\nexport const ARBITRUM_ONE = 'eip155:42161';\nexport const POLYGON = 'eip155:137';\nexport const OPTIMISM = 'eip155:10';\nexport const AVALANCHE = 'eip155:43114';\nexport const SKALE_BASE = 'eip155:1187947933';\nexport const SKALE_BASE_SEPOLIA = 'eip155:324705682';\n\n/** @deprecated Not supported by the Dexter facilitator. Use BASE_MAINNET for EVM payments. */\nexport const ETHEREUM_MAINNET = 'eip155:1';\n\n/**\n * Chain IDs by CAIP-2 network\n */\nconst CHAIN_IDS: Record<string, number> = {\n [BASE_MAINNET]: 8453,\n [BASE_SEPOLIA]: 84532,\n [ARBITRUM_ONE]: 42161,\n [POLYGON]: 137,\n [OPTIMISM]: 10,\n [AVALANCHE]: 43114,\n [SKALE_BASE]: 1187947933,\n [SKALE_BASE_SEPOLIA]: 324705682,\n [ETHEREUM_MAINNET]: 1,\n};\n\n/**\n * Default RPC URLs.\n * Base mainnet uses Dexter's RPC proxy for reliability and zero-config setup.\n * Source of truth: dexter-facilitator/src/config/chains.ts\n */\nconst DEFAULT_RPC_URLS: Record<string, string> = {\n [BASE_MAINNET]: 'https://api.dexter.cash/api/base/rpc',\n [BASE_SEPOLIA]: 'https://sepolia.base.org',\n [ARBITRUM_ONE]: 'https://arb1.arbitrum.io/rpc',\n [POLYGON]: 'https://polygon-rpc.com',\n [OPTIMISM]: 'https://mainnet.optimism.io',\n [AVALANCHE]: 'https://api.avax.network/ext/bc/C/rpc',\n [SKALE_BASE]: 'https://skale-base.skalenodes.com/v1/base',\n [SKALE_BASE_SEPOLIA]: 'https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha',\n [ETHEREUM_MAINNET]: 'https://eth.llamarpc.com',\n};\n\n/**\n * USDC contract addresses by chain.\n * Source of truth: dexter-facilitator/src/config/chains.ts\n */\nexport const USDC_ADDRESSES: Record<string, string> = {\n [BASE_MAINNET]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n [BASE_SEPOLIA]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n [ARBITRUM_ONE]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',\n [POLYGON]: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n [OPTIMISM]: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',\n [AVALANCHE]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',\n [SKALE_BASE]: '0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20',\n [SKALE_BASE_SEPOLIA]: '0x2e08028E3C4c2356572E096d8EF835cD5C6030bD',\n [ETHEREUM_MAINNET]: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n};\n\n/**\n * EVM wallet interface (compatible with wagmi, ethers, viem)\n */\nexport interface EvmWallet {\n /** Wallet address */\n address: string;\n /** Chain ID currently connected to */\n chainId?: number;\n /**\n * Sign typed data (EIP-712)\n * This is the primary signing method for x402 EVM payments\n */\n signTypedData?(params: {\n domain: Record<string, unknown>;\n types: Record<string, unknown[]>;\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<string>;\n /**\n * Alternative: Send transaction directly\n * Used if signTypedData is not available\n */\n sendTransaction?(params: {\n to: string;\n data: string;\n value?: bigint;\n }): Promise<string>;\n}\n\n/**\n * Check if an object is a valid EVM wallet\n */\nexport function isEvmWallet(wallet: unknown): wallet is EvmWallet {\n if (!wallet || typeof wallet !== 'object') return false;\n const w = wallet as Record<string, unknown>;\n return (\n 'address' in w &&\n typeof w.address === 'string' &&\n w.address.startsWith('0x')\n );\n}\n\n// ERC20 balanceOf function selector: 0x70a08231\n\n/**\n * EVM Chain Adapter\n */\nexport class EvmAdapter implements ChainAdapter {\n readonly name = 'EVM';\n readonly networks = [BASE_MAINNET, BASE_SEPOLIA, ETHEREUM_MAINNET, ARBITRUM_ONE];\n\n private config: AdapterConfig;\n private log: (...args: unknown[]) => void;\n\n constructor(config: AdapterConfig = {}) {\n this.config = config;\n this.log = config.verbose\n ? console.log.bind(console, '[x402:evm]')\n : () => {};\n }\n\n canHandle(network: string): boolean {\n // Handle exact CAIP-2\n if (this.networks.includes(network)) return true;\n // Legacy format\n if (network === 'base') return true;\n if (network === 'ethereum') return true;\n if (network === 'arbitrum') return true;\n // Check if it starts with 'eip155:'\n if (network.startsWith('eip155:')) return true;\n return false;\n }\n\n getDefaultRpcUrl(network: string): string {\n if (this.config.rpcUrls?.[network]) {\n return this.config.rpcUrls[network];\n }\n if (DEFAULT_RPC_URLS[network]) {\n return DEFAULT_RPC_URLS[network];\n }\n // Normalize legacy\n if (network === 'base') return DEFAULT_RPC_URLS[BASE_MAINNET];\n if (network === 'ethereum') return DEFAULT_RPC_URLS[ETHEREUM_MAINNET];\n if (network === 'arbitrum') return DEFAULT_RPC_URLS[ARBITRUM_ONE];\n return DEFAULT_RPC_URLS[BASE_MAINNET];\n }\n\n getAddress(wallet: unknown): string | null {\n if (!isEvmWallet(wallet)) return null;\n return wallet.address;\n }\n\n isConnected(wallet: unknown): boolean {\n if (!isEvmWallet(wallet)) return false;\n return !!wallet.address;\n }\n\n private getChainId(network: string): number {\n if (CHAIN_IDS[network]) return CHAIN_IDS[network];\n // Try to extract from CAIP-2\n if (network.startsWith('eip155:')) {\n const chainIdStr = network.split(':')[1];\n return parseInt(chainIdStr, 10);\n }\n // Defaults\n if (network === 'base') return 8453;\n if (network === 'ethereum') return 1;\n if (network === 'arbitrum') return 42161;\n return 8453; // Default to Base\n }\n\n async getBalance(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<number> {\n if (!isEvmWallet(wallet) || !wallet.address) {\n return 0;\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n\n try {\n // Use eth_call to check ERC20 balance\n const data = this.encodeBalanceOf(wallet.address);\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'eth_call',\n params: [\n {\n to: accept.asset,\n data,\n },\n 'latest',\n ],\n }),\n });\n\n const result = (await response.json()) as { error?: unknown; result?: string };\n if (result.error || !result.result) {\n return 0;\n }\n\n const balance = BigInt(result.result);\n const decimals = accept.extra?.decimals ?? 6;\n return Number(balance) / Math.pow(10, decimals);\n } catch {\n return 0;\n }\n }\n\n private encodeBalanceOf(address: string): string {\n // Function selector for balanceOf(address)\n const selector = '0x70a08231';\n // Pad address to 32 bytes\n const paddedAddress = address.slice(2).toLowerCase().padStart(64, '0');\n return selector + paddedAddress;\n }\n\n async buildTransaction(\n accept: PaymentAccept,\n wallet: unknown,\n _rpcUrl?: string\n ): Promise<SignedTransaction> {\n if (!isEvmWallet(wallet)) {\n throw new Error('Invalid EVM wallet');\n }\n if (!wallet.address) {\n throw new Error('Wallet not connected');\n }\n\n const { payTo, asset, extra } = accept;\n // amount is the v2 spec field, maxAmountRequired is v1 fallback\n const amount = accept.amount ?? accept.maxAmountRequired;\n if (!amount) {\n throw new Error('Missing amount in payment requirements');\n }\n\n this.log('Building EVM transaction:', {\n from: wallet.address,\n to: payTo,\n amount,\n asset,\n network: accept.network,\n });\n\n // For x402 v2 EVM payments, we use EIP-712 typed data signing\n // The facilitator will execute the transfer on behalf of the user\n\n const chainId = this.getChainId(accept.network);\n\n // Build the EIP-712 typed data\n // This matches what Dexter's facilitator expects\n const domain = {\n name: extra?.name ?? 'USD Coin',\n version: extra?.version ?? '2',\n chainId: BigInt(chainId),\n verifyingContract: asset as `0x${string}`,\n };\n\n const types = {\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 };\n\n // Generate a cryptographically secure random nonce (32 bytes hex)\n const nonceBytes = new Uint8Array(32);\n (globalThis.crypto ?? (await import('crypto')).webcrypto).getRandomValues(nonceBytes);\n const nonce = ('0x' + [...nonceBytes].map(b => b.toString(16).padStart(2, '0')).join('')) as `0x${string}`;\n\n const now = Math.floor(Date.now() / 1000);\n \n // Authorization object - values as strings for JSON, BigInts for signing\n const authorization = {\n from: wallet.address,\n to: payTo,\n value: amount, // string\n validAfter: String(now - 600), // 10 minutes before (matching upstream)\n validBefore: String(now + (accept.maxTimeoutSeconds || 60)),\n nonce,\n };\n\n // Message for signing uses BigInt values\n const message = {\n from: wallet.address,\n to: payTo,\n value: BigInt(amount),\n validAfter: BigInt(now - 600),\n validBefore: BigInt(now + (accept.maxTimeoutSeconds || 60)),\n nonce,\n };\n\n if (!wallet.signTypedData) {\n throw new Error('Wallet does not support signTypedData (EIP-712)');\n }\n\n const signature = await wallet.signTypedData({\n domain: domain as Record<string, unknown>,\n types: types as Record<string, unknown[]>,\n primaryType: 'TransferWithAuthorization',\n message: message as Record<string, unknown>,\n });\n\n this.log('EIP-712 signature obtained');\n\n // Payload structure matches upstream @x402/evm exactly\n const payload = {\n authorization,\n signature,\n };\n\n return {\n serialized: JSON.stringify(payload),\n signature,\n };\n }\n}\n\n/**\n * Create an EVM adapter instance\n */\nexport function createEvmAdapter(config?: AdapterConfig): EvmAdapter {\n return new EvmAdapter(config);\n}\n\n"],"mappings":"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","names":["DEFAULT_RPC_URLS"]}
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/index.ts","../../src/adapters/solana.ts","../../src/adapters/evm.ts"],"sourcesContent":["/**\n * Chain Adapters\n *\n * x402 v2 is designed to be chain-agnostic. Each adapter handles\n * the specifics of transaction building and signing for its chain.\n *\n * @example\n * ```typescript\n * import { createSolanaAdapter, createEvmAdapter } from '@dexterai/x402/adapters';\n *\n * const adapters = [\n * createSolanaAdapter(),\n * createEvmAdapter(),\n * ];\n *\n * // Find adapter for a network\n * const adapter = adapters.find(a => a.canHandle('eip155:8453'));\n * ```\n */\n\nimport { createSolanaAdapter as _createSolanaAdapter } from './solana';\nimport { createEvmAdapter as _createEvmAdapter } from './evm';\nimport { USDC_ADDRESSES as _USDC_ADDRESSES } from './evm';\n\n// Types\nexport type {\n ChainAdapter,\n AdapterConfig,\n SignedTransaction,\n GenericWallet,\n WalletSet,\n BalanceInfo,\n} from './types';\n\n// Solana\nexport {\n SolanaAdapter,\n createSolanaAdapter,\n isSolanaWallet,\n SOLANA_MAINNET,\n SOLANA_DEVNET,\n SOLANA_TESTNET,\n} from './solana';\nexport type { SolanaWallet } from './solana';\n\n// EVM\nexport {\n EvmAdapter,\n createEvmAdapter,\n isEvmWallet,\n BASE_MAINNET,\n BASE_SEPOLIA,\n ARBITRUM_ONE,\n POLYGON,\n OPTIMISM,\n AVALANCHE,\n SKALE_BASE,\n SKALE_BASE_SEPOLIA,\n ETHEREUM_MAINNET,\n USDC_ADDRESSES,\n} from './evm';\nexport type { EvmWallet } from './evm';\n\n/**\n * Check if an asset address is a known USDC contract (any chain).\n * Single source of truth for decimal inference in the client.\n */\nexport function isKnownUSDC(asset: string): boolean {\n // Solana mints\n if (asset === 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v') return true; // mainnet\n if (asset === '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU') return true; // devnet\n // All EVM USDC addresses (case-insensitive for EVM)\n const lc = asset.toLowerCase();\n for (const addr of Object.values(_USDC_ADDRESSES)) {\n if (addr.toLowerCase() === lc) return true;\n }\n return false;\n}\n\n/**\n * Create all default adapters\n */\nexport function createDefaultAdapters(verbose = false) {\n return [\n _createSolanaAdapter({ verbose }),\n _createEvmAdapter({ verbose }),\n ];\n}\n\n/**\n * Find adapter that can handle a network\n */\nexport function findAdapter(\n adapters: import('./types').ChainAdapter[],\n network: string\n): import('./types').ChainAdapter | undefined {\n return adapters.find(adapter => adapter.canHandle(network));\n}\n\n\n\n","/**\n * Solana Chain Adapter\n *\n * Implements the ChainAdapter interface for Solana networks.\n * Handles transaction building, signing, and balance queries.\n */\n\nimport {\n PublicKey,\n Connection,\n TransactionMessage,\n VersionedTransaction,\n ComputeBudgetProgram,\n type TransactionInstruction,\n} from '@solana/web3.js';\nimport {\n getAssociatedTokenAddress,\n getAccount,\n createTransferCheckedInstruction,\n getMint,\n TOKEN_PROGRAM_ID,\n TOKEN_2022_PROGRAM_ID,\n} from '@solana/spl-token';\nimport type { ChainAdapter, AdapterConfig, SignedTransaction } from './types';\nimport type { PaymentAccept } from '../types';\n\n/**\n * CAIP-2 network identifiers for Solana\n */\nexport const SOLANA_MAINNET = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';\nexport const SOLANA_DEVNET = 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1';\nexport const SOLANA_TESTNET = 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z';\n\n/**\n * Default RPC URLs\n * Mainnet uses Dexter's RPC proxy for reliability and zero-config setup\n */\nconst DEFAULT_RPC_URLS: Record<string, string> = {\n [SOLANA_MAINNET]: 'https://api.dexter.cash/api/solana/rpc',\n [SOLANA_DEVNET]: 'https://api.devnet.solana.com',\n [SOLANA_TESTNET]: 'https://api.testnet.solana.com',\n};\n\n/**\n * Dexter policy-safe compute budget settings\n */\nconst DEFAULT_COMPUTE_UNIT_LIMIT = 12_000;\nconst DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;\n\n/**\n * Solana wallet interface (compatible with @solana/wallet-adapter)\n */\nexport interface SolanaWallet {\n publicKey: { toBase58(): string } | null;\n signTransaction<T>(tx: T): Promise<T>;\n}\n\n/**\n * Check if an object is a valid Solana wallet\n */\nexport function isSolanaWallet(wallet: unknown): wallet is SolanaWallet {\n if (!wallet || typeof wallet !== 'object') return false;\n const w = wallet as Record<string, unknown>;\n return (\n 'publicKey' in w &&\n 'signTransaction' in w &&\n typeof w.signTransaction === 'function'\n );\n}\n\n/**\n * Solana Chain Adapter\n */\nexport class SolanaAdapter implements ChainAdapter {\n readonly name = 'Solana';\n readonly networks = [SOLANA_MAINNET, SOLANA_DEVNET, SOLANA_TESTNET];\n\n private config: AdapterConfig;\n private log: (...args: unknown[]) => void;\n\n constructor(config: AdapterConfig = {}) {\n this.config = config;\n this.log = config.verbose\n ? console.log.bind(console, '[x402:solana]')\n : () => {};\n }\n\n canHandle(network: string): boolean {\n // Handle both exact CAIP-2 and legacy formats\n if (this.networks.includes(network)) return true;\n // Legacy format support\n if (network === 'solana') return true;\n if (network === 'solana-devnet') return true;\n if (network === 'solana-testnet') return true;\n // Check if it starts with 'solana:'\n if (network.startsWith('solana:')) return true;\n return false;\n }\n\n getDefaultRpcUrl(network: string): string {\n // Check custom config first\n if (this.config.rpcUrls?.[network]) {\n return this.config.rpcUrls[network];\n }\n // Check defaults\n if (DEFAULT_RPC_URLS[network]) {\n return DEFAULT_RPC_URLS[network];\n }\n // Normalize legacy networks\n if (network === 'solana') return DEFAULT_RPC_URLS[SOLANA_MAINNET];\n if (network === 'solana-devnet') return DEFAULT_RPC_URLS[SOLANA_DEVNET];\n if (network === 'solana-testnet') return DEFAULT_RPC_URLS[SOLANA_TESTNET];\n // Default to mainnet\n return DEFAULT_RPC_URLS[SOLANA_MAINNET];\n }\n\n getAddress(wallet: unknown): string | null {\n if (!isSolanaWallet(wallet)) return null;\n return wallet.publicKey?.toBase58() ?? null;\n }\n\n isConnected(wallet: unknown): boolean {\n if (!isSolanaWallet(wallet)) return false;\n return wallet.publicKey !== null;\n }\n\n async getBalance(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<number> {\n if (!isSolanaWallet(wallet) || !wallet.publicKey) {\n return 0;\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n const connection = new Connection(url, 'confirmed');\n const userPubkey = new PublicKey(wallet.publicKey.toBase58());\n const mintPubkey = new PublicKey(accept.asset);\n\n try {\n // Determine token program\n const mintInfo = await connection.getAccountInfo(mintPubkey, 'confirmed');\n const programId =\n mintInfo?.owner.toBase58() === TOKEN_2022_PROGRAM_ID.toBase58()\n ? TOKEN_2022_PROGRAM_ID\n : TOKEN_PROGRAM_ID;\n\n const ata = await getAssociatedTokenAddress(\n mintPubkey,\n userPubkey,\n false,\n programId\n );\n\n const account = await getAccount(connection, ata, undefined, programId);\n const decimals = accept.extra?.decimals ?? 6;\n return Number(account.amount) / Math.pow(10, decimals);\n } catch (err) {\n // Token account doesn't exist = 0 balance (expected for new wallets)\n if (err && typeof err === 'object' && 'name' in err &&\n (err.name === 'TokenAccountNotFoundError' || err.name === 'TokenInvalidAccountOwnerError')) {\n return 0;\n }\n // RPC errors, network failures — throw so caller can distinguish from zero balance\n throw err;\n }\n }\n\n async buildTransaction(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<SignedTransaction> {\n if (!isSolanaWallet(wallet)) {\n throw new Error('Invalid Solana wallet');\n }\n if (!wallet.publicKey) {\n throw new Error('Wallet not connected');\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n const connection = new Connection(url, 'confirmed');\n const userPubkey = new PublicKey(wallet.publicKey.toBase58());\n\n // Extract required fields — amount is the v2 spec field, maxAmountRequired is v1 fallback\n const { payTo, asset, extra } = accept;\n const amount = accept.amount ?? accept.maxAmountRequired;\n if (!amount) {\n throw new Error('Missing amount in payment requirements');\n }\n\n if (!extra?.feePayer) {\n throw new Error('Missing feePayer in payment requirements');\n }\n // Note: decimals is optional - we fetch from mint on-chain if not provided\n\n const feePayerPubkey = new PublicKey(extra.feePayer);\n const mintPubkey = new PublicKey(asset);\n const destinationPubkey = new PublicKey(payTo);\n\n this.log('Building transaction:', {\n from: userPubkey.toBase58(),\n to: payTo,\n amount,\n asset,\n feePayer: extra.feePayer,\n });\n\n // Build instructions\n const instructions: TransactionInstruction[] = [];\n\n // 1. ComputeBudget: Set compute unit limit\n instructions.push(\n ComputeBudgetProgram.setComputeUnitLimit({\n units: DEFAULT_COMPUTE_UNIT_LIMIT,\n })\n );\n\n // 2. ComputeBudget: Set compute unit price\n instructions.push(\n ComputeBudgetProgram.setComputeUnitPrice({\n microLamports: DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS,\n })\n );\n\n // 3. Determine token program\n const mintInfo = await connection.getAccountInfo(mintPubkey, 'confirmed');\n if (!mintInfo) {\n throw new Error(`Token mint ${asset} not found`);\n }\n\n const programId =\n mintInfo.owner.toBase58() === TOKEN_2022_PROGRAM_ID.toBase58()\n ? TOKEN_2022_PROGRAM_ID\n : TOKEN_PROGRAM_ID;\n\n // Fetch mint to get decimals (required for TransferChecked)\n const mint = await getMint(connection, mintPubkey, undefined, programId);\n if (typeof extra?.decimals === 'number' && mint.decimals !== extra.decimals) {\n this.log(\n `Decimals mismatch: requirements say ${extra.decimals}, mint says ${mint.decimals}`\n );\n }\n\n // Derive Associated Token Accounts\n const sourceAta = await getAssociatedTokenAddress(\n mintPubkey,\n userPubkey,\n false,\n programId\n );\n const destinationAta = await getAssociatedTokenAddress(\n mintPubkey,\n destinationPubkey,\n false,\n programId\n );\n\n // Verify source ATA exists\n const sourceAtaInfo = await connection.getAccountInfo(sourceAta, 'confirmed');\n if (!sourceAtaInfo) {\n throw new Error(\n `No token account found for ${asset}. Please ensure you have USDC in your wallet.`\n );\n }\n\n // Verify destination ATA exists\n const destAtaInfo = await connection.getAccountInfo(destinationAta, 'confirmed');\n if (!destAtaInfo) {\n throw new Error(\n `Seller token account not found. The seller (${payTo}) must have a USDC account.`\n );\n }\n\n // 4. TransferChecked instruction\n const amountBigInt = BigInt(amount);\n instructions.push(\n createTransferCheckedInstruction(\n sourceAta,\n mintPubkey,\n destinationAta,\n userPubkey,\n amountBigInt,\n mint.decimals,\n [],\n programId\n )\n );\n\n // Get recent blockhash\n const { blockhash } = await connection.getLatestBlockhash('confirmed');\n\n // Compile to V0 message (feePayer is facilitator)\n const message = new TransactionMessage({\n payerKey: feePayerPubkey,\n recentBlockhash: blockhash,\n instructions,\n }).compileToV0Message();\n\n // Create and sign transaction\n const transaction = new VersionedTransaction(message);\n const signedTx = await wallet.signTransaction(transaction);\n\n this.log('Transaction signed successfully');\n\n return {\n serialized: Buffer.from(signedTx.serialize()).toString('base64'),\n };\n }\n}\n\n/**\n * Create a Solana adapter instance\n */\nexport function createSolanaAdapter(config?: AdapterConfig): SolanaAdapter {\n return new SolanaAdapter(config);\n}\n\n\n\n","/**\n * EVM Chain Adapter\n *\n * Implements the ChainAdapter interface for EVM networks (Base, Ethereum, Arbitrum, etc.)\n * Uses EIP-712 typed data signing for x402 v2 payments.\n */\n\nimport type { ChainAdapter, AdapterConfig, SignedTransaction } from './types';\nimport type { PaymentAccept } from '../types';\n\n/**\n * CAIP-2 network identifiers for EVM chains.\n * Mirrors dexter-facilitator/src/config/chains.ts — update both when adding chains.\n */\nexport const BASE_MAINNET = 'eip155:8453';\nexport const BASE_SEPOLIA = 'eip155:84532';\nexport const ARBITRUM_ONE = 'eip155:42161';\nexport const POLYGON = 'eip155:137';\nexport const OPTIMISM = 'eip155:10';\nexport const AVALANCHE = 'eip155:43114';\nexport const SKALE_BASE = 'eip155:1187947933';\nexport const SKALE_BASE_SEPOLIA = 'eip155:324705682';\n\n/** @deprecated Not supported by the Dexter facilitator. Use BASE_MAINNET for EVM payments. */\nexport const ETHEREUM_MAINNET = 'eip155:1';\n\n/**\n * Chain IDs by CAIP-2 network\n */\nconst CHAIN_IDS: Record<string, number> = {\n [BASE_MAINNET]: 8453,\n [BASE_SEPOLIA]: 84532,\n [ARBITRUM_ONE]: 42161,\n [POLYGON]: 137,\n [OPTIMISM]: 10,\n [AVALANCHE]: 43114,\n [SKALE_BASE]: 1187947933,\n [SKALE_BASE_SEPOLIA]: 324705682,\n [ETHEREUM_MAINNET]: 1,\n};\n\n/**\n * Default RPC URLs.\n * Base mainnet uses Dexter's RPC proxy for reliability and zero-config setup.\n * Source of truth: dexter-facilitator/src/config/chains.ts\n */\nconst DEFAULT_RPC_URLS: Record<string, string> = {\n [BASE_MAINNET]: 'https://api.dexter.cash/api/base/rpc',\n [BASE_SEPOLIA]: 'https://sepolia.base.org',\n [ARBITRUM_ONE]: 'https://arb1.arbitrum.io/rpc',\n [POLYGON]: 'https://polygon-rpc.com',\n [OPTIMISM]: 'https://mainnet.optimism.io',\n [AVALANCHE]: 'https://api.avax.network/ext/bc/C/rpc',\n [SKALE_BASE]: 'https://skale-base.skalenodes.com/v1/base',\n [SKALE_BASE_SEPOLIA]: 'https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha',\n [ETHEREUM_MAINNET]: 'https://eth.llamarpc.com',\n};\n\n/**\n * USDC contract addresses by chain.\n * Source of truth: dexter-facilitator/src/config/chains.ts\n */\nexport const USDC_ADDRESSES: Record<string, string> = {\n [BASE_MAINNET]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n [BASE_SEPOLIA]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n [ARBITRUM_ONE]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',\n [POLYGON]: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n [OPTIMISM]: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',\n [AVALANCHE]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',\n [SKALE_BASE]: '0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20',\n [SKALE_BASE_SEPOLIA]: '0x2e08028E3C4c2356572E096d8EF835cD5C6030bD',\n [ETHEREUM_MAINNET]: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n};\n\n/**\n * EVM wallet interface (compatible with wagmi, ethers, viem)\n */\nexport interface EvmWallet {\n /** Wallet address */\n address: string;\n /** Chain ID currently connected to */\n chainId?: number;\n /**\n * Sign typed data (EIP-712)\n * This is the primary signing method for x402 EVM payments\n */\n signTypedData?(params: {\n domain: Record<string, unknown>;\n types: Record<string, unknown[]>;\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<string>;\n /**\n * Alternative: Send transaction directly\n * Used if signTypedData is not available\n */\n sendTransaction?(params: {\n to: string;\n data: string;\n value?: bigint;\n }): Promise<string>;\n}\n\n/**\n * Check if an object is a valid EVM wallet\n */\nexport function isEvmWallet(wallet: unknown): wallet is EvmWallet {\n if (!wallet || typeof wallet !== 'object') return false;\n const w = wallet as Record<string, unknown>;\n return (\n 'address' in w &&\n typeof w.address === 'string' &&\n w.address.startsWith('0x')\n );\n}\n\n// ERC20 balanceOf function selector: 0x70a08231\n\n/**\n * EVM Chain Adapter\n */\nexport class EvmAdapter implements ChainAdapter {\n readonly name = 'EVM';\n readonly networks = [BASE_MAINNET, BASE_SEPOLIA, ETHEREUM_MAINNET, ARBITRUM_ONE];\n\n private config: AdapterConfig;\n private log: (...args: unknown[]) => void;\n\n constructor(config: AdapterConfig = {}) {\n this.config = config;\n this.log = config.verbose\n ? console.log.bind(console, '[x402:evm]')\n : () => {};\n }\n\n canHandle(network: string): boolean {\n // Handle exact CAIP-2\n if (this.networks.includes(network)) return true;\n // Legacy format\n if (network === 'base') return true;\n if (network === 'ethereum') return true;\n if (network === 'arbitrum') return true;\n // Check if it starts with 'eip155:'\n if (network.startsWith('eip155:')) return true;\n return false;\n }\n\n getDefaultRpcUrl(network: string): string {\n if (this.config.rpcUrls?.[network]) {\n return this.config.rpcUrls[network];\n }\n if (DEFAULT_RPC_URLS[network]) {\n return DEFAULT_RPC_URLS[network];\n }\n // Normalize legacy\n if (network === 'base') return DEFAULT_RPC_URLS[BASE_MAINNET];\n if (network === 'ethereum') return DEFAULT_RPC_URLS[ETHEREUM_MAINNET];\n if (network === 'arbitrum') return DEFAULT_RPC_URLS[ARBITRUM_ONE];\n return DEFAULT_RPC_URLS[BASE_MAINNET];\n }\n\n getAddress(wallet: unknown): string | null {\n if (!isEvmWallet(wallet)) return null;\n return wallet.address;\n }\n\n isConnected(wallet: unknown): boolean {\n if (!isEvmWallet(wallet)) return false;\n return !!wallet.address;\n }\n\n private getChainId(network: string): number {\n if (CHAIN_IDS[network]) return CHAIN_IDS[network];\n // Try to extract from CAIP-2\n if (network.startsWith('eip155:')) {\n const chainIdStr = network.split(':')[1];\n return parseInt(chainIdStr, 10);\n }\n // Defaults\n if (network === 'base') return 8453;\n if (network === 'ethereum') return 1;\n if (network === 'arbitrum') return 42161;\n return 8453; // Default to Base\n }\n\n async getBalance(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<number> {\n if (!isEvmWallet(wallet) || !wallet.address) {\n return 0;\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n\n try {\n // Use eth_call to check ERC20 balance\n const data = this.encodeBalanceOf(wallet.address);\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'eth_call',\n params: [\n {\n to: accept.asset,\n data,\n },\n 'latest',\n ],\n }),\n });\n\n if (!response.ok) {\n throw new Error(`RPC request failed: ${response.status}`);\n }\n\n const result = (await response.json()) as { error?: unknown; result?: string };\n if (result.error) {\n throw new Error(`RPC error: ${JSON.stringify(result.error)}`);\n }\n if (!result.result || result.result === '0x') {\n return 0;\n }\n\n const balance = BigInt(result.result);\n const decimals = accept.extra?.decimals ?? 6;\n return Number(balance) / Math.pow(10, decimals);\n } catch (err) {\n // Re-throw RPC/network errors so caller can distinguish from zero balance\n throw err;\n }\n }\n\n private encodeBalanceOf(address: string): string {\n // Function selector for balanceOf(address)\n const selector = '0x70a08231';\n // Pad address to 32 bytes\n const paddedAddress = address.slice(2).toLowerCase().padStart(64, '0');\n return selector + paddedAddress;\n }\n\n async buildTransaction(\n accept: PaymentAccept,\n wallet: unknown,\n _rpcUrl?: string\n ): Promise<SignedTransaction> {\n if (!isEvmWallet(wallet)) {\n throw new Error('Invalid EVM wallet');\n }\n if (!wallet.address) {\n throw new Error('Wallet not connected');\n }\n\n const { payTo, asset, extra } = accept;\n // amount is the v2 spec field, maxAmountRequired is v1 fallback\n const amount = accept.amount ?? accept.maxAmountRequired;\n if (!amount) {\n throw new Error('Missing amount in payment requirements');\n }\n\n this.log('Building EVM transaction:', {\n from: wallet.address,\n to: payTo,\n amount,\n asset,\n network: accept.network,\n });\n\n // For x402 v2 EVM payments, we use EIP-712 typed data signing\n // The facilitator will execute the transfer on behalf of the user\n\n const chainId = this.getChainId(accept.network);\n\n // Build the EIP-712 typed data\n // This matches what Dexter's facilitator expects\n const domain = {\n name: extra?.name ?? 'USD Coin',\n version: extra?.version ?? '2',\n chainId: BigInt(chainId),\n verifyingContract: asset as `0x${string}`,\n };\n\n const types = {\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 };\n\n // Generate a cryptographically secure random nonce (32 bytes hex)\n const nonceBytes = new Uint8Array(32);\n (globalThis.crypto ?? (await import('crypto')).webcrypto).getRandomValues(nonceBytes);\n const nonce = ('0x' + [...nonceBytes].map(b => b.toString(16).padStart(2, '0')).join('')) as `0x${string}`;\n\n const now = Math.floor(Date.now() / 1000);\n \n // Authorization object - values as strings for JSON, BigInts for signing\n const authorization = {\n from: wallet.address,\n to: payTo,\n value: amount, // string\n validAfter: String(now - 600), // 10 minutes before (matching upstream)\n validBefore: String(now + (accept.maxTimeoutSeconds || 60)),\n nonce,\n };\n\n // Message for signing uses BigInt values\n const message = {\n from: wallet.address,\n to: payTo,\n value: BigInt(amount),\n validAfter: BigInt(now - 600),\n validBefore: BigInt(now + (accept.maxTimeoutSeconds || 60)),\n nonce,\n };\n\n if (!wallet.signTypedData) {\n throw new Error('Wallet does not support signTypedData (EIP-712)');\n }\n\n const signature = await wallet.signTypedData({\n domain: domain as Record<string, unknown>,\n types: types as Record<string, unknown[]>,\n primaryType: 'TransferWithAuthorization',\n message: message as Record<string, unknown>,\n });\n\n this.log('EIP-712 signature obtained');\n\n // Payload structure matches upstream @x402/evm exactly\n const payload = {\n authorization,\n signature,\n };\n\n return {\n serialized: JSON.stringify(payload),\n signature,\n };\n }\n}\n\n/**\n * Create an EVM adapter instance\n */\nexport function createEvmAdapter(config?: AdapterConfig): EvmAdapter {\n return new EvmAdapter(config);\n}\n\n"],"mappings":"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","names":["DEFAULT_RPC_URLS"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { C as ChainAdapter } from '../types-
|
|
2
|
-
export { A as AdapterConfig, B as BalanceInfo, G as GenericWallet, S as SignedTransaction, W as WalletSet } from '../types-
|
|
3
|
-
import { b as SolanaAdapter, d as EvmAdapter } from '../solana-
|
|
4
|
-
export { A as ARBITRUM_ONE, k as AVALANCHE, B as BASE_MAINNET, j as BASE_SEPOLIA, n as ETHEREUM_MAINNET, E as EvmWallet, O as OPTIMISM, P as POLYGON, l as SKALE_BASE, m as SKALE_BASE_SEPOLIA, e as SOLANA_DEVNET, S as SOLANA_MAINNET, f as SOLANA_TESTNET, g as SolanaWallet, U as USDC_ADDRESSES, a as createEvmAdapter, c as createSolanaAdapter, h as isEvmWallet, i as isSolanaWallet } from '../solana-
|
|
5
|
-
import '../types-
|
|
1
|
+
import { C as ChainAdapter } from '../types-CfKflCZO.cjs';
|
|
2
|
+
export { A as AdapterConfig, B as BalanceInfo, G as GenericWallet, S as SignedTransaction, W as WalletSet } from '../types-CfKflCZO.cjs';
|
|
3
|
+
import { b as SolanaAdapter, d as EvmAdapter } from '../solana-BcOfK6Eq.cjs';
|
|
4
|
+
export { A as ARBITRUM_ONE, k as AVALANCHE, B as BASE_MAINNET, j as BASE_SEPOLIA, n as ETHEREUM_MAINNET, E as EvmWallet, O as OPTIMISM, P as POLYGON, l as SKALE_BASE, m as SKALE_BASE_SEPOLIA, e as SOLANA_DEVNET, S as SOLANA_MAINNET, f as SOLANA_TESTNET, g as SolanaWallet, U as USDC_ADDRESSES, a as createEvmAdapter, c as createSolanaAdapter, h as isEvmWallet, i as isSolanaWallet } from '../solana-BcOfK6Eq.cjs';
|
|
5
|
+
import '../types-CjLMR7qs.cjs';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Check if an asset address is a known USDC contract (any chain).
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { C as ChainAdapter } from '../types-
|
|
2
|
-
export { A as AdapterConfig, B as BalanceInfo, G as GenericWallet, S as SignedTransaction, W as WalletSet } from '../types-
|
|
3
|
-
import { b as SolanaAdapter, d as EvmAdapter } from '../solana-
|
|
4
|
-
export { A as ARBITRUM_ONE, k as AVALANCHE, B as BASE_MAINNET, j as BASE_SEPOLIA, n as ETHEREUM_MAINNET, E as EvmWallet, O as OPTIMISM, P as POLYGON, l as SKALE_BASE, m as SKALE_BASE_SEPOLIA, e as SOLANA_DEVNET, S as SOLANA_MAINNET, f as SOLANA_TESTNET, g as SolanaWallet, U as USDC_ADDRESSES, a as createEvmAdapter, c as createSolanaAdapter, h as isEvmWallet, i as isSolanaWallet } from '../solana-
|
|
5
|
-
import '../types-
|
|
1
|
+
import { C as ChainAdapter } from '../types-BIHhO2-I.js';
|
|
2
|
+
export { A as AdapterConfig, B as BalanceInfo, G as GenericWallet, S as SignedTransaction, W as WalletSet } from '../types-BIHhO2-I.js';
|
|
3
|
+
import { b as SolanaAdapter, d as EvmAdapter } from '../solana-Cxr5byPa.js';
|
|
4
|
+
export { A as ARBITRUM_ONE, k as AVALANCHE, B as BASE_MAINNET, j as BASE_SEPOLIA, n as ETHEREUM_MAINNET, E as EvmWallet, O as OPTIMISM, P as POLYGON, l as SKALE_BASE, m as SKALE_BASE_SEPOLIA, e as SOLANA_DEVNET, S as SOLANA_MAINNET, f as SOLANA_TESTNET, g as SolanaWallet, U as USDC_ADDRESSES, a as createEvmAdapter, c as createSolanaAdapter, h as isEvmWallet, i as isSolanaWallet } from '../solana-Cxr5byPa.js';
|
|
5
|
+
import '../types-CjLMR7qs.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Check if an asset address is a known USDC contract (any chain).
|
package/dist/adapters/index.js
CHANGED
|
@@ -87,8 +87,11 @@ var SolanaAdapter = class {
|
|
|
87
87
|
const account = await getAccount(connection, ata, void 0, programId);
|
|
88
88
|
const decimals = accept.extra?.decimals ?? 6;
|
|
89
89
|
return Number(account.amount) / Math.pow(10, decimals);
|
|
90
|
-
} catch {
|
|
91
|
-
|
|
90
|
+
} catch (err) {
|
|
91
|
+
if (err && typeof err === "object" && "name" in err && (err.name === "TokenAccountNotFoundError" || err.name === "TokenInvalidAccountOwnerError")) {
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
throw err;
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
97
|
async buildTransaction(accept, wallet, rpcUrl) {
|
|
@@ -316,15 +319,21 @@ var EvmAdapter = class {
|
|
|
316
319
|
]
|
|
317
320
|
})
|
|
318
321
|
});
|
|
322
|
+
if (!response.ok) {
|
|
323
|
+
throw new Error(`RPC request failed: ${response.status}`);
|
|
324
|
+
}
|
|
319
325
|
const result = await response.json();
|
|
320
|
-
if (result.error
|
|
326
|
+
if (result.error) {
|
|
327
|
+
throw new Error(`RPC error: ${JSON.stringify(result.error)}`);
|
|
328
|
+
}
|
|
329
|
+
if (!result.result || result.result === "0x") {
|
|
321
330
|
return 0;
|
|
322
331
|
}
|
|
323
332
|
const balance = BigInt(result.result);
|
|
324
333
|
const decimals = accept.extra?.decimals ?? 6;
|
|
325
334
|
return Number(balance) / Math.pow(10, decimals);
|
|
326
|
-
} catch {
|
|
327
|
-
|
|
335
|
+
} catch (err) {
|
|
336
|
+
throw err;
|
|
328
337
|
}
|
|
329
338
|
}
|
|
330
339
|
encodeBalanceOf(address) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/solana.ts","../../src/adapters/evm.ts","../../src/adapters/index.ts"],"sourcesContent":["/**\n * Solana Chain Adapter\n *\n * Implements the ChainAdapter interface for Solana networks.\n * Handles transaction building, signing, and balance queries.\n */\n\nimport {\n PublicKey,\n Connection,\n TransactionMessage,\n VersionedTransaction,\n ComputeBudgetProgram,\n type TransactionInstruction,\n} from '@solana/web3.js';\nimport {\n getAssociatedTokenAddress,\n getAccount,\n createTransferCheckedInstruction,\n getMint,\n TOKEN_PROGRAM_ID,\n TOKEN_2022_PROGRAM_ID,\n} from '@solana/spl-token';\nimport type { ChainAdapter, AdapterConfig, SignedTransaction } from './types';\nimport type { PaymentAccept } from '../types';\n\n/**\n * CAIP-2 network identifiers for Solana\n */\nexport const SOLANA_MAINNET = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';\nexport const SOLANA_DEVNET = 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1';\nexport const SOLANA_TESTNET = 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z';\n\n/**\n * Default RPC URLs\n * Mainnet uses Dexter's RPC proxy for reliability and zero-config setup\n */\nconst DEFAULT_RPC_URLS: Record<string, string> = {\n [SOLANA_MAINNET]: 'https://api.dexter.cash/api/solana/rpc',\n [SOLANA_DEVNET]: 'https://api.devnet.solana.com',\n [SOLANA_TESTNET]: 'https://api.testnet.solana.com',\n};\n\n/**\n * Dexter policy-safe compute budget settings\n */\nconst DEFAULT_COMPUTE_UNIT_LIMIT = 12_000;\nconst DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;\n\n/**\n * Solana wallet interface (compatible with @solana/wallet-adapter)\n */\nexport interface SolanaWallet {\n publicKey: { toBase58(): string } | null;\n signTransaction<T>(tx: T): Promise<T>;\n}\n\n/**\n * Check if an object is a valid Solana wallet\n */\nexport function isSolanaWallet(wallet: unknown): wallet is SolanaWallet {\n if (!wallet || typeof wallet !== 'object') return false;\n const w = wallet as Record<string, unknown>;\n return (\n 'publicKey' in w &&\n 'signTransaction' in w &&\n typeof w.signTransaction === 'function'\n );\n}\n\n/**\n * Solana Chain Adapter\n */\nexport class SolanaAdapter implements ChainAdapter {\n readonly name = 'Solana';\n readonly networks = [SOLANA_MAINNET, SOLANA_DEVNET, SOLANA_TESTNET];\n\n private config: AdapterConfig;\n private log: (...args: unknown[]) => void;\n\n constructor(config: AdapterConfig = {}) {\n this.config = config;\n this.log = config.verbose\n ? console.log.bind(console, '[x402:solana]')\n : () => {};\n }\n\n canHandle(network: string): boolean {\n // Handle both exact CAIP-2 and legacy formats\n if (this.networks.includes(network)) return true;\n // Legacy format support\n if (network === 'solana') return true;\n if (network === 'solana-devnet') return true;\n if (network === 'solana-testnet') return true;\n // Check if it starts with 'solana:'\n if (network.startsWith('solana:')) return true;\n return false;\n }\n\n getDefaultRpcUrl(network: string): string {\n // Check custom config first\n if (this.config.rpcUrls?.[network]) {\n return this.config.rpcUrls[network];\n }\n // Check defaults\n if (DEFAULT_RPC_URLS[network]) {\n return DEFAULT_RPC_URLS[network];\n }\n // Normalize legacy networks\n if (network === 'solana') return DEFAULT_RPC_URLS[SOLANA_MAINNET];\n if (network === 'solana-devnet') return DEFAULT_RPC_URLS[SOLANA_DEVNET];\n if (network === 'solana-testnet') return DEFAULT_RPC_URLS[SOLANA_TESTNET];\n // Default to mainnet\n return DEFAULT_RPC_URLS[SOLANA_MAINNET];\n }\n\n getAddress(wallet: unknown): string | null {\n if (!isSolanaWallet(wallet)) return null;\n return wallet.publicKey?.toBase58() ?? null;\n }\n\n isConnected(wallet: unknown): boolean {\n if (!isSolanaWallet(wallet)) return false;\n return wallet.publicKey !== null;\n }\n\n async getBalance(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<number> {\n if (!isSolanaWallet(wallet) || !wallet.publicKey) {\n return 0;\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n const connection = new Connection(url, 'confirmed');\n const userPubkey = new PublicKey(wallet.publicKey.toBase58());\n const mintPubkey = new PublicKey(accept.asset);\n\n try {\n // Determine token program\n const mintInfo = await connection.getAccountInfo(mintPubkey, 'confirmed');\n const programId =\n mintInfo?.owner.toBase58() === TOKEN_2022_PROGRAM_ID.toBase58()\n ? TOKEN_2022_PROGRAM_ID\n : TOKEN_PROGRAM_ID;\n\n const ata = await getAssociatedTokenAddress(\n mintPubkey,\n userPubkey,\n false,\n programId\n );\n\n const account = await getAccount(connection, ata, undefined, programId);\n const decimals = accept.extra?.decimals ?? 6;\n return Number(account.amount) / Math.pow(10, decimals);\n } catch {\n // Token account doesn't exist\n return 0;\n }\n }\n\n async buildTransaction(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<SignedTransaction> {\n if (!isSolanaWallet(wallet)) {\n throw new Error('Invalid Solana wallet');\n }\n if (!wallet.publicKey) {\n throw new Error('Wallet not connected');\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n const connection = new Connection(url, 'confirmed');\n const userPubkey = new PublicKey(wallet.publicKey.toBase58());\n\n // Extract required fields — amount is the v2 spec field, maxAmountRequired is v1 fallback\n const { payTo, asset, extra } = accept;\n const amount = accept.amount ?? accept.maxAmountRequired;\n if (!amount) {\n throw new Error('Missing amount in payment requirements');\n }\n\n if (!extra?.feePayer) {\n throw new Error('Missing feePayer in payment requirements');\n }\n // Note: decimals is optional - we fetch from mint on-chain if not provided\n\n const feePayerPubkey = new PublicKey(extra.feePayer);\n const mintPubkey = new PublicKey(asset);\n const destinationPubkey = new PublicKey(payTo);\n\n this.log('Building transaction:', {\n from: userPubkey.toBase58(),\n to: payTo,\n amount,\n asset,\n feePayer: extra.feePayer,\n });\n\n // Build instructions\n const instructions: TransactionInstruction[] = [];\n\n // 1. ComputeBudget: Set compute unit limit\n instructions.push(\n ComputeBudgetProgram.setComputeUnitLimit({\n units: DEFAULT_COMPUTE_UNIT_LIMIT,\n })\n );\n\n // 2. ComputeBudget: Set compute unit price\n instructions.push(\n ComputeBudgetProgram.setComputeUnitPrice({\n microLamports: DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS,\n })\n );\n\n // 3. Determine token program\n const mintInfo = await connection.getAccountInfo(mintPubkey, 'confirmed');\n if (!mintInfo) {\n throw new Error(`Token mint ${asset} not found`);\n }\n\n const programId =\n mintInfo.owner.toBase58() === TOKEN_2022_PROGRAM_ID.toBase58()\n ? TOKEN_2022_PROGRAM_ID\n : TOKEN_PROGRAM_ID;\n\n // Fetch mint to get decimals (required for TransferChecked)\n const mint = await getMint(connection, mintPubkey, undefined, programId);\n if (typeof extra?.decimals === 'number' && mint.decimals !== extra.decimals) {\n this.log(\n `Decimals mismatch: requirements say ${extra.decimals}, mint says ${mint.decimals}`\n );\n }\n\n // Derive Associated Token Accounts\n const sourceAta = await getAssociatedTokenAddress(\n mintPubkey,\n userPubkey,\n false,\n programId\n );\n const destinationAta = await getAssociatedTokenAddress(\n mintPubkey,\n destinationPubkey,\n false,\n programId\n );\n\n // Verify source ATA exists\n const sourceAtaInfo = await connection.getAccountInfo(sourceAta, 'confirmed');\n if (!sourceAtaInfo) {\n throw new Error(\n `No token account found for ${asset}. Please ensure you have USDC in your wallet.`\n );\n }\n\n // Verify destination ATA exists\n const destAtaInfo = await connection.getAccountInfo(destinationAta, 'confirmed');\n if (!destAtaInfo) {\n throw new Error(\n `Seller token account not found. The seller (${payTo}) must have a USDC account.`\n );\n }\n\n // 4. TransferChecked instruction\n const amountBigInt = BigInt(amount);\n instructions.push(\n createTransferCheckedInstruction(\n sourceAta,\n mintPubkey,\n destinationAta,\n userPubkey,\n amountBigInt,\n mint.decimals,\n [],\n programId\n )\n );\n\n // Get recent blockhash\n const { blockhash } = await connection.getLatestBlockhash('confirmed');\n\n // Compile to V0 message (feePayer is facilitator)\n const message = new TransactionMessage({\n payerKey: feePayerPubkey,\n recentBlockhash: blockhash,\n instructions,\n }).compileToV0Message();\n\n // Create and sign transaction\n const transaction = new VersionedTransaction(message);\n const signedTx = await wallet.signTransaction(transaction);\n\n this.log('Transaction signed successfully');\n\n return {\n serialized: Buffer.from(signedTx.serialize()).toString('base64'),\n };\n }\n}\n\n/**\n * Create a Solana adapter instance\n */\nexport function createSolanaAdapter(config?: AdapterConfig): SolanaAdapter {\n return new SolanaAdapter(config);\n}\n\n\n\n","/**\n * EVM Chain Adapter\n *\n * Implements the ChainAdapter interface for EVM networks (Base, Ethereum, Arbitrum, etc.)\n * Uses EIP-712 typed data signing for x402 v2 payments.\n */\n\nimport type { ChainAdapter, AdapterConfig, SignedTransaction } from './types';\nimport type { PaymentAccept } from '../types';\n\n/**\n * CAIP-2 network identifiers for EVM chains.\n * Mirrors dexter-facilitator/src/config/chains.ts — update both when adding chains.\n */\nexport const BASE_MAINNET = 'eip155:8453';\nexport const BASE_SEPOLIA = 'eip155:84532';\nexport const ARBITRUM_ONE = 'eip155:42161';\nexport const POLYGON = 'eip155:137';\nexport const OPTIMISM = 'eip155:10';\nexport const AVALANCHE = 'eip155:43114';\nexport const SKALE_BASE = 'eip155:1187947933';\nexport const SKALE_BASE_SEPOLIA = 'eip155:324705682';\n\n/** @deprecated Not supported by the Dexter facilitator. Use BASE_MAINNET for EVM payments. */\nexport const ETHEREUM_MAINNET = 'eip155:1';\n\n/**\n * Chain IDs by CAIP-2 network\n */\nconst CHAIN_IDS: Record<string, number> = {\n [BASE_MAINNET]: 8453,\n [BASE_SEPOLIA]: 84532,\n [ARBITRUM_ONE]: 42161,\n [POLYGON]: 137,\n [OPTIMISM]: 10,\n [AVALANCHE]: 43114,\n [SKALE_BASE]: 1187947933,\n [SKALE_BASE_SEPOLIA]: 324705682,\n [ETHEREUM_MAINNET]: 1,\n};\n\n/**\n * Default RPC URLs.\n * Base mainnet uses Dexter's RPC proxy for reliability and zero-config setup.\n * Source of truth: dexter-facilitator/src/config/chains.ts\n */\nconst DEFAULT_RPC_URLS: Record<string, string> = {\n [BASE_MAINNET]: 'https://api.dexter.cash/api/base/rpc',\n [BASE_SEPOLIA]: 'https://sepolia.base.org',\n [ARBITRUM_ONE]: 'https://arb1.arbitrum.io/rpc',\n [POLYGON]: 'https://polygon-rpc.com',\n [OPTIMISM]: 'https://mainnet.optimism.io',\n [AVALANCHE]: 'https://api.avax.network/ext/bc/C/rpc',\n [SKALE_BASE]: 'https://skale-base.skalenodes.com/v1/base',\n [SKALE_BASE_SEPOLIA]: 'https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha',\n [ETHEREUM_MAINNET]: 'https://eth.llamarpc.com',\n};\n\n/**\n * USDC contract addresses by chain.\n * Source of truth: dexter-facilitator/src/config/chains.ts\n */\nexport const USDC_ADDRESSES: Record<string, string> = {\n [BASE_MAINNET]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n [BASE_SEPOLIA]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n [ARBITRUM_ONE]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',\n [POLYGON]: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n [OPTIMISM]: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',\n [AVALANCHE]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',\n [SKALE_BASE]: '0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20',\n [SKALE_BASE_SEPOLIA]: '0x2e08028E3C4c2356572E096d8EF835cD5C6030bD',\n [ETHEREUM_MAINNET]: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n};\n\n/**\n * EVM wallet interface (compatible with wagmi, ethers, viem)\n */\nexport interface EvmWallet {\n /** Wallet address */\n address: string;\n /** Chain ID currently connected to */\n chainId?: number;\n /**\n * Sign typed data (EIP-712)\n * This is the primary signing method for x402 EVM payments\n */\n signTypedData?(params: {\n domain: Record<string, unknown>;\n types: Record<string, unknown[]>;\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<string>;\n /**\n * Alternative: Send transaction directly\n * Used if signTypedData is not available\n */\n sendTransaction?(params: {\n to: string;\n data: string;\n value?: bigint;\n }): Promise<string>;\n}\n\n/**\n * Check if an object is a valid EVM wallet\n */\nexport function isEvmWallet(wallet: unknown): wallet is EvmWallet {\n if (!wallet || typeof wallet !== 'object') return false;\n const w = wallet as Record<string, unknown>;\n return (\n 'address' in w &&\n typeof w.address === 'string' &&\n w.address.startsWith('0x')\n );\n}\n\n// ERC20 balanceOf function selector: 0x70a08231\n\n/**\n * EVM Chain Adapter\n */\nexport class EvmAdapter implements ChainAdapter {\n readonly name = 'EVM';\n readonly networks = [BASE_MAINNET, BASE_SEPOLIA, ETHEREUM_MAINNET, ARBITRUM_ONE];\n\n private config: AdapterConfig;\n private log: (...args: unknown[]) => void;\n\n constructor(config: AdapterConfig = {}) {\n this.config = config;\n this.log = config.verbose\n ? console.log.bind(console, '[x402:evm]')\n : () => {};\n }\n\n canHandle(network: string): boolean {\n // Handle exact CAIP-2\n if (this.networks.includes(network)) return true;\n // Legacy format\n if (network === 'base') return true;\n if (network === 'ethereum') return true;\n if (network === 'arbitrum') return true;\n // Check if it starts with 'eip155:'\n if (network.startsWith('eip155:')) return true;\n return false;\n }\n\n getDefaultRpcUrl(network: string): string {\n if (this.config.rpcUrls?.[network]) {\n return this.config.rpcUrls[network];\n }\n if (DEFAULT_RPC_URLS[network]) {\n return DEFAULT_RPC_URLS[network];\n }\n // Normalize legacy\n if (network === 'base') return DEFAULT_RPC_URLS[BASE_MAINNET];\n if (network === 'ethereum') return DEFAULT_RPC_URLS[ETHEREUM_MAINNET];\n if (network === 'arbitrum') return DEFAULT_RPC_URLS[ARBITRUM_ONE];\n return DEFAULT_RPC_URLS[BASE_MAINNET];\n }\n\n getAddress(wallet: unknown): string | null {\n if (!isEvmWallet(wallet)) return null;\n return wallet.address;\n }\n\n isConnected(wallet: unknown): boolean {\n if (!isEvmWallet(wallet)) return false;\n return !!wallet.address;\n }\n\n private getChainId(network: string): number {\n if (CHAIN_IDS[network]) return CHAIN_IDS[network];\n // Try to extract from CAIP-2\n if (network.startsWith('eip155:')) {\n const chainIdStr = network.split(':')[1];\n return parseInt(chainIdStr, 10);\n }\n // Defaults\n if (network === 'base') return 8453;\n if (network === 'ethereum') return 1;\n if (network === 'arbitrum') return 42161;\n return 8453; // Default to Base\n }\n\n async getBalance(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<number> {\n if (!isEvmWallet(wallet) || !wallet.address) {\n return 0;\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n\n try {\n // Use eth_call to check ERC20 balance\n const data = this.encodeBalanceOf(wallet.address);\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'eth_call',\n params: [\n {\n to: accept.asset,\n data,\n },\n 'latest',\n ],\n }),\n });\n\n const result = (await response.json()) as { error?: unknown; result?: string };\n if (result.error || !result.result) {\n return 0;\n }\n\n const balance = BigInt(result.result);\n const decimals = accept.extra?.decimals ?? 6;\n return Number(balance) / Math.pow(10, decimals);\n } catch {\n return 0;\n }\n }\n\n private encodeBalanceOf(address: string): string {\n // Function selector for balanceOf(address)\n const selector = '0x70a08231';\n // Pad address to 32 bytes\n const paddedAddress = address.slice(2).toLowerCase().padStart(64, '0');\n return selector + paddedAddress;\n }\n\n async buildTransaction(\n accept: PaymentAccept,\n wallet: unknown,\n _rpcUrl?: string\n ): Promise<SignedTransaction> {\n if (!isEvmWallet(wallet)) {\n throw new Error('Invalid EVM wallet');\n }\n if (!wallet.address) {\n throw new Error('Wallet not connected');\n }\n\n const { payTo, asset, extra } = accept;\n // amount is the v2 spec field, maxAmountRequired is v1 fallback\n const amount = accept.amount ?? accept.maxAmountRequired;\n if (!amount) {\n throw new Error('Missing amount in payment requirements');\n }\n\n this.log('Building EVM transaction:', {\n from: wallet.address,\n to: payTo,\n amount,\n asset,\n network: accept.network,\n });\n\n // For x402 v2 EVM payments, we use EIP-712 typed data signing\n // The facilitator will execute the transfer on behalf of the user\n\n const chainId = this.getChainId(accept.network);\n\n // Build the EIP-712 typed data\n // This matches what Dexter's facilitator expects\n const domain = {\n name: extra?.name ?? 'USD Coin',\n version: extra?.version ?? '2',\n chainId: BigInt(chainId),\n verifyingContract: asset as `0x${string}`,\n };\n\n const types = {\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 };\n\n // Generate a cryptographically secure random nonce (32 bytes hex)\n const nonceBytes = new Uint8Array(32);\n (globalThis.crypto ?? (await import('crypto')).webcrypto).getRandomValues(nonceBytes);\n const nonce = ('0x' + [...nonceBytes].map(b => b.toString(16).padStart(2, '0')).join('')) as `0x${string}`;\n\n const now = Math.floor(Date.now() / 1000);\n \n // Authorization object - values as strings for JSON, BigInts for signing\n const authorization = {\n from: wallet.address,\n to: payTo,\n value: amount, // string\n validAfter: String(now - 600), // 10 minutes before (matching upstream)\n validBefore: String(now + (accept.maxTimeoutSeconds || 60)),\n nonce,\n };\n\n // Message for signing uses BigInt values\n const message = {\n from: wallet.address,\n to: payTo,\n value: BigInt(amount),\n validAfter: BigInt(now - 600),\n validBefore: BigInt(now + (accept.maxTimeoutSeconds || 60)),\n nonce,\n };\n\n if (!wallet.signTypedData) {\n throw new Error('Wallet does not support signTypedData (EIP-712)');\n }\n\n const signature = await wallet.signTypedData({\n domain: domain as Record<string, unknown>,\n types: types as Record<string, unknown[]>,\n primaryType: 'TransferWithAuthorization',\n message: message as Record<string, unknown>,\n });\n\n this.log('EIP-712 signature obtained');\n\n // Payload structure matches upstream @x402/evm exactly\n const payload = {\n authorization,\n signature,\n };\n\n return {\n serialized: JSON.stringify(payload),\n signature,\n };\n }\n}\n\n/**\n * Create an EVM adapter instance\n */\nexport function createEvmAdapter(config?: AdapterConfig): EvmAdapter {\n return new EvmAdapter(config);\n}\n\n","/**\n * Chain Adapters\n *\n * x402 v2 is designed to be chain-agnostic. Each adapter handles\n * the specifics of transaction building and signing for its chain.\n *\n * @example\n * ```typescript\n * import { createSolanaAdapter, createEvmAdapter } from '@dexterai/x402/adapters';\n *\n * const adapters = [\n * createSolanaAdapter(),\n * createEvmAdapter(),\n * ];\n *\n * // Find adapter for a network\n * const adapter = adapters.find(a => a.canHandle('eip155:8453'));\n * ```\n */\n\nimport { createSolanaAdapter as _createSolanaAdapter } from './solana';\nimport { createEvmAdapter as _createEvmAdapter } from './evm';\nimport { USDC_ADDRESSES as _USDC_ADDRESSES } from './evm';\n\n// Types\nexport type {\n ChainAdapter,\n AdapterConfig,\n SignedTransaction,\n GenericWallet,\n WalletSet,\n BalanceInfo,\n} from './types';\n\n// Solana\nexport {\n SolanaAdapter,\n createSolanaAdapter,\n isSolanaWallet,\n SOLANA_MAINNET,\n SOLANA_DEVNET,\n SOLANA_TESTNET,\n} from './solana';\nexport type { SolanaWallet } from './solana';\n\n// EVM\nexport {\n EvmAdapter,\n createEvmAdapter,\n isEvmWallet,\n BASE_MAINNET,\n BASE_SEPOLIA,\n ARBITRUM_ONE,\n POLYGON,\n OPTIMISM,\n AVALANCHE,\n SKALE_BASE,\n SKALE_BASE_SEPOLIA,\n ETHEREUM_MAINNET,\n USDC_ADDRESSES,\n} from './evm';\nexport type { EvmWallet } from './evm';\n\n/**\n * Check if an asset address is a known USDC contract (any chain).\n * Single source of truth for decimal inference in the client.\n */\nexport function isKnownUSDC(asset: string): boolean {\n // Solana mints\n if (asset === 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v') return true; // mainnet\n if (asset === '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU') return true; // devnet\n // All EVM USDC addresses (case-insensitive for EVM)\n const lc = asset.toLowerCase();\n for (const addr of Object.values(_USDC_ADDRESSES)) {\n if (addr.toLowerCase() === lc) return true;\n }\n return false;\n}\n\n/**\n * Create all default adapters\n */\nexport function createDefaultAdapters(verbose = false) {\n return [\n _createSolanaAdapter({ verbose }),\n _createEvmAdapter({ verbose }),\n ];\n}\n\n/**\n * Find adapter that can handle a network\n */\nexport function findAdapter(\n adapters: import('./types').ChainAdapter[],\n network: string\n): import('./types').ChainAdapter | undefined {\n return adapters.find(adapter => adapter.canHandle(network));\n}\n\n\n\n"],"mappings":"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","names":["DEFAULT_RPC_URLS"]}
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/solana.ts","../../src/adapters/evm.ts","../../src/adapters/index.ts"],"sourcesContent":["/**\n * Solana Chain Adapter\n *\n * Implements the ChainAdapter interface for Solana networks.\n * Handles transaction building, signing, and balance queries.\n */\n\nimport {\n PublicKey,\n Connection,\n TransactionMessage,\n VersionedTransaction,\n ComputeBudgetProgram,\n type TransactionInstruction,\n} from '@solana/web3.js';\nimport {\n getAssociatedTokenAddress,\n getAccount,\n createTransferCheckedInstruction,\n getMint,\n TOKEN_PROGRAM_ID,\n TOKEN_2022_PROGRAM_ID,\n} from '@solana/spl-token';\nimport type { ChainAdapter, AdapterConfig, SignedTransaction } from './types';\nimport type { PaymentAccept } from '../types';\n\n/**\n * CAIP-2 network identifiers for Solana\n */\nexport const SOLANA_MAINNET = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';\nexport const SOLANA_DEVNET = 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1';\nexport const SOLANA_TESTNET = 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z';\n\n/**\n * Default RPC URLs\n * Mainnet uses Dexter's RPC proxy for reliability and zero-config setup\n */\nconst DEFAULT_RPC_URLS: Record<string, string> = {\n [SOLANA_MAINNET]: 'https://api.dexter.cash/api/solana/rpc',\n [SOLANA_DEVNET]: 'https://api.devnet.solana.com',\n [SOLANA_TESTNET]: 'https://api.testnet.solana.com',\n};\n\n/**\n * Dexter policy-safe compute budget settings\n */\nconst DEFAULT_COMPUTE_UNIT_LIMIT = 12_000;\nconst DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1;\n\n/**\n * Solana wallet interface (compatible with @solana/wallet-adapter)\n */\nexport interface SolanaWallet {\n publicKey: { toBase58(): string } | null;\n signTransaction<T>(tx: T): Promise<T>;\n}\n\n/**\n * Check if an object is a valid Solana wallet\n */\nexport function isSolanaWallet(wallet: unknown): wallet is SolanaWallet {\n if (!wallet || typeof wallet !== 'object') return false;\n const w = wallet as Record<string, unknown>;\n return (\n 'publicKey' in w &&\n 'signTransaction' in w &&\n typeof w.signTransaction === 'function'\n );\n}\n\n/**\n * Solana Chain Adapter\n */\nexport class SolanaAdapter implements ChainAdapter {\n readonly name = 'Solana';\n readonly networks = [SOLANA_MAINNET, SOLANA_DEVNET, SOLANA_TESTNET];\n\n private config: AdapterConfig;\n private log: (...args: unknown[]) => void;\n\n constructor(config: AdapterConfig = {}) {\n this.config = config;\n this.log = config.verbose\n ? console.log.bind(console, '[x402:solana]')\n : () => {};\n }\n\n canHandle(network: string): boolean {\n // Handle both exact CAIP-2 and legacy formats\n if (this.networks.includes(network)) return true;\n // Legacy format support\n if (network === 'solana') return true;\n if (network === 'solana-devnet') return true;\n if (network === 'solana-testnet') return true;\n // Check if it starts with 'solana:'\n if (network.startsWith('solana:')) return true;\n return false;\n }\n\n getDefaultRpcUrl(network: string): string {\n // Check custom config first\n if (this.config.rpcUrls?.[network]) {\n return this.config.rpcUrls[network];\n }\n // Check defaults\n if (DEFAULT_RPC_URLS[network]) {\n return DEFAULT_RPC_URLS[network];\n }\n // Normalize legacy networks\n if (network === 'solana') return DEFAULT_RPC_URLS[SOLANA_MAINNET];\n if (network === 'solana-devnet') return DEFAULT_RPC_URLS[SOLANA_DEVNET];\n if (network === 'solana-testnet') return DEFAULT_RPC_URLS[SOLANA_TESTNET];\n // Default to mainnet\n return DEFAULT_RPC_URLS[SOLANA_MAINNET];\n }\n\n getAddress(wallet: unknown): string | null {\n if (!isSolanaWallet(wallet)) return null;\n return wallet.publicKey?.toBase58() ?? null;\n }\n\n isConnected(wallet: unknown): boolean {\n if (!isSolanaWallet(wallet)) return false;\n return wallet.publicKey !== null;\n }\n\n async getBalance(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<number> {\n if (!isSolanaWallet(wallet) || !wallet.publicKey) {\n return 0;\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n const connection = new Connection(url, 'confirmed');\n const userPubkey = new PublicKey(wallet.publicKey.toBase58());\n const mintPubkey = new PublicKey(accept.asset);\n\n try {\n // Determine token program\n const mintInfo = await connection.getAccountInfo(mintPubkey, 'confirmed');\n const programId =\n mintInfo?.owner.toBase58() === TOKEN_2022_PROGRAM_ID.toBase58()\n ? TOKEN_2022_PROGRAM_ID\n : TOKEN_PROGRAM_ID;\n\n const ata = await getAssociatedTokenAddress(\n mintPubkey,\n userPubkey,\n false,\n programId\n );\n\n const account = await getAccount(connection, ata, undefined, programId);\n const decimals = accept.extra?.decimals ?? 6;\n return Number(account.amount) / Math.pow(10, decimals);\n } catch (err) {\n // Token account doesn't exist = 0 balance (expected for new wallets)\n if (err && typeof err === 'object' && 'name' in err &&\n (err.name === 'TokenAccountNotFoundError' || err.name === 'TokenInvalidAccountOwnerError')) {\n return 0;\n }\n // RPC errors, network failures — throw so caller can distinguish from zero balance\n throw err;\n }\n }\n\n async buildTransaction(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<SignedTransaction> {\n if (!isSolanaWallet(wallet)) {\n throw new Error('Invalid Solana wallet');\n }\n if (!wallet.publicKey) {\n throw new Error('Wallet not connected');\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n const connection = new Connection(url, 'confirmed');\n const userPubkey = new PublicKey(wallet.publicKey.toBase58());\n\n // Extract required fields — amount is the v2 spec field, maxAmountRequired is v1 fallback\n const { payTo, asset, extra } = accept;\n const amount = accept.amount ?? accept.maxAmountRequired;\n if (!amount) {\n throw new Error('Missing amount in payment requirements');\n }\n\n if (!extra?.feePayer) {\n throw new Error('Missing feePayer in payment requirements');\n }\n // Note: decimals is optional - we fetch from mint on-chain if not provided\n\n const feePayerPubkey = new PublicKey(extra.feePayer);\n const mintPubkey = new PublicKey(asset);\n const destinationPubkey = new PublicKey(payTo);\n\n this.log('Building transaction:', {\n from: userPubkey.toBase58(),\n to: payTo,\n amount,\n asset,\n feePayer: extra.feePayer,\n });\n\n // Build instructions\n const instructions: TransactionInstruction[] = [];\n\n // 1. ComputeBudget: Set compute unit limit\n instructions.push(\n ComputeBudgetProgram.setComputeUnitLimit({\n units: DEFAULT_COMPUTE_UNIT_LIMIT,\n })\n );\n\n // 2. ComputeBudget: Set compute unit price\n instructions.push(\n ComputeBudgetProgram.setComputeUnitPrice({\n microLamports: DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS,\n })\n );\n\n // 3. Determine token program\n const mintInfo = await connection.getAccountInfo(mintPubkey, 'confirmed');\n if (!mintInfo) {\n throw new Error(`Token mint ${asset} not found`);\n }\n\n const programId =\n mintInfo.owner.toBase58() === TOKEN_2022_PROGRAM_ID.toBase58()\n ? TOKEN_2022_PROGRAM_ID\n : TOKEN_PROGRAM_ID;\n\n // Fetch mint to get decimals (required for TransferChecked)\n const mint = await getMint(connection, mintPubkey, undefined, programId);\n if (typeof extra?.decimals === 'number' && mint.decimals !== extra.decimals) {\n this.log(\n `Decimals mismatch: requirements say ${extra.decimals}, mint says ${mint.decimals}`\n );\n }\n\n // Derive Associated Token Accounts\n const sourceAta = await getAssociatedTokenAddress(\n mintPubkey,\n userPubkey,\n false,\n programId\n );\n const destinationAta = await getAssociatedTokenAddress(\n mintPubkey,\n destinationPubkey,\n false,\n programId\n );\n\n // Verify source ATA exists\n const sourceAtaInfo = await connection.getAccountInfo(sourceAta, 'confirmed');\n if (!sourceAtaInfo) {\n throw new Error(\n `No token account found for ${asset}. Please ensure you have USDC in your wallet.`\n );\n }\n\n // Verify destination ATA exists\n const destAtaInfo = await connection.getAccountInfo(destinationAta, 'confirmed');\n if (!destAtaInfo) {\n throw new Error(\n `Seller token account not found. The seller (${payTo}) must have a USDC account.`\n );\n }\n\n // 4. TransferChecked instruction\n const amountBigInt = BigInt(amount);\n instructions.push(\n createTransferCheckedInstruction(\n sourceAta,\n mintPubkey,\n destinationAta,\n userPubkey,\n amountBigInt,\n mint.decimals,\n [],\n programId\n )\n );\n\n // Get recent blockhash\n const { blockhash } = await connection.getLatestBlockhash('confirmed');\n\n // Compile to V0 message (feePayer is facilitator)\n const message = new TransactionMessage({\n payerKey: feePayerPubkey,\n recentBlockhash: blockhash,\n instructions,\n }).compileToV0Message();\n\n // Create and sign transaction\n const transaction = new VersionedTransaction(message);\n const signedTx = await wallet.signTransaction(transaction);\n\n this.log('Transaction signed successfully');\n\n return {\n serialized: Buffer.from(signedTx.serialize()).toString('base64'),\n };\n }\n}\n\n/**\n * Create a Solana adapter instance\n */\nexport function createSolanaAdapter(config?: AdapterConfig): SolanaAdapter {\n return new SolanaAdapter(config);\n}\n\n\n\n","/**\n * EVM Chain Adapter\n *\n * Implements the ChainAdapter interface for EVM networks (Base, Ethereum, Arbitrum, etc.)\n * Uses EIP-712 typed data signing for x402 v2 payments.\n */\n\nimport type { ChainAdapter, AdapterConfig, SignedTransaction } from './types';\nimport type { PaymentAccept } from '../types';\n\n/**\n * CAIP-2 network identifiers for EVM chains.\n * Mirrors dexter-facilitator/src/config/chains.ts — update both when adding chains.\n */\nexport const BASE_MAINNET = 'eip155:8453';\nexport const BASE_SEPOLIA = 'eip155:84532';\nexport const ARBITRUM_ONE = 'eip155:42161';\nexport const POLYGON = 'eip155:137';\nexport const OPTIMISM = 'eip155:10';\nexport const AVALANCHE = 'eip155:43114';\nexport const SKALE_BASE = 'eip155:1187947933';\nexport const SKALE_BASE_SEPOLIA = 'eip155:324705682';\n\n/** @deprecated Not supported by the Dexter facilitator. Use BASE_MAINNET for EVM payments. */\nexport const ETHEREUM_MAINNET = 'eip155:1';\n\n/**\n * Chain IDs by CAIP-2 network\n */\nconst CHAIN_IDS: Record<string, number> = {\n [BASE_MAINNET]: 8453,\n [BASE_SEPOLIA]: 84532,\n [ARBITRUM_ONE]: 42161,\n [POLYGON]: 137,\n [OPTIMISM]: 10,\n [AVALANCHE]: 43114,\n [SKALE_BASE]: 1187947933,\n [SKALE_BASE_SEPOLIA]: 324705682,\n [ETHEREUM_MAINNET]: 1,\n};\n\n/**\n * Default RPC URLs.\n * Base mainnet uses Dexter's RPC proxy for reliability and zero-config setup.\n * Source of truth: dexter-facilitator/src/config/chains.ts\n */\nconst DEFAULT_RPC_URLS: Record<string, string> = {\n [BASE_MAINNET]: 'https://api.dexter.cash/api/base/rpc',\n [BASE_SEPOLIA]: 'https://sepolia.base.org',\n [ARBITRUM_ONE]: 'https://arb1.arbitrum.io/rpc',\n [POLYGON]: 'https://polygon-rpc.com',\n [OPTIMISM]: 'https://mainnet.optimism.io',\n [AVALANCHE]: 'https://api.avax.network/ext/bc/C/rpc',\n [SKALE_BASE]: 'https://skale-base.skalenodes.com/v1/base',\n [SKALE_BASE_SEPOLIA]: 'https://base-sepolia-testnet.skalenodes.com/v1/jubilant-horrible-ancha',\n [ETHEREUM_MAINNET]: 'https://eth.llamarpc.com',\n};\n\n/**\n * USDC contract addresses by chain.\n * Source of truth: dexter-facilitator/src/config/chains.ts\n */\nexport const USDC_ADDRESSES: Record<string, string> = {\n [BASE_MAINNET]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n [BASE_SEPOLIA]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n [ARBITRUM_ONE]: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',\n [POLYGON]: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n [OPTIMISM]: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85',\n [AVALANCHE]: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',\n [SKALE_BASE]: '0x85889c8c714505E0c94b30fcfcF64fE3Ac8FCb20',\n [SKALE_BASE_SEPOLIA]: '0x2e08028E3C4c2356572E096d8EF835cD5C6030bD',\n [ETHEREUM_MAINNET]: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n};\n\n/**\n * EVM wallet interface (compatible with wagmi, ethers, viem)\n */\nexport interface EvmWallet {\n /** Wallet address */\n address: string;\n /** Chain ID currently connected to */\n chainId?: number;\n /**\n * Sign typed data (EIP-712)\n * This is the primary signing method for x402 EVM payments\n */\n signTypedData?(params: {\n domain: Record<string, unknown>;\n types: Record<string, unknown[]>;\n primaryType: string;\n message: Record<string, unknown>;\n }): Promise<string>;\n /**\n * Alternative: Send transaction directly\n * Used if signTypedData is not available\n */\n sendTransaction?(params: {\n to: string;\n data: string;\n value?: bigint;\n }): Promise<string>;\n}\n\n/**\n * Check if an object is a valid EVM wallet\n */\nexport function isEvmWallet(wallet: unknown): wallet is EvmWallet {\n if (!wallet || typeof wallet !== 'object') return false;\n const w = wallet as Record<string, unknown>;\n return (\n 'address' in w &&\n typeof w.address === 'string' &&\n w.address.startsWith('0x')\n );\n}\n\n// ERC20 balanceOf function selector: 0x70a08231\n\n/**\n * EVM Chain Adapter\n */\nexport class EvmAdapter implements ChainAdapter {\n readonly name = 'EVM';\n readonly networks = [BASE_MAINNET, BASE_SEPOLIA, ETHEREUM_MAINNET, ARBITRUM_ONE];\n\n private config: AdapterConfig;\n private log: (...args: unknown[]) => void;\n\n constructor(config: AdapterConfig = {}) {\n this.config = config;\n this.log = config.verbose\n ? console.log.bind(console, '[x402:evm]')\n : () => {};\n }\n\n canHandle(network: string): boolean {\n // Handle exact CAIP-2\n if (this.networks.includes(network)) return true;\n // Legacy format\n if (network === 'base') return true;\n if (network === 'ethereum') return true;\n if (network === 'arbitrum') return true;\n // Check if it starts with 'eip155:'\n if (network.startsWith('eip155:')) return true;\n return false;\n }\n\n getDefaultRpcUrl(network: string): string {\n if (this.config.rpcUrls?.[network]) {\n return this.config.rpcUrls[network];\n }\n if (DEFAULT_RPC_URLS[network]) {\n return DEFAULT_RPC_URLS[network];\n }\n // Normalize legacy\n if (network === 'base') return DEFAULT_RPC_URLS[BASE_MAINNET];\n if (network === 'ethereum') return DEFAULT_RPC_URLS[ETHEREUM_MAINNET];\n if (network === 'arbitrum') return DEFAULT_RPC_URLS[ARBITRUM_ONE];\n return DEFAULT_RPC_URLS[BASE_MAINNET];\n }\n\n getAddress(wallet: unknown): string | null {\n if (!isEvmWallet(wallet)) return null;\n return wallet.address;\n }\n\n isConnected(wallet: unknown): boolean {\n if (!isEvmWallet(wallet)) return false;\n return !!wallet.address;\n }\n\n private getChainId(network: string): number {\n if (CHAIN_IDS[network]) return CHAIN_IDS[network];\n // Try to extract from CAIP-2\n if (network.startsWith('eip155:')) {\n const chainIdStr = network.split(':')[1];\n return parseInt(chainIdStr, 10);\n }\n // Defaults\n if (network === 'base') return 8453;\n if (network === 'ethereum') return 1;\n if (network === 'arbitrum') return 42161;\n return 8453; // Default to Base\n }\n\n async getBalance(\n accept: PaymentAccept,\n wallet: unknown,\n rpcUrl?: string\n ): Promise<number> {\n if (!isEvmWallet(wallet) || !wallet.address) {\n return 0;\n }\n\n const url = rpcUrl || this.getDefaultRpcUrl(accept.network);\n\n try {\n // Use eth_call to check ERC20 balance\n const data = this.encodeBalanceOf(wallet.address);\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'eth_call',\n params: [\n {\n to: accept.asset,\n data,\n },\n 'latest',\n ],\n }),\n });\n\n if (!response.ok) {\n throw new Error(`RPC request failed: ${response.status}`);\n }\n\n const result = (await response.json()) as { error?: unknown; result?: string };\n if (result.error) {\n throw new Error(`RPC error: ${JSON.stringify(result.error)}`);\n }\n if (!result.result || result.result === '0x') {\n return 0;\n }\n\n const balance = BigInt(result.result);\n const decimals = accept.extra?.decimals ?? 6;\n return Number(balance) / Math.pow(10, decimals);\n } catch (err) {\n // Re-throw RPC/network errors so caller can distinguish from zero balance\n throw err;\n }\n }\n\n private encodeBalanceOf(address: string): string {\n // Function selector for balanceOf(address)\n const selector = '0x70a08231';\n // Pad address to 32 bytes\n const paddedAddress = address.slice(2).toLowerCase().padStart(64, '0');\n return selector + paddedAddress;\n }\n\n async buildTransaction(\n accept: PaymentAccept,\n wallet: unknown,\n _rpcUrl?: string\n ): Promise<SignedTransaction> {\n if (!isEvmWallet(wallet)) {\n throw new Error('Invalid EVM wallet');\n }\n if (!wallet.address) {\n throw new Error('Wallet not connected');\n }\n\n const { payTo, asset, extra } = accept;\n // amount is the v2 spec field, maxAmountRequired is v1 fallback\n const amount = accept.amount ?? accept.maxAmountRequired;\n if (!amount) {\n throw new Error('Missing amount in payment requirements');\n }\n\n this.log('Building EVM transaction:', {\n from: wallet.address,\n to: payTo,\n amount,\n asset,\n network: accept.network,\n });\n\n // For x402 v2 EVM payments, we use EIP-712 typed data signing\n // The facilitator will execute the transfer on behalf of the user\n\n const chainId = this.getChainId(accept.network);\n\n // Build the EIP-712 typed data\n // This matches what Dexter's facilitator expects\n const domain = {\n name: extra?.name ?? 'USD Coin',\n version: extra?.version ?? '2',\n chainId: BigInt(chainId),\n verifyingContract: asset as `0x${string}`,\n };\n\n const types = {\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 };\n\n // Generate a cryptographically secure random nonce (32 bytes hex)\n const nonceBytes = new Uint8Array(32);\n (globalThis.crypto ?? (await import('crypto')).webcrypto).getRandomValues(nonceBytes);\n const nonce = ('0x' + [...nonceBytes].map(b => b.toString(16).padStart(2, '0')).join('')) as `0x${string}`;\n\n const now = Math.floor(Date.now() / 1000);\n \n // Authorization object - values as strings for JSON, BigInts for signing\n const authorization = {\n from: wallet.address,\n to: payTo,\n value: amount, // string\n validAfter: String(now - 600), // 10 minutes before (matching upstream)\n validBefore: String(now + (accept.maxTimeoutSeconds || 60)),\n nonce,\n };\n\n // Message for signing uses BigInt values\n const message = {\n from: wallet.address,\n to: payTo,\n value: BigInt(amount),\n validAfter: BigInt(now - 600),\n validBefore: BigInt(now + (accept.maxTimeoutSeconds || 60)),\n nonce,\n };\n\n if (!wallet.signTypedData) {\n throw new Error('Wallet does not support signTypedData (EIP-712)');\n }\n\n const signature = await wallet.signTypedData({\n domain: domain as Record<string, unknown>,\n types: types as Record<string, unknown[]>,\n primaryType: 'TransferWithAuthorization',\n message: message as Record<string, unknown>,\n });\n\n this.log('EIP-712 signature obtained');\n\n // Payload structure matches upstream @x402/evm exactly\n const payload = {\n authorization,\n signature,\n };\n\n return {\n serialized: JSON.stringify(payload),\n signature,\n };\n }\n}\n\n/**\n * Create an EVM adapter instance\n */\nexport function createEvmAdapter(config?: AdapterConfig): EvmAdapter {\n return new EvmAdapter(config);\n}\n\n","/**\n * Chain Adapters\n *\n * x402 v2 is designed to be chain-agnostic. Each adapter handles\n * the specifics of transaction building and signing for its chain.\n *\n * @example\n * ```typescript\n * import { createSolanaAdapter, createEvmAdapter } from '@dexterai/x402/adapters';\n *\n * const adapters = [\n * createSolanaAdapter(),\n * createEvmAdapter(),\n * ];\n *\n * // Find adapter for a network\n * const adapter = adapters.find(a => a.canHandle('eip155:8453'));\n * ```\n */\n\nimport { createSolanaAdapter as _createSolanaAdapter } from './solana';\nimport { createEvmAdapter as _createEvmAdapter } from './evm';\nimport { USDC_ADDRESSES as _USDC_ADDRESSES } from './evm';\n\n// Types\nexport type {\n ChainAdapter,\n AdapterConfig,\n SignedTransaction,\n GenericWallet,\n WalletSet,\n BalanceInfo,\n} from './types';\n\n// Solana\nexport {\n SolanaAdapter,\n createSolanaAdapter,\n isSolanaWallet,\n SOLANA_MAINNET,\n SOLANA_DEVNET,\n SOLANA_TESTNET,\n} from './solana';\nexport type { SolanaWallet } from './solana';\n\n// EVM\nexport {\n EvmAdapter,\n createEvmAdapter,\n isEvmWallet,\n BASE_MAINNET,\n BASE_SEPOLIA,\n ARBITRUM_ONE,\n POLYGON,\n OPTIMISM,\n AVALANCHE,\n SKALE_BASE,\n SKALE_BASE_SEPOLIA,\n ETHEREUM_MAINNET,\n USDC_ADDRESSES,\n} from './evm';\nexport type { EvmWallet } from './evm';\n\n/**\n * Check if an asset address is a known USDC contract (any chain).\n * Single source of truth for decimal inference in the client.\n */\nexport function isKnownUSDC(asset: string): boolean {\n // Solana mints\n if (asset === 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v') return true; // mainnet\n if (asset === '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU') return true; // devnet\n // All EVM USDC addresses (case-insensitive for EVM)\n const lc = asset.toLowerCase();\n for (const addr of Object.values(_USDC_ADDRESSES)) {\n if (addr.toLowerCase() === lc) return true;\n }\n return false;\n}\n\n/**\n * Create all default adapters\n */\nexport function createDefaultAdapters(verbose = false) {\n return [\n _createSolanaAdapter({ verbose }),\n _createEvmAdapter({ verbose }),\n ];\n}\n\n/**\n * Find adapter that can handle a network\n */\nexport function findAdapter(\n adapters: import('./types').ChainAdapter[],\n network: string\n): import('./types').ChainAdapter | undefined {\n return adapters.find(adapter => adapter.canHandle(network));\n}\n\n\n\n"],"mappings":";AAOA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAOA,IAAM,iBAAiB;AACvB,IAAM,gBAAgB;AACtB,IAAM,iBAAiB;AAM9B,IAAM,mBAA2C;AAAA,EAC/C,CAAC,cAAc,GAAG;AAAA,EAClB,CAAC,aAAa,GAAG;AAAA,EACjB,CAAC,cAAc,GAAG;AACpB;AAKA,IAAM,6BAA6B;AACnC,IAAM,2CAA2C;AAa1C,SAAS,eAAe,QAAyC;AACtE,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAClD,QAAM,IAAI;AACV,SACE,eAAe,KACf,qBAAqB,KACrB,OAAO,EAAE,oBAAoB;AAEjC;AAKO,IAAM,gBAAN,MAA4C;AAAA,EACxC,OAAO;AAAA,EACP,WAAW,CAAC,gBAAgB,eAAe,cAAc;AAAA,EAE1D;AAAA,EACA;AAAA,EAER,YAAY,SAAwB,CAAC,GAAG;AACtC,SAAK,SAAS;AACd,SAAK,MAAM,OAAO,UACd,QAAQ,IAAI,KAAK,SAAS,eAAe,IACzC,MAAM;AAAA,IAAC;AAAA,EACb;AAAA,EAEA,UAAU,SAA0B;AAElC,QAAI,KAAK,SAAS,SAAS,OAAO,EAAG,QAAO;AAE5C,QAAI,YAAY,SAAU,QAAO;AACjC,QAAI,YAAY,gBAAiB,QAAO;AACxC,QAAI,YAAY,iBAAkB,QAAO;AAEzC,QAAI,QAAQ,WAAW,SAAS,EAAG,QAAO;AAC1C,WAAO;AAAA,EACT;AAAA,EAEA,iBAAiB,SAAyB;AAExC,QAAI,KAAK,OAAO,UAAU,OAAO,GAAG;AAClC,aAAO,KAAK,OAAO,QAAQ,OAAO;AAAA,IACpC;AAEA,QAAI,iBAAiB,OAAO,GAAG;AAC7B,aAAO,iBAAiB,OAAO;AAAA,IACjC;AAEA,QAAI,YAAY,SAAU,QAAO,iBAAiB,cAAc;AAChE,QAAI,YAAY,gBAAiB,QAAO,iBAAiB,aAAa;AACtE,QAAI,YAAY,iBAAkB,QAAO,iBAAiB,cAAc;AAExE,WAAO,iBAAiB,cAAc;AAAA,EACxC;AAAA,EAEA,WAAW,QAAgC;AACzC,QAAI,CAAC,eAAe,MAAM,EAAG,QAAO;AACpC,WAAO,OAAO,WAAW,SAAS,KAAK;AAAA,EACzC;AAAA,EAEA,YAAY,QAA0B;AACpC,QAAI,CAAC,eAAe,MAAM,EAAG,QAAO;AACpC,WAAO,OAAO,cAAc;AAAA,EAC9B;AAAA,EAEA,MAAM,WACJ,QACA,QACA,QACiB;AACjB,QAAI,CAAC,eAAe,MAAM,KAAK,CAAC,OAAO,WAAW;AAChD,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,UAAU,KAAK,iBAAiB,OAAO,OAAO;AAC1D,UAAM,aAAa,IAAI,WAAW,KAAK,WAAW;AAClD,UAAM,aAAa,IAAI,UAAU,OAAO,UAAU,SAAS,CAAC;AAC5D,UAAM,aAAa,IAAI,UAAU,OAAO,KAAK;AAE7C,QAAI;AAEF,YAAM,WAAW,MAAM,WAAW,eAAe,YAAY,WAAW;AACxE,YAAM,YACJ,UAAU,MAAM,SAAS,MAAM,sBAAsB,SAAS,IAC1D,wBACA;AAEN,YAAM,MAAM,MAAM;AAAA,QAChB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,YAAM,UAAU,MAAM,WAAW,YAAY,KAAK,QAAW,SAAS;AACtE,YAAM,WAAW,OAAO,OAAO,YAAY;AAC3C,aAAO,OAAO,QAAQ,MAAM,IAAI,KAAK,IAAI,IAAI,QAAQ;AAAA,IACvD,SAAS,KAAK;AAEZ,UAAI,OAAO,OAAO,QAAQ,YAAY,UAAU,QAC3C,IAAI,SAAS,+BAA+B,IAAI,SAAS,kCAAkC;AAC9F,eAAO;AAAA,MACT;AAEA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,iBACJ,QACA,QACA,QAC4B;AAC5B,QAAI,CAAC,eAAe,MAAM,GAAG;AAC3B,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AACA,QAAI,CAAC,OAAO,WAAW;AACrB,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AAEA,UAAM,MAAM,UAAU,KAAK,iBAAiB,OAAO,OAAO;AAC1D,UAAM,aAAa,IAAI,WAAW,KAAK,WAAW;AAClD,UAAM,aAAa,IAAI,UAAU,OAAO,UAAU,SAAS,CAAC;AAG5D,UAAM,EAAE,OAAO,OAAO,MAAM,IAAI;AAChC,UAAM,SAAS,OAAO,UAAU,OAAO;AACvC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AAEA,QAAI,CAAC,OAAO,UAAU;AACpB,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AAGA,UAAM,iBAAiB,IAAI,UAAU,MAAM,QAAQ;AACnD,UAAM,aAAa,IAAI,UAAU,KAAK;AACtC,UAAM,oBAAoB,IAAI,UAAU,KAAK;AAE7C,SAAK,IAAI,yBAAyB;AAAA,MAChC,MAAM,WAAW,SAAS;AAAA,MAC1B,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,UAAU,MAAM;AAAA,IAClB,CAAC;AAGD,UAAM,eAAyC,CAAC;AAGhD,iBAAa;AAAA,MACX,qBAAqB,oBAAoB;AAAA,QACvC,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAGA,iBAAa;AAAA,MACX,qBAAqB,oBAAoB;AAAA,QACvC,eAAe;AAAA,MACjB,CAAC;AAAA,IACH;AAGA,UAAM,WAAW,MAAM,WAAW,eAAe,YAAY,WAAW;AACxE,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,cAAc,KAAK,YAAY;AAAA,IACjD;AAEA,UAAM,YACJ,SAAS,MAAM,SAAS,MAAM,sBAAsB,SAAS,IACzD,wBACA;AAGN,UAAM,OAAO,MAAM,QAAQ,YAAY,YAAY,QAAW,SAAS;AACvE,QAAI,OAAO,OAAO,aAAa,YAAY,KAAK,aAAa,MAAM,UAAU;AAC3E,WAAK;AAAA,QACH,uCAAuC,MAAM,QAAQ,eAAe,KAAK,QAAQ;AAAA,MACnF;AAAA,IACF;AAGA,UAAM,YAAY,MAAM;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,iBAAiB,MAAM;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAGA,UAAM,gBAAgB,MAAM,WAAW,eAAe,WAAW,WAAW;AAC5E,QAAI,CAAC,eAAe;AAClB,YAAM,IAAI;AAAA,QACR,8BAA8B,KAAK;AAAA,MACrC;AAAA,IACF;AAGA,UAAM,cAAc,MAAM,WAAW,eAAe,gBAAgB,WAAW;AAC/E,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI;AAAA,QACR,+CAA+C,KAAK;AAAA,MACtD;AAAA,IACF;AAGA,UAAM,eAAe,OAAO,MAAM;AAClC,iBAAa;AAAA,MACX;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,KAAK;AAAA,QACL,CAAC;AAAA,QACD;AAAA,MACF;AAAA,IACF;AAGA,UAAM,EAAE,UAAU,IAAI,MAAM,WAAW,mBAAmB,WAAW;AAGrE,UAAM,UAAU,IAAI,mBAAmB;AAAA,MACrC,UAAU;AAAA,MACV,iBAAiB;AAAA,MACjB;AAAA,IACF,CAAC,EAAE,mBAAmB;AAGtB,UAAM,cAAc,IAAI,qBAAqB,OAAO;AACpD,UAAM,WAAW,MAAM,OAAO,gBAAgB,WAAW;AAEzD,SAAK,IAAI,iCAAiC;AAE1C,WAAO;AAAA,MACL,YAAY,OAAO,KAAK,SAAS,UAAU,CAAC,EAAE,SAAS,QAAQ;AAAA,IACjE;AAAA,EACF;AACF;AAKO,SAAS,oBAAoB,QAAuC;AACzE,SAAO,IAAI,cAAc,MAAM;AACjC;;;AC/SO,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,UAAU;AAChB,IAAM,WAAW;AACjB,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,qBAAqB;AAG3B,IAAM,mBAAmB;AAKhC,IAAM,YAAoC;AAAA,EACxC,CAAC,YAAY,GAAG;AAAA,EAChB,CAAC,YAAY,GAAG;AAAA,EAChB,CAAC,YAAY,GAAG;AAAA,EAChB,CAAC,OAAO,GAAG;AAAA,EACX,CAAC,QAAQ,GAAG;AAAA,EACZ,CAAC,SAAS,GAAG;AAAA,EACb,CAAC,UAAU,GAAG;AAAA,EACd,CAAC,kBAAkB,GAAG;AAAA,EACtB,CAAC,gBAAgB,GAAG;AACtB;AAOA,IAAMA,oBAA2C;AAAA,EAC/C,CAAC,YAAY,GAAG;AAAA,EAChB,CAAC,YAAY,GAAG;AAAA,EAChB,CAAC,YAAY,GAAG;AAAA,EAChB,CAAC,OAAO,GAAG;AAAA,EACX,CAAC,QAAQ,GAAG;AAAA,EACZ,CAAC,SAAS,GAAG;AAAA,EACb,CAAC,UAAU,GAAG;AAAA,EACd,CAAC,kBAAkB,GAAG;AAAA,EACtB,CAAC,gBAAgB,GAAG;AACtB;AAMO,IAAM,iBAAyC;AAAA,EACpD,CAAC,YAAY,GAAG;AAAA,EAChB,CAAC,YAAY,GAAG;AAAA,EAChB,CAAC,YAAY,GAAG;AAAA,EAChB,CAAC,OAAO,GAAG;AAAA,EACX,CAAC,QAAQ,GAAG;AAAA,EACZ,CAAC,SAAS,GAAG;AAAA,EACb,CAAC,UAAU,GAAG;AAAA,EACd,CAAC,kBAAkB,GAAG;AAAA,EACtB,CAAC,gBAAgB,GAAG;AACtB;AAkCO,SAAS,YAAY,QAAsC;AAChE,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAClD,QAAM,IAAI;AACV,SACE,aAAa,KACb,OAAO,EAAE,YAAY,YACrB,EAAE,QAAQ,WAAW,IAAI;AAE7B;AAOO,IAAM,aAAN,MAAyC;AAAA,EACrC,OAAO;AAAA,EACP,WAAW,CAAC,cAAc,cAAc,kBAAkB,YAAY;AAAA,EAEvE;AAAA,EACA;AAAA,EAER,YAAY,SAAwB,CAAC,GAAG;AACtC,SAAK,SAAS;AACd,SAAK,MAAM,OAAO,UACd,QAAQ,IAAI,KAAK,SAAS,YAAY,IACtC,MAAM;AAAA,IAAC;AAAA,EACb;AAAA,EAEA,UAAU,SAA0B;AAElC,QAAI,KAAK,SAAS,SAAS,OAAO,EAAG,QAAO;AAE5C,QAAI,YAAY,OAAQ,QAAO;AAC/B,QAAI,YAAY,WAAY,QAAO;AACnC,QAAI,YAAY,WAAY,QAAO;AAEnC,QAAI,QAAQ,WAAW,SAAS,EAAG,QAAO;AAC1C,WAAO;AAAA,EACT;AAAA,EAEA,iBAAiB,SAAyB;AACxC,QAAI,KAAK,OAAO,UAAU,OAAO,GAAG;AAClC,aAAO,KAAK,OAAO,QAAQ,OAAO;AAAA,IACpC;AACA,QAAIA,kBAAiB,OAAO,GAAG;AAC7B,aAAOA,kBAAiB,OAAO;AAAA,IACjC;AAEA,QAAI,YAAY,OAAQ,QAAOA,kBAAiB,YAAY;AAC5D,QAAI,YAAY,WAAY,QAAOA,kBAAiB,gBAAgB;AACpE,QAAI,YAAY,WAAY,QAAOA,kBAAiB,YAAY;AAChE,WAAOA,kBAAiB,YAAY;AAAA,EACtC;AAAA,EAEA,WAAW,QAAgC;AACzC,QAAI,CAAC,YAAY,MAAM,EAAG,QAAO;AACjC,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,YAAY,QAA0B;AACpC,QAAI,CAAC,YAAY,MAAM,EAAG,QAAO;AACjC,WAAO,CAAC,CAAC,OAAO;AAAA,EAClB;AAAA,EAEQ,WAAW,SAAyB;AAC1C,QAAI,UAAU,OAAO,EAAG,QAAO,UAAU,OAAO;AAEhD,QAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,YAAM,aAAa,QAAQ,MAAM,GAAG,EAAE,CAAC;AACvC,aAAO,SAAS,YAAY,EAAE;AAAA,IAChC;AAEA,QAAI,YAAY,OAAQ,QAAO;AAC/B,QAAI,YAAY,WAAY,QAAO;AACnC,QAAI,YAAY,WAAY,QAAO;AACnC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WACJ,QACA,QACA,QACiB;AACjB,QAAI,CAAC,YAAY,MAAM,KAAK,CAAC,OAAO,SAAS;AAC3C,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,UAAU,KAAK,iBAAiB,OAAO,OAAO;AAE1D,QAAI;AAEF,YAAM,OAAO,KAAK,gBAAgB,OAAO,OAAO;AAChD,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU;AAAA,UACnB,SAAS;AAAA,UACT,IAAI;AAAA,UACJ,QAAQ;AAAA,UACR,QAAQ;AAAA,YACN;AAAA,cACE,IAAI,OAAO;AAAA,cACX;AAAA,YACF;AAAA,YACA;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,uBAAuB,SAAS,MAAM,EAAE;AAAA,MAC1D;AAEA,YAAM,SAAU,MAAM,SAAS,KAAK;AACpC,UAAI,OAAO,OAAO;AAChB,cAAM,IAAI,MAAM,cAAc,KAAK,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,MAC9D;AACA,UAAI,CAAC,OAAO,UAAU,OAAO,WAAW,MAAM;AAC5C,eAAO;AAAA,MACT;AAEA,YAAM,UAAU,OAAO,OAAO,MAAM;AACpC,YAAM,WAAW,OAAO,OAAO,YAAY;AAC3C,aAAO,OAAO,OAAO,IAAI,KAAK,IAAI,IAAI,QAAQ;AAAA,IAChD,SAAS,KAAK;AAEZ,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEQ,gBAAgB,SAAyB;AAE/C,UAAM,WAAW;AAEjB,UAAM,gBAAgB,QAAQ,MAAM,CAAC,EAAE,YAAY,EAAE,SAAS,IAAI,GAAG;AACrE,WAAO,WAAW;AAAA,EACpB;AAAA,EAEA,MAAM,iBACJ,QACA,QACA,SAC4B;AAC5B,QAAI,CAAC,YAAY,MAAM,GAAG;AACxB,YAAM,IAAI,MAAM,oBAAoB;AAAA,IACtC;AACA,QAAI,CAAC,OAAO,SAAS;AACnB,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AAEA,UAAM,EAAE,OAAO,OAAO,MAAM,IAAI;AAEhC,UAAM,SAAS,OAAO,UAAU,OAAO;AACvC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AAEA,SAAK,IAAI,6BAA6B;AAAA,MACpC,MAAM,OAAO;AAAA,MACb,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,SAAS,OAAO;AAAA,IAClB,CAAC;AAKD,UAAM,UAAU,KAAK,WAAW,OAAO,OAAO;AAI9C,UAAM,SAAS;AAAA,MACb,MAAM,OAAO,QAAQ;AAAA,MACrB,SAAS,OAAO,WAAW;AAAA,MAC3B,SAAS,OAAO,OAAO;AAAA,MACvB,mBAAmB;AAAA,IACrB;AAEA,UAAM,QAAQ;AAAA,MACZ,2BAA2B;AAAA,QACzB,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,QAChC,EAAE,MAAM,MAAM,MAAM,UAAU;AAAA,QAC9B,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,QACjC,EAAE,MAAM,cAAc,MAAM,UAAU;AAAA,QACtC,EAAE,MAAM,eAAe,MAAM,UAAU;AAAA,QACvC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,MACnC;AAAA,IACF;AAGA,UAAM,aAAa,IAAI,WAAW,EAAE;AACpC,KAAC,WAAW,WAAW,MAAM,OAAO,QAAQ,GAAG,WAAW,gBAAgB,UAAU;AACpF,UAAM,QAAS,OAAO,CAAC,GAAG,UAAU,EAAE,IAAI,OAAK,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AAEvF,UAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAGxC,UAAM,gBAAgB;AAAA,MACpB,MAAM,OAAO;AAAA,MACb,IAAI;AAAA,MACJ,OAAO;AAAA;AAAA,MACP,YAAY,OAAO,MAAM,GAAG;AAAA;AAAA,MAC5B,aAAa,OAAO,OAAO,OAAO,qBAAqB,GAAG;AAAA,MAC1D;AAAA,IACF;AAGA,UAAM,UAAU;AAAA,MACd,MAAM,OAAO;AAAA,MACb,IAAI;AAAA,MACJ,OAAO,OAAO,MAAM;AAAA,MACpB,YAAY,OAAO,MAAM,GAAG;AAAA,MAC5B,aAAa,OAAO,OAAO,OAAO,qBAAqB,GAAG;AAAA,MAC1D;AAAA,IACF;AAEA,QAAI,CAAC,OAAO,eAAe;AACzB,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AAEA,UAAM,YAAY,MAAM,OAAO,cAAc;AAAA,MAC3C;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb;AAAA,IACF,CAAC;AAED,SAAK,IAAI,4BAA4B;AAGrC,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,MACL,YAAY,KAAK,UAAU,OAAO;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AACF;AAKO,SAAS,iBAAiB,QAAoC;AACnE,SAAO,IAAI,WAAW,MAAM;AAC9B;;;AChSO,SAAS,YAAY,OAAwB;AAElD,MAAI,UAAU,+CAAgD,QAAO;AACrE,MAAI,UAAU,+CAAgD,QAAO;AAErE,QAAM,KAAK,MAAM,YAAY;AAC7B,aAAW,QAAQ,OAAO,OAAO,cAAe,GAAG;AACjD,QAAI,KAAK,YAAY,MAAM,GAAI,QAAO;AAAA,EACxC;AACA,SAAO;AACT;AAKO,SAAS,sBAAsB,UAAU,OAAO;AACrD,SAAO;AAAA,IACL,oBAAqB,EAAE,QAAQ,CAAC;AAAA,IAChC,iBAAkB,EAAE,QAAQ,CAAC;AAAA,EAC/B;AACF;AAKO,SAAS,YACd,UACA,SAC4C;AAC5C,SAAO,SAAS,KAAK,aAAW,QAAQ,UAAU,OAAO,CAAC;AAC5D;","names":["DEFAULT_RPC_URLS"]}
|
package/dist/client/index.cjs
CHANGED
|
@@ -187,6 +187,7 @@ var client_exports = {};
|
|
|
187
187
|
__export(client_exports, {
|
|
188
188
|
BASE_MAINNET: () => BASE_MAINNET,
|
|
189
189
|
DEXTER_FACILITATOR_URL: () => DEXTER_FACILITATOR_URL,
|
|
190
|
+
KEYPAIR_SYMBOL: () => KEYPAIR_SYMBOL,
|
|
190
191
|
SOLANA_MAINNET: () => SOLANA_MAINNET,
|
|
191
192
|
USDC_MINT: () => USDC_MINT,
|
|
192
193
|
X402Error: () => X402Error,
|
|
@@ -298,8 +299,11 @@ var SolanaAdapter = class {
|
|
|
298
299
|
const account = await (0, import_spl_token.getAccount)(connection, ata, void 0, programId);
|
|
299
300
|
const decimals = accept.extra?.decimals ?? 6;
|
|
300
301
|
return Number(account.amount) / Math.pow(10, decimals);
|
|
301
|
-
} catch {
|
|
302
|
-
|
|
302
|
+
} catch (err) {
|
|
303
|
+
if (err && typeof err === "object" && "name" in err && (err.name === "TokenAccountNotFoundError" || err.name === "TokenInvalidAccountOwnerError")) {
|
|
304
|
+
return 0;
|
|
305
|
+
}
|
|
306
|
+
throw err;
|
|
303
307
|
}
|
|
304
308
|
}
|
|
305
309
|
async buildTransaction(accept, wallet, rpcUrl) {
|
|
@@ -527,15 +531,21 @@ var EvmAdapter = class {
|
|
|
527
531
|
]
|
|
528
532
|
})
|
|
529
533
|
});
|
|
534
|
+
if (!response.ok) {
|
|
535
|
+
throw new Error(`RPC request failed: ${response.status}`);
|
|
536
|
+
}
|
|
530
537
|
const result = await response.json();
|
|
531
|
-
if (result.error
|
|
538
|
+
if (result.error) {
|
|
539
|
+
throw new Error(`RPC error: ${JSON.stringify(result.error)}`);
|
|
540
|
+
}
|
|
541
|
+
if (!result.result || result.result === "0x") {
|
|
532
542
|
return 0;
|
|
533
543
|
}
|
|
534
544
|
const balance = BigInt(result.result);
|
|
535
545
|
const decimals = accept.extra?.decimals ?? 6;
|
|
536
546
|
return Number(balance) / Math.pow(10, decimals);
|
|
537
|
-
} catch {
|
|
538
|
-
|
|
547
|
+
} catch (err) {
|
|
548
|
+
throw err;
|
|
539
549
|
}
|
|
540
550
|
}
|
|
541
551
|
encodeBalanceOf(address) {
|
|
@@ -651,7 +661,8 @@ function createX402Client(config) {
|
|
|
651
661
|
maxAmountAtomic,
|
|
652
662
|
fetch: customFetch = globalThis.fetch,
|
|
653
663
|
verbose = false,
|
|
654
|
-
accessPass: accessPassConfig
|
|
664
|
+
accessPass: accessPassConfig,
|
|
665
|
+
onPaymentRequired
|
|
655
666
|
} = config;
|
|
656
667
|
const log = verbose ? console.log.bind(console, "[x402]") : () => {
|
|
657
668
|
};
|
|
@@ -764,13 +775,17 @@ function createX402Client(config) {
|
|
|
764
775
|
const paymentAmount = accept.amount ?? accept.maxAmountRequired;
|
|
765
776
|
if (!paymentAmount) return null;
|
|
766
777
|
const rpcUrl = getRpcUrl(accept.network, adapter);
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
778
|
+
try {
|
|
779
|
+
const balance = await adapter.getBalance(accept, wallet, rpcUrl);
|
|
780
|
+
const requiredAmount = Number(paymentAmount) / Math.pow(10, decimals);
|
|
781
|
+
if (balance < requiredAmount) {
|
|
782
|
+
throw new X402Error(
|
|
783
|
+
"insufficient_balance",
|
|
784
|
+
`Insufficient balance for access pass. Have $${balance.toFixed(4)}, need $${requiredAmount.toFixed(4)}`
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
} catch (err) {
|
|
788
|
+
if (err instanceof X402Error) throw err;
|
|
774
789
|
}
|
|
775
790
|
const signedTx = await adapter.buildTransaction(accept, wallet, rpcUrl);
|
|
776
791
|
let payload;
|
|
@@ -783,13 +798,19 @@ function createX402Client(config) {
|
|
|
783
798
|
let resolvedResource = requirements.resource;
|
|
784
799
|
if (typeof requirements.resource === "string") {
|
|
785
800
|
try {
|
|
786
|
-
|
|
801
|
+
const resolved = new URL(requirements.resource, originalUrl);
|
|
802
|
+
if (["http:", "https:"].includes(resolved.protocol)) {
|
|
803
|
+
resolvedResource = resolved.toString();
|
|
804
|
+
}
|
|
787
805
|
} catch {
|
|
788
806
|
}
|
|
789
807
|
} else if (requirements.resource && typeof requirements.resource === "object" && "url" in requirements.resource) {
|
|
790
808
|
const rObj = requirements.resource;
|
|
791
809
|
try {
|
|
792
|
-
|
|
810
|
+
const resolved = new URL(rObj.url, originalUrl);
|
|
811
|
+
if (["http:", "https:"].includes(resolved.protocol)) {
|
|
812
|
+
resolvedResource = { ...rObj, url: resolved.toString() };
|
|
813
|
+
}
|
|
793
814
|
} catch {
|
|
794
815
|
}
|
|
795
816
|
}
|
|
@@ -917,16 +938,27 @@ function createX402Client(config) {
|
|
|
917
938
|
}
|
|
918
939
|
const rpcUrl = getRpcUrl(accept.network, adapter);
|
|
919
940
|
log("Checking balance...");
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
941
|
+
try {
|
|
942
|
+
const balance = await adapter.getBalance(accept, wallet, rpcUrl);
|
|
943
|
+
const requiredAmount = Number(paymentAmount) / Math.pow(10, decimals);
|
|
944
|
+
if (balance < requiredAmount) {
|
|
945
|
+
const network = adapter.name === "EVM" ? "Base" : "Solana";
|
|
946
|
+
throw new X402Error(
|
|
947
|
+
"insufficient_balance",
|
|
948
|
+
`Insufficient USDC balance on ${network}. Have $${balance.toFixed(4)}, need $${requiredAmount.toFixed(4)}`
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
log(`Balance OK: $${balance.toFixed(4)} >= $${requiredAmount.toFixed(4)}`);
|
|
952
|
+
} catch (err) {
|
|
953
|
+
if (err instanceof X402Error) throw err;
|
|
954
|
+
log("Balance check failed (RPC error), proceeding with transaction attempt");
|
|
955
|
+
}
|
|
956
|
+
if (onPaymentRequired) {
|
|
957
|
+
const approved = await onPaymentRequired(accept);
|
|
958
|
+
if (!approved) {
|
|
959
|
+
throw new X402Error("payment_rejected", "Payment rejected by onPaymentRequired callback");
|
|
960
|
+
}
|
|
928
961
|
}
|
|
929
|
-
log(`Balance OK: $${balance.toFixed(4)} >= $${requiredAmount.toFixed(4)}`);
|
|
930
962
|
log("Building transaction...");
|
|
931
963
|
const signedTx = await adapter.buildTransaction(accept, wallet, rpcUrl);
|
|
932
964
|
log("Transaction signed");
|
|
@@ -1012,6 +1044,7 @@ function createX402Client(config) {
|
|
|
1012
1044
|
|
|
1013
1045
|
// src/client/keypair-wallet.ts
|
|
1014
1046
|
var import_web32 = require("@solana/web3.js");
|
|
1047
|
+
var KEYPAIR_SYMBOL = /* @__PURE__ */ Symbol.for("x402:keypair");
|
|
1015
1048
|
async function createKeypairWallet(privateKey) {
|
|
1016
1049
|
let keypair;
|
|
1017
1050
|
if (typeof privateKey === "string") {
|
|
@@ -1066,7 +1099,9 @@ async function createKeypairWallet(privateKey) {
|
|
|
1066
1099
|
}
|
|
1067
1100
|
throw new Error("Unknown transaction type");
|
|
1068
1101
|
},
|
|
1102
|
+
[KEYPAIR_SYMBOL]: keypair,
|
|
1069
1103
|
keypair
|
|
1104
|
+
// deprecated — kept for backwards compat
|
|
1070
1105
|
};
|
|
1071
1106
|
}
|
|
1072
1107
|
function isKeypairWallet(wallet) {
|
|
@@ -1180,6 +1215,7 @@ async function fireImpressionBeacon(response) {
|
|
|
1180
1215
|
0 && (module.exports = {
|
|
1181
1216
|
BASE_MAINNET,
|
|
1182
1217
|
DEXTER_FACILITATOR_URL,
|
|
1218
|
+
KEYPAIR_SYMBOL,
|
|
1183
1219
|
SOLANA_MAINNET,
|
|
1184
1220
|
USDC_MINT,
|
|
1185
1221
|
X402Error,
|