-
Notifications
You must be signed in to change notification settings - Fork 116
[RFC] event: expose BOLT12 invoice in PaymentSuccessful for proof of payment #733
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[RFC] event: expose BOLT12 invoice in PaymentSuccessful for proof of payment #733
Conversation
This patch adds the `bolt12_invoice` field to the `PaymentSuccessful` event, enabling users to obtain proof of payment for BOLT12 transactions. Problem: Previously, after a successful BOLT12 payment, users had no way to access the paid invoice data. This made it impossible to provide proof of payment to third parties, who need both the payment preimage and the original invoice to verify that sha256(preimage) matches the invoice's payment_hash. Solution: Add a `bolt12_invoice: Option<Vec<u8>>` field to `PaymentSuccessful` that contains the serialized BOLT12 invoice bytes. The invoice is serialized using LDK's standard encoding, which can be parsed back using `Bolt12Invoice::try_from(bytes)` in native Rust, or by hex-encoding the bytes and using `Bolt12Invoice.from_str()` in FFI bindings. Design decisions: - Store as `Vec<u8>` rather than the complex `PaidBolt12Invoice` type to avoid UniFFI limitations with objects in enum variants - Return `None` for `StaticInvoice` (async payments) since proof of payment is not possible for those payment types anyway - Use TLV tag 7 for serialization, maintaining backward compatibility with existing persisted events This implementation follows the maintainer guidance from PR lightningdevkit#563 to expose the invoice via the event rather than storing it in the payment store. Signed-off-by: Vincenzo Palazzo <[email protected]>
|
I've assigned @tnull as a reviewer! |
|
@tnull IDK if this is a good design to have with the ffi, but I had to work around some unify ffi limitation with the enum type that is used inside the |
|
🔔 1st Reminder Hey @tnull! This PR has been waiting for your review. |
|
🔔 2nd Reminder Hey @tnull! This PR has been waiting for your review. |
|
🔔 3rd Reminder Hey @tnull! This PR has been waiting for your review. |
tnull
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exposing the BOLT12 invoice makes sense to me, though we should do it properly instead of just exposing the bytes.
src/event.rs
Outdated
| /// | ||
| /// To parse the invoice in native Rust, use `Bolt12Invoice::try_from(bytes)`. | ||
| /// In FFI bindings, hex-encode the bytes and use `Bolt12Invoice.from_str(hex_string)`. | ||
| bolt12_invoice: Option<Vec<u8>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should expose the raw bytes here, although I have to say that I also find the PaidBolt12Invoice type pretty awkward tbh. But I guess we'll have to bite that bullet now.
Note that we'll probably need to add our own version of PaidBolt12Invoice though as Uniffi doesn't support tuple enum variants, so we'll need to add a local version with named enum variants, and then add an impl From<LdkPaidBolt12Invoice> for PaidBolt12Invoice, as well as expose the StaticInvoice APIs in the ffi/types.rs/UDL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about the commit 4c6b18e
This patch refactors the BOLT12 invoice exposure in PaymentSuccessful to use properly typed wrappers instead of raw Vec<u8> bytes. Problem: The previous implementation exposed the BOLT12 invoice as Option<Vec<u8>> which required users to manually deserialize the bytes and didn't provide a good API experience. Additionally, UniFFI bindings need proper type wrappers to generate idiomatic foreign language bindings. Solution: - Add StaticInvoice wrapper type with accessor methods (offer_id, is_offer_expired, signing_pubkey, etc.) - Create PaidBolt12Invoice as a struct with a discriminant enum (PaidBolt12InvoiceKind) and optional fields for bolt12_invoice and static_invoice - Implement From<LdkPaidBolt12Invoice> for automatic conversion - Add Writeable/Readable implementations for serialization - Update UDL bindings with StaticInvoice interface and PaidBolt12Invoice dictionary Design decisions: - PaidBolt12Invoice is a struct (dictionary) rather than an enum because UniFFI does not support objects in enum variant data. The workaround uses a discriminant enum (PaidBolt12InvoiceKind) with optional object fields, which is the recommended pattern per UniFFI documentation. - Both uniffi and non-uniffi builds share the same API through conditional compilation in types.rs, ensuring consistent behavior across all build configurations. Signed-off-by: Vincenzo Palazzo <[email protected]>
4c6b18e to
a3a60b3
Compare
This patch adds the
bolt12_invoicefield to thePaymentSuccessfulevent, enabling users to obtain proof of payment for BOLT12 transactions.Problem:
Previously, after a successful BOLT12 payment, users had no way to access the paid invoice data. This made it impossible to provide proof of payment to third parties, who need both the payment preimage and the original invoice to verify that sha256(preimage) matches the invoice's payment_hash.
Solution:
Add a
bolt12_invoice: Option<Vec<u8>>field toPaymentSuccessfulthat contains the serialized BOLT12 invoice bytes. The invoice is serialized using LDK's standard encoding, which can be parsed back usingBolt12Invoice::try_from(bytes)in native Rust, or by hex-encoding the bytes and usingBolt12Invoice.from_str()in FFI bindings.Design decisions:
Vec<u8>rather than the complexPaidBolt12Invoicetype to avoid UniFFI limitations with objects in enum variantsNoneforStaticInvoice(async payments) since proof of payment is not possible for those payment types anywayThis implementation follows the maintainer guidance from PR #563 to expose the invoice via the event rather than storing it in the payment store.