Skip to content

lnurlp: bind direct receives to the metadata description hash (LUD-18 payerdata) - #3221

Closed
singap2002-code wants to merge 1 commit into
stackernews:masterfrom
singap2002-code:fix/lud18-payerdata-description-hash
Closed

lnurlp: bind direct receives to the metadata description hash (LUD-18 payerdata)#3221
singap2002-code wants to merge 1 commit into
stackernews:masterfrom
singap2002-code:fix/lud18-payerdata-description-hash

Conversation

@singap2002-code

Copy link
Copy Markdown

Description

Fixes #3220.

Since ca3b05e, LN-address payments to users with proxyReceive disabled are received directly through their attached wallet via createExternalReceiveInvoice(). When the payer attaches LUD-18 payerdata, pay.js computes descriptionHash = sha256(metadata + payerdata) and passes it down the direct path with requireDescriptionHash: !!nostr — i.e. unenforced for LUD-18 requests.

Consequences:

  1. createBolt11FromWalletProtocols() only filters protocolSupportsDescriptionHash when requireDescriptionHash is true, so hash-incapable protocols (LN_ADDR, LNBITS, PHOENIXD, BLINK, CLINK) mint an invoice with a plain description memo;
  2. the post-mint hash verification is skipped as well.

The payer therefore receives an invoice whose description does not hash to what the service recorded, while LUD-06 wallets bind the invoice to the fetched metadata — a mismatch that spec-conforming wallets can reject. The proxy path doesn't have this problem because the wrapped payer-facing invoice is actually minted with the descriptionHash tag.

Fix

Bind direct receives to the plain-metadata description hash (LUD-18 payer identity is persisted separately via lud18Data), and keep the zap-request hash for NIP-57, which is already enforced via requireDescriptionHash: !!nostr:

descriptionHash: nostr ? descriptionHash : metadataDescriptionHash,
descriptionHashPreimage: nostr ? descriptionHashPreimage : metadata,

This keeps direct receives working for every protocol (no new hard requirement for hash-capable wallets) and makes the payer-facing invoice consistent with what wallets verify.

Additional Context

Checklist

  • I have read the contributing guidelines
  • I have performed a self-review of my code
  • My changes generate no new warnings/errors (syntax verified; change is confined to one branch argument in pay.js)
  • I confirm this contribution was prepared with AI assistance; all code references were verified against master (d4aaf0a) and the specs (LUD-06, LUD-18)

The metadata+payerdata description hash (LUD-18) is only enforced by the
proxy wrap. For direct receives it was passed down unenforced
(requireDescriptionHash is only set for NIP-57 requests), so hash-incapable
protocols minted invoices whose description does not hash to what the
service recorded, while LUD-06 wallets verify the invoice against the
fetched metadata.

Bind direct receives to the plain metadata hash (keeping the zap-request
hash for NIP-57) so every protocol yields an invoice consistent with what
wallets verify; payer identity is already persisted via lud18Data.

Closes stackernews#3220
@huumn huumn closed this Sep 7, 2026
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.

lnurlp direct receive with LUD-18 payerdata: payer gets a plain-metadata invoice while the service records a metadata+payerdata description hash

3 participants