From add3ad93ff37f1daaedab5788f00663be299555c Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Thu, 30 Jul 2026 08:51:36 -0700 Subject: bolt12 zaps: pay offers, NWC pay/receive, per-user offers, NIP-44 - sendLightning fetches an invoice from lno1 offers (payer_note passthrough for NIP-177 zap intents) and pays it through the existing bolt12 path - NWC: new nwc#2 pay/receive methods (BIP-321 URIs, payer proofs stubbed until CLN 26.06 createproof), nip44_v2 alongside nip04 with per-request scheme detection, dual 23196/23197 notifications, 13194 refreshed when its content or encryption tag goes stale - standing per-user bolt12 offer via GET /offer; incoming bolt12 payments record invreq_payer_note as memo - parse/fetchinvoice routes handle offers; zap display parses kind 9736 receipts (amount tag + embedded intent) and drops a call to a sync() helper that never existed Co-Authored-By: Claude Fable 5 --- lib/payments.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'lib/payments.ts') diff --git a/lib/payments.ts b/lib/payments.ts index df2c8857..56aa08de 100644 --- a/lib/payments.ts +++ b/lib/payments.ts @@ -717,6 +717,7 @@ export const sendLightning = async ({ amount, fee = undefined, memo = undefined, + payerNote = undefined, }) => { let p; @@ -736,8 +737,29 @@ export const sendLightning = async ({ } } + let decoded = await ln.decode(pr); + + // A bolt12 offer (lno1...) isn't payable directly — fetch a real invoice + // from it over onion messages, then pay that. payerNote rides along in + // invreq_payer_note (NIP-177 bolt12 zaps put nostr:nip177: there). + if (decoded.type === "bolt12 offer") { + if (decoded.offer_currency) + fail("Currency-denominated offers are not supported"); + if (!decoded.offer_amount_msat && !amount) fail("Amount required"); + + const { invoice } = await ln.fetchinvoice({ + offer: pr, + amount_msat: decoded.offer_amount_msat ? undefined : amount * 1000, + payer_note: payerNote, + timeout: 60, + }); + + pr = invoice.replace(/\s/g, "").toLowerCase(); + decoded = await ln.decode(pr); + } + let { type, invoice_amount_msat, amount_msat, invoice_node_id, payee } = - await ln.decode(pr); + decoded; if (type.includes("bolt12")) { amount_msat = invoice_amount_msat; payee = invoice_node_id; -- cgit v1.2.3