@@ -11,7 +11,7 @@ use crate::chain::ChainSource;
1111use crate :: connection:: ConnectionManager ;
1212use crate :: logger:: { log_debug, log_error, log_info, LdkLogger , Logger } ;
1313use crate :: types:: { ChannelManager , KeysManager , LiquidityManager , PeerManager , Wallet } ;
14- use crate :: { Config , Error } ;
14+ use crate :: { total_anchor_channels_reserve_sats , Config , Error } ;
1515
1616use lightning:: events:: HTLCDestination ;
1717use lightning:: ln:: channelmanager:: { InterceptId , MIN_FINAL_CLTV_EXPIRY_DELTA } ;
@@ -27,8 +27,8 @@ use lightning_liquidity::lsps1::client::LSPS1ClientConfig as LdkLSPS1ClientConfi
2727use lightning_liquidity:: lsps1:: event:: LSPS1ClientEvent ;
2828use lightning_liquidity:: lsps1:: msgs:: { ChannelInfo , LSPS1Options , OrderId , OrderParameters } ;
2929use lightning_liquidity:: lsps2:: client:: LSPS2ClientConfig as LdkLSPS2ClientConfig ;
30- use lightning_liquidity:: lsps2:: event:: LSPS2ClientEvent ;
31- use lightning_liquidity:: lsps2:: msgs:: OpeningFeeParams ;
30+ use lightning_liquidity:: lsps2:: event:: { LSPS2ClientEvent , LSPS2ServiceEvent } ;
31+ use lightning_liquidity:: lsps2:: msgs:: { OpeningFeeParams , RawOpeningFeeParams } ;
3232use lightning_liquidity:: lsps2:: service:: LSPS2ServiceConfig as LdkLSPS2ServiceConfig ;
3333use lightning_liquidity:: lsps2:: utils:: compute_opening_fee;
3434use lightning_liquidity:: { LiquidityClientConfig , LiquidityServiceConfig } ;
@@ -40,13 +40,21 @@ use bitcoin::secp256k1::{PublicKey, Secp256k1};
4040
4141use tokio:: sync:: oneshot;
4242
43+ use chrono:: { DateTime , Utc } ;
44+
45+ use rand:: Rng ;
46+
4347use std:: collections:: HashMap ;
4448use std:: ops:: Deref ;
4549use std:: sync:: { Arc , Mutex , RwLock } ;
4650use std:: time:: Duration ;
4751
4852const LIQUIDITY_REQUEST_TIMEOUT_SECS : u64 = 5 ;
4953
54+ const LSPS2_GETINFO_REQUEST_EXPIRY : Duration = Duration :: from_secs ( 60 * 60 * 24 ) ;
55+ const LSPS2_CLIENT_TRUSTS_LSP_MODE : bool = true ;
56+ const LSPS2_CHANNEL_CLTV_EXPIRY_DELTA : u32 = 72 ;
57+
5058struct LSPS1Client {
5159 lsp_node_id : PublicKey ,
5260 lsp_address : SocketAddress ,
@@ -132,6 +140,7 @@ where
132140 lsps1_client : Option < LSPS1Client > ,
133141 lsps2_client : Option < LSPS2Client > ,
134142 lsps2_service : Option < LSPS2Service > ,
143+ wallet : Arc < Wallet > ,
135144 channel_manager : Arc < ChannelManager > ,
136145 keys_manager : Arc < KeysManager > ,
137146 chain_source : Arc < ChainSource > ,
@@ -144,7 +153,7 @@ where
144153 L :: Target : LdkLogger ,
145154{
146155 pub ( crate ) fn new (
147- channel_manager : Arc < ChannelManager > , keys_manager : Arc < KeysManager > ,
156+ wallet : Arc < Wallet > , channel_manager : Arc < ChannelManager > , keys_manager : Arc < KeysManager > ,
148157 chain_source : Arc < ChainSource > , config : Arc < Config > , logger : L ,
149158 ) -> Self {
150159 let lsps1_client = None ;
@@ -154,6 +163,7 @@ where
154163 lsps1_client,
155164 lsps2_client,
156165 lsps2_service,
166+ wallet,
157167 channel_manager,
158168 keys_manager,
159169 chain_source,
@@ -232,7 +242,9 @@ where
232242 lsps1_client : self . lsps1_client ,
233243 lsps2_client : self . lsps2_client ,
234244 lsps2_service : self . lsps2_service ,
245+ wallet : self . wallet ,
235246 channel_manager : self . channel_manager ,
247+ peer_manager : RwLock :: new ( None ) ,
236248 keys_manager : self . keys_manager ,
237249 liquidity_manager,
238250 config : self . config ,
@@ -248,7 +260,9 @@ where
248260 lsps1_client : Option < LSPS1Client > ,
249261 lsps2_client : Option < LSPS2Client > ,
250262 lsps2_service : Option < LSPS2Service > ,
263+ wallet : Arc < Wallet > ,
251264 channel_manager : Arc < ChannelManager > ,
265+ peer_manager : RwLock < Option < Arc < PeerManager > > > ,
252266 keys_manager : Arc < KeysManager > ,
253267 liquidity_manager : Arc < LiquidityManager > ,
254268 config : Arc < Config > ,
@@ -260,6 +274,7 @@ where
260274 L :: Target : LdkLogger ,
261275{
262276 pub ( crate ) fn set_peer_manager ( & self , peer_manager : Arc < PeerManager > ) {
277+ * self . peer_manager . write ( ) . unwrap ( ) = Some ( Arc :: clone ( & peer_manager) ) ;
263278 let process_msgs_callback = move || peer_manager. process_events ( ) ;
264279 self . liquidity_manager . set_process_msgs_callback ( process_msgs_callback) ;
265280 }
@@ -447,6 +462,254 @@ where
447462 log_error ! ( self . logger, "Received unexpected LSPS1Client::OrderStatus event!" ) ;
448463 }
449464 } ,
465+ Event :: LSPS2Service ( LSPS2ServiceEvent :: GetInfo {
466+ request_id,
467+ counterparty_node_id,
468+ token,
469+ } ) => {
470+ if let Some ( lsps2_service_handler) =
471+ self . liquidity_manager . lsps2_service_handler ( ) . as_ref ( )
472+ {
473+ let service_config = if let Some ( service_config) =
474+ self . lsps2_service . as_ref ( ) . map ( |s| s. service_config . clone ( ) )
475+ {
476+ service_config
477+ } else {
478+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
479+ return ;
480+ } ;
481+
482+ if let Some ( required) = service_config. require_token {
483+ if token != Some ( required) {
484+ log_error ! (
485+ self . logger,
486+ "Rejecting LSPS2 request {:?} from counterparty {} as the client provided an invalid token." ,
487+ request_id,
488+ counterparty_node_id
489+ ) ;
490+ lsps2_service_handler. invalid_token_provided ( & counterparty_node_id, request_id. clone ( ) ) . unwrap_or_else ( |e| {
491+ debug_assert ! ( false , "Failed to reject LSPS2 request. This should never happen." ) ;
492+ log_error ! (
493+ self . logger,
494+ "Failed to reject LSPS2 request {:?} from counterparty {} due to: {:?}. This should never happen." ,
495+ request_id,
496+ counterparty_node_id,
497+ e
498+ ) ;
499+ } ) ;
500+ return ;
501+ }
502+ }
503+
504+ let mut valid_until: DateTime < Utc > = Utc :: now ( ) ;
505+ valid_until += LSPS2_GETINFO_REQUEST_EXPIRY ;
506+
507+ let opening_fee_params = RawOpeningFeeParams {
508+ min_fee_msat : service_config. min_channel_opening_fee_msat ,
509+ proportional : service_config. channel_opening_fee_ppm ,
510+ valid_until,
511+ min_lifetime : service_config. min_channel_lifetime ,
512+ max_client_to_self_delay : service_config. max_client_to_self_delay ,
513+ min_payment_size_msat : service_config. min_payment_size_msat ,
514+ max_payment_size_msat : service_config. max_payment_size_msat ,
515+ } ;
516+
517+ let opening_fee_params_menu = vec ! [ opening_fee_params] ;
518+
519+ if let Err ( e) = lsps2_service_handler. opening_fee_params_generated (
520+ & counterparty_node_id,
521+ request_id,
522+ opening_fee_params_menu,
523+ ) {
524+ log_error ! (
525+ self . logger,
526+ "Failed to handle generated opening fee params: {:?}" ,
527+ e
528+ ) ;
529+ }
530+ } else {
531+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
532+ return ;
533+ }
534+ } ,
535+ Event :: LSPS2Service ( LSPS2ServiceEvent :: BuyRequest {
536+ request_id,
537+ counterparty_node_id,
538+ opening_fee_params : _,
539+ payment_size_msat,
540+ } ) => {
541+ if let Some ( lsps2_service_handler) =
542+ self . liquidity_manager . lsps2_service_handler ( ) . as_ref ( )
543+ {
544+ let service_config = if let Some ( service_config) =
545+ self . lsps2_service . as_ref ( ) . map ( |s| s. service_config . clone ( ) )
546+ {
547+ service_config
548+ } else {
549+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
550+ return ;
551+ } ;
552+
553+ let user_channel_id: u128 = rand:: thread_rng ( ) . gen :: < u128 > ( ) ;
554+ let intercept_scid = self . channel_manager . get_intercept_scid ( ) ;
555+
556+ if let Some ( payment_size_msat) = payment_size_msat {
557+ // We already check this in `lightning-liquidity`, but better safe than
558+ // sorry.
559+ //
560+ // TODO: We might want to eventually send back an error here, but we
561+ // currently can't and have to trust `lightning-liquidity` is doing the
562+ // right thing.
563+ //
564+ // TODO: Eventually we also might want to make sure that we have sufficient
565+ // liquidity for the channel opening here.
566+ if payment_size_msat > service_config. max_payment_size_msat
567+ || payment_size_msat < service_config. min_payment_size_msat
568+ {
569+ log_error ! (
570+ self . logger,
571+ "Rejecting to handle LSPS2 buy request {:?} from counterparty {} as the client requested an invalid payment size." ,
572+ request_id,
573+ counterparty_node_id
574+ ) ;
575+ return ;
576+ }
577+ }
578+
579+ match lsps2_service_handler. invoice_parameters_generated (
580+ & counterparty_node_id,
581+ request_id,
582+ intercept_scid,
583+ LSPS2_CHANNEL_CLTV_EXPIRY_DELTA ,
584+ LSPS2_CLIENT_TRUSTS_LSP_MODE ,
585+ user_channel_id,
586+ ) {
587+ Ok ( ( ) ) => { } ,
588+ Err ( e) => {
589+ log_error ! (
590+ self . logger,
591+ "Failed to provide invoice parameters: {:?}" ,
592+ e
593+ ) ;
594+ return ;
595+ } ,
596+ }
597+ } else {
598+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
599+ return ;
600+ }
601+ } ,
602+ Event :: LSPS2Service ( LSPS2ServiceEvent :: OpenChannel {
603+ their_network_key,
604+ amt_to_forward_msat,
605+ opening_fee_msat : _,
606+ user_channel_id,
607+ intercept_scid : _,
608+ } ) => {
609+ if self . liquidity_manager . lsps2_service_handler ( ) . is_none ( ) {
610+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
611+ return ;
612+ } ;
613+
614+ let service_config = if let Some ( service_config) =
615+ self . lsps2_service . as_ref ( ) . map ( |s| s. service_config . clone ( ) )
616+ {
617+ service_config
618+ } else {
619+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
620+ return ;
621+ } ;
622+
623+ let init_features = if let Some ( peer_manager) =
624+ self . peer_manager . read ( ) . unwrap ( ) . as_ref ( )
625+ {
626+ // Fail if we're not connected to the prospective channel partner.
627+ if let Some ( peer) = peer_manager. peer_by_node_id ( & their_network_key) {
628+ peer. init_features
629+ } else {
630+ // TODO: We just silently fail here. Eventually we will need to remember
631+ // the pending requests and regularly retry opening the channel until we
632+ // succeed.
633+ log_error ! (
634+ self . logger,
635+ "Failed to open LSPS2 channel to {} due to peer not being not connected." ,
636+ their_network_key,
637+ ) ;
638+ return ;
639+ }
640+ } else {
641+ debug_assert ! ( false , "Failed to handle LSPS2ServiceEvent as peer manager isn't available. This should never happen." , ) ;
642+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as peer manager isn't available. This should never happen." , ) ;
643+ return ;
644+ } ;
645+
646+ // Fail if we have insufficient onchain funds available.
647+ let over_provisioning_msat = ( amt_to_forward_msat
648+ * service_config. channel_over_provisioning_ppm as u64 )
649+ / 1_000_000 ;
650+ let channel_amount_sats = ( amt_to_forward_msat + over_provisioning_msat) / 1000 ;
651+ let cur_anchor_reserve_sats =
652+ total_anchor_channels_reserve_sats ( & self . channel_manager , & self . config ) ;
653+ let spendable_amount_sats =
654+ self . wallet . get_spendable_amount_sats ( cur_anchor_reserve_sats) . unwrap_or ( 0 ) ;
655+ let required_funds_sats = channel_amount_sats
656+ + self . config . anchor_channels_config . as_ref ( ) . map_or ( 0 , |c| {
657+ if init_features. requires_anchors_zero_fee_htlc_tx ( )
658+ && !c. trusted_peers_no_reserve . contains ( & their_network_key)
659+ {
660+ c. per_channel_reserve_sats
661+ } else {
662+ 0
663+ }
664+ } ) ;
665+ if spendable_amount_sats < required_funds_sats {
666+ log_error ! ( self . logger,
667+ "Unable to create channel due to insufficient funds. Available: {}sats, Required: {}sats" ,
668+ spendable_amount_sats, channel_amount_sats
669+ ) ;
670+ // TODO: We just silently fail here. Eventually we will need to remember
671+ // the pending requests and regularly retry opening the channel until we
672+ // succeed.
673+ return ;
674+ }
675+
676+ let mut config = * self . channel_manager . get_current_default_configuration ( ) ;
677+
678+ // Set the HTLC-value-in-flight to 100% of the channel value to ensure we can
679+ // forward the payment.
680+ config
681+ . channel_handshake_config
682+ . max_inbound_htlc_value_in_flight_percent_of_channel = 100 ;
683+
684+ // We set the forwarding fee to 0 for now as we're getting paid by the channel fee.
685+ //
686+ // TODO: revisit this decision eventually.
687+ config. channel_config . forwarding_fee_base_msat = 0 ;
688+ config. channel_config . forwarding_fee_proportional_millionths = 0 ;
689+
690+ match self . channel_manager . create_channel (
691+ their_network_key,
692+ channel_amount_sats,
693+ 0 ,
694+ user_channel_id,
695+ None ,
696+ Some ( config) ,
697+ ) {
698+ Ok ( _) => { } ,
699+ Err ( e) => {
700+ // TODO: We just silently fail here. Eventually we will need to remember
701+ // the pending requests and regularly retry opening the channel until we
702+ // succeed.
703+ log_error ! (
704+ self . logger,
705+ "Failed to open LSPS2 channel to {}: {:?}" ,
706+ their_network_key,
707+ e
708+ ) ;
709+ return ;
710+ } ,
711+ }
712+ } ,
450713 Event :: LSPS2Client ( LSPS2ClientEvent :: OpeningParametersReady {
451714 request_id,
452715 counterparty_node_id,
0 commit comments