moltspay 0.2.2 → 0.2.4

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.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { C as ChainName, a as ChainConfig, P as PaymentAgentConfig, b as CreateInvoiceParams, I as Invoice, V as VerifyOptions, c as VerifyResult, W as WalletBalance, A as AuditAction, d as AuditEntry } from './index-CyFg9s2m.js';
2
2
  export { E as EIP712TypedData, e as PendingTransfer, f as PermitExecuteResult, g as PermitRequest, h as PermitSignature, S as SecureWalletConfig, i as SecurityLimits, T as TransferParams, j as TransferResult } from './index-CyFg9s2m.js';
3
- export { CreateWalletOptions, CreateWalletResult, PermitData, PermitWallet, PermitWalletConfig, SecureWallet, TransferWithPermitParams, TransferWithPermitResult, Wallet, WalletData, createWallet, formatPermitRequest, getWalletAddress, loadWallet, walletExists } from './wallet/index.js';
3
+ export { AllowanceStatus, AllowanceWallet, AllowanceWalletConfig, CreateWalletOptions, CreateWalletResult, OwnerPermit, PermitData, PermitSigner, PermitWallet, PermitWalletConfig, SecureWallet, SignPermitConfig, SignPermitParams, SignPermitResult, SpendParams, SpendResult, TransferWithPermitParams, TransferWithPermitResult, Wallet, WalletData, createWallet, formatPermitRequest, generatePermitInstructions, getWalletAddress, loadWallet, signPermit, walletExists } from './wallet/index.js';
4
4
  export { PermitPayment } from './permit/index.js';
5
5
  export { CreateOrderParams, MemoryOrderStore, Order, OrderManager, OrderStatus, OrderStore } from './orders/index.js';
6
6
  export { VerifyPaymentParams, VerifyPaymentResult, getTransactionStatus, verifyPayment, waitForTransaction } from './verify/index.js';
@@ -288,6 +288,32 @@ declare const SellerTemplates: {
288
288
  * 10. End
289
289
  */
290
290
  end(): string;
291
+ /**
292
+ * Offer Permit payment option
293
+ */
294
+ offerPermitPayment(params: {
295
+ service: string;
296
+ price: number;
297
+ sellerAddress: string;
298
+ chain?: ChainName;
299
+ invoiceId: string;
300
+ }): string;
301
+ /**
302
+ * Confirm Permit received, executing payment
303
+ */
304
+ executingPermit(invoiceId: string): string;
305
+ /**
306
+ * Permit payment successful
307
+ */
308
+ permitPaymentReceived(params: {
309
+ amount: number;
310
+ txHash: string;
311
+ invoiceId: string;
312
+ }): string;
313
+ /**
314
+ * Permit payment failed
315
+ */
316
+ permitPaymentFailed(error: string, invoiceId: string): string;
291
317
  };
292
318
  declare const BuyerTemplates: {
293
319
  /**
@@ -351,10 +377,48 @@ declare const BuyerTemplates: {
351
377
  deadlineHours?: number;
352
378
  reason?: string;
353
379
  }): string;
380
+ /**
381
+ * Confirm willing to pay via Permit
382
+ */
383
+ confirmPermitPayment(): string;
384
+ /**
385
+ * Send signed Permit to Seller
386
+ */
387
+ sendPermit(params: {
388
+ permit: {
389
+ owner: string;
390
+ spender: string;
391
+ value: string;
392
+ deadline: number;
393
+ nonce: number;
394
+ v: number;
395
+ r: string;
396
+ s: string;
397
+ };
398
+ invoiceId: string;
399
+ amount: number;
400
+ }): string;
401
+ /**
402
+ * Simplified Permit message (compact JSON for agent parsing)
403
+ */
404
+ sendPermitCompact(params: {
405
+ permit: {
406
+ owner: string;
407
+ spender: string;
408
+ value: string;
409
+ deadline: number;
410
+ v: number;
411
+ r: string;
412
+ s: string;
413
+ };
414
+ invoiceId: string;
415
+ }): string;
354
416
  };
355
417
  declare const StatusMarkers: {
356
418
  walletReady: string;
357
419
  permitReady: (amount: number) => string;
420
+ permitSent: (invoiceId: string, amount: number) => string;
421
+ awaitingPermit: (invoiceId: string) => string;
358
422
  paymentSent: (txHash: string, amount: number) => string;
359
423
  paymentConfirmed: (txHash: string) => string;
360
424
  delivered: (url: string, hash?: string) => string;
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
+ AllowanceWallet: () => AllowanceWallet,
33
34
  AuditLog: () => AuditLog,
34
35
  BuyerTemplates: () => BuyerTemplates,
35
36
  CHAINS: () => CHAINS,
@@ -38,6 +39,7 @@ __export(src_exports, {
38
39
  OrderManager: () => OrderManager,
39
40
  PaymentAgent: () => PaymentAgent,
40
41
  PermitPayment: () => PermitPayment,
42
+ PermitSigner: () => PermitSigner,
41
43
  PermitWallet: () => PermitWallet,
42
44
  SecureWallet: () => SecureWallet,
43
45
  SellerTemplates: () => SellerTemplates,
@@ -51,6 +53,7 @@ __export(src_exports, {
51
53
  formatReceiptText: () => formatReceiptText,
52
54
  generatePaymentGuide: () => generatePaymentGuide,
53
55
  generatePaymentReminder: () => generatePaymentReminder,
56
+ generatePermitInstructions: () => generatePermitInstructions,
54
57
  generateReceipt: () => generateReceipt,
55
58
  generateReceiptFromInvoice: () => generateReceiptFromInvoice,
56
59
  generateWalletGuide: () => generateWalletGuide,
@@ -62,6 +65,7 @@ __export(src_exports, {
62
65
  listChains: () => listChains,
63
66
  loadWallet: () => loadWallet,
64
67
  parseStatusMarker: () => parseStatusMarker,
68
+ signPermit: () => signPermit,
65
69
  verifyPayment: () => verifyPayment,
66
70
  waitForTransaction: () => waitForTransaction,
67
71
  walletExists: () => walletExists
@@ -1213,8 +1217,352 @@ After signing, send { v, r, s, deadline } to the Agent.
1213
1217
  \u26A0\uFE0F Note: This authorization only allows the Agent to spend up to ${amount} USDC from your wallet. Your private key is never exposed.`;
1214
1218
  }
1215
1219
 
1216
- // src/permit/Permit.ts
1220
+ // src/wallet/signPermit.ts
1217
1221
  var import_ethers5 = require("ethers");
1222
+ async function signPermit(config, params) {
1223
+ const chain = config.chain || "base";
1224
+ const chainConfig = getChain(chain);
1225
+ const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;
1226
+ if (!privateKey) {
1227
+ throw new Error("privateKey is required");
1228
+ }
1229
+ const rpcUrl = config.rpcUrl || chainConfig.rpc;
1230
+ const provider = new import_ethers5.ethers.JsonRpcProvider(rpcUrl);
1231
+ const wallet = new import_ethers5.ethers.Wallet(privateKey, provider);
1232
+ const usdcContract = new import_ethers5.ethers.Contract(chainConfig.usdc, ERC20_ABI, provider);
1233
+ const nonce = Number(await usdcContract.nonces(wallet.address));
1234
+ let deadline;
1235
+ if (!params.deadline) {
1236
+ deadline = Math.floor(Date.now() / 1e3) + 30 * 60;
1237
+ } else if (params.deadline < 1e6) {
1238
+ deadline = Math.floor(Date.now() / 1e3) + params.deadline * 60;
1239
+ } else {
1240
+ deadline = params.deadline;
1241
+ }
1242
+ const value = BigInt(Math.floor(params.amount * 1e6)).toString();
1243
+ const domain = {
1244
+ name: "USD Coin",
1245
+ version: "2",
1246
+ chainId: chainConfig.chainId,
1247
+ verifyingContract: chainConfig.usdc
1248
+ };
1249
+ const types = {
1250
+ Permit: [
1251
+ { name: "owner", type: "address" },
1252
+ { name: "spender", type: "address" },
1253
+ { name: "value", type: "uint256" },
1254
+ { name: "nonce", type: "uint256" },
1255
+ { name: "deadline", type: "uint256" }
1256
+ ]
1257
+ };
1258
+ const message = {
1259
+ owner: wallet.address,
1260
+ spender: params.spender,
1261
+ value,
1262
+ nonce,
1263
+ deadline
1264
+ };
1265
+ const signature = await wallet.signTypedData(domain, types, message);
1266
+ const sig = import_ethers5.ethers.Signature.from(signature);
1267
+ return {
1268
+ owner: wallet.address,
1269
+ spender: params.spender,
1270
+ value,
1271
+ deadline,
1272
+ nonce,
1273
+ v: sig.v,
1274
+ r: sig.r,
1275
+ s: sig.s
1276
+ };
1277
+ }
1278
+ var PermitSigner = class {
1279
+ config;
1280
+ constructor(config) {
1281
+ this.config = config;
1282
+ }
1283
+ async sign(params) {
1284
+ return signPermit(this.config, params);
1285
+ }
1286
+ };
1287
+
1288
+ // src/wallet/AllowanceWallet.ts
1289
+ var import_ethers6 = require("ethers");
1290
+ var PERMIT_ABI2 = [
1291
+ ...ERC20_ABI,
1292
+ "function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)",
1293
+ "function transferFrom(address from, address to, uint256 amount) returns (bool)",
1294
+ "function allowance(address owner, address spender) view returns (uint256)",
1295
+ "function nonces(address owner) view returns (uint256)"
1296
+ ];
1297
+ var AllowanceWallet = class {
1298
+ chain;
1299
+ chainConfig;
1300
+ address;
1301
+ // Agent's address
1302
+ wallet;
1303
+ provider;
1304
+ usdcContract;
1305
+ /** Stored permits from owners */
1306
+ permits = /* @__PURE__ */ new Map();
1307
+ constructor(config) {
1308
+ this.chain = config.chain || "base_sepolia";
1309
+ this.chainConfig = getChain(this.chain);
1310
+ const rpcUrl = config.rpcUrl || this.chainConfig.rpc;
1311
+ this.provider = new import_ethers6.ethers.JsonRpcProvider(rpcUrl);
1312
+ this.wallet = new import_ethers6.ethers.Wallet(config.privateKey, this.provider);
1313
+ this.address = this.wallet.address;
1314
+ this.usdcContract = new import_ethers6.ethers.Contract(
1315
+ this.chainConfig.usdc,
1316
+ PERMIT_ABI2,
1317
+ this.wallet
1318
+ );
1319
+ }
1320
+ /**
1321
+ * Store a Permit received from Owner
1322
+ * Call this when Owner sends you a signed Permit
1323
+ */
1324
+ storePermit(permit) {
1325
+ const ownerLower = permit.owner.toLowerCase();
1326
+ this.permits.set(ownerLower, permit);
1327
+ }
1328
+ /**
1329
+ * Get stored Permit for an owner
1330
+ */
1331
+ getPermit(owner) {
1332
+ return this.permits.get(owner.toLowerCase());
1333
+ }
1334
+ /**
1335
+ * Check allowance status with an owner
1336
+ */
1337
+ async checkAllowance(owner) {
1338
+ const ownerAddress = import_ethers6.ethers.getAddress(owner);
1339
+ const [allowance, ownerBalance, agentGasBalance] = await Promise.all([
1340
+ this.usdcContract.allowance(ownerAddress, this.address),
1341
+ this.usdcContract.balanceOf(ownerAddress),
1342
+ this.provider.getBalance(this.address)
1343
+ ]);
1344
+ const allowanceNum = Number(allowance) / 1e6;
1345
+ const hasGas = Number(import_ethers6.ethers.formatEther(agentGasBalance)) >= 1e-4;
1346
+ return {
1347
+ owner: ownerAddress,
1348
+ agent: this.address,
1349
+ allowance: allowanceNum.toFixed(2),
1350
+ ownerBalance: (Number(ownerBalance) / 1e6).toFixed(2),
1351
+ agentGasBalance: import_ethers6.ethers.formatEther(agentGasBalance),
1352
+ canSpend: allowanceNum > 0 && hasGas,
1353
+ chain: this.chainConfig.name
1354
+ };
1355
+ }
1356
+ /**
1357
+ * Spend from Owner's wallet using Permit allowance
1358
+ *
1359
+ * @example
1360
+ * ```typescript
1361
+ * const agent = new AllowanceWallet({
1362
+ * chain: 'base',
1363
+ * privateKey: process.env.AGENT_KEY // Only needs gas
1364
+ * });
1365
+ *
1366
+ * // Owner gave us a Permit
1367
+ * agent.storePermit(ownerPermit);
1368
+ *
1369
+ * // Spend to pay for a service
1370
+ * const result = await agent.spend({
1371
+ * to: '0xServiceProvider...',
1372
+ * amount: 2.99,
1373
+ * });
1374
+ * ```
1375
+ */
1376
+ async spend(params) {
1377
+ const { to, amount, permit } = params;
1378
+ try {
1379
+ const toAddress = import_ethers6.ethers.getAddress(to);
1380
+ const amountWei = BigInt(Math.floor(amount * 1e6));
1381
+ let ownerPermit = permit;
1382
+ let ownerAddress;
1383
+ if (ownerPermit) {
1384
+ ownerAddress = import_ethers6.ethers.getAddress(ownerPermit.owner);
1385
+ this.storePermit(ownerPermit);
1386
+ } else {
1387
+ for (const [owner, p] of this.permits) {
1388
+ const allowance = await this.usdcContract.allowance(owner, this.address);
1389
+ if (BigInt(allowance) >= amountWei) {
1390
+ ownerAddress = import_ethers6.ethers.getAddress(owner);
1391
+ ownerPermit = p;
1392
+ break;
1393
+ }
1394
+ }
1395
+ if (!ownerPermit) {
1396
+ return {
1397
+ success: false,
1398
+ error: "No valid permit found. Ask Owner to sign a Permit first.",
1399
+ from: "",
1400
+ to: toAddress,
1401
+ amount
1402
+ };
1403
+ }
1404
+ }
1405
+ const currentAllowance = await this.usdcContract.allowance(ownerAddress, this.address);
1406
+ if (BigInt(currentAllowance) < amountWei) {
1407
+ const now = Math.floor(Date.now() / 1e3);
1408
+ if (ownerPermit.deadline < now) {
1409
+ return {
1410
+ success: false,
1411
+ error: `Permit expired at ${new Date(ownerPermit.deadline * 1e3).toISOString()}. Ask Owner for a new Permit.`,
1412
+ from: ownerAddress,
1413
+ to: toAddress,
1414
+ amount
1415
+ };
1416
+ }
1417
+ const currentNonce = await this.usdcContract.nonces(ownerAddress);
1418
+ if (Number(currentNonce) !== ownerPermit.nonce) {
1419
+ return {
1420
+ success: false,
1421
+ error: `Permit nonce mismatch (expected ${ownerPermit.nonce}, got ${currentNonce}). Owner may have used this permit or signed a new one.`,
1422
+ from: ownerAddress,
1423
+ to: toAddress,
1424
+ amount
1425
+ };
1426
+ }
1427
+ console.log("[AllowanceWallet] Submitting permit on-chain...");
1428
+ const permitTx = await this.usdcContract.permit(
1429
+ ownerAddress,
1430
+ this.address,
1431
+ ownerPermit.value,
1432
+ ownerPermit.deadline,
1433
+ ownerPermit.v,
1434
+ ownerPermit.r,
1435
+ ownerPermit.s
1436
+ );
1437
+ await permitTx.wait();
1438
+ console.log("[AllowanceWallet] Permit submitted:", permitTx.hash);
1439
+ }
1440
+ console.log("[AllowanceWallet] Executing transferFrom...");
1441
+ const tx = await this.usdcContract.transferFrom(
1442
+ ownerAddress,
1443
+ toAddress,
1444
+ amountWei
1445
+ );
1446
+ const receipt = await tx.wait();
1447
+ const newAllowance = await this.usdcContract.allowance(ownerAddress, this.address);
1448
+ return {
1449
+ success: true,
1450
+ txHash: tx.hash,
1451
+ from: ownerAddress,
1452
+ to: toAddress,
1453
+ amount,
1454
+ remainingAllowance: (Number(newAllowance) / 1e6).toFixed(2),
1455
+ explorerUrl: `${this.chainConfig.explorerTx}${tx.hash}`
1456
+ };
1457
+ } catch (error) {
1458
+ const message = error.message;
1459
+ if (message.includes("ERC20InsufficientAllowance")) {
1460
+ return {
1461
+ success: false,
1462
+ error: "Insufficient allowance. Ask Owner to sign a new Permit with higher amount.",
1463
+ from: "",
1464
+ to,
1465
+ amount
1466
+ };
1467
+ }
1468
+ if (message.includes("ERC20InsufficientBalance")) {
1469
+ return {
1470
+ success: false,
1471
+ error: "Owner's wallet has insufficient USDC balance.",
1472
+ from: "",
1473
+ to,
1474
+ amount
1475
+ };
1476
+ }
1477
+ return {
1478
+ success: false,
1479
+ error: message,
1480
+ from: "",
1481
+ to,
1482
+ amount
1483
+ };
1484
+ }
1485
+ }
1486
+ /**
1487
+ * Get Agent's gas balance (ETH)
1488
+ */
1489
+ async getGasBalance() {
1490
+ const balance = await this.provider.getBalance(this.address);
1491
+ return import_ethers6.ethers.formatEther(balance);
1492
+ }
1493
+ };
1494
+ function generatePermitInstructions(params) {
1495
+ const { ownerAddress, agentAddress, amount, deadlineHours = 24, chain = "base" } = params;
1496
+ const chainConfig = getChain(chain);
1497
+ const deadline = Math.floor(Date.now() / 1e3) + deadlineHours * 3600;
1498
+ const value = BigInt(Math.floor(amount * 1e6)).toString();
1499
+ const eip712Domain = {
1500
+ name: "USD Coin",
1501
+ version: "2",
1502
+ chainId: chainConfig.chainId,
1503
+ verifyingContract: chainConfig.usdc
1504
+ };
1505
+ const typedData = {
1506
+ types: {
1507
+ EIP712Domain: [
1508
+ { name: "name", type: "string" },
1509
+ { name: "version", type: "string" },
1510
+ { name: "chainId", type: "uint256" },
1511
+ { name: "verifyingContract", type: "address" }
1512
+ ],
1513
+ Permit: [
1514
+ { name: "owner", type: "address" },
1515
+ { name: "spender", type: "address" },
1516
+ { name: "value", type: "uint256" },
1517
+ { name: "nonce", type: "uint256" },
1518
+ { name: "deadline", type: "uint256" }
1519
+ ]
1520
+ },
1521
+ primaryType: "Permit",
1522
+ domain: eip712Domain,
1523
+ message: {
1524
+ owner: ownerAddress,
1525
+ spender: agentAddress,
1526
+ value,
1527
+ nonce: "<GET_FROM_USDC_CONTRACT>",
1528
+ // Owner needs to query this
1529
+ deadline
1530
+ }
1531
+ };
1532
+ const instructions = `
1533
+ \u{1F510} **Grant USDC Spending Allowance to Your Agent**
1534
+
1535
+ Your Agent (${agentAddress}) is requesting permission to spend up to ${amount} USDC from your wallet.
1536
+
1537
+ **What this does:**
1538
+ - Allows your Agent to pay for services on your behalf
1539
+ - Your USDC stays in YOUR wallet until spent
1540
+ - Agent can only spend up to the authorized amount
1541
+ - Expires in ${deadlineHours} hours
1542
+ - You can revoke anytime by moving your USDC
1543
+
1544
+ **How to sign (MetaMask / any web3 wallet):**
1545
+
1546
+ 1. Go to https://etherscan.io/address/${chainConfig.usdc}#readContract
1547
+ 2. Query \`nonces(${ownerAddress})\` to get your current nonce
1548
+ 3. Use eth_signTypedData_v4 with the data below (replace nonce)
1549
+ 4. Send the signature {v, r, s, deadline, nonce} to your Agent
1550
+
1551
+ **Chain:** ${chainConfig.name}
1552
+ **USDC Contract:** ${chainConfig.usdc}
1553
+
1554
+ **EIP-712 Typed Data:**
1555
+ \`\`\`json
1556
+ ${JSON.stringify(typedData, null, 2)}
1557
+ \`\`\`
1558
+
1559
+ \u26A0\uFE0F Never share your private key. This signature only authorizes spending, not wallet access.
1560
+ `;
1561
+ return { instructions, typedData, eip712Domain };
1562
+ }
1563
+
1564
+ // src/permit/Permit.ts
1565
+ var import_ethers7 = require("ethers");
1218
1566
  var PermitPayment = class {
1219
1567
  chain;
1220
1568
  chainConfig;
@@ -1227,13 +1575,13 @@ var PermitPayment = class {
1227
1575
  this.chainConfig = getChain(this.chain);
1228
1576
  this.spenderAddress = config.spenderAddress || process.env.PAYMENT_AGENT_WALLET || "";
1229
1577
  const rpcUrl = config.rpcUrl || this.chainConfig.rpc;
1230
- this.provider = new import_ethers5.ethers.JsonRpcProvider(rpcUrl);
1578
+ this.provider = new import_ethers7.ethers.JsonRpcProvider(rpcUrl);
1231
1579
  const privateKey = config.privateKey || process.env.PAYMENT_AGENT_PRIVATE_KEY;
1232
1580
  if (privateKey) {
1233
- this.wallet = new import_ethers5.ethers.Wallet(privateKey, this.provider);
1581
+ this.wallet = new import_ethers7.ethers.Wallet(privateKey, this.provider);
1234
1582
  this.spenderAddress = this.wallet.address;
1235
1583
  }
1236
- this.usdcContract = new import_ethers5.ethers.Contract(
1584
+ this.usdcContract = new import_ethers7.ethers.Contract(
1237
1585
  this.chainConfig.usdc,
1238
1586
  ERC20_ABI,
1239
1587
  this.wallet || this.provider
@@ -1516,8 +1864,8 @@ var OrderManager = class {
1516
1864
  };
1517
1865
 
1518
1866
  // src/verify/index.ts
1519
- var import_ethers6 = require("ethers");
1520
- var TRANSFER_EVENT_TOPIC = import_ethers6.ethers.id("Transfer(address,address,uint256)");
1867
+ var import_ethers8 = require("ethers");
1868
+ var TRANSFER_EVENT_TOPIC = import_ethers8.ethers.id("Transfer(address,address,uint256)");
1521
1869
  async function verifyPayment(params) {
1522
1870
  const { txHash, expectedAmount, expectedTo } = params;
1523
1871
  let chain;
@@ -1534,7 +1882,7 @@ async function verifyPayment(params) {
1534
1882
  return { verified: false, error: `Unsupported chain: ${params.chain}` };
1535
1883
  }
1536
1884
  try {
1537
- const provider = new import_ethers6.ethers.JsonRpcProvider(chain.rpc);
1885
+ const provider = new import_ethers8.ethers.JsonRpcProvider(chain.rpc);
1538
1886
  const receipt = await provider.getTransactionReceipt(txHash);
1539
1887
  if (!receipt) {
1540
1888
  return { verified: false, error: "Transaction not found or not confirmed" };
@@ -1594,7 +1942,7 @@ async function getTransactionStatus(txHash, chain = "base") {
1594
1942
  return { status: "not_found" };
1595
1943
  }
1596
1944
  try {
1597
- const provider = new import_ethers6.ethers.JsonRpcProvider(chainConfig.rpc);
1945
+ const provider = new import_ethers8.ethers.JsonRpcProvider(chainConfig.rpc);
1598
1946
  const receipt = await provider.getTransactionReceipt(txHash);
1599
1947
  if (!receipt) {
1600
1948
  const tx = await provider.getTransaction(txHash);
@@ -1631,7 +1979,7 @@ async function waitForTransaction(txHash, chain = "base", confirmations = 1, tim
1631
1979
  } catch (e) {
1632
1980
  return { verified: false, confirmed: false, error: `Unsupported chain: ${chain}` };
1633
1981
  }
1634
- const provider = new import_ethers6.ethers.JsonRpcProvider(chainConfig.rpc);
1982
+ const provider = new import_ethers8.ethers.JsonRpcProvider(chainConfig.rpc);
1635
1983
  try {
1636
1984
  const receipt = await provider.waitForTransaction(txHash, confirmations, timeoutMs);
1637
1985
  if (!receipt) {
@@ -2054,6 +2402,58 @@ ${receipt.delivery?.url ? `- Delivery: ${receipt.delivery.url}` : ""}
2054
2402
  */
2055
2403
  end() {
2056
2404
  return `Thank you for your purchase. This transaction is complete. Feel free to reach out if you need modifications or new services.`;
2405
+ },
2406
+ // ============ Permit Payment (Seller receives Permit from Client) ============
2407
+ /**
2408
+ * Offer Permit payment option
2409
+ */
2410
+ offerPermitPayment(params) {
2411
+ const { service, price, sellerAddress, chain = "base", invoiceId } = params;
2412
+ const chainConfig = getChain(chain);
2413
+ return `Quote:
2414
+ - Service: ${service}
2415
+ - Price: ${price} USDC
2416
+ - Chain: ${chainConfig.name}
2417
+ - Invoice: ${invoiceId}
2418
+
2419
+ You can pay by signing a Permit authorizing my wallet to collect payment:
2420
+ - Spender (me): \`${sellerAddress}\`
2421
+ - Amount: ${price} USDC
2422
+
2423
+ Sign the Permit and send me the data. I'll then execute the collection.
2424
+ [status:awaiting_permit invoice=${invoiceId}]`;
2425
+ },
2426
+ /**
2427
+ * Confirm Permit received, executing payment
2428
+ */
2429
+ executingPermit(invoiceId) {
2430
+ return `Permit received for invoice ${invoiceId}. Executing payment collection now...`;
2431
+ },
2432
+ /**
2433
+ * Permit payment successful
2434
+ */
2435
+ permitPaymentReceived(params) {
2436
+ const { amount, txHash, invoiceId } = params;
2437
+ return `Payment collected successfully!
2438
+ - Invoice: ${invoiceId}
2439
+ - Amount: ${amount} USDC
2440
+ - Tx Hash: \`${txHash}\`
2441
+
2442
+ Starting to process your request now.
2443
+ [status:payment_confirmed tx=${txHash}]`;
2444
+ },
2445
+ /**
2446
+ * Permit payment failed
2447
+ */
2448
+ permitPaymentFailed(error, invoiceId) {
2449
+ return `Failed to collect payment for invoice ${invoiceId}: ${error}
2450
+
2451
+ Please check:
2452
+ - Permit signature is valid
2453
+ - Permit hasn't expired
2454
+ - Your wallet has sufficient USDC balance
2455
+
2456
+ You can re-sign and send a new Permit.`;
2057
2457
  }
2058
2458
  };
2059
2459
  var BuyerTemplates = {
@@ -2146,11 +2546,46 @@ ${requirements}`;
2146
2546
  const { amount, agentAddress, deadlineHours = 24, reason } = params;
2147
2547
  return `Boss, I need a USDC spending allowance (Permit) for ${reason || "purchasing services"}.
2148
2548
  Please authorize ${amount} USDC to my wallet ${agentAddress}, valid for ${deadlineHours} hours.`;
2549
+ },
2550
+ // ============ Permit Payment (Client signs Permit to Seller) ============
2551
+ /**
2552
+ * Confirm willing to pay via Permit
2553
+ */
2554
+ confirmPermitPayment() {
2555
+ return `Confirmed. I'll sign a Permit authorizing you to collect the payment.`;
2556
+ },
2557
+ /**
2558
+ * Send signed Permit to Seller
2559
+ */
2560
+ sendPermit(params) {
2561
+ const { permit, invoiceId, amount } = params;
2562
+ return `Payment authorized via Permit.
2563
+
2564
+ Invoice: ${invoiceId}
2565
+ Amount: ${amount} USDC
2566
+
2567
+ Permit Data:
2568
+ \`\`\`json
2569
+ ${JSON.stringify(permit, null, 2)}
2570
+ \`\`\`
2571
+
2572
+ [status:permit_sent invoice=${invoiceId} amount=${amount}]`;
2573
+ },
2574
+ /**
2575
+ * Simplified Permit message (compact JSON for agent parsing)
2576
+ */
2577
+ sendPermitCompact(params) {
2578
+ const { permit, invoiceId } = params;
2579
+ return `Permit signed for invoice ${invoiceId}:
2580
+ ${JSON.stringify(permit)}
2581
+ [status:permit_sent invoice=${invoiceId}]`;
2149
2582
  }
2150
2583
  };
2151
2584
  var StatusMarkers = {
2152
2585
  walletReady: "[status:wallet_ready]",
2153
2586
  permitReady: (amount) => `[status:permit_ready USDC=${amount}]`,
2587
+ permitSent: (invoiceId, amount) => `[status:permit_sent invoice=${invoiceId} amount=${amount}]`,
2588
+ awaitingPermit: (invoiceId) => `[status:awaiting_permit invoice=${invoiceId}]`,
2154
2589
  paymentSent: (txHash, amount) => `[status:payment_sent tx=${txHash} amount=${amount} USDC]`,
2155
2590
  paymentConfirmed: (txHash) => `[status:payment_confirmed tx=${txHash}]`,
2156
2591
  delivered: (url, hash) => `[status:delivered url=${url}${hash ? ` hash=${hash}` : ""}]`,
@@ -2170,6 +2605,24 @@ function parseStatusMarker(message) {
2170
2605
  data: { amount: amountMatch?.[1] || "0" }
2171
2606
  };
2172
2607
  }
2608
+ if (content.startsWith("permit_sent")) {
2609
+ const invoiceMatch = content.match(/invoice=(\S+)/);
2610
+ const amountMatch = content.match(/amount=(\d+(?:\.\d+)?)/);
2611
+ return {
2612
+ type: "permit_sent",
2613
+ data: {
2614
+ invoiceId: invoiceMatch?.[1] || "",
2615
+ amount: amountMatch?.[1] || "0"
2616
+ }
2617
+ };
2618
+ }
2619
+ if (content.startsWith("awaiting_permit")) {
2620
+ const invoiceMatch = content.match(/invoice=(\S+)/);
2621
+ return {
2622
+ type: "awaiting_permit",
2623
+ data: { invoiceId: invoiceMatch?.[1] || "" }
2624
+ };
2625
+ }
2173
2626
  if (content.startsWith("payment_sent")) {
2174
2627
  const txMatch = content.match(/tx=(\S+)/);
2175
2628
  const amountMatch = content.match(/amount=(\d+(?:\.\d+)?)/);
@@ -2214,6 +2667,7 @@ function parseStatusMarker(message) {
2214
2667
  }
2215
2668
  // Annotate the CommonJS export names for ESM import in node:
2216
2669
  0 && (module.exports = {
2670
+ AllowanceWallet,
2217
2671
  AuditLog,
2218
2672
  BuyerTemplates,
2219
2673
  CHAINS,
@@ -2222,6 +2676,7 @@ function parseStatusMarker(message) {
2222
2676
  OrderManager,
2223
2677
  PaymentAgent,
2224
2678
  PermitPayment,
2679
+ PermitSigner,
2225
2680
  PermitWallet,
2226
2681
  SecureWallet,
2227
2682
  SellerTemplates,
@@ -2235,6 +2690,7 @@ function parseStatusMarker(message) {
2235
2690
  formatReceiptText,
2236
2691
  generatePaymentGuide,
2237
2692
  generatePaymentReminder,
2693
+ generatePermitInstructions,
2238
2694
  generateReceipt,
2239
2695
  generateReceiptFromInvoice,
2240
2696
  generateWalletGuide,
@@ -2246,6 +2702,7 @@ function parseStatusMarker(message) {
2246
2702
  listChains,
2247
2703
  loadWallet,
2248
2704
  parseStatusMarker,
2705
+ signPermit,
2249
2706
  verifyPayment,
2250
2707
  waitForTransaction,
2251
2708
  walletExists