From d554a13cf4560891010f50e117754825c1f1be7a Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sat, 1 Aug 2026 15:02:01 -0700 Subject: Make NWC budgets accumulate and travel across devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit onRequest handled every request against the connection object captured at listen() time, so each spend was recorded against a stale snapshot — spentToday restarted from the old value on every payment and the daily budget never actually bound. The connection is now re-resolved from stored state per request, which also stops serving a connection revoked on another device mid-session. recordSpend now publishes the sync snapshot so the spend (and the payment's movement + vtxo change) reaches the user's other devices. Test: two payments must accumulate to 52. Co-Authored-By: Claude Fable 5 --- src/features/nwc.js | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src') diff --git a/src/features/nwc.js b/src/features/nwc.js index f561a8a..20b0dd3 100644 --- a/src/features/nwc.js +++ b/src/features/nwc.js @@ -78,6 +78,10 @@ export function nwcFeature(ctx) { function recordSpend(c, sat) { const { today, spent } = spendRoom(c); updateConn(c.id, { spentDate: today, spentToday: spent + sat, lastUsed: Date.now() }); + // Publish the snapshot: budgets only bind across devices if the spend + // travels — and the payment just changed the ark state (vtxos, movement) + // that the user's other devices display. + try { wallet.saveCache(); } catch {} } // The relays advertised in the URI MUST be the ones we listen on, or a @@ -226,6 +230,13 @@ export function nwcFeature(ctx) { if (ev.pubkey !== c.clientPk) { return console.log(`nwc: guard drop — pubkey mismatch got=${ev.pubkey.slice(0, 8)} want=${c.clientPk.slice(0, 8)}`); } + // Re-resolve the connection from stored state: the closure's `c` is a + // snapshot from listen() time, so budget math computed from it restarts + // from a stale value on every request (spends never accumulate), and a + // connection revoked on another device would keep being served here. + const cur = (load().conns || []).find((x) => x.id === c.id); + if (!cur || cur.revoked) return console.log('nwc: guard drop — connection gone or revoked', c.id); + c = cur; const scheme = ev.tags?.find((x) => x[0] === 'encryption')?.[1] === 'nip44_v2' ? 'nip44_v2' : 'nip04'; -- cgit v1.2.3