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
@@ -20,7 +20,20 @@ var CHAINS = {
20
20
  name: "Base",
21
21
  chainId: 8453,
22
22
  rpc: "https://mainnet.base.org",
23
+ tokens: {
24
+ USDC: {
25
+ address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
26
+ decimals: 6,
27
+ symbol: "USDC"
28
+ },
29
+ USDT: {
30
+ address: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",
31
+ decimals: 6,
32
+ symbol: "USDT"
33
+ }
34
+ },
23
35
  usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
36
+ // deprecated, for backward compat
24
37
  explorer: "https://basescan.org/address/",
25
38
  explorerTx: "https://basescan.org/tx/",
26
39
  avgBlockTime: 2
@@ -29,6 +42,18 @@ var CHAINS = {
29
42
  name: "Polygon",
30
43
  chainId: 137,
31
44
  rpc: "https://polygon-rpc.com",
45
+ tokens: {
46
+ USDC: {
47
+ address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
48
+ decimals: 6,
49
+ symbol: "USDC"
50
+ },
51
+ USDT: {
52
+ address: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
53
+ decimals: 6,
54
+ symbol: "USDT"
55
+ }
56
+ },
32
57
  usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
33
58
  explorer: "https://polygonscan.com/address/",
34
59
  explorerTx: "https://polygonscan.com/tx/",
@@ -38,6 +63,18 @@ var CHAINS = {
38
63
  name: "Ethereum",
39
64
  chainId: 1,
40
65
  rpc: "https://eth.llamarpc.com",
66
+ tokens: {
67
+ USDC: {
68
+ address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
69
+ decimals: 6,
70
+ symbol: "USDC"
71
+ },
72
+ USDT: {
73
+ address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
74
+ decimals: 6,
75
+ symbol: "USDT"
76
+ }
77
+ },
41
78
  usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
42
79
  explorer: "https://etherscan.io/address/",
43
80
  explorerTx: "https://etherscan.io/tx/",
@@ -48,6 +85,19 @@ var CHAINS = {
48
85
  name: "Base Sepolia",
49
86
  chainId: 84532,
50
87
  rpc: "https://sepolia.base.org",
88
+ tokens: {
89
+ USDC: {
90
+ address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
91
+ decimals: 6,
92
+ symbol: "USDC"
93
+ },
94
+ USDT: {
95
+ address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
96
+ // Same as USDC on testnet (no official USDT)
97
+ decimals: 6,
98
+ symbol: "USDT"
99
+ }
100
+ },
51
101
  usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
52
102
  explorer: "https://sepolia.basescan.org/address/",
53
103
  explorerTx: "https://sepolia.basescan.org/tx/",
@@ -57,6 +107,19 @@ var CHAINS = {
57
107
  name: "Sepolia",
58
108
  chainId: 11155111,
59
109
  rpc: "https://rpc.sepolia.org",
110
+ tokens: {
111
+ USDC: {
112
+ address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
113
+ decimals: 6,
114
+ symbol: "USDC"
115
+ },
116
+ USDT: {
117
+ address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
118
+ // Same as USDC on testnet
119
+ decimals: 6,
120
+ symbol: "USDT"
121
+ }
122
+ },
60
123
  usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
61
124
  explorer: "https://sepolia.etherscan.io/address/",
62
125
  explorerTx: "https://sepolia.etherscan.io/tx/",
@@ -143,8 +206,13 @@ var MoltsPayClient = class {
143
206
  *
144
207
  * This is GASLESS for the client - server pays gas to claim payment.
145
208
  * This is PAY-FOR-SUCCESS - payment only claimed if service succeeds.
209
+ *
210
+ * @param serverUrl - Server URL
211
+ * @param service - Service ID
212
+ * @param params - Service parameters
213
+ * @param options - Payment options (token selection)
146
214
  */
147
- async pay(serverUrl, service, params) {
215
+ async pay(serverUrl, service, params, options = {}) {
148
216
  if (!this.wallet || !this.walletData) {
149
217
  throw new Error("Client not initialized. Run: npx moltspay init");
150
218
  }
@@ -191,12 +259,25 @@ var MoltsPayClient = class {
191
259
  }
192
260
  const amount = Number(amountRaw) / 1e6;
193
261
  this.checkLimits(amount);
194
- console.log(`[MoltsPay] Signing payment: $${amount} USDC (gasless)`);
262
+ let token = options.token || "USDC";
263
+ if (options.autoSelect) {
264
+ const balances = await this.getBalance();
265
+ if (balances.usdc >= amount) {
266
+ token = "USDC";
267
+ } else if (balances.usdt >= amount) {
268
+ token = "USDT";
269
+ } else {
270
+ throw new Error(`Insufficient balance: need $${amount}, have ${balances.usdc} USDC / ${balances.usdt} USDT`);
271
+ }
272
+ }
273
+ console.log(`[MoltsPay] Signing payment: $${amount} ${token} (gasless)`);
195
274
  const payTo = req.payTo || req.resource;
196
275
  if (!payTo) {
197
276
  throw new Error("Missing payTo address in payment requirements");
198
277
  }
199
- const authorization = await this.signEIP3009(payTo, amount, chain);
278
+ const authorization = await this.signEIP3009(payTo, amount, chain, token);
279
+ const tokenConfig = chain.tokens[token];
280
+ const tokenName = token === "USDC" ? "USD Coin" : "Tether USD";
200
281
  const payload = {
201
282
  x402Version: X402_VERSION,
202
283
  payload: authorization,
@@ -204,11 +285,11 @@ var MoltsPayClient = class {
204
285
  accepted: {
205
286
  scheme: "exact",
206
287
  network,
207
- asset: req.asset || chain.usdc,
288
+ asset: tokenConfig.address,
208
289
  amount: amountRaw,
209
290
  payTo,
210
291
  maxTimeoutSeconds: req.maxTimeoutSeconds || 300,
211
- extra: req.extra || { name: "USD Coin", version: "2" }
292
+ extra: req.extra || { name: tokenName, version: "2" }
212
293
  }
213
294
  };
214
295
  const paymentHeader = Buffer.from(JSON.stringify(payload)).toString("base64");
@@ -232,12 +313,14 @@ var MoltsPayClient = class {
232
313
  /**
233
314
  * Sign EIP-3009 transferWithAuthorization (GASLESS)
234
315
  * This only signs - no on-chain transaction, no gas needed.
316
+ * Supports both USDC and USDT.
235
317
  */
236
- async signEIP3009(to, amount, chain) {
318
+ async signEIP3009(to, amount, chain, token = "USDC") {
237
319
  const validAfter = 0;
238
320
  const validBefore = Math.floor(Date.now() / 1e3) + 3600;
239
321
  const nonce = ethers.hexlify(ethers.randomBytes(32));
240
- const value = BigInt(Math.floor(amount * 1e6)).toString();
322
+ const tokenConfig = chain.tokens[token];
323
+ const value = BigInt(Math.floor(amount * 10 ** tokenConfig.decimals)).toString();
241
324
  const authorization = {
242
325
  from: this.wallet.address,
243
326
  to,
@@ -246,11 +329,12 @@ var MoltsPayClient = class {
246
329
  validBefore: validBefore.toString(),
247
330
  nonce
248
331
  };
332
+ const tokenName = token === "USDC" ? "USD Coin" : "Tether USD";
249
333
  const domain = {
250
- name: "USD Coin",
334
+ name: tokenName,
251
335
  version: "2",
252
336
  chainId: chain.chainId,
253
- verifyingContract: chain.usdc
337
+ verifyingContract: tokenConfig.address
254
338
  };
255
339
  const types = {
256
340
  TransferWithAuthorization: [
@@ -385,7 +469,7 @@ var MoltsPayClient = class {
385
469
  return { address: wallet.address, configDir };
386
470
  }
387
471
  /**
388
- * Get wallet balance
472
+ * Get wallet balance (USDC, USDT, and native token)
389
473
  */
390
474
  async getBalance() {
391
475
  if (!this.wallet) {
@@ -398,12 +482,15 @@ var MoltsPayClient = class {
398
482
  throw new Error(`Unknown chain: ${this.config.chain}`);
399
483
  }
400
484
  const provider = new ethers.JsonRpcProvider(chain.rpc);
401
- const nativeBalance = await provider.getBalance(this.wallet.address);
402
- const usdcAbi = ["function balanceOf(address) view returns (uint256)"];
403
- const usdc = new ethers.Contract(chain.usdc, usdcAbi, provider);
404
- const usdcBalance = await usdc.balanceOf(this.wallet.address);
485
+ const tokenAbi = ["function balanceOf(address) view returns (uint256)"];
486
+ const [nativeBalance, usdcBalance, usdtBalance] = await Promise.all([
487
+ provider.getBalance(this.wallet.address),
488
+ new ethers.Contract(chain.tokens.USDC.address, tokenAbi, provider).balanceOf(this.wallet.address),
489
+ new ethers.Contract(chain.tokens.USDT.address, tokenAbi, provider).balanceOf(this.wallet.address)
490
+ ]);
405
491
  return {
406
- usdc: parseFloat(ethers.formatUnits(usdcBalance, 6)),
492
+ usdc: parseFloat(ethers.formatUnits(usdcBalance, chain.tokens.USDC.decimals)),
493
+ usdt: parseFloat(ethers.formatUnits(usdtBalance, chain.tokens.USDT.decimals)),
407
494
  native: parseFloat(ethers.formatEther(nativeBalance))
408
495
  };
409
496
  }
@@ -863,16 +950,24 @@ var X402_VERSION3 = 2;
863
950
  var PAYMENT_REQUIRED_HEADER2 = "x-payment-required";
864
951
  var PAYMENT_HEADER2 = "x-payment";
865
952
  var PAYMENT_RESPONSE_HEADER = "x-payment-response";
866
- var USDC_ADDRESSES = {
867
- "eip155:8453": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
868
- // Base mainnet
869
- "eip155:84532": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
870
- // Base Sepolia
953
+ var TOKEN_ADDRESSES = {
954
+ "eip155:8453": {
955
+ USDC: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
956
+ USDT: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2"
957
+ },
958
+ "eip155:84532": {
959
+ USDC: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
960
+ USDT: "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
961
+ // Same as USDC on testnet
962
+ }
871
963
  };
872
- var USDC_DOMAIN = {
873
- name: "USD Coin",
874
- version: "2"
964
+ var TOKEN_DOMAINS = {
965
+ USDC: { name: "USD Coin", version: "2" },
966
+ USDT: { name: "Tether USD", version: "2" }
875
967
  };
968
+ function getAcceptedCurrencies(config) {
969
+ return config.acceptedCurrencies ?? [config.currency];
970
+ }
876
971
  function loadEnvFile2() {
877
972
  const envPaths = [
878
973
  path2.join(process.cwd(), ".env"),
@@ -984,6 +1079,9 @@ var MoltsPayServer = class {
984
1079
  if (url.pathname === "/services" && req.method === "GET") {
985
1080
  return this.handleGetServices(res);
986
1081
  }
1082
+ if (url.pathname === "/.well-known/agent-services.json" && req.method === "GET") {
1083
+ return this.handleAgentServicesDiscovery(res);
1084
+ }
987
1085
  if (url.pathname === "/health" && req.method === "GET") {
988
1086
  return await this.handleHealthCheck(res);
989
1087
  }
@@ -1007,6 +1105,44 @@ var MoltsPayServer = class {
1007
1105
  this.sendJson(res, 500, { error: err.message || "Internal error" });
1008
1106
  }
1009
1107
  }
1108
+ /**
1109
+ * GET /.well-known/agent-services.json - Standard discovery endpoint
1110
+ */
1111
+ handleAgentServicesDiscovery(res) {
1112
+ const services = this.manifest.services.map((s) => ({
1113
+ id: s.id,
1114
+ name: s.name,
1115
+ description: s.description,
1116
+ price: s.price,
1117
+ currency: s.currency,
1118
+ acceptedCurrencies: getAcceptedCurrencies(s),
1119
+ input: s.input,
1120
+ output: s.output,
1121
+ available: this.skills.has(s.id)
1122
+ }));
1123
+ this.sendJson(res, 200, {
1124
+ version: "1.0",
1125
+ provider: {
1126
+ name: this.manifest.provider.name,
1127
+ description: this.manifest.provider.description,
1128
+ wallet: this.manifest.provider.wallet,
1129
+ chain: this.manifest.provider.chain || "base"
1130
+ },
1131
+ services,
1132
+ endpoints: {
1133
+ services: "/services",
1134
+ execute: "/execute",
1135
+ health: "/health"
1136
+ },
1137
+ payment: {
1138
+ protocol: "x402",
1139
+ version: X402_VERSION3,
1140
+ network: this.networkId,
1141
+ schemes: ["exact"],
1142
+ mainnet: this.useMainnet
1143
+ }
1144
+ });
1145
+ }
1010
1146
  /**
1011
1147
  * GET /services - List available services
1012
1148
  */
@@ -1017,6 +1153,7 @@ var MoltsPayServer = class {
1017
1153
  description: s.description,
1018
1154
  price: s.price,
1019
1155
  currency: s.currency,
1156
+ acceptedCurrencies: getAcceptedCurrencies(s),
1020
1157
  input: s.input,
1021
1158
  output: s.output,
1022
1159
  available: this.skills.has(s.id)
@@ -1083,7 +1220,14 @@ var MoltsPayServer = class {
1083
1220
  if (!validation.valid) {
1084
1221
  return this.sendJson(res, 402, { error: validation.error });
1085
1222
  }
1086
- const requirements = this.buildPaymentRequirements(skill.config);
1223
+ const paymentToken = this.detectPaymentToken(payment);
1224
+ if (paymentToken && !this.isTokenAccepted(skill.config, paymentToken)) {
1225
+ const accepted = getAcceptedCurrencies(skill.config);
1226
+ return this.sendJson(res, 402, {
1227
+ error: `Token ${paymentToken} not accepted. Accepted: ${accepted.join(", ")}`
1228
+ });
1229
+ }
1230
+ const requirements = this.buildPaymentRequirements(skill.config, paymentToken);
1087
1231
  console.log(`[MoltsPay] Verifying payment...`);
1088
1232
  const verifyResult = await this.registry.verify(payment, requirements);
1089
1233
  if (!verifyResult.valid) {
@@ -1093,10 +1237,16 @@ var MoltsPayServer = class {
1093
1237
  });
1094
1238
  }
1095
1239
  console.log(`[MoltsPay] Verified by ${verifyResult.facilitator}`);
1096
- console.log(`[MoltsPay] Executing skill: ${service}`);
1240
+ const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || "1200");
1241
+ console.log(`[MoltsPay] Executing skill: ${service} (timeout: ${timeoutSeconds}s)`);
1097
1242
  let result;
1098
1243
  try {
1099
- result = await skill.handler(params || {});
1244
+ result = await Promise.race([
1245
+ skill.handler(params || {}),
1246
+ new Promise(
1247
+ (_, reject) => setTimeout(() => reject(new Error(`Skill timeout after ${timeoutSeconds}s`)), timeoutSeconds * 1e3)
1248
+ )
1249
+ ]);
1100
1250
  } catch (err) {
1101
1251
  console.error("[MoltsPay] Skill execution failed:", err.message);
1102
1252
  return this.sendJson(res, 500, {
@@ -1132,12 +1282,15 @@ var MoltsPayServer = class {
1132
1282
  }
1133
1283
  /**
1134
1284
  * Return 402 with x402 payment requirements (v2 format)
1285
+ * Includes requirements for all accepted currencies
1135
1286
  */
1136
1287
  sendPaymentRequired(config, res) {
1137
- const requirements = this.buildPaymentRequirements(config);
1288
+ const acceptedTokens = getAcceptedCurrencies(config);
1289
+ const accepts = acceptedTokens.map((token) => this.buildPaymentRequirements(config, token));
1138
1290
  const paymentRequired = {
1139
1291
  x402Version: X402_VERSION3,
1140
- accepts: [requirements],
1292
+ accepts,
1293
+ acceptedCurrencies: acceptedTokens,
1141
1294
  resource: {
1142
1295
  url: `/execute?service=${config.id}`,
1143
1296
  description: `${config.name} - $${config.price} ${config.currency}`,
@@ -1152,6 +1305,7 @@ var MoltsPayServer = class {
1152
1305
  res.end(JSON.stringify({
1153
1306
  error: "Payment required",
1154
1307
  message: `Service requires $${config.price} ${config.currency}`,
1308
+ acceptedCurrencies: acceptedTokens,
1155
1309
  x402: paymentRequired
1156
1310
  }, null, 2));
1157
1311
  }
@@ -1174,20 +1328,47 @@ var MoltsPayServer = class {
1174
1328
  }
1175
1329
  /**
1176
1330
  * Build payment requirements for facilitator
1331
+ * Returns requirements for the primary currency (USDC by default)
1332
+ * Server accepts any of the acceptedCurrencies
1177
1333
  */
1178
- buildPaymentRequirements(config) {
1334
+ buildPaymentRequirements(config, token) {
1179
1335
  const amountInUnits = Math.floor(config.price * 1e6).toString();
1180
- const usdcAddress = USDC_ADDRESSES[this.networkId];
1336
+ const acceptedTokens = getAcceptedCurrencies(config);
1337
+ const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
1338
+ const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
1339
+ const tokenAddress = tokenAddresses[selectedToken];
1340
+ const tokenDomain = TOKEN_DOMAINS[selectedToken] || TOKEN_DOMAINS.USDC;
1181
1341
  return {
1182
1342
  scheme: "exact",
1183
1343
  network: this.networkId,
1184
- asset: usdcAddress,
1344
+ asset: tokenAddress,
1185
1345
  amount: amountInUnits,
1186
1346
  payTo: this.manifest.provider.wallet,
1187
1347
  maxTimeoutSeconds: 300,
1188
- extra: USDC_DOMAIN
1348
+ extra: tokenDomain
1189
1349
  };
1190
1350
  }
1351
+ /**
1352
+ * Detect which token is being used in the payment
1353
+ */
1354
+ detectPaymentToken(payment) {
1355
+ const asset = payment.accepted?.asset || payment.payload?.asset;
1356
+ if (!asset) return void 0;
1357
+ const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
1358
+ for (const [symbol, address] of Object.entries(tokenAddresses)) {
1359
+ if (address.toLowerCase() === asset.toLowerCase()) {
1360
+ return symbol;
1361
+ }
1362
+ }
1363
+ return void 0;
1364
+ }
1365
+ /**
1366
+ * Check if payment token is accepted for service
1367
+ */
1368
+ isTokenAccepted(config, token) {
1369
+ const accepted = getAcceptedCurrencies(config);
1370
+ return accepted.includes(token);
1371
+ }
1191
1372
  async readBody(req) {
1192
1373
  return new Promise((resolve2, reject) => {
1193
1374
  let body = "";
@@ -1305,9 +1486,15 @@ var MoltsPayServer = class {
1305
1486
  error: `Service not found: ${service}`
1306
1487
  });
1307
1488
  }
1489
+ const timeoutSeconds = parseInt(process.env.SKILL_TIMEOUT_SECONDS || "1200");
1308
1490
  let result;
1309
1491
  try {
1310
- result = await skill.handler(params || {});
1492
+ result = await Promise.race([
1493
+ skill.handler(params || {}),
1494
+ new Promise(
1495
+ (_, reject) => setTimeout(() => reject(new Error(`Skill timeout after ${timeoutSeconds}s`)), timeoutSeconds * 1e3)
1496
+ )
1497
+ ]);
1311
1498
  console.log(`[MoltsPay] /proxy: Skill succeeded, now settling payment...`);
1312
1499
  } catch (err) {
1313
1500
  console.error(`[MoltsPay] /proxy: Skill failed: ${err.message} - NOT settling`);
@@ -1381,18 +1568,22 @@ var MoltsPayServer = class {
1381
1568
  /**
1382
1569
  * Build payment requirements for proxy endpoint (uses provided wallet)
1383
1570
  */
1384
- buildProxyPaymentRequirements(config, wallet) {
1571
+ buildProxyPaymentRequirements(config, wallet, token) {
1385
1572
  const amountInUnits = Math.floor(config.price * 1e6).toString();
1386
- const usdcAddress = USDC_ADDRESSES[this.networkId];
1573
+ const acceptedTokens = getAcceptedCurrencies(config);
1574
+ const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
1575
+ const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
1576
+ const tokenAddress = tokenAddresses[selectedToken];
1577
+ const tokenDomain = TOKEN_DOMAINS[selectedToken] || TOKEN_DOMAINS.USDC;
1387
1578
  return {
1388
1579
  scheme: "exact",
1389
1580
  network: this.networkId,
1390
- asset: usdcAddress,
1581
+ asset: tokenAddress,
1391
1582
  amount: amountInUnits,
1392
1583
  payTo: wallet,
1393
1584
  // Use provided wallet, not manifest
1394
1585
  maxTimeoutSeconds: 300,
1395
- extra: USDC_DOMAIN
1586
+ extra: tokenDomain
1396
1587
  };
1397
1588
  }
1398
1589
  /**
@@ -1525,7 +1716,7 @@ program.command("status").description("Show wallet status and balance").option("
1525
1716
  return;
1526
1717
  }
1527
1718
  const config = client.getConfig();
1528
- let balance = { usdc: 0, native: 0 };
1719
+ let balance = { usdc: 0, usdt: 0, native: 0 };
1529
1720
  try {
1530
1721
  balance = await client.getBalance();
1531
1722
  } catch (err) {
@@ -1542,7 +1733,7 @@ program.command("status").description("Show wallet status and balance").option("
1542
1733
  console.log("\n\u{1F4CA} MoltsPay Status\n");
1543
1734
  console.log(` Wallet: ${client.address}`);
1544
1735
  console.log(` Chain: ${config.chain}`);
1545
- console.log(` Balance: ${balance.usdc.toFixed(2)} USDC`);
1736
+ console.log(` Balance: ${balance.usdc.toFixed(2)} USDC | ${balance.usdt.toFixed(2)} USDT`);
1546
1737
  console.log(` Native: ${balance.native.toFixed(6)} ETH`);
1547
1738
  console.log("");
1548
1739
  console.log(" Limits:");
@@ -1786,7 +1977,7 @@ program.command("stop").description("Stop the running MoltsPay server").action(a
1786
1977
  process.exit(1);
1787
1978
  }
1788
1979
  });
1789
- 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("--json", "Output raw JSON only").action(async (server, service, paramsJson, options) => {
1980
+ 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) => {
1790
1981
  const client = new MoltsPayClient();
1791
1982
  if (!client.isInitialized) {
1792
1983
  console.error("\u274C Wallet not initialized. Run: npx moltspay init");
@@ -1821,6 +2012,7 @@ program.command("pay <server> <service> [params]").description("Pay for a servic
1821
2012
  process.exit(1);
1822
2013
  }
1823
2014
  const imageDisplay = params.image_url || (params.image_base64 ? `[local file: ${options.image}]` : null);
2015
+ const token = (options.token || "USDC").toUpperCase();
1824
2016
  if (!options.json) {
1825
2017
  console.log(`
1826
2018
  \u{1F4B3} MoltsPay - Paying for service
@@ -1829,11 +2021,12 @@ program.command("pay <server> <service> [params]").description("Pay for a servic
1829
2021
  console.log(` Service: ${service}`);
1830
2022
  console.log(` Prompt: ${params.prompt}`);
1831
2023
  if (imageDisplay) console.log(` Image: ${imageDisplay}`);
2024
+ console.log(` Token: ${token}`);
1832
2025
  console.log(` Wallet: ${client.address}`);
1833
2026
  console.log("");
1834
2027
  }
1835
2028
  try {
1836
- const result = await client.pay(server, service, params);
2029
+ const result = await client.pay(server, service, params, { token });
1837
2030
  if (options.json) {
1838
2031
  console.log(JSON.stringify(result));
1839
2032
  } else {