moltspay 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +221 -38
  2. package/dist/cdp/index.d.mts +4 -4
  3. package/dist/cdp/index.d.ts +4 -4
  4. package/dist/cdp/index.js +57 -0
  5. package/dist/cdp/index.js.map +1 -1
  6. package/dist/cdp/index.mjs +57 -0
  7. package/dist/cdp/index.mjs.map +1 -1
  8. package/dist/chains/index.d.mts +9 -8
  9. package/dist/chains/index.d.ts +9 -8
  10. package/dist/chains/index.js +57 -0
  11. package/dist/chains/index.js.map +1 -1
  12. package/dist/chains/index.mjs +57 -0
  13. package/dist/chains/index.mjs.map +1 -1
  14. package/dist/cli/index.js +1975 -273
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli/index.mjs +1977 -265
  17. package/dist/cli/index.mjs.map +1 -1
  18. package/dist/client/index.d.mts +36 -3
  19. package/dist/client/index.d.ts +36 -3
  20. package/dist/client/index.js +540 -32
  21. package/dist/client/index.js.map +1 -1
  22. package/dist/client/index.mjs +548 -30
  23. package/dist/client/index.mjs.map +1 -1
  24. package/dist/facilitators/index.d.mts +220 -1
  25. package/dist/facilitators/index.d.ts +220 -1
  26. package/dist/facilitators/index.js +664 -1
  27. package/dist/facilitators/index.js.map +1 -1
  28. package/dist/facilitators/index.mjs +670 -1
  29. package/dist/facilitators/index.mjs.map +1 -1
  30. package/dist/{index-On9ZaGDW.d.mts → index-D_2FkLwV.d.mts} +6 -2
  31. package/dist/{index-On9ZaGDW.d.ts → index-D_2FkLwV.d.ts} +6 -2
  32. package/dist/index.d.mts +2 -1
  33. package/dist/index.d.ts +2 -1
  34. package/dist/index.js +1413 -146
  35. package/dist/index.js.map +1 -1
  36. package/dist/index.mjs +1421 -144
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/server/index.d.mts +13 -3
  39. package/dist/server/index.d.ts +13 -3
  40. package/dist/server/index.js +905 -52
  41. package/dist/server/index.js.map +1 -1
  42. package/dist/server/index.mjs +915 -52
  43. package/dist/server/index.mjs.map +1 -1
  44. package/dist/verify/index.d.mts +1 -1
  45. package/dist/verify/index.d.ts +1 -1
  46. package/dist/verify/index.js +57 -0
  47. package/dist/verify/index.js.map +1 -1
  48. package/dist/verify/index.mjs +57 -0
  49. package/dist/verify/index.mjs.map +1 -1
  50. package/dist/wallet/index.d.mts +3 -3
  51. package/dist/wallet/index.d.ts +3 -3
  52. package/dist/wallet/index.js +57 -0
  53. package/dist/wallet/index.js.map +1 -1
  54. package/dist/wallet/index.mjs +57 -0
  55. package/dist/wallet/index.mjs.map +1 -1
  56. package/package.json +4 -1
  57. package/schemas/moltspay.services.schema.json +27 -132
package/README.md CHANGED
@@ -21,11 +21,12 @@ MoltsPay enables agent-to-agent commerce using the [x402 protocol](https://www.x
21
21
 
22
22
  - 🔌 **Skill Integration** - Add `moltspay.services.json` to any existing skill
23
23
  - 🎫 **x402 Protocol** - HTTP-native payments (402 Payment Required)
24
- - 💨 **Gasless** - Both client and server pay no gas (CDP facilitator handles it)
24
+ - 💨 **Gasless** - Both client and server pay no gas (facilitators handle it)
25
25
  - ✅ **Payment Verification** - Automatic on-chain verification
26
26
  - 🔒 **Secure Wallet** - Spending limits, whitelist, and audit logging
27
- - ⛓️ **Multi-chain** - Base, Polygon, Ethereum (mainnet & testnet)
27
+ - ⛓️ **Multi-chain** - Base, Polygon, Solana, BNB, Tempo (mainnet & testnet)
28
28
  - 🤖 **Agent-to-Agent** - Complete A2A payment flow support
29
+ - 🌐 **Multi-VM** - EVM chains + Solana (SVM) with unified API
29
30
 
30
31
  ## Installation
31
32
 
@@ -51,8 +52,9 @@ export async function textToVideo({ prompt }) {
51
52
  {
52
53
  "provider": {
53
54
  "name": "My Video Service",
54
- "wallet": "0xYOUR_WALLET_ADDRESS",
55
- "chains": ["base", "polygon"]
55
+ "wallet": "0xYOUR_EVM_WALLET_ADDRESS",
56
+ "solana_wallet": "YOUR_SOLANA_ADDRESS",
57
+ "chains": ["base", "polygon", "solana", "bnb"]
56
58
  },
57
59
  "services": [{
58
60
  "id": "text-to-video",
@@ -63,6 +65,8 @@ export async function textToVideo({ prompt }) {
63
65
  }
64
66
  ```
65
67
 
68
+ **Note:** `solana_wallet` is optional - only needed if accepting Solana payments.
69
+
66
70
  **3. Start server:**
67
71
  ```bash
68
72
  npx moltspay start ./my-skill --port 3000
@@ -74,15 +78,15 @@ That's it! Your skill now accepts x402 payments.
74
78
 
75
79
  **1. Initialize wallet (one time):**
76
80
  ```bash
77
- npx moltspay init --chain base
78
- # Output: Wallet address 0xABC123...
81
+ npx moltspay init # EVM wallet (Base, Polygon, BNB, etc.)
82
+ npx moltspay init --chain solana # Solana wallet (mainnet & devnet)
79
83
  ```
80
84
 
81
85
  **2. Fund your wallet (US users):**
82
86
  ```bash
83
- npx moltspay fund 50
87
+ npx moltspay fund 5
84
88
  # Opens Coinbase Pay - use debit card or Apple Pay
85
- # USDC arrives in ~2 minutes. No ETH needed!
89
+ # USDC arrives in < 1 minutes. No ETH needed!
86
90
  ```
87
91
 
88
92
  Or send USDC directly to your wallet address from any exchange.
@@ -102,30 +106,43 @@ Want to test before using real money? Use our testnet faucets:
102
106
 
103
107
  ```bash
104
108
  # 1. Create wallet (if you don't have one)
105
- npx moltspay init
109
+ npx moltspay init # EVM wallet (Base, Polygon, BNB, etc.)
110
+ npx moltspay init --chain solana # Solana wallet (mainnet & devnet)
106
111
 
107
- # 2. Get free testnet tokens
112
+ # 2. Get free testnet tokens (pick one or all!)
108
113
  npx moltspay faucet # Base Sepolia (1 USDC, once per 24h)
109
- npx moltspay faucet --chain tempo_moderato # Tempo testnet (pathUSD)
114
+ npx moltspay faucet --chain solana_devnet # Solana devnet (1 USDC)
115
+ npx moltspay faucet --chain bnb_testnet # BNB testnet (1 USDC + 0.001 tBNB for gas)
116
+ npx moltspay faucet --chain tempo_moderato # Tempo testnet (1 pathUSD)
110
117
 
111
- # 3. Test payments
112
- # Option A: Base Sepolia
113
- npx moltspay pay https://moltspay.com/a/yaqing text-to-video \
118
+ # 3. Test payments on different chains
119
+ # Base Sepolia (CDP, gasless)
120
+ npx moltspay pay https://moltspay.com/a/zen7 text-to-video \
114
121
  --chain base_sepolia --prompt "a robot dancing"
115
122
 
116
- # Option B: Tempo Moderato (gas-free, MPP protocol)
123
+ # Solana devnet (SPL transfer)
124
+ npx moltspay pay https://moltspay.com/a/zen7 text-to-video \
125
+ --chain solana_devnet --prompt "a cat playing piano"
126
+
127
+ # BNB testnet (gas sponsored)
128
+ npx moltspay pay https://moltspay.com/a/zen7 text-to-video \
129
+ --chain bnb_testnet --prompt "a sunset timelapse"
130
+
131
+ # Tempo Moderato (gas-free, MPP protocol)
117
132
  npx moltspay pay https://server.com service-id \
118
133
  --chain tempo_moderato --prompt "test"
119
134
  ```
120
135
 
121
136
  ## Payment Protocols
122
137
 
123
- MoltsPay supports two payment protocols:
138
+ MoltsPay supports multiple payment protocols, each optimized for different chains:
124
139
 
125
140
  | Protocol | Chains | Gas | Description |
126
141
  |----------|--------|-----|-------------|
127
- | x402 | Base, Polygon, Ethereum | Gasless (CDP pays) | HTTP 402 + EIP-3009 signatures |
128
- | MPP | Tempo Moderato | Gas-free native | HTTP 402 + WWW-Authenticate |
142
+ | x402 + CDP | Base, Polygon | Gasless (CDP pays) | HTTP 402 + EIP-3009 signatures |
143
+ | x402 + SOL | Solana | Gasless (server pays) | HTTP 402 + SPL transfer |
144
+ | x402 + BNB | BNB | Gasless (server pays) | HTTP 402 + EIP-712 intent signing |
145
+ | MPP | Tempo | Gas-free native | HTTP 402 + WWW-Authenticate |
129
146
 
130
147
  ### How x402 Protocol Works
131
148
 
@@ -180,6 +197,58 @@ Client Server
180
197
 
181
198
  **Key insight:** On Tempo, the client executes the transfer directly (gas-free), then retries with the transaction hash. No CDP facilitator needed.
182
199
 
200
+ ### How Solana Protocol Works
201
+
202
+ ```
203
+ Client Server (Fee Payer) Solana Network
204
+ │ │ │
205
+ │ POST /execute │ │
206
+ │ ─────────────────────────> │ │
207
+ │ │ │
208
+ │ 402 + payment requirements │ │
209
+ │ (includes solana_wallet) │ │
210
+ │ <───────────────────────── │ │
211
+ │ │ │
212
+ │ [Sign SPL Transfer] │ │
213
+ │ [NO GAS - just signing] │ │
214
+ │ │ │
215
+ │ POST + X-Payment (signature) │ │
216
+ │ ─────────────────────────> │ Execute transfer │
217
+ │ │ (server pays ~$0.001 SOL) │
218
+ │ │ ─────────────────────────> │
219
+ │ │ │
220
+ │ 200 OK + result │ │
221
+ │ <───────────────────────── │ │
222
+ ```
223
+
224
+ **Key insight:** Client only signs the SPL transfer (gasless). Server acts as fee payer and executes the transaction on-chain.
225
+
226
+ ### How BNB Protocol Works
227
+
228
+ ```
229
+ Client Server BNB Network
230
+ │ │ │
231
+ │ POST /execute │ │
232
+ │ ─────────────────────────> │ │
233
+ │ │ │
234
+ │ 402 + payment requirements │ │
235
+ │ (includes bnbSpender) │ │
236
+ │ <───────────────────────── │ │
237
+ │ │ │
238
+ │ [Sign EIP-712 intent] │ │
239
+ │ [NO GAS - just signing] │ │
240
+ │ │ │
241
+ │ POST + X-Payment (signature) │ │
242
+ │ ─────────────────────────> │ Execute transferFrom │
243
+ │ │ (server pays ~$0.0001 gas) │
244
+ │ │ ─────────────────────────> │
245
+ │ │ │
246
+ │ 200 OK + result │ │
247
+ │ <───────────────────────── │ │
248
+ ```
249
+
250
+ **Key insight:** Client only signs an intent (gasless). Server executes the actual transfer and pays the minimal gas (~$0.0001). This is the "pay-for-success" model - payment only happens if service succeeds.
251
+
183
252
  ## Skill Structure
184
253
 
185
254
  MoltsPay reads your skill's existing structure:
@@ -305,9 +374,11 @@ Clients can then pay using `--chain base_sepolia` and get free testnet USDC via
305
374
 
306
375
  ```bash
307
376
  # === Client Commands ===
308
- npx moltspay init # Create wallet
377
+ npx moltspay init # Create wallet (EVM + Solana)
309
378
  npx moltspay fund <amount> # Fund wallet via Coinbase (US)
310
- npx moltspay faucet # Get free testnet USDC
379
+ npx moltspay faucet # Get free testnet USDC (Base Sepolia)
380
+ npx moltspay faucet --chain solana_devnet # Get Solana devnet USDC
381
+ npx moltspay faucet --chain bnb_testnet # Get BNB testnet USDC + tBNB
311
382
  npx moltspay faucet --chain tempo_moderato # Get Tempo testnet tokens
312
383
  npx moltspay status # Check balance (all chains)
313
384
  npx moltspay config # Update limits
@@ -326,7 +397,12 @@ npx moltspay services --json # Output as JSON
326
397
  # === Pay with Chain Selection ===
327
398
  npx moltspay pay <url> <service> --chain base # Pay on Base (default)
328
399
  npx moltspay pay <url> <service> --chain polygon # Pay on Polygon
329
- npx moltspay pay <url> <service> --chain base_sepolia # Pay on testnet
400
+ npx moltspay pay <url> <service> --chain base_sepolia # Pay on Base testnet
401
+ npx moltspay pay <url> <service> --chain solana # Pay on Solana
402
+ npx moltspay pay <url> <service> --chain solana_devnet # Pay on Solana devnet
403
+ npx moltspay pay <url> <service> --chain bnb # Pay on BNB
404
+ npx moltspay pay <url> <service> --chain bnb_testnet # Pay on BNB testnet
405
+ npx moltspay pay <url> <service> --chain tempo_moderato # Pay on Tempo
330
406
 
331
407
  # === Server Commands ===
332
408
  npx moltspay start <skill-dir> # Start server
@@ -335,7 +411,7 @@ npx moltspay validate <path> # Validate manifest
335
411
 
336
412
  # === Options ===
337
413
  --port <port> # Server port (default 3000)
338
- --chain <chain> # Chain: base, polygon, base_sepolia, tempo_moderato
414
+ --chain <chain> # Chain: base, polygon, solana, bnb, tempo_moderato, + testnets
339
415
  --token <token> # Token: USDC, USDT
340
416
  --max-per-tx <amount> # Spending limit per transaction
341
417
  --max-per-day <amount> # Daily spending limit
@@ -377,15 +453,120 @@ server.listen(3000);
377
453
 
378
454
  ## Supported Chains
379
455
 
380
- | Chain | ID | Type | Notes |
381
- |-------|-----|------|-------|
382
- | Base | 8453 | Mainnet | Primary chain |
383
- | Polygon | 137 | Mainnet | |
384
- | Ethereum | 1 | Mainnet | |
385
- | Base Sepolia | 84532 | Testnet | For testing |
386
- | Tempo Moderato | 42431 | Testnet | MPP protocol, gas-free |
456
+ | Chain | ID | Type | Facilitator | Gas Model |
457
+ |-------|-----|------|-------------|-----------|
458
+ | Base | 8453 | Mainnet | CDP | Gasless (CDP pays) |
459
+ | Polygon | 137 | Mainnet | CDP | Gasless (CDP pays) |
460
+ | Base Sepolia | 84532 | Testnet | CDP | Gasless (CDP pays) |
461
+ | Solana | - | Mainnet | SOL | Gasless (server pays) |
462
+ | Solana Devnet | - | Testnet | SOL | Gasless (server pays) |
463
+ | BNB | 56 | Mainnet | BNB | Gasless (server pays) |
464
+ | BNB Testnet | 97 | Testnet | BNB | Gasless (server pays) |
465
+ | Tempo Moderato | 42431 | Testnet | Tempo | Gas-free native |
466
+
467
+ **Notes:**
468
+ - Ethereum mainnet NOT recommended (gas too expensive)
469
+ - Each chain uses a specialized facilitator for optimal UX
470
+
471
+ ### Facilitator Architecture
472
+
473
+ A **facilitator** is the entity that executes the on-chain payment and pays the gas fees. MoltsPay supports two types:
474
+
475
+ | Type | Facilitator | Who Pays Gas? | Trust Model |
476
+ |------|-------------|---------------|-------------|
477
+ | **External** | CDP (Coinbase) | Coinbase | Trust Coinbase infrastructure |
478
+ | **Self-hosted** | SOL, BNB, Tempo | Your server | Trust your own server |
479
+
480
+ **External Facilitator (CDP):**
481
+ - Uses Coinbase Developer Platform as a third-party settlement service
482
+ - Coinbase handles all on-chain execution and gas fees
483
+ - Requires CDP API credentials
484
+ - Supported chains: Base, Polygon
485
+
486
+ **Self-hosted Facilitator (SOL, BNB, Tempo):**
487
+ - Your MoltsPay server acts as the facilitator
488
+ - Server pays gas fees (~$0.001 per tx)
489
+ - No external dependency - fully self-sovereign
490
+ - You control the entire payment flow
491
+
492
+ **Why Self-hosted is More Decentralized:**
493
+
494
+ | Aspect | CDP (External) | Self-hosted |
495
+ |--------|----------------|-------------|
496
+ | Single point of failure | ❌ Coinbase down = everyone stuck | ✅ Each provider independent |
497
+ | Censorship risk | ❌ Coinbase can block accounts | ✅ Cannot be censored |
498
+ | Dependency | ❌ Relies on third-party | ✅ Fully autonomous |
499
+
500
+ This self-hosted approach is a key innovation: **any service provider can become their own facilitator** without relying on third-party infrastructure. Unlike CDP where all users depend on Coinbase, self-hosted facilitators create a truly decentralized network with no single point of failure.
387
501
 
388
- ### Tempo Testnet (New!)
502
+ **Note:** Clients never need to know the facilitator's private keys. They only sign their own payments - the facilitator handles settlement transparently.
503
+
504
+ ### Facilitators Explained
505
+
506
+ | Facilitator | Chains | How It Works |
507
+ |-------------|--------|--------------|
508
+ | **CDP** | Base, Polygon | Client signs EIP-3009, Coinbase executes transfer |
509
+ | **SOL** | Solana | Client signs SPL transfer, server executes as fee payer |
510
+ | **BNB** | BNB | Client signs EIP-712 intent, server executes transfer |
511
+ | **Tempo** | Tempo Moderato | Client executes TIP-20 transfer (native gas-free) |
512
+
513
+ ### Solana Support
514
+
515
+ Solana uses the **SolanaFacilitator** with SPL token transfers. Key differences:
516
+
517
+ - **Gasless for users** - Server acts as fee payer (~$0.001 SOL per tx)
518
+ - **Separate wallet** - Solana uses ed25519 keys (different from EVM's secp256k1)
519
+ - **Wallet stored at** `~/.moltspay/wallet-solana.json`
520
+ - **Token** - Official Circle USDC SPL token
521
+
522
+ ```bash
523
+ # Initialize includes Solana wallet automatically
524
+ npx moltspay init
525
+
526
+ # Check Solana balance
527
+ npx moltspay status
528
+
529
+ # Get free devnet USDC
530
+ npx moltspay faucet --chain solana_devnet
531
+
532
+ # Pay on Solana
533
+ npx moltspay pay https://server.com service-id --chain solana --prompt "test"
534
+ ```
535
+
536
+ **USDC Addresses:**
537
+ | Network | Mint Address |
538
+ |---------|--------------|
539
+ | Mainnet | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` |
540
+ | Devnet | `4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU` |
541
+
542
+ ### BNB Chain Support
543
+
544
+ BNB uses the **BNBFacilitator** with a pre-approval flow. Since CDP doesn't support BNB, we use a different approach:
545
+
546
+ 1. Client signs an EIP-712 payment intent (no gas needed)
547
+ 2. Server validates and executes the transfer
548
+ 3. Server sponsors gas (~$0.0001 per tx)
549
+
550
+ ```bash
551
+ # Get free testnet USDC + tBNB for gas
552
+ npx moltspay faucet --chain bnb_testnet
553
+
554
+ # Pay on BNB (client pays no gas!)
555
+ npx moltspay pay https://server.com service-id --chain bnb_testnet --prompt "test"
556
+
557
+ # Check BNB balance
558
+ npx moltspay status
559
+ ```
560
+
561
+ **Important:** BNB tokens use 18 decimals (not 6 like Base/Polygon).
562
+
563
+ **Token Addresses (BNB Mainnet):**
564
+ | Token | Address |
565
+ |-------|---------|
566
+ | USDC | `0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d` |
567
+ | USDT | `0x55d398326f99059fF775485246999027B3197955` |
568
+
569
+ ### Tempo Testnet
389
570
 
390
571
  Tempo Moderato is a gas-free testnet that supports the **MPP (Machine Payments Protocol)**. Perfect for testing agent-to-agent payments without any gas fees.
391
572
 
@@ -408,24 +589,26 @@ npx moltspay status
408
589
 
409
590
  ## Live Example: Zen7 Video Generation
410
591
 
411
- Live service at `https://juai8.com/zen7/`
592
+ Live service at `https://moltspay.com/a/zen7`
412
593
 
413
594
  **Services:**
414
- - `text-to-video` - $0.99 USDC - Generate video from text prompt
415
- - `image-to-video` - $1.49 USDC - Animate a static image
595
+ - `text-to-video` - $0.01 USDC - Generate video from text prompt
596
+ - `image-to-video` - $0.01 USDC - Animate a static image
416
597
 
417
- **Supported Chains:** Base, Polygon
598
+ **Supported Chains:** Base, Polygon, Solana, BNB, Tempo (mainnet & testnet)
418
599
 
419
600
  **Try it:**
420
601
  ```bash
421
602
  # List services
422
- npx moltspay services https://juai8.com/zen7
603
+ npx moltspay services https://moltspay.com/a/zen7
423
604
 
424
605
  # Pay on Base (default)
425
- npx moltspay pay https://juai8.com/zen7 text-to-video --prompt "a happy cat"
606
+ npx moltspay pay https://moltspay.com/a/zen7 text-to-video --prompt "a happy cat"
426
607
 
427
- # Pay on Polygon
428
- npx moltspay pay https://juai8.com/zen7 text-to-video --chain polygon --prompt "a happy cat"
608
+ # Pay on different chains
609
+ npx moltspay pay https://moltspay.com/a/zen7 text-to-video --chain polygon --prompt "a happy cat"
610
+ npx moltspay pay https://moltspay.com/a/zen7 text-to-video --chain bnb_testnet --prompt "a happy cat"
611
+ npx moltspay pay https://moltspay.com/a/zen7 text-to-video --chain solana_devnet --prompt "a happy cat"
429
612
  ```
430
613
 
431
614
  ## Use Cases
@@ -1,4 +1,4 @@
1
- import { C as ChainName } from '../index-On9ZaGDW.mjs';
1
+ import { E as EvmChainName } from '../index-D_2FkLwV.mjs';
2
2
  import { getChain } from '../chains/index.mjs';
3
3
 
4
4
  /**
@@ -14,7 +14,7 @@ interface CDPWalletConfig {
14
14
  /** Storage directory (default: ~/.moltspay) */
15
15
  storageDir?: string;
16
16
  /** Chain name */
17
- chain?: ChainName;
17
+ chain?: EvmChainName;
18
18
  /** CDP API credentials (or use env vars) */
19
19
  apiKeyId?: string;
20
20
  apiKeySecret?: string;
@@ -26,7 +26,7 @@ interface CDPWalletData {
26
26
  /** CDP wallet ID */
27
27
  walletId: string;
28
28
  /** Chain */
29
- chain: ChainName;
29
+ chain: EvmChainName;
30
30
  /** Created timestamp */
31
31
  createdAt: string;
32
32
  /** CDP account data (for restoration) */
@@ -75,7 +75,7 @@ declare function getCDPWalletAddress(storageDir?: string): string | null;
75
75
  */
76
76
  declare class CDPWallet {
77
77
  readonly address: string;
78
- readonly chain: ChainName;
78
+ readonly chain: EvmChainName;
79
79
  readonly chainConfig: ReturnType<typeof getChain>;
80
80
  private storageDir;
81
81
  constructor(config?: CDPWalletConfig);
@@ -1,4 +1,4 @@
1
- import { C as ChainName } from '../index-On9ZaGDW.js';
1
+ import { E as EvmChainName } from '../index-D_2FkLwV.js';
2
2
  import { getChain } from '../chains/index.js';
3
3
 
4
4
  /**
@@ -14,7 +14,7 @@ interface CDPWalletConfig {
14
14
  /** Storage directory (default: ~/.moltspay) */
15
15
  storageDir?: string;
16
16
  /** Chain name */
17
- chain?: ChainName;
17
+ chain?: EvmChainName;
18
18
  /** CDP API credentials (or use env vars) */
19
19
  apiKeyId?: string;
20
20
  apiKeySecret?: string;
@@ -26,7 +26,7 @@ interface CDPWalletData {
26
26
  /** CDP wallet ID */
27
27
  walletId: string;
28
28
  /** Chain */
29
- chain: ChainName;
29
+ chain: EvmChainName;
30
30
  /** Created timestamp */
31
31
  createdAt: string;
32
32
  /** CDP account data (for restoration) */
@@ -75,7 +75,7 @@ declare function getCDPWalletAddress(storageDir?: string): string | null;
75
75
  */
76
76
  declare class CDPWallet {
77
77
  readonly address: string;
78
- readonly chain: ChainName;
78
+ readonly chain: EvmChainName;
79
79
  readonly chainConfig: ReturnType<typeof getChain>;
80
80
  private storageDir;
81
81
  constructor(config?: CDPWalletConfig);
package/dist/cdp/index.js CHANGED
@@ -147,6 +147,63 @@ var CHAINS = {
147
147
  explorerTx: "https://explore.testnet.tempo.xyz/tx/",
148
148
  avgBlockTime: 0.5
149
149
  // ~500ms finality
150
+ },
151
+ // ============ BNB Chain Testnet ============
152
+ bnb_testnet: {
153
+ name: "BNB Testnet",
154
+ chainId: 97,
155
+ rpc: "https://data-seed-prebsc-1-s1.binance.org:8545",
156
+ tokens: {
157
+ // Note: BNB uses 18 decimals for stablecoins (unlike Base/Polygon which use 6)
158
+ // Using official Binance-Peg testnet tokens
159
+ USDC: {
160
+ address: "0x64544969ed7EBf5f083679233325356EbE738930",
161
+ // Testnet USDC
162
+ decimals: 18,
163
+ symbol: "USDC",
164
+ eip712Name: "USD Coin"
165
+ },
166
+ USDT: {
167
+ address: "0x337610d27c682E347C9cD60BD4b3b107C9d34dDd",
168
+ // Testnet USDT
169
+ decimals: 18,
170
+ symbol: "USDT",
171
+ eip712Name: "Tether USD"
172
+ }
173
+ },
174
+ usdc: "0x64544969ed7EBf5f083679233325356EbE738930",
175
+ explorer: "https://testnet.bscscan.com/address/",
176
+ explorerTx: "https://testnet.bscscan.com/tx/",
177
+ avgBlockTime: 3,
178
+ // BNB-specific: requires approval for pay-for-success flow
179
+ requiresApproval: true
180
+ },
181
+ // ============ BNB Chain Mainnet ============
182
+ bnb: {
183
+ name: "BNB Smart Chain",
184
+ chainId: 56,
185
+ rpc: "https://bsc-dataseed.binance.org",
186
+ tokens: {
187
+ // Note: BNB uses 18 decimals for stablecoins
188
+ USDC: {
189
+ address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
190
+ decimals: 18,
191
+ symbol: "USDC",
192
+ eip712Name: "USD Coin"
193
+ },
194
+ USDT: {
195
+ address: "0x55d398326f99059fF775485246999027B3197955",
196
+ decimals: 18,
197
+ symbol: "USDT",
198
+ eip712Name: "Tether USD"
199
+ }
200
+ },
201
+ usdc: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d",
202
+ explorer: "https://bscscan.com/address/",
203
+ explorerTx: "https://bscscan.com/tx/",
204
+ avgBlockTime: 3,
205
+ // BNB-specific: requires approval for pay-for-success flow
206
+ requiresApproval: true
150
207
  }
151
208
  };
152
209
  function getChain(name) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cdp/index.ts","../../src/chains/index.ts"],"sourcesContent":["/**\n * CDP (Coinbase Developer Platform) Wallet Integration\n * \n * Creates and manages wallets via Coinbase's CDP SDK.\n * These wallets are hosted by Coinbase, making them easy to use for AI Agents.\n * \n * @see https://docs.cdp.coinbase.com/\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { ChainName } from '../types/index.js';\nimport { getChain } from '../chains/index.js';\n\n// CDP config file location\nconst DEFAULT_STORAGE_DIR = path.join(process.env.HOME || '.', '.moltspay');\nconst CDP_CONFIG_FILE = 'cdp-wallet.json';\n\nexport interface CDPWalletConfig {\n /** Storage directory (default: ~/.moltspay) */\n storageDir?: string;\n /** Chain name */\n chain?: ChainName;\n /** CDP API credentials (or use env vars) */\n apiKeyId?: string;\n apiKeySecret?: string;\n walletSecret?: string;\n}\n\nexport interface CDPWalletData {\n /** Wallet address */\n address: string;\n /** CDP wallet ID */\n walletId: string;\n /** Chain */\n chain: ChainName;\n /** Created timestamp */\n createdAt: string;\n /** CDP account data (for restoration) */\n accountData?: string;\n}\n\nexport interface CDPInitResult {\n success: boolean;\n address?: string;\n walletId?: string;\n isNew?: boolean;\n error?: string;\n storagePath?: string;\n}\n\n/**\n * Check if CDP SDK is available\n */\nexport function isCDPAvailable(): boolean {\n try {\n require.resolve('@coinbase/cdp-sdk');\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get CDP credentials from environment\n */\nfunction getCDPCredentials(config: CDPWalletConfig): {\n apiKeyId: string;\n apiKeySecret: string;\n walletSecret?: string;\n} | null {\n const apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;\n const apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;\n const walletSecret = config.walletSecret || process.env.CDP_WALLET_SECRET;\n\n if (!apiKeyId || !apiKeySecret) {\n return null;\n }\n\n return { apiKeyId, apiKeySecret, walletSecret };\n}\n\n/**\n * Initialize CDP wallet\n * \n * Creates a new CDP wallet or loads existing one.\n * \n * @example\n * ```bash\n * # Set credentials\n * export CDP_API_KEY_ID=your-key-id\n * export CDP_API_KEY_SECRET=your-key-secret\n * \n * # Initialize\n * npx moltspay init --cdp --chain base\n * ```\n */\nexport async function initCDPWallet(config: CDPWalletConfig = {}): Promise<CDPInitResult> {\n const storageDir = config.storageDir || DEFAULT_STORAGE_DIR;\n const chain = config.chain || 'base';\n const storagePath = path.join(storageDir, CDP_CONFIG_FILE);\n\n // Check for existing wallet\n if (fs.existsSync(storagePath)) {\n try {\n const data = JSON.parse(fs.readFileSync(storagePath, 'utf-8')) as CDPWalletData;\n return {\n success: true,\n address: data.address,\n walletId: data.walletId,\n isNew: false,\n storagePath,\n };\n } catch (error) {\n // Continue to create new\n }\n }\n\n // Check CDP availability\n if (!isCDPAvailable()) {\n return {\n success: false,\n error: 'CDP SDK not installed. Run: npm install @coinbase/cdp-sdk',\n };\n }\n\n // Get credentials\n const creds = getCDPCredentials(config);\n if (!creds) {\n return {\n success: false,\n error: 'CDP credentials not found. Set CDP_API_KEY_ID and CDP_API_KEY_SECRET environment variables.',\n };\n }\n\n try {\n // Dynamic import to avoid errors when CDP SDK is not installed\n const { CdpClient } = await import('@coinbase/cdp-sdk');\n\n // Initialize CDP client\n const cdp = new CdpClient({\n apiKeyId: creds.apiKeyId,\n apiKeySecret: creds.apiKeySecret,\n walletSecret: creds.walletSecret,\n });\n\n // Create EVM account\n const account = await cdp.evm.createAccount();\n\n // Ensure storage directory exists\n if (!fs.existsSync(storageDir)) {\n fs.mkdirSync(storageDir, { recursive: true });\n }\n\n // Save wallet data\n const walletData: CDPWalletData = {\n address: account.address,\n walletId: account.address, // CDP uses address as ID for EVM\n chain,\n createdAt: new Date().toISOString(),\n };\n\n fs.writeFileSync(storagePath, JSON.stringify(walletData, null, 2), { mode: 0o600 });\n\n return {\n success: true,\n address: account.address,\n walletId: account.address,\n isNew: true,\n storagePath,\n };\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n}\n\n/**\n * Load existing CDP wallet\n */\nexport function loadCDPWallet(config: CDPWalletConfig = {}): CDPWalletData | null {\n const storageDir = config.storageDir || DEFAULT_STORAGE_DIR;\n const storagePath = path.join(storageDir, CDP_CONFIG_FILE);\n\n if (!fs.existsSync(storagePath)) {\n return null;\n }\n\n try {\n return JSON.parse(fs.readFileSync(storagePath, 'utf-8')) as CDPWalletData;\n } catch {\n return null;\n }\n}\n\n/**\n * Get CDP wallet address (quick check without full init)\n */\nexport function getCDPWalletAddress(storageDir?: string): string | null {\n const data = loadCDPWallet({ storageDir });\n return data?.address || null;\n}\n\n/**\n * CDP Wallet class for making payments\n * \n * Uses CDP SDK for wallet operations with x402 support.\n */\nexport class CDPWallet {\n readonly address: string;\n readonly chain: ChainName;\n readonly chainConfig: ReturnType<typeof getChain>;\n private storageDir: string;\n\n constructor(config: CDPWalletConfig = {}) {\n this.storageDir = config.storageDir || DEFAULT_STORAGE_DIR;\n this.chain = config.chain || 'base';\n this.chainConfig = getChain(this.chain);\n\n // Load existing wallet\n const data = loadCDPWallet(config);\n if (!data) {\n throw new Error('CDP wallet not initialized. Run: npx moltspay init --cdp');\n }\n this.address = data.address;\n }\n\n /**\n * Get USDC balance\n */\n async getBalance(): Promise<{ usdc: string; eth: string }> {\n // Use ethers to check balance (read-only, no CDP needed)\n const { ethers } = await import('ethers');\n const provider = new ethers.JsonRpcProvider(this.chainConfig.rpc);\n \n const usdcContract = new ethers.Contract(\n this.chainConfig.usdc,\n ['function balanceOf(address) view returns (uint256)'],\n provider\n );\n\n const [usdcBalance, ethBalance] = await Promise.all([\n usdcContract.balanceOf(this.address),\n provider.getBalance(this.address),\n ]);\n\n return {\n usdc: (Number(usdcBalance) / 1e6).toFixed(2),\n eth: ethers.formatEther(ethBalance),\n };\n }\n\n /**\n * Transfer USDC to a recipient\n * \n * Requires CDP SDK and credentials to sign transactions.\n */\n async transfer(params: { to: string; amount: number }): Promise<{\n success: boolean;\n txHash?: string;\n error?: string;\n explorerUrl?: string;\n }> {\n if (!isCDPAvailable()) {\n return { success: false, error: 'CDP SDK not installed' };\n }\n\n const creds = getCDPCredentials({});\n if (!creds) {\n return { success: false, error: 'CDP credentials not found' };\n }\n\n try {\n const { CdpClient } = await import('@coinbase/cdp-sdk');\n const { ethers } = await import('ethers');\n\n const cdp = new CdpClient({\n apiKeyId: creds.apiKeyId,\n apiKeySecret: creds.apiKeySecret,\n walletSecret: creds.walletSecret,\n });\n\n // Get the account\n const account = await cdp.evm.getAccount({ address: this.address as `0x${string}` });\n\n // Build transfer transaction\n const amountWei = BigInt(Math.floor(params.amount * 1e6));\n const iface = new ethers.Interface([\n 'function transfer(address to, uint256 amount) returns (bool)',\n ]);\n const callData = iface.encodeFunctionData('transfer', [params.to, amountWei]);\n\n // Send transaction (use any to avoid type issues with CDP SDK versions)\n const txOptions: any = {\n to: this.chainConfig.usdc,\n data: callData,\n };\n const tx = await account.sendTransaction(txOptions);\n\n return {\n success: true,\n txHash: tx.transactionHash,\n explorerUrl: `${this.chainConfig.explorerTx}${tx.transactionHash}`,\n };\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n }\n\n /**\n * Create viem-compatible signer for x402\n * \n * This allows using CDP wallet with x402 protocol.\n */\n async getViemAccount(): Promise<unknown> {\n if (!isCDPAvailable()) {\n throw new Error('CDP SDK not installed');\n }\n\n const creds = getCDPCredentials({});\n if (!creds) {\n throw new Error('CDP credentials not found');\n }\n\n const { CdpClient } = await import('@coinbase/cdp-sdk');\n const { toAccount } = await import('viem/accounts');\n\n const cdp = new CdpClient({\n apiKeyId: creds.apiKeyId,\n apiKeySecret: creds.apiKeySecret,\n walletSecret: creds.walletSecret,\n });\n\n const account = await cdp.evm.getAccount({ address: this.address as `0x${string}` });\n return toAccount(account);\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"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/cdp/index.ts","../../src/chains/index.ts"],"sourcesContent":["/**\n * CDP (Coinbase Developer Platform) Wallet Integration\n * \n * Creates and manages wallets via Coinbase's CDP SDK.\n * These wallets are hosted by Coinbase, making them easy to use for AI Agents.\n * \n * @see https://docs.cdp.coinbase.com/\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { EvmChainName } from '../types/index.js';\nimport { getChain } from '../chains/index.js';\n\n// CDP config file location\nconst DEFAULT_STORAGE_DIR = path.join(process.env.HOME || '.', '.moltspay');\nconst CDP_CONFIG_FILE = 'cdp-wallet.json';\n\nexport interface CDPWalletConfig {\n /** Storage directory (default: ~/.moltspay) */\n storageDir?: string;\n /** Chain name */\n chain?: EvmChainName;\n /** CDP API credentials (or use env vars) */\n apiKeyId?: string;\n apiKeySecret?: string;\n walletSecret?: string;\n}\n\nexport interface CDPWalletData {\n /** Wallet address */\n address: string;\n /** CDP wallet ID */\n walletId: string;\n /** Chain */\n chain: EvmChainName;\n /** Created timestamp */\n createdAt: string;\n /** CDP account data (for restoration) */\n accountData?: string;\n}\n\nexport interface CDPInitResult {\n success: boolean;\n address?: string;\n walletId?: string;\n isNew?: boolean;\n error?: string;\n storagePath?: string;\n}\n\n/**\n * Check if CDP SDK is available\n */\nexport function isCDPAvailable(): boolean {\n try {\n require.resolve('@coinbase/cdp-sdk');\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get CDP credentials from environment\n */\nfunction getCDPCredentials(config: CDPWalletConfig): {\n apiKeyId: string;\n apiKeySecret: string;\n walletSecret?: string;\n} | null {\n const apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;\n const apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;\n const walletSecret = config.walletSecret || process.env.CDP_WALLET_SECRET;\n\n if (!apiKeyId || !apiKeySecret) {\n return null;\n }\n\n return { apiKeyId, apiKeySecret, walletSecret };\n}\n\n/**\n * Initialize CDP wallet\n * \n * Creates a new CDP wallet or loads existing one.\n * \n * @example\n * ```bash\n * # Set credentials\n * export CDP_API_KEY_ID=your-key-id\n * export CDP_API_KEY_SECRET=your-key-secret\n * \n * # Initialize\n * npx moltspay init --cdp --chain base\n * ```\n */\nexport async function initCDPWallet(config: CDPWalletConfig = {}): Promise<CDPInitResult> {\n const storageDir = config.storageDir || DEFAULT_STORAGE_DIR;\n const chain = config.chain || 'base';\n const storagePath = path.join(storageDir, CDP_CONFIG_FILE);\n\n // Check for existing wallet\n if (fs.existsSync(storagePath)) {\n try {\n const data = JSON.parse(fs.readFileSync(storagePath, 'utf-8')) as CDPWalletData;\n return {\n success: true,\n address: data.address,\n walletId: data.walletId,\n isNew: false,\n storagePath,\n };\n } catch (error) {\n // Continue to create new\n }\n }\n\n // Check CDP availability\n if (!isCDPAvailable()) {\n return {\n success: false,\n error: 'CDP SDK not installed. Run: npm install @coinbase/cdp-sdk',\n };\n }\n\n // Get credentials\n const creds = getCDPCredentials(config);\n if (!creds) {\n return {\n success: false,\n error: 'CDP credentials not found. Set CDP_API_KEY_ID and CDP_API_KEY_SECRET environment variables.',\n };\n }\n\n try {\n // Dynamic import to avoid errors when CDP SDK is not installed\n const { CdpClient } = await import('@coinbase/cdp-sdk');\n\n // Initialize CDP client\n const cdp = new CdpClient({\n apiKeyId: creds.apiKeyId,\n apiKeySecret: creds.apiKeySecret,\n walletSecret: creds.walletSecret,\n });\n\n // Create EVM account\n const account = await cdp.evm.createAccount();\n\n // Ensure storage directory exists\n if (!fs.existsSync(storageDir)) {\n fs.mkdirSync(storageDir, { recursive: true });\n }\n\n // Save wallet data\n const walletData: CDPWalletData = {\n address: account.address,\n walletId: account.address, // CDP uses address as ID for EVM\n chain,\n createdAt: new Date().toISOString(),\n };\n\n fs.writeFileSync(storagePath, JSON.stringify(walletData, null, 2), { mode: 0o600 });\n\n return {\n success: true,\n address: account.address,\n walletId: account.address,\n isNew: true,\n storagePath,\n };\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n}\n\n/**\n * Load existing CDP wallet\n */\nexport function loadCDPWallet(config: CDPWalletConfig = {}): CDPWalletData | null {\n const storageDir = config.storageDir || DEFAULT_STORAGE_DIR;\n const storagePath = path.join(storageDir, CDP_CONFIG_FILE);\n\n if (!fs.existsSync(storagePath)) {\n return null;\n }\n\n try {\n return JSON.parse(fs.readFileSync(storagePath, 'utf-8')) as CDPWalletData;\n } catch {\n return null;\n }\n}\n\n/**\n * Get CDP wallet address (quick check without full init)\n */\nexport function getCDPWalletAddress(storageDir?: string): string | null {\n const data = loadCDPWallet({ storageDir });\n return data?.address || null;\n}\n\n/**\n * CDP Wallet class for making payments\n * \n * Uses CDP SDK for wallet operations with x402 support.\n */\nexport class CDPWallet {\n readonly address: string;\n readonly chain: EvmChainName;\n readonly chainConfig: ReturnType<typeof getChain>;\n private storageDir: string;\n\n constructor(config: CDPWalletConfig = {}) {\n this.storageDir = config.storageDir || DEFAULT_STORAGE_DIR;\n this.chain = config.chain || 'base';\n this.chainConfig = getChain(this.chain);\n\n // Load existing wallet\n const data = loadCDPWallet(config);\n if (!data) {\n throw new Error('CDP wallet not initialized. Run: npx moltspay init --cdp');\n }\n this.address = data.address;\n }\n\n /**\n * Get USDC balance\n */\n async getBalance(): Promise<{ usdc: string; eth: string }> {\n // Use ethers to check balance (read-only, no CDP needed)\n const { ethers } = await import('ethers');\n const provider = new ethers.JsonRpcProvider(this.chainConfig.rpc);\n \n const usdcContract = new ethers.Contract(\n this.chainConfig.usdc,\n ['function balanceOf(address) view returns (uint256)'],\n provider\n );\n\n const [usdcBalance, ethBalance] = await Promise.all([\n usdcContract.balanceOf(this.address),\n provider.getBalance(this.address),\n ]);\n\n return {\n usdc: (Number(usdcBalance) / 1e6).toFixed(2),\n eth: ethers.formatEther(ethBalance),\n };\n }\n\n /**\n * Transfer USDC to a recipient\n * \n * Requires CDP SDK and credentials to sign transactions.\n */\n async transfer(params: { to: string; amount: number }): Promise<{\n success: boolean;\n txHash?: string;\n error?: string;\n explorerUrl?: string;\n }> {\n if (!isCDPAvailable()) {\n return { success: false, error: 'CDP SDK not installed' };\n }\n\n const creds = getCDPCredentials({});\n if (!creds) {\n return { success: false, error: 'CDP credentials not found' };\n }\n\n try {\n const { CdpClient } = await import('@coinbase/cdp-sdk');\n const { ethers } = await import('ethers');\n\n const cdp = new CdpClient({\n apiKeyId: creds.apiKeyId,\n apiKeySecret: creds.apiKeySecret,\n walletSecret: creds.walletSecret,\n });\n\n // Get the account\n const account = await cdp.evm.getAccount({ address: this.address as `0x${string}` });\n\n // Build transfer transaction\n const amountWei = BigInt(Math.floor(params.amount * 1e6));\n const iface = new ethers.Interface([\n 'function transfer(address to, uint256 amount) returns (bool)',\n ]);\n const callData = iface.encodeFunctionData('transfer', [params.to, amountWei]);\n\n // Send transaction (use any to avoid type issues with CDP SDK versions)\n const txOptions: any = {\n to: this.chainConfig.usdc,\n data: callData,\n };\n const tx = await account.sendTransaction(txOptions);\n\n return {\n success: true,\n txHash: tx.transactionHash,\n explorerUrl: `${this.chainConfig.explorerTx}${tx.transactionHash}`,\n };\n } catch (error) {\n return {\n success: false,\n error: (error as Error).message,\n };\n }\n }\n\n /**\n * Create viem-compatible signer for x402\n * \n * This allows using CDP wallet with x402 protocol.\n */\n async getViemAccount(): Promise<unknown> {\n if (!isCDPAvailable()) {\n throw new Error('CDP SDK not installed');\n }\n\n const creds = getCDPCredentials({});\n if (!creds) {\n throw new Error('CDP credentials not found');\n }\n\n const { CdpClient } = await import('@coinbase/cdp-sdk');\n const { toAccount } = await import('viem/accounts');\n\n const cdp = new CdpClient({\n apiKeyId: creds.apiKeyId,\n apiKeySecret: creds.apiKeySecret,\n walletSecret: creds.walletSecret,\n });\n\n const account = await cdp.evm.getAccount({ address: this.address as `0x${string}` });\n return toAccount(account);\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"],"mappings":"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","names":[]}