moltspay 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -30369,7 +30369,6 @@ init_cjs_shims();
30369
30369
  init_cjs_shims();
30370
30370
  var import_fs = require("fs");
30371
30371
  var import_http = require("http");
30372
- var import_ethers = require("ethers");
30373
30372
 
30374
30373
  // src/chains/index.ts
30375
30374
  init_cjs_shims();
@@ -30456,34 +30455,26 @@ init_cjs_shims();
30456
30455
  var X402_VERSION = 2;
30457
30456
  var PAYMENT_REQUIRED_HEADER = "x-payment-required";
30458
30457
  var PAYMENT_HEADER = "x-payment";
30458
+ var PAYMENT_RESPONSE_HEADER = "x-payment-response";
30459
+ var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
30459
30460
  var MoltsPayServer = class {
30460
30461
  manifest;
30461
30462
  skills = /* @__PURE__ */ new Map();
30462
30463
  options;
30463
- provider = null;
30464
- wallet = null;
30464
+ facilitatorUrl;
30465
30465
  constructor(servicesPath, options = {}) {
30466
30466
  const content = (0, import_fs.readFileSync)(servicesPath, "utf-8");
30467
30467
  this.manifest = JSON.parse(content);
30468
30468
  this.options = {
30469
30469
  port: options.port || 3e3,
30470
- host: options.host || "0.0.0.0",
30471
- privateKey: options.privateKey || process.env.MOLTSPAY_PRIVATE_KEY
30470
+ host: options.host || "0.0.0.0"
30472
30471
  };
30473
- if (this.options.privateKey) {
30474
- try {
30475
- const chain2 = getChain(this.manifest.provider.chain);
30476
- this.provider = new import_ethers.ethers.JsonRpcProvider(chain2.rpc);
30477
- this.wallet = new import_ethers.ethers.Wallet(this.options.privateKey, this.provider);
30478
- console.log(`[MoltsPay] Payment wallet: ${this.wallet.address}`);
30479
- } catch (err) {
30480
- console.warn("[MoltsPay] Warning: Could not initialize wallet for payment claims");
30481
- }
30482
- }
30472
+ this.facilitatorUrl = options.facilitatorUrl || DEFAULT_FACILITATOR_URL;
30483
30473
  console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);
30484
30474
  console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);
30485
30475
  console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);
30486
- console.log(`[MoltsPay] Protocol: x402 (gasless, pay-for-success)`);
30476
+ console.log(`[MoltsPay] Facilitator: ${this.facilitatorUrl}`);
30477
+ console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);
30487
30478
  }
30488
30479
  /**
30489
30480
  * Register a skill handler for a service
@@ -30493,48 +30484,45 @@ var MoltsPayServer = class {
30493
30484
  if (!config) {
30494
30485
  throw new Error(`Service '${serviceId}' not found in manifest`);
30495
30486
  }
30496
- this.skills.set(serviceId, {
30497
- id: serviceId,
30498
- config,
30499
- handler
30500
- });
30501
- console.log(`[MoltsPay] Registered skill: ${serviceId} ($${config.price} ${config.currency})`);
30487
+ this.skills.set(serviceId, { id: serviceId, config, handler });
30502
30488
  return this;
30503
30489
  }
30504
30490
  /**
30505
- * Start the server
30491
+ * Start HTTP server
30506
30492
  */
30507
30493
  listen(port) {
30508
- const p = port || this.options.port;
30494
+ const p = port || this.options.port || 3e3;
30495
+ const host = this.options.host || "0.0.0.0";
30509
30496
  const server = (0, import_http.createServer)((req, res) => this.handleRequest(req, res));
30510
- server.listen(p, this.options.host, () => {
30511
- console.log(`[MoltsPay] Server listening on http://${this.options.host}:${p}`);
30497
+ server.listen(p, host, () => {
30498
+ console.log(`[MoltsPay] Server listening on http://${host}:${p}`);
30512
30499
  console.log(`[MoltsPay] Endpoints:`);
30513
30500
  console.log(` GET /services - List available services`);
30514
30501
  console.log(` POST /execute - Execute service (x402 payment)`);
30515
30502
  });
30516
30503
  }
30504
+ /**
30505
+ * Handle incoming request
30506
+ */
30517
30507
  async handleRequest(req, res) {
30518
- const url = new URL(req.url || "/", `http://${req.headers.host}`);
30519
- const path2 = url.pathname;
30520
- const method = req.method || "GET";
30521
30508
  res.setHeader("Access-Control-Allow-Origin", "*");
30522
30509
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
30523
30510
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Payment");
30524
30511
  res.setHeader("Access-Control-Expose-Headers", "X-Payment-Required, X-Payment-Response");
30525
- if (method === "OPTIONS") {
30512
+ if (req.method === "OPTIONS") {
30526
30513
  res.writeHead(204);
30527
30514
  res.end();
30528
30515
  return;
30529
30516
  }
30530
30517
  try {
30531
- if (method === "GET" && path2 === "/services") {
30518
+ const url = new URL(req.url || "/", `http://${req.headers.host}`);
30519
+ if (url.pathname === "/services" && req.method === "GET") {
30532
30520
  return this.handleGetServices(res);
30533
30521
  }
30534
- if (method === "POST" && path2 === "/execute") {
30522
+ if (url.pathname === "/execute" && req.method === "POST") {
30535
30523
  const body = await this.readBody(req);
30536
30524
  const paymentHeader = req.headers[PAYMENT_HEADER];
30537
- return this.handleExecute(body, paymentHeader, res);
30525
+ return await this.handleExecute(body, paymentHeader, res);
30538
30526
  }
30539
30527
  this.sendJson(res, 404, { error: "Not found" });
30540
30528
  } catch (err) {
@@ -30563,7 +30551,8 @@ var MoltsPayServer = class {
30563
30551
  x402: {
30564
30552
  version: X402_VERSION,
30565
30553
  network: `eip155:${chain2.chainId}`,
30566
- schemes: ["exact"]
30554
+ schemes: ["exact"],
30555
+ facilitator: this.facilitatorUrl
30567
30556
  }
30568
30557
  });
30569
30558
  }
@@ -30600,6 +30589,11 @@ var MoltsPayServer = class {
30600
30589
  if (!validation.valid) {
30601
30590
  return this.sendJson(res, 402, { error: validation.error });
30602
30591
  }
30592
+ console.log(`[MoltsPay] Verifying payment with facilitator...`);
30593
+ const verifyResult = await this.verifyWithFacilitator(payment, skill.config);
30594
+ if (!verifyResult.valid) {
30595
+ return this.sendJson(res, 402, { error: `Payment verification failed: ${verifyResult.error}` });
30596
+ }
30603
30597
  console.log(`[MoltsPay] Executing skill: ${service}`);
30604
30598
  let result;
30605
30599
  try {
@@ -30611,19 +30605,30 @@ var MoltsPayServer = class {
30611
30605
  message: err.message
30612
30606
  });
30613
30607
  }
30614
- console.log(`[MoltsPay] Skill succeeded, claiming payment...`);
30615
- let txHash = null;
30608
+ console.log(`[MoltsPay] Skill succeeded, settling payment...`);
30609
+ let settlement = null;
30616
30610
  try {
30617
- txHash = await this.claimPayment(payment);
30618
- console.log(`[MoltsPay] Payment claimed: ${txHash}`);
30611
+ settlement = await this.settleWithFacilitator(payment, skill.config);
30612
+ console.log(`[MoltsPay] Payment settled: ${settlement.transaction || "pending"}`);
30619
30613
  } catch (err) {
30620
- console.error("[MoltsPay] Payment claim failed:", err.message);
30614
+ console.error("[MoltsPay] Settlement failed:", err.message);
30615
+ }
30616
+ const responseHeaders = {};
30617
+ if (settlement) {
30618
+ const responsePayload = {
30619
+ success: true,
30620
+ transaction: settlement.transaction,
30621
+ network: payment.network
30622
+ };
30623
+ responseHeaders[PAYMENT_RESPONSE_HEADER] = Buffer.from(
30624
+ JSON.stringify(responsePayload)
30625
+ ).toString("base64");
30621
30626
  }
30622
30627
  this.sendJson(res, 200, {
30623
30628
  success: true,
30624
30629
  result,
30625
- payment: txHash ? { txHash, status: "claimed" } : { status: "pending" }
30626
- });
30630
+ payment: settlement ? { transaction: settlement.transaction, status: "settled" } : { status: "pending" }
30631
+ }, responseHeaders);
30627
30632
  }
30628
30633
  /**
30629
30634
  * Return 402 with x402 payment requirements
@@ -30636,7 +30641,9 @@ var MoltsPayServer = class {
30636
30641
  network: `eip155:${chain2.chainId}`,
30637
30642
  maxAmountRequired: amountInUnits,
30638
30643
  resource: this.manifest.provider.wallet,
30639
- description: `${config.name} - $${config.price} ${config.currency}`
30644
+ description: `${config.name} - $${config.price} ${config.currency}`,
30645
+ // Include facilitator info for client
30646
+ extra: JSON.stringify({ facilitator: this.facilitatorUrl })
30640
30647
  }];
30641
30648
  const encoded = Buffer.from(JSON.stringify(requirements)).toString("base64");
30642
30649
  res.writeHead(402, {
@@ -30650,7 +30657,7 @@ var MoltsPayServer = class {
30650
30657
  }, null, 2));
30651
30658
  }
30652
30659
  /**
30653
- * Validate x402 payment payload
30660
+ * Basic payment validation (before calling facilitator)
30654
30661
  */
30655
30662
  validatePayment(payment, config) {
30656
30663
  if (payment.x402Version !== X402_VERSION) {
@@ -30664,51 +30671,66 @@ var MoltsPayServer = class {
30664
30671
  if (payment.network !== expectedNetwork) {
30665
30672
  return { valid: false, error: `Network mismatch: expected ${expectedNetwork}` };
30666
30673
  }
30667
- const auth = payment.payload.authorization;
30668
- if (auth.to.toLowerCase() !== this.manifest.provider.wallet.toLowerCase()) {
30669
- return { valid: false, error: "Payment recipient mismatch" };
30670
- }
30671
- const amount = Number(auth.value) / 1e6;
30672
- if (amount < config.price) {
30673
- return { valid: false, error: `Insufficient amount: $${amount} < $${config.price}` };
30674
- }
30675
- const now = Math.floor(Date.now() / 1e3);
30676
- if (Number(auth.validBefore) < now) {
30677
- return { valid: false, error: "Payment authorization expired" };
30678
- }
30679
- if (Number(auth.validAfter) > now) {
30680
- return { valid: false, error: "Payment authorization not yet valid" };
30681
- }
30682
30674
  return { valid: true };
30683
30675
  }
30684
30676
  /**
30685
- * Claim payment using transferWithAuthorization
30677
+ * Verify payment with facilitator
30686
30678
  */
30687
- async claimPayment(payment) {
30688
- if (!this.wallet || !this.provider) {
30689
- throw new Error("Wallet not configured for payment claims");
30679
+ async verifyWithFacilitator(payment, config) {
30680
+ try {
30681
+ const chain2 = getChain(this.manifest.provider.chain);
30682
+ const amountInUnits = Math.floor(config.price * 1e6).toString();
30683
+ const requirements = {
30684
+ scheme: "exact",
30685
+ network: `eip155:${chain2.chainId}`,
30686
+ maxAmountRequired: amountInUnits,
30687
+ resource: this.manifest.provider.wallet
30688
+ };
30689
+ const response = await fetch(`${this.facilitatorUrl}/verify`, {
30690
+ method: "POST",
30691
+ headers: { "Content-Type": "application/json" },
30692
+ body: JSON.stringify({
30693
+ paymentPayload: payment,
30694
+ paymentRequirements: requirements
30695
+ })
30696
+ });
30697
+ const result = await response.json();
30698
+ if (!response.ok || !result.isValid) {
30699
+ return { valid: false, error: result.invalidReason || "Verification failed" };
30700
+ }
30701
+ return { valid: true };
30702
+ } catch (err) {
30703
+ return { valid: false, error: `Facilitator error: ${err.message}` };
30690
30704
  }
30705
+ }
30706
+ /**
30707
+ * Settle payment with facilitator (execute on-chain transfer)
30708
+ */
30709
+ async settleWithFacilitator(payment, config) {
30691
30710
  const chain2 = getChain(this.manifest.provider.chain);
30692
- const auth = payment.payload.authorization;
30693
- const sig = payment.payload.signature;
30694
- const { r, s, v } = import_ethers.ethers.Signature.from(sig);
30695
- const usdcAbi = [
30696
- "function transferWithAuthorization(address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s)"
30697
- ];
30698
- const usdc = new import_ethers.ethers.Contract(chain2.usdc, usdcAbi, this.wallet);
30699
- const tx = await usdc.transferWithAuthorization(
30700
- auth.from,
30701
- auth.to,
30702
- auth.value,
30703
- auth.validAfter,
30704
- auth.validBefore,
30705
- auth.nonce,
30706
- v,
30707
- r,
30708
- s
30709
- );
30710
- const receipt = await tx.wait();
30711
- return receipt.hash;
30711
+ const amountInUnits = Math.floor(config.price * 1e6).toString();
30712
+ const requirements = {
30713
+ scheme: "exact",
30714
+ network: `eip155:${chain2.chainId}`,
30715
+ maxAmountRequired: amountInUnits,
30716
+ resource: this.manifest.provider.wallet
30717
+ };
30718
+ const response = await fetch(`${this.facilitatorUrl}/settle`, {
30719
+ method: "POST",
30720
+ headers: { "Content-Type": "application/json" },
30721
+ body: JSON.stringify({
30722
+ paymentPayload: payment,
30723
+ paymentRequirements: requirements
30724
+ })
30725
+ });
30726
+ const result = await response.json();
30727
+ if (!response.ok) {
30728
+ throw new Error(result.error || "Settlement failed");
30729
+ }
30730
+ return {
30731
+ transaction: result.transaction,
30732
+ status: result.status || "settled"
30733
+ };
30712
30734
  }
30713
30735
  async readBody(req) {
30714
30736
  return new Promise((resolve, reject) => {
@@ -30724,8 +30746,12 @@ var MoltsPayServer = class {
30724
30746
  req.on("error", reject);
30725
30747
  });
30726
30748
  }
30727
- sendJson(res, status, data) {
30728
- res.writeHead(status, { "Content-Type": "application/json" });
30749
+ sendJson(res, status, data, extraHeaders) {
30750
+ const headers = { "Content-Type": "application/json" };
30751
+ if (extraHeaders) {
30752
+ Object.assign(headers, extraHeaders);
30753
+ }
30754
+ res.writeHead(status, headers);
30729
30755
  res.end(JSON.stringify(data, null, 2));
30730
30756
  }
30731
30757
  };
@@ -30735,7 +30761,7 @@ init_cjs_shims();
30735
30761
  var import_fs2 = require("fs");
30736
30762
  var import_os = require("os");
30737
30763
  var import_path = require("path");
30738
- var import_ethers2 = require("ethers");
30764
+ var import_ethers = require("ethers");
30739
30765
 
30740
30766
  // src/client/types.ts
30741
30767
  init_cjs_shims();
@@ -30763,7 +30789,7 @@ var MoltsPayClient = class {
30763
30789
  this.config = this.loadConfig();
30764
30790
  this.walletData = this.loadWallet();
30765
30791
  if (this.walletData) {
30766
- this.wallet = new import_ethers2.Wallet(this.walletData.privateKey);
30792
+ this.wallet = new import_ethers.Wallet(this.walletData.privateKey);
30767
30793
  }
30768
30794
  }
30769
30795
  /**
@@ -30884,7 +30910,7 @@ var MoltsPayClient = class {
30884
30910
  async signEIP3009(to, amount, chain2) {
30885
30911
  const validAfter = 0;
30886
30912
  const validBefore = Math.floor(Date.now() / 1e3) + 3600;
30887
- const nonce = import_ethers2.ethers.hexlify(import_ethers2.ethers.randomBytes(32));
30913
+ const nonce = import_ethers.ethers.hexlify(import_ethers.ethers.randomBytes(32));
30888
30914
  const value = BigInt(Math.floor(amount * 1e6)).toString();
30889
30915
  const authorization = {
30890
30916
  from: this.wallet.address,
@@ -30966,7 +30992,7 @@ var MoltsPayClient = class {
30966
30992
  */
30967
30993
  static init(configDir, options) {
30968
30994
  (0, import_fs2.mkdirSync)(configDir, { recursive: true });
30969
- const wallet = import_ethers2.Wallet.createRandom();
30995
+ const wallet = import_ethers.Wallet.createRandom();
30970
30996
  const walletData = {
30971
30997
  address: wallet.address,
30972
30998
  privateKey: wallet.privateKey,
@@ -30998,14 +31024,14 @@ var MoltsPayClient = class {
30998
31024
  } catch {
30999
31025
  throw new Error(`Unknown chain: ${this.config.chain}`);
31000
31026
  }
31001
- const provider = new import_ethers2.ethers.JsonRpcProvider(chain2.rpc);
31027
+ const provider = new import_ethers.ethers.JsonRpcProvider(chain2.rpc);
31002
31028
  const nativeBalance = await provider.getBalance(this.wallet.address);
31003
31029
  const usdcAbi = ["function balanceOf(address) view returns (uint256)"];
31004
- const usdc = new import_ethers2.ethers.Contract(chain2.usdc, usdcAbi, provider);
31030
+ const usdc = new import_ethers.ethers.Contract(chain2.usdc, usdcAbi, provider);
31005
31031
  const usdcBalance = await usdc.balanceOf(this.wallet.address);
31006
31032
  return {
31007
- usdc: parseFloat(import_ethers2.ethers.formatUnits(usdcBalance, 6)),
31008
- native: parseFloat(import_ethers2.ethers.formatEther(nativeBalance))
31033
+ usdc: parseFloat(import_ethers.ethers.formatUnits(usdcBalance, 6)),
31034
+ native: parseFloat(import_ethers.ethers.formatEther(nativeBalance))
31009
31035
  };
31010
31036
  }
31011
31037
  };
@@ -31015,11 +31041,11 @@ init_cjs_shims();
31015
31041
 
31016
31042
  // src/wallet/Wallet.ts
31017
31043
  init_cjs_shims();
31018
- var import_ethers3 = require("ethers");
31044
+ var import_ethers2 = require("ethers");
31019
31045
 
31020
31046
  // src/wallet/createWallet.ts
31021
31047
  init_cjs_shims();
31022
- var import_ethers4 = require("ethers");
31048
+ var import_ethers3 = require("ethers");
31023
31049
  var import_fs3 = require("fs");
31024
31050
  var import_path2 = require("path");
31025
31051
  var import_crypto = require("crypto");
@@ -31064,7 +31090,7 @@ function createWallet(options = {}) {
31064
31090
  }
31065
31091
  }
31066
31092
  try {
31067
- const wallet = import_ethers4.ethers.Wallet.createRandom();
31093
+ const wallet = import_ethers3.ethers.Wallet.createRandom();
31068
31094
  const walletData = {
31069
31095
  address: wallet.address,
31070
31096
  label: options.label,
@@ -31137,8 +31163,8 @@ function walletExists(storagePath) {
31137
31163
 
31138
31164
  // src/verify/index.ts
31139
31165
  init_cjs_shims();
31140
- var import_ethers5 = require("ethers");
31141
- var TRANSFER_EVENT_TOPIC = import_ethers5.ethers.id("Transfer(address,address,uint256)");
31166
+ var import_ethers4 = require("ethers");
31167
+ var TRANSFER_EVENT_TOPIC = import_ethers4.ethers.id("Transfer(address,address,uint256)");
31142
31168
  async function verifyPayment(params) {
31143
31169
  const { txHash, expectedAmount, expectedTo } = params;
31144
31170
  let chain2;
@@ -31155,7 +31181,7 @@ async function verifyPayment(params) {
31155
31181
  return { verified: false, error: `Unsupported chain: ${params.chain}` };
31156
31182
  }
31157
31183
  try {
31158
- const provider = new import_ethers5.ethers.JsonRpcProvider(chain2.rpc);
31184
+ const provider = new import_ethers4.ethers.JsonRpcProvider(chain2.rpc);
31159
31185
  const receipt = await provider.getTransactionReceipt(txHash);
31160
31186
  if (!receipt) {
31161
31187
  return { verified: false, error: "Transaction not found or not confirmed" };
@@ -31215,7 +31241,7 @@ async function getTransactionStatus(txHash, chain2 = "base") {
31215
31241
  return { status: "not_found" };
31216
31242
  }
31217
31243
  try {
31218
- const provider = new import_ethers5.ethers.JsonRpcProvider(chainConfig.rpc);
31244
+ const provider = new import_ethers4.ethers.JsonRpcProvider(chainConfig.rpc);
31219
31245
  const receipt = await provider.getTransactionReceipt(txHash);
31220
31246
  if (!receipt) {
31221
31247
  const tx = await provider.getTransaction(txHash);
@@ -31252,7 +31278,7 @@ async function waitForTransaction(txHash, chain2 = "base", confirmations = 1, ti
31252
31278
  } catch (e) {
31253
31279
  return { verified: false, confirmed: false, error: `Unsupported chain: ${chain2}` };
31254
31280
  }
31255
- const provider = new import_ethers5.ethers.JsonRpcProvider(chainConfig.rpc);
31281
+ const provider = new import_ethers4.ethers.JsonRpcProvider(chainConfig.rpc);
31256
31282
  try {
31257
31283
  const receipt = await provider.waitForTransaction(txHash, confirmations, timeoutMs);
31258
31284
  if (!receipt) {
@@ -31393,9 +31419,9 @@ var CDPWallet = class {
31393
31419
  * Get USDC balance
31394
31420
  */
31395
31421
  async getBalance() {
31396
- const { ethers: ethers6 } = await import("ethers");
31397
- const provider = new ethers6.JsonRpcProvider(this.chainConfig.rpc);
31398
- const usdcContract = new ethers6.Contract(
31422
+ const { ethers: ethers5 } = await import("ethers");
31423
+ const provider = new ethers5.JsonRpcProvider(this.chainConfig.rpc);
31424
+ const usdcContract = new ethers5.Contract(
31399
31425
  this.chainConfig.usdc,
31400
31426
  ["function balanceOf(address) view returns (uint256)"],
31401
31427
  provider
@@ -31406,7 +31432,7 @@ var CDPWallet = class {
31406
31432
  ]);
31407
31433
  return {
31408
31434
  usdc: (Number(usdcBalance) / 1e6).toFixed(2),
31409
- eth: ethers6.formatEther(ethBalance)
31435
+ eth: ethers5.formatEther(ethBalance)
31410
31436
  };
31411
31437
  }
31412
31438
  /**
@@ -31424,7 +31450,7 @@ var CDPWallet = class {
31424
31450
  }
31425
31451
  try {
31426
31452
  const { CdpClient } = await import("@coinbase/cdp-sdk");
31427
- const { ethers: ethers6 } = await import("ethers");
31453
+ const { ethers: ethers5 } = await import("ethers");
31428
31454
  const cdp = new CdpClient({
31429
31455
  apiKeyId: creds.apiKeyId,
31430
31456
  apiKeySecret: creds.apiKeySecret,
@@ -31432,7 +31458,7 @@ var CDPWallet = class {
31432
31458
  });
31433
31459
  const account = await cdp.evm.getAccount({ address: this.address });
31434
31460
  const amountWei = BigInt(Math.floor(params.amount * 1e6));
31435
- const iface = new ethers6.Interface([
31461
+ const iface = new ethers5.Interface([
31436
31462
  "function transfer(address to, uint256 amount) returns (bool)"
31437
31463
  ]);
31438
31464
  const callData = iface.encodeFunctionData("transfer", [params.to, amountWei]);