Skip to content

lnaddress: commit invoices to the LNURL metadata - #16

Open
nGoline wants to merge 2 commits into
mainfrom
fix/lnurl-metadata
Open

nGoline wants to merge 2 commits into
mainfrom
fix/lnurl-metadata

Conversation

@nGoline

@nGoline nGoline commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Fixes the protocol bugs found while deploying v0.1.0 against Core Lightning.

1. Invoices didn't commit to the metadata (LUD-06, high)

LUD-06 requires the invoice's h tag to equal sha256(utf8(metadata)), where metadata is the exact string served at /.well-known/lnurlp/<username>. v0.1.0 put payment for <username> (or the comment) in the plain description, so strict wallets (Zeus, Phoenix, Breez) rejected the invoices.

  • New Helpers/LnUrlMetadata builds the metadata once. The well-known response and the callback both use it.
  • CLN: Description = metadata, Deschashonly = true.
  • LND: DescriptionHash = sha256(metadata), no Memo.
  • The LUD-12 comment no longer goes in the description, which would break the hash. CLN keeps it in the invoice label (lnaddress-<user>-<id>: <comment>), so it shows in RTL; LND drops it.

2. LUD-16 metadata (medium)

  • Metadata now includes ["text/identifier","<user>@<domain>"] (domain lowercased, port stripped) and is serialized with System.Text.Json instead of string interpolation.
  • Usernames must match the LUD-16 charset [a-z0-9-_.], case-insensitive and served lowercase. Anything else returns 404 {"status":"ERROR","reason":"Not found"} from both well-known and callback, without calling the node.

3. Verify only covers LnAddress invoices on CLN

/lnurl/verify/<hash> now returns Not found for CLN invoices whose label doesn't start with lnaddress-, so invoices created by RTL, Zeus and other apps aren't exposed. LND has no label to check; the README now limits the "use a dedicated node" warning to LND.

Tests

  • Unit (41, was 16): metadata shape, username charset (including quote/backslash injection and Unicode case-folding tricks), well-known identifier, and a test that the metadata served by .well-known is exactly what the callback passes to the backend (with mixed-case host and port).
  • CLN integration (8/8, on v26.06.9): CLN's own lightning-cli decode reports description_hash == sha256(metadata); the comment lands in the label and leaves the hash unchanged; a foreign invoice created on the node returns null from lookup.
  • LND integration (6/6): LND's DecodePayReq reports description_hash == sha256(metadata), with and without a comment.
  • The CLN test image is bumped from v26.06.8 to v26.06.9 to match production. node.proto is byte-identical between the two.

Behavior changes for deployments

  • Invoice descriptions are now a hash, so wallets show the metadata text (Paying user@domain) instead of payment for user.
  • Comments: on CLN they're in the invoice label; on LND they're gone.
  • Usernames outside [a-z0-9-_.] now get 404; mixed case is lowercased.
  • No changes to env vars, port or /health.

Merges cleanly with #13, #14 and #15.

🤖 Generated with Claude Code

nGoline and others added 2 commits October 22, 2026 10:13
The cln-grpc node.proto is unchanged between v26.06.8 and v26.06.9.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LUD-06 requires the invoice's description hash to equal sha256 of the
metadata served at /.well-known/lnurlp. Invoices carried a plain
description instead, so wallets that check it (Zeus, Phoenix, Breez)
rejected them.

Build the metadata in one place and use it for both the well-known
response and the invoice: CLN gets it as the description with
deschashonly, LND as the description hash. The LUD-12 comment no longer
goes in the description; CLN keeps it in the invoice label and LND
drops it.

The metadata now includes the LUD-16 text/identifier entry and is
serialized as JSON instead of interpolated. Usernames outside the LUD-16
charset return 404 and the rest are lowercased.

On CLN, verify only answers for invoices labeled lnaddress-, so it no
longer exposes other invoices on the node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant