moltspay 1.3.0 → 1.4.1
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/.env.example +14 -0
- package/README.md +319 -89
- package/dist/cdp/index.d.mts +4 -4
- package/dist/cdp/index.d.ts +4 -4
- package/dist/cdp/index.js +57 -0
- package/dist/cdp/index.js.map +1 -1
- package/dist/cdp/index.mjs +57 -0
- package/dist/cdp/index.mjs.map +1 -1
- package/dist/chains/index.d.mts +9 -8
- package/dist/chains/index.d.ts +9 -8
- package/dist/chains/index.js +57 -0
- package/dist/chains/index.js.map +1 -1
- package/dist/chains/index.mjs +57 -0
- package/dist/chains/index.mjs.map +1 -1
- package/dist/cli/index.js +2021 -285
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +2023 -277
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/index.d.mts +39 -3
- package/dist/client/index.d.ts +39 -3
- package/dist/client/index.js +563 -37
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +571 -35
- package/dist/client/index.mjs.map +1 -1
- package/dist/facilitators/index.d.mts +220 -1
- package/dist/facilitators/index.d.ts +220 -1
- package/dist/facilitators/index.js +664 -1
- package/dist/facilitators/index.js.map +1 -1
- package/dist/facilitators/index.mjs +670 -1
- package/dist/facilitators/index.mjs.map +1 -1
- package/dist/{index-On9ZaGDW.d.mts → index-D_2FkLwV.d.mts} +6 -2
- package/dist/{index-On9ZaGDW.d.ts → index-D_2FkLwV.d.ts} +6 -2
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1440 -153
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1448 -151
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.d.mts +13 -3
- package/dist/server/index.d.ts +13 -3
- package/dist/server/index.js +909 -54
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +919 -54
- package/dist/server/index.mjs.map +1 -1
- package/dist/verify/index.d.mts +1 -1
- package/dist/verify/index.d.ts +1 -1
- package/dist/verify/index.js +57 -0
- package/dist/verify/index.js.map +1 -1
- package/dist/verify/index.mjs +57 -0
- package/dist/verify/index.mjs.map +1 -1
- package/dist/wallet/index.d.mts +3 -3
- package/dist/wallet/index.d.ts +3 -3
- package/dist/wallet/index.js +57 -0
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +57 -0
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +5 -2
- package/schemas/moltspay.services.schema.json +27 -132
package/dist/wallet/index.mjs
CHANGED
|
@@ -108,6 +108,63 @@ var CHAINS = {
|
|
|
108
108
|
explorerTx: "https://explore.testnet.tempo.xyz/tx/",
|
|
109
109
|
avgBlockTime: 0.5
|
|
110
110
|
// ~500ms finality
|
|
111
|
+
},
|
|
112
|
+
// ============ BNB Chain Testnet ============
|
|
113
|
+
bnb_testnet: {
|
|
114
|
+
name: "BNB Testnet",
|
|
115
|
+
chainId: 97,
|
|
116
|
+
rpc: "https://data-seed-prebsc-1-s1.binance.org:8545",
|
|
117
|
+
tokens: {
|
|
118
|
+
// Note: BNB uses 18 decimals for stablecoins (unlike Base/Polygon which use 6)
|
|
119
|
+
// Using official Binance-Peg testnet tokens
|
|
120
|
+
USDC: {
|
|
121
|
+
address: "0x64544969ed7EBf5f083679233325356EbE738930",
|
|
122
|
+
// Testnet USDC
|
|
123
|
+
decimals: 18,
|
|
124
|
+
symbol: "USDC",
|
|
125
|
+
eip712Name: "USD Coin"
|
|
126
|
+
},
|
|
127
|
+
USDT: {
|
|
128
|
+
address: "0x337610d27c682E347C9cD60BD4b3b107C9d34dDd",
|
|
129
|
+
// Testnet USDT
|
|
130
|
+
decimals: 18,
|
|
131
|
+
symbol: "USDT",
|
|
132
|
+
eip712Name: "Tether USD"
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
usdc: "0x64544969ed7EBf5f083679233325356EbE738930",
|
|
136
|
+
explorer: "https://testnet.bscscan.com/address/",
|
|
137
|
+
explorerTx: "https://testnet.bscscan.com/tx/",
|
|
138
|
+
avgBlockTime: 3,
|
|
139
|
+
// BNB-specific: requires approval for pay-for-success flow
|
|
140
|
+
requiresApproval: true
|
|
141
|
+
},
|
|
142
|
+
// ============ BNB Chain Mainnet ============
|
|
143
|
+
bnb: {
|
|
144
|
+
name: "BNB Smart Chain",
|
|
145
|
+
chainId: 56,
|
|
146
|
+
rpc: "https://bsc-dataseed.binance.org",
|
|
147
|
+
tokens: {
|
|
148
|
+
// Note: BNB uses 18 decimals for stablecoins
|
|
149
|
+
USDC: {
|
|
150
|
+
address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
|
|
151
|
+
decimals: 18,
|
|
152
|
+
symbol: "USDC",
|
|
153
|
+
eip712Name: "USD Coin"
|
|
154
|
+
},
|
|
155
|
+
USDT: {
|
|
156
|
+
address: "0x55d398326f99059fF775485246999027B3197955",
|
|
157
|
+
decimals: 18,
|
|
158
|
+
symbol: "USDT",
|
|
159
|
+
eip712Name: "Tether USD"
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
usdc: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
|
|
163
|
+
explorer: "https://bscscan.com/address/",
|
|
164
|
+
explorerTx: "https://bscscan.com/tx/",
|
|
165
|
+
avgBlockTime: 3,
|
|
166
|
+
// BNB-specific: requires approval for pay-for-success flow
|
|
167
|
+
requiresApproval: true
|
|
111
168
|
}
|
|
112
169
|
};
|
|
113
170
|
function getChain(name) {
|
|
@@ -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 (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 eip712Name: 'USD Coin', // EIP-712 domain name\n },\n USDT: {\n address: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2',\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'Tether USD',\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-bor-rpc.publicnode.com',\n tokens: {\n USDC: {\n address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'USD Coin',\n },\n USDT: {\n address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',\n decimals: 6,\n symbol: 'USDT',\n eip712Name: '(PoS) Tether USD', // Polygon uses this name\n },\n },\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\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 eip712Name: 'USDC', // Testnet USDC uses 'USDC' not 'USD Coin'\n },\n USDT: {\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Same as USDC on testnet (no official USDT)\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'USDC', // Uses same contract as USDC\n },\n },\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n // ============ Tempo Testnet (Moderato) ============\n tempo_moderato: {\n name: 'Tempo Moderato',\n chainId: 42431,\n rpc: 'https://rpc.moderato.tempo.xyz',\n tokens: {\n // TIP-20 stablecoins on Tempo testnet (from mppx SDK)\n // Note: Tempo uses USD as native gas token, not ETH\n USDC: {\n address: '0x20c0000000000000000000000000000000000000', // pathUSD - primary testnet stablecoin\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'pathUSD',\n },\n USDT: {\n address: '0x20c0000000000000000000000000000000000001', // alphaUSD\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'alphaUSD',\n },\n },\n usdc: '0x20c0000000000000000000000000000000000000',\n explorer: 'https://explore.testnet.tempo.xyz/address/',\n explorerTx: 'https://explore.testnet.tempo.xyz/tx/',\n avgBlockTime: 0.5, // ~500ms finality\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":["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 EvmChainName,\n ChainConfig,\n WalletBalance,\n TransferResult,\n TokenSymbol,\n} from '../types/index.js';\n\nexport interface WalletConfig {\n chain?: EvmChainName;\n privateKey?: string;\n rpcUrl?: string;\n}\n\nexport class Wallet {\n readonly chain: EvmChainName;\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, EvmChainName, TokenSymbol } from '../types/index.js';\n\nexport const CHAINS: Record<EvmChainName, 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 eip712Name: 'USD Coin', // EIP-712 domain name\n },\n USDT: {\n address: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2',\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'Tether USD',\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-bor-rpc.publicnode.com',\n tokens: {\n USDC: {\n address: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'USD Coin',\n },\n USDT: {\n address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',\n decimals: 6,\n symbol: 'USDT',\n eip712Name: '(PoS) Tether USD', // Polygon uses this name\n },\n },\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\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 eip712Name: 'USDC', // Testnet USDC uses 'USDC' not 'USD Coin'\n },\n USDT: {\n address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Same as USDC on testnet (no official USDT)\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'USDC', // Uses same contract as USDC\n },\n },\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n // ============ Tempo Testnet (Moderato) ============\n tempo_moderato: {\n name: 'Tempo Moderato',\n chainId: 42431,\n rpc: 'https://rpc.moderato.tempo.xyz',\n tokens: {\n // TIP-20 stablecoins on Tempo testnet (from mppx SDK)\n // Note: Tempo uses USD as native gas token, not ETH\n USDC: {\n address: '0x20c0000000000000000000000000000000000000', // pathUSD - primary testnet stablecoin\n decimals: 6,\n symbol: 'USDC',\n eip712Name: 'pathUSD',\n },\n USDT: {\n address: '0x20c0000000000000000000000000000000000001', // alphaUSD\n decimals: 6,\n symbol: 'USDT',\n eip712Name: 'alphaUSD',\n },\n },\n usdc: '0x20c0000000000000000000000000000000000000',\n explorer: 'https://explore.testnet.tempo.xyz/address/',\n explorerTx: 'https://explore.testnet.tempo.xyz/tx/',\n avgBlockTime: 0.5, // ~500ms finality\n },\n // ============ BNB Chain Testnet ============\n bnb_testnet: {\n name: 'BNB Testnet',\n chainId: 97,\n rpc: 'https://data-seed-prebsc-1-s1.binance.org:8545',\n tokens: {\n // Note: BNB uses 18 decimals for stablecoins (unlike Base/Polygon which use 6)\n // Using official Binance-Peg testnet tokens\n USDC: {\n address: '0x64544969ed7EBf5f083679233325356EbE738930', // Testnet USDC\n decimals: 18,\n symbol: 'USDC',\n eip712Name: 'USD Coin',\n },\n USDT: {\n address: '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd', // Testnet USDT\n decimals: 18,\n symbol: 'USDT',\n eip712Name: 'Tether USD',\n },\n },\n usdc: '0x64544969ed7EBf5f083679233325356EbE738930',\n explorer: 'https://testnet.bscscan.com/address/',\n explorerTx: 'https://testnet.bscscan.com/tx/',\n avgBlockTime: 3,\n // BNB-specific: requires approval for pay-for-success flow\n requiresApproval: true,\n },\n // ============ BNB Chain Mainnet ============\n bnb: {\n name: 'BNB Smart Chain',\n chainId: 56,\n rpc: 'https://bsc-dataseed.binance.org',\n tokens: {\n // Note: BNB uses 18 decimals for stablecoins\n USDC: {\n address: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',\n decimals: 18,\n symbol: 'USDC',\n eip712Name: 'USD Coin',\n },\n USDT: {\n address: '0x55d398326f99059fF775485246999027B3197955',\n decimals: 18,\n symbol: 'USDT',\n eip712Name: 'Tether USD',\n },\n },\n usdc: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d',\n explorer: 'https://bscscan.com/address/',\n explorerTx: 'https://bscscan.com/tx/',\n avgBlockTime: 3,\n // BNB-specific: requires approval for pay-for-success flow\n requiresApproval: true,\n },\n};\n\n/**\n * Get token address for a chain\n */\nexport function getTokenAddress(chainName: EvmChainName, 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: EvmChainName, 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: EvmChainName): 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 EVM chains\n */\nexport function listChains(): EvmChainName[] {\n return Object.keys(CHAINS) as EvmChainName[];\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, EvmChainName, 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":["ethers"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moltspay",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Payment infrastructure for AI Agents - Server & Client SDK",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agent",
|
|
@@ -49,10 +49,13 @@
|
|
|
49
49
|
"test:run": "vitest run",
|
|
50
50
|
"lint": "eslint src/",
|
|
51
51
|
"typecheck": "tsc --noEmit",
|
|
52
|
-
"prepublishOnly": "npm run build"
|
|
52
|
+
"prepublishOnly": "npm run typecheck && npm run build"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
|
+
"@solana/spl-token": "^0.4.14",
|
|
56
|
+
"@solana/web3.js": "^1.98.4",
|
|
55
57
|
"@x402/fetch": "^2.7.0",
|
|
58
|
+
"bs58": "^6.0.0",
|
|
56
59
|
"commander": "^12.0.0",
|
|
57
60
|
"dotenv": "^17.3.1",
|
|
58
61
|
"ethers": "^6.11.0",
|
|
@@ -23,52 +23,30 @@
|
|
|
23
23
|
"wallet": {
|
|
24
24
|
"type": "string",
|
|
25
25
|
"pattern": "^0x[a-fA-F0-9]{40}$",
|
|
26
|
-
"description": "
|
|
26
|
+
"description": "EVM address to receive payments (Base, Polygon, BNB, etc.)"
|
|
27
|
+
},
|
|
28
|
+
"solana_wallet": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$",
|
|
31
|
+
"description": "Solana address to receive payments (solana, solana_devnet)"
|
|
27
32
|
},
|
|
28
33
|
"chain": {
|
|
29
34
|
"type": "string",
|
|
30
|
-
"enum": ["base", "
|
|
35
|
+
"enum": ["base", "polygon", "base_sepolia", "tempo_moderato", "bnb", "bnb_testnet", "solana", "solana_devnet"],
|
|
31
36
|
"default": "base",
|
|
32
|
-
"description": "
|
|
37
|
+
"description": "Single chain mode (use 'chains' for multi-chain)"
|
|
33
38
|
},
|
|
34
39
|
"chains": {
|
|
35
40
|
"type": "array",
|
|
36
|
-
"description": "
|
|
41
|
+
"description": "Supported chains. EVM chains use 'wallet', Solana chains use 'solana_wallet'.",
|
|
37
42
|
"items": {
|
|
38
|
-
"type": "
|
|
39
|
-
"
|
|
40
|
-
"properties": {
|
|
41
|
-
"chain": {
|
|
42
|
-
"type": "string",
|
|
43
|
-
"enum": ["base", "ethereum", "polygon"],
|
|
44
|
-
"description": "Chain name"
|
|
45
|
-
},
|
|
46
|
-
"network": {
|
|
47
|
-
"type": "string",
|
|
48
|
-
"pattern": "^eip155:\\d+$",
|
|
49
|
-
"description": "CAIP-2 network identifier",
|
|
50
|
-
"examples": ["eip155:8453", "eip155:137", "eip155:1"]
|
|
51
|
-
},
|
|
52
|
-
"wallet": {
|
|
53
|
-
"type": "string",
|
|
54
|
-
"pattern": "^0x[a-fA-F0-9]{40}$",
|
|
55
|
-
"description": "Optional per-chain wallet address. Falls back to provider.wallet if not specified."
|
|
56
|
-
},
|
|
57
|
-
"tokens": {
|
|
58
|
-
"type": "array",
|
|
59
|
-
"items": {
|
|
60
|
-
"type": "string",
|
|
61
|
-
"enum": ["USDC", "USDT"]
|
|
62
|
-
},
|
|
63
|
-
"description": "Tokens accepted on this chain",
|
|
64
|
-
"examples": [["USDC", "USDT"]]
|
|
65
|
-
}
|
|
66
|
-
}
|
|
43
|
+
"type": "string",
|
|
44
|
+
"enum": ["base", "polygon", "base_sepolia", "tempo_moderato", "bnb", "bnb_testnet", "solana", "solana_devnet"]
|
|
67
45
|
},
|
|
68
|
-
"examples": [
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
]
|
|
46
|
+
"examples": [
|
|
47
|
+
["base", "polygon", "solana_devnet"],
|
|
48
|
+
["base", "base_sepolia", "solana", "solana_devnet"]
|
|
49
|
+
]
|
|
72
50
|
}
|
|
73
51
|
}
|
|
74
52
|
},
|
|
@@ -83,82 +61,20 @@
|
|
|
83
61
|
"id": {
|
|
84
62
|
"type": "string",
|
|
85
63
|
"pattern": "^[a-z0-9-]+$",
|
|
86
|
-
"description": "Unique service identifier
|
|
64
|
+
"description": "Unique service identifier",
|
|
87
65
|
"examples": ["text-to-video", "image-to-video"]
|
|
88
66
|
},
|
|
89
|
-
"name": {
|
|
90
|
-
|
|
91
|
-
"description": "Human-readable service name"
|
|
92
|
-
},
|
|
93
|
-
"description": {
|
|
94
|
-
"type": "string",
|
|
95
|
-
"description": "Service description"
|
|
96
|
-
},
|
|
67
|
+
"name": { "type": "string", "description": "Human-readable service name" },
|
|
68
|
+
"description": { "type": "string", "description": "Service description" },
|
|
97
69
|
"function": {
|
|
98
70
|
"type": "string",
|
|
99
71
|
"pattern": "^[a-zA-Z][a-zA-Z0-9]*$",
|
|
100
|
-
"description": "Function name exported from index.js"
|
|
101
|
-
"examples": ["textToVideo", "imageToVideo"]
|
|
102
|
-
},
|
|
103
|
-
"price": {
|
|
104
|
-
"type": "number",
|
|
105
|
-
"minimum": 0,
|
|
106
|
-
"description": "Price in currency units (e.g., 0.99 for $0.99)"
|
|
107
|
-
},
|
|
108
|
-
"currency": {
|
|
109
|
-
"type": "string",
|
|
110
|
-
"enum": ["USDC", "USDT"],
|
|
111
|
-
"default": "USDC",
|
|
112
|
-
"description": "Primary/display currency for pricing"
|
|
72
|
+
"description": "Function name exported from index.js"
|
|
113
73
|
},
|
|
114
|
-
"
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
"enum": ["USDC", "USDT"]
|
|
119
|
-
},
|
|
120
|
-
"description": "Tokens accepted for payment. If not specified, defaults to [currency].",
|
|
121
|
-
"examples": [["USDC", "USDT"]]
|
|
122
|
-
},
|
|
123
|
-
"input": {
|
|
124
|
-
"type": "object",
|
|
125
|
-
"description": "Input parameters schema",
|
|
126
|
-
"additionalProperties": {
|
|
127
|
-
"type": "object",
|
|
128
|
-
"properties": {
|
|
129
|
-
"type": {
|
|
130
|
-
"type": "string",
|
|
131
|
-
"enum": ["string", "number", "boolean", "object", "array"]
|
|
132
|
-
},
|
|
133
|
-
"required": {
|
|
134
|
-
"type": "boolean",
|
|
135
|
-
"default": false
|
|
136
|
-
},
|
|
137
|
-
"description": {
|
|
138
|
-
"type": "string"
|
|
139
|
-
},
|
|
140
|
-
"default": {},
|
|
141
|
-
"enum": {
|
|
142
|
-
"type": "array"
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
},
|
|
147
|
-
"output": {
|
|
148
|
-
"type": "object",
|
|
149
|
-
"description": "Output schema",
|
|
150
|
-
"additionalProperties": {
|
|
151
|
-
"type": "object",
|
|
152
|
-
"properties": {
|
|
153
|
-
"type": {
|
|
154
|
-
"type": "string"
|
|
155
|
-
},
|
|
156
|
-
"description": {
|
|
157
|
-
"type": "string"
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
74
|
+
"price": { "type": "number", "minimum": 0, "description": "Price in currency units" },
|
|
75
|
+
"currency": { "type": "string", "enum": ["USDC", "USDT"], "default": "USDC" },
|
|
76
|
+
"input": { "type": "object", "description": "Input parameters schema" },
|
|
77
|
+
"output": { "type": "object", "description": "Output schema" }
|
|
162
78
|
}
|
|
163
79
|
}
|
|
164
80
|
}
|
|
@@ -167,33 +83,12 @@
|
|
|
167
83
|
{
|
|
168
84
|
"provider": {
|
|
169
85
|
"name": "Zen7 Video Generation",
|
|
170
|
-
"wallet": "0xb8d6f2441e8f8dfB6288A74Cf73804cDd0484E0C"
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
{
|
|
174
|
-
"id": "text-to-video",
|
|
175
|
-
"function": "textToVideo",
|
|
176
|
-
"price": 0.99,
|
|
177
|
-
"currency": "USDC",
|
|
178
|
-
"acceptedCurrencies": ["USDC", "USDT"]
|
|
179
|
-
}
|
|
180
|
-
]
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
"provider": {
|
|
184
|
-
"name": "Multi-Chain Service",
|
|
185
|
-
"wallet": "0xDefaultWallet...",
|
|
186
|
-
"chains": [
|
|
187
|
-
{"chain": "base", "network": "eip155:8453", "tokens": ["USDC", "USDT"]},
|
|
188
|
-
{"chain": "polygon", "network": "eip155:137", "wallet": "0xPolygonWallet...", "tokens": ["USDC"]}
|
|
189
|
-
]
|
|
86
|
+
"wallet": "0xb8d6f2441e8f8dfB6288A74Cf73804cDd0484E0C",
|
|
87
|
+
"solana_wallet": "CNbgcwV95JCguguA652kxwXPhS6EwoskeBPH45o8ow7K",
|
|
88
|
+
"chains": ["base", "base_sepolia", "polygon", "solana_devnet"]
|
|
190
89
|
},
|
|
191
90
|
"services": [
|
|
192
|
-
{
|
|
193
|
-
"id": "my-service",
|
|
194
|
-
"price": 1.00,
|
|
195
|
-
"currency": "USDC"
|
|
196
|
-
}
|
|
91
|
+
{ "id": "text-to-video", "function": "textToVideo", "price": 0.99, "currency": "USDC" }
|
|
197
92
|
]
|
|
198
93
|
}
|
|
199
94
|
]
|