aboutsummaryrefslogtreecommitdiffstats
path: root/lib/nwc.ts
Commit message (Collapse)AuthorAgeFilesLines
* nwc: budget keysend, atomic dedup, serialize spends (S4/S6/S8)Adam Soltys2026-08-071-12/+66
| | | | | | | | | | | | | | | - pay_keysend never called checkBudget and never recorded to ${pubkey}:payments, so a budget-limited connection string was a full-drain credential. Budget-check it, honor max_fee, and record the debit so subsequent budgeted calls count it (S4). - Replace the non-atomic zScore-then-(unawaited)-zAdd dedup with an awaited SET NX claim, so two concurrent deliveries of the same signed event can't both reach handle() and pay twice; also reject future-dated created_at beyond a small skew (S6). - Serialize budget-affecting methods per app with an async mutex so a concurrent request can't read a stale spent-total and overspend (S8). Co-Authored-By: Claude Opus 4.8 <[email protected]>
* nwc: republish 13194 info events unconditionally every 2 minutesAdam Soltys2026-08-041-53/+18
| | | | | | | | | | | | | The stored replaceable 13194 info event was intermittently disappearing from the relay, leaving NWC clients (Alby etc.) with "no info event" until the next hourly existence-check happened to republish it. Drop the check-then-publish dance and just republish both server info events every 2 minutes — a replaceable event overwrites in place, so it's cheap and self-heals immediately. Silence the per-publish success log since it now fires on every interval. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Dpqu6wizYe1c1g4k5Gd8JK
* nwc: conform pay/receive to the BIP-321 methods spec (nwc#2)Adam Soltys2026-07-311-15/+116
| | | | | | | | | | | | | | | | | | | | Tightens our implementation of the BIP-321-based NWC methods proposed in https://github.com/nostr-wallet-connect/nwc/pull/2 — the successor to pay_invoice/make_invoice that clients are asked to transition to for bolt12 zaps in https://github.com/nostr-protocol/nips/pull/2421: - reject cross-network payment instructions before paying (UNSUPPORTED_NETWORK) instead of failing after the debit - reject unknown req- BIP-321 params, including req-pop since we can't open proof-of-payment callbacks - reject a request amount that conflicts with the instruction amount - payer_note is delivered or rejected, never dropped: bolt11+note is rejected, internal settlements hand the note over as the payment memo - receive mints a per-request bolt12 offer carrying the requested description/amount instead of reusing the standing amountless offer - get_info reports the node's actual network instead of "mainnet" Co-Authored-By: Claude Fable 5 <[email protected]>
* bolt12 payer proofs: disclose zap fields, lightningd v26.06.2 in sampleAdam Soltys2026-07-301-10/+17
| | | | | | | | | | | createproof's default proof omits invreq_payer_note, and passing include replaces the default disclosure set — so for zap payments request both invreq_payer_note and invoice_amount, which NIP-177 verification requires. Verified end to end on v26.06.2: NWC pay over nip44 returns a proof that decodes valid with note + amount disclosed and preimage matching the payment hash. Co-Authored-By: Claude Fable 5 <[email protected]>
* bolt12 zaps: pay offers, NWC pay/receive, per-user offers, NIP-44Adam Soltys2026-07-301-53/+303
| | | | | | | | | | | | | | | | - 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 <[email protected]>
* nwc: confirm 13194 info-event publish so it cannot be silently droppedAdam Soltys2026-06-281-3/+47
| | | | | | | | | | | | | | | | publishInfo sent the kind-13194 info event over the long-lived NWC socket fire-and-forget. The nostr lib Relay.send is async (await wait_connected; ws.send) but was called without await, and success was logged immediately. A send that rejected (e.g. ws in CLOSING state during a strfry reconnect) was silently dropped while the log claimed success, leaving NWC clients with "no info event" until a manual republish. Publish over a fresh short-lived socket and wait for the relay OK, retrying up to 3x with honest logging (warn on unconfirmed, err on give-up). ensureInfos receive-based detection is unchanged. Verified on prod: deleted both info events, restarted, both republished within seconds. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* nwc: fix pay_invoice reply reliability, rate-limit drops, notificationsAdam Soltys2026-06-061-36/+81
| | | | | | | | | | | | | | | | | | | | | | | | | Three issues reported by an NWC client integrator (refs #80): (a) pay_invoice sync reply: the handler polled listpays for ~20s then returned a misleading "Payment timed out" error on slow routes even though the payment settled — client never got the preimage. sendLightning already runs xpay to completion and finalize() sets p.ref = preimage, so return that directly; keep a longer listpays loop only as a fallback, and on still-in-flight return an explicit "check with lookup_invoice" rather than implying failure. (b) rate limiting: raised per-pubkey cap 5/min -> 60/min (normal usage — a balance check + payment + a few lookup_invoice reconciles — trivially exceeded 5), and over-limit requests now get a NIP-47 RATE_LIMITED error reply instead of a silent drop that looked exactly like a lost reply. Also: every request path now always sends a 23195 reply (success, error, or handler-returned- nothing) so a client never hangs waiting. (c) notifications: payment_received/payment_sent are advertised in the info event but app.notify defaulted to false unless the client sent notify:"true" (only ~1% of apps had it on), so they never fired. Default notify ON; only disable when explicitly "false". (Existing apps still false — backfill TBD.) Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* nwc: pay_invoice honors request amount for amountless bolt11Adam Soltys2026-06-041-2/+14
| | | | | | | | | | | | | | | | pay_invoice derived the amount solely from the decoded invoice, so an amountless bolt11 yielded amount = round(undefined/1000) = NaN and sendLightning rejected it with "Invalid amount". NIP-47 allows the client to specify the amount (msat) in the request for exactly this case (AlbyHub supports it; Alby Go and others hit the error). Fall back to the request's `amount` field when the invoice carries none; invoice amount still takes precedence when present, and a still-missing amount returns a clear error instead of NaN. sendLightning/sendInternal already handle amountless invoices given a valid amount — the bug was only the handler dropping it. Fixes #83 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* nwc: fix make_invoice timestamps (ms -> seconds) breaking NWC clientsAdam Soltys2026-06-041-5/+8
| | | | | | | | | | | | | | | | | | generate() stores `created` in milliseconds (Date.now()), but the NWC make_invoice response returned it directly as created_at and computed expires_at = created_at + expiry. NWC timestamps are Unix SECONDS (NIP-47), so clients parsed a ~1.78e12 expires_at that overflowed their date types — e.g. ptcpay's .NET DateTimeOffset, whose max is 253402300799 (issue #84: "creating lightning invoices via NWC fails ... Valid values are between -62135596800 and 253402300799"). Convert created to seconds before use. The other NWC handlers were already correct (lookup_invoice reads seconds straight from cln; list_transactions divides p.created by 1000). Only make_invoice leaked milliseconds. Fixes #84 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* nwc: publish 13194 info event only when missing, recheck hourlyAdam Soltys2026-06-021-26/+65
| | | | | | | | | | | | | | | | | | NWC clients (Alby Go, Lightning Piggies) fetch the kind 13194 info event (capability advertisement) before they'll talk to the wallet; without it they report "no info event" and show an unknown balance. The events went missing after strfry restarted on 2026-05-29 and stayed gone for days, because the app only published them once in the relay's on-open handler and nothing re-asserted them. 13194 is a replaceable event meant to persist, so instead of blindly republishing, query the relay on connect and publish only the server pubkeys whose info event is actually missing (ensureInfo). Re-check hourly so a relay restart that leaves our socket intact also self-heals. Interval is cleared on close/reconnect alongside the heartbeat to avoid leaks. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* nwc: handle stale client state cleanly and skip reverted-duplicate recordsAdam Soltys2026-05-171-1/+5
| | | | | | | | | | | | | | | | | | Three small NWC robustness fixes that surfaced from the Apr 29 double-credit cleanup: - fail loudly when an NWC request references a pubkey whose user record no longer exists (migrated/deleted account); previously crashed inside handle() on `user.id` - swallow `pubkey not found` and `user not found` in the per-event catch so deleted-app/migrated-user spam doesn't fill the error log — these are client-side staleness, not server faults - use gf() instead of g() when fetching payment records (consistent with the rest of the codebase: arc fallback for wiped main-db pointers) - filter `revertedDuplicate` payments out of list_transactions so clients never see the doubled records that were later reverted Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* nwc heartbeatAdam Soltys2026-03-291-8/+21
|
* stop republishing primal eventsAdam Soltys2026-03-181-1/+14
|
* adjust ln minfeeregtest-dataAdam Soltys2026-03-151-9/+1
|
* consult archive for older paymentsAdam Soltys2026-01-301-4/+8
|
* relay reconnect logicAdam Soltys2026-01-301-31/+45
|
* purge old nwc eventsAdam Soltys2026-01-281-2/+12
|
* quiet nwc failuresAdam Soltys2026-01-211-8/+8
|
* loggingAdam Soltys2026-01-211-8/+8
|
* Fix incorrect extratlvs format in pay_keysendEric P2025-11-091-1/+11
|
* rm logAdam Soltys2025-10-011-3/+0
|
* rotate server keyAdam Soltys2025-09-291-5/+36
|
* catch errors in pay_invoiceAdam Soltys2025-09-291-19/+23
|
* add missing make_invoice fields (fixes #78)Adam Soltys2025-07-261-2/+8
|
* put metadata in payment memoAdam Soltys2025-04-131-1/+2
|
* rm logAdam Soltys2025-03-081-1/+0
|
* fix get_infoAdam Soltys2025-03-081-1/+1
|
* nwc date comparison in secondsAdam Soltys2025-03-071-4/+3
|
* nwc max feeAdam Soltys2025-03-051-1/+2
|
* fix payment_hash lookupAdam Soltys2025-03-051-4/+7
|
* get payment_hash if possibleAdam Soltys2025-03-051-2/+2
|
* add importsAdam Soltys2025-03-051-0/+2
|
* add blockhash to get info responseAdam Soltys2025-03-051-7/+24
|
* record payment_hashAdam Soltys2025-03-051-5/+15
|
* handle no budgetAdam Soltys2025-02-201-1/+1
|
* check createdAdam Soltys2025-02-191-3/+4
|
* return quota exceeded errorAdam Soltys2025-02-171-1/+1
|
* fix nwc periodsAdam Soltys2025-02-181-7/+11
|
* nwc app prefixAdam Soltys2025-02-131-2/+2
|
* add uid to default appAdam Soltys2025-02-131-1/+2
|
* catch nwc errorsAdam Soltys2025-02-121-8/+8
|
* catch payment errorsAdam Soltys2025-02-121-7/+10
|
* nwc refactorAdam Soltys2025-02-121-9/+10
|
* nwc error loggingAdam Soltys2025-02-121-6/+6
|
* nwc notificationsAdam Soltys2025-02-111-11/+15
|
* default app on registerAdam Soltys2025-02-111-1/+2
|
* remove importsAdam Soltys2025-02-101-2/+0
|
* rm logsAdam Soltys2025-02-101-5/+0
|
* budgetAdam Soltys2025-02-101-8/+27
|
* check nwc budgetAdam Soltys2025-02-091-2/+19
|