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.
@@ -1,10 +1,16 @@
1
1
  #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
2
8
 
3
9
  // src/cli/index.ts
4
10
  import { Command } from "commander";
5
11
  import { homedir as homedir2 } from "os";
6
- import { join as join2, dirname, resolve } from "path";
7
- import { existsSync as existsSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync3, unlinkSync, mkdirSync as mkdirSync2 } from "fs";
12
+ import { join as join3, dirname, resolve } from "path";
13
+ import { existsSync as existsSync3, writeFileSync as writeFileSync2, readFileSync as readFileSync3, unlinkSync, mkdirSync as mkdirSync2 } from "fs";
8
14
  import { spawn } from "child_process";
9
15
 
10
16
  // src/client/index.ts
@@ -342,30 +348,107 @@ var MoltsPayClient = class {
342
348
  };
343
349
 
344
350
  // src/server/index.ts
345
- import { readFileSync as readFileSync2 } from "fs";
351
+ import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
346
352
  import { createServer } from "http";
353
+ import * as path from "path";
347
354
  var X402_VERSION2 = 2;
348
355
  var PAYMENT_REQUIRED_HEADER2 = "x-payment-required";
349
356
  var PAYMENT_HEADER2 = "x-payment";
350
357
  var PAYMENT_RESPONSE_HEADER = "x-payment-response";
351
- var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
358
+ var FACILITATOR_TESTNET = "https://www.x402.org/facilitator";
359
+ var FACILITATOR_MAINNET = "https://api.cdp.coinbase.com/platform/v2/x402";
360
+ var USDC_ADDRESSES = {
361
+ "eip155:8453": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
362
+ // Base mainnet
363
+ "eip155:84532": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
364
+ // Base Sepolia
365
+ };
366
+ var USDC_DOMAIN = {
367
+ name: "USD Coin",
368
+ version: "2"
369
+ };
370
+ function loadEnvFiles() {
371
+ try {
372
+ const dotenv = __require("dotenv");
373
+ const envPaths = [
374
+ path.join(process.cwd(), ".env"),
375
+ path.join(process.env.HOME || "", ".moltspay", ".env")
376
+ ];
377
+ for (const envPath of envPaths) {
378
+ if (existsSync2(envPath)) {
379
+ dotenv.config({ path: envPath });
380
+ console.log(`[MoltsPay] Loaded config from ${envPath}`);
381
+ break;
382
+ }
383
+ }
384
+ } catch {
385
+ }
386
+ }
387
+ function getCDPConfig() {
388
+ loadEnvFiles();
389
+ return {
390
+ useMainnet: process.env.USE_MAINNET?.toLowerCase() === "true",
391
+ apiKeyId: process.env.CDP_API_KEY_ID,
392
+ apiKeySecret: process.env.CDP_API_KEY_SECRET
393
+ };
394
+ }
395
+ async function getCDPAuthHeaders(method, urlPath, body) {
396
+ const config = getCDPConfig();
397
+ if (!config.apiKeyId || !config.apiKeySecret) {
398
+ throw new Error("CDP_API_KEY_ID and CDP_API_KEY_SECRET required for mainnet");
399
+ }
400
+ try {
401
+ const { getAuthHeaders } = await import("@coinbase/cdp-sdk/auth");
402
+ const headers = await getAuthHeaders({
403
+ apiKeyId: config.apiKeyId,
404
+ apiKeySecret: config.apiKeySecret,
405
+ requestMethod: method,
406
+ requestHost: "api.cdp.coinbase.com",
407
+ requestPath: urlPath,
408
+ requestBody: body
409
+ });
410
+ return headers;
411
+ } catch (err) {
412
+ console.error("[MoltsPay] Failed to generate CDP auth headers:", err.message);
413
+ throw err;
414
+ }
415
+ }
352
416
  var MoltsPayServer = class {
353
417
  manifest;
354
418
  skills = /* @__PURE__ */ new Map();
355
419
  options;
420
+ cdpConfig;
356
421
  facilitatorUrl;
422
+ networkId;
357
423
  constructor(servicesPath, options = {}) {
424
+ this.cdpConfig = getCDPConfig();
358
425
  const content = readFileSync2(servicesPath, "utf-8");
359
426
  this.manifest = JSON.parse(content);
360
427
  this.options = {
361
428
  port: options.port || 3e3,
362
429
  host: options.host || "0.0.0.0"
363
430
  };
364
- this.facilitatorUrl = options.facilitatorUrl || DEFAULT_FACILITATOR_URL;
431
+ if (this.cdpConfig.useMainnet) {
432
+ if (!this.cdpConfig.apiKeyId || !this.cdpConfig.apiKeySecret) {
433
+ console.warn("[MoltsPay] WARNING: USE_MAINNET=true but CDP keys not set!");
434
+ console.warn("[MoltsPay] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in ~/.moltspay/.env");
435
+ }
436
+ this.facilitatorUrl = FACILITATOR_MAINNET;
437
+ this.networkId = "eip155:8453";
438
+ } else {
439
+ this.facilitatorUrl = options.facilitatorUrl || FACILITATOR_TESTNET;
440
+ this.networkId = "eip155:84532";
441
+ }
442
+ const networkName = this.cdpConfig.useMainnet ? "Base mainnet" : "Base Sepolia (testnet)";
443
+ const facilitatorName = this.cdpConfig.useMainnet ? "CDP" : "x402.org";
365
444
  console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);
366
445
  console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);
367
446
  console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);
368
- console.log(`[MoltsPay] Facilitator: ${this.facilitatorUrl}`);
447
+ console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);
448
+ console.log(`[MoltsPay] Facilitator: ${facilitatorName} (${this.facilitatorUrl})`);
449
+ if (this.cdpConfig.useMainnet && this.cdpConfig.apiKeyId) {
450
+ console.log(`[MoltsPay] CDP API Key: ${this.cdpConfig.apiKeyId.slice(0, 8)}...`);
451
+ }
369
452
  console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);
370
453
  }
371
454
  /**
@@ -426,7 +509,6 @@ var MoltsPayServer = class {
426
509
  * GET /services - List available services
427
510
  */
428
511
  handleGetServices(res) {
429
- const chain = getChain(this.manifest.provider.chain);
430
512
  const services = this.manifest.services.map((s) => ({
431
513
  id: s.id,
432
514
  name: s.name,
@@ -442,16 +524,15 @@ var MoltsPayServer = class {
442
524
  services,
443
525
  x402: {
444
526
  version: X402_VERSION2,
445
- network: `eip155:${chain.chainId}`,
527
+ network: this.networkId,
446
528
  schemes: ["exact"],
447
- facilitator: this.facilitatorUrl
529
+ facilitator: this.cdpConfig.useMainnet ? "cdp" : "x402.org",
530
+ mainnet: this.cdpConfig.useMainnet
448
531
  }
449
532
  });
450
533
  }
451
534
  /**
452
535
  * POST /execute - Execute service with x402 payment
453
- * Body: { service: string, params: object }
454
- * Header: X-Payment (optional - if missing, returns 402)
455
536
  */
456
537
  async handleExecute(body, paymentHeader, res) {
457
538
  const { service, params } = body;
@@ -526,17 +607,8 @@ var MoltsPayServer = class {
526
607
  * Return 402 with x402 payment requirements
527
608
  */
528
609
  sendPaymentRequired(config, res) {
529
- const chain = getChain(this.manifest.provider.chain);
530
- const amountInUnits = Math.floor(config.price * 1e6).toString();
531
- const requirements = [{
532
- scheme: "exact",
533
- network: `eip155:${chain.chainId}`,
534
- maxAmountRequired: amountInUnits,
535
- resource: this.manifest.provider.wallet,
536
- description: `${config.name} - $${config.price} ${config.currency}`,
537
- // Include facilitator info for client
538
- extra: JSON.stringify({ facilitator: this.facilitatorUrl })
539
- }];
610
+ const requirements = [this.buildPaymentRequirements(config)];
611
+ requirements[0].description = `${config.name} - $${config.price} ${config.currency}`;
540
612
  const encoded = Buffer.from(JSON.stringify(requirements)).toString("base64");
541
613
  res.writeHead(402, {
542
614
  "Content-Type": "application/json",
@@ -549,7 +621,7 @@ var MoltsPayServer = class {
549
621
  }, null, 2));
550
622
  }
551
623
  /**
552
- * Basic payment validation (before calling facilitator)
624
+ * Basic payment validation
553
625
  */
554
626
  validatePayment(payment, config) {
555
627
  if (payment.x402Version !== X402_VERSION2) {
@@ -558,37 +630,57 @@ var MoltsPayServer = class {
558
630
  if (payment.scheme !== "exact") {
559
631
  return { valid: false, error: `Unsupported scheme: ${payment.scheme}` };
560
632
  }
561
- const chain = getChain(this.manifest.provider.chain);
562
- const expectedNetwork = `eip155:${chain.chainId}`;
563
- if (payment.network !== expectedNetwork) {
564
- return { valid: false, error: `Network mismatch: expected ${expectedNetwork}` };
633
+ if (payment.network !== this.networkId) {
634
+ return { valid: false, error: `Network mismatch: expected ${this.networkId}, got ${payment.network}` };
565
635
  }
566
636
  return { valid: true };
567
637
  }
568
638
  /**
569
- * Verify payment with facilitator
639
+ * Build complete payment requirements for facilitator
640
+ */
641
+ buildPaymentRequirements(config) {
642
+ const amountInUnits = Math.floor(config.price * 1e6).toString();
643
+ const usdcAddress = USDC_ADDRESSES[this.networkId];
644
+ return {
645
+ scheme: "exact",
646
+ network: this.networkId,
647
+ maxAmountRequired: amountInUnits,
648
+ amount: amountInUnits,
649
+ asset: usdcAddress,
650
+ payTo: this.manifest.provider.wallet,
651
+ maxTimeoutSeconds: 300,
652
+ extra: USDC_DOMAIN
653
+ };
654
+ }
655
+ /**
656
+ * Verify payment with facilitator (testnet or CDP)
570
657
  */
571
658
  async verifyWithFacilitator(payment, config) {
572
659
  try {
573
- const chain = getChain(this.manifest.provider.chain);
574
- const amountInUnits = Math.floor(config.price * 1e6).toString();
575
- const requirements = {
576
- scheme: "exact",
577
- network: `eip155:${chain.chainId}`,
578
- maxAmountRequired: amountInUnits,
579
- resource: this.manifest.provider.wallet
660
+ const requirements = this.buildPaymentRequirements(config);
661
+ const requestBody = {
662
+ paymentPayload: payment,
663
+ paymentRequirements: requirements
580
664
  };
665
+ console.log("[MoltsPay] Verify request:", JSON.stringify(requestBody, null, 2));
666
+ let headers = { "Content-Type": "application/json" };
667
+ if (this.cdpConfig.useMainnet) {
668
+ const authHeaders = await getCDPAuthHeaders(
669
+ "POST",
670
+ "/platform/v2/x402/verify",
671
+ requestBody
672
+ );
673
+ headers = { ...headers, ...authHeaders };
674
+ }
581
675
  const response = await fetch(`${this.facilitatorUrl}/verify`, {
582
676
  method: "POST",
583
- headers: { "Content-Type": "application/json" },
584
- body: JSON.stringify({
585
- paymentPayload: payment,
586
- paymentRequirements: requirements
587
- })
677
+ headers,
678
+ body: JSON.stringify(requestBody)
588
679
  });
589
680
  const result = await response.json();
681
+ console.log("[MoltsPay] Verify response:", JSON.stringify(result, null, 2));
590
682
  if (!response.ok || !result.isValid) {
591
- return { valid: false, error: result.invalidReason || "Verification failed" };
683
+ return { valid: false, error: result.invalidReason || result.error || "Verification failed" };
592
684
  }
593
685
  return { valid: true };
594
686
  } catch (err) {
@@ -599,25 +691,28 @@ var MoltsPayServer = class {
599
691
  * Settle payment with facilitator (execute on-chain transfer)
600
692
  */
601
693
  async settleWithFacilitator(payment, config) {
602
- const chain = getChain(this.manifest.provider.chain);
603
- const amountInUnits = Math.floor(config.price * 1e6).toString();
604
- const requirements = {
605
- scheme: "exact",
606
- network: `eip155:${chain.chainId}`,
607
- maxAmountRequired: amountInUnits,
608
- resource: this.manifest.provider.wallet
694
+ const requirements = this.buildPaymentRequirements(config);
695
+ const requestBody = {
696
+ paymentPayload: payment,
697
+ paymentRequirements: requirements
609
698
  };
699
+ let headers = { "Content-Type": "application/json" };
700
+ if (this.cdpConfig.useMainnet) {
701
+ const authHeaders = await getCDPAuthHeaders(
702
+ "POST",
703
+ "/platform/v2/x402/settle",
704
+ requestBody
705
+ );
706
+ headers = { ...headers, ...authHeaders };
707
+ }
610
708
  const response = await fetch(`${this.facilitatorUrl}/settle`, {
611
709
  method: "POST",
612
- headers: { "Content-Type": "application/json" },
613
- body: JSON.stringify({
614
- paymentPayload: payment,
615
- paymentRequirements: requirements
616
- })
710
+ headers,
711
+ body: JSON.stringify(requestBody)
617
712
  });
618
713
  const result = await response.json();
619
- if (!response.ok) {
620
- throw new Error(result.error || "Settlement failed");
714
+ if (!response.ok || !result.success) {
715
+ throw new Error(result.error || result.errorReason || "Settlement failed");
621
716
  }
622
717
  return {
623
718
  transaction: result.transaction,
@@ -651,9 +746,9 @@ var MoltsPayServer = class {
651
746
  // src/cli/index.ts
652
747
  import * as readline from "readline";
653
748
  var program = new Command();
654
- var DEFAULT_CONFIG_DIR = join2(homedir2(), ".moltspay");
655
- var PID_FILE = join2(DEFAULT_CONFIG_DIR, "server.pid");
656
- if (!existsSync2(DEFAULT_CONFIG_DIR)) {
749
+ var DEFAULT_CONFIG_DIR = join3(homedir2(), ".moltspay");
750
+ var PID_FILE = join3(DEFAULT_CONFIG_DIR, "server.pid");
751
+ if (!existsSync3(DEFAULT_CONFIG_DIR)) {
657
752
  mkdirSync2(DEFAULT_CONFIG_DIR, { recursive: true });
658
753
  }
659
754
  function prompt(question) {
@@ -671,7 +766,7 @@ function prompt(question) {
671
766
  program.name("moltspay").description("MoltsPay - Payment infrastructure for AI Agents").version("1.0.0");
672
767
  program.command("init").description("Initialize MoltsPay client (create wallet, set limits)").option("--chain <chain>", "Blockchain to use", "base").option("--max-per-tx <amount>", "Max amount per transaction").option("--max-per-day <amount>", "Max amount per day").option("--config-dir <dir>", "Config directory", DEFAULT_CONFIG_DIR).action(async (options) => {
673
768
  console.log("\n\u{1F510} MoltsPay Client Setup\n");
674
- if (existsSync2(join2(options.configDir, "wallet.json"))) {
769
+ if (existsSync3(join3(options.configDir, "wallet.json"))) {
675
770
  console.log('\u26A0\uFE0F Already initialized. Use "moltspay config" to update settings.');
676
771
  console.log(` Config dir: ${options.configDir}`);
677
772
  return;
@@ -698,7 +793,7 @@ program.command("init").description("Initialize MoltsPay client (create wallet,
698
793
  console.log(`
699
794
  \u{1F4C1} Config saved to: ${result.configDir}`);
700
795
  console.log(`
701
- \u26A0\uFE0F IMPORTANT: Back up ${join2(result.configDir, "wallet.json")}`);
796
+ \u26A0\uFE0F IMPORTANT: Back up ${join3(result.configDir, "wallet.json")}`);
702
797
  console.log(` This file contains your private key!
703
798
  `);
704
799
  console.log(`\u{1F4B0} Fund your wallet with USDC on ${chain} to start using services.
@@ -806,7 +901,7 @@ program.command("services <url>").description("List services from a provider").o
806
901
  });
807
902
  program.command("start <manifest>").description("Start MoltsPay server from services manifest").option("-p, --port <port>", "Port to listen on", "3000").option("--host <host>", "Host to bind", "0.0.0.0").option("--facilitator <url>", "x402 facilitator URL (default: https://x402.org/facilitator)").action(async (manifest, options) => {
808
903
  const manifestPath = resolve(manifest);
809
- if (!existsSync2(manifestPath)) {
904
+ if (!existsSync3(manifestPath)) {
810
905
  console.error(`\u274C Manifest not found: ${manifestPath}`);
811
906
  process.exit(1);
812
907
  }
@@ -870,7 +965,7 @@ program.command("start <manifest>").description("Start MoltsPay server from serv
870
965
  server.listen(port);
871
966
  const cleanup = () => {
872
967
  try {
873
- if (existsSync2(PID_FILE)) {
968
+ if (existsSync3(PID_FILE)) {
874
969
  unlinkSync(PID_FILE);
875
970
  }
876
971
  } catch {
@@ -893,7 +988,7 @@ program.command("start <manifest>").description("Start MoltsPay server from serv
893
988
  }
894
989
  });
895
990
  program.command("stop").description("Stop the running MoltsPay server").action(async () => {
896
- if (!existsSync2(PID_FILE)) {
991
+ if (!existsSync3(PID_FILE)) {
897
992
  console.log("\u274C No running server found (no PID file)");
898
993
  process.exit(1);
899
994
  }
@@ -923,7 +1018,7 @@ program.command("stop").description("Stop the running MoltsPay server").action(a
923
1018
  process.kill(pid, "SIGKILL");
924
1019
  } catch {
925
1020
  }
926
- if (existsSync2(PID_FILE)) {
1021
+ if (existsSync3(PID_FILE)) {
927
1022
  unlinkSync(PID_FILE);
928
1023
  }
929
1024
  console.log("\u2705 Server stopped\n");
@@ -954,7 +1049,7 @@ program.command("pay <server> <service> [params]").description("Pay for a servic
954
1049
  params.image_url = imagePath;
955
1050
  } else {
956
1051
  const filePath = resolve(imagePath);
957
- if (!existsSync2(filePath)) {
1052
+ if (!existsSync3(filePath)) {
958
1053
  console.error(`\u274C Image file not found: ${filePath}`);
959
1054
  process.exit(1);
960
1055
  }