moltspay 0.9.3 → 0.9.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.
Files changed (51) hide show
  1. package/.env.example +7 -0
  2. package/dist/cdp/index.d.mts +1 -1
  3. package/dist/cdp/index.d.ts +1 -1
  4. package/dist/cdp/index.js +63 -0
  5. package/dist/cdp/index.js.map +1 -1
  6. package/dist/cdp/index.mjs +63 -0
  7. package/dist/cdp/index.mjs.map +1 -1
  8. package/dist/chains/index.d.mts +9 -5
  9. package/dist/chains/index.d.ts +9 -5
  10. package/dist/chains/index.js +85 -0
  11. package/dist/chains/index.js.map +1 -1
  12. package/dist/chains/index.mjs +83 -0
  13. package/dist/chains/index.mjs.map +1 -1
  14. package/dist/cli/index.js +234 -41
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/cli/index.mjs +234 -41
  17. package/dist/cli/index.mjs.map +1 -1
  18. package/dist/client/index.d.mts +18 -3
  19. package/dist/client/index.d.ts +18 -3
  20. package/dist/client/index.js +102 -15
  21. package/dist/client/index.js.map +1 -1
  22. package/dist/client/index.mjs +102 -15
  23. package/dist/client/index.mjs.map +1 -1
  24. package/dist/{index-Dg8n6wdW.d.mts → index-B3v8IWjM.d.mts} +11 -1
  25. package/dist/{index-Dg8n6wdW.d.ts → index-B3v8IWjM.d.ts} +11 -1
  26. package/dist/index.d.mts +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +248 -45
  29. package/dist/index.js.map +1 -1
  30. package/dist/index.mjs +248 -45
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/server/index.d.mts +23 -1
  33. package/dist/server/index.d.ts +23 -1
  34. package/dist/server/index.js +126 -22
  35. package/dist/server/index.js.map +1 -1
  36. package/dist/server/index.mjs +126 -22
  37. package/dist/server/index.mjs.map +1 -1
  38. package/dist/verify/index.d.mts +7 -0
  39. package/dist/verify/index.d.ts +7 -0
  40. package/dist/verify/index.js +83 -8
  41. package/dist/verify/index.js.map +1 -1
  42. package/dist/verify/index.mjs +83 -8
  43. package/dist/verify/index.mjs.map +1 -1
  44. package/dist/wallet/index.d.mts +16 -8
  45. package/dist/wallet/index.d.ts +16 -8
  46. package/dist/wallet/index.js +114 -18
  47. package/dist/wallet/index.js.map +1 -1
  48. package/dist/wallet/index.mjs +114 -18
  49. package/dist/wallet/index.mjs.map +1 -1
  50. package/package.json +1 -1
  51. package/schemas/moltspay.services.schema.json +13 -3
package/dist/index.mjs CHANGED
@@ -30802,16 +30802,24 @@ var X402_VERSION2 = 2;
30802
30802
  var PAYMENT_REQUIRED_HEADER = "x-payment-required";
30803
30803
  var PAYMENT_HEADER = "x-payment";
30804
30804
  var PAYMENT_RESPONSE_HEADER = "x-payment-response";
30805
- var USDC_ADDRESSES = {
30806
- "eip155:8453": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
30807
- // Base mainnet
30808
- "eip155:84532": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
30809
- // Base Sepolia
30805
+ var TOKEN_ADDRESSES = {
30806
+ "eip155:8453": {
30807
+ USDC: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
30808
+ USDT: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2"
30809
+ },
30810
+ "eip155:84532": {
30811
+ USDC: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
30812
+ USDT: "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
30813
+ // Same as USDC on testnet
30814
+ }
30810
30815
  };
30811
- var USDC_DOMAIN = {
30812
- name: "USD Coin",
30813
- version: "2"
30816
+ var TOKEN_DOMAINS = {
30817
+ USDC: { name: "USD Coin", version: "2" },
30818
+ USDT: { name: "Tether USD", version: "2" }
30814
30819
  };
30820
+ function getAcceptedCurrencies(config) {
30821
+ return config.acceptedCurrencies ?? [config.currency];
30822
+ }
30815
30823
  function loadEnvFile2() {
30816
30824
  const envPaths = [
30817
30825
  path3.join(process.cwd(), ".env"),
@@ -30923,6 +30931,9 @@ var MoltsPayServer = class {
30923
30931
  if (url.pathname === "/services" && req.method === "GET") {
30924
30932
  return this.handleGetServices(res);
30925
30933
  }
30934
+ if (url.pathname === "/.well-known/agent-services.json" && req.method === "GET") {
30935
+ return this.handleAgentServicesDiscovery(res);
30936
+ }
30926
30937
  if (url.pathname === "/health" && req.method === "GET") {
30927
30938
  return await this.handleHealthCheck(res);
30928
30939
  }
@@ -30946,6 +30957,44 @@ var MoltsPayServer = class {
30946
30957
  this.sendJson(res, 500, { error: err.message || "Internal error" });
30947
30958
  }
30948
30959
  }
30960
+ /**
30961
+ * GET /.well-known/agent-services.json - Standard discovery endpoint
30962
+ */
30963
+ handleAgentServicesDiscovery(res) {
30964
+ const services = this.manifest.services.map((s) => ({
30965
+ id: s.id,
30966
+ name: s.name,
30967
+ description: s.description,
30968
+ price: s.price,
30969
+ currency: s.currency,
30970
+ acceptedCurrencies: getAcceptedCurrencies(s),
30971
+ input: s.input,
30972
+ output: s.output,
30973
+ available: this.skills.has(s.id)
30974
+ }));
30975
+ this.sendJson(res, 200, {
30976
+ version: "1.0",
30977
+ provider: {
30978
+ name: this.manifest.provider.name,
30979
+ description: this.manifest.provider.description,
30980
+ wallet: this.manifest.provider.wallet,
30981
+ chain: this.manifest.provider.chain || "base"
30982
+ },
30983
+ services,
30984
+ endpoints: {
30985
+ services: "/services",
30986
+ execute: "/execute",
30987
+ health: "/health"
30988
+ },
30989
+ payment: {
30990
+ protocol: "x402",
30991
+ version: X402_VERSION2,
30992
+ network: this.networkId,
30993
+ schemes: ["exact"],
30994
+ mainnet: this.useMainnet
30995
+ }
30996
+ });
30997
+ }
30949
30998
  /**
30950
30999
  * GET /services - List available services
30951
31000
  */
@@ -30956,6 +31005,7 @@ var MoltsPayServer = class {
30956
31005
  description: s.description,
30957
31006
  price: s.price,
30958
31007
  currency: s.currency,
31008
+ acceptedCurrencies: getAcceptedCurrencies(s),
30959
31009
  input: s.input,
30960
31010
  output: s.output,
30961
31011
  available: this.skills.has(s.id)
@@ -31022,7 +31072,14 @@ var MoltsPayServer = class {
31022
31072
  if (!validation.valid) {
31023
31073
  return this.sendJson(res, 402, { error: validation.error });
31024
31074
  }
31025
- const requirements = this.buildPaymentRequirements(skill.config);
31075
+ const paymentToken = this.detectPaymentToken(payment);
31076
+ if (paymentToken && !this.isTokenAccepted(skill.config, paymentToken)) {
31077
+ const accepted = getAcceptedCurrencies(skill.config);
31078
+ return this.sendJson(res, 402, {
31079
+ error: `Token ${paymentToken} not accepted. Accepted: ${accepted.join(", ")}`
31080
+ });
31081
+ }
31082
+ const requirements = this.buildPaymentRequirements(skill.config, paymentToken);
31026
31083
  console.log(`[MoltsPay] Verifying payment...`);
31027
31084
  const verifyResult = await this.registry.verify(payment, requirements);
31028
31085
  if (!verifyResult.valid) {
@@ -31032,10 +31089,16 @@ var MoltsPayServer = class {
31032
31089
  });
31033
31090
  }
31034
31091
  console.log(`[MoltsPay] Verified by ${verifyResult.facilitator}`);
31035
- console.log(`[MoltsPay] Executing skill: ${service}`);
31092
+ const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || "1200");
31093
+ console.log(`[MoltsPay] Executing skill: ${service} (timeout: ${timeoutSeconds}s)`);
31036
31094
  let result;
31037
31095
  try {
31038
- result = await skill.handler(params || {});
31096
+ result = await Promise.race([
31097
+ skill.handler(params || {}),
31098
+ new Promise(
31099
+ (_, reject) => setTimeout(() => reject(new Error(`Skill timeout after ${timeoutSeconds}s`)), timeoutSeconds * 1e3)
31100
+ )
31101
+ ]);
31039
31102
  } catch (err) {
31040
31103
  console.error("[MoltsPay] Skill execution failed:", err.message);
31041
31104
  return this.sendJson(res, 500, {
@@ -31071,12 +31134,15 @@ var MoltsPayServer = class {
31071
31134
  }
31072
31135
  /**
31073
31136
  * Return 402 with x402 payment requirements (v2 format)
31137
+ * Includes requirements for all accepted currencies
31074
31138
  */
31075
31139
  sendPaymentRequired(config, res) {
31076
- const requirements = this.buildPaymentRequirements(config);
31140
+ const acceptedTokens = getAcceptedCurrencies(config);
31141
+ const accepts = acceptedTokens.map((token) => this.buildPaymentRequirements(config, token));
31077
31142
  const paymentRequired = {
31078
31143
  x402Version: X402_VERSION2,
31079
- accepts: [requirements],
31144
+ accepts,
31145
+ acceptedCurrencies: acceptedTokens,
31080
31146
  resource: {
31081
31147
  url: `/execute?service=${config.id}`,
31082
31148
  description: `${config.name} - $${config.price} ${config.currency}`,
@@ -31091,6 +31157,7 @@ var MoltsPayServer = class {
31091
31157
  res.end(JSON.stringify({
31092
31158
  error: "Payment required",
31093
31159
  message: `Service requires $${config.price} ${config.currency}`,
31160
+ acceptedCurrencies: acceptedTokens,
31094
31161
  x402: paymentRequired
31095
31162
  }, null, 2));
31096
31163
  }
@@ -31113,20 +31180,47 @@ var MoltsPayServer = class {
31113
31180
  }
31114
31181
  /**
31115
31182
  * Build payment requirements for facilitator
31183
+ * Returns requirements for the primary currency (USDC by default)
31184
+ * Server accepts any of the acceptedCurrencies
31116
31185
  */
31117
- buildPaymentRequirements(config) {
31186
+ buildPaymentRequirements(config, token) {
31118
31187
  const amountInUnits = Math.floor(config.price * 1e6).toString();
31119
- const usdcAddress = USDC_ADDRESSES[this.networkId];
31188
+ const acceptedTokens = getAcceptedCurrencies(config);
31189
+ const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
31190
+ const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
31191
+ const tokenAddress = tokenAddresses[selectedToken];
31192
+ const tokenDomain = TOKEN_DOMAINS[selectedToken] || TOKEN_DOMAINS.USDC;
31120
31193
  return {
31121
31194
  scheme: "exact",
31122
31195
  network: this.networkId,
31123
- asset: usdcAddress,
31196
+ asset: tokenAddress,
31124
31197
  amount: amountInUnits,
31125
31198
  payTo: this.manifest.provider.wallet,
31126
31199
  maxTimeoutSeconds: 300,
31127
- extra: USDC_DOMAIN
31200
+ extra: tokenDomain
31128
31201
  };
31129
31202
  }
31203
+ /**
31204
+ * Detect which token is being used in the payment
31205
+ */
31206
+ detectPaymentToken(payment) {
31207
+ const asset = payment.accepted?.asset || payment.payload?.asset;
31208
+ if (!asset) return void 0;
31209
+ const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
31210
+ for (const [symbol, address] of Object.entries(tokenAddresses)) {
31211
+ if (address.toLowerCase() === asset.toLowerCase()) {
31212
+ return symbol;
31213
+ }
31214
+ }
31215
+ return void 0;
31216
+ }
31217
+ /**
31218
+ * Check if payment token is accepted for service
31219
+ */
31220
+ isTokenAccepted(config, token) {
31221
+ const accepted = getAcceptedCurrencies(config);
31222
+ return accepted.includes(token);
31223
+ }
31130
31224
  async readBody(req) {
31131
31225
  return new Promise((resolve, reject) => {
31132
31226
  let body = "";
@@ -31244,9 +31338,15 @@ var MoltsPayServer = class {
31244
31338
  error: `Service not found: ${service}`
31245
31339
  });
31246
31340
  }
31341
+ const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || "1200");
31247
31342
  let result;
31248
31343
  try {
31249
- result = await skill.handler(params || {});
31344
+ result = await Promise.race([
31345
+ skill.handler(params || {}),
31346
+ new Promise(
31347
+ (_, reject) => setTimeout(() => reject(new Error(`Skill timeout after ${timeoutSeconds}s`)), timeoutSeconds * 1e3)
31348
+ )
31349
+ ]);
31250
31350
  console.log(`[MoltsPay] /proxy: Skill succeeded, now settling payment...`);
31251
31351
  } catch (err) {
31252
31352
  console.error(`[MoltsPay] /proxy: Skill failed: ${err.message} - NOT settling`);
@@ -31320,18 +31420,22 @@ var MoltsPayServer = class {
31320
31420
  /**
31321
31421
  * Build payment requirements for proxy endpoint (uses provided wallet)
31322
31422
  */
31323
- buildProxyPaymentRequirements(config, wallet) {
31423
+ buildProxyPaymentRequirements(config, wallet, token) {
31324
31424
  const amountInUnits = Math.floor(config.price * 1e6).toString();
31325
- const usdcAddress = USDC_ADDRESSES[this.networkId];
31425
+ const acceptedTokens = getAcceptedCurrencies(config);
31426
+ const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
31427
+ const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
31428
+ const tokenAddress = tokenAddresses[selectedToken];
31429
+ const tokenDomain = TOKEN_DOMAINS[selectedToken] || TOKEN_DOMAINS.USDC;
31326
31430
  return {
31327
31431
  scheme: "exact",
31328
31432
  network: this.networkId,
31329
- asset: usdcAddress,
31433
+ asset: tokenAddress,
31330
31434
  amount: amountInUnits,
31331
31435
  payTo: wallet,
31332
31436
  // Use provided wallet, not manifest
31333
31437
  maxTimeoutSeconds: 300,
31334
- extra: USDC_DOMAIN
31438
+ extra: tokenDomain
31335
31439
  };
31336
31440
  }
31337
31441
  /**
@@ -31377,7 +31481,20 @@ var CHAINS = {
31377
31481
  name: "Base",
31378
31482
  chainId: 8453,
31379
31483
  rpc: "https://mainnet.base.org",
31484
+ tokens: {
31485
+ USDC: {
31486
+ address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
31487
+ decimals: 6,
31488
+ symbol: "USDC"
31489
+ },
31490
+ USDT: {
31491
+ address: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",
31492
+ decimals: 6,
31493
+ symbol: "USDT"
31494
+ }
31495
+ },
31380
31496
  usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
31497
+ // deprecated, for backward compat
31381
31498
  explorer: "https://basescan.org/address/",
31382
31499
  explorerTx: "https://basescan.org/tx/",
31383
31500
  avgBlockTime: 2
@@ -31386,6 +31503,18 @@ var CHAINS = {
31386
31503
  name: "Polygon",
31387
31504
  chainId: 137,
31388
31505
  rpc: "https://polygon-rpc.com",
31506
+ tokens: {
31507
+ USDC: {
31508
+ address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
31509
+ decimals: 6,
31510
+ symbol: "USDC"
31511
+ },
31512
+ USDT: {
31513
+ address: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
31514
+ decimals: 6,
31515
+ symbol: "USDT"
31516
+ }
31517
+ },
31389
31518
  usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
31390
31519
  explorer: "https://polygonscan.com/address/",
31391
31520
  explorerTx: "https://polygonscan.com/tx/",
@@ -31395,6 +31524,18 @@ var CHAINS = {
31395
31524
  name: "Ethereum",
31396
31525
  chainId: 1,
31397
31526
  rpc: "https://eth.llamarpc.com",
31527
+ tokens: {
31528
+ USDC: {
31529
+ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
31530
+ decimals: 6,
31531
+ symbol: "USDC"
31532
+ },
31533
+ USDT: {
31534
+ address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
31535
+ decimals: 6,
31536
+ symbol: "USDT"
31537
+ }
31538
+ },
31398
31539
  usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
31399
31540
  explorer: "https://etherscan.io/address/",
31400
31541
  explorerTx: "https://etherscan.io/tx/",
@@ -31405,6 +31546,19 @@ var CHAINS = {
31405
31546
  name: "Base Sepolia",
31406
31547
  chainId: 84532,
31407
31548
  rpc: "https://sepolia.base.org",
31549
+ tokens: {
31550
+ USDC: {
31551
+ address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
31552
+ decimals: 6,
31553
+ symbol: "USDC"
31554
+ },
31555
+ USDT: {
31556
+ address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
31557
+ // Same as USDC on testnet (no official USDT)
31558
+ decimals: 6,
31559
+ symbol: "USDT"
31560
+ }
31561
+ },
31408
31562
  usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
31409
31563
  explorer: "https://sepolia.basescan.org/address/",
31410
31564
  explorerTx: "https://sepolia.basescan.org/tx/",
@@ -31414,6 +31568,19 @@ var CHAINS = {
31414
31568
  name: "Sepolia",
31415
31569
  chainId: 11155111,
31416
31570
  rpc: "https://rpc.sepolia.org",
31571
+ tokens: {
31572
+ USDC: {
31573
+ address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
31574
+ decimals: 6,
31575
+ symbol: "USDC"
31576
+ },
31577
+ USDT: {
31578
+ address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
31579
+ // Same as USDC on testnet
31580
+ decimals: 6,
31581
+ symbol: "USDT"
31582
+ }
31583
+ },
31417
31584
  usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
31418
31585
  explorer: "https://sepolia.etherscan.io/address/",
31419
31586
  explorerTx: "https://sepolia.etherscan.io/tx/",
@@ -31522,8 +31689,13 @@ var MoltsPayClient = class {
31522
31689
  *
31523
31690
  * This is GASLESS for the client - server pays gas to claim payment.
31524
31691
  * This is PAY-FOR-SUCCESS - payment only claimed if service succeeds.
31692
+ *
31693
+ * @param serverUrl - Server URL
31694
+ * @param service - Service ID
31695
+ * @param params - Service parameters
31696
+ * @param options - Payment options (token selection)
31525
31697
  */
31526
- async pay(serverUrl, service, params) {
31698
+ async pay(serverUrl, service, params, options = {}) {
31527
31699
  if (!this.wallet || !this.walletData) {
31528
31700
  throw new Error("Client not initialized. Run: npx moltspay init");
31529
31701
  }
@@ -31570,12 +31742,25 @@ var MoltsPayClient = class {
31570
31742
  }
31571
31743
  const amount = Number(amountRaw) / 1e6;
31572
31744
  this.checkLimits(amount);
31573
- console.log(`[MoltsPay] Signing payment: $${amount} USDC (gasless)`);
31745
+ let token = options.token || "USDC";
31746
+ if (options.autoSelect) {
31747
+ const balances = await this.getBalance();
31748
+ if (balances.usdc >= amount) {
31749
+ token = "USDC";
31750
+ } else if (balances.usdt >= amount) {
31751
+ token = "USDT";
31752
+ } else {
31753
+ throw new Error(`Insufficient balance: need $${amount}, have ${balances.usdc} USDC / ${balances.usdt} USDT`);
31754
+ }
31755
+ }
31756
+ console.log(`[MoltsPay] Signing payment: $${amount} ${token} (gasless)`);
31574
31757
  const payTo = req.payTo || req.resource;
31575
31758
  if (!payTo) {
31576
31759
  throw new Error("Missing payTo address in payment requirements");
31577
31760
  }
31578
- const authorization = await this.signEIP3009(payTo, amount, chain2);
31761
+ const authorization = await this.signEIP3009(payTo, amount, chain2, token);
31762
+ const tokenConfig = chain2.tokens[token];
31763
+ const tokenName = token === "USDC" ? "USD Coin" : "Tether USD";
31579
31764
  const payload = {
31580
31765
  x402Version: X402_VERSION3,
31581
31766
  payload: authorization,
@@ -31583,11 +31768,11 @@ var MoltsPayClient = class {
31583
31768
  accepted: {
31584
31769
  scheme: "exact",
31585
31770
  network,
31586
- asset: req.asset || chain2.usdc,
31771
+ asset: tokenConfig.address,
31587
31772
  amount: amountRaw,
31588
31773
  payTo,
31589
31774
  maxTimeoutSeconds: req.maxTimeoutSeconds || 300,
31590
- extra: req.extra || { name: "USD Coin", version: "2" }
31775
+ extra: req.extra || { name: tokenName, version: "2" }
31591
31776
  }
31592
31777
  };
31593
31778
  const paymentHeader = Buffer.from(JSON.stringify(payload)).toString("base64");
@@ -31611,12 +31796,14 @@ var MoltsPayClient = class {
31611
31796
  /**
31612
31797
  * Sign EIP-3009 transferWithAuthorization (GASLESS)
31613
31798
  * This only signs - no on-chain transaction, no gas needed.
31799
+ * Supports both USDC and USDT.
31614
31800
  */
31615
- async signEIP3009(to, amount, chain2) {
31801
+ async signEIP3009(to, amount, chain2, token = "USDC") {
31616
31802
  const validAfter = 0;
31617
31803
  const validBefore = Math.floor(Date.now() / 1e3) + 3600;
31618
31804
  const nonce = ethers.hexlify(ethers.randomBytes(32));
31619
- const value = BigInt(Math.floor(amount * 1e6)).toString();
31805
+ const tokenConfig = chain2.tokens[token];
31806
+ const value = BigInt(Math.floor(amount * 10 ** tokenConfig.decimals)).toString();
31620
31807
  const authorization = {
31621
31808
  from: this.wallet.address,
31622
31809
  to,
@@ -31625,11 +31812,12 @@ var MoltsPayClient = class {
31625
31812
  validBefore: validBefore.toString(),
31626
31813
  nonce
31627
31814
  };
31815
+ const tokenName = token === "USDC" ? "USD Coin" : "Tether USD";
31628
31816
  const domain = {
31629
- name: "USD Coin",
31817
+ name: tokenName,
31630
31818
  version: "2",
31631
31819
  chainId: chain2.chainId,
31632
- verifyingContract: chain2.usdc
31820
+ verifyingContract: tokenConfig.address
31633
31821
  };
31634
31822
  const types = {
31635
31823
  TransferWithAuthorization: [
@@ -31764,7 +31952,7 @@ var MoltsPayClient = class {
31764
31952
  return { address: wallet.address, configDir };
31765
31953
  }
31766
31954
  /**
31767
- * Get wallet balance
31955
+ * Get wallet balance (USDC, USDT, and native token)
31768
31956
  */
31769
31957
  async getBalance() {
31770
31958
  if (!this.wallet) {
@@ -31777,12 +31965,15 @@ var MoltsPayClient = class {
31777
31965
  throw new Error(`Unknown chain: ${this.config.chain}`);
31778
31966
  }
31779
31967
  const provider = new ethers.JsonRpcProvider(chain2.rpc);
31780
- const nativeBalance = await provider.getBalance(this.wallet.address);
31781
- const usdcAbi = ["function balanceOf(address) view returns (uint256)"];
31782
- const usdc = new ethers.Contract(chain2.usdc, usdcAbi, provider);
31783
- const usdcBalance = await usdc.balanceOf(this.wallet.address);
31968
+ const tokenAbi = ["function balanceOf(address) view returns (uint256)"];
31969
+ const [nativeBalance, usdcBalance, usdtBalance] = await Promise.all([
31970
+ provider.getBalance(this.wallet.address),
31971
+ new ethers.Contract(chain2.tokens.USDC.address, tokenAbi, provider).balanceOf(this.wallet.address),
31972
+ new ethers.Contract(chain2.tokens.USDT.address, tokenAbi, provider).balanceOf(this.wallet.address)
31973
+ ]);
31784
31974
  return {
31785
- usdc: parseFloat(ethers.formatUnits(usdcBalance, 6)),
31975
+ usdc: parseFloat(ethers.formatUnits(usdcBalance, chain2.tokens.USDC.decimals)),
31976
+ usdt: parseFloat(ethers.formatUnits(usdtBalance, chain2.tokens.USDT.decimals)),
31786
31977
  native: parseFloat(ethers.formatEther(nativeBalance))
31787
31978
  };
31788
31979
  }
@@ -31918,7 +32109,7 @@ init_esm_shims();
31918
32109
  import { ethers as ethers4 } from "ethers";
31919
32110
  var TRANSFER_EVENT_TOPIC = ethers4.id("Transfer(address,address,uint256)");
31920
32111
  async function verifyPayment(params) {
31921
- const { txHash, expectedAmount, expectedTo } = params;
32112
+ const { txHash, expectedAmount, expectedTo, expectedToken } = params;
31922
32113
  let chain2;
31923
32114
  try {
31924
32115
  if (typeof params.chain === "number") {
@@ -31941,12 +32132,20 @@ async function verifyPayment(params) {
31941
32132
  if (receipt.status !== 1) {
31942
32133
  return { verified: false, error: "Transaction failed" };
31943
32134
  }
31944
- const usdcAddress = chain2.usdc?.toLowerCase();
31945
- if (!usdcAddress) {
31946
- return { verified: false, error: `Chain ${chain2.name} USDC address not configured` };
32135
+ const tokenAddresses = {};
32136
+ if (!expectedToken || expectedToken === "USDC") {
32137
+ tokenAddresses[chain2.tokens.USDC.address.toLowerCase()] = "USDC";
32138
+ }
32139
+ if (!expectedToken || expectedToken === "USDT") {
32140
+ tokenAddresses[chain2.tokens.USDT.address.toLowerCase()] = "USDT";
32141
+ }
32142
+ if (Object.keys(tokenAddresses).length === 0) {
32143
+ return { verified: false, error: `No token addresses configured for ${chain2.name}` };
31947
32144
  }
31948
32145
  for (const log of receipt.logs) {
31949
- if (log.address.toLowerCase() !== usdcAddress) {
32146
+ const logAddress = log.address.toLowerCase();
32147
+ const detectedToken = tokenAddresses[logAddress];
32148
+ if (!detectedToken) {
31950
32149
  continue;
31951
32150
  }
31952
32151
  if (log.topics.length < 3 || log.topics[0] !== TRANSFER_EVENT_TOPIC) {
@@ -31955,15 +32154,17 @@ async function verifyPayment(params) {
31955
32154
  const from = "0x" + log.topics[1].slice(-40);
31956
32155
  const to = "0x" + log.topics[2].slice(-40);
31957
32156
  const amountRaw = BigInt(log.data);
31958
- const amount = Number(amountRaw) / 1e6;
32157
+ const tokenConfig = chain2.tokens[detectedToken];
32158
+ const amount = Number(amountRaw) / 10 ** tokenConfig.decimals;
31959
32159
  if (expectedTo && to.toLowerCase() !== expectedTo.toLowerCase()) {
31960
32160
  continue;
31961
32161
  }
31962
32162
  if (amount < expectedAmount) {
31963
32163
  return {
31964
32164
  verified: false,
31965
- error: `Insufficient amount: received ${amount} USDC, expected ${expectedAmount} USDC`,
32165
+ error: `Insufficient amount: received ${amount} ${detectedToken}, expected ${expectedAmount}`,
31966
32166
  amount,
32167
+ token: detectedToken,
31967
32168
  from,
31968
32169
  to,
31969
32170
  txHash,
@@ -31973,13 +32174,15 @@ async function verifyPayment(params) {
31973
32174
  return {
31974
32175
  verified: true,
31975
32176
  amount,
32177
+ token: detectedToken,
31976
32178
  from,
31977
32179
  to,
31978
32180
  txHash,
31979
32181
  blockNumber: receipt.blockNumber
31980
32182
  };
31981
32183
  }
31982
- return { verified: false, error: "No USDC transfer found" };
32184
+ const tokenList = expectedToken ? expectedToken : "USDC/USDT";
32185
+ return { verified: false, error: `No ${tokenList} transfer found` };
31983
32186
  } catch (e) {
31984
32187
  return { verified: false, error: e.message || String(e) };
31985
32188
  }