Skip to content

Decode BOLT12 invoices in the DecodeInvoice API#215

Open
vincenzopalazzo wants to merge 2 commits into
lightningdevkit:mainfrom
vincenzopalazzo:claude/stupefied-mendeleev-50a203
Open

Decode BOLT12 invoices in the DecodeInvoice API#215
vincenzopalazzo wants to merge 2 commits into
lightningdevkit:mainfrom
vincenzopalazzo:claude/stupefied-mendeleev-50a203

Conversation

@vincenzopalazzo
Copy link
Copy Markdown
Contributor

Summary

  • DecodeInvoice now also decodes a hex-encoded BOLT12 invoice, not just a BOLT11 invoice string.
  • DecodeInvoiceResponse gains a kind field ("bolt11" or "bolt12") identifying which invoice type was decoded.
  • A BOLT12 invoice has no human-readable string form (it is exchanged as raw bytes over onion messages), so the input is expected to be hex-encoded and is parsed via LDK's Bolt12Invoice::try_from. Per the intentionally minimal scope, only kind is populated for a BOLT12 invoice; the remaining fields continue to apply to BOLT11 invoices.
  • CLI / MCP / client docs updated to reflect the broadened input.

Test plan

  • cargo test — new unit tests in decode_invoice.rs cover the BOLT12 invoice round-trip and rejection of unparseable / non-invoice input
  • e2e test_cli_decode_invoice and test_mcp_live_tool_calls assert kind == "bolt11"
  • cargo check --all-features --all-targets, cargo fmt --all, clippy clean for the changed code
  • Protobuf regenerated via RUSTFLAGS="--cfg genproto" cargo build -p ldk-server-grpc

AI tools: implemented with Claude Code (Claude Opus 4.7).

@ldk-reviews-bot
Copy link
Copy Markdown

ldk-reviews-bot commented May 20, 2026

I've assigned @benthecarman as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@benthecarman
Copy link
Copy Markdown
Collaborator

Do we even have a way to get a bolt 12 invoice?

@vincenzopalazzo
Copy link
Copy Markdown
Contributor Author

Do we even have a way to get a bolt 12 invoice?

Ah good point, and yes and no! With the new version of ldk-node we can perform a proof of payment (first version of it) with lightningdevkit/ldk-node#733 but people may want to use ldk to decode an bolt12 invoice that they are getting from somewhere else

Comment thread ldk-server/src/api/decode_invoice.rs Outdated
The `DecodeInvoice` RPC previously accepted only a BOLT11 invoice
string. It now also accepts a hex-encoded BOLT12 invoice, and the
response carries a new `kind` field ("bolt11" or "bolt12") identifying
which was decoded.

Unlike offers and BOLT11 invoices, a BOLT12 invoice has no
human-readable string encoding -- it is exchanged as raw bytes over
onion messages -- so the input is expected to be hex-encoded, and LDK's
`Bolt12Invoice` is parsed via `TryFrom<Vec<u8>>` accordingly.

For a decoded BOLT12 invoice the fields that map onto
`DecodeInvoiceResponse` are populated: `destination` (signing pubkey),
`payment_hash`, `amount_msat`, `timestamp` (`created_at`), `expiry`
(`relative_expiry`), `description`, `fallback_address`, `features`, and
`is_expired`. BOLT11-only fields (`payment_secret`, `route_hints`,
`currency`, ...) are left empty.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vincenzopalazzo vincenzopalazzo force-pushed the claude/stupefied-mendeleev-50a203 branch from 86d444d to bcdb005 Compare May 21, 2026 09:07
Comment thread ldk-server/src/api/decode_invoice.rs
`DecodeInvoiceResponse` previously dropped the blinded payment paths of
a decoded BOLT12 invoice. It now carries them in a new `paths` field,
mirroring the `paths` already exposed for decoded BOLT12 offers. BOLT11
invoices leave the field empty, as they carry route hints instead.

The blinded-path-to-proto conversion is extracted from `decode_offer`
into a shared `blinded_path_to_proto` helper, so offer decoding (blinded
message paths) and invoice decoding (blinded payment paths) build the
same `BlindedPath` representation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pub is_expired: bool,
/// The kind of decoded invoice: "bolt11" or "bolt12".
#[prost(string, tag = "16")]
pub kind: ::prost::alloc::string::String,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this a proper enum

Comment thread e2e-tests/tests/e2e.rs
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a e2e test

Comment thread e2e-tests/tests/mcp.rs
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a mcp test

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.

3 participants