Support HODL Invoices - #2
Merged
Merged
Conversation
Reordered settle/cancel to avoid deleting claimables before we know the LDK action succeeded. In invoice_settle, call claim_funds first and return an error if LDK rejects it; only then best-effort remove the claimable entry. In invoice_cancel, fetch the claimable without removing it, attempt fail_htlc_backwards, return an error if that fails, and only then clean up the claimable. This prevents losing the ability to retry/cancel when LDK rejects the call.
Add mark_claimable_settling() to atomically mark claimable HTLCs as "settling" before calling claim_funds(), preventing the background expiry task from racing to fail_htlc_backwards on the same payment hash.
settle_twice_succeeds: if the invoice is already settled, settling will succeed; cancel_then_settle_fails: cancel first, settle must fail; settle_then_cancel_fails: settle first, cancel must fail; expire_hodl_invoice: short-expiry path; settle/cancel fail after expiry; expire_hodl_invoice_by_blocks: block-driven expiry; settle/cancel fail after; reject_wrong_preimage_settle: good preimage still suceeds.
Make invoice_settle() idempotent by first checking whether the payment has already succeeded before marking the claimable as settling. This enables safe retries after the claimable entry has been cleaned up by the PaymentClaimed event.
Apply formatting and modify gh action to apply formatting in all push/pr
Trying to settle with wrong hash is caught even in the fast path.
Test settle_twice_succeeds now waits for the second settle to be observed as Succeeded. New settle_twice_wrong_preimage_fails: second settle with a wrong preimage returns InvalidPaymentPreimage and invoice remains Succeeded. New settle_after_expiry_idempotent_succeeds: settle once, wait past invoice expiry, settle again; expects idempotent success.
- make hodl persistence crash‑safe - prevent invoice cancellation during settlement
…ter-settle return idempotent 409 - Gate /invoice/settle on inbound status (Failed/Cancelled) and clarify docstring about the no-op claim_funds case when an inbound failure isn't observed. - Add an idempotent /invoice/cancel path that returns InvoiceAlreadySettled (409) when canceling a settled HODL invoice.
borismaxi
reviewed
Jan 13, 2026
Comment on lines
+2688
to
+2696
| /// Settle a HODL invoice that currently has a held HTLC. Requires the invoice | ||
| /// `payment_hash` and the matching 32-byte `payment_preimage`. Fails if the | ||
| /// invoice is not HODL, there is no claimable HTLC (already cancelled, expired, | ||
| /// or failed), or the preimage doesn't match. If the invoice is already settled, | ||
| /// this call succeeds (idempotent). | ||
| /// | ||
| /// Note: if the sender fails the HTLC and we | ||
| /// don't receive an inbound failure signal, the claimable entry may still exist; | ||
| /// in that case `claim_funds` is a no-op and this endpoint still returns 200. |
There was a problem hiding this comment.
I think we should add the following note to invoice_settle API:
/invoice/settle only hands the preimage to LDK and does not guarantee
settlement of the invoice even if the call succeeds. The canonical source
for whether the payment actually settled is /invoice/status. Call POST
/invoice/status with the original BOLT11 invoice, and poll until it reports
Succeeded (or Failed/Cancelled/Expired).
A HODL invoice can be settled only if its HTLCStatus is Claimable.
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds support for HODL invoices to the RGB Lightning Node.
The main functional addition is the ability to create and manage HODL invoices, requiring updates across the API, core logic, error handling, persistence layer, and a new test suite. Incoming HTLCs are held and only settled or cancelled explicitly.
/invoice/hodl,/invoice/settle, and/invoice/cancel.Minor adjustments to workflows and documentation ensure the new feature is well integrated into the development process and clearly documented. More diagrams are WIP to support advanced flows such as submarine swaps.
src/routes.rsadded new routes to create HODL invoices, settle or cancel them. It includes request validation and JSON responses that comply with the updated OpenAPI spec. Wired the new routes intosrc/main.rs.src/ldk.rsupgraded how relevant events are processed. This includes new handlers for holding and settling payments, and updates to invoice retrieval and status checks.src/test/hodl_invoice.rsis a comprehensive test suite verifying HODL invoice creation, payment flows, and settlement/cancellation scenarios.