@@ -24,10 +24,14 @@ use lightning_types::string::UntrustedString;
2424use rand:: RngCore ;
2525
2626use crate :: config:: { AsyncPaymentsRole , Config , LDK_PAYMENT_RETRY_TIMEOUT } ;
27+ use crate :: connection:: ConnectionManager ;
2728use crate :: error:: Error ;
2829use crate :: ffi:: { maybe_deref, maybe_wrap} ;
30+ use crate :: liquidity:: LiquiditySource ;
2931use crate :: logger:: { log_error, log_info, LdkLogger , Logger } ;
3032use crate :: payment:: store:: { PaymentDetails , PaymentDirection , PaymentKind , PaymentStatus } ;
33+ use crate :: peer_store:: { PeerInfo , PeerStore } ;
34+ use crate :: runtime:: Runtime ;
3135use crate :: types:: { ChannelManager , PaymentStore } ;
3236
3337#[ cfg( not( feature = "uniffi" ) ) ]
@@ -52,8 +56,12 @@ type Refund = Arc<crate::ffi::Refund>;
5256/// [BOLT 12]: https://github.com/lightning/bolts/blob/master/12-offer-encoding.md
5357/// [`Node::bolt12_payment`]: crate::Node::bolt12_payment
5458pub struct Bolt12Payment {
59+ runtime : Arc < Runtime > ,
5560 channel_manager : Arc < ChannelManager > ,
61+ connection_manager : Arc < ConnectionManager < Arc < Logger > > > ,
62+ liquidity_source : Option < Arc < LiquiditySource < Arc < Logger > > > > ,
5663 payment_store : Arc < PaymentStore > ,
64+ peer_store : Arc < PeerStore < Arc < Logger > > > ,
5765 config : Arc < Config > ,
5866 is_running : Arc < RwLock < bool > > ,
5967 logger : Arc < Logger > ,
@@ -62,11 +70,25 @@ pub struct Bolt12Payment {
6270
6371impl Bolt12Payment {
6472 pub ( crate ) fn new (
65- channel_manager : Arc < ChannelManager > , payment_store : Arc < PaymentStore > ,
73+ runtime : Arc < Runtime > , channel_manager : Arc < ChannelManager > ,
74+ connection_manager : Arc < ConnectionManager < Arc < Logger > > > ,
75+ liquidity_source : Option < Arc < LiquiditySource < Arc < Logger > > > > ,
76+ payment_store : Arc < PaymentStore > , peer_store : Arc < PeerStore < Arc < Logger > > > ,
6677 config : Arc < Config > , is_running : Arc < RwLock < bool > > , logger : Arc < Logger > ,
6778 async_payments_role : Option < AsyncPaymentsRole > ,
6879 ) -> Self {
69- Self { channel_manager, payment_store, config, is_running, logger, async_payments_role }
80+ Self {
81+ runtime,
82+ channel_manager,
83+ connection_manager,
84+ liquidity_source,
85+ payment_store,
86+ peer_store,
87+ config,
88+ is_running,
89+ logger,
90+ async_payments_role,
91+ }
7092 }
7193
7294 /// Send a payment given an offer.
@@ -368,6 +390,93 @@ impl Bolt12Payment {
368390 Ok ( maybe_wrap ( offer) )
369391 }
370392
393+ /// Returns a payable offer that can be used to request and receive a payment of the amount
394+ /// given via a newly created just-in-time (JIT) channel.
395+ ///
396+ /// When the returned offer is paid, the configured LSPS4-compliant LSP will open a channel
397+ /// to us, supplying just-in-time inbound liquidity.
398+ ///
399+ /// This is useful for nodes that have no channels but want to receive BOLT12 payments.
400+ /// The offer will contain blinded payment paths that route through the LSP.
401+ pub fn receive_via_lsps4_jit_channel (
402+ & self , amount_msat : u64 , description : & str , expiry_secs : Option < u32 > ,
403+ quantity : Option < u64 > ,
404+ ) -> Result < Offer , Error > {
405+ let liquidity_source =
406+ self . liquidity_source . as_ref ( ) . ok_or ( Error :: LiquiditySourceUnavailable ) ?;
407+
408+ let ( node_id, address) =
409+ liquidity_source. get_lsps4_lsp_details ( ) . ok_or ( Error :: LiquiditySourceUnavailable ) ?;
410+
411+ let peer_info = PeerInfo { node_id, address } ;
412+
413+ let con_node_id = peer_info. node_id ;
414+ let con_addr = peer_info. address . clone ( ) ;
415+ let con_cm = Arc :: clone ( & self . connection_manager ) ;
416+
417+ // Connect to LSP
418+ self . runtime . block_on ( async move {
419+ con_cm. connect_peer_if_necessary ( con_node_id, con_addr) . await
420+ } ) ?;
421+
422+ log_info ! ( self . logger, "Connected to LSP {}@{}. " , peer_info. node_id, peer_info. address) ;
423+
424+ // Register with LSPS4 to populate the blinded path config
425+ let liquidity_source = Arc :: clone ( & liquidity_source) ;
426+ self . runtime . block_on ( async move { liquidity_source. lsps4_register_for_bolt12 ( ) . await } ) ?;
427+
428+ // Now create the offer - the LSPS4Router will use the config to create blinded payment paths
429+ let offer = self . receive_inner ( amount_msat, description, expiry_secs, quantity) ?;
430+
431+ // Persist LSP peer to make sure we reconnect on restart.
432+ self . peer_store . add_peer ( peer_info) ?;
433+
434+ Ok ( maybe_wrap ( offer) )
435+ }
436+
437+ /// Returns a payable offer that can be used to request and receive a payment for which the
438+ /// amount is to be determined by the user via a newly created just-in-time (JIT) channel.
439+ ///
440+ /// When the returned offer is paid, the configured LSPS4-compliant LSP will open a channel
441+ /// to us, supplying just-in-time inbound liquidity.
442+ ///
443+ /// This is useful for nodes that have no channels but want to receive BOLT12 payments.
444+ /// The offer will contain blinded payment paths that route through the LSP.
445+ pub fn receive_variable_amount_via_lsps4_jit_channel (
446+ & self , description : & str , expiry_secs : Option < u32 > ,
447+ ) -> Result < Offer , Error > {
448+ let liquidity_source =
449+ self . liquidity_source . as_ref ( ) . ok_or ( Error :: LiquiditySourceUnavailable ) ?;
450+
451+ let ( node_id, address) =
452+ liquidity_source. get_lsps4_lsp_details ( ) . ok_or ( Error :: LiquiditySourceUnavailable ) ?;
453+
454+ let peer_info = PeerInfo { node_id, address } ;
455+
456+ let con_node_id = peer_info. node_id ;
457+ let con_addr = peer_info. address . clone ( ) ;
458+ let con_cm = Arc :: clone ( & self . connection_manager ) ;
459+
460+ // Connect to LSP
461+ self . runtime . block_on ( async move {
462+ con_cm. connect_peer_if_necessary ( con_node_id, con_addr) . await
463+ } ) ?;
464+
465+ log_info ! ( self . logger, "Connected to LSP {}@{}. " , peer_info. node_id, peer_info. address) ;
466+
467+ // Register with LSPS4 to populate the blinded path config
468+ let liquidity_source = Arc :: clone ( & liquidity_source) ;
469+ self . runtime . block_on ( async move { liquidity_source. lsps4_register_for_bolt12 ( ) . await } ) ?;
470+
471+ // Now create the offer - the LSPS4Router will use the config to create blinded payment paths
472+ let offer = self . receive_variable_amount ( description, expiry_secs) ?;
473+
474+ // Persist LSP peer to make sure we reconnect on restart.
475+ self . peer_store . add_peer ( peer_info) ?;
476+
477+ Ok ( offer)
478+ }
479+
371480 /// Requests a refund payment for the given [`Refund`].
372481 ///
373482 /// The returned [`Bolt12Invoice`] is for informational purposes only (i.e., isn't needed to
0 commit comments