@@ -11,7 +11,7 @@ use crate::chain::ChainSource;
11
11
use crate :: connection:: ConnectionManager ;
12
12
use crate :: logger:: { log_debug, log_error, log_info, LdkLogger , Logger } ;
13
13
use crate :: types:: { ChannelManager , KeysManager , LiquidityManager , PeerManager , Wallet } ;
14
- use crate :: { Config , Error } ;
14
+ use crate :: { total_anchor_channels_reserve_sats , Config , Error } ;
15
15
16
16
use lightning:: events:: HTLCDestination ;
17
17
use lightning:: ln:: channelmanager:: { InterceptId , MIN_FINAL_CLTV_EXPIRY_DELTA } ;
@@ -27,8 +27,8 @@ use lightning_liquidity::lsps1::client::LSPS1ClientConfig as LdkLSPS1ClientConfi
27
27
use lightning_liquidity:: lsps1:: event:: LSPS1ClientEvent ;
28
28
use lightning_liquidity:: lsps1:: msgs:: { ChannelInfo , LSPS1Options , OrderId , OrderParameters } ;
29
29
use 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 } ;
32
32
use lightning_liquidity:: lsps2:: service:: LSPS2ServiceConfig as LdkLSPS2ServiceConfig ;
33
33
use lightning_liquidity:: lsps2:: utils:: compute_opening_fee;
34
34
use lightning_liquidity:: { LiquidityClientConfig , LiquidityServiceConfig } ;
@@ -40,13 +40,21 @@ use bitcoin::secp256k1::{PublicKey, Secp256k1};
40
40
41
41
use tokio:: sync:: oneshot;
42
42
43
+ use chrono:: { DateTime , Utc } ;
44
+
45
+ use rand:: Rng ;
46
+
43
47
use std:: collections:: HashMap ;
44
48
use std:: ops:: Deref ;
45
49
use std:: sync:: { Arc , Mutex , RwLock } ;
46
50
use std:: time:: Duration ;
47
51
48
52
const LIQUIDITY_REQUEST_TIMEOUT_SECS : u64 = 5 ;
49
53
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
+
50
58
struct LSPS1Client {
51
59
lsp_node_id : PublicKey ,
52
60
lsp_address : SocketAddress ,
@@ -131,6 +139,7 @@ where
131
139
lsps1_client : Option < LSPS1Client > ,
132
140
lsps2_client : Option < LSPS2Client > ,
133
141
lsps2_service : Option < LSPS2Service > ,
142
+ wallet : Arc < Wallet > ,
134
143
channel_manager : Arc < ChannelManager > ,
135
144
keys_manager : Arc < KeysManager > ,
136
145
chain_source : Arc < ChainSource > ,
@@ -143,7 +152,7 @@ where
143
152
L :: Target : LdkLogger ,
144
153
{
145
154
pub ( crate ) fn new (
146
- channel_manager : Arc < ChannelManager > , keys_manager : Arc < KeysManager > ,
155
+ wallet : Arc < Wallet > , channel_manager : Arc < ChannelManager > , keys_manager : Arc < KeysManager > ,
147
156
chain_source : Arc < ChainSource > , config : Arc < Config > , logger : L ,
148
157
) -> Self {
149
158
let lsps1_client = None ;
@@ -153,6 +162,7 @@ where
153
162
lsps1_client,
154
163
lsps2_client,
155
164
lsps2_service,
165
+ wallet,
156
166
channel_manager,
157
167
keys_manager,
158
168
chain_source,
@@ -231,7 +241,9 @@ where
231
241
lsps1_client : self . lsps1_client ,
232
242
lsps2_client : self . lsps2_client ,
233
243
lsps2_service : self . lsps2_service ,
244
+ wallet : self . wallet ,
234
245
channel_manager : self . channel_manager ,
246
+ peer_manager : RwLock :: new ( None ) ,
235
247
keys_manager : self . keys_manager ,
236
248
liquidity_manager,
237
249
config : self . config ,
@@ -247,7 +259,9 @@ where
247
259
lsps1_client : Option < LSPS1Client > ,
248
260
lsps2_client : Option < LSPS2Client > ,
249
261
lsps2_service : Option < LSPS2Service > ,
262
+ wallet : Arc < Wallet > ,
250
263
channel_manager : Arc < ChannelManager > ,
264
+ peer_manager : RwLock < Option < Arc < PeerManager > > > ,
251
265
keys_manager : Arc < KeysManager > ,
252
266
liquidity_manager : Arc < LiquidityManager > ,
253
267
config : Arc < Config > ,
@@ -259,6 +273,7 @@ where
259
273
L :: Target : LdkLogger ,
260
274
{
261
275
pub ( crate ) fn set_peer_manager ( & self , peer_manager : Arc < PeerManager > ) {
276
+ * self . peer_manager . write ( ) . unwrap ( ) = Some ( Arc :: clone ( & peer_manager) ) ;
262
277
let process_msgs_callback = move || peer_manager. process_events ( ) ;
263
278
self . liquidity_manager . set_process_msgs_callback ( process_msgs_callback) ;
264
279
}
@@ -446,6 +461,254 @@ where
446
461
log_error ! ( self . logger, "Received unexpected LSPS1Client::OrderStatus event!" ) ;
447
462
}
448
463
} ,
464
+ Event :: LSPS2Service ( LSPS2ServiceEvent :: GetInfo {
465
+ request_id,
466
+ counterparty_node_id,
467
+ token,
468
+ } ) => {
469
+ if let Some ( lsps2_service_handler) =
470
+ self . liquidity_manager . lsps2_service_handler ( ) . as_ref ( )
471
+ {
472
+ let service_config = if let Some ( service_config) =
473
+ self . lsps2_service . as_ref ( ) . map ( |s| s. service_config . clone ( ) )
474
+ {
475
+ service_config
476
+ } else {
477
+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
478
+ return ;
479
+ } ;
480
+
481
+ if let Some ( required) = service_config. require_token {
482
+ if token != Some ( required) {
483
+ log_error ! (
484
+ self . logger,
485
+ "Rejecting LSPS2 request {:?} from counterparty {} as the client provided an invalid token." ,
486
+ request_id,
487
+ counterparty_node_id
488
+ ) ;
489
+ lsps2_service_handler. invalid_token_provided ( & counterparty_node_id, request_id. clone ( ) ) . unwrap_or_else ( |e| {
490
+ debug_assert ! ( false , "Failed to reject LSPS2 request. This should never happen." ) ;
491
+ log_error ! (
492
+ self . logger,
493
+ "Failed to reject LSPS2 request {:?} from counterparty {} due to: {:?}. This should never happen." ,
494
+ request_id,
495
+ counterparty_node_id,
496
+ e
497
+ ) ;
498
+ } ) ;
499
+ return ;
500
+ }
501
+ }
502
+
503
+ let mut valid_until: DateTime < Utc > = Utc :: now ( ) ;
504
+ valid_until += LSPS2_GETINFO_REQUEST_EXPIRY ;
505
+
506
+ let opening_fee_params = RawOpeningFeeParams {
507
+ min_fee_msat : service_config. min_channel_opening_fee_msat ,
508
+ proportional : service_config. channel_opening_fee_ppm ,
509
+ valid_until,
510
+ min_lifetime : service_config. min_channel_lifetime ,
511
+ max_client_to_self_delay : service_config. max_client_to_self_delay ,
512
+ min_payment_size_msat : service_config. min_payment_size_msat ,
513
+ max_payment_size_msat : service_config. max_payment_size_msat ,
514
+ } ;
515
+
516
+ let opening_fee_params_menu = vec ! [ opening_fee_params] ;
517
+
518
+ if let Err ( e) = lsps2_service_handler. opening_fee_params_generated (
519
+ & counterparty_node_id,
520
+ request_id,
521
+ opening_fee_params_menu,
522
+ ) {
523
+ log_error ! (
524
+ self . logger,
525
+ "Failed to handle generated opening fee params: {:?}" ,
526
+ e
527
+ ) ;
528
+ }
529
+ } else {
530
+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
531
+ return ;
532
+ }
533
+ } ,
534
+ Event :: LSPS2Service ( LSPS2ServiceEvent :: BuyRequest {
535
+ request_id,
536
+ counterparty_node_id,
537
+ opening_fee_params : _,
538
+ payment_size_msat,
539
+ } ) => {
540
+ if let Some ( lsps2_service_handler) =
541
+ self . liquidity_manager . lsps2_service_handler ( ) . as_ref ( )
542
+ {
543
+ let service_config = if let Some ( service_config) =
544
+ self . lsps2_service . as_ref ( ) . map ( |s| s. service_config . clone ( ) )
545
+ {
546
+ service_config
547
+ } else {
548
+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
549
+ return ;
550
+ } ;
551
+
552
+ let user_channel_id: u128 = rand:: thread_rng ( ) . gen :: < u128 > ( ) ;
553
+ let intercept_scid = self . channel_manager . get_intercept_scid ( ) ;
554
+
555
+ if let Some ( payment_size_msat) = payment_size_msat {
556
+ // We already check this in `lightning-liquidity`, but better safe than
557
+ // sorry.
558
+ //
559
+ // TODO: We might want to eventually send back an error here, but we
560
+ // currently can't and have to trust `lightning-liquidity` is doing the
561
+ // right thing.
562
+ //
563
+ // TODO: Eventually we also might want to make sure that we have sufficient
564
+ // liquidity for the channel opening here.
565
+ if payment_size_msat > service_config. max_payment_size_msat
566
+ || payment_size_msat < service_config. min_payment_size_msat
567
+ {
568
+ log_error ! (
569
+ self . logger,
570
+ "Rejecting to handle LSPS2 buy request {:?} from counterparty {} as the client requested an invalid payment size." ,
571
+ request_id,
572
+ counterparty_node_id
573
+ ) ;
574
+ return ;
575
+ }
576
+ }
577
+
578
+ match lsps2_service_handler. invoice_parameters_generated (
579
+ & counterparty_node_id,
580
+ request_id,
581
+ intercept_scid,
582
+ LSPS2_CHANNEL_CLTV_EXPIRY_DELTA ,
583
+ LSPS2_CLIENT_TRUSTS_LSP_MODE ,
584
+ user_channel_id,
585
+ ) {
586
+ Ok ( ( ) ) => { } ,
587
+ Err ( e) => {
588
+ log_error ! (
589
+ self . logger,
590
+ "Failed to provide invoice parameters: {:?}" ,
591
+ e
592
+ ) ;
593
+ return ;
594
+ } ,
595
+ }
596
+ } else {
597
+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
598
+ return ;
599
+ }
600
+ } ,
601
+ Event :: LSPS2Service ( LSPS2ServiceEvent :: OpenChannel {
602
+ their_network_key,
603
+ amt_to_forward_msat,
604
+ opening_fee_msat : _,
605
+ user_channel_id,
606
+ intercept_scid : _,
607
+ } ) => {
608
+ if self . liquidity_manager . lsps2_service_handler ( ) . is_none ( ) {
609
+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
610
+ return ;
611
+ } ;
612
+
613
+ let service_config = if let Some ( service_config) =
614
+ self . lsps2_service . as_ref ( ) . map ( |s| s. service_config . clone ( ) )
615
+ {
616
+ service_config
617
+ } else {
618
+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured." , ) ;
619
+ return ;
620
+ } ;
621
+
622
+ let init_features = if let Some ( peer_manager) =
623
+ self . peer_manager . read ( ) . unwrap ( ) . as_ref ( )
624
+ {
625
+ // Fail if we're not connected to the prospective channel partner.
626
+ if let Some ( peer) = peer_manager. peer_by_node_id ( & their_network_key) {
627
+ peer. init_features
628
+ } else {
629
+ // TODO: We just silently fail here. Eventually we will need to remember
630
+ // the pending requests and regularly retry opening the channel until we
631
+ // succeed.
632
+ log_error ! (
633
+ self . logger,
634
+ "Failed to open LSPS2 channel to {} due to peer not being not connected." ,
635
+ their_network_key,
636
+ ) ;
637
+ return ;
638
+ }
639
+ } else {
640
+ debug_assert ! ( false , "Failed to handle LSPS2ServiceEvent as peer manager isn't available. This should never happen." , ) ;
641
+ log_error ! ( self . logger, "Failed to handle LSPS2ServiceEvent as peer manager isn't available. This should never happen." , ) ;
642
+ return ;
643
+ } ;
644
+
645
+ // Fail if we have insufficient onchain funds available.
646
+ let over_provisioning_msat = ( amt_to_forward_msat
647
+ * service_config. channel_over_provisioning_ppm as u64 )
648
+ / 1_000_000 ;
649
+ let channel_amount_sats = ( amt_to_forward_msat + over_provisioning_msat) / 1000 ;
650
+ let cur_anchor_reserve_sats =
651
+ total_anchor_channels_reserve_sats ( & self . channel_manager , & self . config ) ;
652
+ let spendable_amount_sats =
653
+ self . wallet . get_spendable_amount_sats ( cur_anchor_reserve_sats) . unwrap_or ( 0 ) ;
654
+ let required_funds_sats = channel_amount_sats
655
+ + self . config . anchor_channels_config . as_ref ( ) . map_or ( 0 , |c| {
656
+ if init_features. requires_anchors_zero_fee_htlc_tx ( )
657
+ && !c. trusted_peers_no_reserve . contains ( & their_network_key)
658
+ {
659
+ c. per_channel_reserve_sats
660
+ } else {
661
+ 0
662
+ }
663
+ } ) ;
664
+ if spendable_amount_sats < required_funds_sats {
665
+ log_error ! ( self . logger,
666
+ "Unable to create channel due to insufficient funds. Available: {}sats, Required: {}sats" ,
667
+ spendable_amount_sats, channel_amount_sats
668
+ ) ;
669
+ // TODO: We just silently fail here. Eventually we will need to remember
670
+ // the pending requests and regularly retry opening the channel until we
671
+ // succeed.
672
+ return ;
673
+ }
674
+
675
+ let mut config = * self . channel_manager . get_current_default_configuration ( ) ;
676
+
677
+ // Set the HTLC-value-in-flight to 100% of the channel value to ensure we can
678
+ // forward the payment.
679
+ config
680
+ . channel_handshake_config
681
+ . max_inbound_htlc_value_in_flight_percent_of_channel = 100 ;
682
+
683
+ // We set the forwarding fee to 0 for now as we're getting paid by the channel fee.
684
+ //
685
+ // TODO: revisit this decision eventually.
686
+ config. channel_config . forwarding_fee_base_msat = 0 ;
687
+ config. channel_config . forwarding_fee_proportional_millionths = 0 ;
688
+
689
+ match self . channel_manager . create_channel (
690
+ their_network_key,
691
+ channel_amount_sats,
692
+ 0 ,
693
+ user_channel_id,
694
+ None ,
695
+ Some ( config) ,
696
+ ) {
697
+ Ok ( _) => { } ,
698
+ Err ( e) => {
699
+ // TODO: We just silently fail here. Eventually we will need to remember
700
+ // the pending requests and regularly retry opening the channel until we
701
+ // succeed.
702
+ log_error ! (
703
+ self . logger,
704
+ "Failed to open LSPS2 channel to {}: {:?}" ,
705
+ their_network_key,
706
+ e
707
+ ) ;
708
+ return ;
709
+ } ,
710
+ }
711
+ } ,
449
712
Event :: LSPS2Client ( LSPS2ClientEvent :: OpeningParametersReady {
450
713
request_id,
451
714
counterparty_node_id,
0 commit comments