Skip to content

Commit 39f04f3

Browse files
committed
Introduce receive_via_jit_channel to UnifiedPayment
1 parent 53268f2 commit 39f04f3

1 file changed

Lines changed: 82 additions & 1 deletion

File tree

src/payment/unified.rs

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, Description};
3232
use crate::config::HRN_RESOLUTION_TIMEOUT_SECS;
3333
use crate::error::Error;
3434
use crate::ffi::maybe_wrap;
35-
use crate::logger::{log_error, LdkLogger, Logger};
35+
use crate::logger::{log_error, log_info, LdkLogger, Logger};
3636
use crate::payment::{Bolt11Payment, Bolt12Payment, OnchainPayment};
3737
use crate::types::HRNResolver;
3838
use crate::Config;
@@ -167,6 +167,87 @@ impl UnifiedPayment {
167167
Ok(format_uri(uri))
168168
}
169169

170+
/// Generates a unified BIP21 URI identical in structure to [`receive`], but uses a
171+
/// JIT (Just-In-Time) BOLT 11 invoice via the configured LSP liquidity source for
172+
/// the purpose of providing inbound liquidity on the fly.
173+
///
174+
/// This method is designed to be called when the node has insufficient inbound capacity
175+
/// to receive the payment over standard Lightning routes. **Note that this method does not
176+
/// automatically detect your current inbound capacity;** the determination of whether
177+
/// inbound capacity is lacking, and the decision to invoke this JIT flow, is left entirely
178+
/// to the discretion of the developer.
179+
///
180+
/// Like [`receive`], the resulting URI provides an on-chain fallback address and a BOLT 12
181+
/// offer. However, the attached BOLT 11 invoice is provisioned through an External Liquidity
182+
/// Provider (LSP) to dynamically open a JIT channel when the payer routes the payment. If no
183+
/// LSP is configured or the JIT generation fails, it falls back to standard local invoice
184+
/// generation.
185+
///
186+
/// # Parameters
187+
/// - `amount_sats`: The amount to be received, specified in satoshis.
188+
/// - `description`: A description or note associated with the payment.
189+
/// This message is visible to the payer and can provide context or details about the payment.
190+
/// - `expiry_sec`: The expiration time for the payment, specified in seconds.
191+
/// - `max_total_lsp_fee_limit_msat`: An optional fee cap in millisatoshis defining the maximum
192+
/// fee you are willing to allow the LSP to charge for opening the JIT liquidity channel.
193+
///
194+
/// # Warning
195+
/// Because this method may require synchronous network negotiation with an external LSP,
196+
/// it can block the calling thread. Mobile applications should ensure this is invoked
197+
/// from a background thread to prevent UI freezing.
198+
pub fn receive_via_jit_channel(
199+
&self, amount_sats: u64, description: &str, expiry_sec: u32,
200+
max_total_lsp_fee_limit_msat: Option<u64>,
201+
) -> Result<String, Error> {
202+
let onchain_address = self.onchain_payment.new_address()?;
203+
let amount_msats = amount_sats * 1_000;
204+
205+
let bolt12_offer =
206+
match self.bolt12_payment.receive_inner(amount_msats, description, None, None) {
207+
Ok(offer) => Some(maybe_wrap(offer)),
208+
Err(e) => {
209+
log_error!(self.logger, "Failed to create offer: {}", e);
210+
None
211+
},
212+
};
213+
214+
let invoice_description = Bolt11InvoiceDescription::Direct(
215+
Description::new(description.to_string()).map_err(|_| Error::InvoiceCreationFailed)?,
216+
);
217+
218+
let bolt11_invoice = match self.bolt11_invoice.receive_via_jit_channel(
219+
amount_msats,
220+
&invoice_description,
221+
expiry_sec,
222+
max_total_lsp_fee_limit_msat,
223+
) {
224+
Ok(invoice) => Some(invoice),
225+
Err(Error::LiquiditySourceUnavailable) => {
226+
log_info!(
227+
self.logger,
228+
"No LSP configured. Falling back to local invoice generation."
229+
);
230+
self.bolt11_invoice.receive(amount_msats, &invoice_description, expiry_sec).ok()
231+
},
232+
Err(e) => {
233+
log_error!(
234+
self.logger,
235+
"LSP JIT invoice creation failed: {:?}. Falling back to local invoice.",
236+
e
237+
);
238+
self.bolt11_invoice.receive(amount_msats, &invoice_description, expiry_sec).ok()
239+
},
240+
};
241+
242+
let extras = Extras { bolt11_invoice, bolt12_offer };
243+
244+
let mut uri = Uri::with_extras(onchain_address, extras);
245+
uri.amount = Some(Amount::from_sat(amount_sats));
246+
uri.message = Some(description.into());
247+
248+
Ok(format_uri(uri))
249+
}
250+
170251
/// Sends a payment given a [BIP 21] URI or [BIP 353] Human-Readable Name.
171252
///
172253
/// This method parses the provided URI string and attempts to send the payment. If the URI

0 commit comments

Comments
 (0)