@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,211 @@
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/lightning/facilitator/index.ts
23
+ var facilitator_exports = {};
24
+ __export(facilitator_exports, {
25
+ LightningScheme: () => LightningScheme,
26
+ registerLightningScheme: () => registerLightningScheme
27
+ });
28
+ module.exports = __toCommonJS(facilitator_exports);
29
+
30
+ // src/constants.ts
31
+ var BTC_MAINNET = "bip122:000000000019d6689c085ae165831e93";
32
+ var BTC_TESTNET = "bip122:000000000933ea01ad0ee984209779ba";
33
+ var LIGHTNING_MAINNET = "lightning:mainnet";
34
+ var LIGHTNING_TESTNET = "lightning:testnet";
35
+ var BTC_NETWORKS = [BTC_MAINNET, BTC_TESTNET];
36
+ var LIGHTNING_NETWORKS = [LIGHTNING_MAINNET, LIGHTNING_TESTNET];
37
+ var ALL_NETWORKS = [...BTC_NETWORKS, ...LIGHTNING_NETWORKS];
38
+ var SCHEME_EXACT = "exact";
39
+
40
+ // src/utils.ts
41
+ function isValidHex(hex, expectedLength) {
42
+ if (!/^[0-9a-fA-F]+$/.test(hex)) {
43
+ return false;
44
+ }
45
+ if (expectedLength !== void 0 && hex.length !== expectedLength * 2) {
46
+ return false;
47
+ }
48
+ return true;
49
+ }
50
+
51
+ // src/lightning/facilitator/scheme.ts
52
+ async function sha256Hex(preimageHex) {
53
+ const bytes = new Uint8Array(preimageHex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
54
+ const hashBuffer = await globalThis.crypto.subtle.digest("SHA-256", bytes);
55
+ const hashArray = new Uint8Array(hashBuffer);
56
+ return Array.from(hashArray).map((b) => b.toString(16).padStart(2, "0")).join("");
57
+ }
58
+ var LightningScheme = class {
59
+ constructor(signer) {
60
+ this.signer = signer;
61
+ __publicField(this, "scheme", SCHEME_EXACT);
62
+ __publicField(this, "caipFamily", "lightning:*");
63
+ }
64
+ /**
65
+ * Get mechanism-specific extra data for the supported kinds endpoint.
66
+ * Lightning has no extra data.
67
+ */
68
+ getExtra(_network) {
69
+ return void 0;
70
+ }
71
+ /**
72
+ * Get signer addresses (node public keys) for this facilitator.
73
+ */
74
+ getSigners(_network) {
75
+ return [...this.signer.getAddresses()];
76
+ }
77
+ /**
78
+ * Verifies a Lightning payment payload.
79
+ *
80
+ * Validates:
81
+ * 1. Payload structure (paymentHash, preimage, bolt11Invoice)
82
+ * 2. Preimage verification: SHA-256(preimage) === paymentHash
83
+ * 3. Payment lookup on the Lightning node
84
+ */
85
+ async verify(payload, requirements) {
86
+ const lnPayload = payload.payload;
87
+ if (!lnPayload?.paymentHash || !lnPayload?.preimage || !lnPayload?.bolt11Invoice) {
88
+ return {
89
+ isValid: false,
90
+ invalidReason: "invalid_payload_structure",
91
+ payer: void 0
92
+ };
93
+ }
94
+ if (payload.accepted.scheme !== SCHEME_EXACT || requirements.scheme !== SCHEME_EXACT) {
95
+ return {
96
+ isValid: false,
97
+ invalidReason: "unsupported_scheme",
98
+ payer: void 0
99
+ };
100
+ }
101
+ const validNetworks = LIGHTNING_NETWORKS;
102
+ if (!validNetworks.includes(requirements.network)) {
103
+ return {
104
+ isValid: false,
105
+ invalidReason: "unsupported_network",
106
+ payer: void 0
107
+ };
108
+ }
109
+ if (!isValidHex(lnPayload.preimage, 32)) {
110
+ return {
111
+ isValid: false,
112
+ invalidReason: "invalid_preimage_format",
113
+ payer: void 0
114
+ };
115
+ }
116
+ if (!isValidHex(lnPayload.paymentHash, 32)) {
117
+ return {
118
+ isValid: false,
119
+ invalidReason: "invalid_payment_hash_format",
120
+ payer: void 0
121
+ };
122
+ }
123
+ try {
124
+ const computedHash = await sha256Hex(lnPayload.preimage);
125
+ if (computedHash !== lnPayload.paymentHash.toLowerCase()) {
126
+ return {
127
+ isValid: false,
128
+ invalidReason: "preimage_hash_mismatch",
129
+ payer: void 0
130
+ };
131
+ }
132
+ } catch {
133
+ return {
134
+ isValid: false,
135
+ invalidReason: "preimage_verification_failed",
136
+ payer: void 0
137
+ };
138
+ }
139
+ try {
140
+ const payment = await this.signer.lookupPayment(lnPayload.paymentHash);
141
+ if (!payment.settled) {
142
+ return {
143
+ isValid: false,
144
+ invalidReason: "payment_not_settled",
145
+ payer: void 0
146
+ };
147
+ }
148
+ if (payment.amountSats && BigInt(payment.amountSats) < BigInt(requirements.amount)) {
149
+ return {
150
+ isValid: false,
151
+ invalidReason: "insufficient_amount",
152
+ payer: void 0
153
+ };
154
+ }
155
+ } catch (error) {
156
+ console.warn("Could not verify payment with Lightning node:", error);
157
+ }
158
+ return {
159
+ isValid: true,
160
+ invalidReason: void 0,
161
+ payer: void 0
162
+ };
163
+ }
164
+ /**
165
+ * Settles a Lightning payment.
166
+ *
167
+ * Lightning payments are atomic (settle-on-pay), so this is effectively
168
+ * a confirmation that the payment was already completed. The actual
169
+ * settlement happened when the client paid the invoice.
170
+ */
171
+ async settle(payload, requirements) {
172
+ const lnPayload = payload.payload;
173
+ if (!lnPayload?.paymentHash || !lnPayload?.preimage) {
174
+ return {
175
+ success: false,
176
+ network: payload.accepted.network,
177
+ transaction: "",
178
+ errorReason: "invalid_payload_structure",
179
+ payer: void 0
180
+ };
181
+ }
182
+ const verifyResult = await this.verify(payload, requirements);
183
+ if (!verifyResult.isValid) {
184
+ return {
185
+ success: false,
186
+ network: payload.accepted.network,
187
+ transaction: "",
188
+ errorReason: verifyResult.invalidReason ?? "verification_failed",
189
+ payer: void 0
190
+ };
191
+ }
192
+ return {
193
+ success: true,
194
+ transaction: lnPayload.paymentHash,
195
+ network: payload.accepted.network,
196
+ payer: void 0
197
+ };
198
+ }
199
+ };
200
+
201
+ // src/lightning/facilitator/register.ts
202
+ function registerLightningScheme(facilitator, config) {
203
+ facilitator.register(config.networks, new LightningScheme(config.signer));
204
+ return facilitator;
205
+ }
206
+ // Annotate the CommonJS export names for ESM import in node:
207
+ 0 && (module.exports = {
208
+ LightningScheme,
209
+ registerLightningScheme
210
+ });
211
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/lightning/facilitator/index.ts","../../../../src/constants.ts","../../../../src/utils.ts","../../../../src/lightning/facilitator/scheme.ts","../../../../src/lightning/facilitator/register.ts"],"sourcesContent":["export { LightningScheme } from './scheme.js'\nexport type { FacilitatorLightningSigner } from './scheme.js'\nexport { registerLightningScheme } from './register.js'\nexport type { LightningFacilitatorConfig } from './register.js'\n","/**\n * Bitcoin & Lightning Network Constants\n *\n * CAIP-2 network identifiers, dust limits, and fee constants.\n */\n\n/**\n * CAIP-2 Network Identifiers for Bitcoin\n * Uses BIP-122 chain genesis block hashes\n */\nexport const BTC_MAINNET = 'bip122:000000000019d6689c085ae165831e93'\nexport const BTC_TESTNET = 'bip122:000000000933ea01ad0ee984209779ba'\n\n/**\n * CAIP-2 Network Identifiers for Lightning Network\n */\nexport const LIGHTNING_MAINNET = 'lightning:mainnet'\nexport const LIGHTNING_TESTNET = 'lightning:testnet'\n\n/**\n * All supported BTC on-chain networks\n */\nexport const BTC_NETWORKS = [BTC_MAINNET, BTC_TESTNET] as const\n\n/**\n * All supported Lightning networks\n */\nexport const LIGHTNING_NETWORKS = [LIGHTNING_MAINNET, LIGHTNING_TESTNET] as const\n\n/**\n * All supported networks (on-chain + Lightning)\n */\nexport const ALL_NETWORKS = [...BTC_NETWORKS, ...LIGHTNING_NETWORKS] as const\n\nexport type BtcNetwork = (typeof BTC_NETWORKS)[number]\nexport type LightningNetwork = (typeof LIGHTNING_NETWORKS)[number]\n\n/**\n * Dust limit in satoshis - minimum viable output value\n * Outputs below this threshold are rejected by Bitcoin nodes\n */\nexport const DUST_LIMIT = 546\n\n/**\n * Minimum relay fee in satoshis\n * Transactions with fees below this are not relayed by default\n */\nexport const MIN_RELAY_FEE = 1000\n\n/**\n * Satoshis per BTC\n */\nexport const SATS_PER_BTC = 100_000_000\n\n/**\n * Scheme identifiers\n */\nexport const SCHEME_EXACT = 'exact'\n\n/**\n * Default timeout for payment validity (in seconds)\n */\nexport const DEFAULT_VALIDITY_DURATION = 3600 // 1 hour\n\n/**\n * Bitcoin address prefixes for basic validation\n */\nexport const MAINNET_ADDRESS_PREFIXES = ['bc1', '1', '3']\nexport const TESTNET_ADDRESS_PREFIXES = ['tb1', 'm', 'n', '2']\n","/**\n * Bitcoin & Lightning Utility Functions\n *\n * Helper functions for address validation, unit conversion,\n * and invoice validation.\n */\n\nimport { SATS_PER_BTC, MAINNET_ADDRESS_PREFIXES, TESTNET_ADDRESS_PREFIXES } from './constants.js'\n\n/**\n * Convert satoshis to BTC\n *\n * @param sats - Amount in satoshis\n * @returns Amount in BTC as string (to avoid floating point issues)\n */\nexport function satoshisToBtc(sats: bigint | number | string): string {\n const satsBigInt = BigInt(sats)\n const whole = satsBigInt / BigInt(SATS_PER_BTC)\n const frac = satsBigInt % BigInt(SATS_PER_BTC)\n\n if (frac === 0n) {\n return whole.toString()\n }\n\n const fracStr = frac.toString().padStart(8, '0')\n return `${whole}.${fracStr}`.replace(/\\.?0+$/, '')\n}\n\n/**\n * Convert BTC to satoshis\n *\n * @param btc - Amount in BTC (string or number)\n * @returns Amount in satoshis as bigint\n */\nexport function btcToSatoshis(btc: string | number): bigint {\n const btcStr = typeof btc === 'number' ? btc.toString() : btc\n const [wholePart, fracPart = ''] = btcStr.split('.')\n const paddedFrac = fracPart.padEnd(8, '0').slice(0, 8)\n const combined = wholePart + paddedFrac\n const result = BigInt(combined.replace(/^0+/, '') || '0')\n return result\n}\n\n/**\n * Validate a Bitcoin address (basic format validation)\n *\n * Checks address prefix against known formats:\n * - Mainnet: bc1 (bech32), 1 (P2PKH), 3 (P2SH)\n * - Testnet: tb1 (bech32), m/n (P2PKH), 2 (P2SH)\n *\n * @param address - Bitcoin address to validate\n * @returns true if the address has a valid format\n */\nexport function validateBitcoinAddress(address: string): boolean {\n if (!address || address.length < 14 || address.length > 90) {\n return false\n }\n\n const allPrefixes = [...MAINNET_ADDRESS_PREFIXES, ...TESTNET_ADDRESS_PREFIXES]\n return allPrefixes.some((prefix) => address.startsWith(prefix))\n}\n\n/**\n * Check if a Bitcoin address is for mainnet\n *\n * @param address - Bitcoin address\n * @returns true if mainnet address\n */\nexport function isMainnetAddress(address: string): boolean {\n return MAINNET_ADDRESS_PREFIXES.some((prefix) => address.startsWith(prefix))\n}\n\n/**\n * Check if a Bitcoin address is for testnet\n *\n * @param address - Bitcoin address\n * @returns true if testnet address\n */\nexport function isTestnetAddress(address: string): boolean {\n return TESTNET_ADDRESS_PREFIXES.some((prefix) => address.startsWith(prefix))\n}\n\n/**\n * Validate a BOLT11 Lightning invoice (basic format validation)\n *\n * BOLT11 invoices follow the format:\n * - lnbc... for mainnet\n * - lntb... for testnet\n * - lnbcrt... for regtest\n *\n * @param invoice - BOLT11 invoice string\n * @returns true if the invoice has a valid format\n */\nexport function validateBolt11Invoice(invoice: string): boolean {\n if (!invoice || invoice.length < 20) {\n return false\n }\n\n const lower = invoice.toLowerCase()\n return lower.startsWith('lnbc') || lower.startsWith('lntb') || lower.startsWith('lnbcrt')\n}\n\n/**\n * Validate a hex-encoded string\n *\n * @param hex - String to validate\n * @param expectedLength - Expected byte length (hex length / 2)\n * @returns true if valid hex of expected length\n */\nexport function isValidHex(hex: string, expectedLength?: number): boolean {\n if (!/^[0-9a-fA-F]+$/.test(hex)) {\n return false\n }\n if (expectedLength !== undefined && hex.length !== expectedLength * 2) {\n return false\n }\n return true\n}\n","/**\n * Lightning Network Facilitator Scheme Implementation\n *\n * Verifies Lightning Network payments using preimage verification.\n * Lightning payments are atomic (settle-on-pay), so settlement is a no-op.\n */\n\nimport type {\n PaymentPayload,\n PaymentRequirements,\n SchemeNetworkFacilitator,\n SettleResponse,\n VerifyResponse,\n} from '@t402/core/types'\nimport type { LightningPayload } from '../../types.js'\nimport { SCHEME_EXACT, LIGHTNING_NETWORKS } from '../../constants.js'\nimport { isValidHex } from '../../utils.js'\n\n/**\n * Facilitator Lightning signer interface\n */\nexport interface FacilitatorLightningSigner {\n /**\n * Get all node public keys this facilitator manages\n */\n getAddresses(): readonly string[]\n\n /**\n * Look up a payment by its payment hash\n *\n * @param paymentHash - Hex-encoded payment hash\n * @returns Payment status\n */\n lookupPayment(paymentHash: string): Promise<{\n settled: boolean\n amountSats?: string\n preimage?: string\n }>\n}\n\n/**\n * Compute SHA-256 hash of a hex-encoded preimage\n *\n * @param preimageHex - Hex-encoded preimage\n * @returns Hex-encoded SHA-256 hash\n */\nasync function sha256Hex(preimageHex: string): Promise<string> {\n const bytes = new Uint8Array(preimageHex.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16)))\n const hashBuffer = await globalThis.crypto.subtle.digest('SHA-256', bytes)\n const hashArray = new Uint8Array(hashBuffer)\n return Array.from(hashArray)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\n/**\n * Lightning Network facilitator implementation for the Exact payment scheme.\n *\n * Verification is done by checking that SHA-256(preimage) === paymentHash.\n * Lightning payments are atomic, so settle is a confirmation-only operation.\n */\nexport class LightningScheme implements SchemeNetworkFacilitator {\n readonly scheme = SCHEME_EXACT\n readonly caipFamily = 'lightning:*'\n\n constructor(private readonly signer: FacilitatorLightningSigner) {}\n\n /**\n * Get mechanism-specific extra data for the supported kinds endpoint.\n * Lightning has no extra data.\n */\n getExtra(_network: string): Record<string, unknown> | undefined {\n return undefined\n }\n\n /**\n * Get signer addresses (node public keys) for this facilitator.\n */\n getSigners(_network: string): string[] {\n return [...this.signer.getAddresses()]\n }\n\n /**\n * Verifies a Lightning payment payload.\n *\n * Validates:\n * 1. Payload structure (paymentHash, preimage, bolt11Invoice)\n * 2. Preimage verification: SHA-256(preimage) === paymentHash\n * 3. Payment lookup on the Lightning node\n */\n async verify(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<VerifyResponse> {\n const lnPayload = payload.payload as LightningPayload | undefined\n\n // Validate payload structure\n if (!lnPayload?.paymentHash || !lnPayload?.preimage || !lnPayload?.bolt11Invoice) {\n return {\n isValid: false,\n invalidReason: 'invalid_payload_structure',\n payer: undefined,\n }\n }\n\n // Verify scheme matches\n if (payload.accepted.scheme !== SCHEME_EXACT || requirements.scheme !== SCHEME_EXACT) {\n return {\n isValid: false,\n invalidReason: 'unsupported_scheme',\n payer: undefined,\n }\n }\n\n // Verify network is a valid Lightning network\n const validNetworks: readonly string[] = LIGHTNING_NETWORKS\n if (!validNetworks.includes(requirements.network)) {\n return {\n isValid: false,\n invalidReason: 'unsupported_network',\n payer: undefined,\n }\n }\n\n // Validate preimage format (32 bytes hex)\n if (!isValidHex(lnPayload.preimage, 32)) {\n return {\n isValid: false,\n invalidReason: 'invalid_preimage_format',\n payer: undefined,\n }\n }\n\n // Validate payment hash format (32 bytes hex)\n if (!isValidHex(lnPayload.paymentHash, 32)) {\n return {\n isValid: false,\n invalidReason: 'invalid_payment_hash_format',\n payer: undefined,\n }\n }\n\n // Core verification: SHA-256(preimage) must equal paymentHash\n try {\n const computedHash = await sha256Hex(lnPayload.preimage)\n\n if (computedHash !== lnPayload.paymentHash.toLowerCase()) {\n return {\n isValid: false,\n invalidReason: 'preimage_hash_mismatch',\n payer: undefined,\n }\n }\n } catch {\n return {\n isValid: false,\n invalidReason: 'preimage_verification_failed',\n payer: undefined,\n }\n }\n\n // Optionally verify with the Lightning node\n try {\n const payment = await this.signer.lookupPayment(lnPayload.paymentHash)\n\n if (!payment.settled) {\n return {\n isValid: false,\n invalidReason: 'payment_not_settled',\n payer: undefined,\n }\n }\n\n // Verify amount matches if available\n if (payment.amountSats && BigInt(payment.amountSats) < BigInt(requirements.amount)) {\n return {\n isValid: false,\n invalidReason: 'insufficient_amount',\n payer: undefined,\n }\n }\n } catch (error) {\n // If we can't verify with the node, the preimage verification is sufficient\n console.warn('Could not verify payment with Lightning node:', error)\n }\n\n return {\n isValid: true,\n invalidReason: undefined,\n payer: undefined,\n }\n }\n\n /**\n * Settles a Lightning payment.\n *\n * Lightning payments are atomic (settle-on-pay), so this is effectively\n * a confirmation that the payment was already completed. The actual\n * settlement happened when the client paid the invoice.\n */\n async settle(\n payload: PaymentPayload,\n requirements: PaymentRequirements,\n ): Promise<SettleResponse> {\n const lnPayload = payload.payload as LightningPayload | undefined\n\n if (!lnPayload?.paymentHash || !lnPayload?.preimage) {\n return {\n success: false,\n network: payload.accepted.network,\n transaction: '',\n errorReason: 'invalid_payload_structure',\n payer: undefined,\n }\n }\n\n // Verify the payment\n const verifyResult = await this.verify(payload, requirements)\n if (!verifyResult.isValid) {\n return {\n success: false,\n network: payload.accepted.network,\n transaction: '',\n errorReason: verifyResult.invalidReason ?? 'verification_failed',\n payer: undefined,\n }\n }\n\n // Lightning is settle-on-pay: the payment hash serves as the transaction ID\n return {\n success: true,\n transaction: lnPayload.paymentHash,\n network: payload.accepted.network,\n payer: undefined,\n }\n }\n}\n","import { t402Facilitator } from '@t402/core/facilitator'\nimport { Network } from '@t402/core/types'\nimport { FacilitatorLightningSigner, LightningScheme } from './scheme.js'\n\n/**\n * Configuration options for registering Lightning schemes to an t402Facilitator\n */\nexport interface LightningFacilitatorConfig {\n /**\n * The Lightning signer for facilitator operations\n */\n signer: FacilitatorLightningSigner\n\n /**\n * Networks to register (single network or array of networks)\n * Examples: \"lightning:mainnet\", [\"lightning:mainnet\", \"lightning:testnet\"]\n */\n networks: Network | Network[]\n}\n\n/**\n * Registers Lightning payment schemes to an t402Facilitator instance.\n *\n * @param facilitator - The t402Facilitator instance to register schemes to\n * @param config - Configuration for Lightning facilitator registration\n * @returns The facilitator instance for chaining\n */\nexport function registerLightningScheme(\n facilitator: t402Facilitator,\n config: LightningFacilitatorConfig,\n): t402Facilitator {\n facilitator.register(config.networks, new LightningScheme(config.signer))\n return facilitator\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,96 @@
1
+ import { SchemeNetworkServer, MoneyParser, Price, Network, AssetAmount, PaymentRequirements } from '@t402/core/types';
2
+ import { t402ResourceServer } from '@t402/core/server';
3
+
4
+ /**
5
+ * Lightning Network Server Scheme Implementation
6
+ *
7
+ * Handles price parsing and payment requirement enhancement for
8
+ * Lightning Network payments.
9
+ */
10
+
11
+ /**
12
+ * Lightning invoice generator function
13
+ * Used to create BOLT11 invoices for payment requirements
14
+ */
15
+ type InvoiceGenerator = (amountSats: string, description: string, expiry: number) => Promise<{
16
+ bolt11Invoice: string;
17
+ paymentHash: string;
18
+ }>;
19
+ /**
20
+ * Configuration options for Lightning server scheme
21
+ */
22
+ interface LightningSchemeConfig {
23
+ /**
24
+ * Function to generate BOLT11 invoices
25
+ */
26
+ generateInvoice: InvoiceGenerator;
27
+ }
28
+ /**
29
+ * Lightning Network server implementation for the Exact payment scheme.
30
+ * Generates BOLT11 invoices and enhances payment requirements.
31
+ */
32
+ declare class LightningScheme implements SchemeNetworkServer {
33
+ readonly scheme = "exact";
34
+ private moneyParsers;
35
+ private config;
36
+ constructor(config: LightningSchemeConfig);
37
+ /**
38
+ * Register a custom money parser in the parser chain.
39
+ *
40
+ * @param parser - Custom function to convert amount to AssetAmount (or null to skip)
41
+ * @returns The server instance for chaining
42
+ */
43
+ registerMoneyParser(parser: MoneyParser): LightningScheme;
44
+ /**
45
+ * Parses a price into an asset amount in satoshis.
46
+ *
47
+ * @param price - The price to parse
48
+ * @param network - The network to use
49
+ * @returns Promise that resolves to the parsed asset amount
50
+ */
51
+ parsePrice(price: Price, network: Network): Promise<AssetAmount>;
52
+ /**
53
+ * Build payment requirements for Lightning Network.
54
+ *
55
+ * Generates a BOLT11 invoice and adds it to the extra field.
56
+ */
57
+ enhancePaymentRequirements(paymentRequirements: PaymentRequirements, supportedKind: {
58
+ t402Version: number;
59
+ scheme: string;
60
+ network: Network;
61
+ extra?: Record<string, unknown>;
62
+ }, extensionKeys: string[]): Promise<PaymentRequirements>;
63
+ /**
64
+ * Parse Money (string | number) to a decimal number.
65
+ */
66
+ private parseMoneyToDecimal;
67
+ /**
68
+ * Default money conversion: treat amount as BTC, convert to satoshis.
69
+ */
70
+ private defaultMoneyConversion;
71
+ }
72
+
73
+ /**
74
+ * Configuration options for registering Lightning schemes to an t402ResourceServer
75
+ */
76
+ interface LightningResourceServerConfig {
77
+ /**
78
+ * Optional specific networks to register
79
+ * If not provided, registers wildcard support (lightning:*)
80
+ */
81
+ networks?: Network[];
82
+ /**
83
+ * Scheme configuration (invoice generator, etc.)
84
+ */
85
+ schemeConfig: LightningSchemeConfig;
86
+ }
87
+ /**
88
+ * Registers Lightning payment schemes to an t402ResourceServer instance.
89
+ *
90
+ * @param server - The t402ResourceServer instance to register schemes to
91
+ * @param config - Configuration for Lightning resource server registration
92
+ * @returns The server instance for chaining
93
+ */
94
+ declare function registerLightningScheme(server: t402ResourceServer, config: LightningResourceServerConfig): t402ResourceServer;
95
+
96
+ export { type InvoiceGenerator, type LightningResourceServerConfig, LightningScheme, type LightningSchemeConfig, registerLightningScheme };
@@ -0,0 +1,157 @@
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/lightning/server/index.ts
23
+ var server_exports = {};
24
+ __export(server_exports, {
25
+ LightningScheme: () => LightningScheme,
26
+ registerLightningScheme: () => registerLightningScheme
27
+ });
28
+ module.exports = __toCommonJS(server_exports);
29
+
30
+ // src/constants.ts
31
+ var BTC_MAINNET = "bip122:000000000019d6689c085ae165831e93";
32
+ var BTC_TESTNET = "bip122:000000000933ea01ad0ee984209779ba";
33
+ var LIGHTNING_MAINNET = "lightning:mainnet";
34
+ var LIGHTNING_TESTNET = "lightning:testnet";
35
+ var BTC_NETWORKS = [BTC_MAINNET, BTC_TESTNET];
36
+ var LIGHTNING_NETWORKS = [LIGHTNING_MAINNET, LIGHTNING_TESTNET];
37
+ var ALL_NETWORKS = [...BTC_NETWORKS, ...LIGHTNING_NETWORKS];
38
+ var SATS_PER_BTC = 1e8;
39
+ var SCHEME_EXACT = "exact";
40
+
41
+ // src/lightning/server/scheme.ts
42
+ var LightningScheme = class {
43
+ constructor(config) {
44
+ __publicField(this, "scheme", SCHEME_EXACT);
45
+ __publicField(this, "moneyParsers", []);
46
+ __publicField(this, "config");
47
+ this.config = config;
48
+ }
49
+ /**
50
+ * Register a custom money parser in the parser chain.
51
+ *
52
+ * @param parser - Custom function to convert amount to AssetAmount (or null to skip)
53
+ * @returns The server instance for chaining
54
+ */
55
+ registerMoneyParser(parser) {
56
+ this.moneyParsers.push(parser);
57
+ return this;
58
+ }
59
+ /**
60
+ * Parses a price into an asset amount in satoshis.
61
+ *
62
+ * @param price - The price to parse
63
+ * @param network - The network to use
64
+ * @returns Promise that resolves to the parsed asset amount
65
+ */
66
+ async parsePrice(price, network) {
67
+ if (typeof price === "object" && price !== null && "amount" in price) {
68
+ if (!price.asset) {
69
+ throw new Error(`Asset must be specified for AssetAmount on network ${network}`);
70
+ }
71
+ return {
72
+ amount: price.amount,
73
+ asset: price.asset,
74
+ extra: price.extra || {}
75
+ };
76
+ }
77
+ const amount = this.parseMoneyToDecimal(price);
78
+ for (const parser of this.moneyParsers) {
79
+ const result = await parser(amount, network);
80
+ if (result !== null) {
81
+ return result;
82
+ }
83
+ }
84
+ return this.defaultMoneyConversion(amount);
85
+ }
86
+ /**
87
+ * Build payment requirements for Lightning Network.
88
+ *
89
+ * Generates a BOLT11 invoice and adds it to the extra field.
90
+ */
91
+ async enhancePaymentRequirements(paymentRequirements, supportedKind, extensionKeys) {
92
+ void extensionKeys;
93
+ const extra = { ...paymentRequirements.extra };
94
+ const invoice = await this.config.generateInvoice(
95
+ paymentRequirements.amount,
96
+ `t402 payment on ${supportedKind.network}`,
97
+ paymentRequirements.maxTimeoutSeconds
98
+ );
99
+ extra.bolt11Invoice = invoice.bolt11Invoice;
100
+ extra.paymentHash = invoice.paymentHash;
101
+ return {
102
+ ...paymentRequirements,
103
+ asset: paymentRequirements.asset || "BTC",
104
+ extra
105
+ };
106
+ }
107
+ /**
108
+ * Parse Money (string | number) to a decimal number.
109
+ */
110
+ parseMoneyToDecimal(money) {
111
+ if (typeof money === "number") {
112
+ if (!Number.isFinite(money)) {
113
+ throw new Error(`Invalid money value: ${money}`);
114
+ }
115
+ return money;
116
+ }
117
+ const cleanMoney = money.replace(/^\$/, "").trim();
118
+ const amount = parseFloat(cleanMoney);
119
+ if (isNaN(amount)) {
120
+ throw new Error(`Invalid money format: ${money}`);
121
+ }
122
+ return amount;
123
+ }
124
+ /**
125
+ * Default money conversion: treat amount as BTC, convert to satoshis.
126
+ */
127
+ defaultMoneyConversion(amount) {
128
+ const sats = Math.floor(amount * SATS_PER_BTC);
129
+ return {
130
+ amount: sats.toString(),
131
+ asset: "BTC",
132
+ extra: {
133
+ symbol: "BTC",
134
+ decimals: 8
135
+ }
136
+ };
137
+ }
138
+ };
139
+
140
+ // src/lightning/server/register.ts
141
+ function registerLightningScheme(server, config) {
142
+ const scheme = new LightningScheme(config.schemeConfig);
143
+ if (config.networks && config.networks.length > 0) {
144
+ config.networks.forEach((network) => {
145
+ server.register(network, scheme);
146
+ });
147
+ } else {
148
+ server.register("lightning:*", scheme);
149
+ }
150
+ return server;
151
+ }
152
+ // Annotate the CommonJS export names for ESM import in node:
153
+ 0 && (module.exports = {
154
+ LightningScheme,
155
+ registerLightningScheme
156
+ });
157
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/lightning/server/index.ts","../../../../src/constants.ts","../../../../src/lightning/server/scheme.ts","../../../../src/lightning/server/register.ts"],"sourcesContent":["export { LightningScheme } from './scheme.js'\nexport type { LightningSchemeConfig, InvoiceGenerator } from './scheme.js'\nexport { registerLightningScheme } from './register.js'\nexport type { LightningResourceServerConfig } from './register.js'\n","/**\n * Bitcoin & Lightning Network Constants\n *\n * CAIP-2 network identifiers, dust limits, and fee constants.\n */\n\n/**\n * CAIP-2 Network Identifiers for Bitcoin\n * Uses BIP-122 chain genesis block hashes\n */\nexport const BTC_MAINNET = 'bip122:000000000019d6689c085ae165831e93'\nexport const BTC_TESTNET = 'bip122:000000000933ea01ad0ee984209779ba'\n\n/**\n * CAIP-2 Network Identifiers for Lightning Network\n */\nexport const LIGHTNING_MAINNET = 'lightning:mainnet'\nexport const LIGHTNING_TESTNET = 'lightning:testnet'\n\n/**\n * All supported BTC on-chain networks\n */\nexport const BTC_NETWORKS = [BTC_MAINNET, BTC_TESTNET] as const\n\n/**\n * All supported Lightning networks\n */\nexport const LIGHTNING_NETWORKS = [LIGHTNING_MAINNET, LIGHTNING_TESTNET] as const\n\n/**\n * All supported networks (on-chain + Lightning)\n */\nexport const ALL_NETWORKS = [...BTC_NETWORKS, ...LIGHTNING_NETWORKS] as const\n\nexport type BtcNetwork = (typeof BTC_NETWORKS)[number]\nexport type LightningNetwork = (typeof LIGHTNING_NETWORKS)[number]\n\n/**\n * Dust limit in satoshis - minimum viable output value\n * Outputs below this threshold are rejected by Bitcoin nodes\n */\nexport const DUST_LIMIT = 546\n\n/**\n * Minimum relay fee in satoshis\n * Transactions with fees below this are not relayed by default\n */\nexport const MIN_RELAY_FEE = 1000\n\n/**\n * Satoshis per BTC\n */\nexport const SATS_PER_BTC = 100_000_000\n\n/**\n * Scheme identifiers\n */\nexport const SCHEME_EXACT = 'exact'\n\n/**\n * Default timeout for payment validity (in seconds)\n */\nexport const DEFAULT_VALIDITY_DURATION = 3600 // 1 hour\n\n/**\n * Bitcoin address prefixes for basic validation\n */\nexport const MAINNET_ADDRESS_PREFIXES = ['bc1', '1', '3']\nexport const TESTNET_ADDRESS_PREFIXES = ['tb1', 'm', 'n', '2']\n","/**\n * Lightning Network Server Scheme Implementation\n *\n * Handles price parsing and payment requirement enhancement for\n * Lightning Network payments.\n */\n\nimport type {\n AssetAmount,\n Network,\n PaymentRequirements,\n Price,\n SchemeNetworkServer,\n MoneyParser,\n} from '@t402/core/types'\nimport { SCHEME_EXACT, SATS_PER_BTC } from '../../constants.js'\n\n/**\n * Lightning invoice generator function\n * Used to create BOLT11 invoices for payment requirements\n */\nexport type InvoiceGenerator = (\n amountSats: string,\n description: string,\n expiry: number,\n) => Promise<{\n bolt11Invoice: string\n paymentHash: string\n}>\n\n/**\n * Configuration options for Lightning server scheme\n */\nexport interface LightningSchemeConfig {\n /**\n * Function to generate BOLT11 invoices\n */\n generateInvoice: InvoiceGenerator\n}\n\n/**\n * Lightning Network server implementation for the Exact payment scheme.\n * Generates BOLT11 invoices and enhances payment requirements.\n */\nexport class LightningScheme implements SchemeNetworkServer {\n readonly scheme = SCHEME_EXACT\n private moneyParsers: MoneyParser[] = []\n private config: LightningSchemeConfig\n\n constructor(config: LightningSchemeConfig) {\n this.config = config\n }\n\n /**\n * Register a custom money parser in the parser chain.\n *\n * @param parser - Custom function to convert amount to AssetAmount (or null to skip)\n * @returns The server instance for chaining\n */\n registerMoneyParser(parser: MoneyParser): LightningScheme {\n this.moneyParsers.push(parser)\n return this\n }\n\n /**\n * Parses a price into an asset amount in satoshis.\n *\n * @param price - The price to parse\n * @param network - The network to use\n * @returns Promise that resolves to the parsed asset amount\n */\n async parsePrice(price: Price, network: Network): Promise<AssetAmount> {\n // If already an AssetAmount, return it directly\n if (typeof price === 'object' && price !== null && 'amount' in price) {\n if (!price.asset) {\n throw new Error(`Asset must be specified for AssetAmount on network ${network}`)\n }\n return {\n amount: price.amount,\n asset: price.asset,\n extra: price.extra || {},\n }\n }\n\n // Parse Money to decimal number\n const amount = this.parseMoneyToDecimal(price)\n\n // Try each custom money parser in order\n for (const parser of this.moneyParsers) {\n const result = await parser(amount, network)\n if (result !== null) {\n return result\n }\n }\n\n // Default: convert to satoshis\n return this.defaultMoneyConversion(amount)\n }\n\n /**\n * Build payment requirements for Lightning Network.\n *\n * Generates a BOLT11 invoice and adds it to the extra field.\n */\n async enhancePaymentRequirements(\n paymentRequirements: PaymentRequirements,\n supportedKind: {\n t402Version: number\n scheme: string\n network: Network\n extra?: Record<string, unknown>\n },\n extensionKeys: string[],\n ): Promise<PaymentRequirements> {\n void extensionKeys\n\n const extra = { ...paymentRequirements.extra }\n\n // Generate a BOLT11 invoice for the payment\n const invoice = await this.config.generateInvoice(\n paymentRequirements.amount,\n `t402 payment on ${supportedKind.network}`,\n paymentRequirements.maxTimeoutSeconds,\n )\n\n extra.bolt11Invoice = invoice.bolt11Invoice\n extra.paymentHash = invoice.paymentHash\n\n return {\n ...paymentRequirements,\n asset: paymentRequirements.asset || 'BTC',\n extra,\n }\n }\n\n /**\n * Parse Money (string | number) to a decimal number.\n */\n private parseMoneyToDecimal(money: string | number): number {\n if (typeof money === 'number') {\n if (!Number.isFinite(money)) {\n throw new Error(`Invalid money value: ${money}`)\n }\n return money\n }\n\n const cleanMoney = money.replace(/^\\$/, '').trim()\n const amount = parseFloat(cleanMoney)\n\n if (isNaN(amount)) {\n throw new Error(`Invalid money format: ${money}`)\n }\n\n return amount\n }\n\n /**\n * Default money conversion: treat amount as BTC, convert to satoshis.\n */\n private defaultMoneyConversion(amount: number): AssetAmount {\n const sats = Math.floor(amount * SATS_PER_BTC)\n\n return {\n amount: sats.toString(),\n asset: 'BTC',\n extra: {\n symbol: 'BTC',\n decimals: 8,\n },\n }\n }\n}\n","import { t402ResourceServer } from '@t402/core/server'\nimport { Network } from '@t402/core/types'\nimport { LightningScheme, LightningSchemeConfig } from './scheme.js'\n\n/**\n * Configuration options for registering Lightning schemes to an t402ResourceServer\n */\nexport interface LightningResourceServerConfig {\n /**\n * Optional specific networks to register\n * If not provided, registers wildcard support (lightning:*)\n */\n networks?: Network[]\n\n /**\n * Scheme configuration (invoice generator, etc.)\n */\n schemeConfig: LightningSchemeConfig\n}\n\n/**\n * Registers Lightning payment schemes to an t402ResourceServer instance.\n *\n * @param server - The t402ResourceServer instance to register schemes to\n * @param config - Configuration for Lightning resource server registration\n * @returns The server instance for chaining\n */\nexport function registerLightningScheme(\n server: t402ResourceServer,\n config: LightningResourceServerConfig,\n): t402ResourceServer {\n const scheme = new LightningScheme(config.schemeConfig)\n\n if (config.networks && config.networks.length > 0) {\n config.networks.forEach((network) => {\n server.register(network, scheme)\n })\n } else {\n server.register('lightning:*', scheme)\n }\n\n return server\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Bitcoin & Lightning Signer Interfaces
3
+ *
4
+ * Defines the signer interfaces for t402 client operations.
5
+ * These interfaces abstract the signing implementation,
6
+ * allowing integration with various Bitcoin wallets and Lightning nodes.
7
+ */
8
+ /**
9
+ * ClientBtcSigner - Used by t402 clients to sign Bitcoin transactions
10
+ *
11
+ * Implementations may include:
12
+ * - bitcoinjs-lib with private key
13
+ * - Hardware wallet (Ledger, Trezor)
14
+ * - Browser extension wallet
15
+ */
16
+ interface ClientBtcSigner {
17
+ /**
18
+ * Sign a PSBT (Partially Signed Bitcoin Transaction)
19
+ *
20
+ * @param psbt - Base64-encoded unsigned PSBT
21
+ * @returns Base64-encoded signed PSBT
22
+ */
23
+ signPsbt(psbt: string): Promise<string>;
24
+ /**
25
+ * Get the signer's Bitcoin address
26
+ *
27
+ * @returns Bitcoin address string
28
+ */
29
+ getAddress(): string;
30
+ /**
31
+ * Get the signer's public key (hex-encoded)
32
+ *
33
+ * @returns Public key as hex string
34
+ */
35
+ getPublicKey(): string;
36
+ }
37
+ /**
38
+ * ClientLightningSigner - Used by t402 clients to pay Lightning invoices
39
+ *
40
+ * Implementations may include:
41
+ * - LND node client
42
+ * - CLN (Core Lightning) client
43
+ * - WebLN browser extension
44
+ */
45
+ interface ClientLightningSigner {
46
+ /**
47
+ * Pay a BOLT11 Lightning invoice
48
+ *
49
+ * @param bolt11 - BOLT11 invoice string
50
+ * @returns Payment result with preimage and payment hash
51
+ */
52
+ payInvoice(bolt11: string): Promise<{
53
+ preimage: string;
54
+ paymentHash: string;
55
+ }>;
56
+ /**
57
+ * Get the Lightning node's public key
58
+ *
59
+ * @returns Node public key as hex string
60
+ */
61
+ getNodePubKey(): string;
62
+ }
63
+
64
+ export type { ClientBtcSigner as C, ClientLightningSigner as a };