@@ -32,7 +32,7 @@ use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, Description};
3232use crate :: config:: HRN_RESOLUTION_TIMEOUT_SECS ;
3333use crate :: error:: Error ;
3434use crate :: ffi:: maybe_wrap;
35- use crate :: logger:: { log_error, LdkLogger , Logger } ;
35+ use crate :: logger:: { log_error, log_info , LdkLogger , Logger } ;
3636use crate :: payment:: { Bolt11Payment , Bolt12Payment , OnchainPayment } ;
3737use crate :: types:: HRNResolver ;
3838use 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