Skip to content

Commit 7188bca

Browse files
refactor: 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 f31d768 commit 7188bca

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
@@ -96,6 +96,7 @@ mod peer_store;
9696
mod sweep;
9797
mod tx_broadcaster;
9898
mod types;
99+
mod uniffi_conversions;
99100
#[cfg(feature = "uniffi")]
100101
mod uniffi_types;
101102
mod wallet;

src/payment/bolt11.rs

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

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

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

70-
macro_rules! maybe_convert_description {
71-
($description: expr) => {{
72-
#[cfg(not(feature = "uniffi"))]
73-
{
74-
$description
75-
}
76-
#[cfg(feature = "uniffi")]
77-
{
78-
&LdkBolt11InvoiceDescription::try_from($description)?
79-
}
80-
}};
81-
}
82-
8353
/// A payment handler allowing to create and pay [BOLT 11] invoices.
8454
///
8555
/// Should be retrieved by calling [`Node::bolt11_payment`].
@@ -125,7 +95,7 @@ impl Bolt11Payment {
12595
pub fn send(
12696
&self, invoice: &Bolt11Invoice, sending_parameters: Option<SendingParameters>,
12797
) -> Result<PaymentId, Error> {
128-
let invoice = maybe_convert_invoice(invoice);
98+
let invoice = maybe_convert(invoice);
12999
let rt_lock = self.runtime.read().unwrap();
130100
if rt_lock.is_none() {
131101
return Err(Error::NotRunning);
@@ -234,7 +204,7 @@ impl Bolt11Payment {
234204
&self, invoice: &Bolt11Invoice, amount_msat: u64,
235205
sending_parameters: Option<SendingParameters>,
236206
) -> Result<PaymentId, Error> {
237-
let invoice = maybe_convert_invoice(invoice);
207+
let invoice = maybe_convert(invoice);
238208
let rt_lock = self.runtime.read().unwrap();
239209
if rt_lock.is_none() {
240210
return Err(Error::NotRunning);
@@ -466,9 +436,9 @@ impl Bolt11Payment {
466436
pub fn receive(
467437
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
468438
) -> Result<Bolt11Invoice, Error> {
469-
let description = maybe_convert_description!(description);
470-
let invoice = self.receive_inner(Some(amount_msat), description, expiry_secs, None)?;
471-
Ok(maybe_wrap_invoice(invoice))
439+
let description = maybe_convert(description);
440+
let invoice = self.receive_inner(Some(amount_msat), &description, expiry_secs, None)?;
441+
Ok(maybe_wrap(invoice))
472442
}
473443

474444
/// Returns a payable invoice that can be used to request a payment of the amount
@@ -489,10 +459,10 @@ impl Bolt11Payment {
489459
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
490460
payment_hash: PaymentHash,
491461
) -> Result<Bolt11Invoice, Error> {
492-
let description = maybe_convert_description!(description);
462+
let description = maybe_convert(description);
493463
let invoice =
494-
self.receive_inner(Some(amount_msat), description, expiry_secs, Some(payment_hash))?;
495-
Ok(maybe_wrap_invoice(invoice))
464+
self.receive_inner(Some(amount_msat), &description, expiry_secs, Some(payment_hash))?;
465+
Ok(maybe_wrap(invoice))
496466
}
497467

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

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

532502
pub(crate) fn receive_inner(
@@ -601,15 +571,15 @@ impl Bolt11Payment {
601571
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
602572
max_total_lsp_fee_limit_msat: Option<u64>,
603573
) -> Result<Bolt11Invoice, Error> {
604-
let description = maybe_convert_description!(description);
574+
let description = maybe_convert(description);
605575
let invoice = self.receive_via_jit_channel_inner(
606576
Some(amount_msat),
607-
description,
577+
&description,
608578
expiry_secs,
609579
max_total_lsp_fee_limit_msat,
610580
None,
611581
)?;
612-
Ok(maybe_wrap_invoice(invoice))
582+
Ok(maybe_wrap(invoice))
613583
}
614584

615585
/// Returns a payable invoice that can be used to request a variable amount payment (also known
@@ -627,15 +597,15 @@ impl Bolt11Payment {
627597
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
628598
max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
629599
) -> Result<Bolt11Invoice, Error> {
630-
let description = maybe_convert_description!(description);
600+
let description = maybe_convert(description);
631601
let invoice = self.receive_via_jit_channel_inner(
632602
None,
633-
description,
603+
&description,
634604
expiry_secs,
635605
None,
636606
max_proportional_lsp_fee_limit_ppm_msat,
637607
)?;
638-
Ok(maybe_wrap_invoice(invoice))
608+
Ok(maybe_wrap(invoice))
639609
}
640610

641611
fn receive_via_jit_channel_inner(
@@ -742,7 +712,7 @@ impl Bolt11Payment {
742712
/// amount times [`Config::probing_liquidity_limit_multiplier`] won't be used to send
743713
/// pre-flight probes.
744714
pub fn send_probes(&self, invoice: &Bolt11Invoice) -> Result<(), Error> {
745-
let invoice = maybe_convert_invoice(invoice);
715+
let invoice = maybe_convert(invoice);
746716
let rt_lock = self.runtime.read().unwrap();
747717
if rt_lock.is_none() {
748718
return Err(Error::NotRunning);
@@ -775,7 +745,7 @@ impl Bolt11Payment {
775745
pub fn send_probes_using_amount(
776746
&self, invoice: &Bolt11Invoice, amount_msat: u64,
777747
) -> Result<(), Error> {
778-
let invoice = maybe_convert_invoice(invoice);
748+
let invoice = maybe_convert(invoice);
779749
let rt_lock = self.runtime.read().unwrap();
780750
if rt_lock.is_none() {
781751
return Err(Error::NotRunning);

src/payment/bolt12.rs

Lines changed: 11 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,11 @@ use crate::error::Error;
1414
use crate::logger::{log_error, log_info, LdkLogger, Logger};
1515
use crate::payment::store::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus};
1616
use crate::types::{ChannelManager, PaymentStore};
17+
use crate::uniffi_conversions::{maybe_convert, maybe_wrap};
1718

1819
use lightning::ln::channelmanager::{PaymentId, Retry};
19-
use lightning::offers::invoice::Bolt12Invoice as LdkBolt12Invoice;
2020
use lightning::offers::offer::{Amount, Offer as LdkOffer, Quantity};
2121
use lightning::offers::parse::Bolt12SemanticError;
22-
use lightning::offers::refund::Refund as LdkRefund;
2322
use lightning::util::string::UntrustedString;
2423

2524
use rand::RngCore;
@@ -29,65 +28,20 @@ use std::sync::{Arc, RwLock};
2928
use std::time::{Duration, SystemTime, UNIX_EPOCH};
3029

3130
#[cfg(not(feature = "uniffi"))]
32-
type Bolt12Invoice = LdkBolt12Invoice;
31+
type Bolt12Invoice = lightning::offers::invoice::Bolt12Invoice;
3332
#[cfg(feature = "uniffi")]
3433
type Bolt12Invoice = Arc<crate::uniffi_types::Bolt12Invoice>;
3534

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

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

73-
#[cfg(not(feature = "uniffi"))]
74-
pub fn maybe_convert_refund(refund: &Refund) -> &LdkRefund {
75-
refund
76-
}
77-
#[cfg(feature = "uniffi")]
78-
pub fn maybe_convert_refund(refund: &Refund) -> &LdkRefund {
79-
&refund.inner
80-
}
81-
82-
#[cfg(not(feature = "uniffi"))]
83-
pub fn maybe_wrap_refund(refund: Refund) -> LdkRefund {
84-
refund
85-
}
86-
#[cfg(feature = "uniffi")]
87-
pub fn maybe_wrap_refund(refund: LdkRefund) -> Refund {
88-
Arc::new(refund.into())
89-
}
90-
9145
/// A payment handler allowing to create and pay [BOLT 12] offers and refunds.
9246
///
9347
/// Should be retrieved by calling [`Node::bolt12_payment`].
@@ -119,7 +73,7 @@ impl Bolt12Payment {
11973
pub fn send(
12074
&self, offer: &Offer, quantity: Option<u64>, payer_note: Option<String>,
12175
) -> Result<PaymentId, Error> {
122-
let offer = maybe_convert_offer(offer);
76+
let offer = maybe_convert(offer);
12377
let rt_lock = self.runtime.read().unwrap();
12478
if rt_lock.is_none() {
12579
return Err(Error::NotRunning);
@@ -221,7 +175,7 @@ impl Bolt12Payment {
221175
pub fn send_using_amount(
222176
&self, offer: &Offer, amount_msat: u64, quantity: Option<u64>, payer_note: Option<String>,
223177
) -> Result<PaymentId, Error> {
224-
let offer = maybe_convert_offer(offer);
178+
let offer = maybe_convert(offer);
225179
let rt_lock = self.runtime.read().unwrap();
226180
if rt_lock.is_none() {
227181
return Err(Error::NotRunning);
@@ -357,7 +311,7 @@ impl Bolt12Payment {
357311
&self, amount_msat: u64, description: &str, expiry_secs: Option<u32>, quantity: Option<u64>,
358312
) -> Result<Offer, Error> {
359313
let offer = self.receive_inner(amount_msat, description, expiry_secs, quantity)?;
360-
Ok(maybe_wrap_offer(offer))
314+
Ok(maybe_wrap(offer))
361315
}
362316

363317
/// Returns a payable offer that can be used to request and receive a payment for which the
@@ -381,7 +335,7 @@ impl Bolt12Payment {
381335
Error::OfferCreationFailed
382336
})?;
383337

384-
Ok(maybe_wrap_offer(offer))
338+
Ok(maybe_wrap(offer))
385339
}
386340

387341
/// Requests a refund payment for the given [`Refund`].
@@ -392,8 +346,8 @@ impl Bolt12Payment {
392346
/// [`Refund`]: lightning::offers::refund::Refund
393347
/// [`Bolt12Invoice`]: lightning::offers::invoice::Bolt12Invoice
394348
pub fn request_refund_payment(&self, refund: &Refund) -> Result<Bolt12Invoice, Error> {
395-
let refund = maybe_convert_refund(refund);
396-
let invoice = self.channel_manager.request_refund_payment(refund).map_err(|e| {
349+
let refund = maybe_convert(refund);
350+
let invoice = self.channel_manager.request_refund_payment(&refund).map_err(|e| {
397351
log_error!(self.logger, "Failed to request refund payment: {:?}", e);
398352
Error::InvoiceRequestCreationFailed
399353
})?;
@@ -420,7 +374,7 @@ impl Bolt12Payment {
420374

421375
self.payment_store.insert(payment)?;
422376

423-
Ok(maybe_wrap_bolt12_invoice(invoice))
377+
Ok(maybe_wrap(invoice))
424378
}
425379

426380
/// Returns a [`Refund`] object that can be used to offer a refund payment of the amount given.
@@ -487,6 +441,6 @@ impl Bolt12Payment {
487441

488442
self.payment_store.insert(payment)?;
489443

490-
Ok(maybe_wrap_refund(refund))
444+
Ok(maybe_wrap(refund))
491445
}
492446
}

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)