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.js
CHANGED
|
@@ -60,12 +60,15 @@ var CHAINS = {
|
|
|
60
60
|
USDC: {
|
|
61
61
|
address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
62
62
|
decimals: 6,
|
|
63
|
-
symbol: "USDC"
|
|
63
|
+
symbol: "USDC",
|
|
64
|
+
eip712Name: "USD Coin"
|
|
65
|
+
// EIP-712 domain name
|
|
64
66
|
},
|
|
65
67
|
USDT: {
|
|
66
68
|
address: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",
|
|
67
69
|
decimals: 6,
|
|
68
|
-
symbol: "USDT"
|
|
70
|
+
symbol: "USDT",
|
|
71
|
+
eip712Name: "Tether USD"
|
|
69
72
|
}
|
|
70
73
|
},
|
|
71
74
|
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
@@ -82,12 +85,15 @@ var CHAINS = {
|
|
|
82
85
|
USDC: {
|
|
83
86
|
address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
84
87
|
decimals: 6,
|
|
85
|
-
symbol: "USDC"
|
|
88
|
+
symbol: "USDC",
|
|
89
|
+
eip712Name: "USD Coin"
|
|
86
90
|
},
|
|
87
91
|
USDT: {
|
|
88
92
|
address: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
|
|
89
93
|
decimals: 6,
|
|
90
|
-
symbol: "USDT"
|
|
94
|
+
symbol: "USDT",
|
|
95
|
+
eip712Name: "(PoS) Tether USD"
|
|
96
|
+
// Polygon uses this name
|
|
91
97
|
}
|
|
92
98
|
},
|
|
93
99
|
usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
@@ -95,27 +101,6 @@ var CHAINS = {
|
|
|
95
101
|
explorerTx: "https://polygonscan.com/tx/",
|
|
96
102
|
avgBlockTime: 2
|
|
97
103
|
},
|
|
98
|
-
ethereum: {
|
|
99
|
-
name: "Ethereum",
|
|
100
|
-
chainId: 1,
|
|
101
|
-
rpc: "https://eth.llamarpc.com",
|
|
102
|
-
tokens: {
|
|
103
|
-
USDC: {
|
|
104
|
-
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
105
|
-
decimals: 6,
|
|
106
|
-
symbol: "USDC"
|
|
107
|
-
},
|
|
108
|
-
USDT: {
|
|
109
|
-
address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
110
|
-
decimals: 6,
|
|
111
|
-
symbol: "USDT"
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
115
|
-
explorer: "https://etherscan.io/address/",
|
|
116
|
-
explorerTx: "https://etherscan.io/tx/",
|
|
117
|
-
avgBlockTime: 12
|
|
118
|
-
},
|
|
119
104
|
// ============ Testnet ============
|
|
120
105
|
base_sepolia: {
|
|
121
106
|
name: "Base Sepolia",
|
|
@@ -125,41 +110,23 @@ var CHAINS = {
|
|
|
125
110
|
USDC: {
|
|
126
111
|
address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
127
112
|
decimals: 6,
|
|
128
|
-
symbol: "USDC"
|
|
113
|
+
symbol: "USDC",
|
|
114
|
+
eip712Name: "USDC"
|
|
115
|
+
// Testnet USDC uses 'USDC' not 'USD Coin'
|
|
129
116
|
},
|
|
130
117
|
USDT: {
|
|
131
118
|
address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
132
119
|
// Same as USDC on testnet (no official USDT)
|
|
133
120
|
decimals: 6,
|
|
134
|
-
symbol: "USDT"
|
|
121
|
+
symbol: "USDT",
|
|
122
|
+
eip712Name: "USDC"
|
|
123
|
+
// Uses same contract as USDC
|
|
135
124
|
}
|
|
136
125
|
},
|
|
137
126
|
usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
138
127
|
explorer: "https://sepolia.basescan.org/address/",
|
|
139
128
|
explorerTx: "https://sepolia.basescan.org/tx/",
|
|
140
129
|
avgBlockTime: 2
|
|
141
|
-
},
|
|
142
|
-
sepolia: {
|
|
143
|
-
name: "Sepolia",
|
|
144
|
-
chainId: 11155111,
|
|
145
|
-
rpc: "https://rpc.sepolia.org",
|
|
146
|
-
tokens: {
|
|
147
|
-
USDC: {
|
|
148
|
-
address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
149
|
-
decimals: 6,
|
|
150
|
-
symbol: "USDC"
|
|
151
|
-
},
|
|
152
|
-
USDT: {
|
|
153
|
-
address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
154
|
-
// Same as USDC on testnet
|
|
155
|
-
decimals: 6,
|
|
156
|
-
symbol: "USDT"
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
160
|
-
explorer: "https://sepolia.etherscan.io/address/",
|
|
161
|
-
explorerTx: "https://sepolia.etherscan.io/tx/",
|
|
162
|
-
avgBlockTime: 12
|
|
163
130
|
}
|
|
164
131
|
};
|
|
165
132
|
function getChain(name) {
|
|
@@ -325,7 +292,7 @@ Server accepts: ${serverChains.join(", ")}`
|
|
|
325
292
|
} else {
|
|
326
293
|
throw new Error(
|
|
327
294
|
`Server accepts: ${serverChains.join(", ")}
|
|
328
|
-
Please specify: --chain base
|
|
295
|
+
Please specify: --chain base, --chain polygon, or --chain base_sepolia`
|
|
329
296
|
);
|
|
330
297
|
}
|
|
331
298
|
}
|
|
@@ -367,13 +334,19 @@ Please specify: --chain base or --chain polygon`
|
|
|
367
334
|
if (!payTo) {
|
|
368
335
|
throw new Error("Missing payTo address in payment requirements");
|
|
369
336
|
}
|
|
370
|
-
const
|
|
337
|
+
const domainOverride = req.extra && typeof req.extra === "object" && req.extra.name ? { name: req.extra.name, version: req.extra.version || "2" } : void 0;
|
|
338
|
+
const authorization = await this.signEIP3009(payTo, amount, chain, token, domainOverride);
|
|
371
339
|
const tokenConfig = chain.tokens[token];
|
|
372
|
-
const
|
|
340
|
+
const extra = req.extra && typeof req.extra === "object" ? req.extra : {
|
|
341
|
+
name: tokenConfig.eip712Name || "USD Coin",
|
|
342
|
+
version: "2"
|
|
343
|
+
};
|
|
373
344
|
const payload = {
|
|
374
345
|
x402Version: X402_VERSION,
|
|
346
|
+
scheme: "exact",
|
|
347
|
+
network,
|
|
375
348
|
payload: authorization,
|
|
376
|
-
//
|
|
349
|
+
// { authorization: {...}, signature: "0x..." }
|
|
377
350
|
accepted: {
|
|
378
351
|
scheme: "exact",
|
|
379
352
|
network,
|
|
@@ -381,7 +354,7 @@ Please specify: --chain base or --chain polygon`
|
|
|
381
354
|
amount: amountRaw,
|
|
382
355
|
payTo,
|
|
383
356
|
maxTimeoutSeconds: req.maxTimeoutSeconds || 300,
|
|
384
|
-
extra
|
|
357
|
+
extra
|
|
385
358
|
}
|
|
386
359
|
};
|
|
387
360
|
const paymentHeader = Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
@@ -411,7 +384,7 @@ Please specify: --chain base or --chain polygon`
|
|
|
411
384
|
* This only signs - no on-chain transaction, no gas needed.
|
|
412
385
|
* Supports both USDC and USDT.
|
|
413
386
|
*/
|
|
414
|
-
async signEIP3009(to, amount, chain, token = "USDC") {
|
|
387
|
+
async signEIP3009(to, amount, chain, token = "USDC", domainOverride) {
|
|
415
388
|
const validAfter = 0;
|
|
416
389
|
const validBefore = Math.floor(Date.now() / 1e3) + 3600;
|
|
417
390
|
const nonce = import_ethers.ethers.hexlify(import_ethers.ethers.randomBytes(32));
|
|
@@ -425,10 +398,11 @@ Please specify: --chain base or --chain polygon`
|
|
|
425
398
|
validBefore: validBefore.toString(),
|
|
426
399
|
nonce
|
|
427
400
|
};
|
|
428
|
-
const tokenName = token === "USDC" ? "USD Coin" : "Tether USD";
|
|
401
|
+
const tokenName = domainOverride?.name || tokenConfig.eip712Name || (token === "USDC" ? "USD Coin" : "Tether USD");
|
|
402
|
+
const tokenVersion = domainOverride?.version || "2";
|
|
429
403
|
const domain = {
|
|
430
404
|
name: tokenName,
|
|
431
|
-
version:
|
|
405
|
+
version: tokenVersion,
|
|
432
406
|
chainId: chain.chainId,
|
|
433
407
|
verifyingContract: tokenConfig.address
|
|
434
408
|
};
|
|
@@ -597,7 +571,7 @@ Please specify: --chain base or --chain polygon`
|
|
|
597
571
|
if (!this.wallet) {
|
|
598
572
|
throw new Error("Client not initialized");
|
|
599
573
|
}
|
|
600
|
-
const supportedChains = ["base", "polygon"];
|
|
574
|
+
const supportedChains = ["base", "polygon", "base_sepolia"];
|
|
601
575
|
const tokenAbi = ["function balanceOf(address) view returns (uint256)"];
|
|
602
576
|
const results = {};
|
|
603
577
|
await Promise.all(
|
|
@@ -646,8 +620,8 @@ init_cjs_shims();
|
|
|
646
620
|
var import_fs2 = require("fs");
|
|
647
621
|
var path = __toESM(require("path"));
|
|
648
622
|
var X402_VERSION2 = 2;
|
|
649
|
-
var
|
|
650
|
-
var
|
|
623
|
+
var CDP_URL = "https://api.cdp.coinbase.com/platform/v2/x402";
|
|
624
|
+
var TESTNET_CHAIN_IDS = [84532];
|
|
651
625
|
function loadEnvFile() {
|
|
652
626
|
const envPaths = [
|
|
653
627
|
path.join(process.cwd(), ".env"),
|
|
@@ -682,31 +656,33 @@ var CDPFacilitator = class extends BaseFacilitator {
|
|
|
682
656
|
displayName = "Coinbase CDP";
|
|
683
657
|
supportedNetworks;
|
|
684
658
|
endpoint;
|
|
685
|
-
useMainnet;
|
|
686
659
|
apiKeyId;
|
|
687
660
|
apiKeySecret;
|
|
688
661
|
constructor(config = {}) {
|
|
689
662
|
super();
|
|
690
663
|
loadEnvFile();
|
|
691
|
-
this.useMainnet = config.useMainnet ?? process.env.USE_MAINNET?.toLowerCase() === "true";
|
|
692
664
|
this.apiKeyId = config.apiKeyId || process.env.CDP_API_KEY_ID;
|
|
693
665
|
this.apiKeySecret = config.apiKeySecret || process.env.CDP_API_KEY_SECRET;
|
|
694
|
-
this.endpoint =
|
|
695
|
-
this.supportedNetworks =
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
666
|
+
this.endpoint = CDP_URL;
|
|
667
|
+
this.supportedNetworks = [
|
|
668
|
+
"eip155:8453",
|
|
669
|
+
// Base mainnet
|
|
670
|
+
"eip155:137",
|
|
671
|
+
// Polygon mainnet
|
|
672
|
+
"eip155:84532"
|
|
673
|
+
// Base Sepolia (testnet)
|
|
674
|
+
];
|
|
675
|
+
if (!this.apiKeyId || !this.apiKeySecret) {
|
|
676
|
+
console.warn("[CDPFacilitator] WARNING: Missing CDP credentials!");
|
|
677
|
+
console.warn("[CDPFacilitator] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in ~/.moltspay/.env");
|
|
699
678
|
}
|
|
700
679
|
}
|
|
701
680
|
/**
|
|
702
681
|
* Get auth headers for CDP API requests
|
|
703
682
|
*/
|
|
704
683
|
async getAuthHeaders(method, urlPath, body) {
|
|
705
|
-
if (!this.useMainnet) {
|
|
706
|
-
return {};
|
|
707
|
-
}
|
|
708
684
|
if (!this.apiKeyId || !this.apiKeySecret) {
|
|
709
|
-
throw new Error("CDP credentials required
|
|
685
|
+
throw new Error("CDP credentials required. Set CDP_API_KEY_ID and CDP_API_KEY_SECRET");
|
|
710
686
|
}
|
|
711
687
|
try {
|
|
712
688
|
const { getAuthHeaders } = await import("@coinbase/cdp-sdk/auth");
|
|
@@ -758,23 +734,23 @@ var CDPFacilitator = class extends BaseFacilitator {
|
|
|
758
734
|
paymentPayload,
|
|
759
735
|
paymentRequirements: requirements
|
|
760
736
|
};
|
|
737
|
+
console.log("[CDP Verify] Payload:", JSON.stringify(paymentPayload, null, 2));
|
|
738
|
+
const authHeaders = await this.getAuthHeaders(
|
|
739
|
+
"POST",
|
|
740
|
+
"/platform/v2/x402/verify",
|
|
741
|
+
requestBody
|
|
742
|
+
);
|
|
761
743
|
const headers = {
|
|
762
|
-
"Content-Type": "application/json"
|
|
744
|
+
"Content-Type": "application/json",
|
|
745
|
+
...authHeaders
|
|
763
746
|
};
|
|
764
|
-
if (this.useMainnet) {
|
|
765
|
-
const authHeaders = await this.getAuthHeaders(
|
|
766
|
-
"POST",
|
|
767
|
-
"/platform/v2/x402/verify",
|
|
768
|
-
requestBody
|
|
769
|
-
);
|
|
770
|
-
Object.assign(headers, authHeaders);
|
|
771
|
-
}
|
|
772
747
|
const response = await fetch(`${this.endpoint}/verify`, {
|
|
773
748
|
method: "POST",
|
|
774
749
|
headers,
|
|
775
750
|
body: JSON.stringify(requestBody)
|
|
776
751
|
});
|
|
777
752
|
const result = await response.json();
|
|
753
|
+
console.log("[CDP Verify] Response:", response.status, JSON.stringify(result));
|
|
778
754
|
if (!response.ok || !result.isValid) {
|
|
779
755
|
return {
|
|
780
756
|
valid: false,
|
|
@@ -800,17 +776,15 @@ var CDPFacilitator = class extends BaseFacilitator {
|
|
|
800
776
|
paymentPayload,
|
|
801
777
|
paymentRequirements: requirements
|
|
802
778
|
};
|
|
779
|
+
const authHeaders = await this.getAuthHeaders(
|
|
780
|
+
"POST",
|
|
781
|
+
"/platform/v2/x402/settle",
|
|
782
|
+
requestBody
|
|
783
|
+
);
|
|
803
784
|
const headers = {
|
|
804
|
-
"Content-Type": "application/json"
|
|
785
|
+
"Content-Type": "application/json",
|
|
786
|
+
...authHeaders
|
|
805
787
|
};
|
|
806
|
-
if (this.useMainnet) {
|
|
807
|
-
const authHeaders = await this.getAuthHeaders(
|
|
808
|
-
"POST",
|
|
809
|
-
"/platform/v2/x402/settle",
|
|
810
|
-
requestBody
|
|
811
|
-
);
|
|
812
|
-
Object.assign(headers, authHeaders);
|
|
813
|
-
}
|
|
814
788
|
const response = await fetch(`${this.endpoint}/settle`, {
|
|
815
789
|
method: "POST",
|
|
816
790
|
headers,
|
|
@@ -845,13 +819,19 @@ var CDPFacilitator = class extends BaseFacilitator {
|
|
|
845
819
|
freeQuota: 1e3
|
|
846
820
|
};
|
|
847
821
|
}
|
|
822
|
+
/**
|
|
823
|
+
* Check if a chain ID is testnet
|
|
824
|
+
*/
|
|
825
|
+
static isTestnet(chainId) {
|
|
826
|
+
return TESTNET_CHAIN_IDS.includes(chainId);
|
|
827
|
+
}
|
|
848
828
|
/**
|
|
849
829
|
* Get configuration summary (for logging)
|
|
850
830
|
*/
|
|
851
831
|
getConfigSummary() {
|
|
852
|
-
const mode = this.useMainnet ? "mainnet" : "testnet";
|
|
853
832
|
const hasCredentials = !!(this.apiKeyId && this.apiKeySecret);
|
|
854
|
-
|
|
833
|
+
const networks = this.supportedNetworks.join(", ");
|
|
834
|
+
return `CDP Facilitator (networks: ${networks}, credentials: ${hasCredentials ? "yes" : "no"})`;
|
|
855
835
|
}
|
|
856
836
|
};
|
|
857
837
|
|
|
@@ -1109,9 +1089,27 @@ var CHAIN_TO_NETWORK = {
|
|
|
1109
1089
|
"polygon": "eip155:137"
|
|
1110
1090
|
};
|
|
1111
1091
|
var TOKEN_DOMAINS = {
|
|
1112
|
-
|
|
1113
|
-
|
|
1092
|
+
// Base mainnet
|
|
1093
|
+
"eip155:8453": {
|
|
1094
|
+
USDC: { name: "USD Coin", version: "2" },
|
|
1095
|
+
USDT: { name: "Tether USD", version: "2" }
|
|
1096
|
+
},
|
|
1097
|
+
// Base Sepolia testnet - USDC uses 'USDC' not 'USD Coin'
|
|
1098
|
+
"eip155:84532": {
|
|
1099
|
+
USDC: { name: "USDC", version: "2" },
|
|
1100
|
+
USDT: { name: "USDC", version: "2" }
|
|
1101
|
+
// Same contract as USDC on testnet
|
|
1102
|
+
},
|
|
1103
|
+
// Polygon mainnet
|
|
1104
|
+
"eip155:137": {
|
|
1105
|
+
USDC: { name: "USD Coin", version: "2" },
|
|
1106
|
+
USDT: { name: "(PoS) Tether USD", version: "2" }
|
|
1107
|
+
}
|
|
1114
1108
|
};
|
|
1109
|
+
function getTokenDomain(network, token) {
|
|
1110
|
+
const networkDomains = TOKEN_DOMAINS[network] || TOKEN_DOMAINS["eip155:8453"];
|
|
1111
|
+
return networkDomains[token] || { name: "USD Coin", version: "2" };
|
|
1112
|
+
}
|
|
1115
1113
|
function getAcceptedCurrencies(config) {
|
|
1116
1114
|
return config.acceptedCurrencies ?? [config.currency];
|
|
1117
1115
|
}
|
|
@@ -1205,11 +1203,14 @@ var MoltsPayServer = class {
|
|
|
1205
1203
|
getProviderChains() {
|
|
1206
1204
|
const provider = this.manifest.provider;
|
|
1207
1205
|
if (provider.chains && provider.chains.length > 0) {
|
|
1208
|
-
return provider.chains.map((c) =>
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1206
|
+
return provider.chains.map((c) => {
|
|
1207
|
+
const chainName = typeof c === "string" ? c : c.chain;
|
|
1208
|
+
return {
|
|
1209
|
+
network: CHAIN_TO_NETWORK[chainName] || "eip155:8453",
|
|
1210
|
+
wallet: (typeof c === "object" ? c.wallet : null) || provider.wallet,
|
|
1211
|
+
tokens: (typeof c === "object" ? c.tokens : null) || ["USDC"]
|
|
1212
|
+
};
|
|
1213
|
+
});
|
|
1213
1214
|
}
|
|
1214
1215
|
const chain = provider.chain || "base";
|
|
1215
1216
|
const network = CHAIN_TO_NETWORK[chain] || this.networkId;
|
|
@@ -1419,7 +1420,7 @@ var MoltsPayServer = class {
|
|
|
1419
1420
|
const paymentNetwork = payment.accepted?.network || payment.network || this.networkId;
|
|
1420
1421
|
const paymentWallet = this.getWalletForNetwork(paymentNetwork);
|
|
1421
1422
|
const requirements = this.buildPaymentRequirements(skill.config, paymentNetwork, paymentWallet, paymentToken);
|
|
1422
|
-
console.log(`[MoltsPay] Verifying payment...`);
|
|
1423
|
+
console.log(`[MoltsPay] Verifying payment on ${paymentNetwork}...`);
|
|
1423
1424
|
const verifyResult = await this.registry.verify(payment, requirements);
|
|
1424
1425
|
if (!verifyResult.valid) {
|
|
1425
1426
|
return this.sendJson(res, 402, {
|
|
@@ -1545,7 +1546,7 @@ var MoltsPayServer = class {
|
|
|
1545
1546
|
const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
|
|
1546
1547
|
const tokenAddresses = TOKEN_ADDRESSES[selectedNetwork] || {};
|
|
1547
1548
|
const tokenAddress = tokenAddresses[selectedToken];
|
|
1548
|
-
const tokenDomain =
|
|
1549
|
+
const tokenDomain = getTokenDomain(selectedNetwork, selectedToken);
|
|
1549
1550
|
return {
|
|
1550
1551
|
scheme: "exact",
|
|
1551
1552
|
network: selectedNetwork,
|
|
@@ -1790,7 +1791,7 @@ var MoltsPayServer = class {
|
|
|
1790
1791
|
const selectedToken = token && acceptedTokens.includes(token) ? token : acceptedTokens[0];
|
|
1791
1792
|
const tokenAddresses = TOKEN_ADDRESSES[networkId] || TOKEN_ADDRESSES[this.networkId] || {};
|
|
1792
1793
|
const tokenAddress = tokenAddresses[selectedToken];
|
|
1793
|
-
const tokenDomain =
|
|
1794
|
+
const tokenDomain = getTokenDomain(networkId, selectedToken);
|
|
1794
1795
|
return {
|
|
1795
1796
|
scheme: "exact",
|
|
1796
1797
|
network: networkId,
|
|
@@ -1872,6 +1873,11 @@ program.command("init").description("Initialize MoltsPay client (create wallet,
|
|
|
1872
1873
|
return;
|
|
1873
1874
|
}
|
|
1874
1875
|
let chain = options.chain;
|
|
1876
|
+
const supportedChains = ["base", "polygon", "base_sepolia"];
|
|
1877
|
+
if (!supportedChains.includes(chain)) {
|
|
1878
|
+
console.error(`\u274C Unknown chain: ${chain}. Supported: ${supportedChains.join(", ")}`);
|
|
1879
|
+
process.exit(1);
|
|
1880
|
+
}
|
|
1875
1881
|
let maxPerTx = options.maxPerTx ? parseFloat(options.maxPerTx) : null;
|
|
1876
1882
|
let maxPerDay = options.maxPerDay ? parseFloat(options.maxPerDay) : null;
|
|
1877
1883
|
if (!maxPerTx) {
|
|
@@ -1934,7 +1940,7 @@ program.command("config").description("Update MoltsPay settings").option("--max-
|
|
|
1934
1940
|
}
|
|
1935
1941
|
}
|
|
1936
1942
|
});
|
|
1937
|
-
program.command("fund <amount>").description("Fund wallet with USDC via Coinbase (US debit card / Apple Pay)").option("--chain <chain>", "Chain to fund (base or
|
|
1943
|
+
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) => {
|
|
1938
1944
|
const client = new MoltsPayClient({ configDir: options.configDir });
|
|
1939
1945
|
if (!client.isInitialized) {
|
|
1940
1946
|
console.log("\u274C Not initialized. Run: npx moltspay init");
|
|
@@ -1946,8 +1952,20 @@ program.command("fund <amount>").description("Fund wallet with USDC via Coinbase
|
|
|
1946
1952
|
return;
|
|
1947
1953
|
}
|
|
1948
1954
|
const chain = options.chain?.toLowerCase() || "base";
|
|
1949
|
-
if (!["base", "polygon"].includes(chain)) {
|
|
1950
|
-
console.log("\u274C Invalid chain. Use: base or
|
|
1955
|
+
if (!["base", "polygon", "base_sepolia"].includes(chain)) {
|
|
1956
|
+
console.log("\u274C Invalid chain. Use: base, polygon, or base_sepolia");
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
if (chain === "base_sepolia") {
|
|
1960
|
+
console.log("\n\u{1F9EA} Testnet Funding\n");
|
|
1961
|
+
console.log(` Wallet: ${client.address}`);
|
|
1962
|
+
console.log(` Chain: Base Sepolia (testnet)
|
|
1963
|
+
`);
|
|
1964
|
+
console.log("\u{1F4DD} Get testnet USDC from these faucets:");
|
|
1965
|
+
console.log(" \u2022 Circle Faucet: https://faucet.circle.com/");
|
|
1966
|
+
console.log(" \u2022 Base Sepolia: https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet\n");
|
|
1967
|
+
console.log(`\u{1F4A1} Send USDC to: ${client.address}
|
|
1968
|
+
`);
|
|
1951
1969
|
return;
|
|
1952
1970
|
}
|
|
1953
1971
|
console.log("\n\u{1F4B3} Fund your agent wallet\n");
|
|
@@ -1979,6 +1997,52 @@ program.command("fund <amount>").description("Fund wallet with USDC via Coinbase
|
|
|
1979
1997
|
console.log(`\u274C ${error.message}`);
|
|
1980
1998
|
}
|
|
1981
1999
|
});
|
|
2000
|
+
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) => {
|
|
2001
|
+
let address = options.address;
|
|
2002
|
+
if (!address) {
|
|
2003
|
+
const client = new MoltsPayClient({ configDir: options.configDir });
|
|
2004
|
+
if (client.isInitialized) {
|
|
2005
|
+
address = client.address;
|
|
2006
|
+
} else {
|
|
2007
|
+
console.log('\u274C No wallet found. Either run "npx moltspay init" or provide --address');
|
|
2008
|
+
return;
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
if (!address.match(/^0x[a-fA-F0-9]{40}$/)) {
|
|
2012
|
+
console.log("\u274C Invalid Ethereum address");
|
|
2013
|
+
return;
|
|
2014
|
+
}
|
|
2015
|
+
console.log("\n\u{1F6B0} MoltsPay Testnet Faucet\n");
|
|
2016
|
+
console.log(` Requesting 1 USDC on Base Sepolia...`);
|
|
2017
|
+
console.log(` Address: ${address}
|
|
2018
|
+
`);
|
|
2019
|
+
try {
|
|
2020
|
+
const FAUCET_API = process.env.MOLTSPAY_FAUCET_API || "https://moltspay.com/api/v1/faucet";
|
|
2021
|
+
const response = await fetch(FAUCET_API, {
|
|
2022
|
+
method: "POST",
|
|
2023
|
+
headers: { "Content-Type": "application/json" },
|
|
2024
|
+
body: JSON.stringify({ address })
|
|
2025
|
+
});
|
|
2026
|
+
const result = await response.json();
|
|
2027
|
+
if (!response.ok) {
|
|
2028
|
+
console.log(`\u274C ${result.error || "Request failed"}`);
|
|
2029
|
+
if (result.hint) console.log(` ${result.hint}`);
|
|
2030
|
+
if (result.retry_after) console.log(` Retry after: ${result.retry_after}`);
|
|
2031
|
+
return;
|
|
2032
|
+
}
|
|
2033
|
+
console.log(`\u2705 Received ${result.amount} USDC!
|
|
2034
|
+
`);
|
|
2035
|
+
console.log(` Transaction: ${result.transaction}`);
|
|
2036
|
+
console.log(` Explorer: ${result.explorer}`);
|
|
2037
|
+
console.log(` Faucet balance: ${result.faucet_balance} USDC remaining
|
|
2038
|
+
`);
|
|
2039
|
+
console.log("\u{1F4A1} Use this USDC to test x402 payments:");
|
|
2040
|
+
console.log(` npx moltspay pay <service-url> <service-id> --chain base_sepolia
|
|
2041
|
+
`);
|
|
2042
|
+
} catch (error) {
|
|
2043
|
+
console.log(`\u274C ${error.message}`);
|
|
2044
|
+
}
|
|
2045
|
+
});
|
|
1982
2046
|
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) => {
|
|
1983
2047
|
const client = new MoltsPayClient({ configDir: options.configDir });
|
|
1984
2048
|
if (!client.isInitialized) {
|
|
@@ -2018,7 +2082,7 @@ program.command("status").description("Show wallet status and balance").option("
|
|
|
2018
2082
|
console.log("");
|
|
2019
2083
|
}
|
|
2020
2084
|
});
|
|
2021
|
-
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) => {
|
|
2085
|
+
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) => {
|
|
2022
2086
|
const client = new MoltsPayClient({ configDir: options.configDir });
|
|
2023
2087
|
if (!client.isInitialized) {
|
|
2024
2088
|
console.log("\u274C Not initialized. Run: npx moltspay init");
|
|
@@ -2027,8 +2091,8 @@ program.command("list").description("List recent transactions").option("--days <
|
|
|
2027
2091
|
const days = parseInt(options.days) || 7;
|
|
2028
2092
|
const limit = parseInt(options.limit) || 20;
|
|
2029
2093
|
const chain = options.chain?.toLowerCase() || "all";
|
|
2030
|
-
if (!["base", "polygon", "all"].includes(chain)) {
|
|
2031
|
-
console.log("\u274C Invalid chain. Use: base, polygon, or all");
|
|
2094
|
+
if (!["base", "polygon", "base_sepolia", "all"].includes(chain)) {
|
|
2095
|
+
console.log("\u274C Invalid chain. Use: base, polygon, base_sepolia, or all");
|
|
2032
2096
|
return;
|
|
2033
2097
|
}
|
|
2034
2098
|
const wallet = client.address;
|
|
@@ -2043,9 +2107,14 @@ program.command("list").description("List recent transactions").option("--days <
|
|
|
2043
2107
|
api: "https://polygon.blockscout.com/api/v2",
|
|
2044
2108
|
usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
2045
2109
|
name: "Polygon"
|
|
2110
|
+
},
|
|
2111
|
+
base_sepolia: {
|
|
2112
|
+
api: "https://base-sepolia.blockscout.com/api/v2",
|
|
2113
|
+
usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
2114
|
+
name: "Base Sepolia"
|
|
2046
2115
|
}
|
|
2047
2116
|
};
|
|
2048
|
-
const chainsToQuery = chain === "all" ? ["base", "polygon"] : [chain];
|
|
2117
|
+
const chainsToQuery = chain === "all" ? ["base", "polygon", "base_sepolia"] : [chain];
|
|
2049
2118
|
console.log(`
|
|
2050
2119
|
\u{1F4DC} Transactions (last ${days} day${days > 1 ? "s" : ""})
|
|
2051
2120
|
`);
|
|
@@ -2342,7 +2411,7 @@ program.command("stop").description("Stop the running MoltsPay server").action(a
|
|
|
2342
2411
|
process.exit(1);
|
|
2343
2412
|
}
|
|
2344
2413
|
});
|
|
2345
|
-
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
|
|
2414
|
+
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) => {
|
|
2346
2415
|
const client = new MoltsPayClient();
|
|
2347
2416
|
if (!client.isInitialized) {
|
|
2348
2417
|
console.error("\u274C Wallet not initialized. Run: npx moltspay init");
|
|
@@ -2377,8 +2446,8 @@ program.command("pay <server> <service> [params]").description("Pay for a servic
|
|
|
2377
2446
|
process.exit(1);
|
|
2378
2447
|
}
|
|
2379
2448
|
const chain = options.chain?.toLowerCase();
|
|
2380
|
-
if (chain && !["base", "polygon"].includes(chain)) {
|
|
2381
|
-
console.error(`\u274C Unknown chain: ${chain}. Supported: base, polygon`);
|
|
2449
|
+
if (chain && !["base", "polygon", "base_sepolia"].includes(chain)) {
|
|
2450
|
+
console.error(`\u274C Unknown chain: ${chain}. Supported: base, polygon, base_sepolia`);
|
|
2382
2451
|
process.exit(1);
|
|
2383
2452
|
}
|
|
2384
2453
|
const imageDisplay = params.image_url || (params.image_base64 ? `[local file: ${options.image}]` : null);
|