moltspay 0.5.4 → 0.7.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.
Files changed (68) hide show
  1. package/README.md +0 -124
  2. package/dist/cdp/index.d.mts +111 -0
  3. package/dist/cdp/index.d.ts +111 -0
  4. package/dist/cdp/index.js +30655 -0
  5. package/dist/cdp/index.js.map +1 -0
  6. package/dist/cdp/index.mjs +30631 -0
  7. package/dist/cdp/index.mjs.map +1 -0
  8. package/dist/chains/index.d.mts +1 -1
  9. package/dist/chains/index.d.ts +1 -1
  10. package/dist/cli/index.js +990 -0
  11. package/dist/cli/index.js.map +1 -0
  12. package/dist/cli/index.mjs +967 -0
  13. package/dist/cli/index.mjs.map +1 -0
  14. package/dist/client/index.d.mts +134 -0
  15. package/dist/client/index.d.ts +134 -0
  16. package/dist/client/index.js +331 -0
  17. package/dist/client/index.js.map +1 -0
  18. package/dist/client/index.mjs +296 -0
  19. package/dist/client/index.mjs.map +1 -0
  20. package/dist/createWallet-D53qu7ie.d.mts +77 -0
  21. package/dist/createWallet-D53qu7ie.d.ts +77 -0
  22. package/dist/index-Dg8n6wdW.d.mts +32 -0
  23. package/dist/index-Dg8n6wdW.d.ts +32 -0
  24. package/dist/index.d.mts +6 -1483
  25. package/dist/index.d.ts +6 -1483
  26. package/dist/index.js +31039 -4254
  27. package/dist/index.js.map +1 -1
  28. package/dist/index.mjs +31042 -4203
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/server/index.d.mts +120 -0
  31. package/dist/server/index.d.ts +120 -0
  32. package/dist/server/index.js +418 -0
  33. package/dist/server/index.js.map +1 -0
  34. package/dist/server/index.mjs +393 -0
  35. package/dist/server/index.mjs.map +1 -0
  36. package/dist/wallet/index.d.mts +3 -451
  37. package/dist/wallet/index.d.ts +3 -451
  38. package/dist/wallet/index.js +5 -1021
  39. package/dist/wallet/index.js.map +1 -1
  40. package/dist/wallet/index.mjs +16 -1015
  41. package/dist/wallet/index.mjs.map +1 -1
  42. package/package.json +19 -19
  43. package/dist/cli.js +0 -1984
  44. package/dist/cli.js.map +0 -1
  45. package/dist/cli.mjs +0 -1969
  46. package/dist/cli.mjs.map +0 -1
  47. package/dist/guide/index.d.mts +0 -39
  48. package/dist/guide/index.d.ts +0 -39
  49. package/dist/guide/index.js +0 -181
  50. package/dist/guide/index.js.map +0 -1
  51. package/dist/guide/index.mjs +0 -152
  52. package/dist/guide/index.mjs.map +0 -1
  53. package/dist/index-CyFg9s2m.d.mts +0 -161
  54. package/dist/index-CyFg9s2m.d.ts +0 -161
  55. package/dist/orders/index.d.mts +0 -97
  56. package/dist/orders/index.d.ts +0 -97
  57. package/dist/orders/index.js +0 -162
  58. package/dist/orders/index.js.map +0 -1
  59. package/dist/orders/index.mjs +0 -136
  60. package/dist/orders/index.mjs.map +0 -1
  61. package/dist/permit/index.d.mts +0 -49
  62. package/dist/permit/index.d.ts +0 -49
  63. package/dist/permit/index.js +0 -273
  64. package/dist/permit/index.js.map +0 -1
  65. package/dist/permit/index.mjs +0 -246
  66. package/dist/permit/index.mjs.map +0 -1
  67. /package/dist/{cli.d.mts → cli/index.d.mts} +0 -0
  68. /package/dist/{cli.d.ts → cli/index.d.ts} +0 -0
package/dist/cli.mjs DELETED
@@ -1,1969 +0,0 @@
1
- #!/usr/bin/env node
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
6
- }) : x)(function(x) {
7
- if (typeof require !== "undefined") return require.apply(this, arguments);
8
- throw Error('Dynamic require of "' + x + '" is not supported');
9
- });
10
- var __esm = (fn, res) => function __init() {
11
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
- };
13
- var __export = (target, all) => {
14
- for (var name in all)
15
- __defProp(target, name, { get: all[name], enumerable: true });
16
- };
17
-
18
- // src/chains/index.ts
19
- var chains_exports = {};
20
- __export(chains_exports, {
21
- CHAINS: () => CHAINS,
22
- ERC20_ABI: () => ERC20_ABI,
23
- getChain: () => getChain,
24
- getChainById: () => getChainById,
25
- listChains: () => listChains
26
- });
27
- function getChain(name) {
28
- const config = CHAINS[name];
29
- if (!config) {
30
- throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(", ")}`);
31
- }
32
- return config;
33
- }
34
- function listChains() {
35
- return Object.keys(CHAINS);
36
- }
37
- function getChainById(chainId) {
38
- return Object.values(CHAINS).find((c) => c.chainId === chainId);
39
- }
40
- var CHAINS, ERC20_ABI;
41
- var init_chains = __esm({
42
- "src/chains/index.ts"() {
43
- "use strict";
44
- CHAINS = {
45
- // ============ Mainnet ============
46
- base: {
47
- name: "Base",
48
- chainId: 8453,
49
- rpc: "https://mainnet.base.org",
50
- usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
51
- explorer: "https://basescan.org/address/",
52
- explorerTx: "https://basescan.org/tx/",
53
- avgBlockTime: 2
54
- },
55
- polygon: {
56
- name: "Polygon",
57
- chainId: 137,
58
- rpc: "https://polygon-rpc.com",
59
- usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
60
- explorer: "https://polygonscan.com/address/",
61
- explorerTx: "https://polygonscan.com/tx/",
62
- avgBlockTime: 2
63
- },
64
- ethereum: {
65
- name: "Ethereum",
66
- chainId: 1,
67
- rpc: "https://eth.llamarpc.com",
68
- usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
69
- explorer: "https://etherscan.io/address/",
70
- explorerTx: "https://etherscan.io/tx/",
71
- avgBlockTime: 12
72
- },
73
- // ============ Testnet ============
74
- base_sepolia: {
75
- name: "Base Sepolia",
76
- chainId: 84532,
77
- rpc: "https://sepolia.base.org",
78
- usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
79
- explorer: "https://sepolia.basescan.org/address/",
80
- explorerTx: "https://sepolia.basescan.org/tx/",
81
- avgBlockTime: 2
82
- },
83
- sepolia: {
84
- name: "Sepolia",
85
- chainId: 11155111,
86
- rpc: "https://rpc.sepolia.org",
87
- usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
88
- explorer: "https://sepolia.etherscan.io/address/",
89
- explorerTx: "https://sepolia.etherscan.io/tx/",
90
- avgBlockTime: 12
91
- }
92
- };
93
- ERC20_ABI = [
94
- "function balanceOf(address owner) view returns (uint256)",
95
- "function transfer(address to, uint256 amount) returns (bool)",
96
- "function approve(address spender, uint256 amount) returns (bool)",
97
- "function allowance(address owner, address spender) view returns (uint256)",
98
- "function decimals() view returns (uint8)",
99
- "function symbol() view returns (string)",
100
- "function name() view returns (string)",
101
- "function nonces(address owner) view returns (uint256)",
102
- "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
103
- "event Transfer(address indexed from, address indexed to, uint256 value)",
104
- "event Approval(address indexed owner, address indexed spender, uint256 value)"
105
- ];
106
- }
107
- });
108
-
109
- // src/agent/AgentWallet.ts
110
- var AgentWallet_exports = {};
111
- __export(AgentWallet_exports, {
112
- AgentWallet: () => AgentWallet,
113
- getAgentAddress: () => getAgentAddress
114
- });
115
- import { ethers as ethers2 } from "ethers";
116
- import * as fs from "fs";
117
- import * as path from "path";
118
- function getAgentAddress(config) {
119
- const wallet = new AgentWallet(config);
120
- return wallet.address;
121
- }
122
- var PERMIT_ABI, AgentWallet;
123
- var init_AgentWallet = __esm({
124
- "src/agent/AgentWallet.ts"() {
125
- "use strict";
126
- init_chains();
127
- PERMIT_ABI = [
128
- ...ERC20_ABI,
129
- "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
130
- "function transferFrom(address from, address to, uint256 amount) returns (bool)",
131
- "function allowance(address owner, address spender) view returns (uint256)",
132
- "function nonces(address owner) view returns (uint256)"
133
- ];
134
- AgentWallet = class {
135
- chain;
136
- chainConfig;
137
- storageDir;
138
- _address = null;
139
- _privateKey = null;
140
- _wallet = null;
141
- _provider = null;
142
- _permits = /* @__PURE__ */ new Map();
143
- constructor(config = {}) {
144
- this.chain = config.chain || "base";
145
- this.chainConfig = getChain(this.chain);
146
- this.storageDir = config.storageDir || this.getDefaultStorageDir();
147
- this.ensureInitialized();
148
- }
149
- getDefaultStorageDir() {
150
- const home = process.env.HOME || process.env.USERPROFILE || ".";
151
- return path.join(home, ".moltspay");
152
- }
153
- getWalletPath() {
154
- return path.join(this.storageDir, "wallet.json");
155
- }
156
- getPermitsPath() {
157
- return path.join(this.storageDir, "permits.json");
158
- }
159
- /**
160
- * Auto-initialize: create wallet if not exists
161
- * This is called automatically in constructor
162
- */
163
- ensureInitialized() {
164
- if (!fs.existsSync(this.storageDir)) {
165
- fs.mkdirSync(this.storageDir, { recursive: true });
166
- }
167
- const walletPath = this.getWalletPath();
168
- if (fs.existsSync(walletPath)) {
169
- const data = JSON.parse(fs.readFileSync(walletPath, "utf-8"));
170
- this._address = data.address;
171
- this._privateKey = data.privateKey;
172
- } else {
173
- const wallet = ethers2.Wallet.createRandom();
174
- this._address = wallet.address;
175
- this._privateKey = wallet.privateKey;
176
- fs.writeFileSync(walletPath, JSON.stringify({
177
- address: this._address,
178
- privateKey: this._privateKey,
179
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
180
- chain: this.chain
181
- }, null, 2), { mode: 384 });
182
- }
183
- const permitsPath = this.getPermitsPath();
184
- if (fs.existsSync(permitsPath)) {
185
- const permits = JSON.parse(fs.readFileSync(permitsPath, "utf-8"));
186
- for (const [owner, permit] of Object.entries(permits)) {
187
- this._permits.set(owner.toLowerCase(), permit);
188
- }
189
- }
190
- }
191
- /** Agent's address (auto-generated on first use) */
192
- get address() {
193
- return this._address;
194
- }
195
- get wallet() {
196
- if (!this._wallet) {
197
- this._wallet = new ethers2.Wallet(this._privateKey, this.provider);
198
- }
199
- return this._wallet;
200
- }
201
- get provider() {
202
- if (!this._provider) {
203
- this._provider = new ethers2.JsonRpcProvider(this.chainConfig.rpc);
204
- }
205
- return this._provider;
206
- }
207
- /**
208
- * Store a Permit from Owner
209
- */
210
- storePermit(permit) {
211
- const ownerLower = permit.owner.toLowerCase();
212
- this._permits.set(ownerLower, permit);
213
- const permitsPath = this.getPermitsPath();
214
- const permits = {};
215
- for (const [owner, p] of this._permits) {
216
- permits[owner] = p;
217
- }
218
- fs.writeFileSync(permitsPath, JSON.stringify(permits, null, 2));
219
- }
220
- /**
221
- * Get stored permit for an owner
222
- */
223
- getPermit(owner) {
224
- return this._permits.get(owner.toLowerCase());
225
- }
226
- /**
227
- * Check allowance from an owner
228
- */
229
- async checkAllowance(owner) {
230
- const usdcContract = new ethers2.Contract(
231
- this.chainConfig.usdc,
232
- PERMIT_ABI,
233
- this.provider
234
- );
235
- const ownerAddress = ethers2.getAddress(owner);
236
- const [allowance, balance] = await Promise.all([
237
- usdcContract.allowance(ownerAddress, this.address),
238
- usdcContract.balanceOf(ownerAddress)
239
- ]);
240
- return {
241
- allowance: (Number(allowance) / 1e6).toFixed(2),
242
- ownerBalance: (Number(balance) / 1e6).toFixed(2),
243
- canSpend: Number(allowance) > 0
244
- };
245
- }
246
- /**
247
- * Spend USDC from Owner's wallet
248
- *
249
- * @param to - Recipient (service provider)
250
- * @param amount - Amount in USDC
251
- * @param permit - Optional, uses stored permit if not provided
252
- */
253
- async spend(to, amount, permit) {
254
- const toAddress = ethers2.getAddress(to);
255
- const amountWei = BigInt(Math.floor(amount * 1e6));
256
- let usePermit = permit;
257
- let ownerAddress;
258
- if (usePermit) {
259
- ownerAddress = ethers2.getAddress(usePermit.owner);
260
- this.storePermit(usePermit);
261
- } else {
262
- const usdcContract = new ethers2.Contract(
263
- this.chainConfig.usdc,
264
- PERMIT_ABI,
265
- this.provider
266
- );
267
- for (const [owner, p] of this._permits) {
268
- const allowance = await usdcContract.allowance(owner, this.address);
269
- if (BigInt(allowance) >= amountWei) {
270
- ownerAddress = ethers2.getAddress(owner);
271
- usePermit = p;
272
- break;
273
- }
274
- }
275
- if (!usePermit) {
276
- return {
277
- success: false,
278
- error: "No valid permit. Ask Owner to authorize spending first.",
279
- from: "",
280
- to: toAddress,
281
- amount
282
- };
283
- }
284
- }
285
- try {
286
- const usdcContract = new ethers2.Contract(
287
- this.chainConfig.usdc,
288
- PERMIT_ABI,
289
- this.wallet
290
- );
291
- const currentAllowance = await usdcContract.allowance(ownerAddress, this.address);
292
- if (BigInt(currentAllowance) < amountWei) {
293
- const now = Math.floor(Date.now() / 1e3);
294
- if (usePermit.deadline < now) {
295
- return {
296
- success: false,
297
- error: "Permit expired. Ask Owner for a new authorization.",
298
- from: ownerAddress,
299
- to: toAddress,
300
- amount
301
- };
302
- }
303
- const permitTx = await usdcContract.permit(
304
- ownerAddress,
305
- this.address,
306
- usePermit.value,
307
- usePermit.deadline,
308
- usePermit.v,
309
- usePermit.r,
310
- usePermit.s
311
- );
312
- await permitTx.wait();
313
- }
314
- const tx = await usdcContract.transferFrom(ownerAddress, toAddress, amountWei);
315
- await tx.wait();
316
- const newAllowance = await usdcContract.allowance(ownerAddress, this.address);
317
- return {
318
- success: true,
319
- txHash: tx.hash,
320
- from: ownerAddress,
321
- to: toAddress,
322
- amount,
323
- remainingAllowance: (Number(newAllowance) / 1e6).toFixed(2),
324
- explorerUrl: `${this.chainConfig.explorerTx}${tx.hash}`
325
- };
326
- } catch (error) {
327
- return {
328
- success: false,
329
- error: error.message,
330
- from: ownerAddress,
331
- to: toAddress,
332
- amount
333
- };
334
- }
335
- }
336
- /**
337
- * Get USDC balance
338
- */
339
- async getBalance() {
340
- const usdcContract = new ethers2.Contract(
341
- this.chainConfig.usdc,
342
- PERMIT_ABI,
343
- this.provider
344
- );
345
- const [usdcBalance, ethBalance] = await Promise.all([
346
- usdcContract.balanceOf(this.address),
347
- this.provider.getBalance(this.address)
348
- ]);
349
- return {
350
- usdc: (Number(usdcBalance) / 1e6).toFixed(2),
351
- eth: ethers2.formatEther(ethBalance)
352
- };
353
- }
354
- /**
355
- * Transfer USDC to a recipient (direct payment)
356
- *
357
- * This is the simplest payment method - Agent pays directly from its wallet.
358
- * Requires Agent wallet to have USDC (funded by Owner).
359
- *
360
- * @example
361
- * ```typescript
362
- * const wallet = new AgentWallet({ chain: 'base' });
363
- *
364
- * // Check balance
365
- * const balance = await wallet.getBalance();
366
- * console.log('USDC:', balance.usdc);
367
- *
368
- * // Pay for service
369
- * const result = await wallet.transfer({
370
- * to: '0xServiceProvider...',
371
- * amount: 0.99
372
- * });
373
- * console.log('Tx:', result.txHash);
374
- * ```
375
- */
376
- async transfer(params) {
377
- const { to, amount } = params;
378
- try {
379
- const toAddress = ethers2.getAddress(to);
380
- const amountWei = BigInt(Math.floor(amount * 1e6));
381
- const usdcContract = new ethers2.Contract(
382
- this.chainConfig.usdc,
383
- PERMIT_ABI,
384
- this.wallet
385
- );
386
- const balance = await usdcContract.balanceOf(this.address);
387
- if (BigInt(balance) < amountWei) {
388
- return {
389
- success: false,
390
- error: `Insufficient USDC: have ${(Number(balance) / 1e6).toFixed(2)}, need ${amount}`
391
- };
392
- }
393
- if (!await this.hasGas()) {
394
- return {
395
- success: false,
396
- error: "Insufficient ETH for gas. Need at least 0.0005 ETH."
397
- };
398
- }
399
- const tx = await usdcContract.transfer(toAddress, amountWei);
400
- const receipt = await tx.wait();
401
- if (receipt.status === 1) {
402
- return {
403
- success: true,
404
- txHash: tx.hash,
405
- from: this.address,
406
- to: toAddress,
407
- amount,
408
- explorerUrl: `${this.chainConfig.explorerTx}${tx.hash}`
409
- };
410
- } else {
411
- return {
412
- success: false,
413
- txHash: tx.hash,
414
- error: "Transaction reverted"
415
- };
416
- }
417
- } catch (error) {
418
- return {
419
- success: false,
420
- error: error.message
421
- };
422
- }
423
- }
424
- /**
425
- * Pay for a service (transfer USDC to service provider)
426
- *
427
- * This is the main method for Agent-to-Agent payments.
428
- * Returns payment data ready to submit to service API.
429
- *
430
- * @example
431
- * ```typescript
432
- * const wallet = new AgentWallet({ chain: 'base' });
433
- *
434
- * // Pay for Zen7 video service
435
- * const payment = await wallet.payService({
436
- * provider: '0xb8d6f2441e8f8dfB6288A74Cf73804cDd0484E0C',
437
- * amount: 0.99,
438
- * service: 'video_generation'
439
- * });
440
- *
441
- * if (payment.success) {
442
- * // Submit to service API
443
- * await fetch('/v1/video/generate', {
444
- * body: JSON.stringify({
445
- * prompt: "...",
446
- * payment: payment.paymentData // Ready to use!
447
- * })
448
- * });
449
- * }
450
- * ```
451
- */
452
- async payService(params) {
453
- const result = await this.transfer({
454
- to: params.provider,
455
- amount: params.amount
456
- });
457
- if (result.success && result.txHash) {
458
- return {
459
- success: true,
460
- txHash: result.txHash,
461
- explorerUrl: result.explorerUrl,
462
- paymentData: {
463
- method: "transfer",
464
- chain: this.chain,
465
- tx_hash: result.txHash
466
- }
467
- };
468
- } else {
469
- return {
470
- success: false,
471
- error: result.error
472
- };
473
- }
474
- }
475
- /**
476
- * Get gas balance (ETH needed for transactions)
477
- */
478
- async getGasBalance() {
479
- const balance = await this.provider.getBalance(this.address);
480
- return ethers2.formatEther(balance);
481
- }
482
- /**
483
- * Check if agent has enough gas
484
- */
485
- async hasGas(minEth = 5e-4) {
486
- const balance = await this.getGasBalance();
487
- return parseFloat(balance) >= minEth;
488
- }
489
- /**
490
- * Generate authorization request for Owner
491
- * Owner can sign this with CLI (ethers) or MetaMask
492
- */
493
- async generateAuthRequest(params) {
494
- const { ownerAddress, amount, expiresInHours = 168 } = params;
495
- const deadline = Math.floor(Date.now() / 1e3) + expiresInHours * 3600;
496
- const value = BigInt(Math.floor(amount * 1e6)).toString();
497
- const usdcContract = new ethers2.Contract(
498
- this.chainConfig.usdc,
499
- PERMIT_ABI,
500
- this.provider
501
- );
502
- const nonce = Number(await usdcContract.nonces(ownerAddress));
503
- const domain = {
504
- name: "USD Coin",
505
- version: "2",
506
- chainId: this.chainConfig.chainId,
507
- verifyingContract: this.chainConfig.usdc
508
- };
509
- const types = {
510
- Permit: [
511
- { name: "owner", type: "address" },
512
- { name: "spender", type: "address" },
513
- { name: "value", type: "uint256" },
514
- { name: "nonce", type: "uint256" },
515
- { name: "deadline", type: "uint256" }
516
- ]
517
- };
518
- const permitMessage = {
519
- owner: ownerAddress,
520
- spender: this.address,
521
- value,
522
- nonce,
523
- deadline
524
- };
525
- const typedData = {
526
- types: { ...types, EIP712Domain: [
527
- { name: "name", type: "string" },
528
- { name: "version", type: "string" },
529
- { name: "chainId", type: "uint256" },
530
- { name: "verifyingContract", type: "address" }
531
- ] },
532
- primaryType: "Permit",
533
- domain,
534
- message: permitMessage
535
- };
536
- const cliCommand = `npx moltspay sign-permit \\
537
- --owner ${ownerAddress} \\
538
- --spender ${this.address} \\
539
- --amount ${amount} \\
540
- --deadline ${deadline} \\
541
- --nonce ${nonce} \\
542
- --chain ${this.chain}`;
543
- const message = `\u{1F510} Authorization Request
544
-
545
- I need permission to spend up to ${amount} USDC from your wallet.
546
-
547
- **Details:**
548
- - Your wallet: ${ownerAddress}
549
- - My address: ${this.address}
550
- - Amount: ${amount} USDC
551
- - Expires: ${new Date(deadline * 1e3).toISOString()}
552
- - Chain: ${this.chainConfig.name}
553
-
554
- **Option 1: Sign with CLI** (if you have the private key)
555
- \`\`\`
556
- ${cliCommand}
557
- \`\`\`
558
-
559
- **Option 2: Sign with MetaMask**
560
- Visit: https://moltspay.vercel.app/permit?data=${encodeURIComponent(JSON.stringify(typedData))}
561
-
562
- After signing, send me the signature (v, r, s).`;
563
- return { message, typedData, cliCommand };
564
- }
565
- };
566
- }
567
- });
568
-
569
- // src/cdp/index.ts
570
- var cdp_exports = {};
571
- __export(cdp_exports, {
572
- CDPWallet: () => CDPWallet,
573
- getCDPWalletAddress: () => getCDPWalletAddress,
574
- initCDPWallet: () => initCDPWallet,
575
- isCDPAvailable: () => isCDPAvailable,
576
- loadCDPWallet: () => loadCDPWallet
577
- });
578
- import * as fs3 from "fs";
579
- import * as path3 from "path";
580
- function isCDPAvailable() {
581
- try {
582
- __require.resolve("@coinbase/cdp-sdk");
583
- return true;
584
- } catch {
585
- return false;
586
- }
587
- }
588
- function getCDPCredentials(config) {
589
- const apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;
590
- const apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;
591
- const walletSecret = config.walletSecret || process.env.CDP_WALLET_SECRET;
592
- if (!apiKeyId || !apiKeySecret) {
593
- return null;
594
- }
595
- return { apiKeyId, apiKeySecret, walletSecret };
596
- }
597
- async function initCDPWallet(config = {}) {
598
- const storageDir = config.storageDir || DEFAULT_STORAGE_DIR2;
599
- const chain = config.chain || "base";
600
- const storagePath = path3.join(storageDir, CDP_CONFIG_FILE);
601
- if (fs3.existsSync(storagePath)) {
602
- try {
603
- const data = JSON.parse(fs3.readFileSync(storagePath, "utf-8"));
604
- return {
605
- success: true,
606
- address: data.address,
607
- walletId: data.walletId,
608
- isNew: false,
609
- storagePath
610
- };
611
- } catch (error) {
612
- }
613
- }
614
- if (!isCDPAvailable()) {
615
- return {
616
- success: false,
617
- error: "CDP SDK not installed. Run: npm install @coinbase/cdp-sdk"
618
- };
619
- }
620
- const creds = getCDPCredentials(config);
621
- if (!creds) {
622
- return {
623
- success: false,
624
- error: "CDP credentials not found. Set CDP_API_KEY_ID and CDP_API_KEY_SECRET environment variables."
625
- };
626
- }
627
- try {
628
- const { CdpClient } = await import("@coinbase/cdp-sdk");
629
- const cdp = new CdpClient({
630
- apiKeyId: creds.apiKeyId,
631
- apiKeySecret: creds.apiKeySecret,
632
- walletSecret: creds.walletSecret
633
- });
634
- const account = await cdp.evm.createAccount();
635
- if (!fs3.existsSync(storageDir)) {
636
- fs3.mkdirSync(storageDir, { recursive: true });
637
- }
638
- const walletData = {
639
- address: account.address,
640
- walletId: account.address,
641
- // CDP uses address as ID for EVM
642
- chain,
643
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
644
- };
645
- fs3.writeFileSync(storagePath, JSON.stringify(walletData, null, 2), { mode: 384 });
646
- return {
647
- success: true,
648
- address: account.address,
649
- walletId: account.address,
650
- isNew: true,
651
- storagePath
652
- };
653
- } catch (error) {
654
- return {
655
- success: false,
656
- error: error.message
657
- };
658
- }
659
- }
660
- function loadCDPWallet(config = {}) {
661
- const storageDir = config.storageDir || DEFAULT_STORAGE_DIR2;
662
- const storagePath = path3.join(storageDir, CDP_CONFIG_FILE);
663
- if (!fs3.existsSync(storagePath)) {
664
- return null;
665
- }
666
- try {
667
- return JSON.parse(fs3.readFileSync(storagePath, "utf-8"));
668
- } catch {
669
- return null;
670
- }
671
- }
672
- function getCDPWalletAddress(storageDir) {
673
- const data = loadCDPWallet({ storageDir });
674
- return data?.address || null;
675
- }
676
- var DEFAULT_STORAGE_DIR2, CDP_CONFIG_FILE, CDPWallet;
677
- var init_cdp = __esm({
678
- "src/cdp/index.ts"() {
679
- "use strict";
680
- init_chains();
681
- DEFAULT_STORAGE_DIR2 = path3.join(process.env.HOME || ".", ".moltspay");
682
- CDP_CONFIG_FILE = "cdp-wallet.json";
683
- CDPWallet = class {
684
- address;
685
- chain;
686
- chainConfig;
687
- storageDir;
688
- constructor(config = {}) {
689
- this.storageDir = config.storageDir || DEFAULT_STORAGE_DIR2;
690
- this.chain = config.chain || "base";
691
- this.chainConfig = getChain(this.chain);
692
- const data = loadCDPWallet(config);
693
- if (!data) {
694
- throw new Error("CDP wallet not initialized. Run: npx moltspay init --cdp");
695
- }
696
- this.address = data.address;
697
- }
698
- /**
699
- * Get USDC balance
700
- */
701
- async getBalance() {
702
- const { ethers: ethers11 } = await import("ethers");
703
- const provider = new ethers11.JsonRpcProvider(this.chainConfig.rpc);
704
- const usdcContract = new ethers11.Contract(
705
- this.chainConfig.usdc,
706
- ["function balanceOf(address) view returns (uint256)"],
707
- provider
708
- );
709
- const [usdcBalance, ethBalance] = await Promise.all([
710
- usdcContract.balanceOf(this.address),
711
- provider.getBalance(this.address)
712
- ]);
713
- return {
714
- usdc: (Number(usdcBalance) / 1e6).toFixed(2),
715
- eth: ethers11.formatEther(ethBalance)
716
- };
717
- }
718
- /**
719
- * Transfer USDC to a recipient
720
- *
721
- * Requires CDP SDK and credentials to sign transactions.
722
- */
723
- async transfer(params) {
724
- if (!isCDPAvailable()) {
725
- return { success: false, error: "CDP SDK not installed" };
726
- }
727
- const creds = getCDPCredentials({});
728
- if (!creds) {
729
- return { success: false, error: "CDP credentials not found" };
730
- }
731
- try {
732
- const { CdpClient } = await import("@coinbase/cdp-sdk");
733
- const { ethers: ethers11 } = await import("ethers");
734
- const cdp = new CdpClient({
735
- apiKeyId: creds.apiKeyId,
736
- apiKeySecret: creds.apiKeySecret,
737
- walletSecret: creds.walletSecret
738
- });
739
- const account = await cdp.evm.getAccount({ address: this.address });
740
- const amountWei = BigInt(Math.floor(params.amount * 1e6));
741
- const iface = new ethers11.Interface([
742
- "function transfer(address to, uint256 amount) returns (bool)"
743
- ]);
744
- const callData = iface.encodeFunctionData("transfer", [params.to, amountWei]);
745
- const txOptions = {
746
- to: this.chainConfig.usdc,
747
- data: callData
748
- };
749
- const tx = await account.sendTransaction(txOptions);
750
- return {
751
- success: true,
752
- txHash: tx.transactionHash,
753
- explorerUrl: `${this.chainConfig.explorerTx}${tx.transactionHash}`
754
- };
755
- } catch (error) {
756
- return {
757
- success: false,
758
- error: error.message
759
- };
760
- }
761
- }
762
- /**
763
- * Create viem-compatible signer for x402
764
- *
765
- * This allows using CDP wallet with x402 protocol.
766
- */
767
- async getViemAccount() {
768
- if (!isCDPAvailable()) {
769
- throw new Error("CDP SDK not installed");
770
- }
771
- const creds = getCDPCredentials({});
772
- if (!creds) {
773
- throw new Error("CDP credentials not found");
774
- }
775
- const { CdpClient } = await import("@coinbase/cdp-sdk");
776
- const { toAccount } = await import("viem/accounts");
777
- const cdp = new CdpClient({
778
- apiKeyId: creds.apiKeyId,
779
- apiKeySecret: creds.apiKeySecret,
780
- walletSecret: creds.walletSecret
781
- });
782
- const account = await cdp.evm.getAccount({ address: this.address });
783
- return toAccount(account);
784
- }
785
- };
786
- }
787
- });
788
-
789
- // src/x402/client.ts
790
- var client_exports = {};
791
- __export(client_exports, {
792
- createX402Client: () => createX402Client,
793
- isX402Available: () => isX402Available,
794
- x402Fetch: () => x402Fetch
795
- });
796
- function isX402Available() {
797
- try {
798
- __require.resolve("@x402/fetch");
799
- __require.resolve("@x402/evm");
800
- return true;
801
- } catch {
802
- return false;
803
- }
804
- }
805
- async function createLocalX402Client(config) {
806
- const { AgentWallet: AgentWallet2 } = await Promise.resolve().then(() => (init_AgentWallet(), AgentWallet_exports));
807
- const { ethers: ethers11 } = await import("ethers");
808
- const wallet = new AgentWallet2({
809
- chain: config.chain,
810
- storageDir: config.storageDir
811
- });
812
- const fs4 = await import("fs");
813
- const path4 = await import("path");
814
- const storageDir = config.storageDir || path4.join(process.env.HOME || ".", ".moltspay");
815
- const walletPath = path4.join(storageDir, "wallet.json");
816
- const walletData = JSON.parse(fs4.readFileSync(walletPath, "utf-8"));
817
- const privateKey = config.privateKey || walletData.privateKey;
818
- const { privateKeyToAccount } = await import("viem/accounts");
819
- const signer = privateKeyToAccount(privateKey);
820
- const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
821
- const { registerExactEvmScheme } = await import("@x402/evm/exact/client");
822
- const client = new x402Client();
823
- registerExactEvmScheme(client, { signer });
824
- const fetchWithPayment = wrapFetchWithPayment(fetch, client);
825
- return {
826
- fetch: fetchWithPayment,
827
- address: wallet.address,
828
- chain: config.chain || "base"
829
- };
830
- }
831
- async function createCDPX402Client(config) {
832
- const { CDPWallet: CDPWallet2 } = await Promise.resolve().then(() => (init_cdp(), cdp_exports));
833
- const wallet = new CDPWallet2({
834
- chain: config.chain,
835
- storageDir: config.storageDir
836
- });
837
- const signer = await wallet.getViemAccount();
838
- const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
839
- const { registerExactEvmScheme } = await import("@x402/evm/exact/client");
840
- const client = new x402Client();
841
- registerExactEvmScheme(client, { signer });
842
- const fetchWithPayment = wrapFetchWithPayment(fetch, client);
843
- return {
844
- fetch: fetchWithPayment,
845
- address: wallet.address,
846
- chain: config.chain || "base"
847
- };
848
- }
849
- async function createX402Client(config = {}) {
850
- if (!isX402Available()) {
851
- throw new Error("x402 packages not installed. Run: npm install @x402/fetch @x402/evm");
852
- }
853
- if (config.useCDP) {
854
- return createCDPX402Client(config);
855
- } else {
856
- return createLocalX402Client(config);
857
- }
858
- }
859
- async function x402Fetch(input, init, config) {
860
- const client = await createX402Client(config);
861
- return client.fetch(input, init);
862
- }
863
- var init_client = __esm({
864
- "src/x402/client.ts"() {
865
- "use strict";
866
- }
867
- });
868
-
869
- // src/cli.ts
870
- import { Command } from "commander";
871
-
872
- // src/agent/PaymentAgent.ts
873
- init_chains();
874
- import { ethers } from "ethers";
875
- var PaymentAgent = class _PaymentAgent {
876
- chain;
877
- chainConfig;
878
- walletAddress;
879
- provider;
880
- usdcContract;
881
- static PROTOCOL_VERSION = "1.0";
882
- constructor(config = {}) {
883
- this.chain = config.chain || "base_sepolia";
884
- this.chainConfig = getChain(this.chain);
885
- this.walletAddress = config.walletAddress || process.env.PAYMENT_AGENT_WALLET || "";
886
- if (!this.walletAddress) {
887
- throw new Error("walletAddress is required. Set via config or PAYMENT_AGENT_WALLET env var.");
888
- }
889
- const rpcUrl = config.rpcUrl || this.chainConfig.rpc;
890
- this.provider = new ethers.JsonRpcProvider(rpcUrl);
891
- this.usdcContract = new ethers.Contract(
892
- this.chainConfig.usdc,
893
- ERC20_ABI,
894
- this.provider
895
- );
896
- }
897
- /**
898
- * Generate payment request(Invoice)
899
- */
900
- createInvoice(params) {
901
- const expiresMinutes = params.expiresMinutes || 30;
902
- const expiresAt = new Date(Date.now() + expiresMinutes * 60 * 1e3).toISOString();
903
- const invoice = {
904
- type: "payment_request",
905
- version: _PaymentAgent.PROTOCOL_VERSION,
906
- order_id: params.orderId,
907
- service: params.service,
908
- description: params.description || `${params.service} service`,
909
- amount: params.amount.toFixed(2),
910
- token: "USDC",
911
- chain: this.chain,
912
- chain_id: this.chainConfig.chainId,
913
- recipient: this.walletAddress,
914
- memo: params.orderId,
915
- expires_at: expiresAt,
916
- deep_link: this.generateDeepLink(params.amount, params.orderId),
917
- explorer_url: `${this.chainConfig.explorer}${this.walletAddress}`
918
- };
919
- if (params.metadata) {
920
- invoice.metadata = params.metadata;
921
- }
922
- return invoice;
923
- }
924
- /**
925
- * Generate wallet deep link(supports MetaMask etc)
926
- */
927
- generateDeepLink(amount, memo) {
928
- const amountWei = Math.floor(amount * 1e6);
929
- return `https://metamask.app.link/send/${this.chainConfig.usdc}@${this.chainConfig.chainId}/transfer?address=${this.walletAddress}&uint256=${amountWei}`;
930
- }
931
- /**
932
- * Verify on-chain payment
933
- */
934
- async verifyPayment(txHash, options = {}) {
935
- try {
936
- if (!txHash.startsWith("0x")) {
937
- txHash = "0x" + txHash;
938
- }
939
- const receipt = await this.provider.getTransactionReceipt(txHash);
940
- if (!receipt) {
941
- return { verified: false, error: "Transaction not found", pending: true };
942
- }
943
- if (receipt.status !== 1) {
944
- return { verified: false, error: "Transaction failed" };
945
- }
946
- const transferTopic = ethers.id("Transfer(address,address,uint256)");
947
- const usdcAddress = this.chainConfig.usdc.toLowerCase();
948
- for (const log of receipt.logs) {
949
- if (log.address.toLowerCase() === usdcAddress && log.topics.length >= 3 && log.topics[0] === transferTopic) {
950
- const from = ethers.getAddress("0x" + log.topics[1].slice(-40));
951
- const to = ethers.getAddress("0x" + log.topics[2].slice(-40));
952
- const amountWei = BigInt(log.data);
953
- const amount = Number(amountWei) / 1e6;
954
- if (to.toLowerCase() !== this.walletAddress.toLowerCase()) {
955
- continue;
956
- }
957
- const tolerance = options.tolerance ?? 0.01;
958
- if (options.expectedAmount) {
959
- const diff = Math.abs(amount - options.expectedAmount);
960
- if (diff > options.expectedAmount * tolerance) {
961
- return {
962
- verified: false,
963
- error: `Amount mismatch: expected ${options.expectedAmount}, got ${amount}`
964
- };
965
- }
966
- }
967
- const currentBlock = await this.provider.getBlockNumber();
968
- return {
969
- verified: true,
970
- tx_hash: txHash,
971
- amount: amount.toFixed(2),
972
- token: "USDC",
973
- from,
974
- to,
975
- block_number: receipt.blockNumber,
976
- confirmations: currentBlock - receipt.blockNumber,
977
- explorer_url: `${this.chainConfig.explorerTx}${txHash}`
978
- };
979
- }
980
- }
981
- return { verified: false, error: "No USDC transfer to recipient found in transaction" };
982
- } catch (error) {
983
- return { verified: false, error: error.message };
984
- }
985
- }
986
- /**
987
- * Scan recent transfers (match by amount)
988
- */
989
- async scanRecentTransfers(expectedAmount, timeoutMinutes = 30) {
990
- try {
991
- const currentBlock = await this.provider.getBlockNumber();
992
- const blocksPerMinute = Math.ceil(60 / this.chainConfig.avgBlockTime);
993
- const fromBlock = currentBlock - timeoutMinutes * blocksPerMinute;
994
- const transferTopic = ethers.id("Transfer(address,address,uint256)");
995
- const recipientTopic = ethers.zeroPadValue(this.walletAddress, 32);
996
- const logs = await this.provider.getLogs({
997
- address: this.chainConfig.usdc,
998
- topics: [transferTopic, null, recipientTopic],
999
- fromBlock,
1000
- toBlock: "latest"
1001
- });
1002
- for (const log of logs) {
1003
- const amountWei = BigInt(log.data);
1004
- const amount = Number(amountWei) / 1e6;
1005
- if (Math.abs(amount - expectedAmount) < 0.01) {
1006
- const from = ethers.getAddress("0x" + log.topics[1].slice(-40));
1007
- return {
1008
- verified: true,
1009
- tx_hash: log.transactionHash,
1010
- amount: amount.toFixed(2),
1011
- token: "USDC",
1012
- from,
1013
- to: this.walletAddress,
1014
- block_number: log.blockNumber,
1015
- explorer_url: `${this.chainConfig.explorerTx}${log.transactionHash}`
1016
- };
1017
- }
1018
- }
1019
- return { verified: false, error: "No matching payment found" };
1020
- } catch (error) {
1021
- return { verified: false, error: error.message };
1022
- }
1023
- }
1024
- /**
1025
- * Get wallet balance
1026
- */
1027
- async getBalance(address) {
1028
- const addr = address || this.walletAddress;
1029
- const [ethBalance, usdcBalance] = await Promise.all([
1030
- this.provider.getBalance(addr),
1031
- this.usdcContract.balanceOf(addr)
1032
- ]);
1033
- return {
1034
- address: addr,
1035
- eth: ethers.formatEther(ethBalance),
1036
- usdc: (Number(usdcBalance) / 1e6).toFixed(2),
1037
- chain: this.chain
1038
- };
1039
- }
1040
- /**
1041
- * Format Invoice as human-readable message
1042
- */
1043
- formatInvoiceMessage(invoice, includeJson = true) {
1044
- let msg = `\u{1F3AC} **Payment Request**
1045
-
1046
- **Service:** ${invoice.service}
1047
- **Price:** ${invoice.amount} USDC (${this.chainConfig.name})
1048
-
1049
- **\u{1F4B3} Payment Options:**
1050
-
1051
- 1\uFE0F\u20E3 **Direct Transfer:**
1052
- Send exactly \`${invoice.amount} USDC\` to:
1053
- \`${invoice.recipient}\`
1054
- (Network: ${this.chainConfig.name})
1055
-
1056
- 2\uFE0F\u20E3 **One-Click Pay (MetaMask):**
1057
- ${invoice.deep_link}
1058
-
1059
- \u23F1\uFE0F Expires: ${invoice.expires_at}`;
1060
- if (includeJson) {
1061
- msg += `
1062
-
1063
- 3\uFE0F\u20E3 **For AI Agents:**
1064
- \`\`\`json
1065
- ${JSON.stringify(invoice, null, 2)}
1066
- \`\`\``;
1067
- }
1068
- msg += `
1069
-
1070
- After payment, reply with your tx hash:
1071
- \`paid: 0x...\``;
1072
- return msg;
1073
- }
1074
- };
1075
-
1076
- // src/index.ts
1077
- init_AgentWallet();
1078
-
1079
- // src/wallet/Wallet.ts
1080
- init_chains();
1081
- import { ethers as ethers3 } from "ethers";
1082
- var Wallet = class {
1083
- chain;
1084
- chainConfig;
1085
- address;
1086
- wallet;
1087
- provider;
1088
- usdcContract;
1089
- constructor(config = {}) {
1090
- this.chain = config.chain || "base_sepolia";
1091
- this.chainConfig = getChain(this.chain);
1092
- const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;
1093
- if (!privateKey) {
1094
- throw new Error("privateKey is required. Set via config or PAYMENT_AGENT_PRIVATE_KEY env var.");
1095
- }
1096
- const rpcUrl = config.rpcUrl || this.chainConfig.rpc;
1097
- this.provider = new ethers3.JsonRpcProvider(rpcUrl);
1098
- this.wallet = new ethers3.Wallet(privateKey, this.provider);
1099
- this.address = this.wallet.address;
1100
- this.usdcContract = new ethers3.Contract(
1101
- this.chainConfig.usdc,
1102
- ERC20_ABI,
1103
- this.wallet
1104
- );
1105
- }
1106
- /**
1107
- * Get wallet balance
1108
- */
1109
- async getBalance() {
1110
- const [ethBalance, usdcBalance] = await Promise.all([
1111
- this.provider.getBalance(this.address),
1112
- this.usdcContract.balanceOf(this.address)
1113
- ]);
1114
- return {
1115
- address: this.address,
1116
- eth: ethers3.formatEther(ethBalance),
1117
- usdc: (Number(usdcBalance) / 1e6).toFixed(2),
1118
- chain: this.chain
1119
- };
1120
- }
1121
- /**
1122
- * Send USDC transfer
1123
- */
1124
- async transfer(to, amount) {
1125
- try {
1126
- to = ethers3.getAddress(to);
1127
- const amountWei = BigInt(Math.floor(amount * 1e6));
1128
- const balance = await this.usdcContract.balanceOf(this.address);
1129
- if (BigInt(balance) < amountWei) {
1130
- return {
1131
- success: false,
1132
- error: `Insufficient USDC balance: ${Number(balance) / 1e6} < ${amount}`
1133
- };
1134
- }
1135
- const tx = await this.usdcContract.transfer(to, amountWei);
1136
- const receipt = await tx.wait();
1137
- if (receipt.status === 1) {
1138
- return {
1139
- success: true,
1140
- tx_hash: tx.hash,
1141
- from: this.address,
1142
- to,
1143
- amount,
1144
- gas_used: Number(receipt.gasUsed),
1145
- block_number: receipt.blockNumber,
1146
- explorer_url: `${this.chainConfig.explorerTx}${tx.hash}`
1147
- };
1148
- } else {
1149
- return {
1150
- success: false,
1151
- tx_hash: tx.hash,
1152
- error: "Transaction reverted"
1153
- };
1154
- }
1155
- } catch (error) {
1156
- return {
1157
- success: false,
1158
- error: error.message
1159
- };
1160
- }
1161
- }
1162
- /**
1163
- * Get ETH balance
1164
- */
1165
- async getEthBalance() {
1166
- const balance = await this.provider.getBalance(this.address);
1167
- return ethers3.formatEther(balance);
1168
- }
1169
- /**
1170
- * Get USDC balance
1171
- */
1172
- async getUsdcBalance() {
1173
- const balance = await this.usdcContract.balanceOf(this.address);
1174
- return (Number(balance) / 1e6).toFixed(2);
1175
- }
1176
- };
1177
-
1178
- // src/audit/AuditLog.ts
1179
- import * as fs2 from "fs";
1180
- import * as path2 from "path";
1181
- import * as crypto from "crypto";
1182
- var AuditLog = class {
1183
- basePath;
1184
- lastHash = "0000000000000000";
1185
- constructor(basePath) {
1186
- this.basePath = basePath || path2.join(process.cwd(), "data", "audit");
1187
- this.ensureDir();
1188
- this.loadLastHash();
1189
- }
1190
- /**
1191
- * Record audit log
1192
- */
1193
- async log(params) {
1194
- const now = /* @__PURE__ */ new Date();
1195
- const entry = {
1196
- timestamp: now.getTime() / 1e3,
1197
- datetime: now.toISOString(),
1198
- action: params.action,
1199
- request_id: params.request_id,
1200
- from: params.from,
1201
- to: params.to,
1202
- amount: params.amount,
1203
- tx_hash: params.tx_hash,
1204
- reason: params.reason,
1205
- requester: params.requester,
1206
- prev_hash: this.lastHash,
1207
- hash: "",
1208
- // Filled after calculation
1209
- metadata: params.metadata
1210
- };
1211
- entry.hash = this.calculateHash(entry);
1212
- this.lastHash = entry.hash;
1213
- const filePath = this.getFilePath(now);
1214
- const line = JSON.stringify(entry) + "\n";
1215
- fs2.appendFileSync(filePath, line, "utf-8");
1216
- return entry;
1217
- }
1218
- /**
1219
- * Read logs for specified date
1220
- */
1221
- read(date) {
1222
- const filePath = this.getFilePath(date || /* @__PURE__ */ new Date());
1223
- if (!fs2.existsSync(filePath)) {
1224
- return [];
1225
- }
1226
- const content = fs2.readFileSync(filePath, "utf-8");
1227
- const lines = content.trim().split("\n").filter(Boolean);
1228
- return lines.map((line) => JSON.parse(line));
1229
- }
1230
- /**
1231
- * Verify log integrity
1232
- */
1233
- verify(date) {
1234
- const entries = this.read(date);
1235
- const errors = [];
1236
- for (let i = 0; i < entries.length; i++) {
1237
- const entry = entries[i];
1238
- const expectedHash = this.calculateHash(entry);
1239
- if (entry.hash !== expectedHash) {
1240
- errors.push(`Entry ${i}: hash mismatch (expected ${expectedHash}, got ${entry.hash})`);
1241
- }
1242
- if (i > 0 && entry.prev_hash !== entries[i - 1].hash) {
1243
- errors.push(`Entry ${i}: prev_hash mismatch`);
1244
- }
1245
- }
1246
- return { valid: errors.length === 0, errors };
1247
- }
1248
- /**
1249
- * Search logs
1250
- */
1251
- search(filter) {
1252
- const results = [];
1253
- const startDate = filter.startDate || new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3);
1254
- const endDate = filter.endDate || /* @__PURE__ */ new Date();
1255
- const current = new Date(startDate);
1256
- while (current <= endDate) {
1257
- const entries = this.read(current);
1258
- for (const entry of entries) {
1259
- let match = true;
1260
- if (filter.action && entry.action !== filter.action) match = false;
1261
- if (filter.request_id && entry.request_id !== filter.request_id) match = false;
1262
- if (filter.from && entry.from?.toLowerCase() !== filter.from.toLowerCase()) match = false;
1263
- if (filter.to && entry.to?.toLowerCase() !== filter.to.toLowerCase()) match = false;
1264
- if (match) {
1265
- results.push(entry);
1266
- }
1267
- }
1268
- current.setDate(current.getDate() + 1);
1269
- }
1270
- return results;
1271
- }
1272
- /**
1273
- * Get log file path
1274
- */
1275
- getFilePath(date) {
1276
- const dateStr = date.toISOString().slice(0, 10);
1277
- return path2.join(this.basePath, `audit_${dateStr}.jsonl`);
1278
- }
1279
- /**
1280
- * Calculate entry hash
1281
- */
1282
- calculateHash(entry) {
1283
- const data = {
1284
- timestamp: entry.timestamp,
1285
- action: entry.action,
1286
- request_id: entry.request_id,
1287
- from: entry.from,
1288
- to: entry.to,
1289
- amount: entry.amount,
1290
- tx_hash: entry.tx_hash,
1291
- prev_hash: entry.prev_hash
1292
- };
1293
- const str = JSON.stringify(data);
1294
- return crypto.createHash("sha256").update(str).digest("hex").slice(0, 16);
1295
- }
1296
- /**
1297
- * Load last log entry hash
1298
- */
1299
- loadLastHash() {
1300
- const today = /* @__PURE__ */ new Date();
1301
- for (let i = 0; i < 2; i++) {
1302
- const date = new Date(today);
1303
- date.setDate(date.getDate() - i);
1304
- const entries = this.read(date);
1305
- if (entries.length > 0) {
1306
- this.lastHash = entries[entries.length - 1].hash;
1307
- return;
1308
- }
1309
- }
1310
- }
1311
- /**
1312
- * Ensure directory exists
1313
- */
1314
- ensureDir() {
1315
- if (!fs2.existsSync(this.basePath)) {
1316
- fs2.mkdirSync(this.basePath, { recursive: true });
1317
- }
1318
- }
1319
- };
1320
-
1321
- // src/wallet/SecureWallet.ts
1322
- var DEFAULT_LIMITS = {
1323
- singleMax: 100,
1324
- // Single max $100
1325
- dailyMax: 1e3,
1326
- // Daily max $1000
1327
- requireWhitelist: true
1328
- };
1329
- var SecureWallet = class {
1330
- wallet;
1331
- limits;
1332
- whitelist;
1333
- auditLog;
1334
- dailyTotal = 0;
1335
- dailyDate = "";
1336
- pendingTransfers = /* @__PURE__ */ new Map();
1337
- constructor(config = {}) {
1338
- this.wallet = new Wallet({
1339
- chain: config.chain,
1340
- privateKey: config.privateKey
1341
- });
1342
- this.limits = { ...DEFAULT_LIMITS, ...config.limits };
1343
- this.whitelist = new Set((config.whitelist || []).map((a) => a.toLowerCase()));
1344
- this.auditLog = new AuditLog(config.auditPath);
1345
- }
1346
- /**
1347
- * Get wallet address
1348
- */
1349
- get address() {
1350
- return this.wallet.address;
1351
- }
1352
- /**
1353
- * Get balance
1354
- */
1355
- async getBalance() {
1356
- return this.wallet.getBalance();
1357
- }
1358
- /**
1359
- * Secure transfer (with limit and whitelist checks)
1360
- *
1361
- * Supports two calling methods:
1362
- * - transfer({ to, amount, reason?, requester? })
1363
- * - transfer(to, amount)
1364
- */
1365
- async transfer(paramsOrTo, amountArg) {
1366
- let params;
1367
- if (typeof paramsOrTo === "string") {
1368
- params = {
1369
- to: paramsOrTo,
1370
- amount: typeof amountArg === "string" ? parseFloat(amountArg) : amountArg || 0
1371
- };
1372
- } else {
1373
- params = paramsOrTo;
1374
- }
1375
- const { to, amount, reason, requester } = params;
1376
- const toAddress = to.toLowerCase();
1377
- const requestId = `tr_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
1378
- await this.auditLog.log({
1379
- action: "transfer_request",
1380
- request_id: requestId,
1381
- from: this.wallet.address,
1382
- to,
1383
- amount,
1384
- reason,
1385
- requester
1386
- });
1387
- if (this.limits.requireWhitelist && !this.whitelist.has(toAddress)) {
1388
- await this.auditLog.log({
1389
- action: "transfer_failed",
1390
- request_id: requestId,
1391
- metadata: { error: "Address not in whitelist" }
1392
- });
1393
- return { success: false, error: `Address not in whitelist: ${to}` };
1394
- }
1395
- if (amount > this.limits.singleMax) {
1396
- const pending = {
1397
- id: requestId,
1398
- to,
1399
- amount,
1400
- reason,
1401
- requester,
1402
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
1403
- status: "pending"
1404
- };
1405
- this.pendingTransfers.set(requestId, pending);
1406
- await this.auditLog.log({
1407
- action: "transfer_request",
1408
- request_id: requestId,
1409
- metadata: { pending: true, reason: "Exceeds single limit" }
1410
- });
1411
- return {
1412
- success: false,
1413
- error: `Amount ${amount} exceeds single limit ${this.limits.singleMax}. Pending approval: ${requestId}`
1414
- };
1415
- }
1416
- this.updateDailyTotal();
1417
- if (this.dailyTotal + amount > this.limits.dailyMax) {
1418
- const pending = {
1419
- id: requestId,
1420
- to,
1421
- amount,
1422
- reason,
1423
- requester,
1424
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
1425
- status: "pending"
1426
- };
1427
- this.pendingTransfers.set(requestId, pending);
1428
- await this.auditLog.log({
1429
- action: "transfer_request",
1430
- request_id: requestId,
1431
- metadata: { pending: true, reason: "Exceeds daily limit" }
1432
- });
1433
- return {
1434
- success: false,
1435
- error: `Daily limit would be exceeded (${this.dailyTotal} + ${amount} > ${this.limits.dailyMax}). Pending approval: ${requestId}`
1436
- };
1437
- }
1438
- const result = await this.wallet.transfer(to, amount);
1439
- if (result.success) {
1440
- this.dailyTotal += amount;
1441
- await this.auditLog.log({
1442
- action: "transfer_executed",
1443
- request_id: requestId,
1444
- from: this.wallet.address,
1445
- to,
1446
- amount,
1447
- tx_hash: result.tx_hash,
1448
- reason,
1449
- requester
1450
- });
1451
- } else {
1452
- await this.auditLog.log({
1453
- action: "transfer_failed",
1454
- request_id: requestId,
1455
- metadata: { error: result.error }
1456
- });
1457
- }
1458
- return result;
1459
- }
1460
- /**
1461
- * Approve pending transfer
1462
- */
1463
- async approve(requestId, approver) {
1464
- const pending = this.pendingTransfers.get(requestId);
1465
- if (!pending) {
1466
- return { success: false, error: `Pending transfer not found: ${requestId}` };
1467
- }
1468
- if (pending.status !== "pending") {
1469
- return { success: false, error: `Transfer already ${pending.status}` };
1470
- }
1471
- await this.auditLog.log({
1472
- action: "transfer_approved",
1473
- request_id: requestId,
1474
- metadata: { approver }
1475
- });
1476
- pending.status = "approved";
1477
- const result = await this.wallet.transfer(pending.to, pending.amount);
1478
- if (result.success) {
1479
- pending.status = "executed";
1480
- this.dailyTotal += pending.amount;
1481
- await this.auditLog.log({
1482
- action: "transfer_executed",
1483
- request_id: requestId,
1484
- from: this.wallet.address,
1485
- to: pending.to,
1486
- amount: pending.amount,
1487
- tx_hash: result.tx_hash,
1488
- reason: pending.reason,
1489
- requester: pending.requester,
1490
- metadata: { approved_by: approver }
1491
- });
1492
- } else {
1493
- await this.auditLog.log({
1494
- action: "transfer_failed",
1495
- request_id: requestId,
1496
- metadata: { error: result.error }
1497
- });
1498
- }
1499
- return result;
1500
- }
1501
- /**
1502
- * Reject pending transfer
1503
- */
1504
- async reject(requestId, rejecter, reason) {
1505
- const pending = this.pendingTransfers.get(requestId);
1506
- if (!pending) {
1507
- throw new Error(`Pending transfer not found: ${requestId}`);
1508
- }
1509
- pending.status = "rejected";
1510
- await this.auditLog.log({
1511
- action: "transfer_rejected",
1512
- request_id: requestId,
1513
- metadata: { rejected_by: rejecter, reason }
1514
- });
1515
- }
1516
- /**
1517
- * Add to whitelist
1518
- */
1519
- async addToWhitelist(address, addedBy) {
1520
- const addr = address.toLowerCase();
1521
- this.whitelist.add(addr);
1522
- await this.auditLog.log({
1523
- action: "whitelist_add",
1524
- request_id: `wl_${Date.now()}`,
1525
- to: address,
1526
- metadata: { added_by: addedBy }
1527
- });
1528
- }
1529
- /**
1530
- * Remove from whitelist
1531
- */
1532
- async removeFromWhitelist(address, removedBy) {
1533
- const addr = address.toLowerCase();
1534
- this.whitelist.delete(addr);
1535
- await this.auditLog.log({
1536
- action: "whitelist_remove",
1537
- request_id: `wl_${Date.now()}`,
1538
- to: address,
1539
- metadata: { removed_by: removedBy }
1540
- });
1541
- }
1542
- /**
1543
- * Check if address is whitelisted
1544
- */
1545
- isWhitelisted(address) {
1546
- return this.whitelist.has(address.toLowerCase());
1547
- }
1548
- /**
1549
- * Get pending transfers list
1550
- */
1551
- getPendingTransfers() {
1552
- return Array.from(this.pendingTransfers.values()).filter((p) => p.status === "pending");
1553
- }
1554
- /**
1555
- * Get current limit config
1556
- */
1557
- getLimits() {
1558
- return { ...this.limits };
1559
- }
1560
- /**
1561
- * Get daily used amount
1562
- */
1563
- getDailyUsed() {
1564
- this.updateDailyTotal();
1565
- return this.dailyTotal;
1566
- }
1567
- /**
1568
- * Update daily limit counter
1569
- */
1570
- updateDailyTotal() {
1571
- const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1572
- if (this.dailyDate !== today) {
1573
- this.dailyDate = today;
1574
- this.dailyTotal = 0;
1575
- }
1576
- }
1577
- };
1578
-
1579
- // src/wallet/createWallet.ts
1580
- import { ethers as ethers4 } from "ethers";
1581
- import { join as join3, dirname } from "path";
1582
- var DEFAULT_STORAGE_DIR = join3(process.env.HOME || "~", ".moltspay");
1583
-
1584
- // src/wallet/PermitWallet.ts
1585
- init_chains();
1586
- import { ethers as ethers5 } from "ethers";
1587
- var PERMIT_ABI2 = [
1588
- ...ERC20_ABI,
1589
- "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
1590
- "function transferFrom(address from, address to, uint256 amount) returns (bool)",
1591
- "function allowance(address owner, address spender) view returns (uint256)"
1592
- ];
1593
-
1594
- // src/wallet/signPermit.ts
1595
- init_chains();
1596
- import { ethers as ethers6 } from "ethers";
1597
-
1598
- // src/wallet/AllowanceWallet.ts
1599
- init_chains();
1600
- import { ethers as ethers7 } from "ethers";
1601
- var PERMIT_ABI3 = [
1602
- ...ERC20_ABI,
1603
- "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
1604
- "function transferFrom(address from, address to, uint256 amount) returns (bool)",
1605
- "function allowance(address owner, address spender) view returns (uint256)",
1606
- "function nonces(address owner) view returns (uint256)"
1607
- ];
1608
-
1609
- // src/permit/Permit.ts
1610
- init_chains();
1611
- import { ethers as ethers8 } from "ethers";
1612
-
1613
- // src/verify/index.ts
1614
- init_chains();
1615
- import { ethers as ethers9 } from "ethers";
1616
- var TRANSFER_EVENT_TOPIC = ethers9.id("Transfer(address,address,uint256)");
1617
-
1618
- // src/receipt/index.ts
1619
- init_chains();
1620
-
1621
- // src/templates/index.ts
1622
- init_chains();
1623
-
1624
- // src/index.ts
1625
- init_chains();
1626
-
1627
- // src/x402/index.ts
1628
- init_client();
1629
- init_chains();
1630
- import { ethers as ethers10 } from "ethers";
1631
-
1632
- // src/index.ts
1633
- init_cdp();
1634
-
1635
- // src/cli.ts
1636
- var program = new Command();
1637
- program.name("payment-agent").description("Blockchain payment infrastructure for AI Agents").version("0.1.0");
1638
- program.command("balance").description("Get wallet balance").option("-c, --chain <chain>", "Chain name", "base_sepolia").option("-a, --address <address>", "Wallet address").action(async (options) => {
1639
- try {
1640
- const agent = new PaymentAgent({
1641
- chain: options.chain,
1642
- walletAddress: options.address || process.env.PAYMENT_AGENT_WALLET
1643
- });
1644
- const balance = await agent.getBalance();
1645
- console.log(JSON.stringify(balance, null, 2));
1646
- } catch (error) {
1647
- console.error("Error:", error.message);
1648
- process.exit(1);
1649
- }
1650
- });
1651
- program.command("invoice").description("Generate payment invoice").requiredOption("-o, --order <orderId>", "Order ID").requiredOption("-a, --amount <amount>", "Amount in USDC").option("-s, --service <service>", "Service type", "payment").option("-c, --chain <chain>", "Chain name", "base_sepolia").option("--json", "Output raw JSON").action(async (options) => {
1652
- try {
1653
- const agent = new PaymentAgent({
1654
- chain: options.chain,
1655
- walletAddress: process.env.PAYMENT_AGENT_WALLET
1656
- });
1657
- const invoice = agent.createInvoice({
1658
- orderId: options.order,
1659
- amount: parseFloat(options.amount),
1660
- service: options.service
1661
- });
1662
- if (options.json) {
1663
- console.log(JSON.stringify(invoice, null, 2));
1664
- } else {
1665
- console.log(agent.formatInvoiceMessage(invoice));
1666
- }
1667
- } catch (error) {
1668
- console.error("Error:", error.message);
1669
- process.exit(1);
1670
- }
1671
- });
1672
- program.command("verify").description("Verify a payment transaction").requiredOption("-t, --tx <txHash>", "Transaction hash").option("-a, --amount <amount>", "Expected amount").option("-c, --chain <chain>", "Chain name", "base_sepolia").action(async (options) => {
1673
- try {
1674
- const agent = new PaymentAgent({
1675
- chain: options.chain,
1676
- walletAddress: process.env.PAYMENT_AGENT_WALLET
1677
- });
1678
- const result = await agent.verifyPayment(options.tx, {
1679
- expectedAmount: options.amount ? parseFloat(options.amount) : void 0
1680
- });
1681
- console.log(JSON.stringify(result, null, 2));
1682
- process.exit(result.verified ? 0 : 1);
1683
- } catch (error) {
1684
- console.error("Error:", error.message);
1685
- process.exit(1);
1686
- }
1687
- });
1688
- program.command("transfer").description("Transfer USDC (requires private key)").requiredOption("--to <address>", "Recipient address").requiredOption("-a, --amount <amount>", "Amount in USDC").option("-r, --reason <reason>", "Transfer reason").option("-c, --chain <chain>", "Chain name", "base_sepolia").option("--secure", "Use secure wallet with limits").action(async (options) => {
1689
- try {
1690
- if (options.secure) {
1691
- const wallet = new SecureWallet({ chain: options.chain });
1692
- const result = await wallet.transfer({
1693
- to: options.to,
1694
- amount: parseFloat(options.amount),
1695
- reason: options.reason
1696
- });
1697
- console.log(JSON.stringify(result, null, 2));
1698
- process.exit(result.success ? 0 : 1);
1699
- } else {
1700
- const wallet = new Wallet({ chain: options.chain });
1701
- const result = await wallet.transfer(options.to, parseFloat(options.amount));
1702
- console.log(JSON.stringify(result, null, 2));
1703
- process.exit(result.success ? 0 : 1);
1704
- }
1705
- } catch (error) {
1706
- console.error("Error:", error.message);
1707
- process.exit(1);
1708
- }
1709
- });
1710
- program.command("chains").description("List supported chains").action(() => {
1711
- const chains = listChains();
1712
- console.log("Supported chains:");
1713
- for (const name of chains) {
1714
- const config = CHAINS[name];
1715
- console.log(` ${name}: ${config.name} (chainId: ${config.chainId})`);
1716
- }
1717
- });
1718
- program.command("init").description("Initialize agent wallet").option("-c, --chain <chain>", "Chain name", "base").option("-d, --dir <directory>", "Storage directory", "~/.moltspay").option("--cdp", "Use CDP (Coinbase Developer Platform) wallet").option("--local", "Use local wallet (default)").action(async (options) => {
1719
- const storageDir = options.dir.replace("~", process.env.HOME || ".");
1720
- if (options.cdp) {
1721
- const { initCDPWallet: initCDPWallet2 } = await Promise.resolve().then(() => (init_cdp(), cdp_exports));
1722
- console.log("\u{1F504} Initializing CDP wallet...");
1723
- const result = await initCDPWallet2({
1724
- chain: options.chain,
1725
- storageDir
1726
- });
1727
- if (!result.success) {
1728
- console.error("\u274C Failed:", result.error);
1729
- console.log("");
1730
- console.log("To use CDP wallet, set these environment variables:");
1731
- console.log(" export CDP_API_KEY_ID=your-key-id");
1732
- console.log(" export CDP_API_KEY_SECRET=your-key-secret");
1733
- console.log(" export CDP_WALLET_SECRET=your-wallet-secret # optional");
1734
- console.log("");
1735
- console.log("Get credentials at: https://cdp.coinbase.com/");
1736
- process.exit(1);
1737
- }
1738
- console.log("\u2705 CDP wallet initialized");
1739
- console.log(` Address: ${result.address}`);
1740
- console.log(` Chain: ${options.chain}`);
1741
- console.log(` Storage: ${result.storagePath}`);
1742
- console.log(` New wallet: ${result.isNew ? "Yes" : "No (loaded existing)"}`);
1743
- console.log("");
1744
- console.log("Next steps:");
1745
- console.log(` 1. Fund your wallet: Send USDC to ${result.address}`);
1746
- console.log(" 2. Use x402 to pay for services automatically");
1747
- console.log("");
1748
- console.log("Example:");
1749
- console.log(' import { createX402Client } from "moltspay/x402";');
1750
- console.log(' const client = await createX402Client({ chain: "base", useCDP: true });');
1751
- console.log(' const response = await client.fetch("https://api.example.com/paid-resource");');
1752
- } else {
1753
- const { AgentWallet: AgentWallet2 } = await Promise.resolve().then(() => (init_AgentWallet(), AgentWallet_exports));
1754
- const wallet = new AgentWallet2({
1755
- chain: options.chain,
1756
- storageDir
1757
- });
1758
- console.log("\u2705 Local wallet initialized");
1759
- console.log(` Address: ${wallet.address}`);
1760
- console.log(` Chain: ${options.chain}`);
1761
- console.log(` Storage: ${storageDir}`);
1762
- console.log("");
1763
- console.log("Next steps:");
1764
- console.log(` 1. Fund your wallet: Send USDC to ${wallet.address}`);
1765
- console.log(` 2. Send a small amount of ETH for gas (~0.001 ETH)`);
1766
- console.log("");
1767
- console.log("Or use Permit (no gas needed):");
1768
- console.log(` npx moltspay auth-request --owner <OWNER_ADDRESS> --amount <USDC_AMOUNT>`);
1769
- }
1770
- });
1771
- program.command("auth-request").description("Generate authorization request for Owner").requiredOption("-o, --owner <address>", "Owner wallet address (e.g., MetaMask)").requiredOption("-a, --amount <amount>", "Amount in USDC to authorize").option("-c, --chain <chain>", "Chain name", "base").option("-e, --expires <hours>", "Expiration in hours", "168").option("--json", "Output as JSON").action(async (options) => {
1772
- const { AgentWallet: AgentWallet2 } = await Promise.resolve().then(() => (init_AgentWallet(), AgentWallet_exports));
1773
- const wallet = new AgentWallet2({ chain: options.chain });
1774
- const request = await wallet.generateAuthRequest({
1775
- ownerAddress: options.owner,
1776
- amount: parseFloat(options.amount),
1777
- expiresInHours: parseInt(options.expires)
1778
- });
1779
- if (options.json) {
1780
- console.log(JSON.stringify({
1781
- agentAddress: wallet.address,
1782
- typedData: request.typedData,
1783
- cliCommand: request.cliCommand
1784
- }, null, 2));
1785
- } else {
1786
- console.log(request.message);
1787
- }
1788
- });
1789
- program.command("sign-permit").description("Sign a permit (Owner uses this to authorize Agent)").requiredOption("-o, --owner <address>", "Owner address").requiredOption("-s, --spender <address>", "Spender address (Agent)").requiredOption("-a, --amount <amount>", "Amount in USDC").requiredOption("-d, --deadline <timestamp>", "Deadline timestamp").requiredOption("-n, --nonce <nonce>", "Nonce from contract").option("-c, --chain <chain>", "Chain name", "base").option("-k, --private-key <key>", "Private key (or set OWNER_PRIVATE_KEY env)").action(async (options) => {
1790
- const { ethers: ethers11 } = await import("ethers");
1791
- const { getChain: getChain2 } = await Promise.resolve().then(() => (init_chains(), chains_exports));
1792
- const privateKey = options.privateKey || process.env.OWNER_PRIVATE_KEY;
1793
- if (!privateKey) {
1794
- console.error("Error: Private key required. Use --private-key or set OWNER_PRIVATE_KEY env");
1795
- process.exit(1);
1796
- }
1797
- const chainConfig = getChain2(options.chain);
1798
- const wallet = new ethers11.Wallet(privateKey);
1799
- if (wallet.address.toLowerCase() !== options.owner.toLowerCase()) {
1800
- console.error(`Error: Private key doesn't match owner address`);
1801
- console.error(` Expected: ${options.owner}`);
1802
- console.error(` Got: ${wallet.address}`);
1803
- process.exit(1);
1804
- }
1805
- const value = BigInt(Math.floor(parseFloat(options.amount) * 1e6)).toString();
1806
- const domain = {
1807
- name: "USD Coin",
1808
- version: "2",
1809
- chainId: chainConfig.chainId,
1810
- verifyingContract: chainConfig.usdc
1811
- };
1812
- const types = {
1813
- Permit: [
1814
- { name: "owner", type: "address" },
1815
- { name: "spender", type: "address" },
1816
- { name: "value", type: "uint256" },
1817
- { name: "nonce", type: "uint256" },
1818
- { name: "deadline", type: "uint256" }
1819
- ]
1820
- };
1821
- const message = {
1822
- owner: options.owner,
1823
- spender: options.spender,
1824
- value,
1825
- nonce: parseInt(options.nonce),
1826
- deadline: parseInt(options.deadline)
1827
- };
1828
- const signature = await wallet.signTypedData(domain, types, message);
1829
- const sig = ethers11.Signature.from(signature);
1830
- const permit = {
1831
- owner: options.owner,
1832
- value,
1833
- deadline: parseInt(options.deadline),
1834
- nonce: parseInt(options.nonce),
1835
- v: sig.v,
1836
- r: sig.r,
1837
- s: sig.s
1838
- };
1839
- console.log("\u2705 Permit signed successfully!");
1840
- console.log("");
1841
- console.log("Send this to your Agent:");
1842
- console.log(JSON.stringify(permit, null, 2));
1843
- });
1844
- program.command("spend").description("Spend USDC from Owner wallet (requires permit)").requiredOption("--to <address>", "Recipient address").requiredOption("-a, --amount <amount>", "Amount in USDC").option("-c, --chain <chain>", "Chain name", "base").option("-p, --permit <json>", "Permit JSON (or stored permit is used)").action(async (options) => {
1845
- const { AgentWallet: AgentWallet2 } = await Promise.resolve().then(() => (init_AgentWallet(), AgentWallet_exports));
1846
- const wallet = new AgentWallet2({ chain: options.chain });
1847
- let permit;
1848
- if (options.permit) {
1849
- permit = JSON.parse(options.permit);
1850
- }
1851
- console.log(`Spending ${options.amount} USDC to ${options.to}...`);
1852
- const result = await wallet.spend(options.to, parseFloat(options.amount), permit);
1853
- console.log(JSON.stringify(result, null, 2));
1854
- process.exit(result.success ? 0 : 1);
1855
- });
1856
- program.command("x402").description("Make HTTP request with automatic x402 payment").argument("<url>", "URL to request").option("-X, --method <method>", "HTTP method", "GET").option("-d, --data <json>", "Request body (JSON)").option("-i, --image <path>", "Image file to include (reads file and sends as base64)").option("-H, --header <header...>", "Additional headers (key:value)").option("-c, --chain <chain>", "Chain name", "base").option("--cdp", "Use CDP wallet").option("-o, --output <file>", "Save response to file").option("-v, --verbose", "Show payment details").action(async (url, options) => {
1857
- const { createX402Client: createX402Client2, isX402Available: isX402Available2 } = await Promise.resolve().then(() => (init_client(), client_exports));
1858
- if (!isX402Available2()) {
1859
- console.error("\u274C x402 packages not installed.");
1860
- console.error("");
1861
- console.error("Install them with:");
1862
- console.error(" npm install @x402/fetch @x402/evm viem");
1863
- process.exit(1);
1864
- }
1865
- try {
1866
- if (options.verbose) {
1867
- console.error(`\u{1F504} Initializing x402 client (chain: ${options.chain})...`);
1868
- }
1869
- const client = await createX402Client2({
1870
- chain: options.chain,
1871
- useCDP: options.cdp
1872
- });
1873
- if (options.verbose) {
1874
- console.error(` Wallet: ${client.address}`);
1875
- console.error(` Chain: ${client.chain}`);
1876
- console.error("");
1877
- }
1878
- const headers = {
1879
- "Content-Type": "application/json"
1880
- };
1881
- if (options.header) {
1882
- for (const h of options.header) {
1883
- const [key, ...valueParts] = h.split(":");
1884
- headers[key.trim()] = valueParts.join(":").trim();
1885
- }
1886
- }
1887
- const init = {
1888
- method: options.method.toUpperCase(),
1889
- headers
1890
- };
1891
- let bodyData = {};
1892
- if (options.data) {
1893
- try {
1894
- bodyData = JSON.parse(options.data);
1895
- } catch {
1896
- bodyData = { data: options.data };
1897
- }
1898
- }
1899
- if (options.image) {
1900
- const fs4 = await import("fs");
1901
- const path4 = await import("path");
1902
- const imagePath = path4.resolve(options.image);
1903
- if (!fs4.existsSync(imagePath)) {
1904
- console.error(`\u274C Image file not found: ${imagePath}`);
1905
- process.exit(1);
1906
- }
1907
- const imageBuffer = fs4.readFileSync(imagePath);
1908
- const imageBase64 = imageBuffer.toString("base64");
1909
- if (options.verbose) {
1910
- console.error(`\u{1F4F7} Image: ${imagePath} (${Math.round(imageBuffer.length / 1024)}KB)`);
1911
- }
1912
- bodyData.image_base64 = imageBase64;
1913
- }
1914
- if (["POST", "PUT", "PATCH"].includes(init.method) && Object.keys(bodyData).length > 0) {
1915
- init.body = JSON.stringify(bodyData);
1916
- }
1917
- if (options.verbose) {
1918
- console.error(`\u{1F4E4} ${init.method} ${url}`);
1919
- if (options.data) {
1920
- console.error(` Body: ${options.data.substring(0, 100)}${options.data.length > 100 ? "..." : ""}`);
1921
- }
1922
- console.error("");
1923
- }
1924
- const response = await client.fetch(url, init);
1925
- if (options.verbose) {
1926
- console.error(`\u{1F4E5} Response: ${response.status} ${response.statusText}`);
1927
- console.error("");
1928
- }
1929
- const contentType = response.headers.get("content-type") || "";
1930
- let body;
1931
- if (contentType.includes("application/json")) {
1932
- const json = await response.json();
1933
- body = JSON.stringify(json, null, 2);
1934
- } else {
1935
- body = await response.text();
1936
- }
1937
- if (options.output) {
1938
- const fs4 = await import("fs");
1939
- fs4.writeFileSync(options.output, body);
1940
- console.error(`\u2705 Saved to ${options.output}`);
1941
- } else {
1942
- console.log(body);
1943
- }
1944
- process.exit(response.ok ? 0 : 1);
1945
- } catch (error) {
1946
- console.error("\u274C Error:", error.message);
1947
- process.exit(1);
1948
- }
1949
- });
1950
- program.command("status").description("Show agent wallet status").option("-c, --chain <chain>", "Chain name", "base").option("-o, --owner <address>", "Check allowance from specific owner").action(async (options) => {
1951
- const { AgentWallet: AgentWallet2 } = await Promise.resolve().then(() => (init_AgentWallet(), AgentWallet_exports));
1952
- const wallet = new AgentWallet2({ chain: options.chain });
1953
- console.log("Agent Wallet Status");
1954
- console.log("==================");
1955
- console.log(`Address: ${wallet.address}`);
1956
- console.log(`Chain: ${options.chain}`);
1957
- console.log(`Gas balance: ${await wallet.getGasBalance()} ETH`);
1958
- console.log(`Has gas: ${await wallet.hasGas() ? "Yes \u2705" : "No \u274C (need ~0.0005 ETH)"}`);
1959
- if (options.owner) {
1960
- const allowance = await wallet.checkAllowance(options.owner);
1961
- console.log("");
1962
- console.log(`Allowance from ${options.owner}:`);
1963
- console.log(` Allowance: ${allowance.allowance} USDC`);
1964
- console.log(` Owner balance: ${allowance.ownerBalance} USDC`);
1965
- console.log(` Can spend: ${allowance.canSpend ? "Yes \u2705" : "No \u274C"}`);
1966
- }
1967
- });
1968
- program.parse();
1969
- //# sourceMappingURL=cli.mjs.map