moltspay 0.9.5 → 0.9.7
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/README.md +68 -45
- package/dist/cdp/index.d.mts +1 -1
- package/dist/cdp/index.d.ts +1 -1
- package/dist/cdp/index.js +63 -0
- package/dist/cdp/index.js.map +1 -1
- package/dist/cdp/index.mjs +63 -0
- package/dist/cdp/index.mjs.map +1 -1
- package/dist/chains/index.d.mts +9 -5
- package/dist/chains/index.d.ts +9 -5
- package/dist/chains/index.js +85 -0
- package/dist/chains/index.js.map +1 -1
- package/dist/chains/index.mjs +83 -0
- package/dist/chains/index.mjs.map +1 -1
- package/dist/cli/index.js +201 -38
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +201 -38
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/index.d.mts +18 -3
- package/dist/client/index.d.ts +18 -3
- package/dist/client/index.js +112 -15
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +112 -15
- package/dist/client/index.mjs.map +1 -1
- package/dist/{index-Dg8n6wdW.d.mts → index-B3v8IWjM.d.mts} +11 -1
- package/dist/{index-Dg8n6wdW.d.ts → index-B3v8IWjM.d.ts} +11 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +203 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +203 -42
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.d.mts +19 -1
- package/dist/server/index.d.ts +19 -1
- package/dist/server/index.js +71 -19
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +71 -19
- package/dist/server/index.mjs.map +1 -1
- package/dist/verify/index.d.mts +7 -0
- package/dist/verify/index.d.ts +7 -0
- package/dist/verify/index.js +83 -8
- package/dist/verify/index.js.map +1 -1
- package/dist/verify/index.mjs +83 -8
- package/dist/verify/index.mjs.map +1 -1
- package/dist/wallet/index.d.mts +16 -8
- package/dist/wallet/index.d.ts +16 -8
- package/dist/wallet/index.js +114 -18
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +114 -18
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
- package/schemas/moltspay.services.schema.json +13 -3
package/dist/cli/index.mjs
CHANGED
|
@@ -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,35 @@ var MoltsPayClient = class {
|
|
|
191
259
|
}
|
|
192
260
|
const amount = Number(amountRaw) / 1e6;
|
|
193
261
|
this.checkLimits(amount);
|
|
194
|
-
|
|
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
|
+
if (token === "USDT") {
|
|
274
|
+
const balances = await this.getBalance();
|
|
275
|
+
if (balances.native < 1e-4) {
|
|
276
|
+
throw new Error(
|
|
277
|
+
`USDT requires ETH for gas (~$0.01 on Base). Your ETH balance: ${balances.native.toFixed(6)} ETH. Please add a small amount of ETH to your wallet, or use USDC (gasless).`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
console.log(`[MoltsPay] \u26A0\uFE0F USDT requires gas (~$0.01). Proceeding with payment...`);
|
|
281
|
+
} else {
|
|
282
|
+
console.log(`[MoltsPay] Signing payment: $${amount} ${token} (gasless)`);
|
|
283
|
+
}
|
|
195
284
|
const payTo = req.payTo || req.resource;
|
|
196
285
|
if (!payTo) {
|
|
197
286
|
throw new Error("Missing payTo address in payment requirements");
|
|
198
287
|
}
|
|
199
|
-
const authorization = await this.signEIP3009(payTo, amount, chain);
|
|
288
|
+
const authorization = await this.signEIP3009(payTo, amount, chain, token);
|
|
289
|
+
const tokenConfig = chain.tokens[token];
|
|
290
|
+
const tokenName = token === "USDC" ? "USD Coin" : "Tether USD";
|
|
200
291
|
const payload = {
|
|
201
292
|
x402Version: X402_VERSION,
|
|
202
293
|
payload: authorization,
|
|
@@ -204,11 +295,11 @@ var MoltsPayClient = class {
|
|
|
204
295
|
accepted: {
|
|
205
296
|
scheme: "exact",
|
|
206
297
|
network,
|
|
207
|
-
asset:
|
|
298
|
+
asset: tokenConfig.address,
|
|
208
299
|
amount: amountRaw,
|
|
209
300
|
payTo,
|
|
210
301
|
maxTimeoutSeconds: req.maxTimeoutSeconds || 300,
|
|
211
|
-
extra: req.extra || { name:
|
|
302
|
+
extra: req.extra || { name: tokenName, version: "2" }
|
|
212
303
|
}
|
|
213
304
|
};
|
|
214
305
|
const paymentHeader = Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
@@ -232,12 +323,14 @@ var MoltsPayClient = class {
|
|
|
232
323
|
/**
|
|
233
324
|
* Sign EIP-3009 transferWithAuthorization (GASLESS)
|
|
234
325
|
* This only signs - no on-chain transaction, no gas needed.
|
|
326
|
+
* Supports both USDC and USDT.
|
|
235
327
|
*/
|
|
236
|
-
async signEIP3009(to, amount, chain) {
|
|
328
|
+
async signEIP3009(to, amount, chain, token = "USDC") {
|
|
237
329
|
const validAfter = 0;
|
|
238
330
|
const validBefore = Math.floor(Date.now() / 1e3) + 3600;
|
|
239
331
|
const nonce = ethers.hexlify(ethers.randomBytes(32));
|
|
240
|
-
const
|
|
332
|
+
const tokenConfig = chain.tokens[token];
|
|
333
|
+
const value = BigInt(Math.floor(amount * 10 ** tokenConfig.decimals)).toString();
|
|
241
334
|
const authorization = {
|
|
242
335
|
from: this.wallet.address,
|
|
243
336
|
to,
|
|
@@ -246,11 +339,12 @@ var MoltsPayClient = class {
|
|
|
246
339
|
validBefore: validBefore.toString(),
|
|
247
340
|
nonce
|
|
248
341
|
};
|
|
342
|
+
const tokenName = token === "USDC" ? "USD Coin" : "Tether USD";
|
|
249
343
|
const domain = {
|
|
250
|
-
name:
|
|
344
|
+
name: tokenName,
|
|
251
345
|
version: "2",
|
|
252
346
|
chainId: chain.chainId,
|
|
253
|
-
verifyingContract:
|
|
347
|
+
verifyingContract: tokenConfig.address
|
|
254
348
|
};
|
|
255
349
|
const types = {
|
|
256
350
|
TransferWithAuthorization: [
|
|
@@ -385,7 +479,7 @@ var MoltsPayClient = class {
|
|
|
385
479
|
return { address: wallet.address, configDir };
|
|
386
480
|
}
|
|
387
481
|
/**
|
|
388
|
-
* Get wallet balance
|
|
482
|
+
* Get wallet balance (USDC, USDT, and native token)
|
|
389
483
|
*/
|
|
390
484
|
async getBalance() {
|
|
391
485
|
if (!this.wallet) {
|
|
@@ -398,12 +492,15 @@ var MoltsPayClient = class {
|
|
|
398
492
|
throw new Error(`Unknown chain: ${this.config.chain}`);
|
|
399
493
|
}
|
|
400
494
|
const provider = new ethers.JsonRpcProvider(chain.rpc);
|
|
401
|
-
const
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
|
|
495
|
+
const tokenAbi = ["function balanceOf(address) view returns (uint256)"];
|
|
496
|
+
const [nativeBalance, usdcBalance, usdtBalance] = await Promise.all([
|
|
497
|
+
provider.getBalance(this.wallet.address),
|
|
498
|
+
new ethers.Contract(chain.tokens.USDC.address, tokenAbi, provider).balanceOf(this.wallet.address),
|
|
499
|
+
new ethers.Contract(chain.tokens.USDT.address, tokenAbi, provider).balanceOf(this.wallet.address)
|
|
500
|
+
]);
|
|
405
501
|
return {
|
|
406
|
-
usdc: parseFloat(ethers.formatUnits(usdcBalance,
|
|
502
|
+
usdc: parseFloat(ethers.formatUnits(usdcBalance, chain.tokens.USDC.decimals)),
|
|
503
|
+
usdt: parseFloat(ethers.formatUnits(usdtBalance, chain.tokens.USDT.decimals)),
|
|
407
504
|
native: parseFloat(ethers.formatEther(nativeBalance))
|
|
408
505
|
};
|
|
409
506
|
}
|
|
@@ -863,16 +960,24 @@ var X402_VERSION3 = 2;
|
|
|
863
960
|
var PAYMENT_REQUIRED_HEADER2 = "x-payment-required";
|
|
864
961
|
var PAYMENT_HEADER2 = "x-payment";
|
|
865
962
|
var PAYMENT_RESPONSE_HEADER = "x-payment-response";
|
|
866
|
-
var
|
|
867
|
-
"eip155:8453":
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
963
|
+
var TOKEN_ADDRESSES = {
|
|
964
|
+
"eip155:8453": {
|
|
965
|
+
USDC: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
966
|
+
USDT: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2"
|
|
967
|
+
},
|
|
968
|
+
"eip155:84532": {
|
|
969
|
+
USDC: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
970
|
+
USDT: "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
|
|
971
|
+
// Same as USDC on testnet
|
|
972
|
+
}
|
|
871
973
|
};
|
|
872
|
-
var
|
|
873
|
-
name: "USD Coin",
|
|
874
|
-
version: "2"
|
|
974
|
+
var TOKEN_DOMAINS = {
|
|
975
|
+
USDC: { name: "USD Coin", version: "2" },
|
|
976
|
+
USDT: { name: "Tether USD", version: "2" }
|
|
875
977
|
};
|
|
978
|
+
function getAcceptedCurrencies(config) {
|
|
979
|
+
return config.acceptedCurrencies ?? [config.currency];
|
|
980
|
+
}
|
|
876
981
|
function loadEnvFile2() {
|
|
877
982
|
const envPaths = [
|
|
878
983
|
path2.join(process.cwd(), ".env"),
|
|
@@ -1020,6 +1125,7 @@ var MoltsPayServer = class {
|
|
|
1020
1125
|
description: s.description,
|
|
1021
1126
|
price: s.price,
|
|
1022
1127
|
currency: s.currency,
|
|
1128
|
+
acceptedCurrencies: getAcceptedCurrencies(s),
|
|
1023
1129
|
input: s.input,
|
|
1024
1130
|
output: s.output,
|
|
1025
1131
|
available: this.skills.has(s.id)
|
|
@@ -1057,6 +1163,7 @@ var MoltsPayServer = class {
|
|
|
1057
1163
|
description: s.description,
|
|
1058
1164
|
price: s.price,
|
|
1059
1165
|
currency: s.currency,
|
|
1166
|
+
acceptedCurrencies: getAcceptedCurrencies(s),
|
|
1060
1167
|
input: s.input,
|
|
1061
1168
|
output: s.output,
|
|
1062
1169
|
available: this.skills.has(s.id)
|
|
@@ -1123,7 +1230,14 @@ var MoltsPayServer = class {
|
|
|
1123
1230
|
if (!validation.valid) {
|
|
1124
1231
|
return this.sendJson(res, 402, { error: validation.error });
|
|
1125
1232
|
}
|
|
1126
|
-
const
|
|
1233
|
+
const paymentToken = this.detectPaymentToken(payment);
|
|
1234
|
+
if (paymentToken && !this.isTokenAccepted(skill.config, paymentToken)) {
|
|
1235
|
+
const accepted = getAcceptedCurrencies(skill.config);
|
|
1236
|
+
return this.sendJson(res, 402, {
|
|
1237
|
+
error: `Token ${paymentToken} not accepted. Accepted: ${accepted.join(", ")}`
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
const requirements = this.buildPaymentRequirements(skill.config, paymentToken);
|
|
1127
1241
|
console.log(`[MoltsPay] Verifying payment...`);
|
|
1128
1242
|
const verifyResult = await this.registry.verify(payment, requirements);
|
|
1129
1243
|
if (!verifyResult.valid) {
|
|
@@ -1178,12 +1292,15 @@ var MoltsPayServer = class {
|
|
|
1178
1292
|
}
|
|
1179
1293
|
/**
|
|
1180
1294
|
* Return 402 with x402 payment requirements (v2 format)
|
|
1295
|
+
* Includes requirements for all accepted currencies
|
|
1181
1296
|
*/
|
|
1182
1297
|
sendPaymentRequired(config, res) {
|
|
1183
|
-
const
|
|
1298
|
+
const acceptedTokens = getAcceptedCurrencies(config);
|
|
1299
|
+
const accepts = acceptedTokens.map((token) => this.buildPaymentRequirements(config, token));
|
|
1184
1300
|
const paymentRequired = {
|
|
1185
1301
|
x402Version: X402_VERSION3,
|
|
1186
|
-
accepts
|
|
1302
|
+
accepts,
|
|
1303
|
+
acceptedCurrencies: acceptedTokens,
|
|
1187
1304
|
resource: {
|
|
1188
1305
|
url: `/execute?service=${config.id}`,
|
|
1189
1306
|
description: `${config.name} - $${config.price} ${config.currency}`,
|
|
@@ -1198,6 +1315,7 @@ var MoltsPayServer = class {
|
|
|
1198
1315
|
res.end(JSON.stringify({
|
|
1199
1316
|
error: "Payment required",
|
|
1200
1317
|
message: `Service requires $${config.price} ${config.currency}`,
|
|
1318
|
+
acceptedCurrencies: acceptedTokens,
|
|
1201
1319
|
x402: paymentRequired
|
|
1202
1320
|
}, null, 2));
|
|
1203
1321
|
}
|
|
@@ -1220,20 +1338,47 @@ var MoltsPayServer = class {
|
|
|
1220
1338
|
}
|
|
1221
1339
|
/**
|
|
1222
1340
|
* Build payment requirements for facilitator
|
|
1341
|
+
* Returns requirements for the primary currency (USDC by default)
|
|
1342
|
+
* Server accepts any of the acceptedCurrencies
|
|
1223
1343
|
*/
|
|
1224
|
-
buildPaymentRequirements(config) {
|
|
1344
|
+
buildPaymentRequirements(config, token) {
|
|
1225
1345
|
const amountInUnits = Math.floor(config.price * 1e6).toString();
|
|
1226
|
-
const
|
|
1346
|
+
const acceptedTokens = getAcceptedCurrencies(config);
|
|
1347
|
+
const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
|
|
1348
|
+
const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
|
|
1349
|
+
const tokenAddress = tokenAddresses[selectedToken];
|
|
1350
|
+
const tokenDomain = TOKEN_DOMAINS[selectedToken] || TOKEN_DOMAINS.USDC;
|
|
1227
1351
|
return {
|
|
1228
1352
|
scheme: "exact",
|
|
1229
1353
|
network: this.networkId,
|
|
1230
|
-
asset:
|
|
1354
|
+
asset: tokenAddress,
|
|
1231
1355
|
amount: amountInUnits,
|
|
1232
1356
|
payTo: this.manifest.provider.wallet,
|
|
1233
1357
|
maxTimeoutSeconds: 300,
|
|
1234
|
-
extra:
|
|
1358
|
+
extra: tokenDomain
|
|
1235
1359
|
};
|
|
1236
1360
|
}
|
|
1361
|
+
/**
|
|
1362
|
+
* Detect which token is being used in the payment
|
|
1363
|
+
*/
|
|
1364
|
+
detectPaymentToken(payment) {
|
|
1365
|
+
const asset = payment.accepted?.asset || payment.payload?.asset;
|
|
1366
|
+
if (!asset) return void 0;
|
|
1367
|
+
const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
|
|
1368
|
+
for (const [symbol, address] of Object.entries(tokenAddresses)) {
|
|
1369
|
+
if (address.toLowerCase() === asset.toLowerCase()) {
|
|
1370
|
+
return symbol;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
return void 0;
|
|
1374
|
+
}
|
|
1375
|
+
/**
|
|
1376
|
+
* Check if payment token is accepted for service
|
|
1377
|
+
*/
|
|
1378
|
+
isTokenAccepted(config, token) {
|
|
1379
|
+
const accepted = getAcceptedCurrencies(config);
|
|
1380
|
+
return accepted.includes(token);
|
|
1381
|
+
}
|
|
1237
1382
|
async readBody(req) {
|
|
1238
1383
|
return new Promise((resolve2, reject) => {
|
|
1239
1384
|
let body = "";
|
|
@@ -1433,18 +1578,22 @@ var MoltsPayServer = class {
|
|
|
1433
1578
|
/**
|
|
1434
1579
|
* Build payment requirements for proxy endpoint (uses provided wallet)
|
|
1435
1580
|
*/
|
|
1436
|
-
buildProxyPaymentRequirements(config, wallet) {
|
|
1581
|
+
buildProxyPaymentRequirements(config, wallet, token) {
|
|
1437
1582
|
const amountInUnits = Math.floor(config.price * 1e6).toString();
|
|
1438
|
-
const
|
|
1583
|
+
const acceptedTokens = getAcceptedCurrencies(config);
|
|
1584
|
+
const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
|
|
1585
|
+
const tokenAddresses = TOKEN_ADDRESSES[this.networkId] || {};
|
|
1586
|
+
const tokenAddress = tokenAddresses[selectedToken];
|
|
1587
|
+
const tokenDomain = TOKEN_DOMAINS[selectedToken] || TOKEN_DOMAINS.USDC;
|
|
1439
1588
|
return {
|
|
1440
1589
|
scheme: "exact",
|
|
1441
1590
|
network: this.networkId,
|
|
1442
|
-
asset:
|
|
1591
|
+
asset: tokenAddress,
|
|
1443
1592
|
amount: amountInUnits,
|
|
1444
1593
|
payTo: wallet,
|
|
1445
1594
|
// Use provided wallet, not manifest
|
|
1446
1595
|
maxTimeoutSeconds: 300,
|
|
1447
|
-
extra:
|
|
1596
|
+
extra: tokenDomain
|
|
1448
1597
|
};
|
|
1449
1598
|
}
|
|
1450
1599
|
/**
|
|
@@ -1577,7 +1726,7 @@ program.command("status").description("Show wallet status and balance").option("
|
|
|
1577
1726
|
return;
|
|
1578
1727
|
}
|
|
1579
1728
|
const config = client.getConfig();
|
|
1580
|
-
let balance = { usdc: 0, native: 0 };
|
|
1729
|
+
let balance = { usdc: 0, usdt: 0, native: 0 };
|
|
1581
1730
|
try {
|
|
1582
1731
|
balance = await client.getBalance();
|
|
1583
1732
|
} catch (err) {
|
|
@@ -1594,7 +1743,7 @@ program.command("status").description("Show wallet status and balance").option("
|
|
|
1594
1743
|
console.log("\n\u{1F4CA} MoltsPay Status\n");
|
|
1595
1744
|
console.log(` Wallet: ${client.address}`);
|
|
1596
1745
|
console.log(` Chain: ${config.chain}`);
|
|
1597
|
-
console.log(` Balance: ${balance.usdc.toFixed(2)} USDC`);
|
|
1746
|
+
console.log(` Balance: ${balance.usdc.toFixed(2)} USDC | ${balance.usdt.toFixed(2)} USDT`);
|
|
1598
1747
|
console.log(` Native: ${balance.native.toFixed(6)} ETH`);
|
|
1599
1748
|
console.log("");
|
|
1600
1749
|
console.log(" Limits:");
|
|
@@ -1838,7 +1987,7 @@ program.command("stop").description("Stop the running MoltsPay server").action(a
|
|
|
1838
1987
|
process.exit(1);
|
|
1839
1988
|
}
|
|
1840
1989
|
});
|
|
1841
|
-
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) => {
|
|
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) => {
|
|
1842
1991
|
const client = new MoltsPayClient();
|
|
1843
1992
|
if (!client.isInitialized) {
|
|
1844
1993
|
console.error("\u274C Wallet not initialized. Run: npx moltspay init");
|
|
@@ -1873,6 +2022,19 @@ program.command("pay <server> <service> [params]").description("Pay for a servic
|
|
|
1873
2022
|
process.exit(1);
|
|
1874
2023
|
}
|
|
1875
2024
|
const imageDisplay = params.image_url || (params.image_base64 ? `[local file: ${options.image}]` : null);
|
|
2025
|
+
const token = (options.token || "USDC").toUpperCase();
|
|
2026
|
+
if (token === "USDT") {
|
|
2027
|
+
const balance = await client.getBalance();
|
|
2028
|
+
if (balance.native < 1e-4) {
|
|
2029
|
+
console.log("\n\u26A0\uFE0F USDT requires a small amount of ETH for gas (~$0.01)");
|
|
2030
|
+
console.log(` Your ETH balance: ${balance.native.toFixed(6)} ETH`);
|
|
2031
|
+
console.log(" Please add a tiny amount of ETH to your wallet.\n");
|
|
2032
|
+
process.exit(1);
|
|
2033
|
+
}
|
|
2034
|
+
if (!options.json) {
|
|
2035
|
+
console.log("\n\u26A0\uFE0F Note: USDT payments require gas (~$0.01 on Base)");
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
1876
2038
|
if (!options.json) {
|
|
1877
2039
|
console.log(`
|
|
1878
2040
|
\u{1F4B3} MoltsPay - Paying for service
|
|
@@ -1881,11 +2043,12 @@ program.command("pay <server> <service> [params]").description("Pay for a servic
|
|
|
1881
2043
|
console.log(` Service: ${service}`);
|
|
1882
2044
|
console.log(` Prompt: ${params.prompt}`);
|
|
1883
2045
|
if (imageDisplay) console.log(` Image: ${imageDisplay}`);
|
|
2046
|
+
console.log(` Token: ${token}`);
|
|
1884
2047
|
console.log(` Wallet: ${client.address}`);
|
|
1885
2048
|
console.log("");
|
|
1886
2049
|
}
|
|
1887
2050
|
try {
|
|
1888
|
-
const result = await client.pay(server, service, params);
|
|
2051
|
+
const result = await client.pay(server, service, params, { token });
|
|
1889
2052
|
if (options.json) {
|
|
1890
2053
|
console.log(JSON.stringify(result));
|
|
1891
2054
|
} else {
|