CLN-backed Lightning Addresses cannot create invoices with description_hash
- Dominant language
- TypeScript
- Stars
- 280
- Forks
- 132
- Avg merge
- 4d 15h
- Merged PRs (30d)
- 11
Description
## Bug description
A Lightning Address backed by an Alby Hub using the Core Lightning (CLN) backend cannot create its LNURL-pay invoice through NWC `make_invoice` when a `description_hash` is supplied.
The same Lightning Address flow works with Alby Hubs using the LDK backend.
## Observed behavior
With a payer comment, Hub received this `make_invoice` input:
```json
{
"amount": 1000,
"description": "Testing send",
"description_hash": "f6900ce8976c5dba9152caad6b154c7699593cec419d919727a4feb6b06f6c97",
"expiry": 86400
}
```
Hub rejected the request:
```text
description_hash does not match description
```
This validation result is correct for those values: SHA-256 of the exact string `Testing send` is:
```text
2e677e390d30a2e11496315f9d03b8ddcba72cc3e99a5bbe30bddd8076a8e495
```
Leaving out the payer comment/description does not fix the payment. In that case, the Lightning Address flow supplies the LNURL metadata hash without a description, while the CLN backend rejects any hash-only request:
```go
if descriptionHash != "" {
if description == "" {
return nil, fmt.Errorf("Must have description when using description_hash")
}
// ...
}
```
## Root cause
NIP-47 allows `make_invoice` to contain an optional `description_hash` without a `description`. The LDK backend supports this by constructing a `Bolt11InvoiceDescriptionHash` directly.
Core Lightning's `invoice` RPC works differently: `deschashonly=true` hashes the supplied description itself. It therefore needs the original description preimage and cannot create the LNURL invoice from an arbitrary hash alone.
This produces two failing CLN paths:
1. **No payer comment:** `description` is empty and `description_hash` contains the LNURL metadata hash. Hub rejects the hash-only request.
2. **With payer comment:** the payer comment is passed as `description`, while `description_hash` still commits to the LNURL metadata. Hub hashes the comment, detects a mismatch, and rejects the request.
The payer comment must not replace the LNURL metadata commitment. The resulting BOLT11 invoice must contain `h = SHA256(exact LNURL metadata JSON)`.
## Expected behavior
Lightning Address payments to a CLN-backed Alby Hub should work both with and without a payer comment, consistently with the LDK backend.
## Suggested direction
The CLN invoice path needs access to the exact LNURL metadata string used as the description-hash preimage. For example, the Lightning Address/NWC integration could provide that preimage separately (or use an agreed request/metadata field), and Hub could pass it to CLN as `description` with `deschashonly=true`.
The payer comment should remain separate transaction metadata, such as `metadata.comment`.
Any cross-backend change should ensure LDK/LND/Phoenixd continue producing a hashed-description invoice when both a hash and its preimage are available.
## Acceptance criteria
- A CLN-backed Hub can receive through its Lightning Address without a payer comment.
- A CLN-backed Hub can receive through its Lightning Address with a payer comment.
- The returned BOLT11 invoice's `description_hash` equals SHA-256 of the exact LNURL metadata from the initial pay response.
- The payer comment does not replace or alter the LNURL metadata commitment.
- Regression coverage includes both CLN cases and verifies behavior remains correct for the other Hub backends.
Reported by @MoritzKa from support logs.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at the CLN invoice path handling NWC make_invoice and the Lightning Address/NWC integration. Trace how description and description_hash reach Core Lightning, then compare the LDK path and its handling of the preimage. Done means both payer-comment cases produce invoices whose description_hash commits to the exact LNURL metadata, with regression coverage for CLN and other backends.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, typescript
- Domain
- api, backend, payments
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100