55// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66// accordance with one or both of these licenses.
77
8+ //! Objects related to liquidity management.
9+
810use crate :: chain:: ChainSource ;
9- use crate :: logger:: { log_debug, log_error, log_info, LdkLogger } ;
10- use crate :: types:: { ChannelManager , KeysManager , LiquidityManager , PeerManager } ;
11+ use crate :: connection:: ConnectionManager ;
12+ use crate :: logger:: { log_debug, log_error, log_info, LdkLogger , Logger } ;
13+ use crate :: types:: { ChannelManager , KeysManager , LiquidityManager , PeerManager , Wallet } ;
1114use crate :: { Config , Error } ;
1215
1316use lightning:: ln:: channelmanager:: MIN_FINAL_CLTV_EXPIRY_DELTA ;
@@ -34,7 +37,7 @@ use tokio::sync::oneshot;
3437
3538use std:: collections:: HashMap ;
3639use std:: ops:: Deref ;
37- use std:: sync:: { Arc , Mutex } ;
40+ use std:: sync:: { Arc , Mutex , RwLock } ;
3841use std:: time:: Duration ;
3942
4043const LIQUIDITY_REQUEST_TIMEOUT_SECS : u64 = 5 ;
@@ -896,3 +899,118 @@ pub(crate) struct LSPS2BuyResponse {
896899 intercept_scid : u64 ,
897900 cltv_expiry_delta : u32 ,
898901}
902+
903+ /// A liquidity handler allowing to request channels via the [bLIP-51 / LSPS1] protocol.
904+ ///
905+ /// Should be retrieved by calling [`Node::lsps1_liquidity`].
906+ ///
907+ /// To open [bLIP-52 / LSPS2] JIT channels, please refer to
908+ /// [`Bolt11Payment::receive_via_jit_channel`].
909+ ///
910+ /// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
911+ /// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
912+ /// [`Node::lsps1_liquidity`]: crate::Node::lsps1_liquidity
913+ /// [`Bolt11Payment::receive_via_jit_channel`]: crate::payment::Bolt11Payment::receive_via_jit_channel
914+ #[ derive( Clone ) ]
915+ pub struct LSPS1Liquidity {
916+ runtime : Arc < RwLock < Option < Arc < tokio:: runtime:: Runtime > > > > ,
917+ wallet : Arc < Wallet > ,
918+ connection_manager : Arc < ConnectionManager < Arc < Logger > > > ,
919+ liquidity_source : Option < Arc < LiquiditySource < Arc < Logger > > > > ,
920+ logger : Arc < Logger > ,
921+ }
922+
923+ impl LSPS1Liquidity {
924+ pub ( crate ) fn new (
925+ runtime : Arc < RwLock < Option < Arc < tokio:: runtime:: Runtime > > > > , wallet : Arc < Wallet > ,
926+ connection_manager : Arc < ConnectionManager < Arc < Logger > > > ,
927+ liquidity_source : Option < Arc < LiquiditySource < Arc < Logger > > > > , logger : Arc < Logger > ,
928+ ) -> Self {
929+ Self { runtime, wallet, connection_manager, liquidity_source, logger }
930+ }
931+
932+ /// Connects to the configured LSP and places an order for an inbound channel.
933+ ///
934+ /// The channel will be opened after one of the returned payment options has successfully been
935+ /// paid.
936+ pub fn request_channel (
937+ & self , lsp_balance_sat : u64 , client_balance_sat : u64 , channel_expiry_blocks : u32 ,
938+ announce_channel : bool ,
939+ ) -> Result < LSPS1OrderStatus , Error > {
940+ let liquidity_source =
941+ self . liquidity_source . as_ref ( ) . ok_or ( Error :: LiquiditySourceUnavailable ) ?;
942+
943+ let ( lsp_node_id, lsp_address) = liquidity_source
944+ . get_lsps1_service_details ( )
945+ . ok_or ( Error :: LiquiditySourceUnavailable ) ?;
946+
947+ let rt_lock = self . runtime . read ( ) . unwrap ( ) ;
948+ let runtime = rt_lock. as_ref ( ) . unwrap ( ) ;
949+
950+ let con_node_id = lsp_node_id;
951+ let con_addr = lsp_address. clone ( ) ;
952+ let con_cm = Arc :: clone ( & self . connection_manager ) ;
953+
954+ // We need to use our main runtime here as a local runtime might not be around to poll
955+ // connection futures going forward.
956+ tokio:: task:: block_in_place ( move || {
957+ runtime. block_on ( async move {
958+ con_cm. connect_peer_if_necessary ( con_node_id, con_addr) . await
959+ } )
960+ } ) ?;
961+
962+ log_info ! ( self . logger, "Connected to LSP {}@{}. " , lsp_node_id, lsp_address) ;
963+
964+ let refund_address = self . wallet . get_new_address ( ) ?;
965+
966+ let liquidity_source = Arc :: clone ( & liquidity_source) ;
967+ let response = tokio:: task:: block_in_place ( move || {
968+ runtime. block_on ( async move {
969+ liquidity_source
970+ . lsps1_request_channel (
971+ lsp_balance_sat,
972+ client_balance_sat,
973+ channel_expiry_blocks,
974+ announce_channel,
975+ refund_address,
976+ )
977+ . await
978+ } )
979+ } ) ?;
980+
981+ Ok ( response)
982+ }
983+
984+ /// Connects to the configured LSP and checks for the status of a previously-placed order.
985+ pub fn check_order_status ( & self , order_id : OrderId ) -> Result < LSPS1OrderStatus , Error > {
986+ let liquidity_source =
987+ self . liquidity_source . as_ref ( ) . ok_or ( Error :: LiquiditySourceUnavailable ) ?;
988+
989+ let ( lsp_node_id, lsp_address) = liquidity_source
990+ . get_lsps1_service_details ( )
991+ . ok_or ( Error :: LiquiditySourceUnavailable ) ?;
992+
993+ let rt_lock = self . runtime . read ( ) . unwrap ( ) ;
994+ let runtime = rt_lock. as_ref ( ) . unwrap ( ) ;
995+
996+ let con_node_id = lsp_node_id;
997+ let con_addr = lsp_address. clone ( ) ;
998+ let con_cm = Arc :: clone ( & self . connection_manager ) ;
999+
1000+ // We need to use our main runtime here as a local runtime might not be around to poll
1001+ // connection futures going forward.
1002+ tokio:: task:: block_in_place ( move || {
1003+ runtime. block_on ( async move {
1004+ con_cm. connect_peer_if_necessary ( con_node_id, con_addr) . await
1005+ } )
1006+ } ) ?;
1007+
1008+ let liquidity_source = Arc :: clone ( & liquidity_source) ;
1009+ let response = tokio:: task:: block_in_place ( move || {
1010+ runtime
1011+ . block_on ( async move { liquidity_source. lsps1_check_order_status ( order_id) . await } )
1012+ } ) ?;
1013+
1014+ Ok ( response)
1015+ }
1016+ }
0 commit comments