moltspay 0.2.4 → 0.2.6

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/index.mjs CHANGED
@@ -280,8 +280,317 @@ After payment, reply with your tx hash:
280
280
  }
281
281
  };
282
282
 
283
- // src/wallet/Wallet.ts
283
+ // src/agent/AgentWallet.ts
284
284
  import { ethers as ethers2 } from "ethers";
285
+ import * as fs from "fs";
286
+ import * as path from "path";
287
+ var PERMIT_ABI = [
288
+ ...ERC20_ABI,
289
+ "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
290
+ "function transferFrom(address from, address to, uint256 amount) returns (bool)",
291
+ "function allowance(address owner, address spender) view returns (uint256)",
292
+ "function nonces(address owner) view returns (uint256)"
293
+ ];
294
+ var AgentWallet = class {
295
+ chain;
296
+ chainConfig;
297
+ storageDir;
298
+ _address = null;
299
+ _privateKey = null;
300
+ _wallet = null;
301
+ _provider = null;
302
+ _permits = /* @__PURE__ */ new Map();
303
+ constructor(config = {}) {
304
+ this.chain = config.chain || "base";
305
+ this.chainConfig = getChain(this.chain);
306
+ this.storageDir = config.storageDir || this.getDefaultStorageDir();
307
+ this.ensureInitialized();
308
+ }
309
+ getDefaultStorageDir() {
310
+ const home = process.env.HOME || process.env.USERPROFILE || ".";
311
+ return path.join(home, ".moltspay");
312
+ }
313
+ getWalletPath() {
314
+ return path.join(this.storageDir, "wallet.json");
315
+ }
316
+ getPermitsPath() {
317
+ return path.join(this.storageDir, "permits.json");
318
+ }
319
+ /**
320
+ * Auto-initialize: create wallet if not exists
321
+ * This is called automatically in constructor
322
+ */
323
+ ensureInitialized() {
324
+ if (!fs.existsSync(this.storageDir)) {
325
+ fs.mkdirSync(this.storageDir, { recursive: true });
326
+ }
327
+ const walletPath = this.getWalletPath();
328
+ if (fs.existsSync(walletPath)) {
329
+ const data = JSON.parse(fs.readFileSync(walletPath, "utf-8"));
330
+ this._address = data.address;
331
+ this._privateKey = data.privateKey;
332
+ } else {
333
+ const wallet = ethers2.Wallet.createRandom();
334
+ this._address = wallet.address;
335
+ this._privateKey = wallet.privateKey;
336
+ fs.writeFileSync(walletPath, JSON.stringify({
337
+ address: this._address,
338
+ privateKey: this._privateKey,
339
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
340
+ chain: this.chain
341
+ }, null, 2), { mode: 384 });
342
+ }
343
+ const permitsPath = this.getPermitsPath();
344
+ if (fs.existsSync(permitsPath)) {
345
+ const permits = JSON.parse(fs.readFileSync(permitsPath, "utf-8"));
346
+ for (const [owner, permit] of Object.entries(permits)) {
347
+ this._permits.set(owner.toLowerCase(), permit);
348
+ }
349
+ }
350
+ }
351
+ /** Agent's address (auto-generated on first use) */
352
+ get address() {
353
+ return this._address;
354
+ }
355
+ get wallet() {
356
+ if (!this._wallet) {
357
+ this._wallet = new ethers2.Wallet(this._privateKey, this.provider);
358
+ }
359
+ return this._wallet;
360
+ }
361
+ get provider() {
362
+ if (!this._provider) {
363
+ this._provider = new ethers2.JsonRpcProvider(this.chainConfig.rpc);
364
+ }
365
+ return this._provider;
366
+ }
367
+ /**
368
+ * Store a Permit from Owner
369
+ */
370
+ storePermit(permit) {
371
+ const ownerLower = permit.owner.toLowerCase();
372
+ this._permits.set(ownerLower, permit);
373
+ const permitsPath = this.getPermitsPath();
374
+ const permits = {};
375
+ for (const [owner, p] of this._permits) {
376
+ permits[owner] = p;
377
+ }
378
+ fs.writeFileSync(permitsPath, JSON.stringify(permits, null, 2));
379
+ }
380
+ /**
381
+ * Get stored permit for an owner
382
+ */
383
+ getPermit(owner) {
384
+ return this._permits.get(owner.toLowerCase());
385
+ }
386
+ /**
387
+ * Check allowance from an owner
388
+ */
389
+ async checkAllowance(owner) {
390
+ const usdcContract = new ethers2.Contract(
391
+ this.chainConfig.usdc,
392
+ PERMIT_ABI,
393
+ this.provider
394
+ );
395
+ const ownerAddress = ethers2.getAddress(owner);
396
+ const [allowance, balance] = await Promise.all([
397
+ usdcContract.allowance(ownerAddress, this.address),
398
+ usdcContract.balanceOf(ownerAddress)
399
+ ]);
400
+ return {
401
+ allowance: (Number(allowance) / 1e6).toFixed(2),
402
+ ownerBalance: (Number(balance) / 1e6).toFixed(2),
403
+ canSpend: Number(allowance) > 0
404
+ };
405
+ }
406
+ /**
407
+ * Spend USDC from Owner's wallet
408
+ *
409
+ * @param to - Recipient (service provider)
410
+ * @param amount - Amount in USDC
411
+ * @param permit - Optional, uses stored permit if not provided
412
+ */
413
+ async spend(to, amount, permit) {
414
+ const toAddress = ethers2.getAddress(to);
415
+ const amountWei = BigInt(Math.floor(amount * 1e6));
416
+ let usePermit = permit;
417
+ let ownerAddress;
418
+ if (usePermit) {
419
+ ownerAddress = ethers2.getAddress(usePermit.owner);
420
+ this.storePermit(usePermit);
421
+ } else {
422
+ const usdcContract = new ethers2.Contract(
423
+ this.chainConfig.usdc,
424
+ PERMIT_ABI,
425
+ this.provider
426
+ );
427
+ for (const [owner, p] of this._permits) {
428
+ const allowance = await usdcContract.allowance(owner, this.address);
429
+ if (BigInt(allowance) >= amountWei) {
430
+ ownerAddress = ethers2.getAddress(owner);
431
+ usePermit = p;
432
+ break;
433
+ }
434
+ }
435
+ if (!usePermit) {
436
+ return {
437
+ success: false,
438
+ error: "No valid permit. Ask Owner to authorize spending first.",
439
+ from: "",
440
+ to: toAddress,
441
+ amount
442
+ };
443
+ }
444
+ }
445
+ try {
446
+ const usdcContract = new ethers2.Contract(
447
+ this.chainConfig.usdc,
448
+ PERMIT_ABI,
449
+ this.wallet
450
+ );
451
+ const currentAllowance = await usdcContract.allowance(ownerAddress, this.address);
452
+ if (BigInt(currentAllowance) < amountWei) {
453
+ const now = Math.floor(Date.now() / 1e3);
454
+ if (usePermit.deadline < now) {
455
+ return {
456
+ success: false,
457
+ error: "Permit expired. Ask Owner for a new authorization.",
458
+ from: ownerAddress,
459
+ to: toAddress,
460
+ amount
461
+ };
462
+ }
463
+ const permitTx = await usdcContract.permit(
464
+ ownerAddress,
465
+ this.address,
466
+ usePermit.value,
467
+ usePermit.deadline,
468
+ usePermit.v,
469
+ usePermit.r,
470
+ usePermit.s
471
+ );
472
+ await permitTx.wait();
473
+ }
474
+ const tx = await usdcContract.transferFrom(ownerAddress, toAddress, amountWei);
475
+ await tx.wait();
476
+ const newAllowance = await usdcContract.allowance(ownerAddress, this.address);
477
+ return {
478
+ success: true,
479
+ txHash: tx.hash,
480
+ from: ownerAddress,
481
+ to: toAddress,
482
+ amount,
483
+ remainingAllowance: (Number(newAllowance) / 1e6).toFixed(2),
484
+ explorerUrl: `${this.chainConfig.explorerTx}${tx.hash}`
485
+ };
486
+ } catch (error) {
487
+ return {
488
+ success: false,
489
+ error: error.message,
490
+ from: ownerAddress,
491
+ to: toAddress,
492
+ amount
493
+ };
494
+ }
495
+ }
496
+ /**
497
+ * Get gas balance (ETH needed for transactions)
498
+ */
499
+ async getGasBalance() {
500
+ const balance = await this.provider.getBalance(this.address);
501
+ return ethers2.formatEther(balance);
502
+ }
503
+ /**
504
+ * Check if agent has enough gas
505
+ */
506
+ async hasGas(minEth = 5e-4) {
507
+ const balance = await this.getGasBalance();
508
+ return parseFloat(balance) >= minEth;
509
+ }
510
+ /**
511
+ * Generate authorization request for Owner
512
+ * Owner can sign this with CLI (ethers) or MetaMask
513
+ */
514
+ async generateAuthRequest(params) {
515
+ const { ownerAddress, amount, expiresInHours = 168 } = params;
516
+ const deadline = Math.floor(Date.now() / 1e3) + expiresInHours * 3600;
517
+ const value = BigInt(Math.floor(amount * 1e6)).toString();
518
+ const usdcContract = new ethers2.Contract(
519
+ this.chainConfig.usdc,
520
+ PERMIT_ABI,
521
+ this.provider
522
+ );
523
+ const nonce = Number(await usdcContract.nonces(ownerAddress));
524
+ const domain = {
525
+ name: "USD Coin",
526
+ version: "2",
527
+ chainId: this.chainConfig.chainId,
528
+ verifyingContract: this.chainConfig.usdc
529
+ };
530
+ const types = {
531
+ Permit: [
532
+ { name: "owner", type: "address" },
533
+ { name: "spender", type: "address" },
534
+ { name: "value", type: "uint256" },
535
+ { name: "nonce", type: "uint256" },
536
+ { name: "deadline", type: "uint256" }
537
+ ]
538
+ };
539
+ const permitMessage = {
540
+ owner: ownerAddress,
541
+ spender: this.address,
542
+ value,
543
+ nonce,
544
+ deadline
545
+ };
546
+ const typedData = {
547
+ types: { ...types, EIP712Domain: [
548
+ { name: "name", type: "string" },
549
+ { name: "version", type: "string" },
550
+ { name: "chainId", type: "uint256" },
551
+ { name: "verifyingContract", type: "address" }
552
+ ] },
553
+ primaryType: "Permit",
554
+ domain,
555
+ message: permitMessage
556
+ };
557
+ const cliCommand = `npx moltspay sign-permit \\
558
+ --owner ${ownerAddress} \\
559
+ --spender ${this.address} \\
560
+ --amount ${amount} \\
561
+ --deadline ${deadline} \\
562
+ --nonce ${nonce} \\
563
+ --chain ${this.chain}`;
564
+ const message = `\u{1F510} Authorization Request
565
+
566
+ I need permission to spend up to ${amount} USDC from your wallet.
567
+
568
+ **Details:**
569
+ - Your wallet: ${ownerAddress}
570
+ - My address: ${this.address}
571
+ - Amount: ${amount} USDC
572
+ - Expires: ${new Date(deadline * 1e3).toISOString()}
573
+ - Chain: ${this.chainConfig.name}
574
+
575
+ **Option 1: Sign with CLI** (if you have the private key)
576
+ \`\`\`
577
+ ${cliCommand}
578
+ \`\`\`
579
+
580
+ **Option 2: Sign with MetaMask**
581
+ Visit: https://moltspay.vercel.app/permit?data=${encodeURIComponent(JSON.stringify(typedData))}
582
+
583
+ After signing, send me the signature (v, r, s).`;
584
+ return { message, typedData, cliCommand };
585
+ }
586
+ };
587
+ function getAgentAddress(config) {
588
+ const wallet = new AgentWallet(config);
589
+ return wallet.address;
590
+ }
591
+
592
+ // src/wallet/Wallet.ts
593
+ import { ethers as ethers3 } from "ethers";
285
594
  var Wallet = class {
286
595
  chain;
287
596
  chainConfig;
@@ -297,10 +606,10 @@ var Wallet = class {
297
606
  throw new Error("privateKey is required. Set via config or PAYMENT_AGENT_PRIVATE_KEY env var.");
298
607
  }
299
608
  const rpcUrl = config.rpcUrl || this.chainConfig.rpc;
300
- this.provider = new ethers2.JsonRpcProvider(rpcUrl);
301
- this.wallet = new ethers2.Wallet(privateKey, this.provider);
609
+ this.provider = new ethers3.JsonRpcProvider(rpcUrl);
610
+ this.wallet = new ethers3.Wallet(privateKey, this.provider);
302
611
  this.address = this.wallet.address;
303
- this.usdcContract = new ethers2.Contract(
612
+ this.usdcContract = new ethers3.Contract(
304
613
  this.chainConfig.usdc,
305
614
  ERC20_ABI,
306
615
  this.wallet
@@ -316,7 +625,7 @@ var Wallet = class {
316
625
  ]);
317
626
  return {
318
627
  address: this.address,
319
- eth: ethers2.formatEther(ethBalance),
628
+ eth: ethers3.formatEther(ethBalance),
320
629
  usdc: (Number(usdcBalance) / 1e6).toFixed(2),
321
630
  chain: this.chain
322
631
  };
@@ -326,7 +635,7 @@ var Wallet = class {
326
635
  */
327
636
  async transfer(to, amount) {
328
637
  try {
329
- to = ethers2.getAddress(to);
638
+ to = ethers3.getAddress(to);
330
639
  const amountWei = BigInt(Math.floor(amount * 1e6));
331
640
  const balance = await this.usdcContract.balanceOf(this.address);
332
641
  if (BigInt(balance) < amountWei) {
@@ -367,7 +676,7 @@ var Wallet = class {
367
676
  */
368
677
  async getEthBalance() {
369
678
  const balance = await this.provider.getBalance(this.address);
370
- return ethers2.formatEther(balance);
679
+ return ethers3.formatEther(balance);
371
680
  }
372
681
  /**
373
682
  * Get USDC balance
@@ -379,14 +688,14 @@ var Wallet = class {
379
688
  };
380
689
 
381
690
  // src/audit/AuditLog.ts
382
- import * as fs from "fs";
383
- import * as path from "path";
691
+ import * as fs2 from "fs";
692
+ import * as path2 from "path";
384
693
  import * as crypto from "crypto";
385
694
  var AuditLog = class {
386
695
  basePath;
387
696
  lastHash = "0000000000000000";
388
697
  constructor(basePath) {
389
- this.basePath = basePath || path.join(process.cwd(), "data", "audit");
698
+ this.basePath = basePath || path2.join(process.cwd(), "data", "audit");
390
699
  this.ensureDir();
391
700
  this.loadLastHash();
392
701
  }
@@ -415,7 +724,7 @@ var AuditLog = class {
415
724
  this.lastHash = entry.hash;
416
725
  const filePath = this.getFilePath(now);
417
726
  const line = JSON.stringify(entry) + "\n";
418
- fs.appendFileSync(filePath, line, "utf-8");
727
+ fs2.appendFileSync(filePath, line, "utf-8");
419
728
  return entry;
420
729
  }
421
730
  /**
@@ -423,10 +732,10 @@ var AuditLog = class {
423
732
  */
424
733
  read(date) {
425
734
  const filePath = this.getFilePath(date || /* @__PURE__ */ new Date());
426
- if (!fs.existsSync(filePath)) {
735
+ if (!fs2.existsSync(filePath)) {
427
736
  return [];
428
737
  }
429
- const content = fs.readFileSync(filePath, "utf-8");
738
+ const content = fs2.readFileSync(filePath, "utf-8");
430
739
  const lines = content.trim().split("\n").filter(Boolean);
431
740
  return lines.map((line) => JSON.parse(line));
432
741
  }
@@ -477,7 +786,7 @@ var AuditLog = class {
477
786
  */
478
787
  getFilePath(date) {
479
788
  const dateStr = date.toISOString().slice(0, 10);
480
- return path.join(this.basePath, `audit_${dateStr}.jsonl`);
789
+ return path2.join(this.basePath, `audit_${dateStr}.jsonl`);
481
790
  }
482
791
  /**
483
792
  * Calculate entry hash
@@ -515,8 +824,8 @@ var AuditLog = class {
515
824
  * Ensure directory exists
516
825
  */
517
826
  ensureDir() {
518
- if (!fs.existsSync(this.basePath)) {
519
- fs.mkdirSync(this.basePath, { recursive: true });
827
+ if (!fs2.existsSync(this.basePath)) {
828
+ fs2.mkdirSync(this.basePath, { recursive: true });
520
829
  }
521
830
  }
522
831
  };
@@ -780,11 +1089,11 @@ var SecureWallet = class {
780
1089
  };
781
1090
 
782
1091
  // src/wallet/createWallet.ts
783
- import { ethers as ethers3 } from "ethers";
784
- import { writeFileSync, readFileSync as readFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
785
- import { join as join2, dirname } from "path";
1092
+ import { ethers as ethers4 } from "ethers";
1093
+ import { writeFileSync as writeFileSync2, readFileSync as readFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync3 } from "fs";
1094
+ import { join as join3, dirname } from "path";
786
1095
  import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from "crypto";
787
- var DEFAULT_STORAGE_DIR = join2(process.env.HOME || "~", ".moltspay");
1096
+ var DEFAULT_STORAGE_DIR = join3(process.env.HOME || "~", ".moltspay");
788
1097
  var DEFAULT_STORAGE_FILE = "wallet.json";
789
1098
  function encryptPrivateKey(privateKey, password) {
790
1099
  const salt = randomBytes(16);
@@ -807,10 +1116,10 @@ function decryptPrivateKey(encrypted, password, iv, salt) {
807
1116
  return decrypted;
808
1117
  }
809
1118
  function createWallet(options = {}) {
810
- const storagePath = options.storagePath || join2(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
811
- if (existsSync2(storagePath) && !options.overwrite) {
1119
+ const storagePath = options.storagePath || join3(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
1120
+ if (existsSync3(storagePath) && !options.overwrite) {
812
1121
  try {
813
- const existing = JSON.parse(readFileSync2(storagePath, "utf8"));
1122
+ const existing = JSON.parse(readFileSync3(storagePath, "utf8"));
814
1123
  return {
815
1124
  success: true,
816
1125
  address: existing.address,
@@ -825,7 +1134,7 @@ function createWallet(options = {}) {
825
1134
  }
826
1135
  }
827
1136
  try {
828
- const wallet = ethers3.Wallet.createRandom();
1137
+ const wallet = ethers4.Wallet.createRandom();
829
1138
  const walletData = {
830
1139
  address: wallet.address,
831
1140
  label: options.label,
@@ -842,10 +1151,10 @@ function createWallet(options = {}) {
842
1151
  walletData.privateKey = wallet.privateKey;
843
1152
  }
844
1153
  const dir = dirname(storagePath);
845
- if (!existsSync2(dir)) {
846
- mkdirSync2(dir, { recursive: true });
1154
+ if (!existsSync3(dir)) {
1155
+ mkdirSync3(dir, { recursive: true });
847
1156
  }
848
- writeFileSync(storagePath, JSON.stringify(walletData, null, 2), { mode: 384 });
1157
+ writeFileSync2(storagePath, JSON.stringify(walletData, null, 2), { mode: 384 });
849
1158
  return {
850
1159
  success: true,
851
1160
  address: wallet.address,
@@ -860,12 +1169,12 @@ function createWallet(options = {}) {
860
1169
  }
861
1170
  }
862
1171
  function loadWallet(options = {}) {
863
- const storagePath = options.storagePath || join2(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
864
- if (!existsSync2(storagePath)) {
1172
+ const storagePath = options.storagePath || join3(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
1173
+ if (!existsSync3(storagePath)) {
865
1174
  return { success: false, error: "Wallet not found. Run createWallet() first." };
866
1175
  }
867
1176
  try {
868
- const data = JSON.parse(readFileSync2(storagePath, "utf8"));
1177
+ const data = JSON.parse(readFileSync3(storagePath, "utf8"));
869
1178
  if (data.encrypted) {
870
1179
  if (!options.password) {
871
1180
  return { success: false, error: "Wallet is encrypted. Password required." };
@@ -880,25 +1189,25 @@ function loadWallet(options = {}) {
880
1189
  }
881
1190
  }
882
1191
  function getWalletAddress(storagePath) {
883
- const path2 = storagePath || join2(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
884
- if (!existsSync2(path2)) {
1192
+ const path3 = storagePath || join3(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
1193
+ if (!existsSync3(path3)) {
885
1194
  return null;
886
1195
  }
887
1196
  try {
888
- const data = JSON.parse(readFileSync2(path2, "utf8"));
1197
+ const data = JSON.parse(readFileSync3(path3, "utf8"));
889
1198
  return data.address;
890
1199
  } catch {
891
1200
  return null;
892
1201
  }
893
1202
  }
894
1203
  function walletExists(storagePath) {
895
- const path2 = storagePath || join2(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
896
- return existsSync2(path2);
1204
+ const path3 = storagePath || join3(DEFAULT_STORAGE_DIR, DEFAULT_STORAGE_FILE);
1205
+ return existsSync3(path3);
897
1206
  }
898
1207
 
899
1208
  // src/wallet/PermitWallet.ts
900
- import { ethers as ethers4 } from "ethers";
901
- var PERMIT_ABI = [
1209
+ import { ethers as ethers5 } from "ethers";
1210
+ var PERMIT_ABI2 = [
902
1211
  ...ERC20_ABI,
903
1212
  "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
904
1213
  "function transferFrom(address from, address to, uint256 amount) returns (bool)",
@@ -929,12 +1238,12 @@ var PermitWallet = class {
929
1238
  throw new Error("privateKey is required. Set via config, env var, or walletPath.");
930
1239
  }
931
1240
  const rpcUrl = config.rpcUrl || this.chainConfig.rpc;
932
- this.provider = new ethers4.JsonRpcProvider(rpcUrl);
933
- this.wallet = new ethers4.Wallet(privateKey, this.provider);
1241
+ this.provider = new ethers5.JsonRpcProvider(rpcUrl);
1242
+ this.wallet = new ethers5.Wallet(privateKey, this.provider);
934
1243
  this.address = this.wallet.address;
935
- this.usdcContract = new ethers4.Contract(
1244
+ this.usdcContract = new ethers5.Contract(
936
1245
  this.chainConfig.usdc,
937
- PERMIT_ABI,
1246
+ PERMIT_ABI2,
938
1247
  this.wallet
939
1248
  );
940
1249
  }
@@ -977,9 +1286,9 @@ var PermitWallet = class {
977
1286
  async transferWithPermit(params) {
978
1287
  const { to, amount, permit } = params;
979
1288
  try {
980
- const toAddress = ethers4.getAddress(to);
981
- const ownerAddress = ethers4.getAddress(permit.owner);
982
- if (ethers4.getAddress(permit.spender).toLowerCase() !== this.address.toLowerCase()) {
1289
+ const toAddress = ethers5.getAddress(to);
1290
+ const ownerAddress = ethers5.getAddress(permit.owner);
1291
+ if (ethers5.getAddress(permit.spender).toLowerCase() !== this.address.toLowerCase()) {
983
1292
  return {
984
1293
  success: false,
985
1294
  error: `Permit spender (${permit.spender}) doesn't match wallet address (${this.address})`
@@ -1083,7 +1392,7 @@ var PermitWallet = class {
1083
1392
  */
1084
1393
  async getGasBalance() {
1085
1394
  const balance = await this.provider.getBalance(this.address);
1086
- return ethers4.formatEther(balance);
1395
+ return ethers5.formatEther(balance);
1087
1396
  }
1088
1397
  /**
1089
1398
  * Check if there's enough gas
@@ -1144,7 +1453,7 @@ After signing, send { v, r, s, deadline } to the Agent.
1144
1453
  }
1145
1454
 
1146
1455
  // src/wallet/signPermit.ts
1147
- import { ethers as ethers5 } from "ethers";
1456
+ import { ethers as ethers6 } from "ethers";
1148
1457
  async function signPermit(config, params) {
1149
1458
  const chain = config.chain || "base";
1150
1459
  const chainConfig = getChain(chain);
@@ -1153,9 +1462,9 @@ async function signPermit(config, params) {
1153
1462
  throw new Error("privateKey is required");
1154
1463
  }
1155
1464
  const rpcUrl = config.rpcUrl || chainConfig.rpc;
1156
- const provider = new ethers5.JsonRpcProvider(rpcUrl);
1157
- const wallet = new ethers5.Wallet(privateKey, provider);
1158
- const usdcContract = new ethers5.Contract(chainConfig.usdc, ERC20_ABI, provider);
1465
+ const provider = new ethers6.JsonRpcProvider(rpcUrl);
1466
+ const wallet = new ethers6.Wallet(privateKey, provider);
1467
+ const usdcContract = new ethers6.Contract(chainConfig.usdc, ERC20_ABI, provider);
1159
1468
  const nonce = Number(await usdcContract.nonces(wallet.address));
1160
1469
  let deadline;
1161
1470
  if (!params.deadline) {
@@ -1189,7 +1498,7 @@ async function signPermit(config, params) {
1189
1498
  deadline
1190
1499
  };
1191
1500
  const signature = await wallet.signTypedData(domain, types, message);
1192
- const sig = ethers5.Signature.from(signature);
1501
+ const sig = ethers6.Signature.from(signature);
1193
1502
  return {
1194
1503
  owner: wallet.address,
1195
1504
  spender: params.spender,
@@ -1212,8 +1521,8 @@ var PermitSigner = class {
1212
1521
  };
1213
1522
 
1214
1523
  // src/wallet/AllowanceWallet.ts
1215
- import { ethers as ethers6 } from "ethers";
1216
- var PERMIT_ABI2 = [
1524
+ import { ethers as ethers7 } from "ethers";
1525
+ var PERMIT_ABI3 = [
1217
1526
  ...ERC20_ABI,
1218
1527
  "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
1219
1528
  "function transferFrom(address from, address to, uint256 amount) returns (bool)",
@@ -1234,12 +1543,12 @@ var AllowanceWallet = class {
1234
1543
  this.chain = config.chain || "base_sepolia";
1235
1544
  this.chainConfig = getChain(this.chain);
1236
1545
  const rpcUrl = config.rpcUrl || this.chainConfig.rpc;
1237
- this.provider = new ethers6.JsonRpcProvider(rpcUrl);
1238
- this.wallet = new ethers6.Wallet(config.privateKey, this.provider);
1546
+ this.provider = new ethers7.JsonRpcProvider(rpcUrl);
1547
+ this.wallet = new ethers7.Wallet(config.privateKey, this.provider);
1239
1548
  this.address = this.wallet.address;
1240
- this.usdcContract = new ethers6.Contract(
1549
+ this.usdcContract = new ethers7.Contract(
1241
1550
  this.chainConfig.usdc,
1242
- PERMIT_ABI2,
1551
+ PERMIT_ABI3,
1243
1552
  this.wallet
1244
1553
  );
1245
1554
  }
@@ -1261,20 +1570,20 @@ var AllowanceWallet = class {
1261
1570
  * Check allowance status with an owner
1262
1571
  */
1263
1572
  async checkAllowance(owner) {
1264
- const ownerAddress = ethers6.getAddress(owner);
1573
+ const ownerAddress = ethers7.getAddress(owner);
1265
1574
  const [allowance, ownerBalance, agentGasBalance] = await Promise.all([
1266
1575
  this.usdcContract.allowance(ownerAddress, this.address),
1267
1576
  this.usdcContract.balanceOf(ownerAddress),
1268
1577
  this.provider.getBalance(this.address)
1269
1578
  ]);
1270
1579
  const allowanceNum = Number(allowance) / 1e6;
1271
- const hasGas = Number(ethers6.formatEther(agentGasBalance)) >= 1e-4;
1580
+ const hasGas = Number(ethers7.formatEther(agentGasBalance)) >= 1e-4;
1272
1581
  return {
1273
1582
  owner: ownerAddress,
1274
1583
  agent: this.address,
1275
1584
  allowance: allowanceNum.toFixed(2),
1276
1585
  ownerBalance: (Number(ownerBalance) / 1e6).toFixed(2),
1277
- agentGasBalance: ethers6.formatEther(agentGasBalance),
1586
+ agentGasBalance: ethers7.formatEther(agentGasBalance),
1278
1587
  canSpend: allowanceNum > 0 && hasGas,
1279
1588
  chain: this.chainConfig.name
1280
1589
  };
@@ -1302,18 +1611,18 @@ var AllowanceWallet = class {
1302
1611
  async spend(params) {
1303
1612
  const { to, amount, permit } = params;
1304
1613
  try {
1305
- const toAddress = ethers6.getAddress(to);
1614
+ const toAddress = ethers7.getAddress(to);
1306
1615
  const amountWei = BigInt(Math.floor(amount * 1e6));
1307
1616
  let ownerPermit = permit;
1308
1617
  let ownerAddress;
1309
1618
  if (ownerPermit) {
1310
- ownerAddress = ethers6.getAddress(ownerPermit.owner);
1619
+ ownerAddress = ethers7.getAddress(ownerPermit.owner);
1311
1620
  this.storePermit(ownerPermit);
1312
1621
  } else {
1313
1622
  for (const [owner, p] of this.permits) {
1314
1623
  const allowance = await this.usdcContract.allowance(owner, this.address);
1315
1624
  if (BigInt(allowance) >= amountWei) {
1316
- ownerAddress = ethers6.getAddress(owner);
1625
+ ownerAddress = ethers7.getAddress(owner);
1317
1626
  ownerPermit = p;
1318
1627
  break;
1319
1628
  }
@@ -1414,7 +1723,7 @@ var AllowanceWallet = class {
1414
1723
  */
1415
1724
  async getGasBalance() {
1416
1725
  const balance = await this.provider.getBalance(this.address);
1417
- return ethers6.formatEther(balance);
1726
+ return ethers7.formatEther(balance);
1418
1727
  }
1419
1728
  };
1420
1729
  function generatePermitInstructions(params) {
@@ -1488,7 +1797,7 @@ ${JSON.stringify(typedData, null, 2)}
1488
1797
  }
1489
1798
 
1490
1799
  // src/permit/Permit.ts
1491
- import { ethers as ethers7 } from "ethers";
1800
+ import { ethers as ethers8 } from "ethers";
1492
1801
  var PermitPayment = class {
1493
1802
  chain;
1494
1803
  chainConfig;
@@ -1501,13 +1810,13 @@ var PermitPayment = class {
1501
1810
  this.chainConfig = getChain(this.chain);
1502
1811
  this.spenderAddress = config.spenderAddress || process.env.PAYMENT_AGENT_WALLET || "";
1503
1812
  const rpcUrl = config.rpcUrl || this.chainConfig.rpc;
1504
- this.provider = new ethers7.JsonRpcProvider(rpcUrl);
1813
+ this.provider = new ethers8.JsonRpcProvider(rpcUrl);
1505
1814
  const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;
1506
1815
  if (privateKey) {
1507
- this.wallet = new ethers7.Wallet(privateKey, this.provider);
1816
+ this.wallet = new ethers8.Wallet(privateKey, this.provider);
1508
1817
  this.spenderAddress = this.wallet.address;
1509
1818
  }
1510
- this.usdcContract = new ethers7.Contract(
1819
+ this.usdcContract = new ethers8.Contract(
1511
1820
  this.chainConfig.usdc,
1512
1821
  ERC20_ABI,
1513
1822
  this.wallet || this.provider
@@ -1790,8 +2099,8 @@ var OrderManager = class {
1790
2099
  };
1791
2100
 
1792
2101
  // src/verify/index.ts
1793
- import { ethers as ethers8 } from "ethers";
1794
- var TRANSFER_EVENT_TOPIC = ethers8.id("Transfer(address,address,uint256)");
2102
+ import { ethers as ethers9 } from "ethers";
2103
+ var TRANSFER_EVENT_TOPIC = ethers9.id("Transfer(address,address,uint256)");
1795
2104
  async function verifyPayment(params) {
1796
2105
  const { txHash, expectedAmount, expectedTo } = params;
1797
2106
  let chain;
@@ -1808,7 +2117,7 @@ async function verifyPayment(params) {
1808
2117
  return { verified: false, error: `Unsupported chain: ${params.chain}` };
1809
2118
  }
1810
2119
  try {
1811
- const provider = new ethers8.JsonRpcProvider(chain.rpc);
2120
+ const provider = new ethers9.JsonRpcProvider(chain.rpc);
1812
2121
  const receipt = await provider.getTransactionReceipt(txHash);
1813
2122
  if (!receipt) {
1814
2123
  return { verified: false, error: "Transaction not found or not confirmed" };
@@ -1868,7 +2177,7 @@ async function getTransactionStatus(txHash, chain = "base") {
1868
2177
  return { status: "not_found" };
1869
2178
  }
1870
2179
  try {
1871
- const provider = new ethers8.JsonRpcProvider(chainConfig.rpc);
2180
+ const provider = new ethers9.JsonRpcProvider(chainConfig.rpc);
1872
2181
  const receipt = await provider.getTransactionReceipt(txHash);
1873
2182
  if (!receipt) {
1874
2183
  const tx = await provider.getTransaction(txHash);
@@ -1905,7 +2214,7 @@ async function waitForTransaction(txHash, chain = "base", confirmations = 1, tim
1905
2214
  } catch (e) {
1906
2215
  return { verified: false, confirmed: false, error: `Unsupported chain: ${chain}` };
1907
2216
  }
1908
- const provider = new ethers8.JsonRpcProvider(chainConfig.rpc);
2217
+ const provider = new ethers9.JsonRpcProvider(chainConfig.rpc);
1909
2218
  try {
1910
2219
  const receipt = await provider.waitForTransaction(txHash, confirmations, timeoutMs);
1911
2220
  if (!receipt) {
@@ -2218,8 +2527,14 @@ Can you follow my guidance to set this up?`;
2218
2527
  * 3.1 Installation Guide - First step: install SDK
2219
2528
  */
2220
2529
  guideInstall() {
2221
- return `Step 1: Install the payment module in your environment. Run: \`npm install moltspay ethers\`.
2222
- After installation, create a wallet address and send it to me (address only, never send private key/mnemonic).`;
2530
+ return `Step 1: Install and initialize the payment module:
2531
+
2532
+ \`\`\`bash
2533
+ npm install moltspay
2534
+ npx moltspay init --chain base
2535
+ \`\`\`
2536
+
2537
+ This will automatically create your wallet (no gas needed). Send me your wallet address (never send private key/mnemonic).`;
2223
2538
  },
2224
2539
  /**
2225
2540
  * 3.2 Confirm Wallet Address
@@ -2411,7 +2726,8 @@ var BuyerTemplates = {
2411
2726
  * 3.1 Report Wallet Created
2412
2727
  */
2413
2728
  walletCreated(address) {
2414
- return `I've created my wallet address: ${address}.
2729
+ return `I've installed moltspay and initialized my wallet.
2730
+ My address: ${address}
2415
2731
  [status:wallet_ready]`;
2416
2732
  },
2417
2733
  /**
@@ -2592,6 +2908,7 @@ function parseStatusMarker(message) {
2592
2908
  return { type: "unknown", data: { raw: content } };
2593
2909
  }
2594
2910
  export {
2911
+ AgentWallet,
2595
2912
  AllowanceWallet,
2596
2913
  AuditLog,
2597
2914
  BuyerTemplates,
@@ -2619,6 +2936,7 @@ export {
2619
2936
  generateReceipt,
2620
2937
  generateReceiptFromInvoice,
2621
2938
  generateWalletGuide,
2939
+ getAgentAddress,
2622
2940
  getChain,
2623
2941
  getChainById,
2624
2942
  getTransactionStatus,