moltspay 0.8.1 → 0.8.3
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/.env.example +10 -0
- package/dist/cli/index.js +141 -52
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +160 -65
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.js +237 -148
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +256 -167
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.d.mts +14 -5
- package/dist/server/index.d.ts +14 -5
- package/dist/server/index.js +151 -112
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +149 -113
- package/dist/server/index.mjs.map +1 -1
- package/package.json +3 -1
package/dist/server/index.d.mts
CHANGED
|
@@ -76,9 +76,14 @@ interface MoltsPayServerOptions {
|
|
|
76
76
|
/**
|
|
77
77
|
* MoltsPay Server - Payment infrastructure for AI Agents
|
|
78
78
|
*
|
|
79
|
-
*
|
|
79
|
+
* Supports both testnet (x402.org) and mainnet (CDP) facilitators.
|
|
80
80
|
* Server does NOT need private key - facilitator handles on-chain settlement.
|
|
81
81
|
*
|
|
82
|
+
* Environment variables (from ~/.moltspay/.env or process.env):
|
|
83
|
+
* USE_MAINNET=true - Use Base mainnet (requires CDP keys)
|
|
84
|
+
* CDP_API_KEY_ID=xxx - Coinbase Developer Platform API key ID
|
|
85
|
+
* CDP_API_KEY_SECRET=xxx - CDP API key secret
|
|
86
|
+
*
|
|
82
87
|
* Usage:
|
|
83
88
|
* const server = new MoltsPayServer('./moltspay.services.json');
|
|
84
89
|
* server.skill('text-to-video', async (params) => { ... });
|
|
@@ -89,7 +94,9 @@ declare class MoltsPayServer {
|
|
|
89
94
|
private manifest;
|
|
90
95
|
private skills;
|
|
91
96
|
private options;
|
|
97
|
+
private cdpConfig;
|
|
92
98
|
private facilitatorUrl;
|
|
99
|
+
private networkId;
|
|
93
100
|
constructor(servicesPath: string, options?: MoltsPayServerOptions);
|
|
94
101
|
/**
|
|
95
102
|
* Register a skill handler for a service
|
|
@@ -109,8 +116,6 @@ declare class MoltsPayServer {
|
|
|
109
116
|
private handleGetServices;
|
|
110
117
|
/**
|
|
111
118
|
* POST /execute - Execute service with x402 payment
|
|
112
|
-
* Body: { service: string, params: object }
|
|
113
|
-
* Header: X-Payment (optional - if missing, returns 402)
|
|
114
119
|
*/
|
|
115
120
|
private handleExecute;
|
|
116
121
|
/**
|
|
@@ -118,11 +123,15 @@ declare class MoltsPayServer {
|
|
|
118
123
|
*/
|
|
119
124
|
private sendPaymentRequired;
|
|
120
125
|
/**
|
|
121
|
-
* Basic payment validation
|
|
126
|
+
* Basic payment validation
|
|
122
127
|
*/
|
|
123
128
|
private validatePayment;
|
|
124
129
|
/**
|
|
125
|
-
*
|
|
130
|
+
* Build complete payment requirements for facilitator
|
|
131
|
+
*/
|
|
132
|
+
private buildPaymentRequirements;
|
|
133
|
+
/**
|
|
134
|
+
* Verify payment with facilitator (testnet or CDP)
|
|
126
135
|
*/
|
|
127
136
|
private verifyWithFacilitator;
|
|
128
137
|
/**
|
package/dist/server/index.d.ts
CHANGED
|
@@ -76,9 +76,14 @@ interface MoltsPayServerOptions {
|
|
|
76
76
|
/**
|
|
77
77
|
* MoltsPay Server - Payment infrastructure for AI Agents
|
|
78
78
|
*
|
|
79
|
-
*
|
|
79
|
+
* Supports both testnet (x402.org) and mainnet (CDP) facilitators.
|
|
80
80
|
* Server does NOT need private key - facilitator handles on-chain settlement.
|
|
81
81
|
*
|
|
82
|
+
* Environment variables (from ~/.moltspay/.env or process.env):
|
|
83
|
+
* USE_MAINNET=true - Use Base mainnet (requires CDP keys)
|
|
84
|
+
* CDP_API_KEY_ID=xxx - Coinbase Developer Platform API key ID
|
|
85
|
+
* CDP_API_KEY_SECRET=xxx - CDP API key secret
|
|
86
|
+
*
|
|
82
87
|
* Usage:
|
|
83
88
|
* const server = new MoltsPayServer('./moltspay.services.json');
|
|
84
89
|
* server.skill('text-to-video', async (params) => { ... });
|
|
@@ -89,7 +94,9 @@ declare class MoltsPayServer {
|
|
|
89
94
|
private manifest;
|
|
90
95
|
private skills;
|
|
91
96
|
private options;
|
|
97
|
+
private cdpConfig;
|
|
92
98
|
private facilitatorUrl;
|
|
99
|
+
private networkId;
|
|
93
100
|
constructor(servicesPath: string, options?: MoltsPayServerOptions);
|
|
94
101
|
/**
|
|
95
102
|
* Register a skill handler for a service
|
|
@@ -109,8 +116,6 @@ declare class MoltsPayServer {
|
|
|
109
116
|
private handleGetServices;
|
|
110
117
|
/**
|
|
111
118
|
* POST /execute - Execute service with x402 payment
|
|
112
|
-
* Body: { service: string, params: object }
|
|
113
|
-
* Header: X-Payment (optional - if missing, returns 402)
|
|
114
119
|
*/
|
|
115
120
|
private handleExecute;
|
|
116
121
|
/**
|
|
@@ -118,11 +123,15 @@ declare class MoltsPayServer {
|
|
|
118
123
|
*/
|
|
119
124
|
private sendPaymentRequired;
|
|
120
125
|
/**
|
|
121
|
-
* Basic payment validation
|
|
126
|
+
* Basic payment validation
|
|
122
127
|
*/
|
|
123
128
|
private validatePayment;
|
|
124
129
|
/**
|
|
125
|
-
*
|
|
130
|
+
* Build complete payment requirements for facilitator
|
|
131
|
+
*/
|
|
132
|
+
private buildPaymentRequirements;
|
|
133
|
+
/**
|
|
134
|
+
* Verify payment with facilitator (testnet or CDP)
|
|
126
135
|
*/
|
|
127
136
|
private verifyWithFacilitator;
|
|
128
137
|
/**
|
package/dist/server/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/server/index.ts
|
|
@@ -25,88 +35,105 @@ __export(server_exports, {
|
|
|
25
35
|
module.exports = __toCommonJS(server_exports);
|
|
26
36
|
var import_fs = require("fs");
|
|
27
37
|
var import_http = require("http");
|
|
28
|
-
|
|
29
|
-
// src/chains/index.ts
|
|
30
|
-
var CHAINS = {
|
|
31
|
-
// ============ Mainnet ============
|
|
32
|
-
base: {
|
|
33
|
-
name: "Base",
|
|
34
|
-
chainId: 8453,
|
|
35
|
-
rpc: "https://mainnet.base.org",
|
|
36
|
-
usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
37
|
-
explorer: "https://basescan.org/address/",
|
|
38
|
-
explorerTx: "https://basescan.org/tx/",
|
|
39
|
-
avgBlockTime: 2
|
|
40
|
-
},
|
|
41
|
-
polygon: {
|
|
42
|
-
name: "Polygon",
|
|
43
|
-
chainId: 137,
|
|
44
|
-
rpc: "https://polygon-rpc.com",
|
|
45
|
-
usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
46
|
-
explorer: "https://polygonscan.com/address/",
|
|
47
|
-
explorerTx: "https://polygonscan.com/tx/",
|
|
48
|
-
avgBlockTime: 2
|
|
49
|
-
},
|
|
50
|
-
ethereum: {
|
|
51
|
-
name: "Ethereum",
|
|
52
|
-
chainId: 1,
|
|
53
|
-
rpc: "https://eth.llamarpc.com",
|
|
54
|
-
usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
55
|
-
explorer: "https://etherscan.io/address/",
|
|
56
|
-
explorerTx: "https://etherscan.io/tx/",
|
|
57
|
-
avgBlockTime: 12
|
|
58
|
-
},
|
|
59
|
-
// ============ Testnet ============
|
|
60
|
-
base_sepolia: {
|
|
61
|
-
name: "Base Sepolia",
|
|
62
|
-
chainId: 84532,
|
|
63
|
-
rpc: "https://sepolia.base.org",
|
|
64
|
-
usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
65
|
-
explorer: "https://sepolia.basescan.org/address/",
|
|
66
|
-
explorerTx: "https://sepolia.basescan.org/tx/",
|
|
67
|
-
avgBlockTime: 2
|
|
68
|
-
},
|
|
69
|
-
sepolia: {
|
|
70
|
-
name: "Sepolia",
|
|
71
|
-
chainId: 11155111,
|
|
72
|
-
rpc: "https://rpc.sepolia.org",
|
|
73
|
-
usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
74
|
-
explorer: "https://sepolia.etherscan.io/address/",
|
|
75
|
-
explorerTx: "https://sepolia.etherscan.io/tx/",
|
|
76
|
-
avgBlockTime: 12
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
function getChain(name) {
|
|
80
|
-
const config = CHAINS[name];
|
|
81
|
-
if (!config) {
|
|
82
|
-
throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(", ")}`);
|
|
83
|
-
}
|
|
84
|
-
return config;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// src/server/index.ts
|
|
38
|
+
var path = __toESM(require("path"));
|
|
88
39
|
var X402_VERSION = 2;
|
|
89
40
|
var PAYMENT_REQUIRED_HEADER = "x-payment-required";
|
|
90
41
|
var PAYMENT_HEADER = "x-payment";
|
|
91
42
|
var PAYMENT_RESPONSE_HEADER = "x-payment-response";
|
|
92
|
-
var
|
|
43
|
+
var FACILITATOR_TESTNET = "https://www.x402.org/facilitator";
|
|
44
|
+
var FACILITATOR_MAINNET = "https://api.cdp.coinbase.com/platform/v2/x402";
|
|
45
|
+
var USDC_ADDRESSES = {
|
|
46
|
+
"eip155:8453": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
47
|
+
// Base mainnet
|
|
48
|
+
"eip155:84532": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
|
|
49
|
+
// Base Sepolia
|
|
50
|
+
};
|
|
51
|
+
var USDC_DOMAIN = {
|
|
52
|
+
name: "USD Coin",
|
|
53
|
+
version: "2"
|
|
54
|
+
};
|
|
55
|
+
function loadEnvFiles() {
|
|
56
|
+
try {
|
|
57
|
+
const dotenv = require("dotenv");
|
|
58
|
+
const envPaths = [
|
|
59
|
+
path.join(process.cwd(), ".env"),
|
|
60
|
+
path.join(process.env.HOME || "", ".moltspay", ".env")
|
|
61
|
+
];
|
|
62
|
+
for (const envPath of envPaths) {
|
|
63
|
+
if ((0, import_fs.existsSync)(envPath)) {
|
|
64
|
+
dotenv.config({ path: envPath });
|
|
65
|
+
console.log(`[MoltsPay] Loaded config from ${envPath}`);
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function getCDPConfig() {
|
|
73
|
+
loadEnvFiles();
|
|
74
|
+
return {
|
|
75
|
+
useMainnet: process.env.USE_MAINNET?.toLowerCase() === "true",
|
|
76
|
+
apiKeyId: process.env.CDP_API_KEY_ID,
|
|
77
|
+
apiKeySecret: process.env.CDP_API_KEY_SECRET
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function getCDPAuthHeaders(method, urlPath, body) {
|
|
81
|
+
const config = getCDPConfig();
|
|
82
|
+
if (!config.apiKeyId || !config.apiKeySecret) {
|
|
83
|
+
throw new Error("CDP_API_KEY_ID and CDP_API_KEY_SECRET required for mainnet");
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const { getAuthHeaders } = await import("@coinbase/cdp-sdk/auth");
|
|
87
|
+
const headers = await getAuthHeaders({
|
|
88
|
+
apiKeyId: config.apiKeyId,
|
|
89
|
+
apiKeySecret: config.apiKeySecret,
|
|
90
|
+
requestMethod: method,
|
|
91
|
+
requestHost: "api.cdp.coinbase.com",
|
|
92
|
+
requestPath: urlPath,
|
|
93
|
+
requestBody: body
|
|
94
|
+
});
|
|
95
|
+
return headers;
|
|
96
|
+
} catch (err) {
|
|
97
|
+
console.error("[MoltsPay] Failed to generate CDP auth headers:", err.message);
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
93
101
|
var MoltsPayServer = class {
|
|
94
102
|
manifest;
|
|
95
103
|
skills = /* @__PURE__ */ new Map();
|
|
96
104
|
options;
|
|
105
|
+
cdpConfig;
|
|
97
106
|
facilitatorUrl;
|
|
107
|
+
networkId;
|
|
98
108
|
constructor(servicesPath, options = {}) {
|
|
109
|
+
this.cdpConfig = getCDPConfig();
|
|
99
110
|
const content = (0, import_fs.readFileSync)(servicesPath, "utf-8");
|
|
100
111
|
this.manifest = JSON.parse(content);
|
|
101
112
|
this.options = {
|
|
102
113
|
port: options.port || 3e3,
|
|
103
114
|
host: options.host || "0.0.0.0"
|
|
104
115
|
};
|
|
105
|
-
this.
|
|
116
|
+
if (this.cdpConfig.useMainnet) {
|
|
117
|
+
if (!this.cdpConfig.apiKeyId || !this.cdpConfig.apiKeySecret) {
|
|
118
|
+
console.warn("[MoltsPay] WARNING: USE_MAINNET=true but CDP keys not set!");
|
|
119
|
+
console.warn("[MoltsPay] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in ~/.moltspay/.env");
|
|
120
|
+
}
|
|
121
|
+
this.facilitatorUrl = FACILITATOR_MAINNET;
|
|
122
|
+
this.networkId = "eip155:8453";
|
|
123
|
+
} else {
|
|
124
|
+
this.facilitatorUrl = options.facilitatorUrl || FACILITATOR_TESTNET;
|
|
125
|
+
this.networkId = "eip155:84532";
|
|
126
|
+
}
|
|
127
|
+
const networkName = this.cdpConfig.useMainnet ? "Base mainnet" : "Base Sepolia (testnet)";
|
|
128
|
+
const facilitatorName = this.cdpConfig.useMainnet ? "CDP" : "x402.org";
|
|
106
129
|
console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);
|
|
107
130
|
console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);
|
|
108
131
|
console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);
|
|
109
|
-
console.log(`[MoltsPay]
|
|
132
|
+
console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);
|
|
133
|
+
console.log(`[MoltsPay] Facilitator: ${facilitatorName} (${this.facilitatorUrl})`);
|
|
134
|
+
if (this.cdpConfig.useMainnet && this.cdpConfig.apiKeyId) {
|
|
135
|
+
console.log(`[MoltsPay] CDP API Key: ${this.cdpConfig.apiKeyId.slice(0, 8)}...`);
|
|
136
|
+
}
|
|
110
137
|
console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);
|
|
111
138
|
}
|
|
112
139
|
/**
|
|
@@ -167,7 +194,6 @@ var MoltsPayServer = class {
|
|
|
167
194
|
* GET /services - List available services
|
|
168
195
|
*/
|
|
169
196
|
handleGetServices(res) {
|
|
170
|
-
const chain = getChain(this.manifest.provider.chain);
|
|
171
197
|
const services = this.manifest.services.map((s) => ({
|
|
172
198
|
id: s.id,
|
|
173
199
|
name: s.name,
|
|
@@ -183,16 +209,15 @@ var MoltsPayServer = class {
|
|
|
183
209
|
services,
|
|
184
210
|
x402: {
|
|
185
211
|
version: X402_VERSION,
|
|
186
|
-
network:
|
|
212
|
+
network: this.networkId,
|
|
187
213
|
schemes: ["exact"],
|
|
188
|
-
facilitator: this.
|
|
214
|
+
facilitator: this.cdpConfig.useMainnet ? "cdp" : "x402.org",
|
|
215
|
+
mainnet: this.cdpConfig.useMainnet
|
|
189
216
|
}
|
|
190
217
|
});
|
|
191
218
|
}
|
|
192
219
|
/**
|
|
193
220
|
* POST /execute - Execute service with x402 payment
|
|
194
|
-
* Body: { service: string, params: object }
|
|
195
|
-
* Header: X-Payment (optional - if missing, returns 402)
|
|
196
221
|
*/
|
|
197
222
|
async handleExecute(body, paymentHeader, res) {
|
|
198
223
|
const { service, params } = body;
|
|
@@ -267,17 +292,8 @@ var MoltsPayServer = class {
|
|
|
267
292
|
* Return 402 with x402 payment requirements
|
|
268
293
|
*/
|
|
269
294
|
sendPaymentRequired(config, res) {
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
const requirements = [{
|
|
273
|
-
scheme: "exact",
|
|
274
|
-
network: `eip155:${chain.chainId}`,
|
|
275
|
-
maxAmountRequired: amountInUnits,
|
|
276
|
-
resource: this.manifest.provider.wallet,
|
|
277
|
-
description: `${config.name} - $${config.price} ${config.currency}`,
|
|
278
|
-
// Include facilitator info for client
|
|
279
|
-
extra: JSON.stringify({ facilitator: this.facilitatorUrl })
|
|
280
|
-
}];
|
|
295
|
+
const requirements = [this.buildPaymentRequirements(config)];
|
|
296
|
+
requirements[0].description = `${config.name} - $${config.price} ${config.currency}`;
|
|
281
297
|
const encoded = Buffer.from(JSON.stringify(requirements)).toString("base64");
|
|
282
298
|
res.writeHead(402, {
|
|
283
299
|
"Content-Type": "application/json",
|
|
@@ -290,7 +306,7 @@ var MoltsPayServer = class {
|
|
|
290
306
|
}, null, 2));
|
|
291
307
|
}
|
|
292
308
|
/**
|
|
293
|
-
* Basic payment validation
|
|
309
|
+
* Basic payment validation
|
|
294
310
|
*/
|
|
295
311
|
validatePayment(payment, config) {
|
|
296
312
|
if (payment.x402Version !== X402_VERSION) {
|
|
@@ -299,37 +315,57 @@ var MoltsPayServer = class {
|
|
|
299
315
|
if (payment.scheme !== "exact") {
|
|
300
316
|
return { valid: false, error: `Unsupported scheme: ${payment.scheme}` };
|
|
301
317
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (payment.network !== expectedNetwork) {
|
|
305
|
-
return { valid: false, error: `Network mismatch: expected ${expectedNetwork}` };
|
|
318
|
+
if (payment.network !== this.networkId) {
|
|
319
|
+
return { valid: false, error: `Network mismatch: expected ${this.networkId}, got ${payment.network}` };
|
|
306
320
|
}
|
|
307
321
|
return { valid: true };
|
|
308
322
|
}
|
|
309
323
|
/**
|
|
310
|
-
*
|
|
324
|
+
* Build complete payment requirements for facilitator
|
|
325
|
+
*/
|
|
326
|
+
buildPaymentRequirements(config) {
|
|
327
|
+
const amountInUnits = Math.floor(config.price * 1e6).toString();
|
|
328
|
+
const usdcAddress = USDC_ADDRESSES[this.networkId];
|
|
329
|
+
return {
|
|
330
|
+
scheme: "exact",
|
|
331
|
+
network: this.networkId,
|
|
332
|
+
maxAmountRequired: amountInUnits,
|
|
333
|
+
amount: amountInUnits,
|
|
334
|
+
asset: usdcAddress,
|
|
335
|
+
payTo: this.manifest.provider.wallet,
|
|
336
|
+
maxTimeoutSeconds: 300,
|
|
337
|
+
extra: USDC_DOMAIN
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Verify payment with facilitator (testnet or CDP)
|
|
311
342
|
*/
|
|
312
343
|
async verifyWithFacilitator(payment, config) {
|
|
313
344
|
try {
|
|
314
|
-
const
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
network: `eip155:${chain.chainId}`,
|
|
319
|
-
maxAmountRequired: amountInUnits,
|
|
320
|
-
resource: this.manifest.provider.wallet
|
|
345
|
+
const requirements = this.buildPaymentRequirements(config);
|
|
346
|
+
const requestBody = {
|
|
347
|
+
paymentPayload: payment,
|
|
348
|
+
paymentRequirements: requirements
|
|
321
349
|
};
|
|
350
|
+
console.log("[MoltsPay] Verify request:", JSON.stringify(requestBody, null, 2));
|
|
351
|
+
let headers = { "Content-Type": "application/json" };
|
|
352
|
+
if (this.cdpConfig.useMainnet) {
|
|
353
|
+
const authHeaders = await getCDPAuthHeaders(
|
|
354
|
+
"POST",
|
|
355
|
+
"/platform/v2/x402/verify",
|
|
356
|
+
requestBody
|
|
357
|
+
);
|
|
358
|
+
headers = { ...headers, ...authHeaders };
|
|
359
|
+
}
|
|
322
360
|
const response = await fetch(`${this.facilitatorUrl}/verify`, {
|
|
323
361
|
method: "POST",
|
|
324
|
-
headers
|
|
325
|
-
body: JSON.stringify(
|
|
326
|
-
paymentPayload: payment,
|
|
327
|
-
paymentRequirements: requirements
|
|
328
|
-
})
|
|
362
|
+
headers,
|
|
363
|
+
body: JSON.stringify(requestBody)
|
|
329
364
|
});
|
|
330
365
|
const result = await response.json();
|
|
366
|
+
console.log("[MoltsPay] Verify response:", JSON.stringify(result, null, 2));
|
|
331
367
|
if (!response.ok || !result.isValid) {
|
|
332
|
-
return { valid: false, error: result.invalidReason || "Verification failed" };
|
|
368
|
+
return { valid: false, error: result.invalidReason || result.error || "Verification failed" };
|
|
333
369
|
}
|
|
334
370
|
return { valid: true };
|
|
335
371
|
} catch (err) {
|
|
@@ -340,25 +376,28 @@ var MoltsPayServer = class {
|
|
|
340
376
|
* Settle payment with facilitator (execute on-chain transfer)
|
|
341
377
|
*/
|
|
342
378
|
async settleWithFacilitator(payment, config) {
|
|
343
|
-
const
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
network: `eip155:${chain.chainId}`,
|
|
348
|
-
maxAmountRequired: amountInUnits,
|
|
349
|
-
resource: this.manifest.provider.wallet
|
|
379
|
+
const requirements = this.buildPaymentRequirements(config);
|
|
380
|
+
const requestBody = {
|
|
381
|
+
paymentPayload: payment,
|
|
382
|
+
paymentRequirements: requirements
|
|
350
383
|
};
|
|
384
|
+
let headers = { "Content-Type": "application/json" };
|
|
385
|
+
if (this.cdpConfig.useMainnet) {
|
|
386
|
+
const authHeaders = await getCDPAuthHeaders(
|
|
387
|
+
"POST",
|
|
388
|
+
"/platform/v2/x402/settle",
|
|
389
|
+
requestBody
|
|
390
|
+
);
|
|
391
|
+
headers = { ...headers, ...authHeaders };
|
|
392
|
+
}
|
|
351
393
|
const response = await fetch(`${this.facilitatorUrl}/settle`, {
|
|
352
394
|
method: "POST",
|
|
353
|
-
headers
|
|
354
|
-
body: JSON.stringify(
|
|
355
|
-
paymentPayload: payment,
|
|
356
|
-
paymentRequirements: requirements
|
|
357
|
-
})
|
|
395
|
+
headers,
|
|
396
|
+
body: JSON.stringify(requestBody)
|
|
358
397
|
});
|
|
359
398
|
const result = await response.json();
|
|
360
|
-
if (!response.ok) {
|
|
361
|
-
throw new Error(result.error || "Settlement failed");
|
|
399
|
+
if (!response.ok || !result.success) {
|
|
400
|
+
throw new Error(result.error || result.errorReason || "Settlement failed");
|
|
362
401
|
}
|
|
363
402
|
return {
|
|
364
403
|
transaction: result.transaction,
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/index.ts","../../src/chains/index.ts"],"sourcesContent":["/**\n * MoltsPay Server - Payment infrastructure for AI Agents\n * \n * Uses x402 protocol with public facilitator (https://x402.org/facilitator).\n * Server does NOT need private key - facilitator handles on-chain settlement.\n * \n * Usage:\n * const server = new MoltsPayServer('./moltspay.services.json');\n * server.skill('text-to-video', async (params) => { ... });\n * server.listen(3000);\n */\n\nimport { readFileSync } from 'fs';\nimport { createServer, IncomingMessage, ServerResponse } from 'http';\nimport { getChain } from '../chains/index.js';\nimport type { ChainName } from '../chains/index.js';\nimport {\n ServicesManifest,\n ServiceConfig,\n SkillFunction,\n RegisteredSkill,\n MoltsPayServerOptions,\n} from './types.js';\n\nexport * from './types.js';\n\n// x402 constants\nconst X402_VERSION = 2;\nconst PAYMENT_REQUIRED_HEADER = 'x-payment-required';\nconst PAYMENT_HEADER = 'x-payment';\nconst PAYMENT_RESPONSE_HEADER = 'x-payment-response';\n\n// Default facilitator URL\nconst DEFAULT_FACILITATOR_URL = 'https://x402.org/facilitator';\n\ninterface X402PaymentPayload {\n x402Version: number;\n scheme: string;\n network: string;\n payload: any;\n}\n\nexport class MoltsPayServer {\n private manifest: ServicesManifest;\n private skills: Map<string, RegisteredSkill> = new Map();\n private options: MoltsPayServerOptions;\n private facilitatorUrl: string;\n\n constructor(servicesPath: string, options: MoltsPayServerOptions = {}) {\n // Load services manifest\n const content = readFileSync(servicesPath, 'utf-8');\n this.manifest = JSON.parse(content) as ServicesManifest;\n \n this.options = {\n port: options.port || 3000,\n host: options.host || '0.0.0.0',\n };\n\n this.facilitatorUrl = options.facilitatorUrl || DEFAULT_FACILITATOR_URL;\n\n console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);\n console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);\n console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);\n console.log(`[MoltsPay] Facilitator: ${this.facilitatorUrl}`);\n console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);\n }\n\n /**\n * Register a skill handler for a service\n */\n skill(serviceId: string, handler: SkillFunction): this {\n const config = this.manifest.services.find(s => s.id === serviceId);\n if (!config) {\n throw new Error(`Service '${serviceId}' not found in manifest`);\n }\n this.skills.set(serviceId, { id: serviceId, config, handler });\n return this;\n }\n\n /**\n * Start HTTP server\n */\n listen(port?: number): void {\n const p = port || this.options.port || 3000;\n const host = this.options.host || '0.0.0.0';\n\n const server = createServer((req, res) => this.handleRequest(req, res));\n server.listen(p, host, () => {\n console.log(`[MoltsPay] Server listening on http://${host}:${p}`);\n console.log(`[MoltsPay] Endpoints:`);\n console.log(` GET /services - List available services`);\n console.log(` POST /execute - Execute service (x402 payment)`);\n });\n }\n\n /**\n * Handle incoming request\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // CORS\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Payment');\n res.setHeader('Access-Control-Expose-Headers', 'X-Payment-Required, X-Payment-Response');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n const url = new URL(req.url || '/', `http://${req.headers.host}`);\n \n if (url.pathname === '/services' && req.method === 'GET') {\n return this.handleGetServices(res);\n }\n\n if (url.pathname === '/execute' && req.method === 'POST') {\n const body = await this.readBody(req);\n const paymentHeader = req.headers[PAYMENT_HEADER] as string | undefined;\n return await this.handleExecute(body, paymentHeader, res);\n }\n\n // Not found\n this.sendJson(res, 404, { error: 'Not found' });\n } catch (err: any) {\n console.error('[MoltsPay] Error:', err);\n this.sendJson(res, 500, { error: err.message || 'Internal error' });\n }\n }\n\n /**\n * GET /services - List available services\n */\n private handleGetServices(res: ServerResponse): void {\n const chain = getChain(this.manifest.provider.chain as ChainName);\n \n const services = this.manifest.services.map(s => ({\n id: s.id,\n name: s.name,\n description: s.description,\n price: s.price,\n currency: s.currency,\n input: s.input,\n output: s.output,\n available: this.skills.has(s.id),\n }));\n\n this.sendJson(res, 200, {\n provider: this.manifest.provider,\n services,\n x402: {\n version: X402_VERSION,\n network: `eip155:${chain.chainId}`,\n schemes: ['exact'],\n facilitator: this.facilitatorUrl,\n },\n });\n }\n\n /**\n * POST /execute - Execute service with x402 payment\n * Body: { service: string, params: object }\n * Header: X-Payment (optional - if missing, returns 402)\n */\n private async handleExecute(\n body: any,\n paymentHeader: string | undefined,\n res: ServerResponse\n ): Promise<void> {\n const { service, params } = body;\n\n if (!service) {\n return this.sendJson(res, 400, { error: 'Missing service' });\n }\n\n const skill = this.skills.get(service);\n if (!skill) {\n return this.sendJson(res, 404, { error: `Service '${service}' not found or not registered` });\n }\n\n // Validate required params\n for (const [key, field] of Object.entries(skill.config.input)) {\n if (field.required && (!params || params[key] === undefined)) {\n return this.sendJson(res, 400, { error: `Missing required param: ${key}` });\n }\n }\n\n // If no payment header, return 402 with payment requirements\n if (!paymentHeader) {\n return this.sendPaymentRequired(skill.config, res);\n }\n\n // Parse payment payload\n let payment: X402PaymentPayload;\n try {\n const decoded = Buffer.from(paymentHeader, 'base64').toString('utf-8');\n payment = JSON.parse(decoded);\n } catch {\n return this.sendJson(res, 400, { error: 'Invalid X-Payment header' });\n }\n\n // Validate basic payment fields\n const validation = this.validatePayment(payment, skill.config);\n if (!validation.valid) {\n return this.sendJson(res, 402, { error: validation.error });\n }\n\n // Verify payment with facilitator\n console.log(`[MoltsPay] Verifying payment with facilitator...`);\n const verifyResult = await this.verifyWithFacilitator(payment, skill.config);\n if (!verifyResult.valid) {\n return this.sendJson(res, 402, { error: `Payment verification failed: ${verifyResult.error}` });\n }\n\n // Execute skill FIRST (pay-for-success)\n console.log(`[MoltsPay] Executing skill: ${service}`);\n let result: any;\n try {\n result = await skill.handler(params || {});\n } catch (err: any) {\n console.error('[MoltsPay] Skill execution failed:', err.message);\n // Don't settle payment if skill fails\n return this.sendJson(res, 500, {\n error: 'Service execution failed',\n message: err.message,\n });\n }\n\n // Skill succeeded - now settle payment with facilitator\n console.log(`[MoltsPay] Skill succeeded, settling payment...`);\n let settlement: any = null;\n try {\n settlement = await this.settleWithFacilitator(payment, skill.config);\n console.log(`[MoltsPay] Payment settled: ${settlement.transaction || 'pending'}`);\n } catch (err: any) {\n console.error('[MoltsPay] Settlement failed:', err.message);\n // Still return result - facilitator may settle later\n }\n\n // Build response with settlement info\n const responseHeaders: Record<string, string> = {};\n if (settlement) {\n const responsePayload = {\n success: true,\n transaction: settlement.transaction,\n network: payment.network,\n };\n responseHeaders[PAYMENT_RESPONSE_HEADER] = Buffer.from(\n JSON.stringify(responsePayload)\n ).toString('base64');\n }\n\n this.sendJson(res, 200, {\n success: true,\n result,\n payment: settlement \n ? { transaction: settlement.transaction, status: 'settled' }\n : { status: 'pending' },\n }, responseHeaders);\n }\n\n /**\n * Return 402 with x402 payment requirements\n */\n private sendPaymentRequired(config: ServiceConfig, res: ServerResponse): void {\n const chain = getChain(this.manifest.provider.chain as ChainName);\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n\n const requirements = [{\n scheme: 'exact',\n network: `eip155:${chain.chainId}`,\n maxAmountRequired: amountInUnits,\n resource: this.manifest.provider.wallet,\n description: `${config.name} - $${config.price} ${config.currency}`,\n // Include facilitator info for client\n extra: JSON.stringify({ facilitator: this.facilitatorUrl }),\n }];\n\n const encoded = Buffer.from(JSON.stringify(requirements)).toString('base64');\n\n res.writeHead(402, {\n 'Content-Type': 'application/json',\n [PAYMENT_REQUIRED_HEADER]: encoded,\n });\n res.end(JSON.stringify({\n error: 'Payment required',\n message: `Service requires $${config.price} ${config.currency}`,\n x402: requirements[0],\n }, null, 2));\n }\n\n /**\n * Basic payment validation (before calling facilitator)\n */\n private validatePayment(\n payment: X402PaymentPayload,\n config: ServiceConfig\n ): { valid: boolean; error?: string } {\n if (payment.x402Version !== X402_VERSION) {\n return { valid: false, error: `Unsupported x402 version: ${payment.x402Version}` };\n }\n\n if (payment.scheme !== 'exact') {\n return { valid: false, error: `Unsupported scheme: ${payment.scheme}` };\n }\n\n const chain = getChain(this.manifest.provider.chain as ChainName);\n const expectedNetwork = `eip155:${chain.chainId}`;\n if (payment.network !== expectedNetwork) {\n return { valid: false, error: `Network mismatch: expected ${expectedNetwork}` };\n }\n\n return { valid: true };\n }\n\n /**\n * Verify payment with facilitator\n */\n private async verifyWithFacilitator(\n payment: X402PaymentPayload,\n config: ServiceConfig\n ): Promise<{ valid: boolean; error?: string }> {\n try {\n const chain = getChain(this.manifest.provider.chain as ChainName);\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n\n const requirements = {\n scheme: 'exact',\n network: `eip155:${chain.chainId}`,\n maxAmountRequired: amountInUnits,\n resource: this.manifest.provider.wallet,\n };\n\n const response = await fetch(`${this.facilitatorUrl}/verify`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n paymentPayload: payment,\n paymentRequirements: requirements,\n }),\n });\n\n const result = await response.json() as any;\n\n if (!response.ok || !result.isValid) {\n return { valid: false, error: result.invalidReason || 'Verification failed' };\n }\n\n return { valid: true };\n } catch (err: any) {\n return { valid: false, error: `Facilitator error: ${err.message}` };\n }\n }\n\n /**\n * Settle payment with facilitator (execute on-chain transfer)\n */\n private async settleWithFacilitator(\n payment: X402PaymentPayload,\n config: ServiceConfig\n ): Promise<{ transaction?: string; status: string }> {\n const chain = getChain(this.manifest.provider.chain as ChainName);\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n\n const requirements = {\n scheme: 'exact',\n network: `eip155:${chain.chainId}`,\n maxAmountRequired: amountInUnits,\n resource: this.manifest.provider.wallet,\n };\n\n const response = await fetch(`${this.facilitatorUrl}/settle`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n paymentPayload: payment,\n paymentRequirements: requirements,\n }),\n });\n\n const result = await response.json() as any;\n\n if (!response.ok) {\n throw new Error(result.error || 'Settlement failed');\n }\n\n return {\n transaction: result.transaction,\n status: result.status || 'settled',\n };\n }\n\n private async readBody(req: IncomingMessage): Promise<any> {\n return new Promise((resolve, reject) => {\n let body = '';\n req.on('data', chunk => body += chunk);\n req.on('end', () => {\n try {\n resolve(body ? JSON.parse(body) : {});\n } catch {\n reject(new Error('Invalid JSON'));\n }\n });\n req.on('error', reject);\n });\n }\n\n private sendJson(\n res: ServerResponse, \n status: number, \n data: any,\n extraHeaders?: Record<string, string>\n ): void {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (extraHeaders) {\n Object.assign(headers, extraHeaders);\n }\n res.writeHead(status, headers);\n res.end(JSON.stringify(data, null, 2));\n }\n}\n","/**\n * Blockchain Configuration\n */\n\nimport type { ChainConfig, ChainName } from '../types/index.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n // ============ Mainnet ============\n base: {\n name: 'Base',\n chainId: 8453,\n rpc: 'https://mainnet.base.org',\n usdc: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n explorer: 'https://basescan.org/address/',\n explorerTx: 'https://basescan.org/tx/',\n avgBlockTime: 2,\n },\n polygon: {\n name: 'Polygon',\n chainId: 137,\n rpc: 'https://polygon-rpc.com',\n usdc: '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359',\n explorer: 'https://polygonscan.com/address/',\n explorerTx: 'https://polygonscan.com/tx/',\n avgBlockTime: 2,\n },\n ethereum: {\n name: 'Ethereum',\n chainId: 1,\n rpc: 'https://eth.llamarpc.com',\n usdc: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',\n explorer: 'https://etherscan.io/address/',\n explorerTx: 'https://etherscan.io/tx/',\n avgBlockTime: 12,\n },\n\n // ============ Testnet ============\n base_sepolia: {\n name: 'Base Sepolia',\n chainId: 84532,\n rpc: 'https://sepolia.base.org',\n usdc: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',\n explorer: 'https://sepolia.basescan.org/address/',\n explorerTx: 'https://sepolia.basescan.org/tx/',\n avgBlockTime: 2,\n },\n sepolia: {\n name: 'Sepolia',\n chainId: 11155111,\n rpc: 'https://rpc.sepolia.org',\n usdc: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',\n explorer: 'https://sepolia.etherscan.io/address/',\n explorerTx: 'https://sepolia.etherscan.io/tx/',\n avgBlockTime: 12,\n },\n};\n\n/**\n * Get chain configuration\n */\nexport function getChain(name: ChainName): ChainConfig {\n const config = CHAINS[name];\n if (!config) {\n throw new Error(`Unsupported chain: ${name}. Supported: ${Object.keys(CHAINS).join(', ')}`);\n }\n return config;\n}\n\n/**\n * List all supported chains\n */\nexport function listChains(): ChainName[] {\n return Object.keys(CHAINS) as ChainName[];\n}\n\n/**\n * Get chain config by chainId\n */\nexport function getChainById(chainId: number): ChainConfig | undefined {\n return Object.values(CHAINS).find(c => c.chainId === chainId);\n}\n\n/**\n * ERC20 ABI (minimal, only required methods)\n */\nexport const ERC20_ABI = [\n 'function balanceOf(address owner) view returns (uint256)',\n 'function transfer(address to, uint256 amount) returns (bool)',\n 'function approve(address spender, uint256 amount) returns (bool)',\n 'function allowance(address owner, address spender) view returns (uint256)',\n 'function decimals() view returns (uint8)',\n 'function symbol() view returns (string)',\n 'function name() view returns (string)',\n 'function nonces(address owner) view returns (uint256)',\n 'function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)',\n 'event Transfer(address indexed from, address indexed to, uint256 value)',\n 'event Approval(address indexed owner, address indexed spender, uint256 value)',\n];\n\nexport type { ChainConfig, ChainName };\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/server/index.ts"],"sourcesContent":["/**\n * MoltsPay Server - Payment infrastructure for AI Agents\n * \n * Supports both testnet (x402.org) and mainnet (CDP) facilitators.\n * Server does NOT need private key - facilitator handles on-chain settlement.\n * \n * Environment variables (from ~/.moltspay/.env or process.env):\n * USE_MAINNET=true - Use Base mainnet (requires CDP keys)\n * CDP_API_KEY_ID=xxx - Coinbase Developer Platform API key ID\n * CDP_API_KEY_SECRET=xxx - CDP API key secret\n * \n * Usage:\n * const server = new MoltsPayServer('./moltspay.services.json');\n * server.skill('text-to-video', async (params) => { ... });\n * server.listen(3000);\n */\n\nimport { readFileSync, existsSync } from 'fs';\nimport { createServer, IncomingMessage, ServerResponse } from 'http';\nimport * as path from 'path';\nimport { getChain } from '../chains/index.js';\nimport type { ChainName } from '../chains/index.js';\nimport {\n ServicesManifest,\n ServiceConfig,\n SkillFunction,\n RegisteredSkill,\n MoltsPayServerOptions,\n} from './types.js';\n\nexport * from './types.js';\n\n// x402 constants\nconst X402_VERSION = 2;\nconst PAYMENT_REQUIRED_HEADER = 'x-payment-required';\nconst PAYMENT_HEADER = 'x-payment';\nconst PAYMENT_RESPONSE_HEADER = 'x-payment-response';\n\n// Facilitator URLs\nconst FACILITATOR_TESTNET = 'https://www.x402.org/facilitator';\nconst FACILITATOR_MAINNET = 'https://api.cdp.coinbase.com/platform/v2/x402';\n\n// USDC contract addresses\nconst USDC_ADDRESSES: Record<string, string> = {\n 'eip155:8453': '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // Base mainnet\n 'eip155:84532': '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // Base Sepolia\n};\n\n// EIP-712 domain info for USDC (required for signature verification)\nconst USDC_DOMAIN = {\n name: 'USD Coin',\n version: '2',\n};\n\ninterface X402PaymentPayload {\n x402Version: number;\n scheme: string;\n network: string;\n payload: any;\n}\n\ninterface CDPConfig {\n useMainnet: boolean;\n apiKeyId?: string;\n apiKeySecret?: string;\n}\n\n/**\n * Load environment from .env files\n */\nfunction loadEnvFiles(): void {\n // Try to load dotenv\n try {\n const dotenv = require('dotenv');\n \n // Priority: current dir > ~/.moltspay/\n const envPaths = [\n path.join(process.cwd(), '.env'),\n path.join(process.env.HOME || '', '.moltspay', '.env'),\n ];\n \n for (const envPath of envPaths) {\n if (existsSync(envPath)) {\n dotenv.config({ path: envPath });\n console.log(`[MoltsPay] Loaded config from ${envPath}`);\n break;\n }\n }\n } catch {\n // dotenv not installed, use process.env only\n }\n}\n\n/**\n * Get CDP configuration from environment\n */\nfunction getCDPConfig(): CDPConfig {\n loadEnvFiles();\n \n return {\n useMainnet: process.env.USE_MAINNET?.toLowerCase() === 'true',\n apiKeyId: process.env.CDP_API_KEY_ID,\n apiKeySecret: process.env.CDP_API_KEY_SECRET,\n };\n}\n\n/**\n * Generate CDP auth headers for API requests\n */\nasync function getCDPAuthHeaders(\n method: string,\n urlPath: string,\n body?: any\n): Promise<Record<string, string>> {\n const config = getCDPConfig();\n \n if (!config.apiKeyId || !config.apiKeySecret) {\n throw new Error('CDP_API_KEY_ID and CDP_API_KEY_SECRET required for mainnet');\n }\n \n try {\n // Import CDP SDK auth\n const { getAuthHeaders } = await import('@coinbase/cdp-sdk/auth');\n \n const headers = await getAuthHeaders({\n apiKeyId: config.apiKeyId,\n apiKeySecret: config.apiKeySecret,\n requestMethod: method,\n requestHost: 'api.cdp.coinbase.com',\n requestPath: urlPath,\n requestBody: body,\n });\n \n return headers;\n } catch (err: any) {\n console.error('[MoltsPay] Failed to generate CDP auth headers:', err.message);\n throw err;\n }\n}\n\nexport class MoltsPayServer {\n private manifest: ServicesManifest;\n private skills: Map<string, RegisteredSkill> = new Map();\n private options: MoltsPayServerOptions;\n private cdpConfig: CDPConfig;\n private facilitatorUrl: string;\n private networkId: string;\n\n constructor(servicesPath: string, options: MoltsPayServerOptions = {}) {\n // Load CDP config first\n this.cdpConfig = getCDPConfig();\n \n // Load services manifest\n const content = readFileSync(servicesPath, 'utf-8');\n this.manifest = JSON.parse(content) as ServicesManifest;\n \n this.options = {\n port: options.port || 3000,\n host: options.host || '0.0.0.0',\n };\n\n // Determine facilitator and network based on config\n if (this.cdpConfig.useMainnet) {\n if (!this.cdpConfig.apiKeyId || !this.cdpConfig.apiKeySecret) {\n console.warn('[MoltsPay] WARNING: USE_MAINNET=true but CDP keys not set!');\n console.warn('[MoltsPay] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in ~/.moltspay/.env');\n }\n this.facilitatorUrl = FACILITATOR_MAINNET;\n this.networkId = 'eip155:8453'; // Base mainnet\n } else {\n this.facilitatorUrl = options.facilitatorUrl || FACILITATOR_TESTNET;\n this.networkId = 'eip155:84532'; // Base Sepolia testnet\n }\n\n const networkName = this.cdpConfig.useMainnet ? 'Base mainnet' : 'Base Sepolia (testnet)';\n const facilitatorName = this.cdpConfig.useMainnet ? 'CDP' : 'x402.org';\n \n console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);\n console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);\n console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);\n console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);\n console.log(`[MoltsPay] Facilitator: ${facilitatorName} (${this.facilitatorUrl})`);\n if (this.cdpConfig.useMainnet && this.cdpConfig.apiKeyId) {\n console.log(`[MoltsPay] CDP API Key: ${this.cdpConfig.apiKeyId.slice(0, 8)}...`);\n }\n console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);\n }\n\n /**\n * Register a skill handler for a service\n */\n skill(serviceId: string, handler: SkillFunction): this {\n const config = this.manifest.services.find(s => s.id === serviceId);\n if (!config) {\n throw new Error(`Service '${serviceId}' not found in manifest`);\n }\n this.skills.set(serviceId, { id: serviceId, config, handler });\n return this;\n }\n\n /**\n * Start HTTP server\n */\n listen(port?: number): void {\n const p = port || this.options.port || 3000;\n const host = this.options.host || '0.0.0.0';\n\n const server = createServer((req, res) => this.handleRequest(req, res));\n server.listen(p, host, () => {\n console.log(`[MoltsPay] Server listening on http://${host}:${p}`);\n console.log(`[MoltsPay] Endpoints:`);\n console.log(` GET /services - List available services`);\n console.log(` POST /execute - Execute service (x402 payment)`);\n });\n }\n\n /**\n * Handle incoming request\n */\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n // CORS\n res.setHeader('Access-Control-Allow-Origin', '*');\n res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Payment');\n res.setHeader('Access-Control-Expose-Headers', 'X-Payment-Required, X-Payment-Response');\n\n if (req.method === 'OPTIONS') {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n const url = new URL(req.url || '/', `http://${req.headers.host}`);\n \n if (url.pathname === '/services' && req.method === 'GET') {\n return this.handleGetServices(res);\n }\n\n if (url.pathname === '/execute' && req.method === 'POST') {\n const body = await this.readBody(req);\n const paymentHeader = req.headers[PAYMENT_HEADER] as string | undefined;\n return await this.handleExecute(body, paymentHeader, res);\n }\n\n // Not found\n this.sendJson(res, 404, { error: 'Not found' });\n } catch (err: any) {\n console.error('[MoltsPay] Error:', err);\n this.sendJson(res, 500, { error: err.message || 'Internal error' });\n }\n }\n\n /**\n * GET /services - List available services\n */\n private handleGetServices(res: ServerResponse): void {\n const services = this.manifest.services.map(s => ({\n id: s.id,\n name: s.name,\n description: s.description,\n price: s.price,\n currency: s.currency,\n input: s.input,\n output: s.output,\n available: this.skills.has(s.id),\n }));\n\n this.sendJson(res, 200, {\n provider: this.manifest.provider,\n services,\n x402: {\n version: X402_VERSION,\n network: this.networkId,\n schemes: ['exact'],\n facilitator: this.cdpConfig.useMainnet ? 'cdp' : 'x402.org',\n mainnet: this.cdpConfig.useMainnet,\n },\n });\n }\n\n /**\n * POST /execute - Execute service with x402 payment\n */\n private async handleExecute(\n body: any,\n paymentHeader: string | undefined,\n res: ServerResponse\n ): Promise<void> {\n const { service, params } = body;\n\n if (!service) {\n return this.sendJson(res, 400, { error: 'Missing service' });\n }\n\n const skill = this.skills.get(service);\n if (!skill) {\n return this.sendJson(res, 404, { error: `Service '${service}' not found or not registered` });\n }\n\n // Validate required params\n for (const [key, field] of Object.entries(skill.config.input)) {\n if (field.required && (!params || params[key] === undefined)) {\n return this.sendJson(res, 400, { error: `Missing required param: ${key}` });\n }\n }\n\n // If no payment header, return 402 with payment requirements\n if (!paymentHeader) {\n return this.sendPaymentRequired(skill.config, res);\n }\n\n // Parse payment payload\n let payment: X402PaymentPayload;\n try {\n const decoded = Buffer.from(paymentHeader, 'base64').toString('utf-8');\n payment = JSON.parse(decoded);\n } catch {\n return this.sendJson(res, 400, { error: 'Invalid X-Payment header' });\n }\n\n // Validate basic payment fields\n const validation = this.validatePayment(payment, skill.config);\n if (!validation.valid) {\n return this.sendJson(res, 402, { error: validation.error });\n }\n\n // Verify payment with facilitator\n console.log(`[MoltsPay] Verifying payment with facilitator...`);\n const verifyResult = await this.verifyWithFacilitator(payment, skill.config);\n if (!verifyResult.valid) {\n return this.sendJson(res, 402, { error: `Payment verification failed: ${verifyResult.error}` });\n }\n\n // Execute skill FIRST (pay-for-success)\n console.log(`[MoltsPay] Executing skill: ${service}`);\n let result: any;\n try {\n result = await skill.handler(params || {});\n } catch (err: any) {\n console.error('[MoltsPay] Skill execution failed:', err.message);\n return this.sendJson(res, 500, {\n error: 'Service execution failed',\n message: err.message,\n });\n }\n\n // Skill succeeded - now settle payment with facilitator\n console.log(`[MoltsPay] Skill succeeded, settling payment...`);\n let settlement: any = null;\n try {\n settlement = await this.settleWithFacilitator(payment, skill.config);\n console.log(`[MoltsPay] Payment settled: ${settlement.transaction || 'pending'}`);\n } catch (err: any) {\n console.error('[MoltsPay] Settlement failed:', err.message);\n }\n\n // Build response\n const responseHeaders: Record<string, string> = {};\n if (settlement) {\n const responsePayload = {\n success: true,\n transaction: settlement.transaction,\n network: payment.network,\n };\n responseHeaders[PAYMENT_RESPONSE_HEADER] = Buffer.from(\n JSON.stringify(responsePayload)\n ).toString('base64');\n }\n\n this.sendJson(res, 200, {\n success: true,\n result,\n payment: settlement \n ? { transaction: settlement.transaction, status: 'settled' }\n : { status: 'pending' },\n }, responseHeaders);\n }\n\n /**\n * Return 402 with x402 payment requirements\n */\n private sendPaymentRequired(config: ServiceConfig, res: ServerResponse): void {\n const requirements = [this.buildPaymentRequirements(config)];\n requirements[0].description = `${config.name} - $${config.price} ${config.currency}`;\n\n const encoded = Buffer.from(JSON.stringify(requirements)).toString('base64');\n\n res.writeHead(402, {\n 'Content-Type': 'application/json',\n [PAYMENT_REQUIRED_HEADER]: encoded,\n });\n res.end(JSON.stringify({\n error: 'Payment required',\n message: `Service requires $${config.price} ${config.currency}`,\n x402: requirements[0],\n }, null, 2));\n }\n\n /**\n * Basic payment validation\n */\n private validatePayment(\n payment: X402PaymentPayload,\n config: ServiceConfig\n ): { valid: boolean; error?: string } {\n if (payment.x402Version !== X402_VERSION) {\n return { valid: false, error: `Unsupported x402 version: ${payment.x402Version}` };\n }\n\n if (payment.scheme !== 'exact') {\n return { valid: false, error: `Unsupported scheme: ${payment.scheme}` };\n }\n\n if (payment.network !== this.networkId) {\n return { valid: false, error: `Network mismatch: expected ${this.networkId}, got ${payment.network}` };\n }\n\n return { valid: true };\n }\n\n /**\n * Build complete payment requirements for facilitator\n */\n private buildPaymentRequirements(config: ServiceConfig): Record<string, any> {\n const amountInUnits = Math.floor(config.price * 1e6).toString();\n const usdcAddress = USDC_ADDRESSES[this.networkId];\n\n return {\n scheme: 'exact',\n network: this.networkId,\n maxAmountRequired: amountInUnits,\n amount: amountInUnits,\n asset: usdcAddress,\n payTo: this.manifest.provider.wallet,\n maxTimeoutSeconds: 300,\n extra: USDC_DOMAIN,\n };\n }\n\n /**\n * Verify payment with facilitator (testnet or CDP)\n */\n private async verifyWithFacilitator(\n payment: X402PaymentPayload,\n config: ServiceConfig\n ): Promise<{ valid: boolean; error?: string }> {\n try {\n const requirements = this.buildPaymentRequirements(config);\n\n const requestBody = {\n paymentPayload: payment,\n paymentRequirements: requirements,\n };\n\n console.log('[MoltsPay] Verify request:', JSON.stringify(requestBody, null, 2));\n\n // Build headers\n let headers: Record<string, string> = { 'Content-Type': 'application/json' };\n \n if (this.cdpConfig.useMainnet) {\n // Add CDP auth headers for mainnet\n const authHeaders = await getCDPAuthHeaders(\n 'POST',\n '/platform/v2/x402/verify',\n requestBody\n );\n headers = { ...headers, ...authHeaders };\n }\n\n const response = await fetch(`${this.facilitatorUrl}/verify`, {\n method: 'POST',\n headers,\n body: JSON.stringify(requestBody),\n });\n\n const result = await response.json() as any;\n console.log('[MoltsPay] Verify response:', JSON.stringify(result, null, 2));\n\n if (!response.ok || !result.isValid) {\n return { valid: false, error: result.invalidReason || result.error || 'Verification failed' };\n }\n\n return { valid: true };\n } catch (err: any) {\n return { valid: false, error: `Facilitator error: ${err.message}` };\n }\n }\n\n /**\n * Settle payment with facilitator (execute on-chain transfer)\n */\n private async settleWithFacilitator(\n payment: X402PaymentPayload,\n config: ServiceConfig\n ): Promise<{ transaction?: string; status: string }> {\n const requirements = this.buildPaymentRequirements(config);\n\n const requestBody = {\n paymentPayload: payment,\n paymentRequirements: requirements,\n };\n\n // Build headers\n let headers: Record<string, string> = { 'Content-Type': 'application/json' };\n \n if (this.cdpConfig.useMainnet) {\n // Add CDP auth headers for mainnet\n const authHeaders = await getCDPAuthHeaders(\n 'POST',\n '/platform/v2/x402/settle',\n requestBody\n );\n headers = { ...headers, ...authHeaders };\n }\n\n const response = await fetch(`${this.facilitatorUrl}/settle`, {\n method: 'POST',\n headers,\n body: JSON.stringify(requestBody),\n });\n\n const result = await response.json() as any;\n\n if (!response.ok || !result.success) {\n throw new Error(result.error || result.errorReason || 'Settlement failed');\n }\n\n return {\n transaction: result.transaction,\n status: result.status || 'settled',\n };\n }\n\n private async readBody(req: IncomingMessage): Promise<any> {\n return new Promise((resolve, reject) => {\n let body = '';\n req.on('data', chunk => body += chunk);\n req.on('end', () => {\n try {\n resolve(body ? JSON.parse(body) : {});\n } catch {\n reject(new Error('Invalid JSON'));\n }\n });\n req.on('error', reject);\n });\n }\n\n private sendJson(\n res: ServerResponse, \n status: number, \n data: any,\n extraHeaders?: Record<string, string>\n ): void {\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (extraHeaders) {\n Object.assign(headers, extraHeaders);\n }\n res.writeHead(status, headers);\n res.end(JSON.stringify(data, null, 2));\n }\n}\n"],"mappings":"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","names":[]}
|