moltspay 0.9.7 → 1.0.0

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 (43) hide show
  1. package/README.md +42 -3
  2. package/dist/cdp/index.js +1 -1
  3. package/dist/cdp/index.js.map +1 -1
  4. package/dist/cdp/index.mjs +1 -1
  5. package/dist/cdp/index.mjs.map +1 -1
  6. package/dist/chains/index.js +1 -1
  7. package/dist/chains/index.js.map +1 -1
  8. package/dist/chains/index.mjs +1 -1
  9. package/dist/chains/index.mjs.map +1 -1
  10. package/dist/cli/index.js +206 -47
  11. package/dist/cli/index.js.map +1 -1
  12. package/dist/cli/index.mjs +206 -47
  13. package/dist/cli/index.mjs.map +1 -1
  14. package/dist/client/index.d.mts +11 -1
  15. package/dist/client/index.d.ts +11 -1
  16. package/dist/client/index.js +76 -6
  17. package/dist/client/index.js.map +1 -1
  18. package/dist/client/index.mjs +76 -6
  19. package/dist/client/index.mjs.map +1 -1
  20. package/dist/facilitators/index.js +1 -1
  21. package/dist/facilitators/index.js.map +1 -1
  22. package/dist/facilitators/index.mjs +1 -1
  23. package/dist/facilitators/index.mjs.map +1 -1
  24. package/dist/index.js +180 -32
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.mjs +180 -32
  27. package/dist/index.mjs.map +1 -1
  28. package/dist/server/index.d.mts +25 -5
  29. package/dist/server/index.d.ts +25 -5
  30. package/dist/server/index.js +104 -26
  31. package/dist/server/index.js.map +1 -1
  32. package/dist/server/index.mjs +104 -26
  33. package/dist/server/index.mjs.map +1 -1
  34. package/dist/verify/index.js +1 -1
  35. package/dist/verify/index.js.map +1 -1
  36. package/dist/verify/index.mjs +1 -1
  37. package/dist/verify/index.mjs.map +1 -1
  38. package/dist/wallet/index.js +1 -1
  39. package/dist/wallet/index.js.map +1 -1
  40. package/dist/wallet/index.mjs +1 -1
  41. package/dist/wallet/index.mjs.map +1 -1
  42. package/package.json +1 -1
  43. package/schemas/moltspay.services.schema.json +58 -2
@@ -41,7 +41,7 @@ var CHAINS = {
41
41
  polygon: {
42
42
  name: "Polygon",
43
43
  chainId: 137,
44
- rpc: "https://polygon-rpc.com",
44
+ rpc: "https://polygon-bor-rpc.publicnode.com",
45
45
  tokens: {
46
46
  USDC: {
47
47
  address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
@@ -217,10 +217,14 @@ var MoltsPayClient = class {
217
217
  throw new Error("Client not initialized. Run: npx moltspay init");
218
218
  }
219
219
  console.log(`[MoltsPay] Requesting service: ${service}`);
220
+ const requestBody = { service, params };
221
+ if (options.chain) {
222
+ requestBody.chain = options.chain;
223
+ }
220
224
  const initialRes = await fetch(`${serverUrl}/execute`, {
221
225
  method: "POST",
222
226
  headers: { "Content-Type": "application/json" },
223
- body: JSON.stringify({ service, params })
227
+ body: JSON.stringify(requestBody)
224
228
  });
225
229
  if (initialRes.status !== 402) {
226
230
  const data = await initialRes.json();
@@ -247,11 +251,41 @@ var MoltsPayClient = class {
247
251
  } catch {
248
252
  throw new Error("Invalid x-payment-required header");
249
253
  }
250
- const chain = getChain(this.config.chain);
254
+ const networkToChainName = (network2) => {
255
+ const match = network2.match(/^eip155:(\d+)$/);
256
+ if (!match) return null;
257
+ const chainId = parseInt(match[1]);
258
+ if (chainId === 8453) return "base";
259
+ if (chainId === 137) return "polygon";
260
+ if (chainId === 84532) return "base_sepolia";
261
+ return null;
262
+ };
263
+ const serverChains = requirements.map((r) => networkToChainName(r.network)).filter((c) => c !== null);
264
+ let chainName;
265
+ const userSpecifiedChain = options.chain;
266
+ if (userSpecifiedChain) {
267
+ if (!serverChains.includes(userSpecifiedChain)) {
268
+ throw new Error(
269
+ `Server doesn't accept '${userSpecifiedChain}'.
270
+ Server accepts: ${serverChains.join(", ")}`
271
+ );
272
+ }
273
+ chainName = userSpecifiedChain;
274
+ } else {
275
+ if (serverChains.length === 1 && serverChains[0] === "base") {
276
+ chainName = "base";
277
+ } else {
278
+ throw new Error(
279
+ `Server accepts: ${serverChains.join(", ")}
280
+ Please specify: --chain base or --chain polygon`
281
+ );
282
+ }
283
+ }
284
+ const chain = getChain(chainName);
251
285
  const network = `eip155:${chain.chainId}`;
252
286
  const req = requirements.find((r) => r.scheme === "exact" && r.network === network);
253
287
  if (!req) {
254
- throw new Error(`No matching payment option for ${network}`);
288
+ throw new Error(`Failed to find payment requirement for ${chainName}`);
255
289
  }
256
290
  const amountRaw = req.amount || req.maxAmountRequired;
257
291
  if (!amountRaw) {
@@ -304,13 +338,17 @@ var MoltsPayClient = class {
304
338
  };
305
339
  const paymentHeader = Buffer.from(JSON.stringify(payload)).toString("base64");
306
340
  console.log(`[MoltsPay] Sending request with payment...`);
341
+ const paidRequestBody = { service, params };
342
+ if (options.chain) {
343
+ paidRequestBody.chain = options.chain;
344
+ }
307
345
  const paidRes = await fetch(`${serverUrl}/execute`, {
308
346
  method: "POST",
309
347
  headers: {
310
348
  "Content-Type": "application/json",
311
349
  [PAYMENT_HEADER]: paymentHeader
312
350
  },
313
- body: JSON.stringify({ service, params })
351
+ body: JSON.stringify(paidRequestBody)
314
352
  });
315
353
  const result = await paidRes.json();
316
354
  if (!paidRes.ok) {
@@ -479,7 +517,7 @@ var MoltsPayClient = class {
479
517
  return { address: wallet.address, configDir };
480
518
  }
481
519
  /**
482
- * Get wallet balance (USDC, USDT, and native token)
520
+ * Get wallet balance (USDC, USDT, and native token) on default chain
483
521
  */
484
522
  async getBalance() {
485
523
  if (!this.wallet) {
@@ -504,6 +542,38 @@ var MoltsPayClient = class {
504
542
  native: parseFloat(ethers.formatEther(nativeBalance))
505
543
  };
506
544
  }
545
+ /**
546
+ * Get wallet balances on all supported chains (Base + Polygon)
547
+ */
548
+ async getAllBalances() {
549
+ if (!this.wallet) {
550
+ throw new Error("Client not initialized");
551
+ }
552
+ const supportedChains = ["base", "polygon"];
553
+ const tokenAbi = ["function balanceOf(address) view returns (uint256)"];
554
+ const results = {};
555
+ await Promise.all(
556
+ supportedChains.map(async (chainName) => {
557
+ try {
558
+ const chain = getChain(chainName);
559
+ const provider = new ethers.JsonRpcProvider(chain.rpc);
560
+ const [nativeBalance, usdcBalance, usdtBalance] = await Promise.all([
561
+ provider.getBalance(this.wallet.address),
562
+ new ethers.Contract(chain.tokens.USDC.address, tokenAbi, provider).balanceOf(this.wallet.address),
563
+ new ethers.Contract(chain.tokens.USDT.address, tokenAbi, provider).balanceOf(this.wallet.address)
564
+ ]);
565
+ results[chainName] = {
566
+ usdc: parseFloat(ethers.formatUnits(usdcBalance, chain.tokens.USDC.decimals)),
567
+ usdt: parseFloat(ethers.formatUnits(usdtBalance, chain.tokens.USDT.decimals)),
568
+ native: parseFloat(ethers.formatEther(nativeBalance))
569
+ };
570
+ } catch (err) {
571
+ results[chainName] = { usdc: 0, usdt: 0, native: 0 };
572
+ }
573
+ })
574
+ );
575
+ return results;
576
+ }
507
577
  };
508
578
 
509
579
  // src/server/index.ts
@@ -568,7 +638,7 @@ var CDPFacilitator = class extends BaseFacilitator {
568
638
  this.apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;
569
639
  this.apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;
570
640
  this.endpoint = this.useMainnet ? CDP_MAINNET_URL : CDP_TESTNET_URL;
571
- this.supportedNetworks = this.useMainnet ? ["eip155:8453"] : ["eip155:8453", "eip155:84532"];
641
+ this.supportedNetworks = this.useMainnet ? ["eip155:8453", "eip155:137"] : ["eip155:8453", "eip155:84532", "eip155:137"];
572
642
  if (this.useMainnet && (!this.apiKeyId || !this.apiKeySecret)) {
573
643
  console.warn("[CDPFacilitator] WARNING: Mainnet mode but missing CDP credentials!");
574
644
  console.warn("[CDPFacilitator] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET");
@@ -969,8 +1039,17 @@ var TOKEN_ADDRESSES = {
969
1039
  USDC: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
970
1040
  USDT: "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
971
1041
  // Same as USDC on testnet
1042
+ },
1043
+ "eip155:137": {
1044
+ USDC: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
1045
+ USDT: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F"
972
1046
  }
973
1047
  };
1048
+ var CHAIN_TO_NETWORK = {
1049
+ "base": "eip155:8453",
1050
+ "base_sepolia": "eip155:84532",
1051
+ "polygon": "eip155:137"
1052
+ };
974
1053
  var TOKEN_DOMAINS = {
975
1054
  USDC: { name: "USD Coin", version: "2" },
976
1055
  USDT: { name: "Tether USD", version: "2" }
@@ -1036,11 +1115,17 @@ var MoltsPayServer = class {
1036
1115
  };
1037
1116
  this.registry = new FacilitatorRegistry(facilitatorConfig);
1038
1117
  const primaryFacilitator = this.registry.get(facilitatorConfig.primary);
1039
- const networkName = this.useMainnet ? "Base mainnet" : "Base Sepolia (testnet)";
1040
1118
  console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);
1041
1119
  console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);
1042
1120
  console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);
1043
- console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);
1121
+ const chains = this.manifest.provider.chains;
1122
+ if (chains && chains.length > 0) {
1123
+ const chainNames = chains.map((c) => c.chain || c.network).join(", ");
1124
+ console.log(`[MoltsPay] Chains: ${chainNames} (multi-chain enabled)`);
1125
+ } else {
1126
+ const networkName = this.useMainnet ? "Base mainnet" : "Base Sepolia (testnet)";
1127
+ console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);
1128
+ }
1044
1129
  console.log(`[MoltsPay] Facilitator: ${primaryFacilitator.displayName} (${facilitatorConfig.strategy || "failover"})`);
1045
1130
  console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);
1046
1131
  }
@@ -1055,6 +1140,42 @@ var MoltsPayServer = class {
1055
1140
  this.skills.set(serviceId, { id: serviceId, config, handler });
1056
1141
  return this;
1057
1142
  }
1143
+ /**
1144
+ * Get all configured chains for this provider
1145
+ * Returns array of { network, wallet, tokens } for each chain
1146
+ */
1147
+ getProviderChains() {
1148
+ const provider = this.manifest.provider;
1149
+ if (provider.chains && provider.chains.length > 0) {
1150
+ return provider.chains.map((c) => ({
1151
+ network: c.network || CHAIN_TO_NETWORK[c.chain] || "eip155:8453",
1152
+ wallet: c.wallet || provider.wallet,
1153
+ tokens: c.tokens || ["USDC"]
1154
+ }));
1155
+ }
1156
+ const chain = provider.chain || "base";
1157
+ const network = CHAIN_TO_NETWORK[chain] || this.networkId;
1158
+ return [{
1159
+ network,
1160
+ wallet: provider.wallet,
1161
+ tokens: ["USDC"]
1162
+ }];
1163
+ }
1164
+ /**
1165
+ * Get wallet address for a specific network
1166
+ */
1167
+ getWalletForNetwork(network) {
1168
+ const chains = this.getProviderChains();
1169
+ const chain = chains.find((c) => c.network === network);
1170
+ return chain?.wallet || this.manifest.provider.wallet;
1171
+ }
1172
+ /**
1173
+ * Check if a network is accepted by this provider
1174
+ */
1175
+ isNetworkAccepted(network) {
1176
+ const chains = this.getProviderChains();
1177
+ return chains.some((c) => c.network === network);
1178
+ }
1058
1179
  /**
1059
1180
  * Start HTTP server
1060
1181
  */
@@ -1237,7 +1358,9 @@ var MoltsPayServer = class {
1237
1358
  error: `Token ${paymentToken} not accepted. Accepted: ${accepted.join(", ")}`
1238
1359
  });
1239
1360
  }
1240
- const requirements = this.buildPaymentRequirements(skill.config, paymentToken);
1361
+ const paymentNetwork = payment.accepted?.network || payment.network || this.networkId;
1362
+ const paymentWallet = this.getWalletForNetwork(paymentNetwork);
1363
+ const requirements = this.buildPaymentRequirements(skill.config, paymentNetwork, paymentWallet, paymentToken);
1241
1364
  console.log(`[MoltsPay] Verifying payment...`);
1242
1365
  const verifyResult = await this.registry.verify(payment, requirements);
1243
1366
  if (!verifyResult.valid) {
@@ -1292,15 +1415,29 @@ var MoltsPayServer = class {
1292
1415
  }
1293
1416
  /**
1294
1417
  * Return 402 with x402 payment requirements (v2 format)
1295
- * Includes requirements for all accepted currencies
1418
+ * Includes requirements for all chains and all accepted currencies
1296
1419
  */
1297
1420
  sendPaymentRequired(config, res) {
1298
1421
  const acceptedTokens = getAcceptedCurrencies(config);
1299
- const accepts = acceptedTokens.map((token) => this.buildPaymentRequirements(config, token));
1422
+ const providerChains = this.getProviderChains();
1423
+ const accepts = [];
1424
+ for (const chainConfig of providerChains) {
1425
+ for (const token of acceptedTokens) {
1426
+ if (chainConfig.tokens.includes(token)) {
1427
+ accepts.push(this.buildPaymentRequirements(config, chainConfig.network, chainConfig.wallet, token));
1428
+ }
1429
+ }
1430
+ }
1431
+ const acceptedChains = providerChains.map((c) => {
1432
+ if (c.network === "eip155:8453") return "base";
1433
+ if (c.network === "eip155:137") return "polygon";
1434
+ return c.network;
1435
+ });
1300
1436
  const paymentRequired = {
1301
1437
  x402Version: X402_VERSION3,
1302
1438
  accepts,
1303
1439
  acceptedCurrencies: acceptedTokens,
1440
+ acceptedChains,
1304
1441
  resource: {
1305
1442
  url: `/execute?service=${config.id}`,
1306
1443
  description: `${config.name} - $${config.price} ${config.currency}`,
@@ -1316,6 +1453,7 @@ var MoltsPayServer = class {
1316
1453
  error: "Payment required",
1317
1454
  message: `Service requires $${config.price} ${config.currency}`,
1318
1455
  acceptedCurrencies: acceptedTokens,
1456
+ acceptedChains,
1319
1457
  x402: paymentRequired
1320
1458
  }, null, 2));
1321
1459
  }
@@ -1327,46 +1465,50 @@ var MoltsPayServer = class {
1327
1465
  return { valid: false, error: `Unsupported x402 version: ${payment.x402Version}` };
1328
1466
  }
1329
1467
  const scheme = payment.accepted?.scheme || payment.scheme;
1330
- const network = payment.accepted?.network || payment.network;
1468
+ const network = payment.accepted?.network || payment.network || this.networkId;
1331
1469
  if (scheme !== "exact") {
1332
1470
  return { valid: false, error: `Unsupported scheme: ${scheme}` };
1333
1471
  }
1334
- if (network !== this.networkId) {
1335
- return { valid: false, error: `Network mismatch: expected ${this.networkId}, got ${network}` };
1472
+ if (!this.isNetworkAccepted(network)) {
1473
+ const acceptedChains = this.getProviderChains().map((c) => c.network).join(", ");
1474
+ return { valid: false, error: `Network not accepted: ${network}. Accepted: ${acceptedChains}` };
1336
1475
  }
1337
1476
  return { valid: true };
1338
1477
  }
1339
1478
  /**
1340
1479
  * Build payment requirements for facilitator
1341
- * Returns requirements for the primary currency (USDC by default)
1342
- * Server accepts any of the acceptedCurrencies
1480
+ * Now supports multi-chain: takes network and wallet as parameters
1343
1481
  */
1344
- buildPaymentRequirements(config, token) {
1482
+ buildPaymentRequirements(config, network, wallet, token) {
1345
1483
  const amountInUnits = Math.floor(config.price * 1e6).toString();
1346
1484
  const acceptedTokens = getAcceptedCurrencies(config);
1485
+ const selectedNetwork = network || this.networkId;
1486
+ const selectedWallet = wallet || this.manifest.provider.wallet;
1347
1487
  const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
1348
- const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
1488
+ const tokenAddresses = TOKEN_ADDRESSES[selectedNetwork] || {};
1349
1489
  const tokenAddress = tokenAddresses[selectedToken];
1350
1490
  const tokenDomain = TOKEN_DOMAINS[selectedToken] || TOKEN_DOMAINS.USDC;
1351
1491
  return {
1352
1492
  scheme: "exact",
1353
- network: this.networkId,
1493
+ network: selectedNetwork,
1354
1494
  asset: tokenAddress,
1355
1495
  amount: amountInUnits,
1356
- payTo: this.manifest.provider.wallet,
1496
+ payTo: selectedWallet,
1357
1497
  maxTimeoutSeconds: 300,
1358
1498
  extra: tokenDomain
1359
1499
  };
1360
1500
  }
1361
1501
  /**
1362
1502
  * Detect which token is being used in the payment
1503
+ * Checks across all supported networks
1363
1504
  */
1364
1505
  detectPaymentToken(payment) {
1365
1506
  const asset = payment.accepted?.asset || payment.payload?.asset;
1366
1507
  if (!asset) return void 0;
1367
- const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
1508
+ const paymentNetwork = payment.accepted?.network || payment.network || this.networkId;
1509
+ const tokenAddresses = TOKEN_ADDRESSES[paymentNetwork] || {};
1368
1510
  for (const [symbol, address] of Object.entries(tokenAddresses)) {
1369
- if (address.toLowerCase() === asset.toLowerCase()) {
1511
+ if (address && address.toLowerCase() === asset.toLowerCase()) {
1370
1512
  return symbol;
1371
1513
  }
1372
1514
  }
@@ -1441,6 +1583,10 @@ var MoltsPayServer = class {
1441
1583
  if (isNaN(amountNum) || amountNum <= 0) {
1442
1584
  return this.sendJson(res, 400, { error: "Invalid amount" });
1443
1585
  }
1586
+ const supportedChains = ["base", "polygon", "base_sepolia"];
1587
+ if (chain && !supportedChains.includes(chain)) {
1588
+ return this.sendJson(res, 400, { error: `Unsupported chain: ${chain}. Supported: ${supportedChains.join(", ")}` });
1589
+ }
1444
1590
  const proxyConfig = {
1445
1591
  id: serviceId || "proxy",
1446
1592
  name: description || "Proxy Payment",
@@ -1452,9 +1598,9 @@ var MoltsPayServer = class {
1452
1598
  input: {},
1453
1599
  output: {}
1454
1600
  };
1455
- const requirements = this.buildProxyPaymentRequirements(proxyConfig, wallet);
1601
+ const requirements = this.buildProxyPaymentRequirements(proxyConfig, wallet, currency, chain);
1456
1602
  if (!paymentHeader) {
1457
- return this.sendProxyPaymentRequired(proxyConfig, wallet, memo, res);
1603
+ return this.sendProxyPaymentRequired(proxyConfig, wallet, memo, chain, res);
1458
1604
  }
1459
1605
  let payment;
1460
1606
  try {
@@ -1471,8 +1617,9 @@ var MoltsPayServer = class {
1471
1617
  if (scheme !== "exact") {
1472
1618
  return this.sendJson(res, 402, { error: `Unsupported scheme: ${scheme}` });
1473
1619
  }
1474
- if (network !== this.networkId) {
1475
- return this.sendJson(res, 402, { error: `Network mismatch: expected ${this.networkId}, got ${network}` });
1620
+ const expectedNetwork = chain ? CHAIN_TO_NETWORK[chain] || this.networkId : this.networkId;
1621
+ if (network !== expectedNetwork) {
1622
+ return this.sendJson(res, 402, { error: `Network mismatch: expected ${expectedNetwork}, got ${network}` });
1476
1623
  }
1477
1624
  console.log(`[MoltsPay] /proxy: Verifying payment for ${wallet}...`);
1478
1625
  const verifyResult = await this.registry.verify(payment, requirements);
@@ -1578,16 +1725,17 @@ var MoltsPayServer = class {
1578
1725
  /**
1579
1726
  * Build payment requirements for proxy endpoint (uses provided wallet)
1580
1727
  */
1581
- buildProxyPaymentRequirements(config, wallet, token) {
1728
+ buildProxyPaymentRequirements(config, wallet, token, chain) {
1582
1729
  const amountInUnits = Math.floor(config.price * 1e6).toString();
1583
1730
  const acceptedTokens = getAcceptedCurrencies(config);
1731
+ const networkId = chain ? CHAIN_TO_NETWORK[chain] || this.networkId : this.networkId;
1584
1732
  const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
1585
- const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
1733
+ const tokenAddresses = TOKEN_ADDRESSES[networkId] || TOKEN_ADDRESSES[this.networkId] || {};
1586
1734
  const tokenAddress = tokenAddresses[selectedToken];
1587
1735
  const tokenDomain = TOKEN_DOMAINS[selectedToken] || TOKEN_DOMAINS.USDC;
1588
1736
  return {
1589
1737
  scheme: "exact",
1590
- network: this.networkId,
1738
+ network: networkId,
1591
1739
  asset: tokenAddress,
1592
1740
  amount: amountInUnits,
1593
1741
  payTo: wallet,
@@ -1599,8 +1747,8 @@ var MoltsPayServer = class {
1599
1747
  /**
1600
1748
  * Return 402 with x402 payment requirements for proxy endpoint
1601
1749
  */
1602
- sendProxyPaymentRequired(config, wallet, memo, res) {
1603
- const requirements = this.buildProxyPaymentRequirements(config, wallet);
1750
+ sendProxyPaymentRequired(config, wallet, memo, chain, res) {
1751
+ const requirements = this.buildProxyPaymentRequirements(config, wallet, config.currency, chain);
1604
1752
  const paymentRequired = {
1605
1753
  x402Version: X402_VERSION3,
1606
1754
  accepts: [requirements],
@@ -1726,29 +1874,31 @@ program.command("status").description("Show wallet status and balance").option("
1726
1874
  return;
1727
1875
  }
1728
1876
  const config = client.getConfig();
1729
- let balance = { usdc: 0, usdt: 0, native: 0 };
1877
+ let allBalances = {};
1730
1878
  try {
1731
- balance = await client.getBalance();
1879
+ allBalances = await client.getAllBalances();
1732
1880
  } catch (err) {
1733
- console.error("Warning: Could not fetch balance:", err.message);
1881
+ console.error("Warning: Could not fetch balances:", err.message);
1734
1882
  }
1735
1883
  if (options.json) {
1736
1884
  console.log(JSON.stringify({
1737
1885
  address: client.address,
1738
- chain: config.chain,
1739
- balance,
1886
+ balances: allBalances,
1740
1887
  limits: config.limits
1741
1888
  }, null, 2));
1742
1889
  } else {
1743
- console.log("\n\u{1F4CA} MoltsPay Status\n");
1744
- console.log(` Wallet: ${client.address}`);
1745
- console.log(` Chain: ${config.chain}`);
1746
- console.log(` Balance: ${balance.usdc.toFixed(2)} USDC | ${balance.usdt.toFixed(2)} USDT`);
1747
- console.log(` Native: ${balance.native.toFixed(6)} ETH`);
1890
+ console.log("\n\u{1F4CA} MoltsPay Wallet Status\n");
1891
+ console.log(` Address: ${client.address}`);
1892
+ console.log("");
1893
+ console.log(" Balances:");
1894
+ for (const [chainName, balance] of Object.entries(allBalances)) {
1895
+ const chainLabel = chainName.charAt(0).toUpperCase() + chainName.slice(1);
1896
+ console.log(` ${chainLabel.padEnd(10)} ${balance.usdc.toFixed(2)} USDC | ${balance.usdt.toFixed(2)} USDT`);
1897
+ }
1748
1898
  console.log("");
1749
- console.log(" Limits:");
1750
- console.log(` Max per tx: $${config.limits.maxPerTx}`);
1751
- console.log(` Max per day: $${config.limits.maxPerDay}`);
1899
+ console.log(" Spending Limits:");
1900
+ console.log(` Per Transaction: $${config.limits.maxPerTx}`);
1901
+ console.log(` Daily: $${config.limits.maxPerDay}`);
1752
1902
  console.log("");
1753
1903
  }
1754
1904
  });
@@ -1987,7 +2137,7 @@ program.command("stop").description("Stop the running MoltsPay server").action(a
1987
2137
  process.exit(1);
1988
2138
  }
1989
2139
  });
1990
- program.command("pay <server> <service> [params]").description("Pay for a service and get the result").option("--prompt <text>", "Prompt for the service").option("--image <path>", "Image URL or local file path").option("--token <token>", "Token to pay with (USDC or USDT)", "USDC").option("--json", "Output raw JSON only").action(async (server, service, paramsJson, options) => {
2140
+ program.command("pay <server> <service> [params]").description("Pay for a service and get the result").option("--prompt <text>", "Prompt for the service").option("--image <path>", "Image URL or local file path").option("--token <token>", "Token to pay with (USDC or USDT)", "USDC").option("--chain <chain>", "Chain to pay on (base or polygon). Required if server accepts multiple chains.").option("--json", "Output raw JSON only").action(async (server, service, paramsJson, options) => {
1991
2141
  const client = new MoltsPayClient();
1992
2142
  if (!client.isInitialized) {
1993
2143
  console.error("\u274C Wallet not initialized. Run: npx moltspay init");
@@ -2021,6 +2171,11 @@ program.command("pay <server> <service> [params]").description("Pay for a servic
2021
2171
  console.error("\u274C Missing prompt. Use --prompt or pass JSON params");
2022
2172
  process.exit(1);
2023
2173
  }
2174
+ const chain = options.chain?.toLowerCase();
2175
+ if (chain && !["base", "polygon"].includes(chain)) {
2176
+ console.error(`\u274C Unknown chain: ${chain}. Supported: base, polygon`);
2177
+ process.exit(1);
2178
+ }
2024
2179
  const imageDisplay = params.image_url || (params.image_base64 ? `[local file: ${options.image}]` : null);
2025
2180
  const token = (options.token || "USDC").toUpperCase();
2026
2181
  if (token === "USDT") {
@@ -2043,12 +2198,16 @@ program.command("pay <server> <service> [params]").description("Pay for a servic
2043
2198
  console.log(` Service: ${service}`);
2044
2199
  console.log(` Prompt: ${params.prompt}`);
2045
2200
  if (imageDisplay) console.log(` Image: ${imageDisplay}`);
2201
+ console.log(` Chain: ${chain || "(auto)"}`);
2046
2202
  console.log(` Token: ${token}`);
2047
2203
  console.log(` Wallet: ${client.address}`);
2048
2204
  console.log("");
2049
2205
  }
2050
2206
  try {
2051
- const result = await client.pay(server, service, params, { token });
2207
+ const result = await client.pay(server, service, params, {
2208
+ token,
2209
+ chain
2210
+ });
2052
2211
  if (options.json) {
2053
2212
  console.log(JSON.stringify(result));
2054
2213
  } else {