moltspay 0.9.5 → 0.9.7

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.
Files changed (51) hide show
  1. package/README.md +68 -45
  2. package/dist/cdp/index.d.mts +1 -1
  3. package/dist/cdp/index.d.ts +1 -1
  4. package/dist/cdp/index.js +63 -0
  5. package/dist/cdp/index.js.map +1 -1
  6. package/dist/cdp/index.mjs +63 -0
  7. package/dist/cdp/index.mjs.map +1 -1
  8. package/dist/chains/index.d.mts +9 -5
  9. package/dist/chains/index.d.ts +9 -5
  10. package/dist/chains/index.js +85 -0
  11. package/dist/chains/index.js.map +1 -1
  12. package/dist/chains/index.mjs +83 -0
  13. package/dist/chains/index.mjs.map +1 -1
  14. package/dist/cli/index.js +201 -38
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli/index.mjs +201 -38
  17. package/dist/cli/index.mjs.map +1 -1
  18. package/dist/client/index.d.mts +18 -3
  19. package/dist/client/index.d.ts +18 -3
  20. package/dist/client/index.js +112 -15
  21. package/dist/client/index.js.map +1 -1
  22. package/dist/client/index.mjs +112 -15
  23. package/dist/client/index.mjs.map +1 -1
  24. package/dist/{index-Dg8n6wdW.d.mts → index-B3v8IWjM.d.mts} +11 -1
  25. package/dist/{index-Dg8n6wdW.d.ts → index-B3v8IWjM.d.ts} +11 -1
  26. package/dist/index.d.mts +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +203 -42
  29. package/dist/index.js.map +1 -1
  30. package/dist/index.mjs +203 -42
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/server/index.d.mts +19 -1
  33. package/dist/server/index.d.ts +19 -1
  34. package/dist/server/index.js +71 -19
  35. package/dist/server/index.js.map +1 -1
  36. package/dist/server/index.mjs +71 -19
  37. package/dist/server/index.mjs.map +1 -1
  38. package/dist/verify/index.d.mts +7 -0
  39. package/dist/verify/index.d.ts +7 -0
  40. package/dist/verify/index.js +83 -8
  41. package/dist/verify/index.js.map +1 -1
  42. package/dist/verify/index.mjs +83 -8
  43. package/dist/verify/index.mjs.map +1 -1
  44. package/dist/wallet/index.d.mts +16 -8
  45. package/dist/wallet/index.d.ts +16 -8
  46. package/dist/wallet/index.js +114 -18
  47. package/dist/wallet/index.js.map +1 -1
  48. package/dist/wallet/index.mjs +114 -18
  49. package/dist/wallet/index.mjs.map +1 -1
  50. package/package.json +1 -1
  51. package/schemas/moltspay.services.schema.json +13 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/wallet/index.ts","../../src/wallet/Wallet.ts","../../src/chains/index.ts","../../src/wallet/createWallet.ts"],"sourcesContent":["export { Wallet, type WalletConfig } from './Wallet.js';\nexport { \n createWallet, \n loadWallet, \n getWalletAddress, \n walletExists,\n type CreateWalletOptions,\n type CreateWalletResult,\n type WalletData,\n} from './createWallet.js';\n","/**\n * Wallet - Basic Custody Wallet\n * \n * Features:\n * - Query balance\n * - Send USDC transfer\n */\n\nimport { ethers } from 'ethers';\nimport { getChain, ERC20_ABI } from '../chains/index.js';\nimport type {\n ChainName,\n ChainConfig,\n WalletBalance,\n TransferResult,\n} from '../types/index.js';\n\nexport interface WalletConfig {\n chain?: ChainName;\n privateKey?: string;\n rpcUrl?: string;\n}\n\nexport class Wallet {\n readonly chain: ChainName;\n readonly chainConfig: ChainConfig;\n readonly address: string;\n \n private wallet: ethers.Wallet;\n private provider: ethers.JsonRpcProvider;\n private usdcContract: ethers.Contract;\n\n constructor(config: WalletConfig = {}) {\n this.chain = config.chain || 'base_sepolia';\n this.chainConfig = getChain(this.chain);\n \n const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;\n if (!privateKey) {\n throw new Error('privateKey is required. Set via config or PAYMENT_AGENT_PRIVATE_KEY env var.');\n }\n\n const rpcUrl = config.rpcUrl || this.chainConfig.rpc;\n this.provider = new ethers.JsonRpcProvider(rpcUrl);\n this.wallet = new ethers.Wallet(privateKey, this.provider);\n this.address = this.wallet.address;\n \n this.usdcContract = new ethers.Contract(\n this.chainConfig.usdc,\n ERC20_ABI,\n this.wallet\n );\n }\n\n /**\n * Get wallet balance\n */\n async getBalance(): Promise<WalletBalance> {\n const [ethBalance, usdcBalance] = await Promise.all([\n this.provider.getBalance(this.address),\n this.usdcContract.balanceOf(this.address),\n ]);\n\n return {\n address: this.address,\n eth: ethers.formatEther(ethBalance),\n usdc: (Number(usdcBalance) / 1e6).toFixed(2),\n chain: this.chain,\n };\n }\n\n /**\n * Send USDC transfer\n */\n async transfer(to: string, amount: number): Promise<TransferResult> {\n try {\n // Validate address\n to = ethers.getAddress(to);\n \n // Convert amount (USDC 6 decimals)\n const amountWei = BigInt(Math.floor(amount * 1e6));\n\n // Check balance\n const balance = await this.usdcContract.balanceOf(this.address);\n if (BigInt(balance) < amountWei) {\n return {\n success: false,\n error: `Insufficient USDC balance: ${Number(balance) / 1e6} < ${amount}`,\n };\n }\n\n // Send transaction\n const tx = await this.usdcContract.transfer(to, amountWei);\n const receipt = await tx.wait();\n\n if (receipt.status === 1) {\n return {\n success: true,\n tx_hash: tx.hash,\n from: this.address,\n to,\n amount,\n gas_used: Number(receipt.gasUsed),\n block_number: receipt.blockNumber,\n explorer_url: `${this.chainConfig.explorerTx}${tx.hash}`,\n };\n } else {\n return {\n success: false,\n tx_hash: tx.hash,\n error: 'Transaction reverted',\n };\n }\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n }\n\n /**\n * Get ETH balance\n */\n async getEthBalance(): Promise<string> {\n const balance = await this.provider.getBalance(this.address);\n return ethers.formatEther(balance);\n }\n\n /**\n * Get USDC balance\n */\n async getUsdcBalance(): Promise<string> {\n const balance = await this.usdcContract.balanceOf(this.address);\n return (Number(balance) / 1e6).toFixed(2);\n }\n}\n","/**\n * Blockchain Configuration\n */\n\nimport type { ChainConfig, ChainName } from '../types/index.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n // ============ Mainnet ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-rpc.com',\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n rpc: 'https://eth.llamarpc.com',\n usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n explorer: 'https://etherscan.io/address/',\n explorerTx: 'https://etherscan.io/tx/',\n avgBlockTime: 12,\n },\n\n // ============ Testnet ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n sepolia: {\n name: 'Sepolia',\n chainId: 11155111,\n rpc: 'https://rpc.sepolia.org',\n usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n explorer: 'https://sepolia.etherscan.io/address/',\n explorerTx: 'https://sepolia.etherscan.io/tx/',\n avgBlockTime: 12,\n },\n};\n\n/**\n * Get chain configuration\n */\nexport function getChain(name: ChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * List all supported chains\n */\nexport function listChains(): ChainName[] {\n return Object.keys(CHAINS) as ChainName[];\n}\n\n/**\n * Get chain config by chainId\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n/**\n * ERC20 ABI (minimal, only required methods)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName };\n","/**\n * createWallet - Create a new wallet for Agent\n * \n * Features:\n * - Generate new Ethereum wallet\n * - Securely store private key (encrypted or plaintext, depending on config)\n * - Return wallet address (never return private key)\n */\n\nimport { ethers } from 'ethers';\nimport { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'crypto';\n\nexport interface CreateWalletOptions {\n /** Storage path, default ~/.moltspay/wallet.json */\n storagePath?: string;\n /** Encryption password (optional, plaintext if not provided) */\n password?: string;\n /** Wallet label/name */\n label?: string;\n /** Overwrite if wallet exists */\n overwrite?: boolean;\n}\n\nexport interface WalletData {\n address: string;\n label?: string;\n createdAt: string;\n encrypted: boolean;\n /** Encrypted or plaintext private key */\n privateKey: string;\n /** Encryption IV */\n iv?: string;\n /** Encryption salt */\n salt?: string;\n}\n\nexport interface CreateWalletResult {\n success: boolean;\n address?: string;\n storagePath?: string;\n error?: string;\n /** Whether newly created (false means loaded existing) */\n isNew?: boolean;\n}\n\nconst DEFAULT_STORAGE_DIR = join(process.env.HOME || '~', '.moltspay');\nconst DEFAULT_STORAGE_FILE = 'wallet.json';\n\n/**\n * Encrypt private key\n */\nfunction encryptPrivateKey(privateKey: string, password: string): { encrypted: string; iv: string; salt: string } {\n const salt = randomBytes(16);\n const key = scryptSync(password, salt, 32);\n const iv = randomBytes(16);\n \n const cipher = createCipheriv('aes-256-cbc', key, iv);\n let encrypted = cipher.update(privateKey, 'utf8', 'hex');\n encrypted += cipher.final('hex');\n \n return {\n encrypted,\n iv: iv.toString('hex'),\n salt: salt.toString('hex'),\n };\n}\n\n/**\n * Decrypt private key\n */\nfunction decryptPrivateKey(encrypted: string, password: string, iv: string, salt: string): string {\n const key = scryptSync(password, Buffer.from(salt, 'hex'), 32);\n const decipher = createDecipheriv('aes-256-cbc', key, Buffer.from(iv, 'hex'));\n \n let decrypted = decipher.update(encrypted, 'hex', 'utf8');\n decrypted += decipher.final('utf8');\n \n return decrypted;\n}\n\n/**\n * Create new wallet\n * \n * @example\n * ```typescript\n * // Create unencrypted wallet\n * const result = await createWallet();\n * console.log('Wallet address:', result.address);\n * \n * // Create encrypted wallet\n * const result = await createWallet({ password: 'mySecurePassword' });\n * \n * // Specify storage path\n * const result = await createWallet({ storagePath: './my-wallet.json' });\n * ```\n */\nexport function createWallet(options: CreateWalletOptions = {}): CreateWalletResult {\n const storagePath = options.storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n \n // Check if exists\n if (existsSync(storagePath) && !options.overwrite) {\n // Load existing wallet\n try {\n const existing = JSON.parse(readFileSync(storagePath, 'utf8')) as WalletData;\n return {\n success: true,\n address: existing.address,\n storagePath,\n isNew: false,\n };\n } catch (error) {\n return {\n success: false,\n error: `Failed to load existing wallet: ${(error as Error).message}`,\n };\n }\n }\n\n try {\n // Create new wallet\n const wallet = ethers.Wallet.createRandom();\n \n // Prepare storage data\n const walletData: WalletData = {\n address: wallet.address,\n label: options.label,\n createdAt: new Date().toISOString(),\n encrypted: !!options.password,\n privateKey: '',\n };\n\n if (options.password) {\n // Encrypted storage\n const { encrypted, iv, salt } = encryptPrivateKey(wallet.privateKey, options.password);\n walletData.privateKey = encrypted;\n walletData.iv = iv;\n walletData.salt = salt;\n } else {\n // Plaintext storage (not recommended, but convenient for testing/dev)\n walletData.privateKey = wallet.privateKey;\n }\n\n // Ensure directory exists\n const dir = dirname(storagePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Write file\n writeFileSync(storagePath, JSON.stringify(walletData, null, 2), { mode: 0o600 });\n\n return {\n success: true,\n address: wallet.address,\n storagePath,\n isNew: true,\n };\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n}\n\n/**\n * Load existing wallet\n */\nexport function loadWallet(options: { storagePath?: string; password?: string } = {}): {\n success: boolean;\n address?: string;\n privateKey?: string;\n error?: string;\n} {\n const storagePath = options.storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n\n if (!existsSync(storagePath)) {\n return { success: false, error: 'Wallet not found. Run createWallet() first.' };\n }\n\n try {\n const data = JSON.parse(readFileSync(storagePath, 'utf8')) as WalletData;\n\n if (data.encrypted) {\n if (!options.password) {\n return { success: false, error: 'Wallet is encrypted. Password required.' };\n }\n const privateKey = decryptPrivateKey(data.privateKey, options.password, data.iv!, data.salt!);\n return { success: true, address: data.address, privateKey };\n } else {\n return { success: true, address: data.address, privateKey: data.privateKey };\n }\n } catch (error) {\n return { success: false, error: (error as Error).message };\n }\n}\n\n/**\n * Get wallet address (no password required)\n */\nexport function getWalletAddress(storagePath?: string): string | null {\n const path = storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n \n if (!existsSync(path)) {\n return null;\n }\n\n try {\n const data = JSON.parse(readFileSync(path, 'utf8')) as WalletData;\n return data.address;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if wallet exists\n */\nexport function walletExists(storagePath?: string): boolean {\n const path = storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n return existsSync(path);\n}\n"],"mappings":"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","names":["import_ethers"]}
1
+ {"version":3,"sources":["../../src/wallet/index.ts","../../src/wallet/Wallet.ts","../../src/chains/index.ts","../../src/wallet/createWallet.ts"],"sourcesContent":["export { Wallet, type WalletConfig } from './Wallet.js';\nexport { \n createWallet, \n loadWallet, \n getWalletAddress, \n walletExists,\n type CreateWalletOptions,\n type CreateWalletResult,\n type WalletData,\n} from './createWallet.js';\n","/**\n * Wallet - Basic Custody Wallet\n * \n * Features:\n * - Query balance (USDC, USDT, ETH)\n * - Send token transfers (USDC or USDT)\n */\n\nimport { ethers } from 'ethers';\nimport { getChain, ERC20_ABI } from '../chains/index.js';\nimport type {\n ChainName,\n ChainConfig,\n WalletBalance,\n TransferResult,\n TokenSymbol,\n} from '../types/index.js';\n\nexport interface WalletConfig {\n chain?: ChainName;\n privateKey?: string;\n rpcUrl?: string;\n}\n\nexport class Wallet {\n readonly chain: ChainName;\n readonly chainConfig: ChainConfig;\n readonly address: string;\n \n private wallet: ethers.Wallet;\n private provider: ethers.JsonRpcProvider;\n private tokenContracts: Record<TokenSymbol, ethers.Contract>;\n\n constructor(config: WalletConfig = {}) {\n this.chain = config.chain || 'base_sepolia';\n this.chainConfig = getChain(this.chain);\n \n const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;\n if (!privateKey) {\n throw new Error('privateKey is required. Set via config or PAYMENT_AGENT_PRIVATE_KEY env var.');\n }\n\n const rpcUrl = config.rpcUrl || this.chainConfig.rpc;\n this.provider = new ethers.JsonRpcProvider(rpcUrl);\n this.wallet = new ethers.Wallet(privateKey, this.provider);\n this.address = this.wallet.address;\n \n // Initialize token contracts\n this.tokenContracts = {\n USDC: new ethers.Contract(\n this.chainConfig.tokens.USDC.address,\n ERC20_ABI,\n this.wallet\n ),\n USDT: new ethers.Contract(\n this.chainConfig.tokens.USDT.address,\n ERC20_ABI,\n this.wallet\n ),\n };\n }\n\n /**\n * Get wallet balance for all tokens\n */\n async getBalance(): Promise<WalletBalance> {\n const [ethBalance, usdcBalance, usdtBalance] = await Promise.all([\n this.provider.getBalance(this.address),\n this.tokenContracts.USDC.balanceOf(this.address),\n this.tokenContracts.USDT.balanceOf(this.address),\n ]);\n\n return {\n address: this.address,\n eth: ethers.formatEther(ethBalance),\n usdc: (Number(usdcBalance) / 1e6).toFixed(2),\n usdt: (Number(usdtBalance) / 1e6).toFixed(2),\n chain: this.chain,\n };\n }\n\n /**\n * Send token transfer (USDC or USDT)\n * @param to - recipient address\n * @param amount - amount to send\n * @param token - token to send (default: USDC)\n */\n async transfer(to: string, amount: number, token: TokenSymbol = 'USDC'): Promise<TransferResult> {\n try {\n // Validate address\n to = ethers.getAddress(to);\n \n // Get token contract and config\n const tokenContract = this.tokenContracts[token];\n const tokenConfig = this.chainConfig.tokens[token];\n \n if (!tokenContract || !tokenConfig) {\n return {\n success: false,\n error: `Token ${token} not supported on ${this.chain}`,\n };\n }\n \n // Convert amount (both USDC and USDT have 6 decimals)\n const decimals = tokenConfig.decimals;\n const amountWei = BigInt(Math.floor(amount * (10 ** decimals)));\n\n // Check balance\n const balance = await tokenContract.balanceOf(this.address);\n if (BigInt(balance) < amountWei) {\n return {\n success: false,\n error: `Insufficient ${token} balance: ${Number(balance) / (10 ** decimals)} < ${amount}`,\n };\n }\n\n // Send transaction\n const tx = await tokenContract.transfer(to, amountWei);\n const receipt = await tx.wait();\n\n if (receipt.status === 1) {\n return {\n success: true,\n tx_hash: tx.hash,\n from: this.address,\n to,\n amount,\n token,\n gas_used: Number(receipt.gasUsed),\n block_number: receipt.blockNumber,\n explorer_url: `${this.chainConfig.explorerTx}${tx.hash}`,\n };\n } else {\n return {\n success: false,\n tx_hash: tx.hash,\n token,\n error: 'Transaction reverted',\n };\n }\n } catch (error) {\n return {\n success: false,\n token,\n error: (error as Error).message,\n };\n }\n }\n\n /**\n * Get ETH balance\n */\n async getEthBalance(): Promise<string> {\n const balance = await this.provider.getBalance(this.address);\n return ethers.formatEther(balance);\n }\n\n /**\n * Get token balance\n * @param token - token symbol (default: USDC)\n */\n async getTokenBalance(token: TokenSymbol = 'USDC'): Promise<string> {\n const tokenContract = this.tokenContracts[token];\n const tokenConfig = this.chainConfig.tokens[token];\n const balance = await tokenContract.balanceOf(this.address);\n return (Number(balance) / (10 ** tokenConfig.decimals)).toFixed(2);\n }\n\n /**\n * @deprecated Use getTokenBalance('USDC') instead\n */\n async getUsdcBalance(): Promise<string> {\n return this.getTokenBalance('USDC');\n }\n}\n","/**\n * Blockchain Configuration\n */\n\nimport type { ChainConfig, ChainName, TokenSymbol } from '../types/index.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n // ============ Mainnet ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n tokens: {\n USDC: {\n address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n decimals: 6,\n symbol: 'USDC',\n },\n USDT: {\n address: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2',\n decimals: 6,\n symbol: 'USDT',\n },\n },\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // deprecated, for backward compat\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-rpc.com',\n tokens: {\n USDC: {\n address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n decimals: 6,\n symbol: 'USDC',\n },\n USDT: {\n address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',\n decimals: 6,\n symbol: 'USDT',\n },\n },\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n rpc: 'https://eth.llamarpc.com',\n tokens: {\n USDC: {\n address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n decimals: 6,\n symbol: 'USDC',\n },\n USDT: {\n address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',\n decimals: 6,\n symbol: 'USDT',\n },\n },\n usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n explorer: 'https://etherscan.io/address/',\n explorerTx: 'https://etherscan.io/tx/',\n avgBlockTime: 12,\n },\n\n // ============ Testnet ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n tokens: {\n USDC: {\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n decimals: 6,\n symbol: 'USDC',\n },\n USDT: {\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Same as USDC on testnet (no official USDT)\n decimals: 6,\n symbol: 'USDT',\n },\n },\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n sepolia: {\n name: 'Sepolia',\n chainId: 11155111,\n rpc: 'https://rpc.sepolia.org',\n tokens: {\n USDC: {\n address: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n decimals: 6,\n symbol: 'USDC',\n },\n USDT: {\n address: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', // Same as USDC on testnet\n decimals: 6,\n symbol: 'USDT',\n },\n },\n usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n explorer: 'https://sepolia.etherscan.io/address/',\n explorerTx: 'https://sepolia.etherscan.io/tx/',\n avgBlockTime: 12,\n },\n};\n\n/**\n * Get token address for a chain\n */\nexport function getTokenAddress(chainName: ChainName, token: TokenSymbol): string {\n const chain = CHAINS[chainName];\n if (!chain) {\n throw new Error(`Unsupported chain: ${chainName}`);\n }\n const tokenConfig = chain.tokens[token];\n if (!tokenConfig) {\n throw new Error(`Token ${token} not supported on ${chainName}`);\n }\n return tokenConfig.address;\n}\n\n/**\n * Get token config for a chain\n */\nexport function getTokenConfig(chainName: ChainName, token: TokenSymbol) {\n const chain = CHAINS[chainName];\n if (!chain) {\n throw new Error(`Unsupported chain: ${chainName}`);\n }\n return chain.tokens[token];\n}\n\n/**\n * Get chain configuration\n */\nexport function getChain(name: ChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * List all supported chains\n */\nexport function listChains(): ChainName[] {\n return Object.keys(CHAINS) as ChainName[];\n}\n\n/**\n * Get chain config by chainId\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n/**\n * ERC20 ABI (minimal, only required methods)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName, TokenSymbol };\n","/**\n * createWallet - Create a new wallet for Agent\n * \n * Features:\n * - Generate new Ethereum wallet\n * - Securely store private key (encrypted or plaintext, depending on config)\n * - Return wallet address (never return private key)\n */\n\nimport { ethers } from 'ethers';\nimport { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'crypto';\n\nexport interface CreateWalletOptions {\n /** Storage path, default ~/.moltspay/wallet.json */\n storagePath?: string;\n /** Encryption password (optional, plaintext if not provided) */\n password?: string;\n /** Wallet label/name */\n label?: string;\n /** Overwrite if wallet exists */\n overwrite?: boolean;\n}\n\nexport interface WalletData {\n address: string;\n label?: string;\n createdAt: string;\n encrypted: boolean;\n /** Encrypted or plaintext private key */\n privateKey: string;\n /** Encryption IV */\n iv?: string;\n /** Encryption salt */\n salt?: string;\n}\n\nexport interface CreateWalletResult {\n success: boolean;\n address?: string;\n storagePath?: string;\n error?: string;\n /** Whether newly created (false means loaded existing) */\n isNew?: boolean;\n}\n\nconst DEFAULT_STORAGE_DIR = join(process.env.HOME || '~', '.moltspay');\nconst DEFAULT_STORAGE_FILE = 'wallet.json';\n\n/**\n * Encrypt private key\n */\nfunction encryptPrivateKey(privateKey: string, password: string): { encrypted: string; iv: string; salt: string } {\n const salt = randomBytes(16);\n const key = scryptSync(password, salt, 32);\n const iv = randomBytes(16);\n \n const cipher = createCipheriv('aes-256-cbc', key, iv);\n let encrypted = cipher.update(privateKey, 'utf8', 'hex');\n encrypted += cipher.final('hex');\n \n return {\n encrypted,\n iv: iv.toString('hex'),\n salt: salt.toString('hex'),\n };\n}\n\n/**\n * Decrypt private key\n */\nfunction decryptPrivateKey(encrypted: string, password: string, iv: string, salt: string): string {\n const key = scryptSync(password, Buffer.from(salt, 'hex'), 32);\n const decipher = createDecipheriv('aes-256-cbc', key, Buffer.from(iv, 'hex'));\n \n let decrypted = decipher.update(encrypted, 'hex', 'utf8');\n decrypted += decipher.final('utf8');\n \n return decrypted;\n}\n\n/**\n * Create new wallet\n * \n * @example\n * ```typescript\n * // Create unencrypted wallet\n * const result = await createWallet();\n * console.log('Wallet address:', result.address);\n * \n * // Create encrypted wallet\n * const result = await createWallet({ password: 'mySecurePassword' });\n * \n * // Specify storage path\n * const result = await createWallet({ storagePath: './my-wallet.json' });\n * ```\n */\nexport function createWallet(options: CreateWalletOptions = {}): CreateWalletResult {\n const storagePath = options.storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n \n // Check if exists\n if (existsSync(storagePath) && !options.overwrite) {\n // Load existing wallet\n try {\n const existing = JSON.parse(readFileSync(storagePath, 'utf8')) as WalletData;\n return {\n success: true,\n address: existing.address,\n storagePath,\n isNew: false,\n };\n } catch (error) {\n return {\n success: false,\n error: `Failed to load existing wallet: ${(error as Error).message}`,\n };\n }\n }\n\n try {\n // Create new wallet\n const wallet = ethers.Wallet.createRandom();\n \n // Prepare storage data\n const walletData: WalletData = {\n address: wallet.address,\n label: options.label,\n createdAt: new Date().toISOString(),\n encrypted: !!options.password,\n privateKey: '',\n };\n\n if (options.password) {\n // Encrypted storage\n const { encrypted, iv, salt } = encryptPrivateKey(wallet.privateKey, options.password);\n walletData.privateKey = encrypted;\n walletData.iv = iv;\n walletData.salt = salt;\n } else {\n // Plaintext storage (not recommended, but convenient for testing/dev)\n walletData.privateKey = wallet.privateKey;\n }\n\n // Ensure directory exists\n const dir = dirname(storagePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Write file\n writeFileSync(storagePath, JSON.stringify(walletData, null, 2), { mode: 0o600 });\n\n return {\n success: true,\n address: wallet.address,\n storagePath,\n isNew: true,\n };\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n}\n\n/**\n * Load existing wallet\n */\nexport function loadWallet(options: { storagePath?: string; password?: string } = {}): {\n success: boolean;\n address?: string;\n privateKey?: string;\n error?: string;\n} {\n const storagePath = options.storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n\n if (!existsSync(storagePath)) {\n return { success: false, error: 'Wallet not found. Run createWallet() first.' };\n }\n\n try {\n const data = JSON.parse(readFileSync(storagePath, 'utf8')) as WalletData;\n\n if (data.encrypted) {\n if (!options.password) {\n return { success: false, error: 'Wallet is encrypted. Password required.' };\n }\n const privateKey = decryptPrivateKey(data.privateKey, options.password, data.iv!, data.salt!);\n return { success: true, address: data.address, privateKey };\n } else {\n return { success: true, address: data.address, privateKey: data.privateKey };\n }\n } catch (error) {\n return { success: false, error: (error as Error).message };\n }\n}\n\n/**\n * Get wallet address (no password required)\n */\nexport function getWalletAddress(storagePath?: string): string | null {\n const path = storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n \n if (!existsSync(path)) {\n return null;\n }\n\n try {\n const data = JSON.parse(readFileSync(path, 'utf8')) as WalletData;\n return data.address;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if wallet exists\n */\nexport function walletExists(storagePath?: string): boolean {\n const path = storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n return existsSync(path);\n}\n"],"mappings":"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","names":["import_ethers"]}
@@ -8,7 +8,20 @@ var CHAINS = {
8
8
  name: "Base",
9
9
  chainId: 8453,
10
10
  rpc: "https://mainnet.base.org",
11
+ tokens: {
12
+ USDC: {
13
+ address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
14
+ decimals: 6,
15
+ symbol: "USDC"
16
+ },
17
+ USDT: {
18
+ address: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",
19
+ decimals: 6,
20
+ symbol: "USDT"
21
+ }
22
+ },
11
23
  usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
24
+ // deprecated, for backward compat
12
25
  explorer: "https://basescan.org/address/",
13
26
  explorerTx: "https://basescan.org/tx/",
14
27
  avgBlockTime: 2
@@ -17,6 +30,18 @@ var CHAINS = {
17
30
  name: "Polygon",
18
31
  chainId: 137,
19
32
  rpc: "https://polygon-rpc.com",
33
+ tokens: {
34
+ USDC: {
35
+ address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
36
+ decimals: 6,
37
+ symbol: "USDC"
38
+ },
39
+ USDT: {
40
+ address: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
41
+ decimals: 6,
42
+ symbol: "USDT"
43
+ }
44
+ },
20
45
  usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
21
46
  explorer: "https://polygonscan.com/address/",
22
47
  explorerTx: "https://polygonscan.com/tx/",
@@ -26,6 +51,18 @@ var CHAINS = {
26
51
  name: "Ethereum",
27
52
  chainId: 1,
28
53
  rpc: "https://eth.llamarpc.com",
54
+ tokens: {
55
+ USDC: {
56
+ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
57
+ decimals: 6,
58
+ symbol: "USDC"
59
+ },
60
+ USDT: {
61
+ address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
62
+ decimals: 6,
63
+ symbol: "USDT"
64
+ }
65
+ },
29
66
  usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
30
67
  explorer: "https://etherscan.io/address/",
31
68
  explorerTx: "https://etherscan.io/tx/",
@@ -36,6 +73,19 @@ var CHAINS = {
36
73
  name: "Base Sepolia",
37
74
  chainId: 84532,
38
75
  rpc: "https://sepolia.base.org",
76
+ tokens: {
77
+ USDC: {
78
+ address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
79
+ decimals: 6,
80
+ symbol: "USDC"
81
+ },
82
+ USDT: {
83
+ address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
84
+ // Same as USDC on testnet (no official USDT)
85
+ decimals: 6,
86
+ symbol: "USDT"
87
+ }
88
+ },
39
89
  usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
40
90
  explorer: "https://sepolia.basescan.org/address/",
41
91
  explorerTx: "https://sepolia.basescan.org/tx/",
@@ -45,6 +95,19 @@ var CHAINS = {
45
95
  name: "Sepolia",
46
96
  chainId: 11155111,
47
97
  rpc: "https://rpc.sepolia.org",
98
+ tokens: {
99
+ USDC: {
100
+ address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
101
+ decimals: 6,
102
+ symbol: "USDC"
103
+ },
104
+ USDT: {
105
+ address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
106
+ // Same as USDC on testnet
107
+ decimals: 6,
108
+ symbol: "USDT"
109
+ }
110
+ },
48
111
  usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
49
112
  explorer: "https://sepolia.etherscan.io/address/",
50
113
  explorerTx: "https://sepolia.etherscan.io/tx/",
@@ -79,7 +142,7 @@ var Wallet = class {
79
142
  address;
80
143
  wallet;
81
144
  provider;
82
- usdcContract;
145
+ tokenContracts;
83
146
  constructor(config = {}) {
84
147
  this.chain = config.chain || "base_sepolia";
85
148
  this.chainConfig = getChain(this.chain);
@@ -91,42 +154,63 @@ var Wallet = class {
91
154
  this.provider = new ethers.JsonRpcProvider(rpcUrl);
92
155
  this.wallet = new ethers.Wallet(privateKey, this.provider);
93
156
  this.address = this.wallet.address;
94
- this.usdcContract = new ethers.Contract(
95
- this.chainConfig.usdc,
96
- ERC20_ABI,
97
- this.wallet
98
- );
157
+ this.tokenContracts = {
158
+ USDC: new ethers.Contract(
159
+ this.chainConfig.tokens.USDC.address,
160
+ ERC20_ABI,
161
+ this.wallet
162
+ ),
163
+ USDT: new ethers.Contract(
164
+ this.chainConfig.tokens.USDT.address,
165
+ ERC20_ABI,
166
+ this.wallet
167
+ )
168
+ };
99
169
  }
100
170
  /**
101
- * Get wallet balance
171
+ * Get wallet balance for all tokens
102
172
  */
103
173
  async getBalance() {
104
- const [ethBalance, usdcBalance] = await Promise.all([
174
+ const [ethBalance, usdcBalance, usdtBalance] = await Promise.all([
105
175
  this.provider.getBalance(this.address),
106
- this.usdcContract.balanceOf(this.address)
176
+ this.tokenContracts.USDC.balanceOf(this.address),
177
+ this.tokenContracts.USDT.balanceOf(this.address)
107
178
  ]);
108
179
  return {
109
180
  address: this.address,
110
181
  eth: ethers.formatEther(ethBalance),
111
182
  usdc: (Number(usdcBalance) / 1e6).toFixed(2),
183
+ usdt: (Number(usdtBalance) / 1e6).toFixed(2),
112
184
  chain: this.chain
113
185
  };
114
186
  }
115
187
  /**
116
- * Send USDC transfer
188
+ * Send token transfer (USDC or USDT)
189
+ * @param to - recipient address
190
+ * @param amount - amount to send
191
+ * @param token - token to send (default: USDC)
117
192
  */
118
- async transfer(to, amount) {
193
+ async transfer(to, amount, token = "USDC") {
119
194
  try {
120
195
  to = ethers.getAddress(to);
121
- const amountWei = BigInt(Math.floor(amount * 1e6));
122
- const balance = await this.usdcContract.balanceOf(this.address);
196
+ const tokenContract = this.tokenContracts[token];
197
+ const tokenConfig = this.chainConfig.tokens[token];
198
+ if (!tokenContract || !tokenConfig) {
199
+ return {
200
+ success: false,
201
+ error: `Token ${token} not supported on ${this.chain}`
202
+ };
203
+ }
204
+ const decimals = tokenConfig.decimals;
205
+ const amountWei = BigInt(Math.floor(amount * 10 ** decimals));
206
+ const balance = await tokenContract.balanceOf(this.address);
123
207
  if (BigInt(balance) < amountWei) {
124
208
  return {
125
209
  success: false,
126
- error: `Insufficient USDC balance: ${Number(balance) / 1e6} < ${amount}`
210
+ error: `Insufficient ${token} balance: ${Number(balance) / 10 ** decimals} < ${amount}`
127
211
  };
128
212
  }
129
- const tx = await this.usdcContract.transfer(to, amountWei);
213
+ const tx = await tokenContract.transfer(to, amountWei);
130
214
  const receipt = await tx.wait();
131
215
  if (receipt.status === 1) {
132
216
  return {
@@ -135,6 +219,7 @@ var Wallet = class {
135
219
  from: this.address,
136
220
  to,
137
221
  amount,
222
+ token,
138
223
  gas_used: Number(receipt.gasUsed),
139
224
  block_number: receipt.blockNumber,
140
225
  explorer_url: `${this.chainConfig.explorerTx}${tx.hash}`
@@ -143,12 +228,14 @@ var Wallet = class {
143
228
  return {
144
229
  success: false,
145
230
  tx_hash: tx.hash,
231
+ token,
146
232
  error: "Transaction reverted"
147
233
  };
148
234
  }
149
235
  } catch (error) {
150
236
  return {
151
237
  success: false,
238
+ token,
152
239
  error: error.message
153
240
  };
154
241
  }
@@ -161,11 +248,20 @@ var Wallet = class {
161
248
  return ethers.formatEther(balance);
162
249
  }
163
250
  /**
164
- * Get USDC balance
251
+ * Get token balance
252
+ * @param token - token symbol (default: USDC)
253
+ */
254
+ async getTokenBalance(token = "USDC") {
255
+ const tokenContract = this.tokenContracts[token];
256
+ const tokenConfig = this.chainConfig.tokens[token];
257
+ const balance = await tokenContract.balanceOf(this.address);
258
+ return (Number(balance) / 10 ** tokenConfig.decimals).toFixed(2);
259
+ }
260
+ /**
261
+ * @deprecated Use getTokenBalance('USDC') instead
165
262
  */
166
263
  async getUsdcBalance() {
167
- const balance = await this.usdcContract.balanceOf(this.address);
168
- return (Number(balance) / 1e6).toFixed(2);
264
+ return this.getTokenBalance("USDC");
169
265
  }
170
266
  };
171
267
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/wallet/Wallet.ts","../../src/chains/index.ts","../../src/wallet/createWallet.ts"],"sourcesContent":["/**\n * Wallet - Basic Custody Wallet\n * \n * Features:\n * - Query balance\n * - Send USDC transfer\n */\n\nimport { ethers } from 'ethers';\nimport { getChain, ERC20_ABI } from '../chains/index.js';\nimport type {\n ChainName,\n ChainConfig,\n WalletBalance,\n TransferResult,\n} from '../types/index.js';\n\nexport interface WalletConfig {\n chain?: ChainName;\n privateKey?: string;\n rpcUrl?: string;\n}\n\nexport class Wallet {\n readonly chain: ChainName;\n readonly chainConfig: ChainConfig;\n readonly address: string;\n \n private wallet: ethers.Wallet;\n private provider: ethers.JsonRpcProvider;\n private usdcContract: ethers.Contract;\n\n constructor(config: WalletConfig = {}) {\n this.chain = config.chain || 'base_sepolia';\n this.chainConfig = getChain(this.chain);\n \n const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;\n if (!privateKey) {\n throw new Error('privateKey is required. Set via config or PAYMENT_AGENT_PRIVATE_KEY env var.');\n }\n\n const rpcUrl = config.rpcUrl || this.chainConfig.rpc;\n this.provider = new ethers.JsonRpcProvider(rpcUrl);\n this.wallet = new ethers.Wallet(privateKey, this.provider);\n this.address = this.wallet.address;\n \n this.usdcContract = new ethers.Contract(\n this.chainConfig.usdc,\n ERC20_ABI,\n this.wallet\n );\n }\n\n /**\n * Get wallet balance\n */\n async getBalance(): Promise<WalletBalance> {\n const [ethBalance, usdcBalance] = await Promise.all([\n this.provider.getBalance(this.address),\n this.usdcContract.balanceOf(this.address),\n ]);\n\n return {\n address: this.address,\n eth: ethers.formatEther(ethBalance),\n usdc: (Number(usdcBalance) / 1e6).toFixed(2),\n chain: this.chain,\n };\n }\n\n /**\n * Send USDC transfer\n */\n async transfer(to: string, amount: number): Promise<TransferResult> {\n try {\n // Validate address\n to = ethers.getAddress(to);\n \n // Convert amount (USDC 6 decimals)\n const amountWei = BigInt(Math.floor(amount * 1e6));\n\n // Check balance\n const balance = await this.usdcContract.balanceOf(this.address);\n if (BigInt(balance) < amountWei) {\n return {\n success: false,\n error: `Insufficient USDC balance: ${Number(balance) / 1e6} < ${amount}`,\n };\n }\n\n // Send transaction\n const tx = await this.usdcContract.transfer(to, amountWei);\n const receipt = await tx.wait();\n\n if (receipt.status === 1) {\n return {\n success: true,\n tx_hash: tx.hash,\n from: this.address,\n to,\n amount,\n gas_used: Number(receipt.gasUsed),\n block_number: receipt.blockNumber,\n explorer_url: `${this.chainConfig.explorerTx}${tx.hash}`,\n };\n } else {\n return {\n success: false,\n tx_hash: tx.hash,\n error: 'Transaction reverted',\n };\n }\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n }\n\n /**\n * Get ETH balance\n */\n async getEthBalance(): Promise<string> {\n const balance = await this.provider.getBalance(this.address);\n return ethers.formatEther(balance);\n }\n\n /**\n * Get USDC balance\n */\n async getUsdcBalance(): Promise<string> {\n const balance = await this.usdcContract.balanceOf(this.address);\n return (Number(balance) / 1e6).toFixed(2);\n }\n}\n","/**\n * Blockchain Configuration\n */\n\nimport type { ChainConfig, ChainName } from '../types/index.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n // ============ Mainnet ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-rpc.com',\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n rpc: 'https://eth.llamarpc.com',\n usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n explorer: 'https://etherscan.io/address/',\n explorerTx: 'https://etherscan.io/tx/',\n avgBlockTime: 12,\n },\n\n // ============ Testnet ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n sepolia: {\n name: 'Sepolia',\n chainId: 11155111,\n rpc: 'https://rpc.sepolia.org',\n usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n explorer: 'https://sepolia.etherscan.io/address/',\n explorerTx: 'https://sepolia.etherscan.io/tx/',\n avgBlockTime: 12,\n },\n};\n\n/**\n * Get chain configuration\n */\nexport function getChain(name: ChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * List all supported chains\n */\nexport function listChains(): ChainName[] {\n return Object.keys(CHAINS) as ChainName[];\n}\n\n/**\n * Get chain config by chainId\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n/**\n * ERC20 ABI (minimal, only required methods)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName };\n","/**\n * createWallet - Create a new wallet for Agent\n * \n * Features:\n * - Generate new Ethereum wallet\n * - Securely store private key (encrypted or plaintext, depending on config)\n * - Return wallet address (never return private key)\n */\n\nimport { ethers } from 'ethers';\nimport { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'crypto';\n\nexport interface CreateWalletOptions {\n /** Storage path, default ~/.moltspay/wallet.json */\n storagePath?: string;\n /** Encryption password (optional, plaintext if not provided) */\n password?: string;\n /** Wallet label/name */\n label?: string;\n /** Overwrite if wallet exists */\n overwrite?: boolean;\n}\n\nexport interface WalletData {\n address: string;\n label?: string;\n createdAt: string;\n encrypted: boolean;\n /** Encrypted or plaintext private key */\n privateKey: string;\n /** Encryption IV */\n iv?: string;\n /** Encryption salt */\n salt?: string;\n}\n\nexport interface CreateWalletResult {\n success: boolean;\n address?: string;\n storagePath?: string;\n error?: string;\n /** Whether newly created (false means loaded existing) */\n isNew?: boolean;\n}\n\nconst DEFAULT_STORAGE_DIR = join(process.env.HOME || '~', '.moltspay');\nconst DEFAULT_STORAGE_FILE = 'wallet.json';\n\n/**\n * Encrypt private key\n */\nfunction encryptPrivateKey(privateKey: string, password: string): { encrypted: string; iv: string; salt: string } {\n const salt = randomBytes(16);\n const key = scryptSync(password, salt, 32);\n const iv = randomBytes(16);\n \n const cipher = createCipheriv('aes-256-cbc', key, iv);\n let encrypted = cipher.update(privateKey, 'utf8', 'hex');\n encrypted += cipher.final('hex');\n \n return {\n encrypted,\n iv: iv.toString('hex'),\n salt: salt.toString('hex'),\n };\n}\n\n/**\n * Decrypt private key\n */\nfunction decryptPrivateKey(encrypted: string, password: string, iv: string, salt: string): string {\n const key = scryptSync(password, Buffer.from(salt, 'hex'), 32);\n const decipher = createDecipheriv('aes-256-cbc', key, Buffer.from(iv, 'hex'));\n \n let decrypted = decipher.update(encrypted, 'hex', 'utf8');\n decrypted += decipher.final('utf8');\n \n return decrypted;\n}\n\n/**\n * Create new wallet\n * \n * @example\n * ```typescript\n * // Create unencrypted wallet\n * const result = await createWallet();\n * console.log('Wallet address:', result.address);\n * \n * // Create encrypted wallet\n * const result = await createWallet({ password: 'mySecurePassword' });\n * \n * // Specify storage path\n * const result = await createWallet({ storagePath: './my-wallet.json' });\n * ```\n */\nexport function createWallet(options: CreateWalletOptions = {}): CreateWalletResult {\n const storagePath = options.storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n \n // Check if exists\n if (existsSync(storagePath) && !options.overwrite) {\n // Load existing wallet\n try {\n const existing = JSON.parse(readFileSync(storagePath, 'utf8')) as WalletData;\n return {\n success: true,\n address: existing.address,\n storagePath,\n isNew: false,\n };\n } catch (error) {\n return {\n success: false,\n error: `Failed to load existing wallet: ${(error as Error).message}`,\n };\n }\n }\n\n try {\n // Create new wallet\n const wallet = ethers.Wallet.createRandom();\n \n // Prepare storage data\n const walletData: WalletData = {\n address: wallet.address,\n label: options.label,\n createdAt: new Date().toISOString(),\n encrypted: !!options.password,\n privateKey: '',\n };\n\n if (options.password) {\n // Encrypted storage\n const { encrypted, iv, salt } = encryptPrivateKey(wallet.privateKey, options.password);\n walletData.privateKey = encrypted;\n walletData.iv = iv;\n walletData.salt = salt;\n } else {\n // Plaintext storage (not recommended, but convenient for testing/dev)\n walletData.privateKey = wallet.privateKey;\n }\n\n // Ensure directory exists\n const dir = dirname(storagePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Write file\n writeFileSync(storagePath, JSON.stringify(walletData, null, 2), { mode: 0o600 });\n\n return {\n success: true,\n address: wallet.address,\n storagePath,\n isNew: true,\n };\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n}\n\n/**\n * Load existing wallet\n */\nexport function loadWallet(options: { storagePath?: string; password?: string } = {}): {\n success: boolean;\n address?: string;\n privateKey?: string;\n error?: string;\n} {\n const storagePath = options.storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n\n if (!existsSync(storagePath)) {\n return { success: false, error: 'Wallet not found. Run createWallet() first.' };\n }\n\n try {\n const data = JSON.parse(readFileSync(storagePath, 'utf8')) as WalletData;\n\n if (data.encrypted) {\n if (!options.password) {\n return { success: false, error: 'Wallet is encrypted. Password required.' };\n }\n const privateKey = decryptPrivateKey(data.privateKey, options.password, data.iv!, data.salt!);\n return { success: true, address: data.address, privateKey };\n } else {\n return { success: true, address: data.address, privateKey: data.privateKey };\n }\n } catch (error) {\n return { success: false, error: (error as Error).message };\n }\n}\n\n/**\n * Get wallet address (no password required)\n */\nexport function getWalletAddress(storagePath?: string): string | null {\n const path = storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n \n if (!existsSync(path)) {\n return null;\n }\n\n try {\n const data = JSON.parse(readFileSync(path, 'utf8')) as WalletData;\n return data.address;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if wallet exists\n */\nexport function walletExists(storagePath?: string): boolean {\n const path = storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n return existsSync(path);\n}\n"],"mappings":"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","names":["ethers"]}
1
+ {"version":3,"sources":["../../src/wallet/Wallet.ts","../../src/chains/index.ts","../../src/wallet/createWallet.ts"],"sourcesContent":["/**\n * Wallet - Basic Custody Wallet\n * \n * Features:\n * - Query balance (USDC, USDT, ETH)\n * - Send token transfers (USDC or USDT)\n */\n\nimport { ethers } from 'ethers';\nimport { getChain, ERC20_ABI } from '../chains/index.js';\nimport type {\n ChainName,\n ChainConfig,\n WalletBalance,\n TransferResult,\n TokenSymbol,\n} from '../types/index.js';\n\nexport interface WalletConfig {\n chain?: ChainName;\n privateKey?: string;\n rpcUrl?: string;\n}\n\nexport class Wallet {\n readonly chain: ChainName;\n readonly chainConfig: ChainConfig;\n readonly address: string;\n \n private wallet: ethers.Wallet;\n private provider: ethers.JsonRpcProvider;\n private tokenContracts: Record<TokenSymbol, ethers.Contract>;\n\n constructor(config: WalletConfig = {}) {\n this.chain = config.chain || 'base_sepolia';\n this.chainConfig = getChain(this.chain);\n \n const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;\n if (!privateKey) {\n throw new Error('privateKey is required. Set via config or PAYMENT_AGENT_PRIVATE_KEY env var.');\n }\n\n const rpcUrl = config.rpcUrl || this.chainConfig.rpc;\n this.provider = new ethers.JsonRpcProvider(rpcUrl);\n this.wallet = new ethers.Wallet(privateKey, this.provider);\n this.address = this.wallet.address;\n \n // Initialize token contracts\n this.tokenContracts = {\n USDC: new ethers.Contract(\n this.chainConfig.tokens.USDC.address,\n ERC20_ABI,\n this.wallet\n ),\n USDT: new ethers.Contract(\n this.chainConfig.tokens.USDT.address,\n ERC20_ABI,\n this.wallet\n ),\n };\n }\n\n /**\n * Get wallet balance for all tokens\n */\n async getBalance(): Promise<WalletBalance> {\n const [ethBalance, usdcBalance, usdtBalance] = await Promise.all([\n this.provider.getBalance(this.address),\n this.tokenContracts.USDC.balanceOf(this.address),\n this.tokenContracts.USDT.balanceOf(this.address),\n ]);\n\n return {\n address: this.address,\n eth: ethers.formatEther(ethBalance),\n usdc: (Number(usdcBalance) / 1e6).toFixed(2),\n usdt: (Number(usdtBalance) / 1e6).toFixed(2),\n chain: this.chain,\n };\n }\n\n /**\n * Send token transfer (USDC or USDT)\n * @param to - recipient address\n * @param amount - amount to send\n * @param token - token to send (default: USDC)\n */\n async transfer(to: string, amount: number, token: TokenSymbol = 'USDC'): Promise<TransferResult> {\n try {\n // Validate address\n to = ethers.getAddress(to);\n \n // Get token contract and config\n const tokenContract = this.tokenContracts[token];\n const tokenConfig = this.chainConfig.tokens[token];\n \n if (!tokenContract || !tokenConfig) {\n return {\n success: false,\n error: `Token ${token} not supported on ${this.chain}`,\n };\n }\n \n // Convert amount (both USDC and USDT have 6 decimals)\n const decimals = tokenConfig.decimals;\n const amountWei = BigInt(Math.floor(amount * (10 ** decimals)));\n\n // Check balance\n const balance = await tokenContract.balanceOf(this.address);\n if (BigInt(balance) < amountWei) {\n return {\n success: false,\n error: `Insufficient ${token} balance: ${Number(balance) / (10 ** decimals)} < ${amount}`,\n };\n }\n\n // Send transaction\n const tx = await tokenContract.transfer(to, amountWei);\n const receipt = await tx.wait();\n\n if (receipt.status === 1) {\n return {\n success: true,\n tx_hash: tx.hash,\n from: this.address,\n to,\n amount,\n token,\n gas_used: Number(receipt.gasUsed),\n block_number: receipt.blockNumber,\n explorer_url: `${this.chainConfig.explorerTx}${tx.hash}`,\n };\n } else {\n return {\n success: false,\n tx_hash: tx.hash,\n token,\n error: 'Transaction reverted',\n };\n }\n } catch (error) {\n return {\n success: false,\n token,\n error: (error as Error).message,\n };\n }\n }\n\n /**\n * Get ETH balance\n */\n async getEthBalance(): Promise<string> {\n const balance = await this.provider.getBalance(this.address);\n return ethers.formatEther(balance);\n }\n\n /**\n * Get token balance\n * @param token - token symbol (default: USDC)\n */\n async getTokenBalance(token: TokenSymbol = 'USDC'): Promise<string> {\n const tokenContract = this.tokenContracts[token];\n const tokenConfig = this.chainConfig.tokens[token];\n const balance = await tokenContract.balanceOf(this.address);\n return (Number(balance) / (10 ** tokenConfig.decimals)).toFixed(2);\n }\n\n /**\n * @deprecated Use getTokenBalance('USDC') instead\n */\n async getUsdcBalance(): Promise<string> {\n return this.getTokenBalance('USDC');\n }\n}\n","/**\n * Blockchain Configuration\n */\n\nimport type { ChainConfig, ChainName, TokenSymbol } from '../types/index.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n // ============ Mainnet ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n tokens: {\n USDC: {\n address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n decimals: 6,\n symbol: 'USDC',\n },\n USDT: {\n address: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2',\n decimals: 6,\n symbol: 'USDT',\n },\n },\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // deprecated, for backward compat\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-rpc.com',\n tokens: {\n USDC: {\n address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n decimals: 6,\n symbol: 'USDC',\n },\n USDT: {\n address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',\n decimals: 6,\n symbol: 'USDT',\n },\n },\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n rpc: 'https://eth.llamarpc.com',\n tokens: {\n USDC: {\n address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n decimals: 6,\n symbol: 'USDC',\n },\n USDT: {\n address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',\n decimals: 6,\n symbol: 'USDT',\n },\n },\n usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n explorer: 'https://etherscan.io/address/',\n explorerTx: 'https://etherscan.io/tx/',\n avgBlockTime: 12,\n },\n\n // ============ Testnet ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n tokens: {\n USDC: {\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n decimals: 6,\n symbol: 'USDC',\n },\n USDT: {\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Same as USDC on testnet (no official USDT)\n decimals: 6,\n symbol: 'USDT',\n },\n },\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n sepolia: {\n name: 'Sepolia',\n chainId: 11155111,\n rpc: 'https://rpc.sepolia.org',\n tokens: {\n USDC: {\n address: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n decimals: 6,\n symbol: 'USDC',\n },\n USDT: {\n address: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', // Same as USDC on testnet\n decimals: 6,\n symbol: 'USDT',\n },\n },\n usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n explorer: 'https://sepolia.etherscan.io/address/',\n explorerTx: 'https://sepolia.etherscan.io/tx/',\n avgBlockTime: 12,\n },\n};\n\n/**\n * Get token address for a chain\n */\nexport function getTokenAddress(chainName: ChainName, token: TokenSymbol): string {\n const chain = CHAINS[chainName];\n if (!chain) {\n throw new Error(`Unsupported chain: ${chainName}`);\n }\n const tokenConfig = chain.tokens[token];\n if (!tokenConfig) {\n throw new Error(`Token ${token} not supported on ${chainName}`);\n }\n return tokenConfig.address;\n}\n\n/**\n * Get token config for a chain\n */\nexport function getTokenConfig(chainName: ChainName, token: TokenSymbol) {\n const chain = CHAINS[chainName];\n if (!chain) {\n throw new Error(`Unsupported chain: ${chainName}`);\n }\n return chain.tokens[token];\n}\n\n/**\n * Get chain configuration\n */\nexport function getChain(name: ChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * List all supported chains\n */\nexport function listChains(): ChainName[] {\n return Object.keys(CHAINS) as ChainName[];\n}\n\n/**\n * Get chain config by chainId\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n/**\n * ERC20 ABI (minimal, only required methods)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName, TokenSymbol };\n","/**\n * createWallet - Create a new wallet for Agent\n * \n * Features:\n * - Generate new Ethereum wallet\n * - Securely store private key (encrypted or plaintext, depending on config)\n * - Return wallet address (never return private key)\n */\n\nimport { ethers } from 'ethers';\nimport { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'crypto';\n\nexport interface CreateWalletOptions {\n /** Storage path, default ~/.moltspay/wallet.json */\n storagePath?: string;\n /** Encryption password (optional, plaintext if not provided) */\n password?: string;\n /** Wallet label/name */\n label?: string;\n /** Overwrite if wallet exists */\n overwrite?: boolean;\n}\n\nexport interface WalletData {\n address: string;\n label?: string;\n createdAt: string;\n encrypted: boolean;\n /** Encrypted or plaintext private key */\n privateKey: string;\n /** Encryption IV */\n iv?: string;\n /** Encryption salt */\n salt?: string;\n}\n\nexport interface CreateWalletResult {\n success: boolean;\n address?: string;\n storagePath?: string;\n error?: string;\n /** Whether newly created (false means loaded existing) */\n isNew?: boolean;\n}\n\nconst DEFAULT_STORAGE_DIR = join(process.env.HOME || '~', '.moltspay');\nconst DEFAULT_STORAGE_FILE = 'wallet.json';\n\n/**\n * Encrypt private key\n */\nfunction encryptPrivateKey(privateKey: string, password: string): { encrypted: string; iv: string; salt: string } {\n const salt = randomBytes(16);\n const key = scryptSync(password, salt, 32);\n const iv = randomBytes(16);\n \n const cipher = createCipheriv('aes-256-cbc', key, iv);\n let encrypted = cipher.update(privateKey, 'utf8', 'hex');\n encrypted += cipher.final('hex');\n \n return {\n encrypted,\n iv: iv.toString('hex'),\n salt: salt.toString('hex'),\n };\n}\n\n/**\n * Decrypt private key\n */\nfunction decryptPrivateKey(encrypted: string, password: string, iv: string, salt: string): string {\n const key = scryptSync(password, Buffer.from(salt, 'hex'), 32);\n const decipher = createDecipheriv('aes-256-cbc', key, Buffer.from(iv, 'hex'));\n \n let decrypted = decipher.update(encrypted, 'hex', 'utf8');\n decrypted += decipher.final('utf8');\n \n return decrypted;\n}\n\n/**\n * Create new wallet\n * \n * @example\n * ```typescript\n * // Create unencrypted wallet\n * const result = await createWallet();\n * console.log('Wallet address:', result.address);\n * \n * // Create encrypted wallet\n * const result = await createWallet({ password: 'mySecurePassword' });\n * \n * // Specify storage path\n * const result = await createWallet({ storagePath: './my-wallet.json' });\n * ```\n */\nexport function createWallet(options: CreateWalletOptions = {}): CreateWalletResult {\n const storagePath = options.storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n \n // Check if exists\n if (existsSync(storagePath) && !options.overwrite) {\n // Load existing wallet\n try {\n const existing = JSON.parse(readFileSync(storagePath, 'utf8')) as WalletData;\n return {\n success: true,\n address: existing.address,\n storagePath,\n isNew: false,\n };\n } catch (error) {\n return {\n success: false,\n error: `Failed to load existing wallet: ${(error as Error).message}`,\n };\n }\n }\n\n try {\n // Create new wallet\n const wallet = ethers.Wallet.createRandom();\n \n // Prepare storage data\n const walletData: WalletData = {\n address: wallet.address,\n label: options.label,\n createdAt: new Date().toISOString(),\n encrypted: !!options.password,\n privateKey: '',\n };\n\n if (options.password) {\n // Encrypted storage\n const { encrypted, iv, salt } = encryptPrivateKey(wallet.privateKey, options.password);\n walletData.privateKey = encrypted;\n walletData.iv = iv;\n walletData.salt = salt;\n } else {\n // Plaintext storage (not recommended, but convenient for testing/dev)\n walletData.privateKey = wallet.privateKey;\n }\n\n // Ensure directory exists\n const dir = dirname(storagePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n // Write file\n writeFileSync(storagePath, JSON.stringify(walletData, null, 2), { mode: 0o600 });\n\n return {\n success: true,\n address: wallet.address,\n storagePath,\n isNew: true,\n };\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n}\n\n/**\n * Load existing wallet\n */\nexport function loadWallet(options: { storagePath?: string; password?: string } = {}): {\n success: boolean;\n address?: string;\n privateKey?: string;\n error?: string;\n} {\n const storagePath = options.storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n\n if (!existsSync(storagePath)) {\n return { success: false, error: 'Wallet not found. Run createWallet() first.' };\n }\n\n try {\n const data = JSON.parse(readFileSync(storagePath, 'utf8')) as WalletData;\n\n if (data.encrypted) {\n if (!options.password) {\n return { success: false, error: 'Wallet is encrypted. Password required.' };\n }\n const privateKey = decryptPrivateKey(data.privateKey, options.password, data.iv!, data.salt!);\n return { success: true, address: data.address, privateKey };\n } else {\n return { success: true, address: data.address, privateKey: data.privateKey };\n }\n } catch (error) {\n return { success: false, error: (error as Error).message };\n }\n}\n\n/**\n * Get wallet address (no password required)\n */\nexport function getWalletAddress(storagePath?: string): string | null {\n const path = storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n \n if (!existsSync(path)) {\n return null;\n }\n\n try {\n const data = JSON.parse(readFileSync(path, 'utf8')) as WalletData;\n return data.address;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if wallet exists\n */\nexport function walletExists(storagePath?: string): boolean {\n const path = storagePath || join(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);\n return existsSync(path);\n}\n"],"mappings":";AAQA,SAAS,cAAc;;;ACFhB,IAAM,SAAyC;AAAA;AAAA,EAEpD,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,QAAQ;AAAA,MACN,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,MAAM;AAAA;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,QAAQ;AAAA,MACN,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,QAAQ;AAAA,MACN,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA;AAAA,EAGA,cAAc;AAAA,IACZ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,QAAQ;AAAA,MACN,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA,QACJ,SAAS;AAAA;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,QAAQ;AAAA,MACN,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,MACV;AAAA,MACA,MAAM;AAAA,QACJ,SAAS;AAAA;AAAA,QACT,UAAU;AAAA,QACV,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,IACA,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB;AACF;AA+BO,SAAS,SAAS,MAA8B;AACrD,QAAM,SAAS,OAAO,IAAI;AAC1B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,sBAAsB,IAAI,gBAAgB,OAAO,KAAK,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,EAC5F;AACA,SAAO;AACT;AAmBO,IAAM,YAAY;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;AD/JO,IAAM,SAAN,MAAa;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EAED;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,SAAuB,CAAC,GAAG;AACrC,SAAK,QAAQ,OAAO,SAAS;AAC7B,SAAK,cAAc,SAAS,KAAK,KAAK;AAEtC,UAAM,aAAa,OAAO,cAAc,QAAQ,IAAI;AACpD,QAAI,CAAC,YAAY;AACf,YAAM,IAAI,MAAM,8EAA8E;AAAA,IAChG;AAEA,UAAM,SAAS,OAAO,UAAU,KAAK,YAAY;AACjD,SAAK,WAAW,IAAI,OAAO,gBAAgB,MAAM;AACjD,SAAK,SAAS,IAAI,OAAO,OAAO,YAAY,KAAK,QAAQ;AACzD,SAAK,UAAU,KAAK,OAAO;AAG3B,SAAK,iBAAiB;AAAA,MACpB,MAAM,IAAI,OAAO;AAAA,QACf,KAAK,YAAY,OAAO,KAAK;AAAA,QAC7B;AAAA,QACA,KAAK;AAAA,MACP;AAAA,MACA,MAAM,IAAI,OAAO;AAAA,QACf,KAAK,YAAY,OAAO,KAAK;AAAA,QAC7B;AAAA,QACA,KAAK;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAqC;AACzC,UAAM,CAAC,YAAY,aAAa,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC/D,KAAK,SAAS,WAAW,KAAK,OAAO;AAAA,MACrC,KAAK,eAAe,KAAK,UAAU,KAAK,OAAO;AAAA,MAC/C,KAAK,eAAe,KAAK,UAAU,KAAK,OAAO;AAAA,IACjD,CAAC;AAED,WAAO;AAAA,MACL,SAAS,KAAK;AAAA,MACd,KAAK,OAAO,YAAY,UAAU;AAAA,MAClC,OAAO,OAAO,WAAW,IAAI,KAAK,QAAQ,CAAC;AAAA,MAC3C,OAAO,OAAO,WAAW,IAAI,KAAK,QAAQ,CAAC;AAAA,MAC3C,OAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SAAS,IAAY,QAAgB,QAAqB,QAAiC;AAC/F,QAAI;AAEF,WAAK,OAAO,WAAW,EAAE;AAGzB,YAAM,gBAAgB,KAAK,eAAe,KAAK;AAC/C,YAAM,cAAc,KAAK,YAAY,OAAO,KAAK;AAEjD,UAAI,CAAC,iBAAiB,CAAC,aAAa;AAClC,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,SAAS,KAAK,qBAAqB,KAAK,KAAK;AAAA,QACtD;AAAA,MACF;AAGA,YAAM,WAAW,YAAY;AAC7B,YAAM,YAAY,OAAO,KAAK,MAAM,SAAU,MAAM,QAAS,CAAC;AAG9D,YAAM,UAAU,MAAM,cAAc,UAAU,KAAK,OAAO;AAC1D,UAAI,OAAO,OAAO,IAAI,WAAW;AAC/B,eAAO;AAAA,UACL,SAAS;AAAA,UACT,OAAO,gBAAgB,KAAK,aAAa,OAAO,OAAO,IAAK,MAAM,QAAS,MAAM,MAAM;AAAA,QACzF;AAAA,MACF;AAGA,YAAM,KAAK,MAAM,cAAc,SAAS,IAAI,SAAS;AACrD,YAAM,UAAU,MAAM,GAAG,KAAK;AAE9B,UAAI,QAAQ,WAAW,GAAG;AACxB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS,GAAG;AAAA,UACZ,MAAM,KAAK;AAAA,UACX;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU,OAAO,QAAQ,OAAO;AAAA,UAChC,cAAc,QAAQ;AAAA,UACtB,cAAc,GAAG,KAAK,YAAY,UAAU,GAAG,GAAG,IAAI;AAAA,QACxD;AAAA,MACF,OAAO;AACL,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS,GAAG;AAAA,UACZ;AAAA,UACA,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT;AAAA,QACA,OAAQ,MAAgB;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAiC;AACrC,UAAM,UAAU,MAAM,KAAK,SAAS,WAAW,KAAK,OAAO;AAC3D,WAAO,OAAO,YAAY,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,QAAqB,QAAyB;AAClE,UAAM,gBAAgB,KAAK,eAAe,KAAK;AAC/C,UAAM,cAAc,KAAK,YAAY,OAAO,KAAK;AACjD,UAAM,UAAU,MAAM,cAAc,UAAU,KAAK,OAAO;AAC1D,YAAQ,OAAO,OAAO,IAAK,MAAM,YAAY,UAAW,QAAQ,CAAC;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAkC;AACtC,WAAO,KAAK,gBAAgB,MAAM;AAAA,EACpC;AACF;;;AErKA,SAAS,UAAAA,eAAc;AACvB,SAAS,eAAe,cAAc,YAAY,iBAAiB;AACnE,SAAS,MAAM,eAAe;AAC9B,SAAS,gBAAgB,kBAAkB,aAAa,kBAAkB;AAmC1E,IAAM,sBAAsB,KAAK,QAAQ,IAAI,QAAQ,KAAK,WAAW;AACrE,IAAM,uBAAuB;AAK7B,SAAS,kBAAkB,YAAoB,UAAmE;AAChH,QAAM,OAAO,YAAY,EAAE;AAC3B,QAAM,MAAM,WAAW,UAAU,MAAM,EAAE;AACzC,QAAM,KAAK,YAAY,EAAE;AAEzB,QAAM,SAAS,eAAe,eAAe,KAAK,EAAE;AACpD,MAAI,YAAY,OAAO,OAAO,YAAY,QAAQ,KAAK;AACvD,eAAa,OAAO,MAAM,KAAK;AAE/B,SAAO;AAAA,IACL;AAAA,IACA,IAAI,GAAG,SAAS,KAAK;AAAA,IACrB,MAAM,KAAK,SAAS,KAAK;AAAA,EAC3B;AACF;AAKA,SAAS,kBAAkB,WAAmB,UAAkB,IAAY,MAAsB;AAChG,QAAM,MAAM,WAAW,UAAU,OAAO,KAAK,MAAM,KAAK,GAAG,EAAE;AAC7D,QAAM,WAAW,iBAAiB,eAAe,KAAK,OAAO,KAAK,IAAI,KAAK,CAAC;AAE5E,MAAI,YAAY,SAAS,OAAO,WAAW,OAAO,MAAM;AACxD,eAAa,SAAS,MAAM,MAAM;AAElC,SAAO;AACT;AAkBO,SAAS,aAAa,UAA+B,CAAC,GAAuB;AAClF,QAAM,cAAc,QAAQ,eAAe,KAAK,qBAAqB,oBAAoB;AAGzF,MAAI,WAAW,WAAW,KAAK,CAAC,QAAQ,WAAW;AAEjD,QAAI;AACF,YAAM,WAAW,KAAK,MAAM,aAAa,aAAa,MAAM,CAAC;AAC7D,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,SAAS;AAAA,QAClB;AAAA,QACA,OAAO;AAAA,MACT;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO,mCAAoC,MAAgB,OAAO;AAAA,MACpE;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AAEF,UAAM,SAASA,QAAO,OAAO,aAAa;AAG1C,UAAM,aAAyB;AAAA,MAC7B,SAAS,OAAO;AAAA,MAChB,OAAO,QAAQ;AAAA,MACf,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,WAAW,CAAC,CAAC,QAAQ;AAAA,MACrB,YAAY;AAAA,IACd;AAEA,QAAI,QAAQ,UAAU;AAEpB,YAAM,EAAE,WAAW,IAAI,KAAK,IAAI,kBAAkB,OAAO,YAAY,QAAQ,QAAQ;AACrF,iBAAW,aAAa;AACxB,iBAAW,KAAK;AAChB,iBAAW,OAAO;AAAA,IACpB,OAAO;AAEL,iBAAW,aAAa,OAAO;AAAA,IACjC;AAGA,UAAM,MAAM,QAAQ,WAAW;AAC/B,QAAI,CAAC,WAAW,GAAG,GAAG;AACpB,gBAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACpC;AAGA,kBAAc,aAAa,KAAK,UAAU,YAAY,MAAM,CAAC,GAAG,EAAE,MAAM,IAAM,CAAC;AAE/E,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS,OAAO;AAAA,MAChB;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAQ,MAAgB;AAAA,IAC1B;AAAA,EACF;AACF;AAKO,SAAS,WAAW,UAAuD,CAAC,GAKjF;AACA,QAAM,cAAc,QAAQ,eAAe,KAAK,qBAAqB,oBAAoB;AAEzF,MAAI,CAAC,WAAW,WAAW,GAAG;AAC5B,WAAO,EAAE,SAAS,OAAO,OAAO,8CAA8C;AAAA,EAChF;AAEA,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,aAAa,aAAa,MAAM,CAAC;AAEzD,QAAI,KAAK,WAAW;AAClB,UAAI,CAAC,QAAQ,UAAU;AACrB,eAAO,EAAE,SAAS,OAAO,OAAO,0CAA0C;AAAA,MAC5E;AACA,YAAM,aAAa,kBAAkB,KAAK,YAAY,QAAQ,UAAU,KAAK,IAAK,KAAK,IAAK;AAC5F,aAAO,EAAE,SAAS,MAAM,SAAS,KAAK,SAAS,WAAW;AAAA,IAC5D,OAAO;AACL,aAAO,EAAE,SAAS,MAAM,SAAS,KAAK,SAAS,YAAY,KAAK,WAAW;AAAA,IAC7E;AAAA,EACF,SAAS,OAAO;AACd,WAAO,EAAE,SAAS,OAAO,OAAQ,MAAgB,QAAQ;AAAA,EAC3D;AACF;AAKO,SAAS,iBAAiB,aAAqC;AACpE,QAAM,OAAO,eAAe,KAAK,qBAAqB,oBAAoB;AAE1E,MAAI,CAAC,WAAW,IAAI,GAAG;AACrB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,OAAO,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;AAClD,WAAO,KAAK;AAAA,EACd,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,aAAa,aAA+B;AAC1D,QAAM,OAAO,eAAe,KAAK,qBAAqB,oBAAoB;AAC1E,SAAO,WAAW,IAAI;AACxB;","names":["ethers"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moltspay",
3
- "version": "0.9.5",
3
+ "version": "0.9.7",
4
4
  "description": "Payment infrastructure for AI Agents - Server & Client SDK",
5
5
  "keywords": [
6
6
  "ai-agent",
@@ -68,9 +68,18 @@
68
68
  },
69
69
  "currency": {
70
70
  "type": "string",
71
- "enum": ["USDC", "USDT", "DAI"],
71
+ "enum": ["USDC", "USDT"],
72
72
  "default": "USDC",
73
- "description": "Payment currency"
73
+ "description": "Primary/display currency for pricing"
74
+ },
75
+ "acceptedCurrencies": {
76
+ "type": "array",
77
+ "items": {
78
+ "type": "string",
79
+ "enum": ["USDC", "USDT"]
80
+ },
81
+ "description": "Tokens accepted for payment. If not specified, defaults to [currency].",
82
+ "examples": [["USDC", "USDT"]]
74
83
  },
75
84
  "input": {
76
85
  "type": "object",
@@ -126,7 +135,8 @@
126
135
  "id": "text-to-video",
127
136
  "function": "textToVideo",
128
137
  "price": 0.99,
129
- "currency": "USDC"
138
+ "currency": "USDC",
139
+ "acceptedCurrencies": ["USDC", "USDT"]
130
140
  }
131
141
  ]
132
142
  }