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