moltspay 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -6,6 +6,13 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
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
+ };
9
16
  var __copyProps = (to, from, except, desc) => {
10
17
  if (from && typeof from === "object" || typeof from === "function") {
11
18
  for (let key of __getOwnPropNames(from))
@@ -23,62 +30,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
30
  mod
24
31
  ));
25
32
 
26
- // src/cli.ts
27
- var import_commander = require("commander");
28
-
29
- // src/agent/PaymentAgent.ts
30
- var import_ethers = require("ethers");
31
-
32
33
  // src/chains/index.ts
33
- var CHAINS = {
34
- // ============ Mainnet ============
35
- base: {
36
- name: "Base",
37
- chainId: 8453,
38
- rpc: "https://mainnet.base.org",
39
- usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
40
- explorer: "https://basescan.org/address/",
41
- explorerTx: "https://basescan.org/tx/",
42
- avgBlockTime: 2
43
- },
44
- polygon: {
45
- name: "Polygon",
46
- chainId: 137,
47
- rpc: "https://polygon-rpc.com",
48
- usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
49
- explorer: "https://polygonscan.com/address/",
50
- explorerTx: "https://polygonscan.com/tx/",
51
- avgBlockTime: 2
52
- },
53
- ethereum: {
54
- name: "Ethereum",
55
- chainId: 1,
56
- rpc: "https://eth.llamarpc.com",
57
- usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
58
- explorer: "https://etherscan.io/address/",
59
- explorerTx: "https://etherscan.io/tx/",
60
- avgBlockTime: 12
61
- },
62
- // ============ Testnet ============
63
- base_sepolia: {
64
- name: "Base Sepolia",
65
- chainId: 84532,
66
- rpc: "https://sepolia.base.org",
67
- usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
68
- explorer: "https://sepolia.basescan.org/address/",
69
- explorerTx: "https://sepolia.basescan.org/tx/",
70
- avgBlockTime: 2
71
- },
72
- sepolia: {
73
- name: "Sepolia",
74
- chainId: 11155111,
75
- rpc: "https://rpc.sepolia.org",
76
- usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
77
- explorer: "https://sepolia.etherscan.io/address/",
78
- explorerTx: "https://sepolia.etherscan.io/tx/",
79
- avgBlockTime: 12
80
- }
81
- };
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
+ });
82
42
  function getChain(name) {
83
43
  const config = CHAINS[name];
84
44
  if (!config) {
@@ -89,21 +49,405 @@ function getChain(name) {
89
49
  function listChains() {
90
50
  return Object.keys(CHAINS);
91
51
  }
92
- var ERC20_ABI = [
93
- "function balanceOf(address owner) view returns (uint256)",
94
- "function transfer(address to, uint256 amount) returns (bool)",
95
- "function approve(address spender, uint256 amount) returns (bool)",
96
- "function allowance(address owner, address spender) view returns (uint256)",
97
- "function decimals() view returns (uint8)",
98
- "function symbol() view returns (string)",
99
- "function name() view returns (string)",
100
- "function nonces(address owner) view returns (uint256)",
101
- "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
102
- "event Transfer(address indexed from, address indexed to, uint256 value)",
103
- "event Approval(address indexed owner, address indexed spender, uint256 value)"
104
- ];
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 gas balance (ETH needed for transactions)
353
+ */
354
+ async getGasBalance() {
355
+ const balance = await this.provider.getBalance(this.address);
356
+ return import_ethers2.ethers.formatEther(balance);
357
+ }
358
+ /**
359
+ * Check if agent has enough gas
360
+ */
361
+ async hasGas(minEth = 5e-4) {
362
+ const balance = await this.getGasBalance();
363
+ return parseFloat(balance) >= minEth;
364
+ }
365
+ /**
366
+ * Generate authorization request for Owner
367
+ * Owner can sign this with CLI (ethers) or MetaMask
368
+ */
369
+ async generateAuthRequest(params) {
370
+ const { ownerAddress, amount, expiresInHours = 168 } = params;
371
+ const deadline = Math.floor(Date.now() / 1e3) + expiresInHours * 3600;
372
+ const value = BigInt(Math.floor(amount * 1e6)).toString();
373
+ const usdcContract = new import_ethers2.ethers.Contract(
374
+ this.chainConfig.usdc,
375
+ PERMIT_ABI,
376
+ this.provider
377
+ );
378
+ const nonce = Number(await usdcContract.nonces(ownerAddress));
379
+ const domain = {
380
+ name: "USD Coin",
381
+ version: "2",
382
+ chainId: this.chainConfig.chainId,
383
+ verifyingContract: this.chainConfig.usdc
384
+ };
385
+ const types = {
386
+ Permit: [
387
+ { name: "owner", type: "address" },
388
+ { name: "spender", type: "address" },
389
+ { name: "value", type: "uint256" },
390
+ { name: "nonce", type: "uint256" },
391
+ { name: "deadline", type: "uint256" }
392
+ ]
393
+ };
394
+ const permitMessage = {
395
+ owner: ownerAddress,
396
+ spender: this.address,
397
+ value,
398
+ nonce,
399
+ deadline
400
+ };
401
+ const typedData = {
402
+ types: { ...types, EIP712Domain: [
403
+ { name: "name", type: "string" },
404
+ { name: "version", type: "string" },
405
+ { name: "chainId", type: "uint256" },
406
+ { name: "verifyingContract", type: "address" }
407
+ ] },
408
+ primaryType: "Permit",
409
+ domain,
410
+ message: permitMessage
411
+ };
412
+ const cliCommand = `npx moltspay sign-permit \\
413
+ --owner ${ownerAddress} \\
414
+ --spender ${this.address} \\
415
+ --amount ${amount} \\
416
+ --deadline ${deadline} \\
417
+ --nonce ${nonce} \\
418
+ --chain ${this.chain}`;
419
+ const message = `\u{1F510} Authorization Request
420
+
421
+ I need permission to spend up to ${amount} USDC from your wallet.
422
+
423
+ **Details:**
424
+ - Your wallet: ${ownerAddress}
425
+ - My address: ${this.address}
426
+ - Amount: ${amount} USDC
427
+ - Expires: ${new Date(deadline * 1e3).toISOString()}
428
+ - Chain: ${this.chainConfig.name}
429
+
430
+ **Option 1: Sign with CLI** (if you have the private key)
431
+ \`\`\`
432
+ ${cliCommand}
433
+ \`\`\`
434
+
435
+ **Option 2: Sign with MetaMask**
436
+ Visit: https://moltspay.vercel.app/permit?data=${encodeURIComponent(JSON.stringify(typedData))}
437
+
438
+ After signing, send me the signature (v, r, s).`;
439
+ return { message, typedData, cliCommand };
440
+ }
441
+ };
442
+ }
443
+ });
444
+
445
+ // src/cli.ts
446
+ var import_commander = require("commander");
105
447
 
106
448
  // src/agent/PaymentAgent.ts
449
+ var import_ethers = require("ethers");
450
+ init_chains();
107
451
  var PaymentAgent = class _PaymentAgent {
108
452
  chain;
109
453
  chainConfig;
@@ -305,8 +649,12 @@ After payment, reply with your tx hash:
305
649
  }
306
650
  };
307
651
 
652
+ // src/index.ts
653
+ init_AgentWallet();
654
+
308
655
  // src/wallet/Wallet.ts
309
- var import_ethers2 = require("ethers");
656
+ var import_ethers3 = require("ethers");
657
+ init_chains();
310
658
  var Wallet = class {
311
659
  chain;
312
660
  chainConfig;
@@ -322,10 +670,10 @@ var Wallet = class {
322
670
  throw new Error("privateKey is required. Set via config or PAYMENT_AGENT_PRIVATE_KEY env var.");
323
671
  }
324
672
  const rpcUrl = config.rpcUrl || this.chainConfig.rpc;
325
- this.provider = new import_ethers2.ethers.JsonRpcProvider(rpcUrl);
326
- this.wallet = new import_ethers2.ethers.Wallet(privateKey, this.provider);
673
+ this.provider = new import_ethers3.ethers.JsonRpcProvider(rpcUrl);
674
+ this.wallet = new import_ethers3.ethers.Wallet(privateKey, this.provider);
327
675
  this.address = this.wallet.address;
328
- this.usdcContract = new import_ethers2.ethers.Contract(
676
+ this.usdcContract = new import_ethers3.ethers.Contract(
329
677
  this.chainConfig.usdc,
330
678
  ERC20_ABI,
331
679
  this.wallet
@@ -341,7 +689,7 @@ var Wallet = class {
341
689
  ]);
342
690
  return {
343
691
  address: this.address,
344
- eth: import_ethers2.ethers.formatEther(ethBalance),
692
+ eth: import_ethers3.ethers.formatEther(ethBalance),
345
693
  usdc: (Number(usdcBalance) / 1e6).toFixed(2),
346
694
  chain: this.chain
347
695
  };
@@ -351,7 +699,7 @@ var Wallet = class {
351
699
  */
352
700
  async transfer(to, amount) {
353
701
  try {
354
- to = import_ethers2.ethers.getAddress(to);
702
+ to = import_ethers3.ethers.getAddress(to);
355
703
  const amountWei = BigInt(Math.floor(amount * 1e6));
356
704
  const balance = await this.usdcContract.balanceOf(this.address);
357
705
  if (BigInt(balance) < amountWei) {
@@ -392,7 +740,7 @@ var Wallet = class {
392
740
  */
393
741
  async getEthBalance() {
394
742
  const balance = await this.provider.getBalance(this.address);
395
- return import_ethers2.ethers.formatEther(balance);
743
+ return import_ethers3.ethers.formatEther(balance);
396
744
  }
397
745
  /**
398
746
  * Get USDC balance
@@ -404,14 +752,14 @@ var Wallet = class {
404
752
  };
405
753
 
406
754
  // src/audit/AuditLog.ts
407
- var fs = __toESM(require("fs"));
408
- var path = __toESM(require("path"));
755
+ var fs2 = __toESM(require("fs"));
756
+ var path2 = __toESM(require("path"));
409
757
  var crypto = __toESM(require("crypto"));
410
758
  var AuditLog = class {
411
759
  basePath;
412
760
  lastHash = "0000000000000000";
413
761
  constructor(basePath) {
414
- this.basePath = basePath || path.join(process.cwd(), "data", "audit");
762
+ this.basePath = basePath || path2.join(process.cwd(), "data", "audit");
415
763
  this.ensureDir();
416
764
  this.loadLastHash();
417
765
  }
@@ -440,7 +788,7 @@ var AuditLog = class {
440
788
  this.lastHash = entry.hash;
441
789
  const filePath = this.getFilePath(now);
442
790
  const line = JSON.stringify(entry) + "\n";
443
- fs.appendFileSync(filePath, line, "utf-8");
791
+ fs2.appendFileSync(filePath, line, "utf-8");
444
792
  return entry;
445
793
  }
446
794
  /**
@@ -448,10 +796,10 @@ var AuditLog = class {
448
796
  */
449
797
  read(date) {
450
798
  const filePath = this.getFilePath(date || /* @__PURE__ */ new Date());
451
- if (!fs.existsSync(filePath)) {
799
+ if (!fs2.existsSync(filePath)) {
452
800
  return [];
453
801
  }
454
- const content = fs.readFileSync(filePath, "utf-8");
802
+ const content = fs2.readFileSync(filePath, "utf-8");
455
803
  const lines = content.trim().split("\n").filter(Boolean);
456
804
  return lines.map((line) => JSON.parse(line));
457
805
  }
@@ -502,7 +850,7 @@ var AuditLog = class {
502
850
  */
503
851
  getFilePath(date) {
504
852
  const dateStr = date.toISOString().slice(0, 10);
505
- return path.join(this.basePath, `audit_${dateStr}.jsonl`);
853
+ return path2.join(this.basePath, `audit_${dateStr}.jsonl`);
506
854
  }
507
855
  /**
508
856
  * Calculate entry hash
@@ -540,8 +888,8 @@ var AuditLog = class {
540
888
  * Ensure directory exists
541
889
  */
542
890
  ensureDir() {
543
- if (!fs.existsSync(this.basePath)) {
544
- fs.mkdirSync(this.basePath, { recursive: true });
891
+ if (!fs2.existsSync(this.basePath)) {
892
+ fs2.mkdirSync(this.basePath, { recursive: true });
545
893
  }
546
894
  }
547
895
  };
@@ -805,13 +1153,14 @@ var SecureWallet = class {
805
1153
  };
806
1154
 
807
1155
  // src/wallet/createWallet.ts
808
- var import_ethers3 = require("ethers");
1156
+ var import_ethers4 = require("ethers");
809
1157
  var import_path = require("path");
810
1158
  var DEFAULT_STORAGE_DIR = (0, import_path.join)(process.env.HOME || "~", ".moltspay");
811
1159
 
812
1160
  // src/wallet/PermitWallet.ts
813
- var import_ethers4 = require("ethers");
814
- var PERMIT_ABI = [
1161
+ var import_ethers5 = require("ethers");
1162
+ init_chains();
1163
+ var PERMIT_ABI2 = [
815
1164
  ...ERC20_ABI,
816
1165
  "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
817
1166
  "function transferFrom(address from, address to, uint256 amount) returns (bool)",
@@ -819,14 +1168,37 @@ var PERMIT_ABI = [
819
1168
  ];
820
1169
 
821
1170
  // src/wallet/signPermit.ts
822
- var import_ethers5 = require("ethers");
1171
+ var import_ethers6 = require("ethers");
1172
+ init_chains();
1173
+
1174
+ // src/wallet/AllowanceWallet.ts
1175
+ var import_ethers7 = require("ethers");
1176
+ init_chains();
1177
+ var PERMIT_ABI3 = [
1178
+ ...ERC20_ABI,
1179
+ "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
1180
+ "function transferFrom(address from, address to, uint256 amount) returns (bool)",
1181
+ "function allowance(address owner, address spender) view returns (uint256)",
1182
+ "function nonces(address owner) view returns (uint256)"
1183
+ ];
823
1184
 
824
1185
  // src/permit/Permit.ts
825
- var import_ethers6 = require("ethers");
1186
+ var import_ethers8 = require("ethers");
1187
+ init_chains();
826
1188
 
827
1189
  // src/verify/index.ts
828
- var import_ethers7 = require("ethers");
829
- var TRANSFER_EVENT_TOPIC = import_ethers7.ethers.id("Transfer(address,address,uint256)");
1190
+ var import_ethers9 = require("ethers");
1191
+ init_chains();
1192
+ var TRANSFER_EVENT_TOPIC = import_ethers9.ethers.id("Transfer(address,address,uint256)");
1193
+
1194
+ // src/receipt/index.ts
1195
+ init_chains();
1196
+
1197
+ // src/templates/index.ts
1198
+ init_chains();
1199
+
1200
+ // src/index.ts
1201
+ init_chains();
830
1202
 
831
1203
  // src/cli.ts
832
1204
  var program = new import_commander.Command();
@@ -911,5 +1283,123 @@ program.command("chains").description("List supported chains").action(() => {
911
1283
  console.log(` ${name}: ${config.name} (chainId: ${config.chainId})`);
912
1284
  }
913
1285
  });
1286
+ program.command("init").description("Initialize agent wallet (auto-generates address, no gas needed)").option("-c, --chain <chain>", "Chain name", "base").option("-d, --dir <directory>", "Storage directory", "~/.moltspay").action(async (options) => {
1287
+ const { AgentWallet: AgentWallet2 } = await Promise.resolve().then(() => (init_AgentWallet(), AgentWallet_exports));
1288
+ const storageDir = options.dir.replace("~", process.env.HOME || ".");
1289
+ const wallet = new AgentWallet2({
1290
+ chain: options.chain,
1291
+ storageDir
1292
+ });
1293
+ console.log("\u2705 Agent wallet initialized");
1294
+ console.log(` Address: ${wallet.address}`);
1295
+ console.log(` Chain: ${options.chain}`);
1296
+ console.log(` Storage: ${storageDir}`);
1297
+ console.log("");
1298
+ console.log("Next: Ask your Owner to authorize spending with:");
1299
+ console.log(` npx moltspay auth-request --owner <OWNER_ADDRESS> --amount <USDC_AMOUNT>`);
1300
+ });
1301
+ 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) => {
1302
+ const { AgentWallet: AgentWallet2 } = await Promise.resolve().then(() => (init_AgentWallet(), AgentWallet_exports));
1303
+ const wallet = new AgentWallet2({ chain: options.chain });
1304
+ const request = await wallet.generateAuthRequest({
1305
+ ownerAddress: options.owner,
1306
+ amount: parseFloat(options.amount),
1307
+ expiresInHours: parseInt(options.expires)
1308
+ });
1309
+ if (options.json) {
1310
+ console.log(JSON.stringify({
1311
+ agentAddress: wallet.address,
1312
+ typedData: request.typedData,
1313
+ cliCommand: request.cliCommand
1314
+ }, null, 2));
1315
+ } else {
1316
+ console.log(request.message);
1317
+ }
1318
+ });
1319
+ 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) => {
1320
+ const { ethers: ethers10 } = await import("ethers");
1321
+ const { getChain: getChain2 } = await Promise.resolve().then(() => (init_chains(), chains_exports));
1322
+ const privateKey = options.privateKey || process.env.OWNER_PRIVATE_KEY;
1323
+ if (!privateKey) {
1324
+ console.error("Error: Private key required. Use --private-key or set OWNER_PRIVATE_KEY env");
1325
+ process.exit(1);
1326
+ }
1327
+ const chainConfig = getChain2(options.chain);
1328
+ const wallet = new ethers10.Wallet(privateKey);
1329
+ if (wallet.address.toLowerCase() !== options.owner.toLowerCase()) {
1330
+ console.error(`Error: Private key doesn't match owner address`);
1331
+ console.error(` Expected: ${options.owner}`);
1332
+ console.error(` Got: ${wallet.address}`);
1333
+ process.exit(1);
1334
+ }
1335
+ const value = BigInt(Math.floor(parseFloat(options.amount) * 1e6)).toString();
1336
+ const domain = {
1337
+ name: "USD Coin",
1338
+ version: "2",
1339
+ chainId: chainConfig.chainId,
1340
+ verifyingContract: chainConfig.usdc
1341
+ };
1342
+ const types = {
1343
+ Permit: [
1344
+ { name: "owner", type: "address" },
1345
+ { name: "spender", type: "address" },
1346
+ { name: "value", type: "uint256" },
1347
+ { name: "nonce", type: "uint256" },
1348
+ { name: "deadline", type: "uint256" }
1349
+ ]
1350
+ };
1351
+ const message = {
1352
+ owner: options.owner,
1353
+ spender: options.spender,
1354
+ value,
1355
+ nonce: parseInt(options.nonce),
1356
+ deadline: parseInt(options.deadline)
1357
+ };
1358
+ const signature = await wallet.signTypedData(domain, types, message);
1359
+ const sig = ethers10.Signature.from(signature);
1360
+ const permit = {
1361
+ owner: options.owner,
1362
+ value,
1363
+ deadline: parseInt(options.deadline),
1364
+ nonce: parseInt(options.nonce),
1365
+ v: sig.v,
1366
+ r: sig.r,
1367
+ s: sig.s
1368
+ };
1369
+ console.log("\u2705 Permit signed successfully!");
1370
+ console.log("");
1371
+ console.log("Send this to your Agent:");
1372
+ console.log(JSON.stringify(permit, null, 2));
1373
+ });
1374
+ 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) => {
1375
+ const { AgentWallet: AgentWallet2 } = await Promise.resolve().then(() => (init_AgentWallet(), AgentWallet_exports));
1376
+ const wallet = new AgentWallet2({ chain: options.chain });
1377
+ let permit;
1378
+ if (options.permit) {
1379
+ permit = JSON.parse(options.permit);
1380
+ }
1381
+ console.log(`Spending ${options.amount} USDC to ${options.to}...`);
1382
+ const result = await wallet.spend(options.to, parseFloat(options.amount), permit);
1383
+ console.log(JSON.stringify(result, null, 2));
1384
+ process.exit(result.success ? 0 : 1);
1385
+ });
1386
+ 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) => {
1387
+ const { AgentWallet: AgentWallet2 } = await Promise.resolve().then(() => (init_AgentWallet(), AgentWallet_exports));
1388
+ const wallet = new AgentWallet2({ chain: options.chain });
1389
+ console.log("Agent Wallet Status");
1390
+ console.log("==================");
1391
+ console.log(`Address: ${wallet.address}`);
1392
+ console.log(`Chain: ${options.chain}`);
1393
+ console.log(`Gas balance: ${await wallet.getGasBalance()} ETH`);
1394
+ console.log(`Has gas: ${await wallet.hasGas() ? "Yes \u2705" : "No \u274C (need ~0.0005 ETH)"}`);
1395
+ if (options.owner) {
1396
+ const allowance = await wallet.checkAllowance(options.owner);
1397
+ console.log("");
1398
+ console.log(`Allowance from ${options.owner}:`);
1399
+ console.log(` Allowance: ${allowance.allowance} USDC`);
1400
+ console.log(` Owner balance: ${allowance.ownerBalance} USDC`);
1401
+ console.log(` Can spend: ${allowance.canSpend ? "Yes \u2705" : "No \u274C"}`);
1402
+ }
1403
+ });
914
1404
  program.parse();
915
1405
  //# sourceMappingURL=cli.js.map