aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-06 21:12:19 -0700
committerAdam Soltys <[email protected]>2026-10-06 21:12:19 -0700
commitf53e70ed98eb723479b4276c5b621b599fe570a0 (patch)
tree15a77563c946e5657e3f4de87e09f55cc2883211
parent7727b97c71c11b4b65f47bcc68460ea981c1b22c (diff)
downloadcoinos-server-f53e70ed98eb723479b4276c5b621b599fe570a0.tar.gz
coinos-server-f53e70ed98eb723479b4276c5b621b599fe570a0.zip
payments: lowercase payreq before looking up our own invoices
An uppercase bolt11 for a coinos invoice missed the getInvoice lookup, so it was paid over lightning to our own node instead of internally. The listener then saw the sender's payment pointer for that bolt11 and skipped crediting the recipient. Normalize in POST /payments and nwc pay_invoice. Co-Authored-By: Claude Opus 5.5 <[email protected]>
-rw-r--r--lib/nwc.ts8
-rw-r--r--routes/payments.ts5
2 files changed, 12 insertions, 1 deletions
diff --git a/lib/nwc.ts b/lib/nwc.ts
index 5dba6e97..21bab0a7 100644
--- a/lib/nwc.ts
+++ b/lib/nwc.ts
@@ -634,7 +634,13 @@ const checkBudget = async (app, amount) => {
const handle = (method, params, ev, app, user) =>
({
async pay_invoice() {
- const { invoice: pr, metadata, amount: reqAmountMsat } = params;
+ const { metadata, amount: reqAmountMsat } = params;
+ // Lowercase so getInvoice() finds our own invoices below (see create()
+ // in routes/payments.ts).
+ const pr =
+ typeof params.invoice === "string"
+ ? params.invoice.replace(/\s/g, "").toLowerCase()
+ : params.invoice;
const { amount_msat, payee } = await ln.decode(pr);
const { id } = await ln.getinfo();
// For an amountless bolt11, the invoice carries no amount — NIP-47 lets the
diff --git a/routes/payments.ts b/routes/payments.ts
index 67243a12..66fd3386 100644
--- a/routes/payments.ts
+++ b/routes/payments.ts
@@ -66,6 +66,11 @@ export default {
if (payreq != null && typeof payreq !== "string")
fail("Invalid payment request");
if (hash != null && typeof hash !== "string") fail("Invalid invoice");
+ // Invoices are keyed lowercase. An uppercase payreq (QR-scanned) missed
+ // the lookup below and was paid over cl to ourselves instead of
+ // internally; the listener then found the sender's payment:<bolt11>
+ // pointer and skipped crediting the recipient.
+ if (payreq) payreq = payreq.replace(/\s/g, "").toLowerCase();
if (typeof amount !== "undefined") {
amount = Number.parseInt(amount);