@@ -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 ,
@@ -132,6 +140,7 @@ where
132
140
lsps1_client : Option < LSPS1Client > ,
133
141
lsps2_client : Option < LSPS2Client > ,
134
142
lsps2_service : Option < LSPS2Service > ,
143
+ wallet : Arc < Wallet > ,
135
144
channel_manager : Arc < ChannelManager > ,
136
145
keys_manager : Arc < KeysManager > ,
137
146
chain_source : Arc < ChainSource > ,
@@ -144,7 +153,7 @@ where
144
153
L :: Target : LdkLogger ,
145
154
{
146
155
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 > ,
148
157
chain_source : Arc < ChainSource > , config : Arc < Config > , logger : L ,
149
158
) -> Self {
150
159
let lsps1_client = None ;
@@ -154,6 +163,7 @@ where
154
163
lsps1_client,
155
164
lsps2_client,
156
165
lsps2_service,
166
+ wallet,
157
167
channel_manager,
158
168
keys_manager,
159
169
chain_source,
@@ -232,7 +242,9 @@ where
232
242
lsps1_client : self . lsps1_client ,
233
243
lsps2_client : self . lsps2_client ,
234
244
lsps2_service : self . lsps2_service ,
245
+ wallet : self . wallet ,
235
246
channel_manager : self . channel_manager ,
247
+ peer_manager : RwLock :: new ( None ) ,
236
248
keys_manager : self . keys_manager ,
237
249
liquidity_manager,
238
250
config : self . config ,
@@ -248,7 +260,9 @@ where
248
260
lsps1_client : Option < LSPS1Client > ,
249
261
lsps2_client : Option < LSPS2Client > ,
250
262
lsps2_service : Option < LSPS2Service > ,
263
+ wallet : Arc < Wallet > ,
251
264
channel_manager : Arc < ChannelManager > ,
265
+ peer_manager : RwLock < Option < Arc < PeerManager > > > ,
252
266
keys_manager : Arc < KeysManager > ,
253
267
liquidity_manager : Arc < LiquidityManager > ,
254
268
config : Arc < Config > ,
@@ -260,6 +274,7 @@ where
260
274
L :: Target : LdkLogger ,
261
275
{
262
276
pub ( crate ) fn set_peer_manager ( & self , peer_manager : Arc < PeerManager > ) {
277
+ * self . peer_manager . write ( ) . unwrap ( ) = Some ( Arc :: clone ( & peer_manager) ) ;
263
278
let process_msgs_callback = move || peer_manager. process_events ( ) ;
264
279
self . liquidity_manager . set_process_msgs_callback ( process_msgs_callback) ;
265
280
}
@@ -447,6 +462,254 @@ where
447
462
log_error ! ( self . logger, "Received unexpected LSPS1Client::OrderStatus event!" ) ;
448
463
}
449
464
} ,
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
+ } ,
450
713
Event :: LSPS2Client ( LSPS2ClientEvent :: OpeningParametersReady {
451
714
request_id,
452
715
counterparty_node_id,
0 commit comments