@dexterai/x402 1.6.5 → 1.7.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/dist/adapters/index.d.cts +4 -4
- package/dist/adapters/index.d.ts +4 -4
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +6 -6
- package/dist/client/index.d.ts +6 -6
- package/dist/client/index.js.map +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +4 -4
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js.map +1 -1
- package/dist/server/index.cjs +124 -15
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +89 -7
- package/dist/server/index.d.ts +89 -7
- package/dist/server/index.js +123 -15
- package/dist/server/index.js.map +1 -1
- package/dist/{solana-Bve65qm4.d.ts → solana-CJdhHls8.d.ts} +2 -2
- package/dist/{solana-BYh8ehOi.d.cts → solana-CnW6P4lJ.d.cts} +2 -2
- package/dist/{types--r7urkVI.d.cts → types-BB-2vowq.d.cts} +1 -1
- package/dist/{types-CcVAaoro.d.cts → types-C6ty4U6C.d.cts} +39 -1
- package/dist/{types-CcVAaoro.d.ts → types-C6ty4U6C.d.ts} +39 -1
- package/dist/{types-BtpD4ULe.d.ts → types-ClEZ34n4.d.ts} +1 -1
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/{x402-client-BxQWcK2Z.d.ts → x402-client-B9ECWy7k.d.ts} +2 -2
- package/dist/{x402-client-Dcm2FQ9f.d.cts → x402-client-BhLOoqwa.d.cts} +2 -2
- package/package.json +10 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as AdapterConfig, C as ChainAdapter, S as SignedTransaction } from './types-
|
|
2
|
-
import { P as PaymentAccept } from './types-
|
|
1
|
+
import { A as AdapterConfig, C as ChainAdapter, S as SignedTransaction } from './types-ClEZ34n4.js';
|
|
2
|
+
import { P as PaymentAccept } from './types-C6ty4U6C.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* EVM Chain Adapter
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as AdapterConfig, C as ChainAdapter, S as SignedTransaction } from './types
|
|
2
|
-
import { P as PaymentAccept } from './types-
|
|
1
|
+
import { A as AdapterConfig, C as ChainAdapter, S as SignedTransaction } from './types-BB-2vowq.cjs';
|
|
2
|
+
import { P as PaymentAccept } from './types-C6ty4U6C.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* EVM Chain Adapter
|
|
@@ -14,6 +14,44 @@ declare const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
|
14
14
|
declare const USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
15
15
|
/** Dexter's public x402 v2 facilitator URL */
|
|
16
16
|
declare const DEXTER_FACILITATOR_URL = "https://x402.dexter.cash";
|
|
17
|
+
/**
|
|
18
|
+
* Context passed to a PayToProvider function.
|
|
19
|
+
* Contains request-scoped information for dynamic address resolution.
|
|
20
|
+
*/
|
|
21
|
+
interface PayToContext {
|
|
22
|
+
/** The PAYMENT-SIGNATURE header value (present on retry/verify, undefined on initial 402) */
|
|
23
|
+
paymentHeader?: string;
|
|
24
|
+
/** Amount in atomic units (e.g., '10000' for 0.01 USDC) */
|
|
25
|
+
amountAtomic?: string;
|
|
26
|
+
/** The resource URL being accessed */
|
|
27
|
+
resourceUrl?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Optional defaults a PayToProvider can advertise for auto-configuration.
|
|
31
|
+
* Attached as `_x402Defaults` on the provider function.
|
|
32
|
+
*/
|
|
33
|
+
interface PayToProviderDefaults {
|
|
34
|
+
/** Default CAIP-2 network (e.g., 'eip155:8453' for Base) */
|
|
35
|
+
network?: string;
|
|
36
|
+
/** Default facilitator URL */
|
|
37
|
+
facilitatorUrl?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A function that dynamically resolves a payment address.
|
|
41
|
+
* Used for providers like Stripe that generate per-request deposit addresses.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* import { stripePayTo } from '@dexterai/x402/server';
|
|
46
|
+
*
|
|
47
|
+
* const provider = stripePayTo(process.env.STRIPE_SECRET_KEY);
|
|
48
|
+
* const address = await provider({ amountAtomic: '10000' });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
type PayToProvider = ((context: PayToContext) => Promise<string>) & {
|
|
52
|
+
/** Auto-configuration defaults (set by provider factories like stripePayTo) */
|
|
53
|
+
_x402Defaults?: PayToProviderDefaults;
|
|
54
|
+
};
|
|
17
55
|
/**
|
|
18
56
|
* Resource info included in payment requirements
|
|
19
57
|
*/
|
|
@@ -182,4 +220,4 @@ declare class X402Error extends Error {
|
|
|
182
220
|
constructor(code: X402ErrorCode, message: string, details?: unknown);
|
|
183
221
|
}
|
|
184
222
|
|
|
185
|
-
export { type AccessPassClientConfig as A, 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 AccessPassTier as a, type AccessPassInfo as b, type
|
|
223
|
+
export { type AccessPassClientConfig as A, 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 AccessPassTier as a, type AccessPassInfo as b, type PayToProvider as c, type PaymentRequired as d, type PayToContext as e, type PayToProviderDefaults as f, type AccessPassClaims as g, SOLANA_MAINNET_NETWORK as h, USDC_BASE as i };
|
|
@@ -14,6 +14,44 @@ declare const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
|
14
14
|
declare const USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
15
15
|
/** Dexter's public x402 v2 facilitator URL */
|
|
16
16
|
declare const DEXTER_FACILITATOR_URL = "https://x402.dexter.cash";
|
|
17
|
+
/**
|
|
18
|
+
* Context passed to a PayToProvider function.
|
|
19
|
+
* Contains request-scoped information for dynamic address resolution.
|
|
20
|
+
*/
|
|
21
|
+
interface PayToContext {
|
|
22
|
+
/** The PAYMENT-SIGNATURE header value (present on retry/verify, undefined on initial 402) */
|
|
23
|
+
paymentHeader?: string;
|
|
24
|
+
/** Amount in atomic units (e.g., '10000' for 0.01 USDC) */
|
|
25
|
+
amountAtomic?: string;
|
|
26
|
+
/** The resource URL being accessed */
|
|
27
|
+
resourceUrl?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Optional defaults a PayToProvider can advertise for auto-configuration.
|
|
31
|
+
* Attached as `_x402Defaults` on the provider function.
|
|
32
|
+
*/
|
|
33
|
+
interface PayToProviderDefaults {
|
|
34
|
+
/** Default CAIP-2 network (e.g., 'eip155:8453' for Base) */
|
|
35
|
+
network?: string;
|
|
36
|
+
/** Default facilitator URL */
|
|
37
|
+
facilitatorUrl?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A function that dynamically resolves a payment address.
|
|
41
|
+
* Used for providers like Stripe that generate per-request deposit addresses.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* import { stripePayTo } from '@dexterai/x402/server';
|
|
46
|
+
*
|
|
47
|
+
* const provider = stripePayTo(process.env.STRIPE_SECRET_KEY);
|
|
48
|
+
* const address = await provider({ amountAtomic: '10000' });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
type PayToProvider = ((context: PayToContext) => Promise<string>) & {
|
|
52
|
+
/** Auto-configuration defaults (set by provider factories like stripePayTo) */
|
|
53
|
+
_x402Defaults?: PayToProviderDefaults;
|
|
54
|
+
};
|
|
17
55
|
/**
|
|
18
56
|
* Resource info included in payment requirements
|
|
19
57
|
*/
|
|
@@ -182,4 +220,4 @@ declare class X402Error extends Error {
|
|
|
182
220
|
constructor(code: X402ErrorCode, message: string, details?: unknown);
|
|
183
221
|
}
|
|
184
222
|
|
|
185
|
-
export { type AccessPassClientConfig as A, 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 AccessPassTier as a, type AccessPassInfo as b, type
|
|
223
|
+
export { type AccessPassClientConfig as A, 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 AccessPassTier as a, type AccessPassInfo as b, type PayToProvider as c, type PaymentRequired as d, type PayToContext as e, type PayToProviderDefaults as f, type AccessPassClaims as g, SOLANA_MAINNET_NETWORK as h, USDC_BASE as i };
|
package/dist/utils/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/index.ts","../../src/types.ts","../../src/utils.ts"],"sourcesContent":["/**\n * @dexterai/x402 Utils\n *\n * Helper functions for x402 payments.\n *\n * @example\n * ```typescript\n * import { toAtomicUnits, fromAtomicUnits } from '@dexterai/x402/utils';\n *\n * const atomic = toAtomicUnits(0.05, 6); // '50000'\n * const human = fromAtomicUnits('50000', 6); // 0.05\n * ```\n */\n\nexport {\n toAtomicUnits,\n fromAtomicUnits,\n getChainFamily,\n getChainName,\n getExplorerUrl,\n type ChainFamily,\n} from '../utils';\n","/**\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 for Solana) */\n feePayer?: string;\n /** Token decimals (optional - defaults to 6 for USDC) */\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 /** x402 version (1 or 2, defaults to 2 if not specified) */\n x402Version?: 1 | 2;\n /** Payment scheme (always 'exact' for x402 v2) */\n scheme: 'exact';\n /** CAIP-2 network identifier (v1: 'solana', v2: 'solana:5eykt...') */\n network: string;\n /** Payment amount in atomic units (x402 spec field - REQUIRED) */\n maxAmountRequired: string;\n /** Alias for maxAmountRequired (for convenience) */\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// Access Pass Types\n// ============================================================================\n\n/**\n * A single access pass tier offered by a seller\n */\nexport interface AccessPassTier {\n /** Tier ID (e.g., '1h', '24h') */\n id: string;\n /** Human-readable label (e.g., '1 hour') */\n label: string;\n /** Duration in seconds */\n seconds: number;\n /** Price in USD (e.g., '0.50') */\n price: string;\n /** Price in atomic units (e.g., '500000') */\n priceAtomic: string;\n}\n\n/**\n * Access pass info returned in X-ACCESS-PASS-TIERS header\n */\nexport interface AccessPassInfo {\n /** Available tiers (if tier-based pricing) */\n tiers?: AccessPassTier[];\n /** Rate per hour in USD (if custom duration pricing) */\n ratePerHour?: string;\n /** Pass issuer identifier */\n issuer?: string;\n}\n\n/**\n * JWT claims inside an access pass token\n */\nexport interface AccessPassClaims {\n /** Subject — always 'x402-access-pass' */\n sub: string;\n /** Tier ID or 'custom' */\n tier: string;\n /** Duration in seconds */\n duration: number;\n /** Issued at (unix seconds) */\n iat: number;\n /** Expires at (unix seconds) */\n exp: number;\n /** Payer wallet address */\n payer: string;\n /** Network used for payment */\n network: string;\n /** Issuer identifier */\n iss: string;\n}\n\n/**\n * Client-side access pass configuration\n */\nexport interface AccessPassClientConfig {\n /** Enable access pass mode (default: true when this config is present) */\n enabled?: boolean;\n /** Preferred tier ID (e.g., '1h') — pick this tier if available */\n preferTier?: string;\n /** Preferred custom duration in seconds (e.g., 3600) */\n preferDuration?: number;\n /** Maximum amount willing to spend in USD (e.g., '2.00') */\n maxSpend?: string;\n /** Auto-renew expired passes (default: true) */\n autoRenew?: boolean;\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 | 'missing_amount'\n | 'amount_exceeds_max'\n | 'insufficient_balance'\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 // Access pass errors\n | 'access_pass_expired'\n | 'access_pass_invalid'\n | 'access_pass_tier_not_found'\n | 'access_pass_exceeds_max_spend';\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 // Mainnet uses Dexter's RPC proxy\n return 'https://api.dexter.cash/api/solana/rpc';\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://api.dexter.cash/api/base/rpc'; // Dexter proxy\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://api.dexter.cash/api/base/rpc';\n }\n }\n // Legacy names\n if (network === 'base') return 'https://api.dexter.cash/api/base/rpc';\n if (network === 'ethereum') return 'https://eth.llamarpc.com';\n if (network === 'arbitrum') return 'https://arb1.arbitrum.io/rpc';\n return 'https://api.dexter.cash/api/base/rpc';\n }\n\n // Unknown - return Dexter's Solana proxy\n return 'https://api.dexter.cash/api/solana/rpc';\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 * Unicode-safe base64 encode a string.\n * Works in both Node.js and browsers, handling characters above U+00FF\n * that would cause btoa() to throw InvalidCharacterError.\n */\nfunction safeBase64Encode(str: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf-8').toString('base64');\n }\n // Browser fallback: encode UTF-8 bytes via TextEncoder\n const bytes = new TextEncoder().encode(str);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n/**\n * Unicode-safe base64 decode a string.\n * Works in both Node.js and browsers.\n */\nfunction safeBase64Decode(encoded: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(encoded, 'base64').toString('utf-8');\n }\n // Browser fallback: decode via atob then UTF-8\n const binary = atob(encoded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new TextDecoder().decode(bytes);\n}\n\n/**\n * Encode an object as base64 JSON (Unicode-safe)\n */\nexport function encodeBase64Json(obj: unknown): string {\n return safeBase64Encode(JSON.stringify(obj));\n}\n\n/**\n * Decode base64 JSON to object (Unicode-safe)\n */\nexport function decodeBase64Json<T>(encoded: string): T {\n return JSON.parse(safeBase64Decode(encoded)) as T;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACYO,IAAM,yBAAyB;AAG/B,IAAM,uBAAuB;;;ACU7B,SAAS,cAAc,QAAgB,UAA0B;AACtE,QAAM,aAAa,KAAK,IAAI,IAAI,QAAQ;AACxC,SAAO,KAAK,MAAM,SAAS,UAAU,EAAE,SAAS;AAClD;AAeO,SAAS,gBACd,aACA,UACQ;AACR,QAAM,UAAU,KAAK,IAAI,IAAI,QAAQ;AACrC,SAAO,OAAO,WAAW,IAAI;AAC/B;AAuBO,SAAS,eAAe,SAA8B;AAC3D,MAAI,QAAQ,WAAW,SAAS,KAAK,YAAY,UAAU;AACzD,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,WAAW,SAAS,KAAK,CAAC,QAAQ,YAAY,UAAU,EAAE,SAAS,OAAO,GAAG;AACvF,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAmDO,SAAS,aAAa,SAAyB;AACpD,QAAM,UAAkC;AAAA,IACtC,CAAC,sBAAsB,GAAG;AAAA,IAC1B,2CAA2C;AAAA,IAC3C,2CAA2C;AAAA,IAC3C,UAAU;AAAA,IACV,CAAC,oBAAoB,GAAG;AAAA,IACxB,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AACA,SAAO,QAAQ,OAAO,KAAK;AAC7B;AAaO,SAAS,eAAe,aAAqB,SAAyB;AAC3E,QAAM,SAAS,eAAe,OAAO;AAErC,MAAI,WAAW,UAAU;AACvB,UAAM,WAAW,QAAQ,SAAS,QAAQ,KAAK,YAAY;AAC3D,QAAI,UAAU;AACZ,aAAO,yBAAyB,WAAW;AAAA,IAC7C;AAEA,WAAO,gCAAgC,WAAW;AAAA,EACpD;AAEA,MAAI,WAAW,OAAO;AAEpB,QAAI,UAAU;AACd,QAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,gBAAU,QAAQ,MAAM,GAAG,EAAE,CAAC;AAAA,IAChC,WAAW,YAAY,YAAY;AACjC,gBAAU;AAAA,IACZ,WAAW,YAAY,YAAY;AACjC,gBAAU;AAAA,IACZ;AAEA,YAAQ,SAAS;AAAA,MACf,KAAK;AAAQ,eAAO,2BAA2B,WAAW;AAAA,MAC1D,KAAK;AAAS,eAAO,mCAAmC,WAAW;AAAA,MACnE,KAAK;AAAK,eAAO,2BAA2B,WAAW;AAAA,MACvD,KAAK;AAAS,eAAO,0BAA0B,WAAW;AAAA,MAC1D;AAAS,eAAO,2BAA2B,WAAW;AAAA,IACxD;AAAA,EACF;AAEA,SAAO,yBAAyB,WAAW;AAC7C;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/index.ts","../../src/types.ts","../../src/utils.ts"],"sourcesContent":["/**\n * @dexterai/x402 Utils\n *\n * Helper functions for x402 payments.\n *\n * @example\n * ```typescript\n * import { toAtomicUnits, fromAtomicUnits } from '@dexterai/x402/utils';\n *\n * const atomic = toAtomicUnits(0.05, 6); // '50000'\n * const human = fromAtomicUnits('50000', 6); // 0.05\n * ```\n */\n\nexport {\n toAtomicUnits,\n fromAtomicUnits,\n getChainFamily,\n getChainName,\n getExplorerUrl,\n type ChainFamily,\n} from '../utils';\n","/**\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// PayTo Provider Types (for dynamic address resolution, e.g. Stripe)\n// ============================================================================\n\n/**\n * Context passed to a PayToProvider function.\n * Contains request-scoped information for dynamic address resolution.\n */\nexport interface PayToContext {\n /** The PAYMENT-SIGNATURE header value (present on retry/verify, undefined on initial 402) */\n paymentHeader?: string;\n /** Amount in atomic units (e.g., '10000' for 0.01 USDC) */\n amountAtomic?: string;\n /** The resource URL being accessed */\n resourceUrl?: string;\n}\n\n/**\n * Optional defaults a PayToProvider can advertise for auto-configuration.\n * Attached as `_x402Defaults` on the provider function.\n */\nexport interface PayToProviderDefaults {\n /** Default CAIP-2 network (e.g., 'eip155:8453' for Base) */\n network?: string;\n /** Default facilitator URL */\n facilitatorUrl?: string;\n}\n\n/**\n * A function that dynamically resolves a payment address.\n * Used for providers like Stripe that generate per-request deposit addresses.\n *\n * @example\n * ```typescript\n * import { stripePayTo } from '@dexterai/x402/server';\n *\n * const provider = stripePayTo(process.env.STRIPE_SECRET_KEY);\n * const address = await provider({ amountAtomic: '10000' });\n * ```\n */\nexport type PayToProvider = ((context: PayToContext) => Promise<string>) & {\n /** Auto-configuration defaults (set by provider factories like stripePayTo) */\n _x402Defaults?: PayToProviderDefaults;\n};\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 for Solana) */\n feePayer?: string;\n /** Token decimals (optional - defaults to 6 for USDC) */\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 /** x402 version (1 or 2, defaults to 2 if not specified) */\n x402Version?: 1 | 2;\n /** Payment scheme (always 'exact' for x402 v2) */\n scheme: 'exact';\n /** CAIP-2 network identifier (v1: 'solana', v2: 'solana:5eykt...') */\n network: string;\n /** Payment amount in atomic units (x402 spec field - REQUIRED) */\n maxAmountRequired: string;\n /** Alias for maxAmountRequired (for convenience) */\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// Access Pass Types\n// ============================================================================\n\n/**\n * A single access pass tier offered by a seller\n */\nexport interface AccessPassTier {\n /** Tier ID (e.g., '1h', '24h') */\n id: string;\n /** Human-readable label (e.g., '1 hour') */\n label: string;\n /** Duration in seconds */\n seconds: number;\n /** Price in USD (e.g., '0.50') */\n price: string;\n /** Price in atomic units (e.g., '500000') */\n priceAtomic: string;\n}\n\n/**\n * Access pass info returned in X-ACCESS-PASS-TIERS header\n */\nexport interface AccessPassInfo {\n /** Available tiers (if tier-based pricing) */\n tiers?: AccessPassTier[];\n /** Rate per hour in USD (if custom duration pricing) */\n ratePerHour?: string;\n /** Pass issuer identifier */\n issuer?: string;\n}\n\n/**\n * JWT claims inside an access pass token\n */\nexport interface AccessPassClaims {\n /** Subject — always 'x402-access-pass' */\n sub: string;\n /** Tier ID or 'custom' */\n tier: string;\n /** Duration in seconds */\n duration: number;\n /** Issued at (unix seconds) */\n iat: number;\n /** Expires at (unix seconds) */\n exp: number;\n /** Payer wallet address */\n payer: string;\n /** Network used for payment */\n network: string;\n /** Issuer identifier */\n iss: string;\n}\n\n/**\n * Client-side access pass configuration\n */\nexport interface AccessPassClientConfig {\n /** Enable access pass mode (default: true when this config is present) */\n enabled?: boolean;\n /** Preferred tier ID (e.g., '1h') — pick this tier if available */\n preferTier?: string;\n /** Preferred custom duration in seconds (e.g., 3600) */\n preferDuration?: number;\n /** Maximum amount willing to spend in USD (e.g., '2.00') */\n maxSpend?: string;\n /** Auto-renew expired passes (default: true) */\n autoRenew?: boolean;\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 | 'missing_amount'\n | 'amount_exceeds_max'\n | 'insufficient_balance'\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 // Access pass errors\n | 'access_pass_expired'\n | 'access_pass_invalid'\n | 'access_pass_tier_not_found'\n | 'access_pass_exceeds_max_spend';\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 // Mainnet uses Dexter's RPC proxy\n return 'https://api.dexter.cash/api/solana/rpc';\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://api.dexter.cash/api/base/rpc'; // Dexter proxy\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://api.dexter.cash/api/base/rpc';\n }\n }\n // Legacy names\n if (network === 'base') return 'https://api.dexter.cash/api/base/rpc';\n if (network === 'ethereum') return 'https://eth.llamarpc.com';\n if (network === 'arbitrum') return 'https://arb1.arbitrum.io/rpc';\n return 'https://api.dexter.cash/api/base/rpc';\n }\n\n // Unknown - return Dexter's Solana proxy\n return 'https://api.dexter.cash/api/solana/rpc';\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 * Unicode-safe base64 encode a string.\n * Works in both Node.js and browsers, handling characters above U+00FF\n * that would cause btoa() to throw InvalidCharacterError.\n */\nfunction safeBase64Encode(str: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf-8').toString('base64');\n }\n // Browser fallback: encode UTF-8 bytes via TextEncoder\n const bytes = new TextEncoder().encode(str);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n/**\n * Unicode-safe base64 decode a string.\n * Works in both Node.js and browsers.\n */\nfunction safeBase64Decode(encoded: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(encoded, 'base64').toString('utf-8');\n }\n // Browser fallback: decode via atob then UTF-8\n const binary = atob(encoded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new TextDecoder().decode(bytes);\n}\n\n/**\n * Encode an object as base64 JSON (Unicode-safe)\n */\nexport function encodeBase64Json(obj: unknown): string {\n return safeBase64Encode(JSON.stringify(obj));\n}\n\n/**\n * Decode base64 JSON to object (Unicode-safe)\n */\nexport function decodeBase64Json<T>(encoded: string): T {\n return JSON.parse(safeBase64Decode(encoded)) as T;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACYO,IAAM,yBAAyB;AAG/B,IAAM,uBAAuB;;;ACU7B,SAAS,cAAc,QAAgB,UAA0B;AACtE,QAAM,aAAa,KAAK,IAAI,IAAI,QAAQ;AACxC,SAAO,KAAK,MAAM,SAAS,UAAU,EAAE,SAAS;AAClD;AAeO,SAAS,gBACd,aACA,UACQ;AACR,QAAM,UAAU,KAAK,IAAI,IAAI,QAAQ;AACrC,SAAO,OAAO,WAAW,IAAI;AAC/B;AAuBO,SAAS,eAAe,SAA8B;AAC3D,MAAI,QAAQ,WAAW,SAAS,KAAK,YAAY,UAAU;AACzD,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,WAAW,SAAS,KAAK,CAAC,QAAQ,YAAY,UAAU,EAAE,SAAS,OAAO,GAAG;AACvF,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAmDO,SAAS,aAAa,SAAyB;AACpD,QAAM,UAAkC;AAAA,IACtC,CAAC,sBAAsB,GAAG;AAAA,IAC1B,2CAA2C;AAAA,IAC3C,2CAA2C;AAAA,IAC3C,UAAU;AAAA,IACV,CAAC,oBAAoB,GAAG;AAAA,IACxB,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AACA,SAAO,QAAQ,OAAO,KAAK;AAC7B;AAaO,SAAS,eAAe,aAAqB,SAAyB;AAC3E,QAAM,SAAS,eAAe,OAAO;AAErC,MAAI,WAAW,UAAU;AACvB,UAAM,WAAW,QAAQ,SAAS,QAAQ,KAAK,YAAY;AAC3D,QAAI,UAAU;AACZ,aAAO,yBAAyB,WAAW;AAAA,IAC7C;AAEA,WAAO,gCAAgC,WAAW;AAAA,EACpD;AAEA,MAAI,WAAW,OAAO;AAEpB,QAAI,UAAU;AACd,QAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,gBAAU,QAAQ,MAAM,GAAG,EAAE,CAAC;AAAA,IAChC,WAAW,YAAY,YAAY;AACjC,gBAAU;AAAA,IACZ,WAAW,YAAY,YAAY;AACjC,gBAAU;AAAA,IACZ;AAEA,YAAQ,SAAS;AAAA,MACf,KAAK;AAAQ,eAAO,2BAA2B,WAAW;AAAA,MAC1D,KAAK;AAAS,eAAO,mCAAmC,WAAW;AAAA,MACnE,KAAK;AAAK,eAAO,2BAA2B,WAAW;AAAA,MACvD,KAAK;AAAS,eAAO,0BAA0B,WAAW;AAAA,MAC1D;AAAS,eAAO,2BAA2B,WAAW;AAAA,IACxD;AAAA,EACF;AAEA,SAAO,yBAAyB,WAAW;AAC7C;","names":[]}
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types.ts","../../src/utils.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 for Solana) */\n feePayer?: string;\n /** Token decimals (optional - defaults to 6 for USDC) */\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 /** x402 version (1 or 2, defaults to 2 if not specified) */\n x402Version?: 1 | 2;\n /** Payment scheme (always 'exact' for x402 v2) */\n scheme: 'exact';\n /** CAIP-2 network identifier (v1: 'solana', v2: 'solana:5eykt...') */\n network: string;\n /** Payment amount in atomic units (x402 spec field - REQUIRED) */\n maxAmountRequired: string;\n /** Alias for maxAmountRequired (for convenience) */\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// Access Pass Types\n// ============================================================================\n\n/**\n * A single access pass tier offered by a seller\n */\nexport interface AccessPassTier {\n /** Tier ID (e.g., '1h', '24h') */\n id: string;\n /** Human-readable label (e.g., '1 hour') */\n label: string;\n /** Duration in seconds */\n seconds: number;\n /** Price in USD (e.g., '0.50') */\n price: string;\n /** Price in atomic units (e.g., '500000') */\n priceAtomic: string;\n}\n\n/**\n * Access pass info returned in X-ACCESS-PASS-TIERS header\n */\nexport interface AccessPassInfo {\n /** Available tiers (if tier-based pricing) */\n tiers?: AccessPassTier[];\n /** Rate per hour in USD (if custom duration pricing) */\n ratePerHour?: string;\n /** Pass issuer identifier */\n issuer?: string;\n}\n\n/**\n * JWT claims inside an access pass token\n */\nexport interface AccessPassClaims {\n /** Subject — always 'x402-access-pass' */\n sub: string;\n /** Tier ID or 'custom' */\n tier: string;\n /** Duration in seconds */\n duration: number;\n /** Issued at (unix seconds) */\n iat: number;\n /** Expires at (unix seconds) */\n exp: number;\n /** Payer wallet address */\n payer: string;\n /** Network used for payment */\n network: string;\n /** Issuer identifier */\n iss: string;\n}\n\n/**\n * Client-side access pass configuration\n */\nexport interface AccessPassClientConfig {\n /** Enable access pass mode (default: true when this config is present) */\n enabled?: boolean;\n /** Preferred tier ID (e.g., '1h') — pick this tier if available */\n preferTier?: string;\n /** Preferred custom duration in seconds (e.g., 3600) */\n preferDuration?: number;\n /** Maximum amount willing to spend in USD (e.g., '2.00') */\n maxSpend?: string;\n /** Auto-renew expired passes (default: true) */\n autoRenew?: boolean;\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 | 'missing_amount'\n | 'amount_exceeds_max'\n | 'insufficient_balance'\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 // Access pass errors\n | 'access_pass_expired'\n | 'access_pass_invalid'\n | 'access_pass_tier_not_found'\n | 'access_pass_exceeds_max_spend';\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 // Mainnet uses Dexter's RPC proxy\n return 'https://api.dexter.cash/api/solana/rpc';\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://api.dexter.cash/api/base/rpc'; // Dexter proxy\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://api.dexter.cash/api/base/rpc';\n }\n }\n // Legacy names\n if (network === 'base') return 'https://api.dexter.cash/api/base/rpc';\n if (network === 'ethereum') return 'https://eth.llamarpc.com';\n if (network === 'arbitrum') return 'https://arb1.arbitrum.io/rpc';\n return 'https://api.dexter.cash/api/base/rpc';\n }\n\n // Unknown - return Dexter's Solana proxy\n return 'https://api.dexter.cash/api/solana/rpc';\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 * Unicode-safe base64 encode a string.\n * Works in both Node.js and browsers, handling characters above U+00FF\n * that would cause btoa() to throw InvalidCharacterError.\n */\nfunction safeBase64Encode(str: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf-8').toString('base64');\n }\n // Browser fallback: encode UTF-8 bytes via TextEncoder\n const bytes = new TextEncoder().encode(str);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n/**\n * Unicode-safe base64 decode a string.\n * Works in both Node.js and browsers.\n */\nfunction safeBase64Decode(encoded: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(encoded, 'base64').toString('utf-8');\n }\n // Browser fallback: decode via atob then UTF-8\n const binary = atob(encoded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new TextDecoder().decode(bytes);\n}\n\n/**\n * Encode an object as base64 JSON (Unicode-safe)\n */\nexport function encodeBase64Json(obj: unknown): string {\n return safeBase64Encode(JSON.stringify(obj));\n}\n\n/**\n * Decode base64 JSON to object (Unicode-safe)\n */\nexport function decodeBase64Json<T>(encoded: string): T {\n return JSON.parse(safeBase64Decode(encoded)) as T;\n}\n"],"mappings":";AAYO,IAAM,yBAAyB;AAG/B,IAAM,uBAAuB;;;ACU7B,SAAS,cAAc,QAAgB,UAA0B;AACtE,QAAM,aAAa,KAAK,IAAI,IAAI,QAAQ;AACxC,SAAO,KAAK,MAAM,SAAS,UAAU,EAAE,SAAS;AAClD;AAeO,SAAS,gBACd,aACA,UACQ;AACR,QAAM,UAAU,KAAK,IAAI,IAAI,QAAQ;AACrC,SAAO,OAAO,WAAW,IAAI;AAC/B;AAuBO,SAAS,eAAe,SAA8B;AAC3D,MAAI,QAAQ,WAAW,SAAS,KAAK,YAAY,UAAU;AACzD,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,WAAW,SAAS,KAAK,CAAC,QAAQ,YAAY,UAAU,EAAE,SAAS,OAAO,GAAG;AACvF,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAmDO,SAAS,aAAa,SAAyB;AACpD,QAAM,UAAkC;AAAA,IACtC,CAAC,sBAAsB,GAAG;AAAA,IAC1B,2CAA2C;AAAA,IAC3C,2CAA2C;AAAA,IAC3C,UAAU;AAAA,IACV,CAAC,oBAAoB,GAAG;AAAA,IACxB,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AACA,SAAO,QAAQ,OAAO,KAAK;AAC7B;AAaO,SAAS,eAAe,aAAqB,SAAyB;AAC3E,QAAM,SAAS,eAAe,OAAO;AAErC,MAAI,WAAW,UAAU;AACvB,UAAM,WAAW,QAAQ,SAAS,QAAQ,KAAK,YAAY;AAC3D,QAAI,UAAU;AACZ,aAAO,yBAAyB,WAAW;AAAA,IAC7C;AAEA,WAAO,gCAAgC,WAAW;AAAA,EACpD;AAEA,MAAI,WAAW,OAAO;AAEpB,QAAI,UAAU;AACd,QAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,gBAAU,QAAQ,MAAM,GAAG,EAAE,CAAC;AAAA,IAChC,WAAW,YAAY,YAAY;AACjC,gBAAU;AAAA,IACZ,WAAW,YAAY,YAAY;AACjC,gBAAU;AAAA,IACZ;AAEA,YAAQ,SAAS;AAAA,MACf,KAAK;AAAQ,eAAO,2BAA2B,WAAW;AAAA,MAC1D,KAAK;AAAS,eAAO,mCAAmC,WAAW;AAAA,MACnE,KAAK;AAAK,eAAO,2BAA2B,WAAW;AAAA,MACvD,KAAK;AAAS,eAAO,0BAA0B,WAAW;AAAA,MAC1D;AAAS,eAAO,2BAA2B,WAAW;AAAA,IACxD;AAAA,EACF;AAEA,SAAO,yBAAyB,WAAW;AAC7C;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/types.ts","../../src/utils.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// PayTo Provider Types (for dynamic address resolution, e.g. Stripe)\n// ============================================================================\n\n/**\n * Context passed to a PayToProvider function.\n * Contains request-scoped information for dynamic address resolution.\n */\nexport interface PayToContext {\n /** The PAYMENT-SIGNATURE header value (present on retry/verify, undefined on initial 402) */\n paymentHeader?: string;\n /** Amount in atomic units (e.g., '10000' for 0.01 USDC) */\n amountAtomic?: string;\n /** The resource URL being accessed */\n resourceUrl?: string;\n}\n\n/**\n * Optional defaults a PayToProvider can advertise for auto-configuration.\n * Attached as `_x402Defaults` on the provider function.\n */\nexport interface PayToProviderDefaults {\n /** Default CAIP-2 network (e.g., 'eip155:8453' for Base) */\n network?: string;\n /** Default facilitator URL */\n facilitatorUrl?: string;\n}\n\n/**\n * A function that dynamically resolves a payment address.\n * Used for providers like Stripe that generate per-request deposit addresses.\n *\n * @example\n * ```typescript\n * import { stripePayTo } from '@dexterai/x402/server';\n *\n * const provider = stripePayTo(process.env.STRIPE_SECRET_KEY);\n * const address = await provider({ amountAtomic: '10000' });\n * ```\n */\nexport type PayToProvider = ((context: PayToContext) => Promise<string>) & {\n /** Auto-configuration defaults (set by provider factories like stripePayTo) */\n _x402Defaults?: PayToProviderDefaults;\n};\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 for Solana) */\n feePayer?: string;\n /** Token decimals (optional - defaults to 6 for USDC) */\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 /** x402 version (1 or 2, defaults to 2 if not specified) */\n x402Version?: 1 | 2;\n /** Payment scheme (always 'exact' for x402 v2) */\n scheme: 'exact';\n /** CAIP-2 network identifier (v1: 'solana', v2: 'solana:5eykt...') */\n network: string;\n /** Payment amount in atomic units (x402 spec field - REQUIRED) */\n maxAmountRequired: string;\n /** Alias for maxAmountRequired (for convenience) */\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// Access Pass Types\n// ============================================================================\n\n/**\n * A single access pass tier offered by a seller\n */\nexport interface AccessPassTier {\n /** Tier ID (e.g., '1h', '24h') */\n id: string;\n /** Human-readable label (e.g., '1 hour') */\n label: string;\n /** Duration in seconds */\n seconds: number;\n /** Price in USD (e.g., '0.50') */\n price: string;\n /** Price in atomic units (e.g., '500000') */\n priceAtomic: string;\n}\n\n/**\n * Access pass info returned in X-ACCESS-PASS-TIERS header\n */\nexport interface AccessPassInfo {\n /** Available tiers (if tier-based pricing) */\n tiers?: AccessPassTier[];\n /** Rate per hour in USD (if custom duration pricing) */\n ratePerHour?: string;\n /** Pass issuer identifier */\n issuer?: string;\n}\n\n/**\n * JWT claims inside an access pass token\n */\nexport interface AccessPassClaims {\n /** Subject — always 'x402-access-pass' */\n sub: string;\n /** Tier ID or 'custom' */\n tier: string;\n /** Duration in seconds */\n duration: number;\n /** Issued at (unix seconds) */\n iat: number;\n /** Expires at (unix seconds) */\n exp: number;\n /** Payer wallet address */\n payer: string;\n /** Network used for payment */\n network: string;\n /** Issuer identifier */\n iss: string;\n}\n\n/**\n * Client-side access pass configuration\n */\nexport interface AccessPassClientConfig {\n /** Enable access pass mode (default: true when this config is present) */\n enabled?: boolean;\n /** Preferred tier ID (e.g., '1h') — pick this tier if available */\n preferTier?: string;\n /** Preferred custom duration in seconds (e.g., 3600) */\n preferDuration?: number;\n /** Maximum amount willing to spend in USD (e.g., '2.00') */\n maxSpend?: string;\n /** Auto-renew expired passes (default: true) */\n autoRenew?: boolean;\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 | 'missing_amount'\n | 'amount_exceeds_max'\n | 'insufficient_balance'\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 // Access pass errors\n | 'access_pass_expired'\n | 'access_pass_invalid'\n | 'access_pass_tier_not_found'\n | 'access_pass_exceeds_max_spend';\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 // Mainnet uses Dexter's RPC proxy\n return 'https://api.dexter.cash/api/solana/rpc';\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://api.dexter.cash/api/base/rpc'; // Dexter proxy\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://api.dexter.cash/api/base/rpc';\n }\n }\n // Legacy names\n if (network === 'base') return 'https://api.dexter.cash/api/base/rpc';\n if (network === 'ethereum') return 'https://eth.llamarpc.com';\n if (network === 'arbitrum') return 'https://arb1.arbitrum.io/rpc';\n return 'https://api.dexter.cash/api/base/rpc';\n }\n\n // Unknown - return Dexter's Solana proxy\n return 'https://api.dexter.cash/api/solana/rpc';\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 * Unicode-safe base64 encode a string.\n * Works in both Node.js and browsers, handling characters above U+00FF\n * that would cause btoa() to throw InvalidCharacterError.\n */\nfunction safeBase64Encode(str: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(str, 'utf-8').toString('base64');\n }\n // Browser fallback: encode UTF-8 bytes via TextEncoder\n const bytes = new TextEncoder().encode(str);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n}\n\n/**\n * Unicode-safe base64 decode a string.\n * Works in both Node.js and browsers.\n */\nfunction safeBase64Decode(encoded: string): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(encoded, 'base64').toString('utf-8');\n }\n // Browser fallback: decode via atob then UTF-8\n const binary = atob(encoded);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new TextDecoder().decode(bytes);\n}\n\n/**\n * Encode an object as base64 JSON (Unicode-safe)\n */\nexport function encodeBase64Json(obj: unknown): string {\n return safeBase64Encode(JSON.stringify(obj));\n}\n\n/**\n * Decode base64 JSON to object (Unicode-safe)\n */\nexport function decodeBase64Json<T>(encoded: string): T {\n return JSON.parse(safeBase64Decode(encoded)) as T;\n}\n"],"mappings":";AAYO,IAAM,yBAAyB;AAG/B,IAAM,uBAAuB;;;ACU7B,SAAS,cAAc,QAAgB,UAA0B;AACtE,QAAM,aAAa,KAAK,IAAI,IAAI,QAAQ;AACxC,SAAO,KAAK,MAAM,SAAS,UAAU,EAAE,SAAS;AAClD;AAeO,SAAS,gBACd,aACA,UACQ;AACR,QAAM,UAAU,KAAK,IAAI,IAAI,QAAQ;AACrC,SAAO,OAAO,WAAW,IAAI;AAC/B;AAuBO,SAAS,eAAe,SAA8B;AAC3D,MAAI,QAAQ,WAAW,SAAS,KAAK,YAAY,UAAU;AACzD,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,WAAW,SAAS,KAAK,CAAC,QAAQ,YAAY,UAAU,EAAE,SAAS,OAAO,GAAG;AACvF,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAmDO,SAAS,aAAa,SAAyB;AACpD,QAAM,UAAkC;AAAA,IACtC,CAAC,sBAAsB,GAAG;AAAA,IAC1B,2CAA2C;AAAA,IAC3C,2CAA2C;AAAA,IAC3C,UAAU;AAAA,IACV,CAAC,oBAAoB,GAAG;AAAA,IACxB,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AACA,SAAO,QAAQ,OAAO,KAAK;AAC7B;AAaO,SAAS,eAAe,aAAqB,SAAyB;AAC3E,QAAM,SAAS,eAAe,OAAO;AAErC,MAAI,WAAW,UAAU;AACvB,UAAM,WAAW,QAAQ,SAAS,QAAQ,KAAK,YAAY;AAC3D,QAAI,UAAU;AACZ,aAAO,yBAAyB,WAAW;AAAA,IAC7C;AAEA,WAAO,gCAAgC,WAAW;AAAA,EACpD;AAEA,MAAI,WAAW,OAAO;AAEpB,QAAI,UAAU;AACd,QAAI,QAAQ,WAAW,SAAS,GAAG;AACjC,gBAAU,QAAQ,MAAM,GAAG,EAAE,CAAC;AAAA,IAChC,WAAW,YAAY,YAAY;AACjC,gBAAU;AAAA,IACZ,WAAW,YAAY,YAAY;AACjC,gBAAU;AAAA,IACZ;AAEA,YAAQ,SAAS;AAAA,MACf,KAAK;AAAQ,eAAO,2BAA2B,WAAW;AAAA,MAC1D,KAAK;AAAS,eAAO,mCAAmC,WAAW;AAAA,MACnE,KAAK;AAAK,eAAO,2BAA2B,WAAW;AAAA,MACvD,KAAK;AAAS,eAAO,0BAA0B,WAAW;AAAA,MAC1D;AAAS,eAAO,2BAA2B,WAAW;AAAA,IACxD;AAAA,EACF;AAEA,SAAO,yBAAyB,WAAW;AAC7C;","names":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ChainAdapter, W as WalletSet } from './types-
|
|
2
|
-
import { A as AccessPassClientConfig } from './types-
|
|
1
|
+
import { C as ChainAdapter, W as WalletSet } from './types-ClEZ34n4.js';
|
|
2
|
+
import { A as AccessPassClientConfig } from './types-C6ty4U6C.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* x402 v2 Client
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ChainAdapter, W as WalletSet } from './types
|
|
2
|
-
import { A as AccessPassClientConfig } from './types-
|
|
1
|
+
import { C as ChainAdapter, W as WalletSet } from './types-BB-2vowq.cjs';
|
|
2
|
+
import { A as AccessPassClientConfig } from './types-C6ty4U6C.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* x402 v2 Client
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dexterai/x402",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Chain-agnostic x402 v2 SDK for Solana, Base, and EVM payments",
|
|
5
5
|
"author": "Dexter",
|
|
6
6
|
"license": "MIT",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
"bs58": "^6.0.0",
|
|
62
62
|
"ethers": "^6.13.0",
|
|
63
63
|
"react": "^18.0.0",
|
|
64
|
+
"stripe": "^20.3.1",
|
|
64
65
|
"tsup": "^8.3.5",
|
|
65
66
|
"typescript": "^5.7.2",
|
|
66
67
|
"vitest": "^2.1.8"
|
|
@@ -68,6 +69,7 @@
|
|
|
68
69
|
"peerDependencies": {
|
|
69
70
|
"@solana/wallet-adapter-base": "^0.9.0",
|
|
70
71
|
"react": "^18.0.0 || ^19.0.0",
|
|
72
|
+
"stripe": "^20.0.0",
|
|
71
73
|
"viem": "^2.0.0"
|
|
72
74
|
},
|
|
73
75
|
"peerDependenciesMeta": {
|
|
@@ -77,6 +79,9 @@
|
|
|
77
79
|
"react": {
|
|
78
80
|
"optional": true
|
|
79
81
|
},
|
|
82
|
+
"stripe": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
80
85
|
"viem": {
|
|
81
86
|
"optional": true
|
|
82
87
|
}
|
|
@@ -93,7 +98,10 @@
|
|
|
93
98
|
"payments",
|
|
94
99
|
"dexter",
|
|
95
100
|
"web3",
|
|
96
|
-
"crypto"
|
|
101
|
+
"crypto",
|
|
102
|
+
"stripe",
|
|
103
|
+
"machine-payments",
|
|
104
|
+
"agent-payments"
|
|
97
105
|
],
|
|
98
106
|
"repository": {
|
|
99
107
|
"type": "git",
|