Skip to content

Feature: Add Bolt12 Uniffi Type Wrappers #542

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

Merged
merged 4 commits into from
Jun 10, 2025

Conversation

alexanderwiederin
Copy link
Contributor

@alexanderwiederin alexanderwiederin commented May 19, 2025

Second PR for #504.

This PR adds full Offer-, Refund- and Bolt12Invoice- types for the FFI bindings.

Changes:

  • Type definitions in ldk_node.udl and uniffi_types.rs
  • Implementation of UniffiType trait to standardize conversions between LDK types and their FFI-compatible wrappers in uniffi_conversions.rs
  • Integration of wrapper types in payment handling methods in bolt12.rs and unified_qr.rs

Benefits:

  • Direct access to Offer, Refund and Bolt12Invoice properties from FFI languages
  • Consistent API across languages

Note:

Appreciate that this PR is big. Happy to break down into smaller parts if preferred.

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented May 19, 2025

👋 Thanks for assigning @enigbe 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.

@alexanderwiederin alexanderwiederin marked this pull request as ready for review May 20, 2025 21:21
@tnull tnull requested review from tnull and removed request for valentinewallace May 22, 2025 15:13
Copy link
Collaborator

@tnull tnull left a comment

Choose a reason for hiding this comment

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

Thanks, already looks pretty good! Did a first higher-level pass.

Copy link
Collaborator

@tnull tnull left a comment

Choose a reason for hiding this comment

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

Cool, I like the proposed approach. Very clean!

Just a few comments.

@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @enigbe! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 2nd Reminder

Hey @enigbe! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 3rd Reminder

Hey @enigbe! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@alexanderwiederin alexanderwiederin force-pushed the uniffi-bolt12-clean branch 4 times, most recently from 4a4572a to 1ebcb89 Compare June 9, 2025 13:21
Copy link
Contributor

@enigbe enigbe left a comment

Choose a reason for hiding this comment

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

Well done @alexanderwiederin,

I've reviewed this and just have a small question regarding fixed-sized arrays. The ffi/conversion approach looked good to me, but following your conversation with @tnull has highlighted some gaps in my understanding of Uniffi's internals especially with regards to heap allocation. I'll be looking into that further.

I've also tested this and it LGTM.

Comment on lines +118 to +122
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OfferAmount {
Bitcoin { amount_msats: u64 },
Currency { iso4217_code: String, amount: u64 },
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious about why LdkAmount is not used directly here. OfferAmount is basically the same struct except for the iso4217_code field. Is this because there is no support for fixed-sized arrays?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yea, that's pretty much it. OfferAmount provides a binding-friendly representation by using String instead of a fixed-size byte array for iso4217_code. I also don't think you can automatically convert complex types across FFI language boundaries in general.

}

#[cfg(feature = "uniffi")]
pub fn maybe_wrap<T>(ldk_type: impl Into<T>) -> std::sync::Arc<T> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is ldk_type impl Into<T> and not just T?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question! T is not actually the type that is passed to maybe_wrap. impl Into<T> means that the argument we pass to maybe_wrap can be any type that implements Into<T> to convert itself into T. In our case T would be the UniFFI type that is needed at the call site.

For example, we pass LDK native types (like lightning_invoice::Bolt11Invoice), which gets converted to their corresponding UniFFI wrapper type (like ffi::types::Bolt11Invoice) using .into() before being wrapped in an Arc.

Copy link
Collaborator

@tnull tnull left a comment

Choose a reason for hiding this comment

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

LGTM I think, mod one nit.

Let me know if you intend to make further changes or if this can land from your side.

This commit reorganizes the FFI architecture by introducing conversion
traits for lightning types. Moves code from uniffi_types.rs to a
dedicated ffi module for separation of concerns.
@alexanderwiederin
Copy link
Contributor Author

Thanks for the feedback @tnull. This can land from my side!

Implement Offer struct in ffi/types.rs to provide a wrapper around LDK's Offer for cross-language bindings.

Modified payment handling in bolt12.rs to:
- Support both native and FFI-compatible types via type aliasing
- Implement conditional compilation for transparent FFI support
- Update payment functions to handle wrapped types

Added testing to verify that properties are preserved when wrapping/unwrapping between native and FFI types.
Implement Refund struct in ffi/types.rs to provide a wrapper around LDK's Refund for cross-language bindings.

Modified payment handling in bolt12.rs to:
- Support both native and FFI-compatible types via type aliasing
- Implement conditional compilation for transparent FFI support
- Update payment functions to handle wrapped types

Added testing to verify that properties are preserved when wrapping/unwrapping between native and FFI types.
Implement Bolt12Invoice struct in ffi/types.rs to provide a wrapper around LDK's Bolt12Invoice for cross-language bindings.

Modified payment handling in bolt12.rs to:
- Support both native and FFI-compatible types via type aliasing
- Implement conditional compilation for transparent FFI support
- Update payment functions to handle wrapped types

Added testing to verify that properties are preserved when wrapping/unwrapping between native and FFI types.
Copy link
Collaborator

@tnull tnull left a comment

Choose a reason for hiding this comment

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

LGTM

@tnull tnull merged commit 40a3aeb into lightningdevkit:main Jun 10, 2025
14 of 15 checks passed
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.

5 participants