UNPKG

cdp-wallet-onramp-kit

Version:

Complete toolkit for Coinbase Developer Platform (CDP) Embedded Wallets and Onramp integration with reusable components, utilities, and documentation

199 lines (198 loc) 6.68 kB
"use strict"; // Dynamic import to avoid build-time CDP SDK type checking Object.defineProperty(exports, "__esModule", { value: true }); exports.SUPPORTED_ASSETS = exports.SUPPORTED_NETWORKS = exports.GUEST_CHECKOUT_LIMITS = void 0; exports.generateJWT = generateJWT; exports.createSessionToken = createSessionToken; exports.generateOnrampUrl = generateOnrampUrl; exports.isValidEthereumAddress = isValidEthereumAddress; exports.validateGuestCheckoutAmount = validateGuestCheckoutAmount; /** * Generate a JSON Web Token (JWT) for CDP API authentication. * Uses the CDP SDK to handle all key formats automatically. * * @param config - JWT configuration options * @returns Promise<string> - The generated JWT token * * @example * ```typescript * const jwt = await generateJWT({ * method: 'POST', * path: '/onramp/v1/token' * }); * ``` */ async function generateJWT(config = {}) { const privateKeyString = process.env.CDP_API_KEY_PRIVATE_KEY || process.env.CDP_SECRET_KEY; const keyName = process.env.CDP_API_KEY_NAME || process.env.CDP_SECRET_KEY_NAME; if (!privateKeyString || !keyName) { throw new Error('CDP API credentials are required. Set CDP_API_KEY_PRIVATE_KEY and CDP_API_KEY_NAME environment variables.'); } const { method = 'POST', host = 'api.developer.coinbase.com', path = '/onramp/v1/token', expiresIn = 120 } = config; try { // Use eval to avoid TypeScript trying to resolve the module during build time const cdpSdkAuth = await eval('import("@coinbase/cdp-sdk/auth")'); // Use CDP SDK to generate JWT - handles all key formats correctly const jwt = await cdpSdkAuth.generateJwt({ apiKeyId: keyName, apiKeySecret: privateKeyString, requestMethod: method, requestHost: host, requestPath: path, expiresIn }); return jwt; } catch (error) { console.error('JWT generation failed:', error); console.error('Key format detected:', privateKeyString.startsWith('-----BEGIN') ? 'PEM' : 'Base64'); throw new Error('Failed to generate JWT. Make sure you have @coinbase/cdp-sdk installed:\n' + 'npm install @coinbase/cdp-sdk\n\n' + 'Original error: ' + (error instanceof Error ? error.message : 'Unknown error')); } } /** * Create a session token for initializing the onramp widget. * Session tokens are single-use and expire after 5 minutes. * * @param jwt - The JWT token for authentication * @param params - Session token parameters * @returns Promise<string> - The session token * * @example * ```typescript * const jwt = await generateJWT(); * const sessionToken = await createSessionToken(jwt, { * addresses: [{ * address: '0x1234...5678', * blockchains: ['base', 'ethereum'] * }], * assets: ['USDC', 'ETH'] * }); * ``` */ async function createSessionToken(jwt, params) { const response = await fetch('https://api.developer.coinbase.com/onramp/v1/token', { method: 'POST', headers: { 'Authorization': `Bearer ${jwt}`, 'Content-Type': 'application/json' }, body: JSON.stringify(params) }); if (!response.ok) { const errorText = await response.text(); let errorMessage = `Failed to create session token: ${response.status}`; try { const errorData = JSON.parse(errorText); errorMessage = errorData.message || errorData.error || errorMessage; } catch { errorMessage += ` - ${errorText}`; } throw new Error(errorMessage); } const data = await response.json(); return data.token || data.data?.token; } /** * Generate a complete onramp URL with session token and parameters. * This is a convenience function that combines JWT generation, session token creation, and URL building. * * @param params - Onramp URL parameters * @returns Promise<string> - The complete onramp URL * * @example * ```typescript * const onrampUrl = await generateOnrampUrl({ * addresses: [{ * address: '0x1234...5678', * blockchains: ['base'] * }], * defaultAsset: 'USDC', * presetFiatAmount: 50 * }); * ``` */ async function generateOnrampUrl(params) { // Generate JWT and session token const jwt = await generateJWT(); const sessionToken = await createSessionToken(jwt, { addresses: params.addresses, assets: params.assets }); // Build URL with session token and optional parameters const url = new URL('https://pay.coinbase.com/buy/select-asset'); url.searchParams.set('sessionToken', sessionToken); if (params.defaultAsset) { url.searchParams.set('defaultAsset', params.defaultAsset); } if (params.defaultNetwork) { url.searchParams.set('defaultNetwork', params.defaultNetwork); } if (params.presetFiatAmount) { url.searchParams.set('presetFiatAmount', params.presetFiatAmount.toString()); } if (params.presetCryptoAmount) { url.searchParams.set('presetCryptoAmount', params.presetCryptoAmount.toString()); } if (params.redirectUrl) { url.searchParams.set('redirectUrl', params.redirectUrl); } if (params.partnerUserId) { url.searchParams.set('partnerUserId', params.partnerUserId); } return url.toString(); } /** * Guest checkout limits as defined by Coinbase */ exports.GUEST_CHECKOUT_LIMITS = { minimumAmount: 5, // $5 minimum weeklyLimit: 500, // $500 weekly limit country: 'US' // US residents only }; /** * Supported blockchain networks */ exports.SUPPORTED_NETWORKS = { BASE: 'base', ETHEREUM: 'ethereum', ARBITRUM: 'arbitrum', OPTIMISM: 'optimism', POLYGON: 'polygon' }; /** * Common asset symbols */ exports.SUPPORTED_ASSETS = { ETHEREUM: 'ETH', USD_COIN: 'USDC', BITCOIN: 'BTC', TETHER: 'USDT', DAI: 'DAI' }; /** * Validate wallet address format */ function isValidEthereumAddress(address) { return /^0x[a-fA-F0-9]{40}$/.test(address); } /** * Validate amount within guest checkout limits */ function validateGuestCheckoutAmount(amount) { if (amount < exports.GUEST_CHECKOUT_LIMITS.minimumAmount) { return { isValid: false, error: `Amount must be at least $${exports.GUEST_CHECKOUT_LIMITS.minimumAmount}` }; } if (amount > exports.GUEST_CHECKOUT_LIMITS.weeklyLimit) { return { isValid: false, error: `Amount cannot exceed $${exports.GUEST_CHECKOUT_LIMITS.weeklyLimit} (weekly limit)` }; } return { isValid: true }; }