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 ADDED
@@ -0,0 +1,10 @@
1
+ # MoltsPay Server Configuration
2
+ # Copy to ~/.moltspay/.env or ./.env and fill in values
3
+
4
+ # Network: true = Base mainnet, false = Base Sepolia testnet
5
+ USE_MAINNET=true
6
+
7
+ # CDP API Credentials (required for mainnet)
8
+ # Get from: https://portal.cdp.coinbase.com/
9
+ CDP_API_KEY_ID=
10
+ CDP_API_KEY_SECRET=
package/dist/cli/index.js CHANGED
@@ -367,28 +367,105 @@ var MoltsPayClient = class {
367
367
  // src/server/index.ts
368
368
  var import_fs2 = require("fs");
369
369
  var import_http = require("http");
370
+ var path = __toESM(require("path"));
370
371
  var X402_VERSION2 = 2;
371
372
  var PAYMENT_REQUIRED_HEADER2 = "x-payment-required";
372
373
  var PAYMENT_HEADER2 = "x-payment";
373
374
  var PAYMENT_RESPONSE_HEADER = "x-payment-response";
374
- var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
375
+ var FACILITATOR_TESTNET = "https://www.x402.org/facilitator";
376
+ var FACILITATOR_MAINNET = "https://api.cdp.coinbase.com/platform/v2/x402";
377
+ var USDC_ADDRESSES = {
378
+ "eip155:8453": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
379
+ // Base mainnet
380
+ "eip155:84532": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
381
+ // Base Sepolia
382
+ };
383
+ var USDC_DOMAIN = {
384
+ name: "USD Coin",
385
+ version: "2"
386
+ };
387
+ function loadEnvFiles() {
388
+ try {
389
+ const dotenv = require("dotenv");
390
+ const envPaths = [
391
+ path.join(process.cwd(), ".env"),
392
+ path.join(process.env.HOME || "", ".moltspay", ".env")
393
+ ];
394
+ for (const envPath of envPaths) {
395
+ if ((0, import_fs2.existsSync)(envPath)) {
396
+ dotenv.config({ path: envPath });
397
+ console.log(`[MoltsPay] Loaded config from ${envPath}`);
398
+ break;
399
+ }
400
+ }
401
+ } catch {
402
+ }
403
+ }
404
+ function getCDPConfig() {
405
+ loadEnvFiles();
406
+ return {
407
+ useMainnet: process.env.USE_MAINNET?.toLowerCase() === "true",
408
+ apiKeyId: process.env.CDP_API_KEY_ID,
409
+ apiKeySecret: process.env.CDP_API_KEY_SECRET
410
+ };
411
+ }
412
+ async function getCDPAuthHeaders(method, urlPath, body) {
413
+ const config = getCDPConfig();
414
+ if (!config.apiKeyId || !config.apiKeySecret) {
415
+ throw new Error("CDP_API_KEY_ID and CDP_API_KEY_SECRET required for mainnet");
416
+ }
417
+ try {
418
+ const { getAuthHeaders } = await import("@coinbase/cdp-sdk/auth");
419
+ const headers = await getAuthHeaders({
420
+ apiKeyId: config.apiKeyId,
421
+ apiKeySecret: config.apiKeySecret,
422
+ requestMethod: method,
423
+ requestHost: "api.cdp.coinbase.com",
424
+ requestPath: urlPath,
425
+ requestBody: body
426
+ });
427
+ return headers;
428
+ } catch (err) {
429
+ console.error("[MoltsPay] Failed to generate CDP auth headers:", err.message);
430
+ throw err;
431
+ }
432
+ }
375
433
  var MoltsPayServer = class {
376
434
  manifest;
377
435
  skills = /* @__PURE__ */ new Map();
378
436
  options;
437
+ cdpConfig;
379
438
  facilitatorUrl;
439
+ networkId;
380
440
  constructor(servicesPath, options = {}) {
441
+ this.cdpConfig = getCDPConfig();
381
442
  const content = (0, import_fs2.readFileSync)(servicesPath, "utf-8");
382
443
  this.manifest = JSON.parse(content);
383
444
  this.options = {
384
445
  port: options.port || 3e3,
385
446
  host: options.host || "0.0.0.0"
386
447
  };
387
- this.facilitatorUrl = options.facilitatorUrl || DEFAULT_FACILITATOR_URL;
448
+ if (this.cdpConfig.useMainnet) {
449
+ if (!this.cdpConfig.apiKeyId || !this.cdpConfig.apiKeySecret) {
450
+ console.warn("[MoltsPay] WARNING: USE_MAINNET=true but CDP keys not set!");
451
+ console.warn("[MoltsPay] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in ~/.moltspay/.env");
452
+ }
453
+ this.facilitatorUrl = FACILITATOR_MAINNET;
454
+ this.networkId = "eip155:8453";
455
+ } else {
456
+ this.facilitatorUrl = options.facilitatorUrl || FACILITATOR_TESTNET;
457
+ this.networkId = "eip155:84532";
458
+ }
459
+ const networkName = this.cdpConfig.useMainnet ? "Base mainnet" : "Base Sepolia (testnet)";
460
+ const facilitatorName = this.cdpConfig.useMainnet ? "CDP" : "x402.org";
388
461
  console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);
389
462
  console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);
390
463
  console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);
391
- console.log(`[MoltsPay] Facilitator: ${this.facilitatorUrl}`);
464
+ console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);
465
+ console.log(`[MoltsPay] Facilitator: ${facilitatorName} (${this.facilitatorUrl})`);
466
+ if (this.cdpConfig.useMainnet && this.cdpConfig.apiKeyId) {
467
+ console.log(`[MoltsPay] CDP API Key: ${this.cdpConfig.apiKeyId.slice(0, 8)}...`);
468
+ }
392
469
  console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);
393
470
  }
394
471
  /**
@@ -449,7 +526,6 @@ var MoltsPayServer = class {
449
526
  * GET /services - List available services
450
527
  */
451
528
  handleGetServices(res) {
452
- const chain = getChain(this.manifest.provider.chain);
453
529
  const services = this.manifest.services.map((s) => ({
454
530
  id: s.id,
455
531
  name: s.name,
@@ -465,16 +541,15 @@ var MoltsPayServer = class {
465
541
  services,
466
542
  x402: {
467
543
  version: X402_VERSION2,
468
- network: `eip155:${chain.chainId}`,
544
+ network: this.networkId,
469
545
  schemes: ["exact"],
470
- facilitator: this.facilitatorUrl
546
+ facilitator: this.cdpConfig.useMainnet ? "cdp" : "x402.org",
547
+ mainnet: this.cdpConfig.useMainnet
471
548
  }
472
549
  });
473
550
  }
474
551
  /**
475
552
  * POST /execute - Execute service with x402 payment
476
- * Body: { service: string, params: object }
477
- * Header: X-Payment (optional - if missing, returns 402)
478
553
  */
479
554
  async handleExecute(body, paymentHeader, res) {
480
555
  const { service, params } = body;
@@ -549,17 +624,8 @@ var MoltsPayServer = class {
549
624
  * Return 402 with x402 payment requirements
550
625
  */
551
626
  sendPaymentRequired(config, res) {
552
- const chain = getChain(this.manifest.provider.chain);
553
- const amountInUnits = Math.floor(config.price * 1e6).toString();
554
- const requirements = [{
555
- scheme: "exact",
556
- network: `eip155:${chain.chainId}`,
557
- maxAmountRequired: amountInUnits,
558
- resource: this.manifest.provider.wallet,
559
- description: `${config.name} - $${config.price} ${config.currency}`,
560
- // Include facilitator info for client
561
- extra: JSON.stringify({ facilitator: this.facilitatorUrl })
562
- }];
627
+ const requirements = [this.buildPaymentRequirements(config)];
628
+ requirements[0].description = `${config.name} - $${config.price} ${config.currency}`;
563
629
  const encoded = Buffer.from(JSON.stringify(requirements)).toString("base64");
564
630
  res.writeHead(402, {
565
631
  "Content-Type": "application/json",
@@ -572,7 +638,7 @@ var MoltsPayServer = class {
572
638
  }, null, 2));
573
639
  }
574
640
  /**
575
- * Basic payment validation (before calling facilitator)
641
+ * Basic payment validation
576
642
  */
577
643
  validatePayment(payment, config) {
578
644
  if (payment.x402Version !== X402_VERSION2) {
@@ -581,37 +647,57 @@ var MoltsPayServer = class {
581
647
  if (payment.scheme !== "exact") {
582
648
  return { valid: false, error: `Unsupported scheme: ${payment.scheme}` };
583
649
  }
584
- const chain = getChain(this.manifest.provider.chain);
585
- const expectedNetwork = `eip155:${chain.chainId}`;
586
- if (payment.network !== expectedNetwork) {
587
- return { valid: false, error: `Network mismatch: expected ${expectedNetwork}` };
650
+ if (payment.network !== this.networkId) {
651
+ return { valid: false, error: `Network mismatch: expected ${this.networkId}, got ${payment.network}` };
588
652
  }
589
653
  return { valid: true };
590
654
  }
591
655
  /**
592
- * Verify payment with facilitator
656
+ * Build complete payment requirements for facilitator
657
+ */
658
+ buildPaymentRequirements(config) {
659
+ const amountInUnits = Math.floor(config.price * 1e6).toString();
660
+ const usdcAddress = USDC_ADDRESSES[this.networkId];
661
+ return {
662
+ scheme: "exact",
663
+ network: this.networkId,
664
+ maxAmountRequired: amountInUnits,
665
+ amount: amountInUnits,
666
+ asset: usdcAddress,
667
+ payTo: this.manifest.provider.wallet,
668
+ maxTimeoutSeconds: 300,
669
+ extra: USDC_DOMAIN
670
+ };
671
+ }
672
+ /**
673
+ * Verify payment with facilitator (testnet or CDP)
593
674
  */
594
675
  async verifyWithFacilitator(payment, config) {
595
676
  try {
596
- const chain = getChain(this.manifest.provider.chain);
597
- const amountInUnits = Math.floor(config.price * 1e6).toString();
598
- const requirements = {
599
- scheme: "exact",
600
- network: `eip155:${chain.chainId}`,
601
- maxAmountRequired: amountInUnits,
602
- resource: this.manifest.provider.wallet
677
+ const requirements = this.buildPaymentRequirements(config);
678
+ const requestBody = {
679
+ paymentPayload: payment,
680
+ paymentRequirements: requirements
603
681
  };
682
+ console.log("[MoltsPay] Verify request:", JSON.stringify(requestBody, null, 2));
683
+ let headers = { "Content-Type": "application/json" };
684
+ if (this.cdpConfig.useMainnet) {
685
+ const authHeaders = await getCDPAuthHeaders(
686
+ "POST",
687
+ "/platform/v2/x402/verify",
688
+ requestBody
689
+ );
690
+ headers = { ...headers, ...authHeaders };
691
+ }
604
692
  const response = await fetch(`${this.facilitatorUrl}/verify`, {
605
693
  method: "POST",
606
- headers: { "Content-Type": "application/json" },
607
- body: JSON.stringify({
608
- paymentPayload: payment,
609
- paymentRequirements: requirements
610
- })
694
+ headers,
695
+ body: JSON.stringify(requestBody)
611
696
  });
612
697
  const result = await response.json();
698
+ console.log("[MoltsPay] Verify response:", JSON.stringify(result, null, 2));
613
699
  if (!response.ok || !result.isValid) {
614
- return { valid: false, error: result.invalidReason || "Verification failed" };
700
+ return { valid: false, error: result.invalidReason || result.error || "Verification failed" };
615
701
  }
616
702
  return { valid: true };
617
703
  } catch (err) {
@@ -622,25 +708,28 @@ var MoltsPayServer = class {
622
708
  * Settle payment with facilitator (execute on-chain transfer)
623
709
  */
624
710
  async settleWithFacilitator(payment, config) {
625
- const chain = getChain(this.manifest.provider.chain);
626
- const amountInUnits = Math.floor(config.price * 1e6).toString();
627
- const requirements = {
628
- scheme: "exact",
629
- network: `eip155:${chain.chainId}`,
630
- maxAmountRequired: amountInUnits,
631
- resource: this.manifest.provider.wallet
711
+ const requirements = this.buildPaymentRequirements(config);
712
+ const requestBody = {
713
+ paymentPayload: payment,
714
+ paymentRequirements: requirements
632
715
  };
716
+ let headers = { "Content-Type": "application/json" };
717
+ if (this.cdpConfig.useMainnet) {
718
+ const authHeaders = await getCDPAuthHeaders(
719
+ "POST",
720
+ "/platform/v2/x402/settle",
721
+ requestBody
722
+ );
723
+ headers = { ...headers, ...authHeaders };
724
+ }
633
725
  const response = await fetch(`${this.facilitatorUrl}/settle`, {
634
726
  method: "POST",
635
- headers: { "Content-Type": "application/json" },
636
- body: JSON.stringify({
637
- paymentPayload: payment,
638
- paymentRequirements: requirements
639
- })
727
+ headers,
728
+ body: JSON.stringify(requestBody)
640
729
  });
641
730
  const result = await response.json();
642
- if (!response.ok) {
643
- throw new Error(result.error || "Settlement failed");
731
+ if (!response.ok || !result.success) {
732
+ throw new Error(result.error || result.errorReason || "Settlement failed");
644
733
  }
645
734
  return {
646
735
  transaction: result.transaction,