thunder-bridge 0.8.2 → 0.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -106,7 +106,7 @@ them and this table does not repeat them.
106
106
 
107
107
  | Export | What it does |
108
108
  |---|---|
109
- | `lnurlPayEndpoint(config)` | a whole LNURL-pay endpoint as one Fetch handler, so a static QR points at your domain |
109
+ | `lnurlPayEndpoint(config)` | a whole LNURL-pay endpoint as one Fetch handler, so a static QR points at your domain. From `thunder-bridge/server` |
110
110
  | `seal(secret, plaintext)`, `unseal` | the blob the gateway stores and cannot read |
111
111
  | `toLnurl(url)` | bech32-encode an endpoint url |
112
112
  | `bankTransfer(params)` | register a Czech QR platba as a watched payment. Refuses a gateway that serves strangers |
@@ -127,7 +127,7 @@ whatever runtime you keep state in.
127
127
  |---|---|
128
128
  | `bankRail(config)` | a `Rail` selling for a bank transfer, reading back through any `Statement` |
129
129
  | `lightningRail(config)` | a `Rail` where the gateway mints the invoice, so it learns the address and the amount |
130
- | `blindLightningRail(config)` | a `Rail` that resolves the address itself and tells the gateway only a hash |
130
+ | `blindLightningRail(config)` | a `Rail` that resolves the address itself and tells the gateway only a hash. From `thunder-bridge/server` |
131
131
 
132
132
  `Rail` is `(order: Order) => Promise<Leg>`. Everything that differs between rails
133
133
  is bound once when the rail is built, so the only thing passed per sale is which
package/dist/index.cjs CHANGED
@@ -34,7 +34,6 @@ __export(index_exports, {
34
34
  bankTransfer: () => bankTransfer,
35
35
  bankVerifyEndpoint: () => bankVerifyEndpoint,
36
36
  bitstamp: () => bitstamp,
37
- blindLightningRail: () => blindLightningRail,
38
37
  coinbase: () => coinbase,
39
38
  coinmate: () => coinmate,
40
39
  decodeInvoice: () => decodeInvoice,
@@ -45,7 +44,6 @@ __export(index_exports, {
45
44
  isProvablyPaid: () => isProvablyPaid,
46
45
  kraken: () => kraken,
47
46
  lightningRail: () => lightningRail,
48
- lnurlPayEndpoint: () => lnurlPayEndpoint,
49
47
  lnurlToDataUrl: () => lnurlToDataUrl,
50
48
  lnurlToSvg: () => lnurlToSvg,
51
49
  medianOf: () => medianOf,
@@ -141,8 +139,8 @@ function hexToBytes(hex) {
141
139
  }
142
140
  return bytes;
143
141
  }
144
- function isHex(text3) {
145
- return /^[0-9a-f]+$/i.test(text3) && text3.length % 2 === 0;
142
+ function isHex(text2) {
143
+ return /^[0-9a-f]+$/i.test(text2) && text2.length % 2 === 0;
146
144
  }
147
145
 
148
146
  // ../core/sha256.ts
@@ -236,8 +234,8 @@ function sha256(bytes) {
236
234
  }
237
235
  return asBytes(state);
238
236
  }
239
- function sha256Hex(text3) {
240
- return bytesToHex(sha256(new TextEncoder().encode(text3)));
237
+ function sha256Hex(text2) {
238
+ return bytesToHex(sha256(new TextEncoder().encode(text2)));
241
239
  }
242
240
  function withPadding(bytes) {
243
241
  const padded = new Uint8Array(
@@ -1184,10 +1182,10 @@ function toBase64Url(bytes) {
1184
1182
  for (const byte of bytes) binary += String.fromCharCode(byte);
1185
1183
  return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1186
1184
  }
1187
- function fromBase64Url(text3) {
1188
- if (text3.length === 0 || !/^[A-Za-z0-9_-]+$/.test(text3)) return null;
1185
+ function fromBase64Url(text2) {
1186
+ if (text2.length === 0 || !/^[A-Za-z0-9_-]+$/.test(text2)) return null;
1189
1187
  try {
1190
- const binary = atob(text3.replace(/-/g, "+").replace(/_/g, "/"));
1188
+ const binary = atob(text2.replace(/-/g, "+").replace(/_/g, "/"));
1191
1189
  const bytes = new Uint8Array(binary.length);
1192
1190
  for (let at = 0; at < bytes.length; at++) bytes[at] = binary.charCodeAt(at);
1193
1191
  return bytes;
@@ -1219,368 +1217,6 @@ function asBuffer(bytes) {
1219
1217
  return bytes instanceof Uint8Array && bytes.buffer instanceof ArrayBuffer ? bytes : new Uint8Array(bytes);
1220
1218
  }
1221
1219
 
1222
- // ../core/outbound.ts
1223
- var import_promises = require("dns/promises");
1224
- var import_promises2 = require("timers/promises");
1225
- var HTTP_TIMEOUT_MS2 = 15e3;
1226
- var LOOKUP_TIMEOUT_MS = 5e3;
1227
- var HOPS_FOLLOWED = 2;
1228
- var REDIRECTS = [301, 302, 303, 307, 308];
1229
- var KEEPS_THE_METHOD = [307, 308];
1230
- var CREDENTIALS = ["authorization", "cookie", "proxy-authorization"];
1231
- var BODY_LIMIT_BYTES = 262144;
1232
- async function ask(url, sent = {}) {
1233
- const capped = AbortSignal.timeout(HTTP_TIMEOUT_MS2);
1234
- const signal = sent.deadline ? AbortSignal.any([sent.deadline, capped]) : capped;
1235
- let target = url;
1236
- let carried = sent;
1237
- for (let hop = 0; hop <= HOPS_FOLLOWED; hop += 1) {
1238
- await refuseUnlessPublic(target);
1239
- const response = await fetch(target, {
1240
- method: carried.method ?? "GET",
1241
- headers: carried.headers ?? {},
1242
- body: carried.body,
1243
- redirect: "manual",
1244
- signal
1245
- });
1246
- if (!REDIRECTS.includes(response.status)) return await answerOf(response);
1247
- const location = response.headers.get("location");
1248
- if (location === null) {
1249
- throw new Error(`${target} answered ${response.status} without saying where to`);
1250
- }
1251
- await response.body?.cancel();
1252
- const next = new URL(location, target).toString();
1253
- carried = KEEPS_THE_METHOD.includes(response.status) ? carried : withoutBody(carried);
1254
- carried = sameOrigin(target, next) ? carried : withoutCredentials(carried);
1255
- target = next;
1256
- }
1257
- throw new Error(`${url} redirected more than ${HOPS_FOLLOWED} times`);
1258
- }
1259
- async function resolvesNothingPrivate(url) {
1260
- const host = new URL(url).hostname.replace(/^\[|]$/g, "");
1261
- const found = await Promise.race([
1262
- (0, import_promises.lookup)(host, { all: true, verbatim: true }).catch(() => []),
1263
- (0, import_promises2.setTimeout)(LOOKUP_TIMEOUT_MS, null, { ref: false })
1264
- ]);
1265
- return found !== null && found.every((one) => publicAddress(one.address));
1266
- }
1267
- async function refuseUnlessPublic(url) {
1268
- if (!publicHttps(url)) throw new Error(`${url} is not a public https URL`);
1269
- if (!await resolvesNothingPrivate(url)) throw new Error(`${url} resolves to an address we do not reach`);
1270
- }
1271
- async function answerOf(response) {
1272
- const { status, ok } = response;
1273
- const reader = response.body?.getReader();
1274
- if (!reader) return { status, ok, body: "", truncated: false };
1275
- const read = [];
1276
- let bytes = 0;
1277
- while (bytes <= BODY_LIMIT_BYTES) {
1278
- const { done, value } = await reader.read();
1279
- if (done) return { status, ok, body: text2(read), truncated: false };
1280
- read.push(value);
1281
- bytes += value.length;
1282
- }
1283
- await reader.cancel();
1284
- return { status, ok, body: text2(read), truncated: true };
1285
- }
1286
- function withoutBody(sent) {
1287
- const headers = { ...sent.headers };
1288
- delete headers["content-type"];
1289
- return { ...sent, method: "GET", headers, body: void 0 };
1290
- }
1291
- function withoutCredentials(sent) {
1292
- const headers = { ...sent.headers };
1293
- for (const named of CREDENTIALS) delete headers[named];
1294
- return { ...sent, headers };
1295
- }
1296
- function text2(chunks) {
1297
- const decoder = new TextDecoder();
1298
- let decoded = "";
1299
- for (const chunk of chunks) decoded += decoder.decode(chunk, { stream: true });
1300
- return decoded + decoder.decode();
1301
- }
1302
-
1303
- // ../core/refusal.ts
1304
- var WalletRefused = class extends Error {
1305
- reason;
1306
- constructor(reason, message) {
1307
- super(message);
1308
- this.reason = reason;
1309
- }
1310
- };
1311
- var NoWalletAvailable = class extends Error {
1312
- wallets;
1313
- constructor(wallets) {
1314
- super(wallets.map((wallet) => `${wallet.address} ${wallet.reason}`).join(", "));
1315
- this.wallets = wallets;
1316
- }
1317
- };
1318
-
1319
- // ../core/lnurl.ts
1320
- var VERIFY_WITHOUT_PREIMAGE = ["zeuspay.com", "zeusnuts.com", "ecash.love"];
1321
- var BECH32_CHARSET2 = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
1322
- var BECH32_GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
1323
- var CHECKSUM_SLOTS = [0, 1, 2, 3, 4, 5];
1324
- var LNURL_HRP = "lnurl";
1325
- var RESOLVE_TIMEOUT_MS = 3e4;
1326
- async function resolve(addresses, amountMsat) {
1327
- const served = await firstThatServes(
1328
- addresses,
1329
- (address, deadline) => resolveAddress(address, amountMsat, deadline)
1330
- );
1331
- return served.won;
1332
- }
1333
- async function firstThatServes(addresses, attempt) {
1334
- const deadline = AbortSignal.timeout(RESOLVE_TIMEOUT_MS);
1335
- const refusals3 = [];
1336
- for (const address of addresses) {
1337
- if (deadline.aborted) break;
1338
- try {
1339
- return { won: await attempt(address, deadline), refusals: refusals3 };
1340
- } catch (refusal) {
1341
- if (!(refusal instanceof WalletRefused)) throw refusal;
1342
- console.warn(`wallet ${address} refused, ${refusal.reason}: ${refusal.message}`);
1343
- refusals3.push({ address, reason: refusal.reason });
1344
- }
1345
- }
1346
- throw new NoWalletAvailable(refusals3);
1347
- }
1348
- async function probe(address, amountMsat, deadline) {
1349
- const [user, domain] = splitAddress(address);
1350
- if (cannotReleaseAPreimage(domain)) {
1351
- throw new WalletRefused("cannot-prove-delivery", `${address} never releases a preimage`);
1352
- }
1353
- const pay = await answered(
1354
- `https://${domain}/.well-known/lnurlp/${user}`,
1355
- deadline
1356
- );
1357
- if (pay.tag !== "payRequest" || !pay.callback) {
1358
- throw new WalletRefused("unreachable", `${address} answered with no payRequest`);
1359
- }
1360
- if (amountMsat < pay.minSendable || amountMsat > pay.maxSendable) {
1361
- throw new WalletRefused(
1362
- "amount-not-accepted",
1363
- `${address} takes [${pay.minSendable}, ${pay.maxSendable}] msat, not ${amountMsat}`
1364
- );
1365
- }
1366
- return { address, pay };
1367
- }
1368
- async function resolveAddress(address, amountMsat, deadline) {
1369
- const { pay } = await probe(address, amountMsat, deadline);
1370
- const invoice = await answered(withAmount(pay.callback, amountMsat), deadline);
1371
- if (!invoice.pr) throw new WalletRefused("unreachable", `${address} returned no invoice`);
1372
- if (!invoice.verify || !publicHttps(invoice.verify)) {
1373
- throw new WalletRefused(
1374
- "cannot-prove-delivery",
1375
- `${address} publishes no usable LUD-21 verify URL`
1376
- );
1377
- }
1378
- const issued = decodeIssued(address, invoice.pr);
1379
- if (issued.amountMsat !== amountMsat) {
1380
- throw new WalletRefused(
1381
- "invoice-refused",
1382
- `${address} issued an invoice for ${issued.amountMsat} msat, not ${amountMsat}`
1383
- );
1384
- }
1385
- if (issued.descriptionHash !== sha256Hex(pay.metadata)) {
1386
- throw new WalletRefused(
1387
- "invoice-refused",
1388
- `${address} does not bind its invoice to the metadata it serves`
1389
- );
1390
- }
1391
- return {
1392
- address,
1393
- bolt11: invoice.pr,
1394
- verifyUrl: invoice.verify,
1395
- paymentHash: issued.paymentHash,
1396
- expiresAt: issued.expiresAt
1397
- };
1398
- }
1399
- async function answered(url, deadline) {
1400
- try {
1401
- return await fetchJson(url, deadline);
1402
- } catch (cause) {
1403
- throw new WalletRefused("unreachable", String(cause));
1404
- }
1405
- }
1406
- function decodeIssued(address, bolt11) {
1407
- const { paymentHash, descriptionHash, amountMsat, expiresAt } = decodeInvoice(bolt11);
1408
- if (paymentHash === null || expiresAt === null) {
1409
- throw new WalletRefused("invoice-refused", `${address} issued an invoice we cannot decode`);
1410
- }
1411
- return { paymentHash, descriptionHash, amountMsat, expiresAt };
1412
- }
1413
- function cannotReleaseAPreimage(host) {
1414
- const lowered = host.toLowerCase();
1415
- return VERIFY_WITHOUT_PREIMAGE.some(
1416
- (known) => lowered === known || lowered.endsWith(`.${known}`)
1417
- );
1418
- }
1419
- function toLnurl(endpoint) {
1420
- const scheme = parsedScheme(endpoint);
1421
- if (scheme !== "https:" && scheme !== "http:") {
1422
- throw new Error(`${endpoint} is not an http or https URL`);
1423
- }
1424
- const words = toWords(new TextEncoder().encode(endpoint));
1425
- const data = [...words, ...checksumWords(LNURL_HRP, words)];
1426
- return `${LNURL_HRP}1${data.map((word) => BECH32_CHARSET2[word]).join("")}`.toUpperCase();
1427
- }
1428
- function parsedScheme(endpoint) {
1429
- try {
1430
- return new URL(endpoint).protocol;
1431
- } catch {
1432
- return null;
1433
- }
1434
- }
1435
- function toWords(bytes) {
1436
- const words = [];
1437
- let accumulator = 0;
1438
- let bits = 0;
1439
- for (const byte of bytes) {
1440
- accumulator = accumulator << 8 | byte;
1441
- bits += 8;
1442
- while (bits >= 5) {
1443
- bits -= 5;
1444
- words.push(accumulator >> bits & 31);
1445
- }
1446
- }
1447
- if (bits > 0) words.push(accumulator << 5 - bits & 31);
1448
- return words;
1449
- }
1450
- function checksumWords(hrp, words) {
1451
- const expanded = [...hrp].map((char) => char.charCodeAt(0));
1452
- const values = [
1453
- ...expanded.map((code) => code >> 5),
1454
- 0,
1455
- ...expanded.map((code) => code & 31),
1456
- ...words,
1457
- ...CHECKSUM_SLOTS.map(() => 0)
1458
- ];
1459
- const polymod = bech32Polymod(values) ^ 1;
1460
- return CHECKSUM_SLOTS.map((slot) => polymod >> 5 * (5 - slot) & 31);
1461
- }
1462
- function bech32Polymod(values) {
1463
- let checksum = 1;
1464
- for (const value of values) {
1465
- const top = checksum >> 25;
1466
- checksum = (checksum & 33554431) << 5 ^ value;
1467
- for (let bit = 0; bit < 5; bit++) {
1468
- if (top >> bit & 1) checksum ^= BECH32_GENERATOR[bit];
1469
- }
1470
- }
1471
- return checksum;
1472
- }
1473
- function withAmount(callback, amountMsat) {
1474
- const separator = callback.includes("?") ? "&" : "?";
1475
- return `${callback}${separator}amount=${amountMsat}`;
1476
- }
1477
- function splitAddress(address) {
1478
- const [user, domain, ...rest] = address.split("@");
1479
- if (!user || !domain || rest.length > 0 || !publicHttps(`https://${domain}/`)) {
1480
- throw new WalletRefused("address-unusable", `${address} is not a usable lightning address`);
1481
- }
1482
- return [user, domain];
1483
- }
1484
- async function fetchJson(url, deadline) {
1485
- const answer = await ask(url, { headers: { accept: "application/json" }, deadline });
1486
- if (!answer.ok) throw new Error(`${url} answered ${answer.status}`);
1487
- if (answer.truncated) {
1488
- throw new Error(`${url} answered with more than the ${BODY_LIMIT_BYTES} bytes we read`);
1489
- }
1490
- return JSON.parse(answer.body);
1491
- }
1492
-
1493
- // src/trigger.ts
1494
- var NONCE_BYTES = 16;
1495
- function lnurlPayEndpoint(config) {
1496
- return async (request) => {
1497
- const url = new URL(request.url);
1498
- const asked = url.searchParams.get("to");
1499
- try {
1500
- return asked === null ? await offer(config, url) : await mint(config, url, asked);
1501
- } catch (failure) {
1502
- return refuse(failure instanceof Error ? failure.message : "the trigger could not be served");
1503
- }
1504
- };
1505
- }
1506
- async function offer(config, url) {
1507
- const amountMsat = await config.amountMsat();
1508
- const quote = await config.gateway.createQuote({
1509
- lnAddresses: config.lnAddresses,
1510
- amountMsat
1511
- });
1512
- const nonce = randomNonce();
1513
- const callback = new URL(config.baseUrl ?? `${url.origin}${url.pathname}`);
1514
- callback.searchParams.set("to", quote.lnAddress);
1515
- callback.searchParams.set("msat", String(amountMsat));
1516
- callback.searchParams.set("n", nonce);
1517
- callback.searchParams.set("sig", await sign(config.secret, quote.lnAddress, amountMsat, nonce));
1518
- return Response.json({
1519
- tag: "payRequest",
1520
- callback: callback.toString(),
1521
- metadata: quote.metadata,
1522
- minSendable: amountMsat,
1523
- maxSendable: amountMsat
1524
- });
1525
- }
1526
- async function mint(config, url, address) {
1527
- const amountMsat = Number(url.searchParams.get("msat"));
1528
- const nonce = url.searchParams.get("n") ?? "";
1529
- const signature = url.searchParams.get("sig") ?? "";
1530
- const expected = await sign(config.secret, address, amountMsat, nonce);
1531
- if (!equalInConstantTime(signature, expected)) return refuse("this callback was not signed here");
1532
- const wanted = url.searchParams.get("amount");
1533
- if (wanted !== null && Number(wanted) !== amountMsat) {
1534
- return refuse(`this trigger costs exactly ${amountMsat} msat`);
1535
- }
1536
- const minted = config.blind ? await mintBlind(config, address, amountMsat) : await mintThroughGateway(config, address, amountMsat, nonce);
1537
- return Response.json({
1538
- status: "OK",
1539
- pr: minted.bolt11,
1540
- routes: [],
1541
- verify: minted.verifyUrl
1542
- });
1543
- }
1544
- async function mintThroughGateway(config, address, amountMsat, nonce) {
1545
- const payment = await config.gateway.createPayment(
1546
- { lnAddresses: [address], amountMsat },
1547
- { idempotencyKey: nonce, trigger: config.watchSecret }
1548
- );
1549
- return { bolt11: payment.bolt11, verifyUrl: payment.verifyUrl };
1550
- }
1551
- async function mintBlind(config, address, amountMsat) {
1552
- const resolved = await resolve([address], amountMsat);
1553
- const minted = { ...resolved, amountMsat, lnAddress: resolved.address };
1554
- const locked = config.sealed;
1555
- try {
1556
- await config.gateway.watchPayment({
1557
- paymentHash: resolved.paymentHash,
1558
- verifyUrl: resolved.verifyUrl,
1559
- expiresAt: resolved.expiresAt,
1560
- trigger: config.watchSecret,
1561
- sealed: locked ? await seal(locked.secret, JSON.stringify(locked.data(minted))) : void 0
1562
- });
1563
- } catch (refused) {
1564
- if (!alreadyWatched(refused)) throw refused;
1565
- }
1566
- return { bolt11: resolved.bolt11, verifyUrl: resolved.verifyUrl };
1567
- }
1568
- function alreadyWatched(refused) {
1569
- return refused instanceof ProblemError && isProblemType(refused, PAYMENT_ALREADY_WATCHED);
1570
- }
1571
- function sign(secret, address, amountMsat, nonce) {
1572
- return hmacHex(secret, `${address}|${amountMsat}|${nonce}`);
1573
- }
1574
- function randomNonce() {
1575
- const bytes = crypto.getRandomValues(new Uint8Array(NONCE_BYTES));
1576
- let hex = "";
1577
- for (const byte of bytes) hex += byte.toString(16).padStart(2, "0");
1578
- return hex;
1579
- }
1580
- function refuse(reason) {
1581
- return Response.json({ status: "ERROR", reason });
1582
- }
1583
-
1584
1220
  // src/currency.ts
1585
1221
  var ISO_4217_MINOR_UNITS = {
1586
1222
  BHD: 3,
@@ -1824,6 +1460,66 @@ function asDate(unix) {
1824
1460
  return new Date(unix * MILLIS).toISOString().slice(0, DATE_CHARS);
1825
1461
  }
1826
1462
 
1463
+ // ../core/lnurl.ts
1464
+ var BECH32_CHARSET2 = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
1465
+ var BECH32_GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
1466
+ var CHECKSUM_SLOTS = [0, 1, 2, 3, 4, 5];
1467
+ var LNURL_HRP = "lnurl";
1468
+ function toLnurl(endpoint) {
1469
+ const scheme = parsedScheme(endpoint);
1470
+ if (scheme !== "https:" && scheme !== "http:") {
1471
+ throw new Error(`${endpoint} is not an http or https URL`);
1472
+ }
1473
+ const words = toWords(new TextEncoder().encode(endpoint));
1474
+ const data = [...words, ...checksumWords(LNURL_HRP, words)];
1475
+ return `${LNURL_HRP}1${data.map((word) => BECH32_CHARSET2[word]).join("")}`.toUpperCase();
1476
+ }
1477
+ function parsedScheme(endpoint) {
1478
+ try {
1479
+ return new URL(endpoint).protocol;
1480
+ } catch {
1481
+ return null;
1482
+ }
1483
+ }
1484
+ function toWords(bytes) {
1485
+ const words = [];
1486
+ let accumulator = 0;
1487
+ let bits = 0;
1488
+ for (const byte of bytes) {
1489
+ accumulator = accumulator << 8 | byte;
1490
+ bits += 8;
1491
+ while (bits >= 5) {
1492
+ bits -= 5;
1493
+ words.push(accumulator >> bits & 31);
1494
+ }
1495
+ }
1496
+ if (bits > 0) words.push(accumulator << 5 - bits & 31);
1497
+ return words;
1498
+ }
1499
+ function checksumWords(hrp, words) {
1500
+ const expanded = [...hrp].map((char) => char.charCodeAt(0));
1501
+ const values = [
1502
+ ...expanded.map((code) => code >> 5),
1503
+ 0,
1504
+ ...expanded.map((code) => code & 31),
1505
+ ...words,
1506
+ ...CHECKSUM_SLOTS.map(() => 0)
1507
+ ];
1508
+ const polymod = bech32Polymod(values) ^ 1;
1509
+ return CHECKSUM_SLOTS.map((slot) => polymod >> 5 * (5 - slot) & 31);
1510
+ }
1511
+ function bech32Polymod(values) {
1512
+ let checksum = 1;
1513
+ for (const value of values) {
1514
+ const top = checksum >> 25;
1515
+ checksum = (checksum & 33554431) << 5 ^ value;
1516
+ for (let bit = 0; bit < 5; bit++) {
1517
+ if (top >> bit & 1) checksum ^= BECH32_GENERATOR[bit];
1518
+ }
1519
+ }
1520
+ return checksum;
1521
+ }
1522
+
1827
1523
  // src/qr.ts
1828
1524
  var import_uqr = require("uqr");
1829
1525
  var SAFE_COLOR = /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$|^rgba?\([\d.,%/\s]+\)$|^[a-z]+$/i;
@@ -1937,35 +1633,6 @@ function lightningRail(config) {
1937
1633
  };
1938
1634
  };
1939
1635
  }
1940
- function blindLightningRail(config) {
1941
- return async (order) => {
1942
- const resolved = await invoiceFrom(config.lnAddresses, await config.amountMsat(order));
1943
- const watched = await config.gateway.watchPayment({
1944
- paymentHash: resolved.paymentHash,
1945
- verifyUrl: resolved.verifyUrl,
1946
- expiresAt: resolved.expiresAt,
1947
- trigger: config.trigger,
1948
- sealed: await config.sealed?.(order)
1949
- });
1950
- return {
1951
- id: watched.id,
1952
- rail: config.name ?? LIGHTNING,
1953
- scan: resolved.bolt11,
1954
- qr: encodeForQr(resolved.bolt11),
1955
- expiresAt: resolved.expiresAt
1956
- };
1957
- };
1958
- }
1959
- async function invoiceFrom(lnAddresses, amountMsat) {
1960
- try {
1961
- return await resolve(lnAddresses, amountMsat);
1962
- } catch (refused) {
1963
- if (refused instanceof NoWalletAvailable) {
1964
- throw new NoWalletAvailableError({ title: refused.message }, refused.wallets);
1965
- }
1966
- throw refused;
1967
- }
1968
- }
1969
1636
 
1970
1637
  // src/price.ts
1971
1638
  var MSAT_PER_BTC2 = 1e11;
@@ -2097,13 +1764,13 @@ var DEFAULT_TOLERANCE_SECS = 300;
2097
1764
  async function verifyWebhookSignature(body, signature, secret, timestamp, options = {}) {
2098
1765
  if (!recent(timestamp, options.toleranceSecs ?? DEFAULT_TOLERANCE_SECS)) return false;
2099
1766
  const received = signature.startsWith(SIGNATURE_PREFIX) ? signature.slice(SIGNATURE_PREFIX.length) : signature;
2100
- return equalInConstantTime(await sign2(secret, timestamp, body), received.toLowerCase());
1767
+ return equalInConstantTime(await sign(secret, timestamp, body), received.toLowerCase());
2101
1768
  }
2102
1769
  async function parseWebhook(body, signature, secret, timestamp, options = {}) {
2103
1770
  if (!await verifyWebhookSignature(body, signature, secret, timestamp, options)) return null;
2104
- const text3 = typeof body === "string" ? body : new TextDecoder().decode(body);
1771
+ const text2 = typeof body === "string" ? body : new TextDecoder().decode(body);
2105
1772
  try {
2106
- return paymentFromWire(JSON.parse(text3));
1773
+ return paymentFromWire(JSON.parse(text2));
2107
1774
  } catch {
2108
1775
  return null;
2109
1776
  }
@@ -2119,7 +1786,7 @@ function recent(timestamp, toleranceSecs) {
2119
1786
  if (!Number.isFinite(sent)) return false;
2120
1787
  return Math.abs(Math.floor(Date.now() / 1e3) - sent) <= toleranceSecs;
2121
1788
  }
2122
- async function sign2(secret, timestamp, body) {
1789
+ async function sign(secret, timestamp, body) {
2123
1790
  return hmacHex(secret, signed(timestamp, body));
2124
1791
  }
2125
1792
  function signed(timestamp, body) {
@@ -2147,7 +1814,6 @@ function signed(timestamp, body) {
2147
1814
  bankTransfer,
2148
1815
  bankVerifyEndpoint,
2149
1816
  bitstamp,
2150
- blindLightningRail,
2151
1817
  coinbase,
2152
1818
  coinmate,
2153
1819
  decodeInvoice,
@@ -2158,7 +1824,6 @@ function signed(timestamp, body) {
2158
1824
  isProvablyPaid,
2159
1825
  kraken,
2160
1826
  lightningRail,
2161
- lnurlPayEndpoint,
2162
1827
  lnurlToDataUrl,
2163
1828
  lnurlToSvg,
2164
1829
  medianOf,