diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/payments.ts | 13 |
1 files changed, 12 insertions, 1 deletions
diff --git a/lib/payments.ts b/lib/payments.ts index 16eb7213..c715af47 100644 --- a/lib/payments.ts +++ b/lib/payments.ts @@ -697,6 +697,14 @@ export const sendLightning = async ({ }) => { let p; + // BOLT11 is case-insensitive, but downstream code is not: the stored payment + // hash, the `pending` reconciler entry, and check()'s startsWith("ln") test + // all assume lowercase. An uppercase-pasted invoice gets stored uppercase, + // then check() treats its pending entry as non-lightning and evicts it + // without reversing — a failed send that never gets auto-refunded. Normalize + // once, up front, so every downstream use sees the same lowercase form. + pr = pr.replace(/\s/g, "").toLowerCase(); + if (typeof amount !== "undefined") { amount = Number.parseInt(amount); if (amount < 0 || amount > SATS || Number.isNaN(amount)) { @@ -1072,7 +1080,10 @@ export const check = async () => { const payments = await db.sMembers("pending"); for (const pr of payments) { - if (!pr.startsWith("ln")) { + // Case-insensitive: an uppercase-pasted invoice ("LNBC…") is still a + // lightning payment. Matching case-sensitively here used to evict such + // entries without reversing, stranding failed sends with no auto-refund. + if (!pr.toLowerCase().startsWith("ln")) { await db.sRem("pending", pr); continue; } |
