Skip to content

Expose Bolt11Invoice type in bindings #522

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,45 @@ dictionary NodeAnnouncementInfo {
sequence<SocketAddress> addresses;
};

enum Currency {
"Bitcoin",
"BitcoinTestnet",
"Regtest",
"Simnet",
"Signet",
};

dictionary RouteHintHop {
PublicKey src_node_id;
u64 short_channel_id;
u16 cltv_expiry_delta;
u64? htlc_minimum_msat;
u64? htlc_maximum_msat;
RoutingFees fees;
};

interface Bolt11Invoice {
[Throws=NodeError, Name=from_str]
constructor([ByRef] string invoice_str);
PaymentHash payment_hash();
PaymentSecret payment_secret();
u64? amount_milli_satoshis();
sequence<u8> signable_hash();
u64 timestamp_seconds();
u64 expiry_time_seconds();
u64 seconds_since_epoch();
u64 seconds_until_expiry();
boolean is_expired();
boolean would_expire(u64 at_time_seconds);
Bolt11InvoiceDescription description();
u64 min_final_cltv_expiry_delta();
Network network();
Currency currency();
sequence<Address> fallback_addresses();
sequence<sequence<RouteHintHop>> route_hints();
PublicKey recover_payee_pub_key();
};

[Custom]
typedef string Txid;

Expand All @@ -716,9 +755,6 @@ typedef string NodeId;
[Custom]
typedef string Address;

[Custom]
typedef string Bolt11Invoice;

[Custom]
typedef string Offer;

Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
//! controlled via commands such as [`start`], [`stop`], [`open_channel`], [`send`], etc.:
//!
//! ```no_run
//! # #[cfg(not(feature = "uniffi"))]
//! # {
//! use ldk_node::Builder;
//! use ldk_node::lightning_invoice::Bolt11Invoice;
//! use ldk_node::lightning::ln::msgs::SocketAddress;
Expand Down Expand Up @@ -57,6 +59,7 @@
//!
//! node.stop().unwrap();
//! }
//! # }
//! ```
//!
//! [`build`]: Builder::build
Expand Down
7 changes: 5 additions & 2 deletions src/liquidity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1308,15 +1308,18 @@ type PaymentInfo = lightning_liquidity::lsps1::msgs::PaymentInfo;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PaymentInfo {
/// A Lightning payment using BOLT 11.
pub bolt11: Option<lightning_liquidity::lsps1::msgs::Bolt11PaymentInfo>,
pub bolt11: Option<crate::uniffi_types::Bolt11PaymentInfo>,
/// An onchain payment.
pub onchain: Option<OnchainPaymentInfo>,
}

#[cfg(feature = "uniffi")]
impl From<lightning_liquidity::lsps1::msgs::PaymentInfo> for PaymentInfo {
fn from(value: lightning_liquidity::lsps1::msgs::PaymentInfo) -> Self {
PaymentInfo { bolt11: value.bolt11, onchain: value.onchain.map(|o| o.into()) }
PaymentInfo {
bolt11: value.bolt11.map(|b| b.into()),
onchain: value.onchain.map(|o| o.into()),
}
}
}

Expand Down
56 changes: 45 additions & 11 deletions src/payment/bolt11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,37 @@ use lightning::routing::router::{PaymentParameters, RouteParameters};

use lightning_types::payment::{PaymentHash, PaymentPreimage};

use lightning_invoice::Bolt11Invoice;
use lightning_invoice::Bolt11Invoice as LdkBolt11Invoice;
use lightning_invoice::Bolt11InvoiceDescription as LdkBolt11InvoiceDescription;

use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::Hash;

use std::sync::{Arc, RwLock};

#[cfg(not(feature = "uniffi"))]
type Bolt11Invoice = LdkBolt11Invoice;
#[cfg(feature = "uniffi")]
type Bolt11Invoice = Arc<crate::uniffi_types::Bolt11Invoice>;

#[cfg(not(feature = "uniffi"))]
pub fn maybe_wrap_invoice(invoice: LdkBolt11Invoice) -> Bolt11Invoice {
invoice
}
#[cfg(feature = "uniffi")]
pub fn maybe_wrap_invoice(invoice: LdkBolt11Invoice) -> Bolt11Invoice {
Arc::new(invoice.into())
}

#[cfg(not(feature = "uniffi"))]
pub fn maybe_convert_invoice(invoice: &Bolt11Invoice) -> &LdkBolt11Invoice {
invoice
}
#[cfg(feature = "uniffi")]
pub fn maybe_convert_invoice(invoice: &Bolt11Invoice) -> &LdkBolt11Invoice {
&invoice.inner
}

#[cfg(not(feature = "uniffi"))]
type Bolt11InvoiceDescription = LdkBolt11InvoiceDescription;
#[cfg(feature = "uniffi")]
Expand Down Expand Up @@ -101,6 +124,7 @@ impl Bolt11Payment {
pub fn send(
&self, invoice: &Bolt11Invoice, sending_parameters: Option<SendingParameters>,
) -> Result<PaymentId, Error> {
let invoice = maybe_convert_invoice(invoice);
let rt_lock = self.runtime.read().unwrap();
if rt_lock.is_none() {
return Err(Error::NotRunning);
Expand Down Expand Up @@ -209,6 +233,7 @@ impl Bolt11Payment {
&self, invoice: &Bolt11Invoice, amount_msat: u64,
sending_parameters: Option<SendingParameters>,
) -> Result<PaymentId, Error> {
let invoice = maybe_convert_invoice(invoice);
let rt_lock = self.runtime.read().unwrap();
if rt_lock.is_none() {
return Err(Error::NotRunning);
Expand Down Expand Up @@ -441,7 +466,8 @@ impl Bolt11Payment {
&self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_convert_description!(description);
self.receive_inner(Some(amount_msat), description, expiry_secs, None)
let invoice = self.receive_inner(Some(amount_msat), description, expiry_secs, None)?;
Ok(maybe_wrap_invoice(invoice))
}

/// Returns a payable invoice that can be used to request a payment of the amount
Expand All @@ -463,7 +489,9 @@ impl Bolt11Payment {
payment_hash: PaymentHash,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_convert_description!(description);
self.receive_inner(Some(amount_msat), description, expiry_secs, Some(payment_hash))
let invoice =
self.receive_inner(Some(amount_msat), description, expiry_secs, Some(payment_hash))?;
Ok(maybe_wrap_invoice(invoice))
}

/// Returns a payable invoice that can be used to request and receive a payment for which the
Expand All @@ -474,7 +502,8 @@ impl Bolt11Payment {
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_convert_description!(description);
self.receive_inner(None, description, expiry_secs, None)
let invoice = self.receive_inner(None, description, expiry_secs, None)?;
Ok(maybe_wrap_invoice(invoice))
}

/// Returns a payable invoice that can be used to request a payment for the given payment hash
Expand All @@ -495,13 +524,14 @@ impl Bolt11Payment {
&self, description: &Bolt11InvoiceDescription, expiry_secs: u32, payment_hash: PaymentHash,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_convert_description!(description);
self.receive_inner(None, description, expiry_secs, Some(payment_hash))
let invoice = self.receive_inner(None, description, expiry_secs, Some(payment_hash))?;
Ok(maybe_wrap_invoice(invoice))
}

pub(crate) fn receive_inner(
&self, amount_msat: Option<u64>, invoice_description: &LdkBolt11InvoiceDescription,
expiry_secs: u32, manual_claim_payment_hash: Option<PaymentHash>,
) -> Result<Bolt11Invoice, Error> {
) -> Result<LdkBolt11Invoice, Error> {
let invoice = {
let invoice_params = Bolt11InvoiceParameters {
amount_msats: amount_msat,
Expand Down Expand Up @@ -571,13 +601,14 @@ impl Bolt11Payment {
max_total_lsp_fee_limit_msat: Option<u64>,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_convert_description!(description);
self.receive_via_jit_channel_inner(
let invoice = self.receive_via_jit_channel_inner(
Some(amount_msat),
description,
expiry_secs,
max_total_lsp_fee_limit_msat,
None,
)
)?;
Ok(maybe_wrap_invoice(invoice))
}

/// Returns a payable invoice that can be used to request a variable amount payment (also known
Expand All @@ -596,20 +627,21 @@ impl Bolt11Payment {
max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
) -> Result<Bolt11Invoice, Error> {
let description = maybe_convert_description!(description);
self.receive_via_jit_channel_inner(
let invoice = self.receive_via_jit_channel_inner(
None,
description,
expiry_secs,
None,
max_proportional_lsp_fee_limit_ppm_msat,
)
)?;
Ok(maybe_wrap_invoice(invoice))
}

fn receive_via_jit_channel_inner(
&self, amount_msat: Option<u64>, description: &LdkBolt11InvoiceDescription,
expiry_secs: u32, max_total_lsp_fee_limit_msat: Option<u64>,
max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
) -> Result<Bolt11Invoice, Error> {
) -> Result<LdkBolt11Invoice, Error> {
let liquidity_source =
self.liquidity_source.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;

Expand Down Expand Up @@ -709,6 +741,7 @@ impl Bolt11Payment {
/// amount times [`Config::probing_liquidity_limit_multiplier`] won't be used to send
/// pre-flight probes.
pub fn send_probes(&self, invoice: &Bolt11Invoice) -> Result<(), Error> {
let invoice = maybe_convert_invoice(invoice);
let rt_lock = self.runtime.read().unwrap();
if rt_lock.is_none() {
return Err(Error::NotRunning);
Expand Down Expand Up @@ -741,6 +774,7 @@ impl Bolt11Payment {
pub fn send_probes_using_amount(
&self, invoice: &Bolt11Invoice, amount_msat: u64,
) -> Result<(), Error> {
let invoice = maybe_convert_invoice(invoice);
let rt_lock = self.runtime.read().unwrap();
if rt_lock.is_none() {
return Err(Error::NotRunning);
Expand Down
3 changes: 2 additions & 1 deletion src/payment/unified_qr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! [BOLT 12]: https://github.com/lightning/bolts/blob/master/12-offer-encoding.md
use crate::error::Error;
use crate::logger::{log_error, LdkLogger, Logger};
use crate::payment::{Bolt11Payment, Bolt12Payment, OnchainPayment};
use crate::payment::{bolt11::maybe_wrap_invoice, Bolt11Payment, Bolt12Payment, OnchainPayment};
use crate::Config;

use lightning::ln::channelmanager::PaymentId;
Expand Down Expand Up @@ -149,6 +149,7 @@ impl UnifiedQrPayment {
}

if let Some(invoice) = uri_network_checked.extras.bolt11_invoice {
let invoice = maybe_wrap_invoice(invoice);
match self.bolt11_invoice.send(&invoice, None) {
Ok(payment_id) => return Ok(QrPaymentResult::Bolt11 { payment_id }),
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),
Expand Down
Loading
Loading