aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-06-04 18:40:42 -0700
committerAdam Soltys <[email protected]>2026-06-04 18:40:42 -0700
commitce9616f62d0ac682c1e92956ef4cb48f053df27d (patch)
treef8401db5038e7b7bca613dbe3cce4c15f0fa2aa9
parent0154bb060fad7650cd8b825a30a5d88e7018bf8d (diff)
downloadcoinos-server-ce9616f62d0ac682c1e92956ef4cb48f053df27d.tar.gz
coinos-server-ce9616f62d0ac682c1e92956ef4cb48f053df27d.zip
nwc: pay_invoice honors request amount for amountless bolt11
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]>
-rw-r--r--lib/nwc.ts16
1 files changed, 14 insertions, 2 deletions
diff --git a/lib/nwc.ts b/lib/nwc.ts
index 2213d68a..3a1ae5b0 100644
--- a/lib/nwc.ts
+++ b/lib/nwc.ts
@@ -222,10 +222,22 @@ export default () => {
const handle = (method, params, ev, app, user) =>
({
async pay_invoice() {
- const { invoice: pr, metadata } = params;
+ const { invoice: pr, metadata, amount: reqAmountMsat } = params;
const { amount_msat, payee } = await ln.decode(pr);
const { id } = await ln.getinfo();
- const amount = Math.round(amount_msat / 1000);
+ // For an amountless bolt11, the invoice carries no amount — NIP-47 lets the
+ // client specify it in the request's `amount` field (msat). Fall back to
+ // that so amountless invoices aren't rejected with "Invalid amount"
+ // (issue #83). Invoice amount takes precedence when present.
+ const amountMsat = amount_msat || reqAmountMsat;
+ if (!amountMsat) {
+ return error({
+ code: "OTHER",
+ message:
+ "Amountless invoice requires an amount; specify amount (msat) in the request",
+ });
+ }
+ const amount = Math.round(amountMsat / 1000);
const { max_amount, max_fee, budget_renewal, pubkey, created } = app;
const periods = {