thunder-bridge 1.5.0 → 2.2.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.
- package/README.md +49 -24
- package/dist/{client-Cc5gtjGV.d.ts → bank-B5MxT_6u.d.ts} +367 -42
- package/dist/{client-CzGZcByI.d.cts → bank-Bg6RjuO-.d.cts} +367 -42
- package/dist/bank.cjs +196 -0
- package/dist/bank.d.cts +4 -2
- package/dist/bank.d.ts +4 -2
- package/dist/bank.js +195 -0
- package/dist/{errors-Dmh-Uoh8.d.cts → errors-DJmsalYZ.d.cts} +3 -3
- package/dist/{errors-0vbVoISA.d.ts → errors-VX0R18oE.d.ts} +3 -3
- package/dist/index.cjs +1313 -395
- package/dist/index.d.cts +19 -10
- package/dist/index.d.ts +19 -10
- package/dist/index.js +1312 -395
- package/dist/nwc.cjs +183 -42
- package/dist/nwc.d.cts +10 -111
- package/dist/nwc.d.ts +10 -111
- package/dist/nwc.js +180 -39
- package/dist/price.d.cts +2 -2
- package/dist/price.d.ts +2 -2
- package/dist/qr.cjs +20 -23
- package/dist/qr.js +20 -23
- package/dist/{types-BNPmVnA7.d.cts → types-DYZ9EkmJ.d.cts} +11 -2
- package/dist/{types-BNPmVnA7.d.ts → types-DYZ9EkmJ.d.ts} +11 -2
- package/openapi.yaml +30 -40
- package/package.json +1 -1
- package/dist/bank-B3mHISn1.d.cts +0 -92
- package/dist/bank-B3mHISn1.d.ts +0 -92
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ so the same wallet on another domain can answer differently.
|
|
|
34
34
|
A refusal happens at creation rather than leaving a payment pending until a
|
|
35
35
|
watcher gives up, so a recipient finds out before a payer sees a QR code.
|
|
36
36
|
|
|
37
|
-
If your recipient is on a refused name, `
|
|
37
|
+
If your recipient is on a refused name, `gateway.rails.nwc` is the way round it: your own
|
|
38
38
|
wallet answers over NIP-47 instead of over an address, and the gateway watches the
|
|
39
39
|
hash exactly the same. [docs/lud21-coverage.md](../docs/lud21-coverage.md) is the
|
|
40
40
|
measured list rather than a reading of changelogs, last surveyed 2026-08-12. Read
|
|
@@ -137,16 +137,16 @@ preimage, and which side does the checking.
|
|
|
137
137
|
| the gateway is told | a hash, an expiry and your URL, with the wallet's sealed inside |
|
|
138
138
|
| the invoice is checked by | nobody needs to, you resolved the address yourself |
|
|
139
139
|
| the gateway probes first | `speaksVerify`: a GET on the URL, then a signed POST nonce it must echo |
|
|
140
|
-
| the gateway polls | your `serve.
|
|
140
|
+
| the gateway polls | your `serve.lightningVerify` endpoint, once `relayThrough` is set. Leave it off and the gateway polls the wallet directly, as on the minted rail |
|
|
141
141
|
| `settled` comes from | your endpoint, which unseals, asks the wallet and relays the answer |
|
|
142
142
|
| the pace is set by | you, `pollEverySecs` |
|
|
143
143
|
|
|
144
|
-
| `
|
|
144
|
+
| `rails.nwc` | your own wallet mints it, over NIP-47 `make_invoice` |
|
|
145
145
|
|---|---|
|
|
146
146
|
| the gateway is told | a hash and your URL, with the hash sealed inside |
|
|
147
147
|
| the invoice is checked by | nobody, it is your wallet |
|
|
148
148
|
| the gateway probes first | the same GET and signed nonce |
|
|
149
|
-
| the gateway polls | your `
|
|
149
|
+
| the gateway polls | your `serve.nwcVerify` endpoint |
|
|
150
150
|
| `settled` comes from | `lookup_invoice`, refused unless the wallet's own key signed it |
|
|
151
151
|
| the pace is set by | you, `pollEverySecs` |
|
|
152
152
|
|
|
@@ -203,7 +203,7 @@ without saying whether either invoice was paid.
|
|
|
203
203
|
concluding the invoice went unpaid. The body still reads `settled: false`, and the
|
|
204
204
|
status is what separates "could not ask" from "asked, and no"
|
|
205
205
|
|
|
206
|
-
**`
|
|
206
|
+
**`rails.nwc`**
|
|
207
207
|
|
|
208
208
|
- an NWC connection to your own wallet, and the nostr relays behind it
|
|
209
209
|
- **scope the connection to `make_invoice` and `lookup_invoice`, never
|
|
@@ -252,21 +252,23 @@ Four sharp edges, worth reading before you build:
|
|
|
252
252
|
metadata and answers the verify requests. Every check passes. This protects a
|
|
253
253
|
payer against the operator, never against the recipient's own custodian.
|
|
254
254
|
- **The two proof fetches vet the first hop and no further.** `proveOrigin` and
|
|
255
|
-
`proveSettlement` use the runtime's
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
255
|
+
`proveSettlement` use the runtime's redirect handling, so a public https host
|
|
256
|
+
answering `302` to a private address on its own origin is followed there, while a
|
|
257
|
+
redirect off the recipient's origin fails the proof. `invoiceFrom` is not like
|
|
258
|
+
this: it resolves through the outbound guard, which sets `redirect: "manual"` and
|
|
259
|
+
re-vets every hop. Keep egress control outside this package if that matters.
|
|
259
260
|
- **A payment read cold is only as pinned as its creation.** `payment` checks
|
|
260
|
-
the
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
cold read is checking the gateway's numbers
|
|
261
|
+
the report against the `paymentHash` you hand it, and it was `proveOrigin` at
|
|
262
|
+
creation, against the request you wrote, that tied that hash to an invoice the
|
|
263
|
+
recipient issued. Store the hash you proved alongside the payment id, and never a
|
|
264
|
+
hash a later read handed back, or a cold read is checking the gateway's numbers
|
|
265
|
+
against each other and nothing more.
|
|
264
266
|
- **Availability is not provable, and an address is not a person.** Every check
|
|
265
267
|
here is about an invoice you were given, none about one you were refused, and
|
|
266
268
|
proving an invoice belongs to an address never proves the address belongs to
|
|
267
269
|
whoever you think it does.
|
|
268
270
|
|
|
269
|
-
`
|
|
271
|
+
`agreesWithItself` is the one to be careful with: it asks only whether a report holds
|
|
270
272
|
together, so a gateway that generates a preimage, hashes it and builds an invoice
|
|
271
273
|
around that hash passes it. If a payment matters, ask the recipient with
|
|
272
274
|
`prove` on the payment request or with `proveSettlement`. The full argument, including the five
|
|
@@ -291,7 +293,7 @@ const gateway = new ThunderBridge("https://public.thunder-bridge.agora.gripe", {
|
|
|
291
293
|
});
|
|
292
294
|
|
|
293
295
|
const asked = await gateway.requestPayment({ paidTo: "iamfatik@blink.sv", amount: sats(21) });
|
|
294
|
-
const read = await gateway.payment(asked
|
|
296
|
+
const read = await gateway.payment(asked);
|
|
295
297
|
const quoted = await gateway.quote({ paidTo: "iamfatik@blink.sv", amount: sats(21) });
|
|
296
298
|
|
|
297
299
|
const lnurl = gateway.serve.lnurlPay({
|
|
@@ -306,13 +308,16 @@ const rail = gateway.rails.lightning({ paidTo: "iamfatik@blink.sv", amount: () =
|
|
|
306
308
|
`payments`, `settled`, `firstSettled`, `follow`, `ticket`, `nameFor` and
|
|
307
309
|
`webhookKey`, all on the instance
|
|
308
310
|
- **what you mount** is on `gateway.serve`: an LNURL-pay endpoint, the two ticket
|
|
309
|
-
endpoints, the verify endpoints
|
|
310
|
-
and the readers under it
|
|
311
|
+
endpoints, the verify endpoints `lightningVerify`, `bankVerify` and `nwcVerify`, the
|
|
312
|
+
webhook route, and the readers under it
|
|
311
313
|
- **one call per sale** is on `gateway.rails`: `lightning`, `blindLightning`,
|
|
312
|
-
`bank`, and `transfer` for a bank transfer on its own
|
|
314
|
+
`bank`, `nwc`, and `transfer` for a bank transfer on its own. What the NWC rail
|
|
315
|
+
needs to reach your wallet, `nwcConnection` and the wallet calls, stays in
|
|
316
|
+
`thunder-bridge/nwc`
|
|
313
317
|
- **the proofs** are free functions, deliberately, because a proof you cannot run
|
|
314
318
|
without the thing being audited is not a proof: `proveOrigin`, `proveSettlement`,
|
|
315
|
-
`proveWrapped`, `
|
|
319
|
+
`proveWrapped`, `decodeInvoice`, `preimageMatchesHash`. `agreesWithItself` sits
|
|
320
|
+
beside them and proves less, as the table below says
|
|
316
321
|
- **a payment reads without an assertion.** `Payment` is `MintedPayment |
|
|
317
322
|
WatchedPayment`, so checking `kind` is what makes the address, the amount and the
|
|
318
323
|
invoice non-null. The gateway writes those three together or writes none of them,
|
|
@@ -322,6 +327,20 @@ const rail = gateway.rails.lightning({ paidTo: "iamfatik@blink.sv", amount: () =
|
|
|
322
327
|
What your service answers once those handlers are mounted is written out in
|
|
323
328
|
[`openapi.yaml`](openapi.yaml), shipped with this package.
|
|
324
329
|
|
|
330
|
+
### Which call checks what
|
|
331
|
+
|
|
332
|
+
There are several ways to hear that a payment settled because there are several
|
|
333
|
+
places to hear it from. They do not check the same thing, and the difference is
|
|
334
|
+
what you may act on without asking anyone else.
|
|
335
|
+
|
|
336
|
+
| You hear it through | What the claim is checked against |
|
|
337
|
+
| --- | --- |
|
|
338
|
+
| `payment`, `settled`, `firstSettled`, `paid()` on a `requestPayment`, and `Gateways.settled` | the `{ id, paymentHash }` you hold. Another payment, another hash, or a preimage that does not hash to yours throws `GatewayCheatError` |
|
|
339
|
+
| `serve.webhook`, `serve.readSettlement`, `serve.readPayment` | the gateway's key, the timestamp, the URL it was sent to, and the preimage against the hash in the same body. Find your order by that hash before you act, which is what makes a pair the gateway invented find nothing |
|
|
340
|
+
| `payments`, `follow` | the report itself. An entry claiming paid whose preimage does not hash to its own hash is left out of `payments` and reaches `follow`'s `onError` rather than `onPayment` |
|
|
341
|
+
| `agreesWithItself` | the report itself, and nothing you hold, so a gateway that invents a preimage and names its hash passes it |
|
|
342
|
+
| `proveSettlement` | the recipient's own verify URL, after the origin proof, so the gateway is not asked at all |
|
|
343
|
+
|
|
325
344
|
## Errors
|
|
326
345
|
|
|
327
346
|
Every failure from the gateway is an RFC 9457 problem document. Branch on `type`,
|
|
@@ -398,10 +417,16 @@ try {
|
|
|
398
417
|
|
|
399
418
|
Pass `webhookUrl` when you create a payment, or on any rail. There is no webhook
|
|
400
419
|
secret: a gateway holds nothing of yours, and sending one is refused rather than
|
|
401
|
-
ignored. Every delivery
|
|
402
|
-
publishes at `/webhook-key`, over `<x-timestamp
|
|
403
|
-
|
|
404
|
-
at
|
|
420
|
+
ignored. Every delivery carries `x-signature-v2: ed25519=<signature>` with the key
|
|
421
|
+
the gateway publishes at `/webhook-key`, over the URL it was sent to, `<x-timestamp>`
|
|
422
|
+
and the raw body, so a delivery made for somebody else's endpoint proves nothing at
|
|
423
|
+
yours and a captured one cannot be replayed at you later. Behind a proxy that hands
|
|
424
|
+
the request on under another host or scheme, pass the URL you registered as `url`.
|
|
425
|
+
Until then
|
|
426
|
+
`serve.webhook` acts on each settlement once, answering a replay `200` without
|
|
427
|
+
calling you again. Delivery is still at-least-once: a retry after that window, or
|
|
428
|
+
one reaching another instance of your server, calls you again, so fulfil
|
|
429
|
+
idempotently on `id`.
|
|
405
430
|
|
|
406
431
|
Your handler answers one challenge before any of that. The gateway POSTs
|
|
407
432
|
`{"type":"webhook-challenge","nonce":"..."}` to the URL while the create is still
|
|
@@ -429,7 +454,7 @@ that proves nothing gets a `202` and no callback, because acting on an unproven
|
|
|
429
454
|
claim is the one thing this refuses to do. Pass `onUnproven` when an expiry is news
|
|
430
455
|
you want.
|
|
431
456
|
|
|
432
|
-
`onSettled` is handed a `
|
|
457
|
+
`onSettled` is handed a `SelfConsistent<Settlement>`, so the preimage is a `string` rather
|
|
433
458
|
than something to coerce: the check the route already ran is what narrows it.
|
|
434
459
|
|
|
435
460
|
`gateway.serve.readSettlement` and `gateway.serve.readPayment` are the same checks
|