Skip to content

Commit f07aa51

Browse files
feat: Add UniffiType trait for Lightning type conversions
Implement UniffiType trait to standardize conversion between native LDK types and their FFI-compatible wrappers. Enhanced uniffi_conversions module to: - Add a generic trait-based approach to type conversions - Support all wrapped Lightning types (Offer, Refund, Bolt11Invoice, Bolt12Invoice, Bolt11InvoiceDescription) - Provide consistent maybe_convert and maybe_wrap utilities for conditional compilation - Ensure correct type handling with compile-time feature flags Designed for maintainability and consistency when adding new FFI type wrappers in the future.
1 parent 8693504 commit f07aa51

File tree

5 files changed

+150
-116
lines changed

5 files changed

+150
-116
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ mod peer_store;
9595
mod sweep;
9696
mod tx_broadcaster;
9797
mod types;
98+
mod uniffi_conversions;
9899
#[cfg(feature = "uniffi")]
99100
mod uniffi_types;
100101
mod wallet;

src/payment/bolt11.rs

Lines changed: 23 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use crate::payment::store::{
2121
use crate::payment::SendingParameters;
2222
use crate::peer_store::{PeerInfo, PeerStore};
2323
use crate::types::ChannelManager;
24+
use crate::uniffi_conversions::{maybe_convert, maybe_wrap};
2425

2526
use lightning::ln::bolt11_payment;
2627
use lightning::ln::channelmanager::{
@@ -43,42 +44,11 @@ type Bolt11Invoice = LdkBolt11Invoice;
4344
#[cfg(feature = "uniffi")]
4445
type Bolt11Invoice = Arc<crate::uniffi_types::Bolt11Invoice>;
4546

46-
#[cfg(not(feature = "uniffi"))]
47-
pub(crate) fn maybe_wrap_invoice(invoice: LdkBolt11Invoice) -> Bolt11Invoice {
48-
invoice
49-
}
50-
#[cfg(feature = "uniffi")]
51-
pub(crate) fn maybe_wrap_invoice(invoice: LdkBolt11Invoice) -> Bolt11Invoice {
52-
Arc::new(invoice.into())
53-
}
54-
55-
#[cfg(not(feature = "uniffi"))]
56-
pub fn maybe_convert_invoice(invoice: &Bolt11Invoice) -> &LdkBolt11Invoice {
57-
invoice
58-
}
59-
#[cfg(feature = "uniffi")]
60-
pub fn maybe_convert_invoice(invoice: &Bolt11Invoice) -> &LdkBolt11Invoice {
61-
&invoice.inner
62-
}
63-
6447
#[cfg(not(feature = "uniffi"))]
6548
type Bolt11InvoiceDescription = LdkBolt11InvoiceDescription;
6649
#[cfg(feature = "uniffi")]
6750
type Bolt11InvoiceDescription = crate::uniffi_types::Bolt11InvoiceDescription;
6851

69-
macro_rules! maybe_convert_description {
70-
($description: expr) => {{
71-
#[cfg(not(feature = "uniffi"))]
72-
{
73-
$description
74-
}
75-
#[cfg(feature = "uniffi")]
76-
{
77-
&LdkBolt11InvoiceDescription::try_from($description)?
78-
}
79-
}};
80-
}
81-
8252
/// A payment handler allowing to create and pay [BOLT 11] invoices.
8353
///
8454
/// Should be retrieved by calling [`Node::bolt11_payment`].
@@ -124,7 +94,7 @@ impl Bolt11Payment {
12494
pub fn send(
12595
&self, invoice: &Bolt11Invoice, sending_parameters: Option<SendingParameters>,
12696
) -> Result<PaymentId, Error> {
127-
let invoice = maybe_convert_invoice(invoice);
97+
let invoice = maybe_convert(invoice);
12898
let rt_lock = self.runtime.read().unwrap();
12999
if rt_lock.is_none() {
130100
return Err(Error::NotRunning);
@@ -233,7 +203,7 @@ impl Bolt11Payment {
233203
&self, invoice: &Bolt11Invoice, amount_msat: u64,
234204
sending_parameters: Option<SendingParameters>,
235205
) -> Result<PaymentId, Error> {
236-
let invoice = maybe_convert_invoice(invoice);
206+
let invoice = maybe_convert(invoice);
237207
let rt_lock = self.runtime.read().unwrap();
238208
if rt_lock.is_none() {
239209
return Err(Error::NotRunning);
@@ -465,9 +435,9 @@ impl Bolt11Payment {
465435
pub fn receive(
466436
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
467437
) -> Result<Bolt11Invoice, Error> {
468-
let description = maybe_convert_description!(description);
469-
let invoice = self.receive_inner(Some(amount_msat), description, expiry_secs, None)?;
470-
Ok(maybe_wrap_invoice(invoice))
438+
let description = maybe_convert(description);
439+
let invoice = self.receive_inner(Some(amount_msat), &description, expiry_secs, None)?;
440+
Ok(maybe_wrap(invoice))
471441
}
472442

473443
/// Returns a payable invoice that can be used to request a payment of the amount
@@ -488,10 +458,10 @@ impl Bolt11Payment {
488458
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
489459
payment_hash: PaymentHash,
490460
) -> Result<Bolt11Invoice, Error> {
491-
let description = maybe_convert_description!(description);
461+
let description = maybe_convert(description);
492462
let invoice =
493-
self.receive_inner(Some(amount_msat), description, expiry_secs, Some(payment_hash))?;
494-
Ok(maybe_wrap_invoice(invoice))
463+
self.receive_inner(Some(amount_msat), &description, expiry_secs, Some(payment_hash))?;
464+
Ok(maybe_wrap(invoice))
495465
}
496466

497467
/// Returns a payable invoice that can be used to request and receive a payment for which the
@@ -501,9 +471,9 @@ impl Bolt11Payment {
501471
pub fn receive_variable_amount(
502472
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
503473
) -> Result<Bolt11Invoice, Error> {
504-
let description = maybe_convert_description!(description);
505-
let invoice = self.receive_inner(None, description, expiry_secs, None)?;
506-
Ok(maybe_wrap_invoice(invoice))
474+
let description = maybe_convert(description);
475+
let invoice = self.receive_inner(None, &description, expiry_secs, None)?;
476+
Ok(maybe_wrap(invoice))
507477
}
508478

509479
/// Returns a payable invoice that can be used to request a payment for the given payment hash
@@ -523,9 +493,9 @@ impl Bolt11Payment {
523493
pub fn receive_variable_amount_for_hash(
524494
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32, payment_hash: PaymentHash,
525495
) -> Result<Bolt11Invoice, Error> {
526-
let description = maybe_convert_description!(description);
527-
let invoice = self.receive_inner(None, description, expiry_secs, Some(payment_hash))?;
528-
Ok(maybe_wrap_invoice(invoice))
496+
let description = maybe_convert(description);
497+
let invoice = self.receive_inner(None, &description, expiry_secs, Some(payment_hash))?;
498+
Ok(maybe_wrap(invoice))
529499
}
530500

531501
pub(crate) fn receive_inner(
@@ -600,15 +570,15 @@ impl Bolt11Payment {
600570
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
601571
max_total_lsp_fee_limit_msat: Option<u64>,
602572
) -> Result<Bolt11Invoice, Error> {
603-
let description = maybe_convert_description!(description);
573+
let description = maybe_convert(description);
604574
let invoice = self.receive_via_jit_channel_inner(
605575
Some(amount_msat),
606-
description,
576+
&description,
607577
expiry_secs,
608578
max_total_lsp_fee_limit_msat,
609579
None,
610580
)?;
611-
Ok(maybe_wrap_invoice(invoice))
581+
Ok(maybe_wrap(invoice))
612582
}
613583

614584
/// Returns a payable invoice that can be used to request a variable amount payment (also known
@@ -626,15 +596,15 @@ impl Bolt11Payment {
626596
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
627597
max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
628598
) -> Result<Bolt11Invoice, Error> {
629-
let description = maybe_convert_description!(description);
599+
let description = maybe_convert(description);
630600
let invoice = self.receive_via_jit_channel_inner(
631601
None,
632-
description,
602+
&description,
633603
expiry_secs,
634604
None,
635605
max_proportional_lsp_fee_limit_ppm_msat,
636606
)?;
637-
Ok(maybe_wrap_invoice(invoice))
607+
Ok(maybe_wrap(invoice))
638608
}
639609

640610
fn receive_via_jit_channel_inner(
@@ -741,7 +711,7 @@ impl Bolt11Payment {
741711
/// amount times [`Config::probing_liquidity_limit_multiplier`] won't be used to send
742712
/// pre-flight probes.
743713
pub fn send_probes(&self, invoice: &Bolt11Invoice) -> Result<(), Error> {
744-
let invoice = maybe_convert_invoice(invoice);
714+
let invoice = maybe_convert(invoice);
745715
let rt_lock = self.runtime.read().unwrap();
746716
if rt_lock.is_none() {
747717
return Err(Error::NotRunning);
@@ -774,7 +744,7 @@ impl Bolt11Payment {
774744
pub fn send_probes_using_amount(
775745
&self, invoice: &Bolt11Invoice, amount_msat: u64,
776746
) -> Result<(), Error> {
777-
let invoice = maybe_convert_invoice(invoice);
747+
let invoice = maybe_convert(invoice);
778748
let rt_lock = self.runtime.read().unwrap();
779749
if rt_lock.is_none() {
780750
return Err(Error::NotRunning);

src/payment/bolt12.rs

Lines changed: 11 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@ use crate::payment::store::{
1616
PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus, PaymentStore,
1717
};
1818
use crate::types::ChannelManager;
19+
use crate::uniffi_conversions::{maybe_convert, maybe_wrap};
1920

2021
use lightning::ln::channelmanager::{PaymentId, Retry};
21-
use lightning::offers::invoice::Bolt12Invoice as LdkBolt12Invoice;
2222
use lightning::offers::offer::{Amount, Offer as LdkOffer, Quantity};
2323
use lightning::offers::parse::Bolt12SemanticError;
24-
use lightning::offers::refund::Refund as LdkRefund;
2524
use lightning::util::string::UntrustedString;
2625

2726
use rand::RngCore;
@@ -31,65 +30,20 @@ use std::sync::{Arc, RwLock};
3130
use std::time::{Duration, SystemTime, UNIX_EPOCH};
3231

3332
#[cfg(not(feature = "uniffi"))]
34-
type Bolt12Invoice = LdkBolt12Invoice;
33+
type Bolt12Invoice = lightning::offers::invoice::Bolt12Invoice;
3534
#[cfg(feature = "uniffi")]
3635
type Bolt12Invoice = Arc<crate::uniffi_types::Bolt12Invoice>;
3736

38-
#[cfg(not(feature = "uniffi"))]
39-
fn maybe_wrap_bolt12_invoice(invoice: LdkBolt12Invoice) -> Bolt12Invoice {
40-
invoice
41-
}
42-
#[cfg(feature = "uniffi")]
43-
fn maybe_wrap_bolt12_invoice(invoice: LdkBolt12Invoice) -> Bolt12Invoice {
44-
Arc::new(invoice.into())
45-
}
46-
4737
#[cfg(not(feature = "uniffi"))]
4838
type Offer = LdkOffer;
4939
#[cfg(feature = "uniffi")]
5040
type Offer = Arc<crate::uniffi_types::Offer>;
5141

5242
#[cfg(not(feature = "uniffi"))]
53-
pub fn maybe_convert_offer(offer: &Offer) -> &LdkOffer {
54-
offer
55-
}
56-
#[cfg(feature = "uniffi")]
57-
pub fn maybe_convert_offer(offer: &Offer) -> &LdkOffer {
58-
&offer.inner
59-
}
60-
61-
#[cfg(not(feature = "uniffi"))]
62-
pub fn maybe_wrap_offer(offer: LdkOffer) -> Offer {
63-
offer
64-
}
65-
#[cfg(feature = "uniffi")]
66-
pub fn maybe_wrap_offer(offer: LdkOffer) -> Offer {
67-
Arc::new(offer.into())
68-
}
69-
70-
#[cfg(not(feature = "uniffi"))]
71-
type Refund = LdkRefund;
43+
type Refund = lightning::offers::refund::Refund;
7244
#[cfg(feature = "uniffi")]
7345
type Refund = Arc<crate::uniffi_types::Refund>;
7446

75-
#[cfg(not(feature = "uniffi"))]
76-
pub fn maybe_convert_refund(refund: &Refund) -> &LdkRefund {
77-
refund
78-
}
79-
#[cfg(feature = "uniffi")]
80-
pub fn maybe_convert_refund(refund: &Refund) -> &LdkRefund {
81-
&refund.inner
82-
}
83-
84-
#[cfg(not(feature = "uniffi"))]
85-
pub fn maybe_wrap_refund(refund: Refund) -> LdkRefund {
86-
refund
87-
}
88-
#[cfg(feature = "uniffi")]
89-
pub fn maybe_wrap_refund(refund: LdkRefund) -> Refund {
90-
Arc::new(refund.into())
91-
}
92-
9347
/// A payment handler allowing to create and pay [BOLT 12] offers and refunds.
9448
///
9549
/// Should be retrieved by calling [`Node::bolt12_payment`].
@@ -121,7 +75,7 @@ impl Bolt12Payment {
12175
pub fn send(
12276
&self, offer: &Offer, quantity: Option<u64>, payer_note: Option<String>,
12377
) -> Result<PaymentId, Error> {
124-
let offer = maybe_convert_offer(offer);
78+
let offer = maybe_convert(offer);
12579
let rt_lock = self.runtime.read().unwrap();
12680
if rt_lock.is_none() {
12781
return Err(Error::NotRunning);
@@ -223,7 +177,7 @@ impl Bolt12Payment {
223177
pub fn send_using_amount(
224178
&self, offer: &Offer, amount_msat: u64, quantity: Option<u64>, payer_note: Option<String>,
225179
) -> Result<PaymentId, Error> {
226-
let offer = maybe_convert_offer(offer);
180+
let offer = maybe_convert(offer);
227181
let rt_lock = self.runtime.read().unwrap();
228182
if rt_lock.is_none() {
229183
return Err(Error::NotRunning);
@@ -359,7 +313,7 @@ impl Bolt12Payment {
359313
&self, amount_msat: u64, description: &str, expiry_secs: Option<u32>, quantity: Option<u64>,
360314
) -> Result<Offer, Error> {
361315
let offer = self.receive_inner(amount_msat, description, expiry_secs, quantity)?;
362-
Ok(maybe_wrap_offer(offer))
316+
Ok(maybe_wrap(offer))
363317
}
364318

365319
/// Returns a payable offer that can be used to request and receive a payment for which the
@@ -383,7 +337,7 @@ impl Bolt12Payment {
383337
Error::OfferCreationFailed
384338
})?;
385339

386-
Ok(maybe_wrap_offer(offer))
340+
Ok(maybe_wrap(offer))
387341
}
388342

389343
/// Requests a refund payment for the given [`Refund`].
@@ -394,8 +348,8 @@ impl Bolt12Payment {
394348
/// [`Refund`]: lightning::offers::refund::Refund
395349
/// [`Bolt12Invoice`]: lightning::offers::invoice::Bolt12Invoice
396350
pub fn request_refund_payment(&self, refund: &Refund) -> Result<Bolt12Invoice, Error> {
397-
let refund = maybe_convert_refund(refund);
398-
let invoice = self.channel_manager.request_refund_payment(refund).map_err(|e| {
351+
let refund = maybe_convert(refund);
352+
let invoice = self.channel_manager.request_refund_payment(&refund).map_err(|e| {
399353
log_error!(self.logger, "Failed to request refund payment: {:?}", e);
400354
Error::InvoiceRequestCreationFailed
401355
})?;
@@ -422,7 +376,7 @@ impl Bolt12Payment {
422376

423377
self.payment_store.insert(payment)?;
424378

425-
Ok(maybe_wrap_bolt12_invoice(invoice))
379+
Ok(maybe_wrap(invoice))
426380
}
427381

428382
/// Returns a [`Refund`] object that can be used to offer a refund payment of the amount given.
@@ -489,6 +443,6 @@ impl Bolt12Payment {
489443

490444
self.payment_store.insert(payment)?;
491445

492-
Ok(maybe_wrap_refund(refund))
446+
Ok(maybe_wrap(refund))
493447
}
494448
}

src/payment/unified_qr.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,8 @@
1313
//! [BOLT 12]: https://github.com/lightning/bolts/blob/master/12-offer-encoding.md
1414
use crate::error::Error;
1515
use crate::logger::{log_error, LdkLogger, Logger};
16-
use crate::payment::{
17-
bolt11::maybe_wrap_invoice, bolt12::maybe_wrap_offer, Bolt11Payment, Bolt12Payment,
18-
OnchainPayment,
19-
};
16+
use crate::payment::{Bolt11Payment, Bolt12Payment, OnchainPayment};
17+
use crate::uniffi_conversions::maybe_wrap;
2018
use crate::Config;
2119

2220
use lightning::ln::channelmanager::PaymentId;
@@ -145,15 +143,15 @@ impl UnifiedQrPayment {
145143
uri.clone().require_network(self.config.network).map_err(|_| Error::InvalidNetwork)?;
146144

147145
if let Some(offer) = uri_network_checked.extras.bolt12_offer {
148-
let offer = maybe_wrap_offer(offer);
146+
let offer = maybe_wrap(offer);
149147
match self.bolt12_payment.send(&offer, None, None) {
150148
Ok(payment_id) => return Ok(QrPaymentResult::Bolt12 { payment_id }),
151149
Err(e) => log_error!(self.logger, "Failed to send BOLT12 offer: {:?}. This is part of a unified QR code payment. Falling back to the BOLT11 invoice.", e),
152150
}
153151
}
154152

155153
if let Some(invoice) = uri_network_checked.extras.bolt11_invoice {
156-
let invoice = maybe_wrap_invoice(invoice);
154+
let invoice = maybe_wrap(invoice);
157155
match self.bolt11_invoice.send(&invoice, None) {
158156
Ok(payment_id) => return Ok(QrPaymentResult::Bolt11 { payment_id }),
159157
Err(e) => log_error!(self.logger, "Failed to send BOLT11 invoice: {:?}. This is part of a unified QR code payment. Falling back to the on-chain transaction.", e),

0 commit comments

Comments
 (0)