moltspay 1.2.0 → 1.3.0

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.
Files changed (58) hide show
  1. package/README.md +161 -17
  2. package/dist/cdp/index.d.mts +1 -1
  3. package/dist/cdp/index.d.ts +1 -1
  4. package/dist/cdp/index.js +60 -30408
  5. package/dist/cdp/index.js.map +1 -1
  6. package/dist/cdp/index.mjs +44 -30400
  7. package/dist/cdp/index.mjs.map +1 -1
  8. package/dist/cdp-DeohBe1o.d.ts +66 -0
  9. package/dist/cdp-p_eHuQpb.d.mts +66 -0
  10. package/dist/chains/index.d.mts +1 -1
  11. package/dist/chains/index.d.ts +1 -1
  12. package/dist/chains/index.js +36 -40
  13. package/dist/chains/index.js.map +1 -1
  14. package/dist/chains/index.mjs +36 -40
  15. package/dist/chains/index.mjs.map +1 -1
  16. package/dist/cli/index.js +997 -174
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/cli/index.mjs +1001 -174
  19. package/dist/cli/index.mjs.map +1 -1
  20. package/dist/client/index.d.mts +27 -4
  21. package/dist/client/index.d.ts +27 -4
  22. package/dist/client/index.js +217 -60
  23. package/dist/client/index.js.map +1 -1
  24. package/dist/client/index.mjs +207 -60
  25. package/dist/client/index.mjs.map +1 -1
  26. package/dist/facilitators/index.d.mts +15 -47
  27. package/dist/facilitators/index.d.ts +15 -47
  28. package/dist/facilitators/index.js +273 -34
  29. package/dist/facilitators/index.js.map +1 -1
  30. package/dist/facilitators/index.mjs +272 -34
  31. package/dist/facilitators/index.mjs.map +1 -1
  32. package/dist/{index-B3v8IWjM.d.mts → index-On9ZaGDW.d.mts} +2 -1
  33. package/dist/{index-B3v8IWjM.d.ts → index-On9ZaGDW.d.ts} +2 -1
  34. package/dist/index.d.mts +2 -2
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.js +792 -30657
  37. package/dist/index.js.map +1 -1
  38. package/dist/index.mjs +782 -30657
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/server/index.d.mts +17 -0
  41. package/dist/server/index.d.ts +17 -0
  42. package/dist/server/index.js +513 -48
  43. package/dist/server/index.js.map +1 -1
  44. package/dist/server/index.mjs +513 -48
  45. package/dist/server/index.mjs.map +1 -1
  46. package/dist/verify/index.d.mts +1 -1
  47. package/dist/verify/index.d.ts +1 -1
  48. package/dist/verify/index.js +36 -40
  49. package/dist/verify/index.js.map +1 -1
  50. package/dist/verify/index.mjs +36 -40
  51. package/dist/verify/index.mjs.map +1 -1
  52. package/dist/wallet/index.d.mts +1 -1
  53. package/dist/wallet/index.d.ts +1 -1
  54. package/dist/wallet/index.js +36 -40
  55. package/dist/wallet/index.js.map +1 -1
  56. package/dist/wallet/index.mjs +36 -40
  57. package/dist/wallet/index.mjs.map +1 -1
  58. package/package.json +5 -2
@@ -1,4 +1,4 @@
1
- import { T as TokenSymbol } from '../index-B3v8IWjM.mjs';
1
+ import { T as TokenSymbol } from '../index-On9ZaGDW.mjs';
2
2
 
3
3
  /**
4
4
  * MoltsPay Client Types
@@ -78,8 +78,8 @@ interface PayOptions {
78
78
  token?: TokenSymbol;
79
79
  /** Auto-select token based on balance (default: false) */
80
80
  autoSelect?: boolean;
81
- /** Chain to pay on (base or polygon, default: base) */
82
- chain?: 'base' | 'polygon';
81
+ /** Chain to pay on (base, polygon, or base_sepolia, default: base) */
82
+ chain?: 'base' | 'polygon' | 'base_sepolia';
83
83
  }
84
84
  declare class MoltsPayClient {
85
85
  private configDir;
@@ -166,13 +166,36 @@ declare class MoltsPayClient {
166
166
  native: number;
167
167
  }>;
168
168
  /**
169
- * Get wallet balances on all supported chains (Base + Polygon)
169
+ * Get wallet balances on all supported chains (Base + Polygon + Tempo)
170
170
  */
171
171
  getAllBalances(): Promise<Record<string, {
172
172
  usdc: number;
173
173
  usdt: number;
174
174
  native: number;
175
+ tempo?: {
176
+ pathUSD: number;
177
+ alphaUSD: number;
178
+ betaUSD: number;
179
+ thetaUSD: number;
180
+ };
175
181
  }>>;
182
+ /**
183
+ * Pay for a service using MPP (Machine Payments Protocol)
184
+ *
185
+ * This implements the MPP flow manually for EOA wallets:
186
+ * 1. Request service → get 402 with WWW-Authenticate
187
+ * 2. Parse payment requirements
188
+ * 3. Execute transfer on Tempo chain
189
+ * 4. Retry with transaction hash as credential
190
+ *
191
+ * @param url - Full URL of the MPP-enabled endpoint
192
+ * @param options - Request options (body, headers)
193
+ * @returns Response from the service
194
+ */
195
+ payWithMPP(url: string, options?: {
196
+ body?: any;
197
+ headers?: Record<string, string>;
198
+ }): Promise<any>;
176
199
  }
177
200
 
178
201
  export { type ClientConfig, MoltsPayClient, type MoltsPayClientOptions, type PayOptions, type PaymentRequired, type ProviderInfo, type ServiceInfo, type ServicesResponse, type VerifyResponse, type WalletData };
@@ -1,4 +1,4 @@
1
- import { T as TokenSymbol } from '../index-B3v8IWjM.js';
1
+ import { T as TokenSymbol } from '../index-On9ZaGDW.js';
2
2
 
3
3
  /**
4
4
  * MoltsPay Client Types
@@ -78,8 +78,8 @@ interface PayOptions {
78
78
  token?: TokenSymbol;
79
79
  /** Auto-select token based on balance (default: false) */
80
80
  autoSelect?: boolean;
81
- /** Chain to pay on (base or polygon, default: base) */
82
- chain?: 'base' | 'polygon';
81
+ /** Chain to pay on (base, polygon, or base_sepolia, default: base) */
82
+ chain?: 'base' | 'polygon' | 'base_sepolia';
83
83
  }
84
84
  declare class MoltsPayClient {
85
85
  private configDir;
@@ -166,13 +166,36 @@ declare class MoltsPayClient {
166
166
  native: number;
167
167
  }>;
168
168
  /**
169
- * Get wallet balances on all supported chains (Base + Polygon)
169
+ * Get wallet balances on all supported chains (Base + Polygon + Tempo)
170
170
  */
171
171
  getAllBalances(): Promise<Record<string, {
172
172
  usdc: number;
173
173
  usdt: number;
174
174
  native: number;
175
+ tempo?: {
176
+ pathUSD: number;
177
+ alphaUSD: number;
178
+ betaUSD: number;
179
+ thetaUSD: number;
180
+ };
175
181
  }>>;
182
+ /**
183
+ * Pay for a service using MPP (Machine Payments Protocol)
184
+ *
185
+ * This implements the MPP flow manually for EOA wallets:
186
+ * 1. Request service → get 402 with WWW-Authenticate
187
+ * 2. Parse payment requirements
188
+ * 3. Execute transfer on Tempo chain
189
+ * 4. Retry with transaction hash as credential
190
+ *
191
+ * @param url - Full URL of the MPP-enabled endpoint
192
+ * @param options - Request options (body, headers)
193
+ * @returns Response from the service
194
+ */
195
+ payWithMPP(url: string, options?: {
196
+ body?: any;
197
+ headers?: Record<string, string>;
198
+ }): Promise<any>;
176
199
  }
177
200
 
178
201
  export { type ClientConfig, MoltsPayClient, type MoltsPayClientOptions, type PayOptions, type PaymentRequired, type ProviderInfo, type ServiceInfo, type ServicesResponse, type VerifyResponse, type WalletData };
@@ -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/client/index.ts
@@ -39,12 +49,15 @@ var CHAINS = {
39
49
  USDC: {
40
50
  address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
41
51
  decimals: 6,
42
- symbol: "USDC"
52
+ symbol: "USDC",
53
+ eip712Name: "USD Coin"
54
+ // EIP-712 domain name
43
55
  },
44
56
  USDT: {
45
57
  address: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",
46
58
  decimals: 6,
47
- symbol: "USDT"
59
+ symbol: "USDT",
60
+ eip712Name: "Tether USD"
48
61
  }
49
62
  },
50
63
  usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
@@ -61,12 +74,15 @@ var CHAINS = {
61
74
  USDC: {
62
75
  address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
63
76
  decimals: 6,
64
- symbol: "USDC"
77
+ symbol: "USDC",
78
+ eip712Name: "USD Coin"
65
79
  },
66
80
  USDT: {
67
81
  address: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
68
82
  decimals: 6,
69
- symbol: "USDT"
83
+ symbol: "USDT",
84
+ eip712Name: "(PoS) Tether USD"
85
+ // Polygon uses this name
70
86
  }
71
87
  },
72
88
  usdc: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
@@ -74,27 +90,6 @@ var CHAINS = {
74
90
  explorerTx: "https://polygonscan.com/tx/",
75
91
  avgBlockTime: 2
76
92
  },
77
- ethereum: {
78
- name: "Ethereum",
79
- chainId: 1,
80
- rpc: "https://eth.llamarpc.com",
81
- tokens: {
82
- USDC: {
83
- address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
84
- decimals: 6,
85
- symbol: "USDC"
86
- },
87
- USDT: {
88
- address: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
89
- decimals: 6,
90
- symbol: "USDT"
91
- }
92
- },
93
- usdc: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
94
- explorer: "https://etherscan.io/address/",
95
- explorerTx: "https://etherscan.io/tx/",
96
- avgBlockTime: 12
97
- },
98
93
  // ============ Testnet ============
99
94
  base_sepolia: {
100
95
  name: "Base Sepolia",
@@ -104,13 +99,17 @@ var CHAINS = {
104
99
  USDC: {
105
100
  address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
106
101
  decimals: 6,
107
- symbol: "USDC"
102
+ symbol: "USDC",
103
+ eip712Name: "USDC"
104
+ // Testnet USDC uses 'USDC' not 'USD Coin'
108
105
  },
109
106
  USDT: {
110
107
  address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
111
108
  // Same as USDC on testnet (no official USDT)
112
109
  decimals: 6,
113
- symbol: "USDT"
110
+ symbol: "USDT",
111
+ eip712Name: "USDC"
112
+ // Uses same contract as USDC
114
113
  }
115
114
  },
116
115
  usdc: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
@@ -118,27 +117,34 @@ var CHAINS = {
118
117
  explorerTx: "https://sepolia.basescan.org/tx/",
119
118
  avgBlockTime: 2
120
119
  },
121
- sepolia: {
122
- name: "Sepolia",
123
- chainId: 11155111,
124
- rpc: "https://rpc.sepolia.org",
120
+ // ============ Tempo Testnet (Moderato) ============
121
+ tempo_moderato: {
122
+ name: "Tempo Moderato",
123
+ chainId: 42431,
124
+ rpc: "https://rpc.moderato.tempo.xyz",
125
125
  tokens: {
126
+ // TIP-20 stablecoins on Tempo testnet (from mppx SDK)
127
+ // Note: Tempo uses USD as native gas token, not ETH
126
128
  USDC: {
127
- address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
129
+ address: "0x20c0000000000000000000000000000000000000",
130
+ // pathUSD - primary testnet stablecoin
128
131
  decimals: 6,
129
- symbol: "USDC"
132
+ symbol: "USDC",
133
+ eip712Name: "pathUSD"
130
134
  },
131
135
  USDT: {
132
- address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
133
- // Same as USDC on testnet
136
+ address: "0x20c0000000000000000000000000000000000001",
137
+ // alphaUSD
134
138
  decimals: 6,
135
- symbol: "USDT"
139
+ symbol: "USDT",
140
+ eip712Name: "alphaUSD"
136
141
  }
137
142
  },
138
- usdc: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
139
- explorer: "https://sepolia.etherscan.io/address/",
140
- explorerTx: "https://sepolia.etherscan.io/tx/",
141
- avgBlockTime: 12
143
+ usdc: "0x20c0000000000000000000000000000000000000",
144
+ explorer: "https://explore.testnet.tempo.xyz/address/",
145
+ explorerTx: "https://explore.testnet.tempo.xyz/tx/",
146
+ avgBlockTime: 0.5
147
+ // ~500ms finality
142
148
  }
143
149
  };
144
150
  function getChain(name) {
@@ -301,7 +307,7 @@ Server accepts: ${serverChains.join(", ")}`
301
307
  } else {
302
308
  throw new Error(
303
309
  `Server accepts: ${serverChains.join(", ")}
304
- Please specify: --chain base or --chain polygon`
310
+ Please specify: --chain base, --chain polygon, or --chain base_sepolia`
305
311
  );
306
312
  }
307
313
  }
@@ -343,13 +349,19 @@ Please specify: --chain base or --chain polygon`
343
349
  if (!payTo) {
344
350
  throw new Error("Missing payTo address in payment requirements");
345
351
  }
346
- const authorization = await this.signEIP3009(payTo, amount, chain, token);
352
+ const domainOverride = req.extra && typeof req.extra === "object" && req.extra.name ? { name: req.extra.name, version: req.extra.version || "2" } : void 0;
353
+ const authorization = await this.signEIP3009(payTo, amount, chain, token, domainOverride);
347
354
  const tokenConfig = chain.tokens[token];
348
- const tokenName = token === "USDC" ? "USD Coin" : "Tether USD";
355
+ const extra = req.extra && typeof req.extra === "object" ? req.extra : {
356
+ name: tokenConfig.eip712Name || "USD Coin",
357
+ version: "2"
358
+ };
349
359
  const payload = {
350
360
  x402Version: X402_VERSION,
361
+ scheme: "exact",
362
+ network,
351
363
  payload: authorization,
352
- // v2 requires 'accepted' field with the requirements being fulfilled
364
+ // { authorization: {...}, signature: "0x..." }
353
365
  accepted: {
354
366
  scheme: "exact",
355
367
  network,
@@ -357,7 +369,7 @@ Please specify: --chain base or --chain polygon`
357
369
  amount: amountRaw,
358
370
  payTo,
359
371
  maxTimeoutSeconds: req.maxTimeoutSeconds || 300,
360
- extra: req.extra || { name: tokenName, version: "2" }
372
+ extra
361
373
  }
362
374
  };
363
375
  const paymentHeader = Buffer.from(JSON.stringify(payload)).toString("base64");
@@ -387,7 +399,7 @@ Please specify: --chain base or --chain polygon`
387
399
  * This only signs - no on-chain transaction, no gas needed.
388
400
  * Supports both USDC and USDT.
389
401
  */
390
- async signEIP3009(to, amount, chain, token = "USDC") {
402
+ async signEIP3009(to, amount, chain, token = "USDC", domainOverride) {
391
403
  const validAfter = 0;
392
404
  const validBefore = Math.floor(Date.now() / 1e3) + 3600;
393
405
  const nonce = import_ethers.ethers.hexlify(import_ethers.ethers.randomBytes(32));
@@ -401,10 +413,11 @@ Please specify: --chain base or --chain polygon`
401
413
  validBefore: validBefore.toString(),
402
414
  nonce
403
415
  };
404
- const tokenName = token === "USDC" ? "USD Coin" : "Tether USD";
416
+ const tokenName = domainOverride?.name || tokenConfig.eip712Name || (token === "USDC" ? "USD Coin" : "Tether USD");
417
+ const tokenVersion = domainOverride?.version || "2";
405
418
  const domain = {
406
419
  name: tokenName,
407
- version: "2",
420
+ version: tokenVersion,
408
421
  chainId: chain.chainId,
409
422
  verifyingContract: tokenConfig.address
410
423
  };
@@ -567,30 +580,59 @@ Please specify: --chain base or --chain polygon`
567
580
  };
568
581
  }
569
582
  /**
570
- * Get wallet balances on all supported chains (Base + Polygon)
583
+ * Get wallet balances on all supported chains (Base + Polygon + Tempo)
571
584
  */
572
585
  async getAllBalances() {
573
586
  if (!this.wallet) {
574
587
  throw new Error("Client not initialized");
575
588
  }
576
- const supportedChains = ["base", "polygon"];
589
+ const supportedChains = ["base", "polygon", "base_sepolia", "tempo_moderato"];
577
590
  const tokenAbi = ["function balanceOf(address) view returns (uint256)"];
578
591
  const results = {};
592
+ const tempoTokens = {
593
+ pathUSD: "0x20c0000000000000000000000000000000000000",
594
+ alphaUSD: "0x20c0000000000000000000000000000000000001",
595
+ betaUSD: "0x20c0000000000000000000000000000000000002",
596
+ thetaUSD: "0x20c0000000000000000000000000000000000003"
597
+ };
579
598
  await Promise.all(
580
599
  supportedChains.map(async (chainName) => {
581
600
  try {
582
601
  const chain = getChain(chainName);
583
602
  const provider = new import_ethers.ethers.JsonRpcProvider(chain.rpc);
584
- const [nativeBalance, usdcBalance, usdtBalance] = await Promise.all([
585
- provider.getBalance(this.wallet.address),
586
- new import_ethers.ethers.Contract(chain.tokens.USDC.address, tokenAbi, provider).balanceOf(this.wallet.address),
587
- new import_ethers.ethers.Contract(chain.tokens.USDT.address, tokenAbi, provider).balanceOf(this.wallet.address)
588
- ]);
589
- results[chainName] = {
590
- usdc: parseFloat(import_ethers.ethers.formatUnits(usdcBalance, chain.tokens.USDC.decimals)),
591
- usdt: parseFloat(import_ethers.ethers.formatUnits(usdtBalance, chain.tokens.USDT.decimals)),
592
- native: parseFloat(import_ethers.ethers.formatEther(nativeBalance))
593
- };
603
+ if (chainName === "tempo_moderato") {
604
+ const [nativeBalance, pathUSD, alphaUSD, betaUSD, thetaUSD] = await Promise.all([
605
+ provider.getBalance(this.wallet.address),
606
+ new import_ethers.ethers.Contract(tempoTokens.pathUSD, tokenAbi, provider).balanceOf(this.wallet.address),
607
+ new import_ethers.ethers.Contract(tempoTokens.alphaUSD, tokenAbi, provider).balanceOf(this.wallet.address),
608
+ new import_ethers.ethers.Contract(tempoTokens.betaUSD, tokenAbi, provider).balanceOf(this.wallet.address),
609
+ new import_ethers.ethers.Contract(tempoTokens.thetaUSD, tokenAbi, provider).balanceOf(this.wallet.address)
610
+ ]);
611
+ results[chainName] = {
612
+ usdc: parseFloat(import_ethers.ethers.formatUnits(pathUSD, 6)),
613
+ // pathUSD as default USDC
614
+ usdt: parseFloat(import_ethers.ethers.formatUnits(alphaUSD, 6)),
615
+ // alphaUSD as default USDT
616
+ native: parseFloat(import_ethers.ethers.formatEther(nativeBalance)),
617
+ tempo: {
618
+ pathUSD: parseFloat(import_ethers.ethers.formatUnits(pathUSD, 6)),
619
+ alphaUSD: parseFloat(import_ethers.ethers.formatUnits(alphaUSD, 6)),
620
+ betaUSD: parseFloat(import_ethers.ethers.formatUnits(betaUSD, 6)),
621
+ thetaUSD: parseFloat(import_ethers.ethers.formatUnits(thetaUSD, 6))
622
+ }
623
+ };
624
+ } else {
625
+ const [nativeBalance, usdcBalance, usdtBalance] = await Promise.all([
626
+ provider.getBalance(this.wallet.address),
627
+ new import_ethers.ethers.Contract(chain.tokens.USDC.address, tokenAbi, provider).balanceOf(this.wallet.address),
628
+ new import_ethers.ethers.Contract(chain.tokens.USDT.address, tokenAbi, provider).balanceOf(this.wallet.address)
629
+ ]);
630
+ results[chainName] = {
631
+ usdc: parseFloat(import_ethers.ethers.formatUnits(usdcBalance, chain.tokens.USDC.decimals)),
632
+ usdt: parseFloat(import_ethers.ethers.formatUnits(usdtBalance, chain.tokens.USDT.decimals)),
633
+ native: parseFloat(import_ethers.ethers.formatEther(nativeBalance))
634
+ };
635
+ }
594
636
  } catch (err) {
595
637
  results[chainName] = { usdc: 0, usdt: 0, native: 0 };
596
638
  }
@@ -598,6 +640,121 @@ Please specify: --chain base or --chain polygon`
598
640
  );
599
641
  return results;
600
642
  }
643
+ /**
644
+ * Pay for a service using MPP (Machine Payments Protocol)
645
+ *
646
+ * This implements the MPP flow manually for EOA wallets:
647
+ * 1. Request service → get 402 with WWW-Authenticate
648
+ * 2. Parse payment requirements
649
+ * 3. Execute transfer on Tempo chain
650
+ * 4. Retry with transaction hash as credential
651
+ *
652
+ * @param url - Full URL of the MPP-enabled endpoint
653
+ * @param options - Request options (body, headers)
654
+ * @returns Response from the service
655
+ */
656
+ async payWithMPP(url, options = {}) {
657
+ if (!this.wallet || !this.walletData) {
658
+ throw new Error("Client not initialized. Run: npx moltspay init");
659
+ }
660
+ const { privateKeyToAccount } = await import("viem/accounts");
661
+ const { createWalletClient, createPublicClient, http } = await import("viem");
662
+ const { tempoModerato } = await import("viem/chains");
663
+ const { Actions } = await import("viem/tempo");
664
+ const privateKey = this.walletData.privateKey;
665
+ const account = privateKeyToAccount(privateKey);
666
+ console.log(`[MoltsPay] Making MPP request to: ${url}`);
667
+ console.log(`[MoltsPay] Using account: ${account.address}`);
668
+ const initResponse = await fetch(url, {
669
+ method: "POST",
670
+ headers: {
671
+ "Content-Type": "application/json",
672
+ ...options.headers
673
+ },
674
+ body: options.body ? JSON.stringify(options.body) : void 0
675
+ });
676
+ if (initResponse.status !== 402) {
677
+ if (initResponse.ok) {
678
+ return initResponse.json();
679
+ }
680
+ const errorText = await initResponse.text();
681
+ throw new Error(`Request failed (${initResponse.status}): ${errorText}`);
682
+ }
683
+ const wwwAuth = initResponse.headers.get("www-authenticate");
684
+ if (!wwwAuth || !wwwAuth.toLowerCase().includes("payment")) {
685
+ throw new Error("No WWW-Authenticate Payment challenge in 402 response");
686
+ }
687
+ console.log(`[MoltsPay] Got 402, parsing payment challenge...`);
688
+ const parseAuthParam = (header, key) => {
689
+ const match = header.match(new RegExp(`${key}="([^"]+)"`, "i"));
690
+ return match ? match[1] : null;
691
+ };
692
+ const challengeId = parseAuthParam(wwwAuth, "id");
693
+ const method = parseAuthParam(wwwAuth, "method");
694
+ const realm = parseAuthParam(wwwAuth, "realm");
695
+ const requestB64 = parseAuthParam(wwwAuth, "request");
696
+ if (method !== "tempo") {
697
+ throw new Error(`Unsupported payment method: ${method}`);
698
+ }
699
+ if (!requestB64) {
700
+ throw new Error("Missing request in WWW-Authenticate");
701
+ }
702
+ const requestJson = Buffer.from(requestB64, "base64").toString("utf-8");
703
+ const paymentRequest = JSON.parse(requestJson);
704
+ console.log(`[MoltsPay] Payment request:`, paymentRequest);
705
+ const { amount, currency, recipient, methodDetails } = paymentRequest;
706
+ const chainId = methodDetails?.chainId || 42431;
707
+ console.log(`[MoltsPay] Executing transfer on Tempo (chainId: ${chainId})...`);
708
+ console.log(`[MoltsPay] Amount: ${amount}, To: ${recipient}`);
709
+ const tempoChain = { ...tempoModerato, feeToken: currency };
710
+ const publicClient = createPublicClient({
711
+ chain: tempoChain,
712
+ transport: http("https://rpc.moderato.tempo.xyz")
713
+ });
714
+ const walletClient = createWalletClient({
715
+ account,
716
+ chain: tempoChain,
717
+ transport: http("https://rpc.moderato.tempo.xyz")
718
+ });
719
+ const txHash = await Actions.token.transfer(walletClient, {
720
+ to: recipient,
721
+ amount: BigInt(amount),
722
+ token: currency
723
+ });
724
+ console.log(`[MoltsPay] Transaction sent: ${txHash}`);
725
+ console.log(`[MoltsPay] Waiting for confirmation...`);
726
+ await publicClient.waitForTransactionReceipt({ hash: txHash });
727
+ console.log(`[MoltsPay] Transaction confirmed!`);
728
+ const challenge = {
729
+ id: challengeId,
730
+ realm,
731
+ method: "tempo",
732
+ intent: "charge",
733
+ request: paymentRequest
734
+ };
735
+ const credential = {
736
+ challenge,
737
+ payload: { hash: txHash, type: "hash" },
738
+ source: `did:pkh:eip155:${chainId}:${account.address}`
739
+ };
740
+ const credentialB64 = Buffer.from(JSON.stringify(credential)).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
741
+ console.log(`[MoltsPay] Retrying with payment credential...`);
742
+ const paidResponse = await fetch(url, {
743
+ method: "POST",
744
+ headers: {
745
+ "Content-Type": "application/json",
746
+ "Authorization": `Payment ${credentialB64}`,
747
+ ...options.headers
748
+ },
749
+ body: options.body ? JSON.stringify(options.body) : void 0
750
+ });
751
+ if (!paidResponse.ok) {
752
+ const errorText = await paidResponse.text();
753
+ throw new Error(`Payment verification failed (${paidResponse.status}): ${errorText}`);
754
+ }
755
+ console.log(`[MoltsPay] Payment verified! Service completed.`);
756
+ return paidResponse.json();
757
+ }
601
758
  };
602
759
  // Annotate the CommonJS export names for ESM import in node:
603
760
  0 && (module.exports = {