@t402/btc 2.7.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 (62) hide show
  1. package/README.md +120 -0
  2. package/dist/cjs/exact/client/index.d.ts +89 -0
  3. package/dist/cjs/exact/client/index.js +145 -0
  4. package/dist/cjs/exact/client/index.js.map +1 -0
  5. package/dist/cjs/exact/facilitator/index.d.ts +114 -0
  6. package/dist/cjs/exact/facilitator/index.js +218 -0
  7. package/dist/cjs/exact/facilitator/index.js.map +1 -0
  8. package/dist/cjs/exact/server/index.d.ts +101 -0
  9. package/dist/cjs/exact/server/index.js +161 -0
  10. package/dist/cjs/exact/server/index.js.map +1 -0
  11. package/dist/cjs/index.d.ts +179 -0
  12. package/dist/cjs/index.js +849 -0
  13. package/dist/cjs/index.js.map +1 -0
  14. package/dist/cjs/lightning/client/index.d.ts +82 -0
  15. package/dist/cjs/lightning/client/index.js +114 -0
  16. package/dist/cjs/lightning/client/index.js.map +1 -0
  17. package/dist/cjs/lightning/facilitator/index.d.ts +93 -0
  18. package/dist/cjs/lightning/facilitator/index.js +211 -0
  19. package/dist/cjs/lightning/facilitator/index.js.map +1 -0
  20. package/dist/cjs/lightning/server/index.d.ts +96 -0
  21. package/dist/cjs/lightning/server/index.js +157 -0
  22. package/dist/cjs/lightning/server/index.js.map +1 -0
  23. package/dist/cjs/signer-B_Z4WGLa.d.ts +64 -0
  24. package/dist/esm/chunk-2DEKJ7ER.mjs +123 -0
  25. package/dist/esm/chunk-2DEKJ7ER.mjs.map +1 -0
  26. package/dist/esm/chunk-3IOPLDQH.mjs +74 -0
  27. package/dist/esm/chunk-3IOPLDQH.mjs.map +1 -0
  28. package/dist/esm/chunk-7IU3Z36R.mjs +103 -0
  29. package/dist/esm/chunk-7IU3Z36R.mjs.map +1 -0
  30. package/dist/esm/chunk-HNFWDITA.mjs +170 -0
  31. package/dist/esm/chunk-HNFWDITA.mjs.map +1 -0
  32. package/dist/esm/chunk-MX3PAUPJ.mjs +65 -0
  33. package/dist/esm/chunk-MX3PAUPJ.mjs.map +1 -0
  34. package/dist/esm/chunk-YJYTK2QQ.mjs +127 -0
  35. package/dist/esm/chunk-YJYTK2QQ.mjs.map +1 -0
  36. package/dist/esm/chunk-YWZC2RR7.mjs +38 -0
  37. package/dist/esm/chunk-YWZC2RR7.mjs.map +1 -0
  38. package/dist/esm/chunk-ZOL5R3HZ.mjs +177 -0
  39. package/dist/esm/chunk-ZOL5R3HZ.mjs.map +1 -0
  40. package/dist/esm/exact/client/index.d.mts +89 -0
  41. package/dist/esm/exact/client/index.mjs +11 -0
  42. package/dist/esm/exact/client/index.mjs.map +1 -0
  43. package/dist/esm/exact/facilitator/index.d.mts +114 -0
  44. package/dist/esm/exact/facilitator/index.mjs +11 -0
  45. package/dist/esm/exact/facilitator/index.mjs.map +1 -0
  46. package/dist/esm/exact/server/index.d.mts +101 -0
  47. package/dist/esm/exact/server/index.mjs +10 -0
  48. package/dist/esm/exact/server/index.mjs.map +1 -0
  49. package/dist/esm/index.d.mts +179 -0
  50. package/dist/esm/index.mjs +77 -0
  51. package/dist/esm/index.mjs.map +1 -0
  52. package/dist/esm/lightning/client/index.d.mts +82 -0
  53. package/dist/esm/lightning/client/index.mjs +11 -0
  54. package/dist/esm/lightning/client/index.mjs.map +1 -0
  55. package/dist/esm/lightning/facilitator/index.d.mts +93 -0
  56. package/dist/esm/lightning/facilitator/index.mjs +11 -0
  57. package/dist/esm/lightning/facilitator/index.mjs.map +1 -0
  58. package/dist/esm/lightning/server/index.d.mts +96 -0
  59. package/dist/esm/lightning/server/index.mjs +10 -0
  60. package/dist/esm/lightning/server/index.mjs.map +1 -0
  61. package/dist/esm/signer-B_Z4WGLa.d.mts +64 -0
  62. package/package.json +142 -0
@@ -0,0 +1,849 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
21
+
22
+ // src/index.ts
23
+ var src_exports = {};
24
+ __export(src_exports, {
25
+ ALL_NETWORKS: () => ALL_NETWORKS,
26
+ BTC_MAINNET: () => BTC_MAINNET,
27
+ BTC_NETWORKS: () => BTC_NETWORKS,
28
+ BTC_TESTNET: () => BTC_TESTNET,
29
+ DEFAULT_VALIDITY_DURATION: () => DEFAULT_VALIDITY_DURATION,
30
+ DUST_LIMIT: () => DUST_LIMIT,
31
+ ExactBtcScheme: () => ExactBtcScheme,
32
+ LIGHTNING_MAINNET: () => LIGHTNING_MAINNET,
33
+ LIGHTNING_NETWORKS: () => LIGHTNING_NETWORKS,
34
+ LIGHTNING_TESTNET: () => LIGHTNING_TESTNET,
35
+ LightningScheme: () => LightningScheme,
36
+ MAINNET_ADDRESS_PREFIXES: () => MAINNET_ADDRESS_PREFIXES,
37
+ MIN_RELAY_FEE: () => MIN_RELAY_FEE,
38
+ SATS_PER_BTC: () => SATS_PER_BTC,
39
+ SCHEME_EXACT: () => SCHEME_EXACT,
40
+ TESTNET_ADDRESS_PREFIXES: () => TESTNET_ADDRESS_PREFIXES,
41
+ btcToSatoshis: () => btcToSatoshis,
42
+ isMainnetAddress: () => isMainnetAddress,
43
+ isTestnetAddress: () => isTestnetAddress,
44
+ isValidHex: () => isValidHex,
45
+ registerExactBtcClientScheme: () => registerExactBtcScheme,
46
+ registerExactBtcFacilitatorScheme: () => registerExactBtcScheme3,
47
+ registerExactBtcServerScheme: () => registerExactBtcScheme2,
48
+ registerLightningClientScheme: () => registerLightningScheme,
49
+ registerLightningFacilitatorScheme: () => registerLightningScheme3,
50
+ registerLightningServerScheme: () => registerLightningScheme2,
51
+ satoshisToBtc: () => satoshisToBtc,
52
+ validateBitcoinAddress: () => validateBitcoinAddress,
53
+ validateBolt11Invoice: () => validateBolt11Invoice
54
+ });
55
+ module.exports = __toCommonJS(src_exports);
56
+
57
+ // src/constants.ts
58
+ var BTC_MAINNET = "bip122:000000000019d6689c085ae165831e93";
59
+ var BTC_TESTNET = "bip122:000000000933ea01ad0ee984209779ba";
60
+ var LIGHTNING_MAINNET = "lightning:mainnet";
61
+ var LIGHTNING_TESTNET = "lightning:testnet";
62
+ var BTC_NETWORKS = [BTC_MAINNET, BTC_TESTNET];
63
+ var LIGHTNING_NETWORKS = [LIGHTNING_MAINNET, LIGHTNING_TESTNET];
64
+ var ALL_NETWORKS = [...BTC_NETWORKS, ...LIGHTNING_NETWORKS];
65
+ var DUST_LIMIT = 546;
66
+ var MIN_RELAY_FEE = 1e3;
67
+ var SATS_PER_BTC = 1e8;
68
+ var SCHEME_EXACT = "exact";
69
+ var DEFAULT_VALIDITY_DURATION = 3600;
70
+ var MAINNET_ADDRESS_PREFIXES = ["bc1", "1", "3"];
71
+ var TESTNET_ADDRESS_PREFIXES = ["tb1", "m", "n", "2"];
72
+
73
+ // src/utils.ts
74
+ function satoshisToBtc(sats) {
75
+ const satsBigInt = BigInt(sats);
76
+ const whole = satsBigInt / BigInt(SATS_PER_BTC);
77
+ const frac = satsBigInt % BigInt(SATS_PER_BTC);
78
+ if (frac === 0n) {
79
+ return whole.toString();
80
+ }
81
+ const fracStr = frac.toString().padStart(8, "0");
82
+ return `${whole}.${fracStr}`.replace(/\.?0+$/, "");
83
+ }
84
+ function btcToSatoshis(btc) {
85
+ const btcStr = typeof btc === "number" ? btc.toString() : btc;
86
+ const [wholePart, fracPart = ""] = btcStr.split(".");
87
+ const paddedFrac = fracPart.padEnd(8, "0").slice(0, 8);
88
+ const combined = wholePart + paddedFrac;
89
+ const result = BigInt(combined.replace(/^0+/, "") || "0");
90
+ return result;
91
+ }
92
+ function validateBitcoinAddress(address) {
93
+ if (!address || address.length < 14 || address.length > 90) {
94
+ return false;
95
+ }
96
+ const allPrefixes = [...MAINNET_ADDRESS_PREFIXES, ...TESTNET_ADDRESS_PREFIXES];
97
+ return allPrefixes.some((prefix) => address.startsWith(prefix));
98
+ }
99
+ function isMainnetAddress(address) {
100
+ return MAINNET_ADDRESS_PREFIXES.some((prefix) => address.startsWith(prefix));
101
+ }
102
+ function isTestnetAddress(address) {
103
+ return TESTNET_ADDRESS_PREFIXES.some((prefix) => address.startsWith(prefix));
104
+ }
105
+ function validateBolt11Invoice(invoice) {
106
+ if (!invoice || invoice.length < 20) {
107
+ return false;
108
+ }
109
+ const lower = invoice.toLowerCase();
110
+ return lower.startsWith("lnbc") || lower.startsWith("lntb") || lower.startsWith("lnbcrt");
111
+ }
112
+ function isValidHex(hex, expectedLength) {
113
+ if (!/^[0-9a-fA-F]+$/.test(hex)) {
114
+ return false;
115
+ }
116
+ if (expectedLength !== void 0 && hex.length !== expectedLength * 2) {
117
+ return false;
118
+ }
119
+ return true;
120
+ }
121
+
122
+ // src/exact/client/scheme.ts
123
+ var ExactBtcScheme = class {
124
+ /**
125
+ * Creates a new ExactBtcScheme instance.
126
+ *
127
+ * @param signer - The Bitcoin signer for client operations
128
+ */
129
+ constructor(signer) {
130
+ this.signer = signer;
131
+ __publicField(this, "scheme", SCHEME_EXACT);
132
+ }
133
+ /**
134
+ * Creates a payment payload for the Exact scheme.
135
+ *
136
+ * The payload contains a signed PSBT with a single output
137
+ * paying the required amount to the payTo address.
138
+ *
139
+ * @param t402Version - The t402 protocol version
140
+ * @param paymentRequirements - The payment requirements
141
+ * @returns Promise resolving to a payment payload
142
+ */
143
+ async createPaymentPayload(t402Version, paymentRequirements) {
144
+ if (!paymentRequirements.payTo) {
145
+ throw new Error("PayTo address is required");
146
+ }
147
+ if (!paymentRequirements.amount) {
148
+ throw new Error("Amount is required");
149
+ }
150
+ if (!validateBitcoinAddress(paymentRequirements.payTo)) {
151
+ throw new Error(`Invalid Bitcoin address: ${paymentRequirements.payTo}`);
152
+ }
153
+ const amountSats = BigInt(paymentRequirements.amount);
154
+ if (amountSats < BigInt(DUST_LIMIT)) {
155
+ throw new Error(`Amount ${amountSats} satoshis is below dust limit (${DUST_LIMIT})`);
156
+ }
157
+ const unsignedPsbt = this.buildUnsignedPsbt(paymentRequirements);
158
+ const signedPsbt = await this.signer.signPsbt(unsignedPsbt);
159
+ const payload = {
160
+ signedPsbt
161
+ };
162
+ return {
163
+ t402Version,
164
+ payload
165
+ };
166
+ }
167
+ /**
168
+ * Build an unsigned PSBT for the payment.
169
+ *
170
+ * Creates a minimal PSBT representation with the required output.
171
+ * The actual UTXO selection and fee calculation should be handled
172
+ * by the signer implementation (which typically has wallet context).
173
+ *
174
+ * @param requirements - Payment requirements
175
+ * @returns Base64-encoded unsigned PSBT
176
+ */
177
+ buildUnsignedPsbt(requirements) {
178
+ const psbtData = {
179
+ outputs: [
180
+ {
181
+ address: requirements.payTo,
182
+ value: requirements.amount
183
+ }
184
+ ],
185
+ network: requirements.network,
186
+ fromAddress: this.signer.getAddress(),
187
+ fromPubKey: this.signer.getPublicKey()
188
+ };
189
+ return Buffer.from(JSON.stringify(psbtData)).toString("base64");
190
+ }
191
+ };
192
+
193
+ // src/exact/client/register.ts
194
+ function registerExactBtcScheme(client, config) {
195
+ const scheme = new ExactBtcScheme(config.signer);
196
+ if (config.networks && config.networks.length > 0) {
197
+ config.networks.forEach((network) => {
198
+ client.register(network, scheme);
199
+ });
200
+ } else {
201
+ client.register("bip122:*", scheme);
202
+ }
203
+ if (config.policies) {
204
+ config.policies.forEach((policy) => {
205
+ client.registerPolicy(policy);
206
+ });
207
+ }
208
+ return client;
209
+ }
210
+
211
+ // src/lightning/client/scheme.ts
212
+ var LightningScheme = class {
213
+ /**
214
+ * Creates a new LightningScheme instance.
215
+ *
216
+ * @param signer - The Lightning signer for client operations
217
+ */
218
+ constructor(signer) {
219
+ this.signer = signer;
220
+ __publicField(this, "scheme", SCHEME_EXACT);
221
+ }
222
+ /**
223
+ * Creates a payment payload for the Lightning scheme.
224
+ *
225
+ * 1. Extracts the BOLT11 invoice from requirements.extra.bolt11Invoice
226
+ * 2. Pays the invoice using the Lightning signer
227
+ * 3. Returns the preimage and payment hash as proof of payment
228
+ *
229
+ * @param t402Version - The t402 protocol version
230
+ * @param paymentRequirements - The payment requirements
231
+ * @returns Promise resolving to a payment payload
232
+ */
233
+ async createPaymentPayload(t402Version, paymentRequirements) {
234
+ const bolt11Invoice = paymentRequirements.extra?.bolt11Invoice;
235
+ if (!bolt11Invoice) {
236
+ throw new Error("BOLT11 invoice is required in requirements.extra.bolt11Invoice");
237
+ }
238
+ if (!validateBolt11Invoice(bolt11Invoice)) {
239
+ throw new Error(`Invalid BOLT11 invoice format: ${bolt11Invoice.slice(0, 20)}...`);
240
+ }
241
+ const { preimage, paymentHash } = await this.signer.payInvoice(bolt11Invoice);
242
+ const payload = {
243
+ paymentHash,
244
+ preimage,
245
+ bolt11Invoice
246
+ };
247
+ return {
248
+ t402Version,
249
+ payload
250
+ };
251
+ }
252
+ };
253
+
254
+ // src/lightning/client/register.ts
255
+ function registerLightningScheme(client, config) {
256
+ const scheme = new LightningScheme(config.signer);
257
+ if (config.networks && config.networks.length > 0) {
258
+ config.networks.forEach((network) => {
259
+ client.register(network, scheme);
260
+ });
261
+ } else {
262
+ client.register("lightning:*", scheme);
263
+ }
264
+ if (config.policies) {
265
+ config.policies.forEach((policy) => {
266
+ client.registerPolicy(policy);
267
+ });
268
+ }
269
+ return client;
270
+ }
271
+
272
+ // src/exact/server/scheme.ts
273
+ var ExactBtcScheme2 = class {
274
+ constructor(config) {
275
+ __publicField(this, "scheme", SCHEME_EXACT);
276
+ __publicField(this, "moneyParsers", []);
277
+ __publicField(this, "config");
278
+ this.config = config;
279
+ }
280
+ /**
281
+ * Register a custom money parser in the parser chain.
282
+ *
283
+ * @param parser - Custom function to convert amount to AssetAmount (or null to skip)
284
+ * @returns The server instance for chaining
285
+ */
286
+ registerMoneyParser(parser) {
287
+ this.moneyParsers.push(parser);
288
+ return this;
289
+ }
290
+ /**
291
+ * Parses a price into an asset amount in satoshis.
292
+ *
293
+ * Accepts:
294
+ * - Number: treated as USD, converted to satoshis at a default rate
295
+ * - String with $: treated as USD
296
+ * - AssetAmount: returned directly
297
+ *
298
+ * For Bitcoin, amounts are always in satoshis and the asset is "BTC".
299
+ *
300
+ * @param price - The price to parse
301
+ * @param network - The network to use
302
+ * @returns Promise that resolves to the parsed asset amount
303
+ */
304
+ async parsePrice(price, network) {
305
+ if (typeof price === "object" && price !== null && "amount" in price) {
306
+ if (!price.asset) {
307
+ throw new Error(`Asset must be specified for AssetAmount on network ${network}`);
308
+ }
309
+ return {
310
+ amount: price.amount,
311
+ asset: price.asset,
312
+ extra: price.extra || {}
313
+ };
314
+ }
315
+ const amount = this.parseMoneyToDecimal(price);
316
+ for (const parser of this.moneyParsers) {
317
+ const result = await parser(amount, network);
318
+ if (result !== null) {
319
+ return result;
320
+ }
321
+ }
322
+ return this.defaultMoneyConversion(amount);
323
+ }
324
+ /**
325
+ * Build payment requirements for this scheme/network combination.
326
+ *
327
+ * @param paymentRequirements - Base payment requirements with amount/asset already set
328
+ * @param supportedKind - The supported kind from facilitator
329
+ * @param extensionKeys - Extensions supported by the facilitator
330
+ * @returns Enhanced payment requirements
331
+ */
332
+ async enhancePaymentRequirements(paymentRequirements, supportedKind, extensionKeys) {
333
+ void supportedKind;
334
+ void extensionKeys;
335
+ return {
336
+ ...paymentRequirements,
337
+ payTo: paymentRequirements.payTo || this.config.payTo,
338
+ asset: paymentRequirements.asset || "BTC"
339
+ };
340
+ }
341
+ /**
342
+ * Parse Money (string | number) to a decimal number.
343
+ */
344
+ parseMoneyToDecimal(money) {
345
+ if (typeof money === "number") {
346
+ if (!Number.isFinite(money)) {
347
+ throw new Error(`Invalid money value: ${money}`);
348
+ }
349
+ return money;
350
+ }
351
+ const cleanMoney = money.replace(/^\$/, "").trim();
352
+ const amount = parseFloat(cleanMoney);
353
+ if (isNaN(amount)) {
354
+ throw new Error(`Invalid money format: ${money}`);
355
+ }
356
+ return amount;
357
+ }
358
+ /**
359
+ * Default money conversion: treat amount as satoshis.
360
+ * For direct satoshi amounts, the amount is used as-is.
361
+ */
362
+ defaultMoneyConversion(amount) {
363
+ const sats = Math.floor(amount * SATS_PER_BTC);
364
+ return {
365
+ amount: sats.toString(),
366
+ asset: "BTC",
367
+ extra: {
368
+ symbol: "BTC",
369
+ decimals: 8
370
+ }
371
+ };
372
+ }
373
+ };
374
+
375
+ // src/exact/server/register.ts
376
+ function registerExactBtcScheme2(server, config) {
377
+ const scheme = new ExactBtcScheme2(config.schemeConfig);
378
+ if (config.networks && config.networks.length > 0) {
379
+ config.networks.forEach((network) => {
380
+ server.register(network, scheme);
381
+ });
382
+ } else {
383
+ server.register("bip122:*", scheme);
384
+ }
385
+ return server;
386
+ }
387
+
388
+ // src/exact/facilitator/scheme.ts
389
+ var ExactBtcScheme3 = class {
390
+ constructor(signer) {
391
+ this.signer = signer;
392
+ __publicField(this, "scheme", SCHEME_EXACT);
393
+ __publicField(this, "caipFamily", "bip122:*");
394
+ }
395
+ /**
396
+ * Get mechanism-specific extra data for the supported kinds endpoint.
397
+ * Bitcoin on-chain has no extra data.
398
+ */
399
+ getExtra(_network) {
400
+ return void 0;
401
+ }
402
+ /**
403
+ * Get signer addresses used by this facilitator.
404
+ */
405
+ getSigners(_network) {
406
+ return [...this.signer.getAddresses()];
407
+ }
408
+ /**
409
+ * Verifies a payment payload.
410
+ *
411
+ * Validates:
412
+ * 1. Scheme and network matching
413
+ * 2. PSBT structure and signatures
414
+ * 3. Output matches (payTo, amount)
415
+ * 4. Amount above dust limit
416
+ */
417
+ async verify(payload, requirements) {
418
+ const btcPayload = payload.payload;
419
+ if (!btcPayload?.signedPsbt) {
420
+ return {
421
+ isValid: false,
422
+ invalidReason: "invalid_payload_structure",
423
+ payer: void 0
424
+ };
425
+ }
426
+ if (payload.accepted.scheme !== SCHEME_EXACT || requirements.scheme !== SCHEME_EXACT) {
427
+ return {
428
+ isValid: false,
429
+ invalidReason: "unsupported_scheme",
430
+ payer: void 0
431
+ };
432
+ }
433
+ const validNetworks = BTC_NETWORKS;
434
+ if (!validNetworks.includes(requirements.network)) {
435
+ return {
436
+ isValid: false,
437
+ invalidReason: "unsupported_network",
438
+ payer: void 0
439
+ };
440
+ }
441
+ if (payload.accepted.network !== requirements.network) {
442
+ return {
443
+ isValid: false,
444
+ invalidReason: "network_mismatch",
445
+ payer: void 0
446
+ };
447
+ }
448
+ if (!validateBitcoinAddress(requirements.payTo)) {
449
+ return {
450
+ isValid: false,
451
+ invalidReason: "invalid_pay_to_address",
452
+ payer: void 0
453
+ };
454
+ }
455
+ if (BigInt(requirements.amount) < BigInt(DUST_LIMIT)) {
456
+ return {
457
+ isValid: false,
458
+ invalidReason: "amount_below_dust_limit",
459
+ payer: void 0
460
+ };
461
+ }
462
+ try {
463
+ const result = await this.signer.verifyPsbt({
464
+ signedPsbt: btcPayload.signedPsbt,
465
+ expectedPayTo: requirements.payTo,
466
+ expectedAmount: requirements.amount
467
+ });
468
+ if (!result.valid) {
469
+ return {
470
+ isValid: false,
471
+ invalidReason: result.reason || "psbt_verification_failed",
472
+ payer: result.payer
473
+ };
474
+ }
475
+ return {
476
+ isValid: true,
477
+ invalidReason: void 0,
478
+ payer: result.payer
479
+ };
480
+ } catch (error) {
481
+ const errorMessage = error instanceof Error ? error.message : String(error);
482
+ return {
483
+ isValid: false,
484
+ invalidReason: `verification_error: ${errorMessage}`,
485
+ payer: void 0
486
+ };
487
+ }
488
+ }
489
+ /**
490
+ * Settles a payment by finalizing and broadcasting the PSBT.
491
+ */
492
+ async settle(payload, requirements) {
493
+ const btcPayload = payload.payload;
494
+ if (!btcPayload?.signedPsbt) {
495
+ return {
496
+ success: false,
497
+ network: payload.accepted.network,
498
+ transaction: "",
499
+ errorReason: "invalid_payload_structure",
500
+ payer: void 0
501
+ };
502
+ }
503
+ const verifyResult = await this.verify(payload, requirements);
504
+ if (!verifyResult.isValid) {
505
+ return {
506
+ success: false,
507
+ network: payload.accepted.network,
508
+ transaction: "",
509
+ errorReason: verifyResult.invalidReason ?? "verification_failed",
510
+ payer: verifyResult.payer
511
+ };
512
+ }
513
+ try {
514
+ const txId = await this.signer.broadcastPsbt(btcPayload.signedPsbt);
515
+ const confirmation = await this.signer.waitForConfirmation(txId, 1);
516
+ if (!confirmation.confirmed) {
517
+ return {
518
+ success: false,
519
+ errorReason: "transaction_not_confirmed",
520
+ transaction: txId,
521
+ network: payload.accepted.network,
522
+ payer: verifyResult.payer
523
+ };
524
+ }
525
+ return {
526
+ success: true,
527
+ transaction: txId,
528
+ network: payload.accepted.network,
529
+ payer: verifyResult.payer
530
+ };
531
+ } catch (error) {
532
+ console.error("Failed to settle Bitcoin transaction:", error);
533
+ return {
534
+ success: false,
535
+ errorReason: "transaction_failed",
536
+ transaction: "",
537
+ network: payload.accepted.network,
538
+ payer: verifyResult.payer
539
+ };
540
+ }
541
+ }
542
+ };
543
+
544
+ // src/exact/facilitator/register.ts
545
+ function registerExactBtcScheme3(facilitator, config) {
546
+ facilitator.register(config.networks, new ExactBtcScheme3(config.signer));
547
+ return facilitator;
548
+ }
549
+
550
+ // src/lightning/server/scheme.ts
551
+ var LightningScheme2 = class {
552
+ constructor(config) {
553
+ __publicField(this, "scheme", SCHEME_EXACT);
554
+ __publicField(this, "moneyParsers", []);
555
+ __publicField(this, "config");
556
+ this.config = config;
557
+ }
558
+ /**
559
+ * Register a custom money parser in the parser chain.
560
+ *
561
+ * @param parser - Custom function to convert amount to AssetAmount (or null to skip)
562
+ * @returns The server instance for chaining
563
+ */
564
+ registerMoneyParser(parser) {
565
+ this.moneyParsers.push(parser);
566
+ return this;
567
+ }
568
+ /**
569
+ * Parses a price into an asset amount in satoshis.
570
+ *
571
+ * @param price - The price to parse
572
+ * @param network - The network to use
573
+ * @returns Promise that resolves to the parsed asset amount
574
+ */
575
+ async parsePrice(price, network) {
576
+ if (typeof price === "object" && price !== null && "amount" in price) {
577
+ if (!price.asset) {
578
+ throw new Error(`Asset must be specified for AssetAmount on network ${network}`);
579
+ }
580
+ return {
581
+ amount: price.amount,
582
+ asset: price.asset,
583
+ extra: price.extra || {}
584
+ };
585
+ }
586
+ const amount = this.parseMoneyToDecimal(price);
587
+ for (const parser of this.moneyParsers) {
588
+ const result = await parser(amount, network);
589
+ if (result !== null) {
590
+ return result;
591
+ }
592
+ }
593
+ return this.defaultMoneyConversion(amount);
594
+ }
595
+ /**
596
+ * Build payment requirements for Lightning Network.
597
+ *
598
+ * Generates a BOLT11 invoice and adds it to the extra field.
599
+ */
600
+ async enhancePaymentRequirements(paymentRequirements, supportedKind, extensionKeys) {
601
+ void extensionKeys;
602
+ const extra = { ...paymentRequirements.extra };
603
+ const invoice = await this.config.generateInvoice(
604
+ paymentRequirements.amount,
605
+ `t402 payment on ${supportedKind.network}`,
606
+ paymentRequirements.maxTimeoutSeconds
607
+ );
608
+ extra.bolt11Invoice = invoice.bolt11Invoice;
609
+ extra.paymentHash = invoice.paymentHash;
610
+ return {
611
+ ...paymentRequirements,
612
+ asset: paymentRequirements.asset || "BTC",
613
+ extra
614
+ };
615
+ }
616
+ /**
617
+ * Parse Money (string | number) to a decimal number.
618
+ */
619
+ parseMoneyToDecimal(money) {
620
+ if (typeof money === "number") {
621
+ if (!Number.isFinite(money)) {
622
+ throw new Error(`Invalid money value: ${money}`);
623
+ }
624
+ return money;
625
+ }
626
+ const cleanMoney = money.replace(/^\$/, "").trim();
627
+ const amount = parseFloat(cleanMoney);
628
+ if (isNaN(amount)) {
629
+ throw new Error(`Invalid money format: ${money}`);
630
+ }
631
+ return amount;
632
+ }
633
+ /**
634
+ * Default money conversion: treat amount as BTC, convert to satoshis.
635
+ */
636
+ defaultMoneyConversion(amount) {
637
+ const sats = Math.floor(amount * SATS_PER_BTC);
638
+ return {
639
+ amount: sats.toString(),
640
+ asset: "BTC",
641
+ extra: {
642
+ symbol: "BTC",
643
+ decimals: 8
644
+ }
645
+ };
646
+ }
647
+ };
648
+
649
+ // src/lightning/server/register.ts
650
+ function registerLightningScheme2(server, config) {
651
+ const scheme = new LightningScheme2(config.schemeConfig);
652
+ if (config.networks && config.networks.length > 0) {
653
+ config.networks.forEach((network) => {
654
+ server.register(network, scheme);
655
+ });
656
+ } else {
657
+ server.register("lightning:*", scheme);
658
+ }
659
+ return server;
660
+ }
661
+
662
+ // src/lightning/facilitator/scheme.ts
663
+ async function sha256Hex(preimageHex) {
664
+ const bytes = new Uint8Array(preimageHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
665
+ const hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", bytes);
666
+ const hashArray = new Uint8Array(hashBuffer);
667
+ return Array.from(hashArray).map((b) => b.toString(16).padStart(2, "0")).join("");
668
+ }
669
+ var LightningScheme3 = class {
670
+ constructor(signer) {
671
+ this.signer = signer;
672
+ __publicField(this, "scheme", SCHEME_EXACT);
673
+ __publicField(this, "caipFamily", "lightning:*");
674
+ }
675
+ /**
676
+ * Get mechanism-specific extra data for the supported kinds endpoint.
677
+ * Lightning has no extra data.
678
+ */
679
+ getExtra(_network) {
680
+ return void 0;
681
+ }
682
+ /**
683
+ * Get signer addresses (node public keys) for this facilitator.
684
+ */
685
+ getSigners(_network) {
686
+ return [...this.signer.getAddresses()];
687
+ }
688
+ /**
689
+ * Verifies a Lightning payment payload.
690
+ *
691
+ * Validates:
692
+ * 1. Payload structure (paymentHash, preimage, bolt11Invoice)
693
+ * 2. Preimage verification: SHA-256(preimage) === paymentHash
694
+ * 3. Payment lookup on the Lightning node
695
+ */
696
+ async verify(payload, requirements) {
697
+ const lnPayload = payload.payload;
698
+ if (!lnPayload?.paymentHash || !lnPayload?.preimage || !lnPayload?.bolt11Invoice) {
699
+ return {
700
+ isValid: false,
701
+ invalidReason: "invalid_payload_structure",
702
+ payer: void 0
703
+ };
704
+ }
705
+ if (payload.accepted.scheme !== SCHEME_EXACT || requirements.scheme !== SCHEME_EXACT) {
706
+ return {
707
+ isValid: false,
708
+ invalidReason: "unsupported_scheme",
709
+ payer: void 0
710
+ };
711
+ }
712
+ const validNetworks = LIGHTNING_NETWORKS;
713
+ if (!validNetworks.includes(requirements.network)) {
714
+ return {
715
+ isValid: false,
716
+ invalidReason: "unsupported_network",
717
+ payer: void 0
718
+ };
719
+ }
720
+ if (!isValidHex(lnPayload.preimage, 32)) {
721
+ return {
722
+ isValid: false,
723
+ invalidReason: "invalid_preimage_format",
724
+ payer: void 0
725
+ };
726
+ }
727
+ if (!isValidHex(lnPayload.paymentHash, 32)) {
728
+ return {
729
+ isValid: false,
730
+ invalidReason: "invalid_payment_hash_format",
731
+ payer: void 0
732
+ };
733
+ }
734
+ try {
735
+ const computedHash = await sha256Hex(lnPayload.preimage);
736
+ if (computedHash !== lnPayload.paymentHash.toLowerCase()) {
737
+ return {
738
+ isValid: false,
739
+ invalidReason: "preimage_hash_mismatch",
740
+ payer: void 0
741
+ };
742
+ }
743
+ } catch {
744
+ return {
745
+ isValid: false,
746
+ invalidReason: "preimage_verification_failed",
747
+ payer: void 0
748
+ };
749
+ }
750
+ try {
751
+ const payment = await this.signer.lookupPayment(lnPayload.paymentHash);
752
+ if (!payment.settled) {
753
+ return {
754
+ isValid: false,
755
+ invalidReason: "payment_not_settled",
756
+ payer: void 0
757
+ };
758
+ }
759
+ if (payment.amountSats && BigInt(payment.amountSats) < BigInt(requirements.amount)) {
760
+ return {
761
+ isValid: false,
762
+ invalidReason: "insufficient_amount",
763
+ payer: void 0
764
+ };
765
+ }
766
+ } catch (error) {
767
+ console.warn("Could not verify payment with Lightning node:", error);
768
+ }
769
+ return {
770
+ isValid: true,
771
+ invalidReason: void 0,
772
+ payer: void 0
773
+ };
774
+ }
775
+ /**
776
+ * Settles a Lightning payment.
777
+ *
778
+ * Lightning payments are atomic (settle-on-pay), so this is effectively
779
+ * a confirmation that the payment was already completed. The actual
780
+ * settlement happened when the client paid the invoice.
781
+ */
782
+ async settle(payload, requirements) {
783
+ const lnPayload = payload.payload;
784
+ if (!lnPayload?.paymentHash || !lnPayload?.preimage) {
785
+ return {
786
+ success: false,
787
+ network: payload.accepted.network,
788
+ transaction: "",
789
+ errorReason: "invalid_payload_structure",
790
+ payer: void 0
791
+ };
792
+ }
793
+ const verifyResult = await this.verify(payload, requirements);
794
+ if (!verifyResult.isValid) {
795
+ return {
796
+ success: false,
797
+ network: payload.accepted.network,
798
+ transaction: "",
799
+ errorReason: verifyResult.invalidReason ?? "verification_failed",
800
+ payer: void 0
801
+ };
802
+ }
803
+ return {
804
+ success: true,
805
+ transaction: lnPayload.paymentHash,
806
+ network: payload.accepted.network,
807
+ payer: void 0
808
+ };
809
+ }
810
+ };
811
+
812
+ // src/lightning/facilitator/register.ts
813
+ function registerLightningScheme3(facilitator, config) {
814
+ facilitator.register(config.networks, new LightningScheme3(config.signer));
815
+ return facilitator;
816
+ }
817
+ // Annotate the CommonJS export names for ESM import in node:
818
+ 0 && (module.exports = {
819
+ ALL_NETWORKS,
820
+ BTC_MAINNET,
821
+ BTC_NETWORKS,
822
+ BTC_TESTNET,
823
+ DEFAULT_VALIDITY_DURATION,
824
+ DUST_LIMIT,
825
+ ExactBtcScheme,
826
+ LIGHTNING_MAINNET,
827
+ LIGHTNING_NETWORKS,
828
+ LIGHTNING_TESTNET,
829
+ LightningScheme,
830
+ MAINNET_ADDRESS_PREFIXES,
831
+ MIN_RELAY_FEE,
832
+ SATS_PER_BTC,
833
+ SCHEME_EXACT,
834
+ TESTNET_ADDRESS_PREFIXES,
835
+ btcToSatoshis,
836
+ isMainnetAddress,
837
+ isTestnetAddress,
838
+ isValidHex,
839
+ registerExactBtcClientScheme,
840
+ registerExactBtcFacilitatorScheme,
841
+ registerExactBtcServerScheme,
842
+ registerLightningClientScheme,
843
+ registerLightningFacilitatorScheme,
844
+ registerLightningServerScheme,
845
+ satoshisToBtc,
846
+ validateBitcoinAddress,
847
+ validateBolt11Invoice
848
+ });
849
+ //# sourceMappingURL=index.js.map