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