@dexterai/x402 1.0.0
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/LICENSE +22 -0
- package/README.md +254 -0
- package/assets/dexter-wordmark.svg +30 -0
- package/dist/adapters/index.cjs +481 -0
- package/dist/adapters/index.cjs.map +1 -0
- package/dist/adapters/index.d.cts +15 -0
- package/dist/adapters/index.d.ts +15 -0
- package/dist/adapters/index.js +473 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/client/index.cjs +602 -0
- package/dist/client/index.cjs.map +1 -0
- package/dist/client/index.d.cts +4 -0
- package/dist/client/index.d.ts +4 -0
- package/dist/client/index.js +583 -0
- package/dist/client/index.js.map +1 -0
- package/dist/evm-B4mhmeNZ.d.cts +120 -0
- package/dist/evm-av6iEAW7.d.ts +120 -0
- package/dist/react/index.cjs +827 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +108 -0
- package/dist/react/index.d.ts +108 -0
- package/dist/react/index.js +814 -0
- package/dist/react/index.js.map +1 -0
- package/dist/server/index.cjs +295 -0
- package/dist/server/index.cjs.map +1 -0
- package/dist/server/index.d.cts +191 -0
- package/dist/server/index.d.ts +191 -0
- package/dist/server/index.js +262 -0
- package/dist/server/index.js.map +1 -0
- package/dist/types-DkTxHOns.d.cts +119 -0
- package/dist/types-DkTxHOns.d.ts +119 -0
- package/dist/types-uljmYAuY.d.ts +118 -0
- package/dist/types-vWD8uj2B.d.cts +118 -0
- package/dist/x402-client-BSWNMJbm.d.ts +84 -0
- package/dist/x402-client-DUipGiRr.d.cts +84 -0
- package/package.json +99 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/types.ts","../../src/utils.ts","../../src/server/facilitator-client.ts","../../src/server/x402-server.ts"],"sourcesContent":["/**\n * x402 v2 SDK — Shared Types\n *\n * Chain-agnostic types for x402 v2 payments.\n * Works with Solana, Base, and any future x402-compatible networks.\n */\n\n// ============================================================================\n// Network Constants\n// ============================================================================\n\n/** CAIP-2 network identifier for Solana mainnet */\nexport const SOLANA_MAINNET_NETWORK = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';\n\n/** CAIP-2 network identifier for Base mainnet */\nexport const BASE_MAINNET_NETWORK = 'eip155:8453';\n\n/** Alias for Solana mainnet */\nexport const SOLANA_MAINNET = SOLANA_MAINNET_NETWORK;\n\n/** Alias for Base mainnet */\nexport const BASE_MAINNET = BASE_MAINNET_NETWORK;\n\n// ============================================================================\n// Asset Constants\n// ============================================================================\n\n/** USDC mint on Solana mainnet */\nexport const USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';\n\n/** USDC address on Base mainnet */\nexport const USDC_BASE = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';\n\n// ============================================================================\n// Facilitator Constants\n// ============================================================================\n\n/** Dexter's public x402 v2 facilitator URL */\nexport const DEXTER_FACILITATOR_URL = 'https://x402.dexter.cash';\n\n// ============================================================================\n// Payment Types\n// ============================================================================\n\n/**\n * Asset configuration for payments\n */\nexport interface AssetConfig {\n /** Token address (mint on Solana, contract on EVM) */\n address: string;\n /** Token decimals */\n decimals: number;\n /** Optional: Human-readable symbol */\n symbol?: string;\n}\n\n/**\n * Resource info included in payment requirements\n */\nexport interface ResourceInfo {\n /** Resource URL */\n url: string;\n /** Human-readable description */\n description?: string;\n /** MIME type of the resource */\n mimeType?: string;\n}\n\n/**\n * Extra fields in payment requirements\n * Chain-specific fields may vary\n */\nexport interface AcceptsExtra {\n /** Facilitator address that pays tx fees (required) */\n feePayer: string;\n /** Token decimals (required) */\n decimals: number;\n /** EIP-712: Token name (EVM only) */\n name?: string;\n /** EIP-712: Token version (EVM only) */\n version?: string;\n /** Additional chain-specific fields */\n [key: string]: unknown;\n}\n\n/**\n * A single payment option in the accepts array\n */\nexport interface PaymentAccept {\n /** Payment scheme (always 'exact' for x402 v2) */\n scheme: 'exact';\n /** CAIP-2 network identifier */\n network: string;\n /** Payment amount in atomic units (as string to avoid precision loss) */\n amount: string;\n /** Token address */\n asset: string;\n /** Seller's address to receive payment */\n payTo: string;\n /** Maximum seconds until payment expires */\n maxTimeoutSeconds: number;\n /** Chain-specific extra data */\n extra: AcceptsExtra;\n}\n\n/**\n * Full PaymentRequired structure (sent in PAYMENT-REQUIRED header)\n */\nexport interface PaymentRequired {\n /** x402 version (always 2) */\n x402Version: 2;\n /** Resource being accessed */\n resource: ResourceInfo;\n /** Available payment options */\n accepts: PaymentAccept[];\n /** Optional error message */\n error?: string;\n}\n\n/**\n * PaymentSignature structure (sent in PAYMENT-SIGNATURE header)\n */\nexport interface PaymentSignature {\n /** x402 version (always 2) */\n x402Version: 2;\n /** Resource being accessed */\n resource: ResourceInfo;\n /** The payment option that was accepted */\n accepted: PaymentAccept;\n /** The signed payment */\n payload: {\n /** Signed transaction (base64 for Solana, JSON for EVM) */\n transaction: string;\n };\n}\n\n// ============================================================================\n// Facilitator Response Types\n// ============================================================================\n\n/**\n * Response from /verify endpoint\n */\nexport interface VerifyResponse {\n /** Whether the payment is valid */\n isValid: boolean;\n /** Reason for invalidity (if invalid) */\n invalidReason?: string;\n /** Payer address */\n payer?: string;\n}\n\n/**\n * Response from /settle endpoint\n */\nexport interface SettleResponse {\n /** Whether settlement succeeded */\n success: boolean;\n /** Transaction signature/hash */\n transaction?: string;\n /** Network the payment was made on */\n network: string;\n /** Error reason (if failed) */\n errorReason?: string;\n /** Error code (if failed) */\n errorCode?: string;\n /** Payer address */\n payer?: string;\n}\n\n// ============================================================================\n// Error Types\n// ============================================================================\n\n/**\n * SDK error codes\n */\nexport type X402ErrorCode =\n // Client errors\n | 'missing_payment_required_header'\n | 'invalid_payment_required'\n | 'unsupported_network'\n | 'no_matching_payment_option'\n | 'no_solana_accept' // Legacy, kept for compatibility\n | 'missing_fee_payer'\n | 'missing_decimals'\n | 'amount_exceeds_max'\n | 'wallet_missing_sign_transaction'\n | 'wallet_not_connected'\n | 'transaction_build_failed'\n | 'payment_rejected'\n // Server errors\n | 'invalid_payment_signature'\n | 'facilitator_verify_failed'\n | 'facilitator_settle_failed'\n | 'facilitator_request_failed'\n | 'no_matching_requirement';\n\n/**\n * Custom error class for x402 operations\n */\nexport class X402Error extends Error {\n /** Error code for programmatic handling */\n code: X402ErrorCode;\n /** Additional error details */\n details?: unknown;\n\n constructor(code: X402ErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = 'X402Error';\n this.code = code;\n this.details = details;\n // Maintain proper prototype chain\n Object.setPrototypeOf(this, X402Error.prototype);\n }\n}\n","/**\n * Utility Functions\n *\n * Chain-agnostic helpers for x402 payments.\n */\n\nimport { SOLANA_MAINNET_NETWORK, BASE_MAINNET_NETWORK } from './types';\n\n// ============================================================================\n// Amount Conversion\n// ============================================================================\n\n/**\n * Convert human-readable amount to atomic units\n *\n * @param amount - Human-readable amount (e.g., 0.05 for $0.05)\n * @param decimals - Token decimals (e.g., 6 for USDC)\n * @returns Amount in atomic units as string\n *\n * @example\n * ```typescript\n * toAtomicUnits(0.05, 6) // '50000'\n * toAtomicUnits(1.50, 6) // '1500000'\n * ```\n */\nexport function toAtomicUnits(amount: number, decimals: number): string {\n const multiplier = Math.pow(10, decimals);\n return Math.floor(amount * multiplier).toString();\n}\n\n/**\n * Convert atomic units to human-readable amount\n *\n * @param atomicUnits - Amount in smallest units\n * @param decimals - Token decimals\n * @returns Human-readable amount\n *\n * @example\n * ```typescript\n * fromAtomicUnits('50000', 6) // 0.05\n * fromAtomicUnits(1500000n, 6) // 1.5\n * ```\n */\nexport function fromAtomicUnits(\n atomicUnits: string | bigint | number,\n decimals: number\n): number {\n const divisor = Math.pow(10, decimals);\n return Number(atomicUnits) / divisor;\n}\n\n// ============================================================================\n// Network Helpers\n// ============================================================================\n\n/**\n * Network type\n */\nexport type ChainFamily = 'solana' | 'evm' | 'unknown';\n\n/**\n * Get the chain family from a CAIP-2 network identifier\n *\n * @param network - CAIP-2 network identifier\n * @returns Chain family\n *\n * @example\n * ```typescript\n * getChainFamily('solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp') // 'solana'\n * getChainFamily('eip155:8453') // 'evm'\n * ```\n */\nexport function getChainFamily(network: string): ChainFamily {\n if (network.startsWith('solana:') || network === 'solana') {\n return 'solana';\n }\n if (network.startsWith('eip155:') || ['base', 'ethereum', 'arbitrum'].includes(network)) {\n return 'evm';\n }\n return 'unknown';\n}\n\n/**\n * Get default RPC URL for a network\n *\n * @param network - CAIP-2 network identifier\n * @returns Default RPC URL\n */\nexport function getDefaultRpcUrl(network: string): string {\n const family = getChainFamily(network);\n\n if (family === 'solana') {\n if (network.includes('devnet') || network === 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1') {\n return 'https://api.devnet.solana.com';\n }\n if (network.includes('testnet') || network === 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z') {\n return 'https://api.testnet.solana.com';\n }\n return 'https://api.mainnet-beta.solana.com';\n }\n\n if (family === 'evm') {\n // Extract chain ID from CAIP-2\n if (network.startsWith('eip155:')) {\n const chainId = network.split(':')[1];\n switch (chainId) {\n case '8453': return 'https://mainnet.base.org';\n case '84532': return 'https://sepolia.base.org';\n case '1': return 'https://eth.llamarpc.com';\n case '42161': return 'https://arb1.arbitrum.io/rpc';\n default: return 'https://mainnet.base.org';\n }\n }\n // Legacy names\n if (network === 'base') return 'https://mainnet.base.org';\n if (network === 'ethereum') return 'https://eth.llamarpc.com';\n if (network === 'arbitrum') return 'https://arb1.arbitrum.io/rpc';\n return 'https://mainnet.base.org';\n }\n\n // Unknown - return a generic\n return 'https://api.mainnet-beta.solana.com';\n}\n\n/**\n * Get human-readable chain name\n *\n * @param network - CAIP-2 network identifier\n * @returns Human-readable name\n */\nexport function getChainName(network: string): string {\n const mapping: Record<string, string> = {\n [SOLANA_MAINNET_NETWORK]: 'Solana',\n 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1': 'Solana Devnet',\n 'solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z': 'Solana Testnet',\n 'solana': 'Solana',\n [BASE_MAINNET_NETWORK]: 'Base',\n 'eip155:84532': 'Base Sepolia',\n 'eip155:1': 'Ethereum',\n 'eip155:42161': 'Arbitrum One',\n 'base': 'Base',\n 'ethereum': 'Ethereum',\n 'arbitrum': 'Arbitrum',\n };\n return mapping[network] || network;\n}\n\n// ============================================================================\n// Transaction URL Helpers\n// ============================================================================\n\n/**\n * Get explorer URL for a transaction\n *\n * @param txSignature - Transaction signature/hash\n * @param network - CAIP-2 network identifier\n * @returns Explorer URL\n */\nexport function getExplorerUrl(txSignature: string, network: string): string {\n const family = getChainFamily(network);\n\n if (family === 'solana') {\n const isDevnet = network.includes('devnet') || network === 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1';\n if (isDevnet) {\n return `https://solscan.io/tx/${txSignature}?cluster=devnet`;\n }\n // Prefer Orb Markets for mainnet\n return `https://www.orbmarkets.io/tx/${txSignature}`;\n }\n\n if (family === 'evm') {\n // Extract chain ID\n let chainId = '8453'; // Default to Base\n if (network.startsWith('eip155:')) {\n chainId = network.split(':')[1];\n } else if (network === 'ethereum') {\n chainId = '1';\n } else if (network === 'arbitrum') {\n chainId = '42161';\n }\n\n switch (chainId) {\n case '8453': return `https://basescan.org/tx/${txSignature}`;\n case '84532': return `https://sepolia.basescan.org/tx/${txSignature}`;\n case '1': return `https://etherscan.io/tx/${txSignature}`;\n case '42161': return `https://arbiscan.io/tx/${txSignature}`;\n default: return `https://basescan.org/tx/${txSignature}`;\n }\n }\n\n return `https://solscan.io/tx/${txSignature}`;\n}\n\n// ============================================================================\n// Encoding Helpers\n// ============================================================================\n\n/**\n * Encode an object as base64 JSON\n */\nexport function encodeBase64Json(obj: unknown): string {\n return btoa(JSON.stringify(obj));\n}\n\n/**\n * Decode base64 JSON to object\n */\nexport function decodeBase64Json<T>(encoded: string): T {\n return JSON.parse(atob(encoded)) as T;\n}\n","/**\n * Facilitator Client\n *\n * Communicates with the x402 facilitator for:\n * - /supported - Get supported payment schemes and fee payer addresses\n * - /verify - Verify a payment signature before processing\n * - /settle - Submit the payment for execution\n *\n * Works with any x402 v2 facilitator (Dexter or others).\n */\n\nimport type { PaymentAccept, PaymentSignature, VerifyResponse, SettleResponse } from '../types';\nimport { DEXTER_FACILITATOR_URL } from '../types';\nimport { decodeBase64Json } from '../utils';\n\n/**\n * Supported payment kind from facilitator /supported endpoint\n */\nexport interface SupportedKind {\n x402Version: number;\n scheme: string;\n network: string;\n extra?: {\n feePayer?: string;\n decimals?: number;\n name?: string;\n version?: string;\n [key: string]: unknown;\n };\n}\n\n/**\n * Response from facilitator /supported endpoint\n */\nexport interface SupportedResponse {\n kinds: SupportedKind[];\n}\n\n/**\n * Client for communicating with an x402 v2 facilitator\n */\nexport class FacilitatorClient {\n private facilitatorUrl: string;\n private cachedSupported: SupportedResponse | null = null;\n private cacheTime: number = 0;\n private readonly CACHE_TTL_MS = 60_000; // 1 minute cache\n\n constructor(facilitatorUrl: string = DEXTER_FACILITATOR_URL) {\n this.facilitatorUrl = facilitatorUrl.replace(/\\/$/, ''); // Remove trailing slash\n }\n\n /**\n * Get supported payment kinds from the facilitator\n * Results are cached for 1 minute to reduce network calls\n */\n async getSupported(): Promise<SupportedResponse> {\n const now = Date.now();\n if (this.cachedSupported && now - this.cacheTime < this.CACHE_TTL_MS) {\n return this.cachedSupported;\n }\n\n const response = await fetch(`${this.facilitatorUrl}/supported`);\n if (!response.ok) {\n throw new Error(`Facilitator /supported returned ${response.status}`);\n }\n\n this.cachedSupported = (await response.json()) as SupportedResponse;\n this.cacheTime = now;\n return this.cachedSupported;\n }\n\n /**\n * Get the fee payer address for a specific network\n *\n * @param network - CAIP-2 network identifier\n * @returns Fee payer address\n */\n async getFeePayer(network: string): Promise<string> {\n const supported = await this.getSupported();\n\n // Find matching network support (exact match or v2)\n const kind = supported.kinds.find(\n (k) =>\n k.x402Version === 2 &&\n k.scheme === 'exact' &&\n k.network === network\n );\n\n if (!kind?.extra?.feePayer) {\n throw new Error(\n `Facilitator does not support network \"${network}\" with scheme \"exact\", or feePayer not provided`\n );\n }\n\n return kind.extra.feePayer;\n }\n\n /**\n * Get extra data for a network (feePayer, decimals, EIP-712 data, etc.)\n *\n * @param network - CAIP-2 network identifier\n * @returns Extra data from /supported\n */\n async getNetworkExtra(network: string): Promise<SupportedKind['extra']> {\n const supported = await this.getSupported();\n\n const kind = supported.kinds.find(\n (k) =>\n k.x402Version === 2 &&\n k.scheme === 'exact' &&\n k.network === network\n );\n\n return kind?.extra;\n }\n\n /**\n * Verify a payment with the facilitator\n *\n * @param paymentSignatureHeader - Base64-encoded PAYMENT-SIGNATURE header value\n * @param requirements - The payment requirements that were sent to the client\n * @returns Verification response\n */\n async verifyPayment(\n paymentSignatureHeader: string,\n requirements: PaymentAccept\n ): Promise<VerifyResponse> {\n try {\n const paymentPayload = decodeBase64Json<PaymentSignature>(paymentSignatureHeader);\n\n const verifyPayload = {\n paymentPayload,\n paymentRequirements: requirements,\n };\n\n const response = await fetch(`${this.facilitatorUrl}/verify`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(verifyPayload),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(`Facilitator /verify returned ${response.status}:`, errorText);\n return {\n isValid: false,\n invalidReason: `facilitator_error_${response.status}`,\n };\n }\n\n return (await response.json()) as VerifyResponse;\n } catch (error) {\n console.error('Payment verification failed:', error);\n return {\n isValid: false,\n invalidReason: error instanceof Error ? error.message : 'unexpected_verify_error',\n };\n }\n }\n\n /**\n * Settle a payment with the facilitator\n *\n * @param paymentSignatureHeader - Base64-encoded PAYMENT-SIGNATURE header value\n * @param requirements - The payment requirements that were sent to the client\n * @returns Settlement response with transaction signature on success\n */\n async settlePayment(\n paymentSignatureHeader: string,\n requirements: PaymentAccept\n ): Promise<SettleResponse> {\n try {\n const paymentPayload = decodeBase64Json<PaymentSignature>(paymentSignatureHeader);\n\n const settlePayload = {\n paymentPayload,\n paymentRequirements: requirements,\n };\n\n const response = await fetch(`${this.facilitatorUrl}/settle`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(settlePayload),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(`Facilitator /settle returned ${response.status}:`, errorText);\n return {\n success: false,\n network: requirements.network,\n errorReason: `facilitator_error_${response.status}`,\n };\n }\n\n const result = (await response.json()) as SettleResponse;\n return {\n ...result,\n network: requirements.network,\n };\n } catch (error) {\n console.error('Payment settlement failed:', error);\n return {\n success: false,\n network: requirements.network,\n errorReason: error instanceof Error ? error.message : 'unexpected_settle_error',\n };\n }\n }\n}\n","/**\n * x402 v2 Server\n *\n * Server-side helpers for accepting x402 payments.\n * Chain-agnostic - works with Solana, Base, and any x402-compatible network.\n *\n * @example\n * ```typescript\n * import { createX402Server } from '@dexterai/x402/server';\n *\n * const server = createX402Server({\n * payTo: 'YourAddress...',\n * network: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',\n * });\n *\n * // Handle 402 responses\n * if (!paymentSignature) {\n * const requirements = await server.buildRequirements({\n * amountAtomic: '50000',\n * resourceUrl: '/api/protected',\n * });\n * res.setHeader('PAYMENT-REQUIRED', server.encodeRequirements(requirements));\n * res.status(402).json({});\n * return;\n * }\n *\n * // Verify and settle\n * const verify = await server.verifyPayment(paymentSignature);\n * if (!verify.isValid) throw new Error(verify.invalidReason);\n *\n * const settle = await server.settlePayment(paymentSignature);\n * if (!settle.success) throw new Error(settle.errorReason);\n *\n * // Payment successful!\n * res.json({ transaction: settle.transaction });\n * ```\n */\n\nimport type {\n PaymentRequired,\n PaymentAccept,\n ResourceInfo,\n AcceptsExtra,\n VerifyResponse,\n SettleResponse,\n} from '../types';\nimport {\n SOLANA_MAINNET_NETWORK,\n USDC_MINT,\n DEXTER_FACILITATOR_URL,\n} from '../types';\nimport { FacilitatorClient, type SupportedKind } from './facilitator-client';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Asset configuration\n */\nexport interface AssetConfig {\n /** Token address (mint on Solana, contract on EVM) */\n address: string;\n /** Token decimals */\n decimals: number;\n}\n\n/**\n * Server configuration\n */\nexport interface X402ServerConfig {\n /** Address to receive payments */\n payTo: string;\n /** Facilitator URL (defaults to Dexter) */\n facilitatorUrl?: string;\n /** CAIP-2 network identifier */\n network?: string;\n /** Asset configuration (defaults to USDC) */\n asset?: AssetConfig;\n /** Default payment timeout in seconds */\n defaultTimeoutSeconds?: number;\n}\n\n/**\n * Options for building payment requirements\n */\nexport interface BuildRequirementsOptions {\n /** Amount in atomic units (e.g., '50000' for 0.05 USDC) */\n amountAtomic: string;\n /** Full URL of the resource */\n resourceUrl: string;\n /** Human-readable description */\n description?: string;\n /** MIME type of the response */\n mimeType?: string;\n /** Override timeout for this request */\n timeoutSeconds?: number;\n}\n\n/**\n * x402 Server interface\n */\nexport interface X402Server {\n /** Build payment requirements (fetches feePayer from facilitator) */\n buildRequirements(options: BuildRequirementsOptions): Promise<PaymentRequired>;\n\n /** Encode requirements for PAYMENT-REQUIRED header */\n encodeRequirements(requirements: PaymentRequired): string;\n\n /** Create complete 402 response object */\n create402Response(requirements: PaymentRequired): {\n status: 402;\n headers: { 'PAYMENT-REQUIRED': string };\n body: Record<string, unknown>;\n };\n\n /** Verify payment with facilitator */\n verifyPayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<VerifyResponse>;\n\n /** Settle payment via facilitator */\n settlePayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<SettleResponse>;\n\n /** Get PaymentAccept for verify/settle */\n getPaymentAccept(options: BuildRequirementsOptions): Promise<PaymentAccept>;\n\n /** Get network this server is configured for */\n readonly network: string;\n\n /** Get facilitator client for advanced usage */\n readonly facilitator: FacilitatorClient;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Create an x402 server for accepting payments\n */\nexport function createX402Server(config: X402ServerConfig): X402Server {\n const {\n payTo,\n facilitatorUrl = DEXTER_FACILITATOR_URL,\n network = SOLANA_MAINNET_NETWORK,\n asset = { address: USDC_MINT, decimals: 6 },\n defaultTimeoutSeconds = 60,\n } = config;\n\n const facilitator = new FacilitatorClient(facilitatorUrl);\n\n // Cache for network extra data\n let cachedExtra: SupportedKind['extra'] | null = null;\n\n /**\n * Get extra data from facilitator (cached)\n */\n async function getNetworkExtra(): Promise<AcceptsExtra> {\n if (!cachedExtra) {\n cachedExtra = await facilitator.getNetworkExtra(network);\n }\n\n if (!cachedExtra?.feePayer) {\n throw new Error(`Facilitator does not provide feePayer for network \"${network}\"`);\n }\n\n return {\n feePayer: cachedExtra.feePayer,\n decimals: cachedExtra.decimals ?? asset.decimals,\n // Include any additional EIP-712 data for EVM chains\n name: cachedExtra.name,\n version: cachedExtra.version,\n };\n }\n\n /**\n * Build a PaymentAccept structure\n */\n async function getPaymentAccept(options: BuildRequirementsOptions): Promise<PaymentAccept> {\n const {\n amountAtomic,\n timeoutSeconds = defaultTimeoutSeconds,\n } = options;\n\n const extra = await getNetworkExtra();\n\n return {\n scheme: 'exact',\n network,\n amount: amountAtomic,\n asset: asset.address,\n payTo,\n maxTimeoutSeconds: timeoutSeconds,\n extra,\n };\n }\n\n /**\n * Build payment requirements for a 402 response\n */\n async function buildRequirements(options: BuildRequirementsOptions): Promise<PaymentRequired> {\n const {\n resourceUrl,\n description,\n mimeType = 'application/json',\n } = options;\n\n const resource: ResourceInfo = {\n url: resourceUrl,\n description,\n mimeType,\n };\n\n const accept = await getPaymentAccept(options);\n\n return {\n x402Version: 2,\n resource,\n accepts: [accept],\n error: 'Payment required',\n };\n }\n\n /**\n * Encode requirements for PAYMENT-REQUIRED header\n */\n function encodeRequirements(requirements: PaymentRequired): string {\n return btoa(JSON.stringify(requirements));\n }\n\n /**\n * Create complete 402 response object\n */\n function create402Response(requirements: PaymentRequired) {\n return {\n status: 402 as const,\n headers: {\n 'PAYMENT-REQUIRED': encodeRequirements(requirements),\n },\n body: {},\n };\n }\n\n /**\n * Verify payment with facilitator\n */\n async function verifyPayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<VerifyResponse> {\n // If requirements not provided, build default\n const req = requirements || await getPaymentAccept({\n amountAtomic: '0',\n resourceUrl: '',\n });\n\n return facilitator.verifyPayment(paymentSignatureHeader, req);\n }\n\n /**\n * Settle payment via facilitator\n */\n async function settlePayment(\n paymentSignatureHeader: string,\n requirements?: PaymentAccept\n ): Promise<SettleResponse> {\n const req = requirements || await getPaymentAccept({\n amountAtomic: '0',\n resourceUrl: '',\n });\n\n return facilitator.settlePayment(paymentSignatureHeader, req);\n }\n\n return {\n buildRequirements,\n encodeRequirements,\n create402Response,\n verifyPayment,\n settlePayment,\n getPaymentAccept,\n network,\n facilitator,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 v2 SDK — Shared Types
|
|
3
|
+
*
|
|
4
|
+
* Chain-agnostic types for x402 v2 payments.
|
|
5
|
+
* Works with Solana, Base, and any future x402-compatible networks.
|
|
6
|
+
*/
|
|
7
|
+
/** CAIP-2 network identifier for Solana mainnet */
|
|
8
|
+
declare const SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
|
|
9
|
+
/** CAIP-2 network identifier for Base mainnet */
|
|
10
|
+
declare const BASE_MAINNET_NETWORK = "eip155:8453";
|
|
11
|
+
/** USDC mint on Solana mainnet */
|
|
12
|
+
declare const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
13
|
+
/** USDC address on Base mainnet */
|
|
14
|
+
declare const USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
15
|
+
/** Dexter's public x402 v2 facilitator URL */
|
|
16
|
+
declare const DEXTER_FACILITATOR_URL = "https://x402.dexter.cash";
|
|
17
|
+
/**
|
|
18
|
+
* Resource info included in payment requirements
|
|
19
|
+
*/
|
|
20
|
+
interface ResourceInfo {
|
|
21
|
+
/** Resource URL */
|
|
22
|
+
url: string;
|
|
23
|
+
/** Human-readable description */
|
|
24
|
+
description?: string;
|
|
25
|
+
/** MIME type of the resource */
|
|
26
|
+
mimeType?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Extra fields in payment requirements
|
|
30
|
+
* Chain-specific fields may vary
|
|
31
|
+
*/
|
|
32
|
+
interface AcceptsExtra {
|
|
33
|
+
/** Facilitator address that pays tx fees (required) */
|
|
34
|
+
feePayer: string;
|
|
35
|
+
/** Token decimals (required) */
|
|
36
|
+
decimals: number;
|
|
37
|
+
/** EIP-712: Token name (EVM only) */
|
|
38
|
+
name?: string;
|
|
39
|
+
/** EIP-712: Token version (EVM only) */
|
|
40
|
+
version?: string;
|
|
41
|
+
/** Additional chain-specific fields */
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A single payment option in the accepts array
|
|
46
|
+
*/
|
|
47
|
+
interface PaymentAccept {
|
|
48
|
+
/** Payment scheme (always 'exact' for x402 v2) */
|
|
49
|
+
scheme: 'exact';
|
|
50
|
+
/** CAIP-2 network identifier */
|
|
51
|
+
network: string;
|
|
52
|
+
/** Payment amount in atomic units (as string to avoid precision loss) */
|
|
53
|
+
amount: string;
|
|
54
|
+
/** Token address */
|
|
55
|
+
asset: string;
|
|
56
|
+
/** Seller's address to receive payment */
|
|
57
|
+
payTo: string;
|
|
58
|
+
/** Maximum seconds until payment expires */
|
|
59
|
+
maxTimeoutSeconds: number;
|
|
60
|
+
/** Chain-specific extra data */
|
|
61
|
+
extra: AcceptsExtra;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Full PaymentRequired structure (sent in PAYMENT-REQUIRED header)
|
|
65
|
+
*/
|
|
66
|
+
interface PaymentRequired {
|
|
67
|
+
/** x402 version (always 2) */
|
|
68
|
+
x402Version: 2;
|
|
69
|
+
/** Resource being accessed */
|
|
70
|
+
resource: ResourceInfo;
|
|
71
|
+
/** Available payment options */
|
|
72
|
+
accepts: PaymentAccept[];
|
|
73
|
+
/** Optional error message */
|
|
74
|
+
error?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Response from /verify endpoint
|
|
78
|
+
*/
|
|
79
|
+
interface VerifyResponse {
|
|
80
|
+
/** Whether the payment is valid */
|
|
81
|
+
isValid: boolean;
|
|
82
|
+
/** Reason for invalidity (if invalid) */
|
|
83
|
+
invalidReason?: string;
|
|
84
|
+
/** Payer address */
|
|
85
|
+
payer?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Response from /settle endpoint
|
|
89
|
+
*/
|
|
90
|
+
interface SettleResponse {
|
|
91
|
+
/** Whether settlement succeeded */
|
|
92
|
+
success: boolean;
|
|
93
|
+
/** Transaction signature/hash */
|
|
94
|
+
transaction?: string;
|
|
95
|
+
/** Network the payment was made on */
|
|
96
|
+
network: string;
|
|
97
|
+
/** Error reason (if failed) */
|
|
98
|
+
errorReason?: string;
|
|
99
|
+
/** Error code (if failed) */
|
|
100
|
+
errorCode?: string;
|
|
101
|
+
/** Payer address */
|
|
102
|
+
payer?: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* SDK error codes
|
|
106
|
+
*/
|
|
107
|
+
type X402ErrorCode = 'missing_payment_required_header' | 'invalid_payment_required' | 'unsupported_network' | 'no_matching_payment_option' | 'no_solana_accept' | 'missing_fee_payer' | 'missing_decimals' | 'amount_exceeds_max' | 'wallet_missing_sign_transaction' | 'wallet_not_connected' | 'transaction_build_failed' | 'payment_rejected' | 'invalid_payment_signature' | 'facilitator_verify_failed' | 'facilitator_settle_failed' | 'facilitator_request_failed' | 'no_matching_requirement';
|
|
108
|
+
/**
|
|
109
|
+
* Custom error class for x402 operations
|
|
110
|
+
*/
|
|
111
|
+
declare class X402Error extends Error {
|
|
112
|
+
/** Error code for programmatic handling */
|
|
113
|
+
code: X402ErrorCode;
|
|
114
|
+
/** Additional error details */
|
|
115
|
+
details?: unknown;
|
|
116
|
+
constructor(code: X402ErrorCode, message: string, details?: unknown);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export { BASE_MAINNET_NETWORK as B, DEXTER_FACILITATOR_URL as D, type PaymentAccept as P, type SettleResponse as S, USDC_MINT as U, type VerifyResponse as V, X402Error as X, type PaymentRequired as a, SOLANA_MAINNET_NETWORK as b, USDC_BASE as c };
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* x402 v2 SDK — Shared Types
|
|
3
|
+
*
|
|
4
|
+
* Chain-agnostic types for x402 v2 payments.
|
|
5
|
+
* Works with Solana, Base, and any future x402-compatible networks.
|
|
6
|
+
*/
|
|
7
|
+
/** CAIP-2 network identifier for Solana mainnet */
|
|
8
|
+
declare const SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
|
|
9
|
+
/** CAIP-2 network identifier for Base mainnet */
|
|
10
|
+
declare const BASE_MAINNET_NETWORK = "eip155:8453";
|
|
11
|
+
/** USDC mint on Solana mainnet */
|
|
12
|
+
declare const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
13
|
+
/** USDC address on Base mainnet */
|
|
14
|
+
declare const USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
15
|
+
/** Dexter's public x402 v2 facilitator URL */
|
|
16
|
+
declare const DEXTER_FACILITATOR_URL = "https://x402.dexter.cash";
|
|
17
|
+
/**
|
|
18
|
+
* Resource info included in payment requirements
|
|
19
|
+
*/
|
|
20
|
+
interface ResourceInfo {
|
|
21
|
+
/** Resource URL */
|
|
22
|
+
url: string;
|
|
23
|
+
/** Human-readable description */
|
|
24
|
+
description?: string;
|
|
25
|
+
/** MIME type of the resource */
|
|
26
|
+
mimeType?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Extra fields in payment requirements
|
|
30
|
+
* Chain-specific fields may vary
|
|
31
|
+
*/
|
|
32
|
+
interface AcceptsExtra {
|
|
33
|
+
/** Facilitator address that pays tx fees (required) */
|
|
34
|
+
feePayer: string;
|
|
35
|
+
/** Token decimals (required) */
|
|
36
|
+
decimals: number;
|
|
37
|
+
/** EIP-712: Token name (EVM only) */
|
|
38
|
+
name?: string;
|
|
39
|
+
/** EIP-712: Token version (EVM only) */
|
|
40
|
+
version?: string;
|
|
41
|
+
/** Additional chain-specific fields */
|
|
42
|
+
[key: string]: unknown;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A single payment option in the accepts array
|
|
46
|
+
*/
|
|
47
|
+
interface PaymentAccept {
|
|
48
|
+
/** Payment scheme (always 'exact' for x402 v2) */
|
|
49
|
+
scheme: 'exact';
|
|
50
|
+
/** CAIP-2 network identifier */
|
|
51
|
+
network: string;
|
|
52
|
+
/** Payment amount in atomic units (as string to avoid precision loss) */
|
|
53
|
+
amount: string;
|
|
54
|
+
/** Token address */
|
|
55
|
+
asset: string;
|
|
56
|
+
/** Seller's address to receive payment */
|
|
57
|
+
payTo: string;
|
|
58
|
+
/** Maximum seconds until payment expires */
|
|
59
|
+
maxTimeoutSeconds: number;
|
|
60
|
+
/** Chain-specific extra data */
|
|
61
|
+
extra: AcceptsExtra;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Full PaymentRequired structure (sent in PAYMENT-REQUIRED header)
|
|
65
|
+
*/
|
|
66
|
+
interface PaymentRequired {
|
|
67
|
+
/** x402 version (always 2) */
|
|
68
|
+
x402Version: 2;
|
|
69
|
+
/** Resource being accessed */
|
|
70
|
+
resource: ResourceInfo;
|
|
71
|
+
/** Available payment options */
|
|
72
|
+
accepts: PaymentAccept[];
|
|
73
|
+
/** Optional error message */
|
|
74
|
+
error?: string;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Response from /verify endpoint
|
|
78
|
+
*/
|
|
79
|
+
interface VerifyResponse {
|
|
80
|
+
/** Whether the payment is valid */
|
|
81
|
+
isValid: boolean;
|
|
82
|
+
/** Reason for invalidity (if invalid) */
|
|
83
|
+
invalidReason?: string;
|
|
84
|
+
/** Payer address */
|
|
85
|
+
payer?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Response from /settle endpoint
|
|
89
|
+
*/
|
|
90
|
+
interface SettleResponse {
|
|
91
|
+
/** Whether settlement succeeded */
|
|
92
|
+
success: boolean;
|
|
93
|
+
/** Transaction signature/hash */
|
|
94
|
+
transaction?: string;
|
|
95
|
+
/** Network the payment was made on */
|
|
96
|
+
network: string;
|
|
97
|
+
/** Error reason (if failed) */
|
|
98
|
+
errorReason?: string;
|
|
99
|
+
/** Error code (if failed) */
|
|
100
|
+
errorCode?: string;
|
|
101
|
+
/** Payer address */
|
|
102
|
+
payer?: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* SDK error codes
|
|
106
|
+
*/
|
|
107
|
+
type X402ErrorCode = 'missing_payment_required_header' | 'invalid_payment_required' | 'unsupported_network' | 'no_matching_payment_option' | 'no_solana_accept' | 'missing_fee_payer' | 'missing_decimals' | 'amount_exceeds_max' | 'wallet_missing_sign_transaction' | 'wallet_not_connected' | 'transaction_build_failed' | 'payment_rejected' | 'invalid_payment_signature' | 'facilitator_verify_failed' | 'facilitator_settle_failed' | 'facilitator_request_failed' | 'no_matching_requirement';
|
|
108
|
+
/**
|
|
109
|
+
* Custom error class for x402 operations
|
|
110
|
+
*/
|
|
111
|
+
declare class X402Error extends Error {
|
|
112
|
+
/** Error code for programmatic handling */
|
|
113
|
+
code: X402ErrorCode;
|
|
114
|
+
/** Additional error details */
|
|
115
|
+
details?: unknown;
|
|
116
|
+
constructor(code: X402ErrorCode, message: string, details?: unknown);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export { BASE_MAINNET_NETWORK as B, DEXTER_FACILITATOR_URL as D, type PaymentAccept as P, type SettleResponse as S, USDC_MINT as U, type VerifyResponse as V, X402Error as X, type PaymentRequired as a, SOLANA_MAINNET_NETWORK as b, USDC_BASE as c };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { P as PaymentAccept } from './types-DkTxHOns.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Chain Adapter Interface
|
|
5
|
+
*
|
|
6
|
+
* x402 v2 is chain-agnostic. This interface defines how each chain
|
|
7
|
+
* handles transaction building, signing, and balance queries.
|
|
8
|
+
*
|
|
9
|
+
* Implementations:
|
|
10
|
+
* - SolanaAdapter: Solana mainnet/devnet
|
|
11
|
+
* - EvmAdapter: Base, Arbitrum, Ethereum, etc.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Generic wallet interface that works across chains.
|
|
16
|
+
* Each chain adapter will cast to its specific wallet type.
|
|
17
|
+
*/
|
|
18
|
+
interface GenericWallet {
|
|
19
|
+
/** Chain-specific identifier (address or public key) */
|
|
20
|
+
address: string;
|
|
21
|
+
/** Whether the wallet is connected and ready */
|
|
22
|
+
connected: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Result of building and signing a transaction
|
|
26
|
+
*/
|
|
27
|
+
interface SignedTransaction {
|
|
28
|
+
/** Base64 or hex encoded transaction ready for payload */
|
|
29
|
+
serialized: string;
|
|
30
|
+
/** Transaction signature/hash if available before broadcast */
|
|
31
|
+
signature?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Chain adapter interface - each chain implements this
|
|
35
|
+
*/
|
|
36
|
+
interface ChainAdapter {
|
|
37
|
+
/**
|
|
38
|
+
* Human-readable chain name
|
|
39
|
+
*/
|
|
40
|
+
readonly name: string;
|
|
41
|
+
/**
|
|
42
|
+
* CAIP-2 network identifiers this adapter handles
|
|
43
|
+
* e.g., ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'] for Solana mainnet
|
|
44
|
+
* e.g., ['eip155:8453'] for Base
|
|
45
|
+
*/
|
|
46
|
+
readonly networks: string[];
|
|
47
|
+
/**
|
|
48
|
+
* Check if this adapter can handle a given network
|
|
49
|
+
* @param network - CAIP-2 network identifier
|
|
50
|
+
*/
|
|
51
|
+
canHandle(network: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Build and sign a payment transaction
|
|
54
|
+
*
|
|
55
|
+
* @param accept - The payment option from server's accepts[]
|
|
56
|
+
* @param wallet - Chain-specific wallet (will be cast internally)
|
|
57
|
+
* @param rpcUrl - Optional RPC URL override
|
|
58
|
+
* @returns Signed transaction ready for PAYMENT-SIGNATURE payload
|
|
59
|
+
*/
|
|
60
|
+
buildTransaction(accept: PaymentAccept, wallet: unknown, rpcUrl?: string): Promise<SignedTransaction>;
|
|
61
|
+
/**
|
|
62
|
+
* Get the wallet's balance for the payment asset
|
|
63
|
+
*
|
|
64
|
+
* @param accept - Payment option (contains asset info)
|
|
65
|
+
* @param wallet - Chain-specific wallet
|
|
66
|
+
* @param rpcUrl - Optional RPC URL override
|
|
67
|
+
* @returns Balance in human-readable units (e.g., 12.50 for $12.50 USDC)
|
|
68
|
+
*/
|
|
69
|
+
getBalance(accept: PaymentAccept, wallet: unknown, rpcUrl?: string): Promise<number>;
|
|
70
|
+
/**
|
|
71
|
+
* Get the wallet's address as a string
|
|
72
|
+
* @param wallet - Chain-specific wallet
|
|
73
|
+
*/
|
|
74
|
+
getAddress(wallet: unknown): string | null;
|
|
75
|
+
/**
|
|
76
|
+
* Check if wallet is connected
|
|
77
|
+
* @param wallet - Chain-specific wallet
|
|
78
|
+
*/
|
|
79
|
+
isConnected(wallet: unknown): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Get default RPC URL for a network
|
|
82
|
+
* @param network - CAIP-2 network identifier
|
|
83
|
+
*/
|
|
84
|
+
getDefaultRpcUrl(network: string): string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Configuration for creating a chain adapter
|
|
88
|
+
*/
|
|
89
|
+
interface AdapterConfig {
|
|
90
|
+
/** Custom RPC URLs by network */
|
|
91
|
+
rpcUrls?: Record<string, string>;
|
|
92
|
+
/** Enable verbose logging */
|
|
93
|
+
verbose?: boolean;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Multi-wallet container for different chains
|
|
97
|
+
*/
|
|
98
|
+
interface WalletSet {
|
|
99
|
+
/** Solana wallet (from @solana/wallet-adapter) */
|
|
100
|
+
solana?: unknown;
|
|
101
|
+
/** EVM wallet (from wagmi, ethers, or viem) */
|
|
102
|
+
evm?: unknown;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Balance info across chains
|
|
106
|
+
*/
|
|
107
|
+
interface BalanceInfo {
|
|
108
|
+
/** CAIP-2 network identifier */
|
|
109
|
+
network: string;
|
|
110
|
+
/** Human-readable chain name */
|
|
111
|
+
chainName: string;
|
|
112
|
+
/** Balance in human units */
|
|
113
|
+
balance: number;
|
|
114
|
+
/** Asset symbol (e.g., 'USDC') */
|
|
115
|
+
asset: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type { AdapterConfig as A, BalanceInfo as B, ChainAdapter as C, GenericWallet as G, SignedTransaction as S, WalletSet as W };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { P as PaymentAccept } from './types-DkTxHOns.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Chain Adapter Interface
|
|
5
|
+
*
|
|
6
|
+
* x402 v2 is chain-agnostic. This interface defines how each chain
|
|
7
|
+
* handles transaction building, signing, and balance queries.
|
|
8
|
+
*
|
|
9
|
+
* Implementations:
|
|
10
|
+
* - SolanaAdapter: Solana mainnet/devnet
|
|
11
|
+
* - EvmAdapter: Base, Arbitrum, Ethereum, etc.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Generic wallet interface that works across chains.
|
|
16
|
+
* Each chain adapter will cast to its specific wallet type.
|
|
17
|
+
*/
|
|
18
|
+
interface GenericWallet {
|
|
19
|
+
/** Chain-specific identifier (address or public key) */
|
|
20
|
+
address: string;
|
|
21
|
+
/** Whether the wallet is connected and ready */
|
|
22
|
+
connected: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Result of building and signing a transaction
|
|
26
|
+
*/
|
|
27
|
+
interface SignedTransaction {
|
|
28
|
+
/** Base64 or hex encoded transaction ready for payload */
|
|
29
|
+
serialized: string;
|
|
30
|
+
/** Transaction signature/hash if available before broadcast */
|
|
31
|
+
signature?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Chain adapter interface - each chain implements this
|
|
35
|
+
*/
|
|
36
|
+
interface ChainAdapter {
|
|
37
|
+
/**
|
|
38
|
+
* Human-readable chain name
|
|
39
|
+
*/
|
|
40
|
+
readonly name: string;
|
|
41
|
+
/**
|
|
42
|
+
* CAIP-2 network identifiers this adapter handles
|
|
43
|
+
* e.g., ['solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'] for Solana mainnet
|
|
44
|
+
* e.g., ['eip155:8453'] for Base
|
|
45
|
+
*/
|
|
46
|
+
readonly networks: string[];
|
|
47
|
+
/**
|
|
48
|
+
* Check if this adapter can handle a given network
|
|
49
|
+
* @param network - CAIP-2 network identifier
|
|
50
|
+
*/
|
|
51
|
+
canHandle(network: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Build and sign a payment transaction
|
|
54
|
+
*
|
|
55
|
+
* @param accept - The payment option from server's accepts[]
|
|
56
|
+
* @param wallet - Chain-specific wallet (will be cast internally)
|
|
57
|
+
* @param rpcUrl - Optional RPC URL override
|
|
58
|
+
* @returns Signed transaction ready for PAYMENT-SIGNATURE payload
|
|
59
|
+
*/
|
|
60
|
+
buildTransaction(accept: PaymentAccept, wallet: unknown, rpcUrl?: string): Promise<SignedTransaction>;
|
|
61
|
+
/**
|
|
62
|
+
* Get the wallet's balance for the payment asset
|
|
63
|
+
*
|
|
64
|
+
* @param accept - Payment option (contains asset info)
|
|
65
|
+
* @param wallet - Chain-specific wallet
|
|
66
|
+
* @param rpcUrl - Optional RPC URL override
|
|
67
|
+
* @returns Balance in human-readable units (e.g., 12.50 for $12.50 USDC)
|
|
68
|
+
*/
|
|
69
|
+
getBalance(accept: PaymentAccept, wallet: unknown, rpcUrl?: string): Promise<number>;
|
|
70
|
+
/**
|
|
71
|
+
* Get the wallet's address as a string
|
|
72
|
+
* @param wallet - Chain-specific wallet
|
|
73
|
+
*/
|
|
74
|
+
getAddress(wallet: unknown): string | null;
|
|
75
|
+
/**
|
|
76
|
+
* Check if wallet is connected
|
|
77
|
+
* @param wallet - Chain-specific wallet
|
|
78
|
+
*/
|
|
79
|
+
isConnected(wallet: unknown): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Get default RPC URL for a network
|
|
82
|
+
* @param network - CAIP-2 network identifier
|
|
83
|
+
*/
|
|
84
|
+
getDefaultRpcUrl(network: string): string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Configuration for creating a chain adapter
|
|
88
|
+
*/
|
|
89
|
+
interface AdapterConfig {
|
|
90
|
+
/** Custom RPC URLs by network */
|
|
91
|
+
rpcUrls?: Record<string, string>;
|
|
92
|
+
/** Enable verbose logging */
|
|
93
|
+
verbose?: boolean;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Multi-wallet container for different chains
|
|
97
|
+
*/
|
|
98
|
+
interface WalletSet {
|
|
99
|
+
/** Solana wallet (from @solana/wallet-adapter) */
|
|
100
|
+
solana?: unknown;
|
|
101
|
+
/** EVM wallet (from wagmi, ethers, or viem) */
|
|
102
|
+
evm?: unknown;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Balance info across chains
|
|
106
|
+
*/
|
|
107
|
+
interface BalanceInfo {
|
|
108
|
+
/** CAIP-2 network identifier */
|
|
109
|
+
network: string;
|
|
110
|
+
/** Human-readable chain name */
|
|
111
|
+
chainName: string;
|
|
112
|
+
/** Balance in human units */
|
|
113
|
+
balance: number;
|
|
114
|
+
/** Asset symbol (e.g., 'USDC') */
|
|
115
|
+
asset: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type { AdapterConfig as A, BalanceInfo as B, ChainAdapter as C, GenericWallet as G, SignedTransaction as S, WalletSet as W };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { C as ChainAdapter, W as WalletSet } from './types-uljmYAuY.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* x402 v2 Client
|
|
5
|
+
*
|
|
6
|
+
* Chain-agnostic client for x402 v2 payments.
|
|
7
|
+
* Automatically detects 402 responses, finds a matching payment option,
|
|
8
|
+
* builds the transaction with the appropriate chain adapter, and retries.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { createX402Client } from '@dexterai/x402/client';
|
|
13
|
+
* import { createSolanaAdapter, createEvmAdapter } from '@dexterai/x402/adapters';
|
|
14
|
+
*
|
|
15
|
+
* const client = createX402Client({
|
|
16
|
+
* adapters: [createSolanaAdapter(), createEvmAdapter()],
|
|
17
|
+
* wallets: {
|
|
18
|
+
* solana: solanaWallet,
|
|
19
|
+
* evm: evmWallet,
|
|
20
|
+
* },
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* const response = await client.fetch(url);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Client configuration
|
|
29
|
+
*/
|
|
30
|
+
interface X402ClientConfig {
|
|
31
|
+
/**
|
|
32
|
+
* Chain adapters to use for building transactions.
|
|
33
|
+
* If not provided, uses Solana and EVM adapters by default.
|
|
34
|
+
*/
|
|
35
|
+
adapters?: ChainAdapter[];
|
|
36
|
+
/**
|
|
37
|
+
* Wallets for each chain type.
|
|
38
|
+
* Can also pass a single wallet for backwards compatibility.
|
|
39
|
+
*/
|
|
40
|
+
wallets?: WalletSet;
|
|
41
|
+
/**
|
|
42
|
+
* Legacy: Single wallet (Solana).
|
|
43
|
+
* Use `wallets` for multi-chain support.
|
|
44
|
+
*/
|
|
45
|
+
wallet?: unknown;
|
|
46
|
+
/**
|
|
47
|
+
* Preferred network to use when multiple options are available.
|
|
48
|
+
* CAIP-2 format (e.g., 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', 'eip155:8453')
|
|
49
|
+
*/
|
|
50
|
+
preferredNetwork?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Custom RPC URLs by network
|
|
53
|
+
*/
|
|
54
|
+
rpcUrls?: Record<string, string>;
|
|
55
|
+
/**
|
|
56
|
+
* Maximum payment amount allowed (in atomic units).
|
|
57
|
+
* Rejects payments exceeding this amount.
|
|
58
|
+
*/
|
|
59
|
+
maxAmountAtomic?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Custom fetch implementation
|
|
62
|
+
*/
|
|
63
|
+
fetch?: typeof globalThis.fetch;
|
|
64
|
+
/**
|
|
65
|
+
* Enable verbose logging
|
|
66
|
+
*/
|
|
67
|
+
verbose?: boolean;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* x402 Client interface
|
|
71
|
+
*/
|
|
72
|
+
interface X402Client {
|
|
73
|
+
/**
|
|
74
|
+
* Fetch with automatic x402 payment handling.
|
|
75
|
+
* If the server returns 402, handles payment automatically and retries.
|
|
76
|
+
*/
|
|
77
|
+
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Create an x402 v2 client
|
|
81
|
+
*/
|
|
82
|
+
declare function createX402Client(config: X402ClientConfig): X402Client;
|
|
83
|
+
|
|
84
|
+
export { type X402ClientConfig as X, type X402Client as a, createX402Client as c };
|