aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-08-15 10:45:39 -0700
committerAdam Soltys <[email protected]>2026-08-15 10:45:39 -0700
commit11e007b88e6b45663e3ed4d0bea29b275a9d1ead (patch)
tree28c47eb5ab78410ef04ff1ab439c963fa4a598e1
parent07ac3d010a74f1aa84c463817c0a7ed7d510dbb6 (diff)
downloadcoinosv3-11e007b88e6b45663e3ed4d0bea29b275a9d1ead.tar.gz
coinosv3-11e007b88e6b45663e3ed4d0bea29b275a9d1ead.zip
An invoice's name mapping lives as long as the invoice can settle, and a nameless settle leaves a trace — one paid 1000 sats vanished into a silent continue behind a 1-hour sweep
Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_014tE4U5nEjGTQy8PwYqamfv
-rw-r--r--names/server.js15
1 files changed, 13 insertions, 2 deletions
diff --git a/names/server.js b/names/server.js
index 2bfab2a..23fdb57 100644
--- a/names/server.js
+++ b/names/server.js
@@ -339,7 +339,13 @@ async function settleLoop() {
// LNURL invoices we minted: recorded against their payment hash
const pending = state.invoices && state.invoices[inv.payment_hash];
if (!name && pending) name = pending.key;
- if (!name) continue; // not one of ours (e.g. the ASP's own invoices)
+ if (!name) {
+ // Usually genuinely not ours (the ASP's and boltz's invoices settle on
+ // this node too) — but log it, so a lost mapping is an audit-grep away
+ // instead of an archaeology project.
+ log(`settle without a name: ${inv.payment_hash} ${inv.amount_received_msat || ''}`);
+ continue;
+ }
const sat = Math.floor((inv.amount_received_msat?.msat ?? inv.amount_received_msat ?? 0) / 1000);
if (!sat) continue;
// money has arrived for this name — push-notify their devices (best effort)
@@ -660,8 +666,13 @@ Bun.serve({
state.invoices = state.invoices || {};
state.invoices[inv.payment_hash] = { key, zap, bolt11: inv.bolt11, ts: Date.now() };
// forget invoices nobody paid
+ // Keep mappings as long as the invoice could possibly settle: a 1h
+ // sweep once erased a mapping while the settle loop was catching up
+ // after downtime, stranding a paid 1000 sats unattributed (found
+ // again only via the description_hash). CLN invoices default to a
+ // 7-day expiry — match it.
for (const [h, v] of Object.entries(state.invoices)) {
- if (Date.now() - v.ts > 3600_000) delete state.invoices[h];
+ if (Date.now() - v.ts > 7 * 86400_000) delete state.invoices[h];
}
persist();
log(`lnurl ${key}: issued ${sat} sat (forwarding on settle)`);