moltspay 0.8.1 → 0.8.2

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.
@@ -76,9 +76,14 @@ interface MoltsPayServerOptions {
76
76
  /**
77
77
  * MoltsPay Server - Payment infrastructure for AI Agents
78
78
  *
79
- * Uses x402 protocol with public facilitator (https://x402.org/facilitator).
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,11 @@ declare class MoltsPayServer {
118
123
  */
119
124
  private sendPaymentRequired;
120
125
  /**
121
- * Basic payment validation (before calling facilitator)
126
+ * Basic payment validation
122
127
  */
123
128
  private validatePayment;
124
129
  /**
125
- * Verify payment with facilitator
130
+ * Verify payment with facilitator (testnet or CDP)
126
131
  */
127
132
  private verifyWithFacilitator;
128
133
  /**
@@ -76,9 +76,14 @@ interface MoltsPayServerOptions {
76
76
  /**
77
77
  * MoltsPay Server - Payment infrastructure for AI Agents
78
78
  *
79
- * Uses x402 protocol with public facilitator (https://x402.org/facilitator).
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,11 @@ declare class MoltsPayServer {
118
123
  */
119
124
  private sendPaymentRequired;
120
125
  /**
121
- * Basic payment validation (before calling facilitator)
126
+ * Basic payment validation
122
127
  */
123
128
  private validatePayment;
124
129
  /**
125
- * Verify payment with facilitator
130
+ * Verify payment with facilitator (testnet or CDP)
126
131
  */
127
132
  private verifyWithFacilitator;
128
133
  /**
@@ -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,95 @@ __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 DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
43
+ var FACILITATOR_TESTNET = "https://www.x402.org/facilitator";
44
+ var FACILITATOR_MAINNET = "https://api.cdp.coinbase.com/platform/v2/x402";
45
+ function loadEnvFiles() {
46
+ try {
47
+ const dotenv = require("dotenv");
48
+ const envPaths = [
49
+ path.join(process.cwd(), ".env"),
50
+ path.join(process.env.HOME || "", ".moltspay", ".env")
51
+ ];
52
+ for (const envPath of envPaths) {
53
+ if ((0, import_fs.existsSync)(envPath)) {
54
+ dotenv.config({ path: envPath });
55
+ console.log(`[MoltsPay] Loaded config from ${envPath}`);
56
+ break;
57
+ }
58
+ }
59
+ } catch {
60
+ }
61
+ }
62
+ function getCDPConfig() {
63
+ loadEnvFiles();
64
+ return {
65
+ useMainnet: process.env.USE_MAINNET?.toLowerCase() === "true",
66
+ apiKeyId: process.env.CDP_API_KEY_ID,
67
+ apiKeySecret: process.env.CDP_API_KEY_SECRET
68
+ };
69
+ }
70
+ async function getCDPAuthHeaders(method, urlPath, body) {
71
+ const config = getCDPConfig();
72
+ if (!config.apiKeyId || !config.apiKeySecret) {
73
+ throw new Error("CDP_API_KEY_ID and CDP_API_KEY_SECRET required for mainnet");
74
+ }
75
+ try {
76
+ const { getAuthHeaders } = await import("@coinbase/cdp-sdk/auth");
77
+ const headers = await getAuthHeaders({
78
+ apiKeyId: config.apiKeyId,
79
+ apiKeySecret: config.apiKeySecret,
80
+ requestMethod: method,
81
+ requestHost: "api.cdp.coinbase.com",
82
+ requestPath: urlPath,
83
+ requestBody: body
84
+ });
85
+ return headers;
86
+ } catch (err) {
87
+ console.error("[MoltsPay] Failed to generate CDP auth headers:", err.message);
88
+ throw err;
89
+ }
90
+ }
93
91
  var MoltsPayServer = class {
94
92
  manifest;
95
93
  skills = /* @__PURE__ */ new Map();
96
94
  options;
95
+ cdpConfig;
97
96
  facilitatorUrl;
97
+ networkId;
98
98
  constructor(servicesPath, options = {}) {
99
+ this.cdpConfig = getCDPConfig();
99
100
  const content = (0, import_fs.readFileSync)(servicesPath, "utf-8");
100
101
  this.manifest = JSON.parse(content);
101
102
  this.options = {
102
103
  port: options.port || 3e3,
103
104
  host: options.host || "0.0.0.0"
104
105
  };
105
- this.facilitatorUrl = options.facilitatorUrl || DEFAULT_FACILITATOR_URL;
106
+ if (this.cdpConfig.useMainnet) {
107
+ if (!this.cdpConfig.apiKeyId || !this.cdpConfig.apiKeySecret) {
108
+ console.warn("[MoltsPay] WARNING: USE_MAINNET=true but CDP keys not set!");
109
+ console.warn("[MoltsPay] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in ~/.moltspay/.env");
110
+ }
111
+ this.facilitatorUrl = FACILITATOR_MAINNET;
112
+ this.networkId = "eip155:8453";
113
+ } else {
114
+ this.facilitatorUrl = options.facilitatorUrl || FACILITATOR_TESTNET;
115
+ this.networkId = "eip155:84532";
116
+ }
117
+ const networkName = this.cdpConfig.useMainnet ? "Base mainnet" : "Base Sepolia (testnet)";
118
+ const facilitatorName = this.cdpConfig.useMainnet ? "CDP" : "x402.org";
106
119
  console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);
107
120
  console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);
108
121
  console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);
109
- console.log(`[MoltsPay] Facilitator: ${this.facilitatorUrl}`);
122
+ console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);
123
+ console.log(`[MoltsPay] Facilitator: ${facilitatorName} (${this.facilitatorUrl})`);
124
+ if (this.cdpConfig.useMainnet && this.cdpConfig.apiKeyId) {
125
+ console.log(`[MoltsPay] CDP API Key: ${this.cdpConfig.apiKeyId.slice(0, 8)}...`);
126
+ }
110
127
  console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);
111
128
  }
112
129
  /**
@@ -167,7 +184,6 @@ var MoltsPayServer = class {
167
184
  * GET /services - List available services
168
185
  */
169
186
  handleGetServices(res) {
170
- const chain = getChain(this.manifest.provider.chain);
171
187
  const services = this.manifest.services.map((s) => ({
172
188
  id: s.id,
173
189
  name: s.name,
@@ -183,16 +199,15 @@ var MoltsPayServer = class {
183
199
  services,
184
200
  x402: {
185
201
  version: X402_VERSION,
186
- network: `eip155:${chain.chainId}`,
202
+ network: this.networkId,
187
203
  schemes: ["exact"],
188
- facilitator: this.facilitatorUrl
204
+ facilitator: this.cdpConfig.useMainnet ? "cdp" : "x402.org",
205
+ mainnet: this.cdpConfig.useMainnet
189
206
  }
190
207
  });
191
208
  }
192
209
  /**
193
210
  * POST /execute - Execute service with x402 payment
194
- * Body: { service: string, params: object }
195
- * Header: X-Payment (optional - if missing, returns 402)
196
211
  */
197
212
  async handleExecute(body, paymentHeader, res) {
198
213
  const { service, params } = body;
@@ -267,16 +282,17 @@ var MoltsPayServer = class {
267
282
  * Return 402 with x402 payment requirements
268
283
  */
269
284
  sendPaymentRequired(config, res) {
270
- const chain = getChain(this.manifest.provider.chain);
271
285
  const amountInUnits = Math.floor(config.price * 1e6).toString();
272
286
  const requirements = [{
273
287
  scheme: "exact",
274
- network: `eip155:${chain.chainId}`,
288
+ network: this.networkId,
275
289
  maxAmountRequired: amountInUnits,
276
290
  resource: this.manifest.provider.wallet,
277
291
  description: `${config.name} - $${config.price} ${config.currency}`,
278
- // Include facilitator info for client
279
- extra: JSON.stringify({ facilitator: this.facilitatorUrl })
292
+ extra: JSON.stringify({
293
+ facilitator: this.cdpConfig.useMainnet ? "cdp" : "x402.org",
294
+ mainnet: this.cdpConfig.useMainnet
295
+ })
280
296
  }];
281
297
  const encoded = Buffer.from(JSON.stringify(requirements)).toString("base64");
282
298
  res.writeHead(402, {
@@ -290,7 +306,7 @@ var MoltsPayServer = class {
290
306
  }, null, 2));
291
307
  }
292
308
  /**
293
- * Basic payment validation (before calling facilitator)
309
+ * Basic payment validation
294
310
  */
295
311
  validatePayment(payment, config) {
296
312
  if (payment.x402Version !== X402_VERSION) {
@@ -299,37 +315,45 @@ var MoltsPayServer = class {
299
315
  if (payment.scheme !== "exact") {
300
316
  return { valid: false, error: `Unsupported scheme: ${payment.scheme}` };
301
317
  }
302
- const chain = getChain(this.manifest.provider.chain);
303
- const expectedNetwork = `eip155:${chain.chainId}`;
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
- * Verify payment with facilitator
324
+ * Verify payment with facilitator (testnet or CDP)
311
325
  */
312
326
  async verifyWithFacilitator(payment, config) {
313
327
  try {
314
- const chain = getChain(this.manifest.provider.chain);
315
328
  const amountInUnits = Math.floor(config.price * 1e6).toString();
316
329
  const requirements = {
317
330
  scheme: "exact",
318
- network: `eip155:${chain.chainId}`,
331
+ network: this.networkId,
319
332
  maxAmountRequired: amountInUnits,
320
- resource: this.manifest.provider.wallet
333
+ resource: this.manifest.provider.wallet,
334
+ payTo: this.manifest.provider.wallet
335
+ };
336
+ const requestBody = {
337
+ paymentPayload: payment,
338
+ paymentRequirements: requirements
321
339
  };
340
+ let headers = { "Content-Type": "application/json" };
341
+ if (this.cdpConfig.useMainnet) {
342
+ const authHeaders = await getCDPAuthHeaders(
343
+ "POST",
344
+ "/platform/v2/x402/verify",
345
+ requestBody
346
+ );
347
+ headers = { ...headers, ...authHeaders };
348
+ }
322
349
  const response = await fetch(`${this.facilitatorUrl}/verify`, {
323
350
  method: "POST",
324
- headers: { "Content-Type": "application/json" },
325
- body: JSON.stringify({
326
- paymentPayload: payment,
327
- paymentRequirements: requirements
328
- })
351
+ headers,
352
+ body: JSON.stringify(requestBody)
329
353
  });
330
354
  const result = await response.json();
331
355
  if (!response.ok || !result.isValid) {
332
- return { valid: false, error: result.invalidReason || "Verification failed" };
356
+ return { valid: false, error: result.invalidReason || result.error || "Verification failed" };
333
357
  }
334
358
  return { valid: true };
335
359
  } catch (err) {
@@ -340,25 +364,35 @@ var MoltsPayServer = class {
340
364
  * Settle payment with facilitator (execute on-chain transfer)
341
365
  */
342
366
  async settleWithFacilitator(payment, config) {
343
- const chain = getChain(this.manifest.provider.chain);
344
367
  const amountInUnits = Math.floor(config.price * 1e6).toString();
345
368
  const requirements = {
346
369
  scheme: "exact",
347
- network: `eip155:${chain.chainId}`,
370
+ network: this.networkId,
348
371
  maxAmountRequired: amountInUnits,
349
- resource: this.manifest.provider.wallet
372
+ resource: this.manifest.provider.wallet,
373
+ payTo: this.manifest.provider.wallet
350
374
  };
375
+ const requestBody = {
376
+ paymentPayload: payment,
377
+ paymentRequirements: requirements
378
+ };
379
+ let headers = { "Content-Type": "application/json" };
380
+ if (this.cdpConfig.useMainnet) {
381
+ const authHeaders = await getCDPAuthHeaders(
382
+ "POST",
383
+ "/platform/v2/x402/settle",
384
+ requestBody
385
+ );
386
+ headers = { ...headers, ...authHeaders };
387
+ }
351
388
  const response = await fetch(`${this.facilitatorUrl}/settle`, {
352
389
  method: "POST",
353
- headers: { "Content-Type": "application/json" },
354
- body: JSON.stringify({
355
- paymentPayload: payment,
356
- paymentRequirements: requirements
357
- })
390
+ headers,
391
+ body: JSON.stringify(requestBody)
358
392
  });
359
393
  const result = await response.json();
360
- if (!response.ok) {
361
- throw new Error(result.error || "Settlement failed");
394
+ if (!response.ok || !result.success) {
395
+ throw new Error(result.error || result.errorReason || "Settlement failed");
362
396
  }
363
397
  return {
364
398
  transaction: result.transaction,
@@ -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\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 amountInUnits = Math.floor(config.price * 1e6).toString();\n\n const requirements = [{\n scheme: 'exact',\n network: this.networkId,\n maxAmountRequired: amountInUnits,\n resource: this.manifest.provider.wallet,\n description: `${config.name} - $${config.price} ${config.currency}`,\n extra: JSON.stringify({ \n facilitator: this.cdpConfig.useMainnet ? 'cdp' : 'x402.org',\n mainnet: this.cdpConfig.useMainnet,\n }),\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\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 * 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 amountInUnits = Math.floor(config.price * 1e6).toString();\n\n const requirements = {\n scheme: 'exact',\n network: this.networkId,\n maxAmountRequired: amountInUnits,\n resource: this.manifest.provider.wallet,\n payTo: this.manifest.provider.wallet,\n };\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/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\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 amountInUnits = Math.floor(config.price * 1e6).toString();\n\n const requirements = {\n scheme: 'exact',\n network: this.networkId,\n maxAmountRequired: amountInUnits,\n resource: this.manifest.provider.wallet,\n payTo: this.manifest.provider.wallet,\n };\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":[]}