moltspay 1.2.0 → 1.2.1
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 +78 -9
- package/dist/cdp/index.d.mts +1 -1
- package/dist/cdp/index.d.ts +1 -1
- package/dist/cdp/index.js +16 -49
- package/dist/cdp/index.js.map +1 -1
- package/dist/cdp/index.mjs +16 -49
- package/dist/cdp/index.mjs.map +1 -1
- package/dist/chains/index.d.mts +1 -1
- package/dist/chains/index.d.ts +1 -1
- package/dist/chains/index.js +16 -49
- package/dist/chains/index.js.map +1 -1
- package/dist/chains/index.mjs +16 -49
- package/dist/chains/index.mjs.map +1 -1
- package/dist/cli/index.js +180 -111
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +180 -111
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/index.d.mts +3 -3
- package/dist/client/index.d.ts +3 -3
- package/dist/client/index.js +32 -58
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +32 -58
- package/dist/client/index.mjs.map +1 -1
- package/dist/facilitators/index.d.mts +12 -6
- package/dist/facilitators/index.d.ts +12 -6
- package/dist/facilitators/index.js +39 -33
- package/dist/facilitators/index.js.map +1 -1
- package/dist/facilitators/index.mjs +39 -33
- package/dist/facilitators/index.mjs.map +1 -1
- package/dist/{index-B3v8IWjM.d.mts → index-DgJPZMBG.d.mts} +2 -1
- package/dist/{index-B3v8IWjM.d.ts → index-DgJPZMBG.d.ts} +2 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +102 -101
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +102 -101
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.js +70 -43
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +70 -43
- package/dist/server/index.mjs.map +1 -1
- package/dist/verify/index.d.mts +1 -1
- package/dist/verify/index.d.ts +1 -1
- package/dist/verify/index.js +16 -49
- package/dist/verify/index.js.map +1 -1
- package/dist/verify/index.mjs +16 -49
- package/dist/verify/index.mjs.map +1 -1
- package/dist/wallet/index.d.mts +1 -1
- package/dist/wallet/index.d.ts +1 -1
- package/dist/wallet/index.js +16 -49
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +16 -49
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -40,12 +40,15 @@ var CHAINS = {
|
|
|
40
40
|
USDC: {
|
|
41
41
|
address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
42
42
|
decimals: 6,
|
|
43
|
-
symbol: "USDC"
|
|
43
|
+
symbol: "USDC",
|
|
44
|
+
eip712Name: "USD Coin"
|
|
45
|
+
// EIP-712 domain name
|
|
44
46
|
},
|
|
45
47
|
USDT: {
|
|
46
48
|
address: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",
|
|
47
49
|
decimals: 6,
|
|
48
|
-
symbol: "USDT"
|
|
50
|
+
symbol: "USDT",
|
|
51
|
+
eip712Name: "Tether USD"
|
|
49
52
|
}
|
|
50
53
|
},
|
|
51
54
|
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
@@ -62,12 +65,15 @@ var CHAINS = {
|
|
|
62
65
|
USDC: {
|
|
63
66
|
address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
64
67
|
decimals: 6,
|
|
65
|
-
symbol: "USDC"
|
|
68
|
+
symbol: "USDC",
|
|
69
|
+
eip712Name: "USD Coin"
|
|
66
70
|
},
|
|
67
71
|
USDT: {
|
|
68
72
|
address: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
|
|
69
73
|
decimals: 6,
|
|
70
|
-
symbol: "USDT"
|
|
74
|
+
symbol: "USDT",
|
|
75
|
+
eip712Name: "(PoS) Tether USD"
|
|
76
|
+
// Polygon uses this name
|
|
71
77
|
}
|
|
72
78
|
},
|
|
73
79
|
usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
@@ -75,27 +81,6 @@ var CHAINS = {
|
|
|
75
81
|
explorerTx: "https://polygonscan.com/tx/",
|
|
76
82
|
avgBlockTime: 2
|
|
77
83
|
},
|
|
78
|
-
ethereum: {
|
|
79
|
-
name: "Ethereum",
|
|
80
|
-
chainId: 1,
|
|
81
|
-
rpc: "https://eth.llamarpc.com",
|
|
82
|
-
tokens: {
|
|
83
|
-
USDC: {
|
|
84
|
-
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
85
|
-
decimals: 6,
|
|
86
|
-
symbol: "USDC"
|
|
87
|
-
},
|
|
88
|
-
USDT: {
|
|
89
|
-
address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
90
|
-
decimals: 6,
|
|
91
|
-
symbol: "USDT"
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
95
|
-
explorer: "https://etherscan.io/address/",
|
|
96
|
-
explorerTx: "https://etherscan.io/tx/",
|
|
97
|
-
avgBlockTime: 12
|
|
98
|
-
},
|
|
99
84
|
// ============ Testnet ============
|
|
100
85
|
base_sepolia: {
|
|
101
86
|
name: "Base Sepolia",
|
|
@@ -105,41 +90,23 @@ var CHAINS = {
|
|
|
105
90
|
USDC: {
|
|
106
91
|
address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
107
92
|
decimals: 6,
|
|
108
|
-
symbol: "USDC"
|
|
93
|
+
symbol: "USDC",
|
|
94
|
+
eip712Name: "USDC"
|
|
95
|
+
// Testnet USDC uses 'USDC' not 'USD Coin'
|
|
109
96
|
},
|
|
110
97
|
USDT: {
|
|
111
98
|
address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
112
99
|
// Same as USDC on testnet (no official USDT)
|
|
113
100
|
decimals: 6,
|
|
114
|
-
symbol: "USDT"
|
|
101
|
+
symbol: "USDT",
|
|
102
|
+
eip712Name: "USDC"
|
|
103
|
+
// Uses same contract as USDC
|
|
115
104
|
}
|
|
116
105
|
},
|
|
117
106
|
usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
118
107
|
explorer: "https://sepolia.basescan.org/address/",
|
|
119
108
|
explorerTx: "https://sepolia.basescan.org/tx/",
|
|
120
109
|
avgBlockTime: 2
|
|
121
|
-
},
|
|
122
|
-
sepolia: {
|
|
123
|
-
name: "Sepolia",
|
|
124
|
-
chainId: 11155111,
|
|
125
|
-
rpc: "https://rpc.sepolia.org",
|
|
126
|
-
tokens: {
|
|
127
|
-
USDC: {
|
|
128
|
-
address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
129
|
-
decimals: 6,
|
|
130
|
-
symbol: "USDC"
|
|
131
|
-
},
|
|
132
|
-
USDT: {
|
|
133
|
-
address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
134
|
-
// Same as USDC on testnet
|
|
135
|
-
decimals: 6,
|
|
136
|
-
symbol: "USDT"
|
|
137
|
-
}
|
|
138
|
-
},
|
|
139
|
-
usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
140
|
-
explorer: "https://sepolia.etherscan.io/address/",
|
|
141
|
-
explorerTx: "https://sepolia.etherscan.io/tx/",
|
|
142
|
-
avgBlockTime: 12
|
|
143
110
|
}
|
|
144
111
|
};
|
|
145
112
|
function getChain(name) {
|
|
@@ -305,7 +272,7 @@ Server accepts: ${serverChains.join(", ")}`
|
|
|
305
272
|
} else {
|
|
306
273
|
throw new Error(
|
|
307
274
|
`Server accepts: ${serverChains.join(", ")}
|
|
308
|
-
Please specify: --chain base
|
|
275
|
+
Please specify: --chain base, --chain polygon, or --chain base_sepolia`
|
|
309
276
|
);
|
|
310
277
|
}
|
|
311
278
|
}
|
|
@@ -347,13 +314,19 @@ Please specify: --chain base or --chain polygon`
|
|
|
347
314
|
if (!payTo) {
|
|
348
315
|
throw new Error("Missing payTo address in payment requirements");
|
|
349
316
|
}
|
|
350
|
-
const
|
|
317
|
+
const domainOverride = req.extra && typeof req.extra === "object" && req.extra.name ? { name: req.extra.name, version: req.extra.version || "2" } : void 0;
|
|
318
|
+
const authorization = await this.signEIP3009(payTo, amount, chain, token, domainOverride);
|
|
351
319
|
const tokenConfig = chain.tokens[token];
|
|
352
|
-
const
|
|
320
|
+
const extra = req.extra && typeof req.extra === "object" ? req.extra : {
|
|
321
|
+
name: tokenConfig.eip712Name || "USD Coin",
|
|
322
|
+
version: "2"
|
|
323
|
+
};
|
|
353
324
|
const payload = {
|
|
354
325
|
x402Version: X402_VERSION,
|
|
326
|
+
scheme: "exact",
|
|
327
|
+
network,
|
|
355
328
|
payload: authorization,
|
|
356
|
-
//
|
|
329
|
+
// { authorization: {...}, signature: "0x..." }
|
|
357
330
|
accepted: {
|
|
358
331
|
scheme: "exact",
|
|
359
332
|
network,
|
|
@@ -361,7 +334,7 @@ Please specify: --chain base or --chain polygon`
|
|
|
361
334
|
amount: amountRaw,
|
|
362
335
|
payTo,
|
|
363
336
|
maxTimeoutSeconds: req.maxTimeoutSeconds || 300,
|
|
364
|
-
extra
|
|
337
|
+
extra
|
|
365
338
|
}
|
|
366
339
|
};
|
|
367
340
|
const paymentHeader = Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
@@ -391,7 +364,7 @@ Please specify: --chain base or --chain polygon`
|
|
|
391
364
|
* This only signs - no on-chain transaction, no gas needed.
|
|
392
365
|
* Supports both USDC and USDT.
|
|
393
366
|
*/
|
|
394
|
-
async signEIP3009(to, amount, chain, token = "USDC") {
|
|
367
|
+
async signEIP3009(to, amount, chain, token = "USDC", domainOverride) {
|
|
395
368
|
const validAfter = 0;
|
|
396
369
|
const validBefore = Math.floor(Date.now() / 1e3) + 3600;
|
|
397
370
|
const nonce = ethers.hexlify(ethers.randomBytes(32));
|
|
@@ -405,10 +378,11 @@ Please specify: --chain base or --chain polygon`
|
|
|
405
378
|
validBefore: validBefore.toString(),
|
|
406
379
|
nonce
|
|
407
380
|
};
|
|
408
|
-
const tokenName = token === "USDC" ? "USD Coin" : "Tether USD";
|
|
381
|
+
const tokenName = domainOverride?.name || tokenConfig.eip712Name || (token === "USDC" ? "USD Coin" : "Tether USD");
|
|
382
|
+
const tokenVersion = domainOverride?.version || "2";
|
|
409
383
|
const domain = {
|
|
410
384
|
name: tokenName,
|
|
411
|
-
version:
|
|
385
|
+
version: tokenVersion,
|
|
412
386
|
chainId: chain.chainId,
|
|
413
387
|
verifyingContract: tokenConfig.address
|
|
414
388
|
};
|
|
@@ -577,7 +551,7 @@ Please specify: --chain base or --chain polygon`
|
|
|
577
551
|
if (!this.wallet) {
|
|
578
552
|
throw new Error("Client not initialized");
|
|
579
553
|
}
|
|
580
|
-
const supportedChains = ["base", "polygon"];
|
|
554
|
+
const supportedChains = ["base", "polygon", "base_sepolia"];
|
|
581
555
|
const tokenAbi = ["function balanceOf(address) view returns (uint256)"];
|
|
582
556
|
const results = {};
|
|
583
557
|
await Promise.all(
|
|
@@ -626,8 +600,8 @@ init_esm_shims();
|
|
|
626
600
|
import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
|
|
627
601
|
import * as path2 from "path";
|
|
628
602
|
var X402_VERSION2 = 2;
|
|
629
|
-
var
|
|
630
|
-
var
|
|
603
|
+
var CDP_URL = "https://api.cdp.coinbase.com/platform/v2/x402";
|
|
604
|
+
var TESTNET_CHAIN_IDS = [84532];
|
|
631
605
|
function loadEnvFile() {
|
|
632
606
|
const envPaths = [
|
|
633
607
|
path2.join(process.cwd(), ".env"),
|
|
@@ -662,31 +636,33 @@ var CDPFacilitator = class extends BaseFacilitator {
|
|
|
662
636
|
displayName = "Coinbase CDP";
|
|
663
637
|
supportedNetworks;
|
|
664
638
|
endpoint;
|
|
665
|
-
useMainnet;
|
|
666
639
|
apiKeyId;
|
|
667
640
|
apiKeySecret;
|
|
668
641
|
constructor(config = {}) {
|
|
669
642
|
super();
|
|
670
643
|
loadEnvFile();
|
|
671
|
-
this.useMainnet = config.useMainnet ?? process.env.USE_MAINNET?.toLowerCase() === "true";
|
|
672
644
|
this.apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;
|
|
673
645
|
this.apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;
|
|
674
|
-
this.endpoint =
|
|
675
|
-
this.supportedNetworks =
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
646
|
+
this.endpoint = CDP_URL;
|
|
647
|
+
this.supportedNetworks = [
|
|
648
|
+
"eip155:8453",
|
|
649
|
+
// Base mainnet
|
|
650
|
+
"eip155:137",
|
|
651
|
+
// Polygon mainnet
|
|
652
|
+
"eip155:84532"
|
|
653
|
+
// Base Sepolia (testnet)
|
|
654
|
+
];
|
|
655
|
+
if (!this.apiKeyId || !this.apiKeySecret) {
|
|
656
|
+
console.warn("[CDPFacilitator] WARNING: Missing CDP credentials!");
|
|
657
|
+
console.warn("[CDPFacilitator] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in ~/.moltspay/.env");
|
|
679
658
|
}
|
|
680
659
|
}
|
|
681
660
|
/**
|
|
682
661
|
* Get auth headers for CDP API requests
|
|
683
662
|
*/
|
|
684
663
|
async getAuthHeaders(method, urlPath, body) {
|
|
685
|
-
if (!this.useMainnet) {
|
|
686
|
-
return {};
|
|
687
|
-
}
|
|
688
664
|
if (!this.apiKeyId || !this.apiKeySecret) {
|
|
689
|
-
throw new Error("CDP credentials required
|
|
665
|
+
throw new Error("CDP credentials required. Set CDP_API_KEY_ID and CDP_API_KEY_SECRET");
|
|
690
666
|
}
|
|
691
667
|
try {
|
|
692
668
|
const { getAuthHeaders } = await import("@coinbase/cdp-sdk/auth");
|
|
@@ -738,23 +714,23 @@ var CDPFacilitator = class extends BaseFacilitator {
|
|
|
738
714
|
paymentPayload,
|
|
739
715
|
paymentRequirements: requirements
|
|
740
716
|
};
|
|
717
|
+
console.log("[CDP Verify] Payload:", JSON.stringify(paymentPayload, null, 2));
|
|
718
|
+
const authHeaders = await this.getAuthHeaders(
|
|
719
|
+
"POST",
|
|
720
|
+
"/platform/v2/x402/verify",
|
|
721
|
+
requestBody
|
|
722
|
+
);
|
|
741
723
|
const headers = {
|
|
742
|
-
"Content-Type": "application/json"
|
|
724
|
+
"Content-Type": "application/json",
|
|
725
|
+
...authHeaders
|
|
743
726
|
};
|
|
744
|
-
if (this.useMainnet) {
|
|
745
|
-
const authHeaders = await this.getAuthHeaders(
|
|
746
|
-
"POST",
|
|
747
|
-
"/platform/v2/x402/verify",
|
|
748
|
-
requestBody
|
|
749
|
-
);
|
|
750
|
-
Object.assign(headers, authHeaders);
|
|
751
|
-
}
|
|
752
727
|
const response = await fetch(`${this.endpoint}/verify`, {
|
|
753
728
|
method: "POST",
|
|
754
729
|
headers,
|
|
755
730
|
body: JSON.stringify(requestBody)
|
|
756
731
|
});
|
|
757
732
|
const result = await response.json();
|
|
733
|
+
console.log("[CDP Verify] Response:", response.status, JSON.stringify(result));
|
|
758
734
|
if (!response.ok || !result.isValid) {
|
|
759
735
|
return {
|
|
760
736
|
valid: false,
|
|
@@ -780,17 +756,15 @@ var CDPFacilitator = class extends BaseFacilitator {
|
|
|
780
756
|
paymentPayload,
|
|
781
757
|
paymentRequirements: requirements
|
|
782
758
|
};
|
|
759
|
+
const authHeaders = await this.getAuthHeaders(
|
|
760
|
+
"POST",
|
|
761
|
+
"/platform/v2/x402/settle",
|
|
762
|
+
requestBody
|
|
763
|
+
);
|
|
783
764
|
const headers = {
|
|
784
|
-
"Content-Type": "application/json"
|
|
765
|
+
"Content-Type": "application/json",
|
|
766
|
+
...authHeaders
|
|
785
767
|
};
|
|
786
|
-
if (this.useMainnet) {
|
|
787
|
-
const authHeaders = await this.getAuthHeaders(
|
|
788
|
-
"POST",
|
|
789
|
-
"/platform/v2/x402/settle",
|
|
790
|
-
requestBody
|
|
791
|
-
);
|
|
792
|
-
Object.assign(headers, authHeaders);
|
|
793
|
-
}
|
|
794
768
|
const response = await fetch(`${this.endpoint}/settle`, {
|
|
795
769
|
method: "POST",
|
|
796
770
|
headers,
|
|
@@ -825,13 +799,19 @@ var CDPFacilitator = class extends BaseFacilitator {
|
|
|
825
799
|
freeQuota: 1e3
|
|
826
800
|
};
|
|
827
801
|
}
|
|
802
|
+
/**
|
|
803
|
+
* Check if a chain ID is testnet
|
|
804
|
+
*/
|
|
805
|
+
static isTestnet(chainId) {
|
|
806
|
+
return TESTNET_CHAIN_IDS.includes(chainId);
|
|
807
|
+
}
|
|
828
808
|
/**
|
|
829
809
|
* Get configuration summary (for logging)
|
|
830
810
|
*/
|
|
831
811
|
getConfigSummary() {
|
|
832
|
-
const mode = this.useMainnet ? "mainnet" : "testnet";
|
|
833
812
|
const hasCredentials = !!(this.apiKeyId && this.apiKeySecret);
|
|
834
|
-
|
|
813
|
+
const networks = this.supportedNetworks.join(", ");
|
|
814
|
+
return `CDP Facilitator (networks: ${networks}, credentials: ${hasCredentials ? "yes" : "no"})`;
|
|
835
815
|
}
|
|
836
816
|
};
|
|
837
817
|
|
|
@@ -1089,9 +1069,27 @@ var CHAIN_TO_NETWORK = {
|
|
|
1089
1069
|
"polygon": "eip155:137"
|
|
1090
1070
|
};
|
|
1091
1071
|
var TOKEN_DOMAINS = {
|
|
1092
|
-
|
|
1093
|
-
|
|
1072
|
+
// Base mainnet
|
|
1073
|
+
"eip155:8453": {
|
|
1074
|
+
USDC: { name: "USD Coin", version: "2" },
|
|
1075
|
+
USDT: { name: "Tether USD", version: "2" }
|
|
1076
|
+
},
|
|
1077
|
+
// Base Sepolia testnet - USDC uses 'USDC' not 'USD Coin'
|
|
1078
|
+
"eip155:84532": {
|
|
1079
|
+
USDC: { name: "USDC", version: "2" },
|
|
1080
|
+
USDT: { name: "USDC", version: "2" }
|
|
1081
|
+
// Same contract as USDC on testnet
|
|
1082
|
+
},
|
|
1083
|
+
// Polygon mainnet
|
|
1084
|
+
"eip155:137": {
|
|
1085
|
+
USDC: { name: "USD Coin", version: "2" },
|
|
1086
|
+
USDT: { name: "(PoS) Tether USD", version: "2" }
|
|
1087
|
+
}
|
|
1094
1088
|
};
|
|
1089
|
+
function getTokenDomain(network, token) {
|
|
1090
|
+
const networkDomains = TOKEN_DOMAINS[network] || TOKEN_DOMAINS["eip155:8453"];
|
|
1091
|
+
return networkDomains[token] || { name: "USD Coin", version: "2" };
|
|
1092
|
+
}
|
|
1095
1093
|
function getAcceptedCurrencies(config) {
|
|
1096
1094
|
return config.acceptedCurrencies ?? [config.currency];
|
|
1097
1095
|
}
|
|
@@ -1185,11 +1183,14 @@ var MoltsPayServer = class {
|
|
|
1185
1183
|
getProviderChains() {
|
|
1186
1184
|
const provider = this.manifest.provider;
|
|
1187
1185
|
if (provider.chains && provider.chains.length > 0) {
|
|
1188
|
-
return provider.chains.map((c) =>
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1186
|
+
return provider.chains.map((c) => {
|
|
1187
|
+
const chainName = typeof c === "string" ? c : c.chain;
|
|
1188
|
+
return {
|
|
1189
|
+
network: CHAIN_TO_NETWORK[chainName] || "eip155:8453",
|
|
1190
|
+
wallet: (typeof c === "object" ? c.wallet : null) || provider.wallet,
|
|
1191
|
+
tokens: (typeof c === "object" ? c.tokens : null) || ["USDC"]
|
|
1192
|
+
};
|
|
1193
|
+
});
|
|
1193
1194
|
}
|
|
1194
1195
|
const chain = provider.chain || "base";
|
|
1195
1196
|
const network = CHAIN_TO_NETWORK[chain] || this.networkId;
|
|
@@ -1399,7 +1400,7 @@ var MoltsPayServer = class {
|
|
|
1399
1400
|
const paymentNetwork = payment.accepted?.network || payment.network || this.networkId;
|
|
1400
1401
|
const paymentWallet = this.getWalletForNetwork(paymentNetwork);
|
|
1401
1402
|
const requirements = this.buildPaymentRequirements(skill.config, paymentNetwork, paymentWallet, paymentToken);
|
|
1402
|
-
console.log(`[MoltsPay] Verifying payment...`);
|
|
1403
|
+
console.log(`[MoltsPay] Verifying payment on ${paymentNetwork}...`);
|
|
1403
1404
|
const verifyResult = await this.registry.verify(payment, requirements);
|
|
1404
1405
|
if (!verifyResult.valid) {
|
|
1405
1406
|
return this.sendJson(res, 402, {
|
|
@@ -1525,7 +1526,7 @@ var MoltsPayServer = class {
|
|
|
1525
1526
|
const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
|
|
1526
1527
|
const tokenAddresses = TOKEN_ADDRESSES[selectedNetwork] || {};
|
|
1527
1528
|
const tokenAddress = tokenAddresses[selectedToken];
|
|
1528
|
-
const tokenDomain =
|
|
1529
|
+
const tokenDomain = getTokenDomain(selectedNetwork, selectedToken);
|
|
1529
1530
|
return {
|
|
1530
1531
|
scheme: "exact",
|
|
1531
1532
|
network: selectedNetwork,
|
|
@@ -1770,7 +1771,7 @@ var MoltsPayServer = class {
|
|
|
1770
1771
|
const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
|
|
1771
1772
|
const tokenAddresses = TOKEN_ADDRESSES[networkId] || TOKEN_ADDRESSES[this.networkId] || {};
|
|
1772
1773
|
const tokenAddress = tokenAddresses[selectedToken];
|
|
1773
|
-
const tokenDomain =
|
|
1774
|
+
const tokenDomain = getTokenDomain(networkId, selectedToken);
|
|
1774
1775
|
return {
|
|
1775
1776
|
scheme: "exact",
|
|
1776
1777
|
network: networkId,
|
|
@@ -1852,6 +1853,11 @@ program.command("init").description("Initialize MoltsPay client (create wallet,
|
|
|
1852
1853
|
return;
|
|
1853
1854
|
}
|
|
1854
1855
|
let chain = options.chain;
|
|
1856
|
+
const supportedChains = ["base", "polygon", "base_sepolia"];
|
|
1857
|
+
if (!supportedChains.includes(chain)) {
|
|
1858
|
+
console.error(`\u274C Unknown chain: ${chain}. Supported: ${supportedChains.join(", ")}`);
|
|
1859
|
+
process.exit(1);
|
|
1860
|
+
}
|
|
1855
1861
|
let maxPerTx = options.maxPerTx ? parseFloat(options.maxPerTx) : null;
|
|
1856
1862
|
let maxPerDay = options.maxPerDay ? parseFloat(options.maxPerDay) : null;
|
|
1857
1863
|
if (!maxPerTx) {
|
|
@@ -1914,7 +1920,7 @@ program.command("config").description("Update MoltsPay settings").option("--max-
|
|
|
1914
1920
|
}
|
|
1915
1921
|
}
|
|
1916
1922
|
});
|
|
1917
|
-
program.command("fund <amount>").description("Fund wallet with USDC via Coinbase (US debit card / Apple Pay)").option("--chain <chain>", "Chain to fund (base or
|
|
1923
|
+
program.command("fund <amount>").description("Fund wallet with USDC via Coinbase (US debit card / Apple Pay)").option("--chain <chain>", "Chain to fund (base, polygon, or base_sepolia)", "base").option("--config-dir <dir>", "Config directory", DEFAULT_CONFIG_DIR).action(async (amountStr, options) => {
|
|
1918
1924
|
const client = new MoltsPayClient({ configDir: options.configDir });
|
|
1919
1925
|
if (!client.isInitialized) {
|
|
1920
1926
|
console.log("\u274C Not initialized. Run: npx moltspay init");
|
|
@@ -1926,8 +1932,20 @@ program.command("fund <amount>").description("Fund wallet with USDC via Coinbase
|
|
|
1926
1932
|
return;
|
|
1927
1933
|
}
|
|
1928
1934
|
const chain = options.chain?.toLowerCase() || "base";
|
|
1929
|
-
if (!["base", "polygon"].includes(chain)) {
|
|
1930
|
-
console.log("\u274C Invalid chain. Use: base or
|
|
1935
|
+
if (!["base", "polygon", "base_sepolia"].includes(chain)) {
|
|
1936
|
+
console.log("\u274C Invalid chain. Use: base, polygon, or base_sepolia");
|
|
1937
|
+
return;
|
|
1938
|
+
}
|
|
1939
|
+
if (chain === "base_sepolia") {
|
|
1940
|
+
console.log("\n\u{1F9EA} Testnet Funding\n");
|
|
1941
|
+
console.log(` Wallet: ${client.address}`);
|
|
1942
|
+
console.log(` Chain: Base Sepolia (testnet)
|
|
1943
|
+
`);
|
|
1944
|
+
console.log("\u{1F4DD} Get testnet USDC from these faucets:");
|
|
1945
|
+
console.log(" \u2022 Circle Faucet: https://faucet.circle.com/");
|
|
1946
|
+
console.log(" \u2022 Base Sepolia: https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet\n");
|
|
1947
|
+
console.log(`\u{1F4A1} Send USDC to: ${client.address}
|
|
1948
|
+
`);
|
|
1931
1949
|
return;
|
|
1932
1950
|
}
|
|
1933
1951
|
console.log("\n\u{1F4B3} Fund your agent wallet\n");
|
|
@@ -1959,6 +1977,52 @@ program.command("fund <amount>").description("Fund wallet with USDC via Coinbase
|
|
|
1959
1977
|
console.log(`\u274C ${error.message}`);
|
|
1960
1978
|
}
|
|
1961
1979
|
});
|
|
1980
|
+
program.command("faucet").description("Request testnet USDC from MoltsPay faucet (Base Sepolia)").option("--address <address>", "Wallet address (defaults to your wallet)").option("--config-dir <dir>", "Config directory", DEFAULT_CONFIG_DIR).action(async (options) => {
|
|
1981
|
+
let address = options.address;
|
|
1982
|
+
if (!address) {
|
|
1983
|
+
const client = new MoltsPayClient({ configDir: options.configDir });
|
|
1984
|
+
if (client.isInitialized) {
|
|
1985
|
+
address = client.address;
|
|
1986
|
+
} else {
|
|
1987
|
+
console.log('\u274C No wallet found. Either run "npx moltspay init" or provide --address');
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
if (!address.match(/^0x[a-fA-F0-9]{40}$/)) {
|
|
1992
|
+
console.log("\u274C Invalid Ethereum address");
|
|
1993
|
+
return;
|
|
1994
|
+
}
|
|
1995
|
+
console.log("\n\u{1F6B0} MoltsPay Testnet Faucet\n");
|
|
1996
|
+
console.log(` Requesting 1 USDC on Base Sepolia...`);
|
|
1997
|
+
console.log(` Address: ${address}
|
|
1998
|
+
`);
|
|
1999
|
+
try {
|
|
2000
|
+
const FAUCET_API = process.env.MOLTSPAY_FAUCET_API || "https://moltspay.com/api/v1/faucet";
|
|
2001
|
+
const response = await fetch(FAUCET_API, {
|
|
2002
|
+
method: "POST",
|
|
2003
|
+
headers: { "Content-Type": "application/json" },
|
|
2004
|
+
body: JSON.stringify({ address })
|
|
2005
|
+
});
|
|
2006
|
+
const result = await response.json();
|
|
2007
|
+
if (!response.ok) {
|
|
2008
|
+
console.log(`\u274C ${result.error || "Request failed"}`);
|
|
2009
|
+
if (result.hint) console.log(` ${result.hint}`);
|
|
2010
|
+
if (result.retry_after) console.log(` Retry after: ${result.retry_after}`);
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
console.log(`\u2705 Received ${result.amount} USDC!
|
|
2014
|
+
`);
|
|
2015
|
+
console.log(` Transaction: ${result.transaction}`);
|
|
2016
|
+
console.log(` Explorer: ${result.explorer}`);
|
|
2017
|
+
console.log(` Faucet balance: ${result.faucet_balance} USDC remaining
|
|
2018
|
+
`);
|
|
2019
|
+
console.log("\u{1F4A1} Use this USDC to test x402 payments:");
|
|
2020
|
+
console.log(` npx moltspay pay <service-url> <service-id> --chain base_sepolia
|
|
2021
|
+
`);
|
|
2022
|
+
} catch (error) {
|
|
2023
|
+
console.log(`\u274C ${error.message}`);
|
|
2024
|
+
}
|
|
2025
|
+
});
|
|
1962
2026
|
program.command("status").description("Show wallet status and balance").option("--config-dir <dir>", "Config directory", DEFAULT_CONFIG_DIR).option("--json", "Output as JSON").action(async (options) => {
|
|
1963
2027
|
const client = new MoltsPayClient({ configDir: options.configDir });
|
|
1964
2028
|
if (!client.isInitialized) {
|
|
@@ -1998,7 +2062,7 @@ program.command("status").description("Show wallet status and balance").option("
|
|
|
1998
2062
|
console.log("");
|
|
1999
2063
|
}
|
|
2000
2064
|
});
|
|
2001
|
-
program.command("list").description("List recent transactions").option("--days <n>", "Number of days to look back", "7").option("--chain <chain>", "Chain to query (base, polygon, or all)", "all").option("--limit <n>", "Max transactions to show", "20").option("--config-dir <dir>", "Config directory", DEFAULT_CONFIG_DIR).action(async (options) => {
|
|
2065
|
+
program.command("list").description("List recent transactions").option("--days <n>", "Number of days to look back", "7").option("--chain <chain>", "Chain to query (base, polygon, base_sepolia, or all)", "all").option("--limit <n>", "Max transactions to show", "20").option("--config-dir <dir>", "Config directory", DEFAULT_CONFIG_DIR).action(async (options) => {
|
|
2002
2066
|
const client = new MoltsPayClient({ configDir: options.configDir });
|
|
2003
2067
|
if (!client.isInitialized) {
|
|
2004
2068
|
console.log("\u274C Not initialized. Run: npx moltspay init");
|
|
@@ -2007,8 +2071,8 @@ program.command("list").description("List recent transactions").option("--days <
|
|
|
2007
2071
|
const days = parseInt(options.days) || 7;
|
|
2008
2072
|
const limit = parseInt(options.limit) || 20;
|
|
2009
2073
|
const chain = options.chain?.toLowerCase() || "all";
|
|
2010
|
-
if (!["base", "polygon", "all"].includes(chain)) {
|
|
2011
|
-
console.log("\u274C Invalid chain. Use: base, polygon, or all");
|
|
2074
|
+
if (!["base", "polygon", "base_sepolia", "all"].includes(chain)) {
|
|
2075
|
+
console.log("\u274C Invalid chain. Use: base, polygon, base_sepolia, or all");
|
|
2012
2076
|
return;
|
|
2013
2077
|
}
|
|
2014
2078
|
const wallet = client.address;
|
|
@@ -2023,9 +2087,14 @@ program.command("list").description("List recent transactions").option("--days <
|
|
|
2023
2087
|
api: "https://polygon.blockscout.com/api/v2",
|
|
2024
2088
|
usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
2025
2089
|
name: "Polygon"
|
|
2090
|
+
},
|
|
2091
|
+
base_sepolia: {
|
|
2092
|
+
api: "https://base-sepolia.blockscout.com/api/v2",
|
|
2093
|
+
usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
2094
|
+
name: "Base Sepolia"
|
|
2026
2095
|
}
|
|
2027
2096
|
};
|
|
2028
|
-
const chainsToQuery = chain === "all" ? ["base", "polygon"] : [chain];
|
|
2097
|
+
const chainsToQuery = chain === "all" ? ["base", "polygon", "base_sepolia"] : [chain];
|
|
2029
2098
|
console.log(`
|
|
2030
2099
|
\u{1F4DC} Transactions (last ${days} day${days > 1 ? "s" : ""})
|
|
2031
2100
|
`);
|
|
@@ -2322,7 +2391,7 @@ program.command("stop").description("Stop the running MoltsPay server").action(a
|
|
|
2322
2391
|
process.exit(1);
|
|
2323
2392
|
}
|
|
2324
2393
|
});
|
|
2325
|
-
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
|
|
2394
|
+
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, polygon, or base_sepolia). Required if server accepts multiple chains.").option("--json", "Output raw JSON only").action(async (server, service, paramsJson, options) => {
|
|
2326
2395
|
const client = new MoltsPayClient();
|
|
2327
2396
|
if (!client.isInitialized) {
|
|
2328
2397
|
console.error("\u274C Wallet not initialized. Run: npx moltspay init");
|
|
@@ -2357,8 +2426,8 @@ program.command("pay <server> <service> [params]").description("Pay for a servic
|
|
|
2357
2426
|
process.exit(1);
|
|
2358
2427
|
}
|
|
2359
2428
|
const chain = options.chain?.toLowerCase();
|
|
2360
|
-
if (chain && !["base", "polygon"].includes(chain)) {
|
|
2361
|
-
console.error(`\u274C Unknown chain: ${chain}. Supported: base, polygon`);
|
|
2429
|
+
if (chain && !["base", "polygon", "base_sepolia"].includes(chain)) {
|
|
2430
|
+
console.error(`\u274C Unknown chain: ${chain}. Supported: base, polygon, base_sepolia`);
|
|
2362
2431
|
process.exit(1);
|
|
2363
2432
|
}
|
|
2364
2433
|
const imageDisplay = params.image_url || (params.image_base64 ? `[local file: ${options.image}]` : null);
|