1use crate::chain::ChainSource;
11use crate::connection::ConnectionManager;
12use crate::logger::{log_debug, log_error, log_info, LdkLogger, Logger};
13use crate::types::{ChannelManager, KeysManager, LiquidityManager, PeerManager, Wallet};
14use crate::{total_anchor_channels_reserve_sats, Config, Error};
15
16use lightning::events::HTLCDestination;
17use lightning::ln::channelmanager::{InterceptId, MIN_FINAL_CLTV_EXPIRY_DELTA};
18use lightning::ln::msgs::SocketAddress;
19use lightning::ln::types::ChannelId;
20use lightning::routing::router::{RouteHint, RouteHintHop};
21
22use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, InvoiceBuilder, RoutingFees};
23
24use lightning_liquidity::events::Event;
25use lightning_liquidity::lsps0::ser::RequestId;
26use lightning_liquidity::lsps1::client::LSPS1ClientConfig as LdkLSPS1ClientConfig;
27use lightning_liquidity::lsps1::event::LSPS1ClientEvent;
28use lightning_liquidity::lsps1::msgs::{ChannelInfo, LSPS1Options, OrderId, OrderParameters};
29use lightning_liquidity::lsps2::client::LSPS2ClientConfig as LdkLSPS2ClientConfig;
30use lightning_liquidity::lsps2::event::{LSPS2ClientEvent, LSPS2ServiceEvent};
31use lightning_liquidity::lsps2::msgs::{OpeningFeeParams, RawOpeningFeeParams};
32use lightning_liquidity::lsps2::service::LSPS2ServiceConfig as LdkLSPS2ServiceConfig;
33use lightning_liquidity::lsps2::utils::compute_opening_fee;
34use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig};
35
36use lightning_types::payment::PaymentHash;
37
38use bitcoin::hashes::{sha256, Hash};
39use bitcoin::secp256k1::{PublicKey, Secp256k1};
40
41use tokio::sync::oneshot;
42
43use chrono::{DateTime, Utc};
44
45use rand::Rng;
46
47use std::collections::HashMap;
48use std::ops::Deref;
49use std::sync::{Arc, Mutex, RwLock};
50use std::time::Duration;
51
52const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;
53
54const LSPS2_GETINFO_REQUEST_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
55const LSPS2_CLIENT_TRUSTS_LSP_MODE: bool = true;
56const LSPS2_CHANNEL_CLTV_EXPIRY_DELTA: u32 = 72;
57
58struct LSPS1Client {
59 lsp_node_id: PublicKey,
60 lsp_address: SocketAddress,
61 token: Option<String>,
62 ldk_client_config: LdkLSPS1ClientConfig,
63 pending_opening_params_requests:
64 Mutex<HashMap<RequestId, oneshot::Sender<LSPS1OpeningParamsResponse>>>,
65 pending_create_order_requests: Mutex<HashMap<RequestId, oneshot::Sender<LSPS1OrderStatus>>>,
66 pending_check_order_status_requests:
67 Mutex<HashMap<RequestId, oneshot::Sender<LSPS1OrderStatus>>>,
68}
69
70#[derive(Debug, Clone)]
71pub(crate) struct LSPS1ClientConfig {
72 pub node_id: PublicKey,
73 pub address: SocketAddress,
74 pub token: Option<String>,
75}
76
77struct LSPS2Client {
78 lsp_node_id: PublicKey,
79 lsp_address: SocketAddress,
80 token: Option<String>,
81 ldk_client_config: LdkLSPS2ClientConfig,
82 pending_fee_requests: Mutex<HashMap<RequestId, oneshot::Sender<LSPS2FeeResponse>>>,
83 pending_buy_requests: Mutex<HashMap<RequestId, oneshot::Sender<LSPS2BuyResponse>>>,
84}
85
86#[derive(Debug, Clone)]
87pub(crate) struct LSPS2ClientConfig {
88 pub node_id: PublicKey,
89 pub address: SocketAddress,
90 pub token: Option<String>,
91}
92
93struct LSPS2Service {
94 service_config: LSPS2ServiceConfig,
95 ldk_service_config: LdkLSPS2ServiceConfig,
96}
97
98#[derive(Debug, Clone)]
104pub struct LSPS2ServiceConfig {
105 pub require_token: Option<String>,
109 pub advertise_service: bool,
111 pub channel_opening_fee_ppm: u32,
115 pub channel_over_provisioning_ppm: u32,
124 pub min_channel_opening_fee_msat: u64,
126 pub min_channel_lifetime: u32,
128 pub max_client_to_self_delay: u32,
130 pub min_payment_size_msat: u64,
132 pub max_payment_size_msat: u64,
134}
135
136pub(crate) struct LiquiditySourceBuilder<L: Deref>
137where
138 L::Target: LdkLogger,
139{
140 lsps1_client: Option<LSPS1Client>,
141 lsps2_client: Option<LSPS2Client>,
142 lsps2_service: Option<LSPS2Service>,
143 wallet: Arc<Wallet>,
144 channel_manager: Arc<ChannelManager>,
145 keys_manager: Arc<KeysManager>,
146 chain_source: Arc<ChainSource>,
147 config: Arc<Config>,
148 logger: L,
149}
150
151impl<L: Deref> LiquiditySourceBuilder<L>
152where
153 L::Target: LdkLogger,
154{
155 pub(crate) fn new(
156 wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>, keys_manager: Arc<KeysManager>,
157 chain_source: Arc<ChainSource>, config: Arc<Config>, logger: L,
158 ) -> Self {
159 let lsps1_client = None;
160 let lsps2_client = None;
161 let lsps2_service = None;
162 Self {
163 lsps1_client,
164 lsps2_client,
165 lsps2_service,
166 wallet,
167 channel_manager,
168 keys_manager,
169 chain_source,
170 config,
171 logger,
172 }
173 }
174
175 pub(crate) fn lsps1_client(
176 &mut self, lsp_node_id: PublicKey, lsp_address: SocketAddress, token: Option<String>,
177 ) -> &mut Self {
178 let ldk_client_config = LdkLSPS1ClientConfig { max_channel_fees_msat: None };
180 let pending_opening_params_requests = Mutex::new(HashMap::new());
181 let pending_create_order_requests = Mutex::new(HashMap::new());
182 let pending_check_order_status_requests = Mutex::new(HashMap::new());
183 self.lsps1_client = Some(LSPS1Client {
184 lsp_node_id,
185 lsp_address,
186 token,
187 ldk_client_config,
188 pending_opening_params_requests,
189 pending_create_order_requests,
190 pending_check_order_status_requests,
191 });
192 self
193 }
194
195 pub(crate) fn lsps2_client(
196 &mut self, lsp_node_id: PublicKey, lsp_address: SocketAddress, token: Option<String>,
197 ) -> &mut Self {
198 let ldk_client_config = LdkLSPS2ClientConfig {};
199 let pending_fee_requests = Mutex::new(HashMap::new());
200 let pending_buy_requests = Mutex::new(HashMap::new());
201 self.lsps2_client = Some(LSPS2Client {
202 lsp_node_id,
203 lsp_address,
204 token,
205 ldk_client_config,
206 pending_fee_requests,
207 pending_buy_requests,
208 });
209 self
210 }
211
212 pub(crate) fn lsps2_service(
213 &mut self, promise_secret: [u8; 32], service_config: LSPS2ServiceConfig,
214 ) -> &mut Self {
215 let ldk_service_config = LdkLSPS2ServiceConfig { promise_secret };
216 self.lsps2_service = Some(LSPS2Service { service_config, ldk_service_config });
217 self
218 }
219
220 pub(crate) fn build(self) -> LiquiditySource<L> {
221 let liquidity_service_config = self.lsps2_service.as_ref().map(|s| {
222 let lsps2_service_config = Some(s.ldk_service_config.clone());
223 let advertise_service = s.service_config.advertise_service;
224 LiquidityServiceConfig { lsps2_service_config, advertise_service }
225 });
226
227 let lsps1_client_config = self.lsps1_client.as_ref().map(|s| s.ldk_client_config.clone());
228 let lsps2_client_config = self.lsps2_client.as_ref().map(|s| s.ldk_client_config.clone());
229 let liquidity_client_config =
230 Some(LiquidityClientConfig { lsps1_client_config, lsps2_client_config });
231
232 let liquidity_manager = Arc::new(LiquidityManager::new(
233 Arc::clone(&self.keys_manager),
234 Arc::clone(&self.channel_manager),
235 Some(Arc::clone(&self.chain_source)),
236 None,
237 liquidity_service_config,
238 liquidity_client_config,
239 ));
240
241 LiquiditySource {
242 lsps1_client: self.lsps1_client,
243 lsps2_client: self.lsps2_client,
244 lsps2_service: self.lsps2_service,
245 wallet: self.wallet,
246 channel_manager: self.channel_manager,
247 peer_manager: RwLock::new(None),
248 keys_manager: self.keys_manager,
249 liquidity_manager,
250 config: self.config,
251 logger: self.logger,
252 }
253 }
254}
255
256pub(crate) struct LiquiditySource<L: Deref>
257where
258 L::Target: LdkLogger,
259{
260 lsps1_client: Option<LSPS1Client>,
261 lsps2_client: Option<LSPS2Client>,
262 lsps2_service: Option<LSPS2Service>,
263 wallet: Arc<Wallet>,
264 channel_manager: Arc<ChannelManager>,
265 peer_manager: RwLock<Option<Arc<PeerManager>>>,
266 keys_manager: Arc<KeysManager>,
267 liquidity_manager: Arc<LiquidityManager>,
268 config: Arc<Config>,
269 logger: L,
270}
271
272impl<L: Deref> LiquiditySource<L>
273where
274 L::Target: LdkLogger,
275{
276 pub(crate) fn set_peer_manager(&self, peer_manager: Arc<PeerManager>) {
277 *self.peer_manager.write().unwrap() = Some(Arc::clone(&peer_manager));
278 let process_msgs_callback = move || peer_manager.process_events();
279 self.liquidity_manager.set_process_msgs_callback(process_msgs_callback);
280 }
281
282 pub(crate) fn liquidity_manager(&self) -> &LiquidityManager {
283 self.liquidity_manager.as_ref()
284 }
285
286 pub(crate) fn get_lsps1_lsp_details(&self) -> Option<(PublicKey, SocketAddress)> {
287 self.lsps1_client.as_ref().map(|s| (s.lsp_node_id, s.lsp_address.clone()))
288 }
289
290 pub(crate) fn get_lsps2_lsp_details(&self) -> Option<(PublicKey, SocketAddress)> {
291 self.lsps2_client.as_ref().map(|s| (s.lsp_node_id, s.lsp_address.clone()))
292 }
293
294 pub(crate) async fn handle_next_event(&self) {
295 match self.liquidity_manager.next_event_async().await {
296 Event::LSPS1Client(LSPS1ClientEvent::SupportedOptionsReady {
297 request_id,
298 counterparty_node_id,
299 supported_options,
300 }) => {
301 if let Some(lsps1_client) = self.lsps1_client.as_ref() {
302 if counterparty_node_id != lsps1_client.lsp_node_id {
303 debug_assert!(
304 false,
305 "Received response from unexpected LSP counterparty. This should never happen."
306 );
307 log_error!(
308 self.logger,
309 "Received response from unexpected LSP counterparty. This should never happen."
310 );
311 return;
312 }
313
314 if let Some(sender) = lsps1_client
315 .pending_opening_params_requests
316 .lock()
317 .unwrap()
318 .remove(&request_id)
319 {
320 let response = LSPS1OpeningParamsResponse { supported_options };
321
322 match sender.send(response) {
323 Ok(()) => (),
324 Err(_) => {
325 log_error!(
326 self.logger,
327 "Failed to handle response for request {:?} from liquidity service",
328 request_id
329 );
330 },
331 }
332 } else {
333 debug_assert!(
334 false,
335 "Received response from liquidity service for unknown request."
336 );
337 log_error!(
338 self.logger,
339 "Received response from liquidity service for unknown request."
340 );
341 }
342 } else {
343 log_error!(
344 self.logger,
345 "Received unexpected LSPS1Client::SupportedOptionsReady event!"
346 );
347 }
348 },
349 Event::LSPS1Client(LSPS1ClientEvent::OrderCreated {
350 request_id,
351 counterparty_node_id,
352 order_id,
353 order,
354 payment,
355 channel,
356 }) => {
357 if let Some(lsps1_client) = self.lsps1_client.as_ref() {
358 if counterparty_node_id != lsps1_client.lsp_node_id {
359 debug_assert!(
360 false,
361 "Received response from unexpected LSP counterparty. This should never happen."
362 );
363 log_error!(
364 self.logger,
365 "Received response from unexpected LSP counterparty. This should never happen."
366 );
367 return;
368 }
369
370 if let Some(sender) = lsps1_client
371 .pending_create_order_requests
372 .lock()
373 .unwrap()
374 .remove(&request_id)
375 {
376 let response = LSPS1OrderStatus {
377 order_id,
378 order_params: order,
379 payment_options: payment.into(),
380 channel_state: channel,
381 };
382
383 match sender.send(response) {
384 Ok(()) => (),
385 Err(_) => {
386 log_error!(
387 self.logger,
388 "Failed to handle response for request {:?} from liquidity service",
389 request_id
390 );
391 },
392 }
393 } else {
394 debug_assert!(
395 false,
396 "Received response from liquidity service for unknown request."
397 );
398 log_error!(
399 self.logger,
400 "Received response from liquidity service for unknown request."
401 );
402 }
403 } else {
404 log_error!(self.logger, "Received unexpected LSPS1Client::OrderCreated event!");
405 }
406 },
407 Event::LSPS1Client(LSPS1ClientEvent::OrderStatus {
408 request_id,
409 counterparty_node_id,
410 order_id,
411 order,
412 payment,
413 channel,
414 }) => {
415 if let Some(lsps1_client) = self.lsps1_client.as_ref() {
416 if counterparty_node_id != lsps1_client.lsp_node_id {
417 debug_assert!(
418 false,
419 "Received response from unexpected LSP counterparty. This should never happen."
420 );
421 log_error!(
422 self.logger,
423 "Received response from unexpected LSP counterparty. This should never happen."
424 );
425 return;
426 }
427
428 if let Some(sender) = lsps1_client
429 .pending_check_order_status_requests
430 .lock()
431 .unwrap()
432 .remove(&request_id)
433 {
434 let response = LSPS1OrderStatus {
435 order_id,
436 order_params: order,
437 payment_options: payment.into(),
438 channel_state: channel,
439 };
440
441 match sender.send(response) {
442 Ok(()) => (),
443 Err(_) => {
444 log_error!(
445 self.logger,
446 "Failed to handle response for request {:?} from liquidity service",
447 request_id
448 );
449 },
450 }
451 } else {
452 debug_assert!(
453 false,
454 "Received response from liquidity service for unknown request."
455 );
456 log_error!(
457 self.logger,
458 "Received response from liquidity service for unknown request."
459 );
460 }
461 } else {
462 log_error!(self.logger, "Received unexpected LSPS1Client::OrderStatus event!");
463 }
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 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 if let Some(peer) = peer_manager.peer_by_node_id(&their_network_key) {
628 peer.init_features
629 } else {
630 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 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 return;
674 }
675
676 let mut config = *self.channel_manager.get_current_default_configuration();
677
678 debug_assert_eq!(
680 config
681 .channel_handshake_config
682 .max_inbound_htlc_value_in_flight_percent_of_channel,
683 100
684 );
685 debug_assert!(config.accept_forwards_to_priv_channels);
686
687 config.channel_config.forwarding_fee_base_msat = 0;
691 config.channel_config.forwarding_fee_proportional_millionths = 0;
692
693 match self.channel_manager.create_channel(
694 their_network_key,
695 channel_amount_sats,
696 0,
697 user_channel_id,
698 None,
699 Some(config),
700 ) {
701 Ok(_) => {},
702 Err(e) => {
703 log_error!(
707 self.logger,
708 "Failed to open LSPS2 channel to {}: {:?}",
709 their_network_key,
710 e
711 );
712 return;
713 },
714 }
715 },
716 Event::LSPS2Client(LSPS2ClientEvent::OpeningParametersReady {
717 request_id,
718 counterparty_node_id,
719 opening_fee_params_menu,
720 }) => {
721 if let Some(lsps2_client) = self.lsps2_client.as_ref() {
722 if counterparty_node_id != lsps2_client.lsp_node_id {
723 debug_assert!(
724 false,
725 "Received response from unexpected LSP counterparty. This should never happen."
726 );
727 log_error!(
728 self.logger,
729 "Received response from unexpected LSP counterparty. This should never happen."
730 );
731 return;
732 }
733
734 if let Some(sender) =
735 lsps2_client.pending_fee_requests.lock().unwrap().remove(&request_id)
736 {
737 let response = LSPS2FeeResponse { opening_fee_params_menu };
738
739 match sender.send(response) {
740 Ok(()) => (),
741 Err(_) => {
742 log_error!(
743 self.logger,
744 "Failed to handle response for request {:?} from liquidity service",
745 request_id
746 );
747 },
748 }
749 } else {
750 debug_assert!(
751 false,
752 "Received response from liquidity service for unknown request."
753 );
754 log_error!(
755 self.logger,
756 "Received response from liquidity service for unknown request."
757 );
758 }
759 } else {
760 log_error!(
761 self.logger,
762 "Received unexpected LSPS2Client::OpeningParametersReady event!"
763 );
764 }
765 },
766 Event::LSPS2Client(LSPS2ClientEvent::InvoiceParametersReady {
767 request_id,
768 counterparty_node_id,
769 intercept_scid,
770 cltv_expiry_delta,
771 ..
772 }) => {
773 if let Some(lsps2_client) = self.lsps2_client.as_ref() {
774 if counterparty_node_id != lsps2_client.lsp_node_id {
775 debug_assert!(
776 false,
777 "Received response from unexpected LSP counterparty. This should never happen."
778 );
779 log_error!(
780 self.logger,
781 "Received response from unexpected LSP counterparty. This should never happen."
782 );
783 return;
784 }
785
786 if let Some(sender) =
787 lsps2_client.pending_buy_requests.lock().unwrap().remove(&request_id)
788 {
789 let response = LSPS2BuyResponse { intercept_scid, cltv_expiry_delta };
790
791 match sender.send(response) {
792 Ok(()) => (),
793 Err(_) => {
794 log_error!(
795 self.logger,
796 "Failed to handle response for request {:?} from liquidity service",
797 request_id
798 );
799 },
800 }
801 } else {
802 debug_assert!(
803 false,
804 "Received response from liquidity service for unknown request."
805 );
806 log_error!(
807 self.logger,
808 "Received response from liquidity service for unknown request."
809 );
810 }
811 } else {
812 log_error!(
813 self.logger,
814 "Received unexpected LSPS2Client::InvoiceParametersReady event!"
815 );
816 }
817 },
818 e => {
819 log_error!(self.logger, "Received unexpected liquidity event: {:?}", e);
820 },
821 }
822 }
823
824 pub(crate) async fn lsps1_request_opening_params(
825 &self,
826 ) -> Result<LSPS1OpeningParamsResponse, Error> {
827 let lsps1_client = self.lsps1_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
828
829 let client_handler = self.liquidity_manager.lsps1_client_handler().ok_or_else(|| {
830 log_error!(self.logger, "LSPS1 liquidity client was not configured.",);
831 Error::LiquiditySourceUnavailable
832 })?;
833
834 let (request_sender, request_receiver) = oneshot::channel();
835 {
836 let mut pending_opening_params_requests_lock =
837 lsps1_client.pending_opening_params_requests.lock().unwrap();
838 let request_id = client_handler.request_supported_options(lsps1_client.lsp_node_id);
839 pending_opening_params_requests_lock.insert(request_id, request_sender);
840 }
841
842 tokio::time::timeout(Duration::from_secs(LIQUIDITY_REQUEST_TIMEOUT_SECS), request_receiver)
843 .await
844 .map_err(|e| {
845 log_error!(self.logger, "Liquidity request timed out: {}", e);
846 Error::LiquidityRequestFailed
847 })?
848 .map_err(|e| {
849 log_error!(self.logger, "Failed to handle response from liquidity service: {}", e);
850 Error::LiquidityRequestFailed
851 })
852 }
853
854 pub(crate) async fn lsps1_request_channel(
855 &self, lsp_balance_sat: u64, client_balance_sat: u64, channel_expiry_blocks: u32,
856 announce_channel: bool, refund_address: bitcoin::Address,
857 ) -> Result<LSPS1OrderStatus, Error> {
858 let lsps1_client = self.lsps1_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
859 let client_handler = self.liquidity_manager.lsps1_client_handler().ok_or_else(|| {
860 log_error!(self.logger, "LSPS1 liquidity client was not configured.",);
861 Error::LiquiditySourceUnavailable
862 })?;
863
864 let lsp_limits = self.lsps1_request_opening_params().await?.supported_options;
865 let channel_size_sat = lsp_balance_sat + client_balance_sat;
866
867 if channel_size_sat < lsp_limits.min_channel_balance_sat
868 || channel_size_sat > lsp_limits.max_channel_balance_sat
869 {
870 log_error!(
871 self.logger,
872 "Requested channel size of {}sat doesn't meet the LSP-provided limits (min: {}sat, max: {}sat).",
873 channel_size_sat,
874 lsp_limits.min_channel_balance_sat,
875 lsp_limits.max_channel_balance_sat
876 );
877 return Err(Error::LiquidityRequestFailed);
878 }
879
880 if lsp_balance_sat < lsp_limits.min_initial_lsp_balance_sat
881 || lsp_balance_sat > lsp_limits.max_initial_lsp_balance_sat
882 {
883 log_error!(
884 self.logger,
885 "Requested LSP-side balance of {}sat doesn't meet the LSP-provided limits (min: {}sat, max: {}sat).",
886 lsp_balance_sat,
887 lsp_limits.min_initial_lsp_balance_sat,
888 lsp_limits.max_initial_lsp_balance_sat
889 );
890 return Err(Error::LiquidityRequestFailed);
891 }
892
893 if client_balance_sat < lsp_limits.min_initial_client_balance_sat
894 || client_balance_sat > lsp_limits.max_initial_client_balance_sat
895 {
896 log_error!(
897 self.logger,
898 "Requested client-side balance of {}sat doesn't meet the LSP-provided limits (min: {}sat, max: {}sat).",
899 client_balance_sat,
900 lsp_limits.min_initial_client_balance_sat,
901 lsp_limits.max_initial_client_balance_sat
902 );
903 return Err(Error::LiquidityRequestFailed);
904 }
905
906 let order_params = OrderParameters {
907 lsp_balance_sat,
908 client_balance_sat,
909 required_channel_confirmations: lsp_limits.min_required_channel_confirmations,
910 funding_confirms_within_blocks: lsp_limits.min_funding_confirms_within_blocks,
911 channel_expiry_blocks,
912 token: lsps1_client.token.clone(),
913 announce_channel,
914 };
915
916 let (request_sender, request_receiver) = oneshot::channel();
917 let request_id;
918 {
919 let mut pending_create_order_requests_lock =
920 lsps1_client.pending_create_order_requests.lock().unwrap();
921 request_id = client_handler.create_order(
922 &lsps1_client.lsp_node_id,
923 order_params.clone(),
924 Some(refund_address),
925 );
926 pending_create_order_requests_lock.insert(request_id.clone(), request_sender);
927 }
928
929 let response = tokio::time::timeout(
930 Duration::from_secs(LIQUIDITY_REQUEST_TIMEOUT_SECS),
931 request_receiver,
932 )
933 .await
934 .map_err(|e| {
935 log_error!(self.logger, "Liquidity request with ID {:?} timed out: {}", request_id, e);
936 Error::LiquidityRequestFailed
937 })?
938 .map_err(|e| {
939 log_error!(self.logger, "Failed to handle response from liquidity service: {}", e);
940 Error::LiquidityRequestFailed
941 })?;
942
943 if response.order_params != order_params {
944 log_error!(
945 self.logger,
946 "Aborting LSPS1 request as LSP-provided parameters don't match our order. Expected: {:?}, Received: {:?}", order_params, response.order_params
947 );
948 return Err(Error::LiquidityRequestFailed);
949 }
950
951 Ok(response)
952 }
953
954 pub(crate) async fn lsps1_check_order_status(
955 &self, order_id: OrderId,
956 ) -> Result<LSPS1OrderStatus, Error> {
957 let lsps1_client = self.lsps1_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
958 let client_handler = self.liquidity_manager.lsps1_client_handler().ok_or_else(|| {
959 log_error!(self.logger, "LSPS1 liquidity client was not configured.",);
960 Error::LiquiditySourceUnavailable
961 })?;
962
963 let (request_sender, request_receiver) = oneshot::channel();
964 {
965 let mut pending_check_order_status_requests_lock =
966 lsps1_client.pending_check_order_status_requests.lock().unwrap();
967 let request_id = client_handler.check_order_status(&lsps1_client.lsp_node_id, order_id);
968 pending_check_order_status_requests_lock.insert(request_id, request_sender);
969 }
970
971 let response = tokio::time::timeout(
972 Duration::from_secs(LIQUIDITY_REQUEST_TIMEOUT_SECS),
973 request_receiver,
974 )
975 .await
976 .map_err(|e| {
977 log_error!(self.logger, "Liquidity request timed out: {}", e);
978 Error::LiquidityRequestFailed
979 })?
980 .map_err(|e| {
981 log_error!(self.logger, "Failed to handle response from liquidity service: {}", e);
982 Error::LiquidityRequestFailed
983 })?;
984
985 Ok(response)
986 }
987
988 pub(crate) async fn lsps2_receive_to_jit_channel(
989 &self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
990 max_total_lsp_fee_limit_msat: Option<u64>,
991 ) -> Result<(Bolt11Invoice, u64), Error> {
992 let fee_response = self.lsps2_request_opening_fee_params().await?;
993
994 let (min_total_fee_msat, min_opening_params) = fee_response
995 .opening_fee_params_menu
996 .into_iter()
997 .filter_map(|params| {
998 if amount_msat < params.min_payment_size_msat
999 || amount_msat > params.max_payment_size_msat
1000 {
1001 log_debug!(self.logger,
1002 "Skipping LSP-offered JIT parameters as the payment of {}msat doesn't meet LSP limits (min: {}msat, max: {}msat)",
1003 amount_msat,
1004 params.min_payment_size_msat,
1005 params.max_payment_size_msat
1006 );
1007 None
1008 } else {
1009 compute_opening_fee(amount_msat, params.min_fee_msat, params.proportional as u64)
1010 .map(|fee| (fee, params))
1011 }
1012 })
1013 .min_by_key(|p| p.0)
1014 .ok_or_else(|| {
1015 log_error!(self.logger, "Failed to handle response from liquidity service",);
1016 Error::LiquidityRequestFailed
1017 })?;
1018
1019 if let Some(max_total_lsp_fee_limit_msat) = max_total_lsp_fee_limit_msat {
1020 if min_total_fee_msat > max_total_lsp_fee_limit_msat {
1021 log_error!(self.logger,
1022 "Failed to request inbound JIT channel as LSP's requested total opening fee of {}msat exceeds our fee limit of {}msat",
1023 min_total_fee_msat, max_total_lsp_fee_limit_msat
1024 );
1025 return Err(Error::LiquidityFeeTooHigh);
1026 }
1027 }
1028
1029 log_debug!(
1030 self.logger,
1031 "Choosing cheapest liquidity offer, will pay {}msat in total LSP fees",
1032 min_total_fee_msat
1033 );
1034
1035 let buy_response =
1036 self.lsps2_send_buy_request(Some(amount_msat), min_opening_params).await?;
1037 let invoice = self.lsps2_create_jit_invoice(
1038 buy_response,
1039 Some(amount_msat),
1040 description,
1041 expiry_secs,
1042 )?;
1043
1044 log_info!(self.logger, "JIT-channel invoice created: {}", invoice);
1045 Ok((invoice, min_total_fee_msat))
1046 }
1047
1048 pub(crate) async fn lsps2_receive_variable_amount_to_jit_channel(
1049 &self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
1050 max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
1051 ) -> Result<(Bolt11Invoice, u64), Error> {
1052 let fee_response = self.lsps2_request_opening_fee_params().await?;
1053
1054 let (min_prop_fee_ppm_msat, min_opening_params) = fee_response
1055 .opening_fee_params_menu
1056 .into_iter()
1057 .map(|params| (params.proportional as u64, params))
1058 .min_by_key(|p| p.0)
1059 .ok_or_else(|| {
1060 log_error!(self.logger, "Failed to handle response from liquidity service",);
1061 Error::LiquidityRequestFailed
1062 })?;
1063
1064 if let Some(max_proportional_lsp_fee_limit_ppm_msat) =
1065 max_proportional_lsp_fee_limit_ppm_msat
1066 {
1067 if min_prop_fee_ppm_msat > max_proportional_lsp_fee_limit_ppm_msat {
1068 log_error!(self.logger,
1069 "Failed to request inbound JIT channel as LSP's requested proportional opening fee of {} ppm msat exceeds our fee limit of {} ppm msat",
1070 min_prop_fee_ppm_msat,
1071 max_proportional_lsp_fee_limit_ppm_msat
1072 );
1073 return Err(Error::LiquidityFeeTooHigh);
1074 }
1075 }
1076
1077 log_debug!(
1078 self.logger,
1079 "Choosing cheapest liquidity offer, will pay {}ppm msat in proportional LSP fees",
1080 min_prop_fee_ppm_msat
1081 );
1082
1083 let buy_response = self.lsps2_send_buy_request(None, min_opening_params).await?;
1084 let invoice =
1085 self.lsps2_create_jit_invoice(buy_response, None, description, expiry_secs)?;
1086
1087 log_info!(self.logger, "JIT-channel invoice created: {}", invoice);
1088 Ok((invoice, min_prop_fee_ppm_msat))
1089 }
1090
1091 async fn lsps2_request_opening_fee_params(&self) -> Result<LSPS2FeeResponse, Error> {
1092 let lsps2_client = self.lsps2_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1093
1094 let client_handler = self.liquidity_manager.lsps2_client_handler().ok_or_else(|| {
1095 log_error!(self.logger, "Liquidity client was not configured.",);
1096 Error::LiquiditySourceUnavailable
1097 })?;
1098
1099 let (fee_request_sender, fee_request_receiver) = oneshot::channel();
1100 {
1101 let mut pending_fee_requests_lock = lsps2_client.pending_fee_requests.lock().unwrap();
1102 let request_id = client_handler
1103 .request_opening_params(lsps2_client.lsp_node_id, lsps2_client.token.clone());
1104 pending_fee_requests_lock.insert(request_id, fee_request_sender);
1105 }
1106
1107 tokio::time::timeout(
1108 Duration::from_secs(LIQUIDITY_REQUEST_TIMEOUT_SECS),
1109 fee_request_receiver,
1110 )
1111 .await
1112 .map_err(|e| {
1113 log_error!(self.logger, "Liquidity request timed out: {}", e);
1114 Error::LiquidityRequestFailed
1115 })?
1116 .map_err(|e| {
1117 log_error!(self.logger, "Failed to handle response from liquidity service: {}", e);
1118 Error::LiquidityRequestFailed
1119 })
1120 }
1121
1122 async fn lsps2_send_buy_request(
1123 &self, amount_msat: Option<u64>, opening_fee_params: OpeningFeeParams,
1124 ) -> Result<LSPS2BuyResponse, Error> {
1125 let lsps2_client = self.lsps2_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1126
1127 let client_handler = self.liquidity_manager.lsps2_client_handler().ok_or_else(|| {
1128 log_error!(self.logger, "Liquidity client was not configured.",);
1129 Error::LiquiditySourceUnavailable
1130 })?;
1131
1132 let (buy_request_sender, buy_request_receiver) = oneshot::channel();
1133 {
1134 let mut pending_buy_requests_lock = lsps2_client.pending_buy_requests.lock().unwrap();
1135 let request_id = client_handler
1136 .select_opening_params(lsps2_client.lsp_node_id, amount_msat, opening_fee_params)
1137 .map_err(|e| {
1138 log_error!(
1139 self.logger,
1140 "Failed to send buy request to liquidity service: {:?}",
1141 e
1142 );
1143 Error::LiquidityRequestFailed
1144 })?;
1145 pending_buy_requests_lock.insert(request_id, buy_request_sender);
1146 }
1147
1148 let buy_response = tokio::time::timeout(
1149 Duration::from_secs(LIQUIDITY_REQUEST_TIMEOUT_SECS),
1150 buy_request_receiver,
1151 )
1152 .await
1153 .map_err(|e| {
1154 log_error!(self.logger, "Liquidity request timed out: {}", e);
1155 Error::LiquidityRequestFailed
1156 })?
1157 .map_err(|e| {
1158 log_error!(self.logger, "Failed to handle response from liquidity service: {:?}", e);
1159 Error::LiquidityRequestFailed
1160 })?;
1161
1162 Ok(buy_response)
1163 }
1164
1165 fn lsps2_create_jit_invoice(
1166 &self, buy_response: LSPS2BuyResponse, amount_msat: Option<u64>,
1167 description: &Bolt11InvoiceDescription, expiry_secs: u32,
1168 ) -> Result<Bolt11Invoice, Error> {
1169 let lsps2_client = self.lsps2_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1170
1171 let min_final_cltv_expiry_delta = MIN_FINAL_CLTV_EXPIRY_DELTA + 2;
1173 let (payment_hash, payment_secret) = self
1174 .channel_manager
1175 .create_inbound_payment(None, expiry_secs, Some(min_final_cltv_expiry_delta))
1176 .map_err(|e| {
1177 log_error!(self.logger, "Failed to register inbound payment: {:?}", e);
1178 Error::InvoiceCreationFailed
1179 })?;
1180
1181 let route_hint = RouteHint(vec![RouteHintHop {
1182 src_node_id: lsps2_client.lsp_node_id,
1183 short_channel_id: buy_response.intercept_scid,
1184 fees: RoutingFees { base_msat: 0, proportional_millionths: 0 },
1185 cltv_expiry_delta: buy_response.cltv_expiry_delta as u16,
1186 htlc_minimum_msat: None,
1187 htlc_maximum_msat: None,
1188 }]);
1189
1190 let payment_hash = sha256::Hash::from_slice(&payment_hash.0).map_err(|e| {
1191 log_error!(self.logger, "Invalid payment hash: {:?}", e);
1192 Error::InvoiceCreationFailed
1193 })?;
1194
1195 let currency = self.config.network.into();
1196 let mut invoice_builder = InvoiceBuilder::new(currency)
1197 .invoice_description(description.clone())
1198 .payment_hash(payment_hash)
1199 .payment_secret(payment_secret)
1200 .current_timestamp()
1201 .min_final_cltv_expiry_delta(min_final_cltv_expiry_delta.into())
1202 .expiry_time(Duration::from_secs(expiry_secs.into()))
1203 .private_route(route_hint);
1204
1205 if let Some(amount_msat) = amount_msat {
1206 invoice_builder = invoice_builder.amount_milli_satoshis(amount_msat).basic_mpp();
1207 }
1208
1209 invoice_builder
1210 .build_signed(|hash| {
1211 Secp256k1::new()
1212 .sign_ecdsa_recoverable(hash, &self.keys_manager.get_node_secret_key())
1213 })
1214 .map_err(|e| {
1215 log_error!(self.logger, "Failed to build and sign invoice: {}", e);
1216 Error::InvoiceCreationFailed
1217 })
1218 }
1219
1220 pub(crate) fn handle_channel_ready(
1221 &self, user_channel_id: u128, channel_id: &ChannelId, counterparty_node_id: &PublicKey,
1222 ) {
1223 if let Some(lsps2_service_handler) = self.liquidity_manager.lsps2_service_handler() {
1224 if let Err(e) = lsps2_service_handler.channel_ready(
1225 user_channel_id,
1226 channel_id,
1227 counterparty_node_id,
1228 ) {
1229 log_error!(
1230 self.logger,
1231 "LSPS2 service failed to handle ChannelReady event: {:?}",
1232 e
1233 );
1234 }
1235 }
1236 }
1237
1238 pub(crate) fn handle_htlc_intercepted(
1239 &self, intercept_scid: u64, intercept_id: InterceptId, expected_outbound_amount_msat: u64,
1240 payment_hash: PaymentHash,
1241 ) {
1242 if let Some(lsps2_service_handler) = self.liquidity_manager.lsps2_service_handler() {
1243 if let Err(e) = lsps2_service_handler.htlc_intercepted(
1244 intercept_scid,
1245 intercept_id,
1246 expected_outbound_amount_msat,
1247 payment_hash,
1248 ) {
1249 log_error!(
1250 self.logger,
1251 "LSPS2 service failed to handle HTLCIntercepted event: {:?}",
1252 e
1253 );
1254 }
1255 }
1256 }
1257
1258 pub(crate) fn handle_htlc_handling_failed(&self, failed_next_destination: HTLCDestination) {
1259 if let Some(lsps2_service_handler) = self.liquidity_manager.lsps2_service_handler() {
1260 if let Err(e) = lsps2_service_handler.htlc_handling_failed(failed_next_destination) {
1261 log_error!(
1262 self.logger,
1263 "LSPS2 service failed to handle HTLCHandlingFailed event: {:?}",
1264 e
1265 );
1266 }
1267 }
1268 }
1269
1270 pub(crate) fn handle_payment_forwarded(&self, next_channel_id: Option<ChannelId>) {
1271 if let Some(next_channel_id) = next_channel_id {
1272 if let Some(lsps2_service_handler) = self.liquidity_manager.lsps2_service_handler() {
1273 if let Err(e) = lsps2_service_handler.payment_forwarded(next_channel_id) {
1274 log_error!(
1275 self.logger,
1276 "LSPS2 service failed to handle PaymentForwarded: {:?}",
1277 e
1278 );
1279 }
1280 }
1281 }
1282 }
1283}
1284
1285#[derive(Debug, Clone)]
1286pub(crate) struct LSPS1OpeningParamsResponse {
1287 supported_options: LSPS1Options,
1288}
1289
1290#[derive(Debug, Clone)]
1292pub struct LSPS1OrderStatus {
1293 pub order_id: OrderId,
1295 pub order_params: OrderParameters,
1297 pub payment_options: PaymentInfo,
1299 pub channel_state: Option<ChannelInfo>,
1301}
1302
1303#[cfg(not(feature = "uniffi"))]
1304type PaymentInfo = lightning_liquidity::lsps1::msgs::PaymentInfo;
1305
1306#[cfg(feature = "uniffi")]
1308#[derive(Clone, Debug, PartialEq, Eq)]
1309pub struct PaymentInfo {
1310 pub bolt11: Option<crate::uniffi_types::Bolt11PaymentInfo>,
1312 pub onchain: Option<OnchainPaymentInfo>,
1314}
1315
1316#[cfg(feature = "uniffi")]
1317impl From<lightning_liquidity::lsps1::msgs::PaymentInfo> for PaymentInfo {
1318 fn from(value: lightning_liquidity::lsps1::msgs::PaymentInfo) -> Self {
1319 PaymentInfo {
1320 bolt11: value.bolt11.map(|b| b.into()),
1321 onchain: value.onchain.map(|o| o.into()),
1322 }
1323 }
1324}
1325
1326#[cfg(feature = "uniffi")]
1328#[derive(Clone, Debug, PartialEq, Eq)]
1329pub struct OnchainPaymentInfo {
1330 pub state: lightning_liquidity::lsps1::msgs::PaymentState,
1332 pub expires_at: chrono::DateTime<chrono::Utc>,
1334 pub fee_total_sat: u64,
1336 pub order_total_sat: u64,
1338 pub address: bitcoin::Address,
1341 pub min_onchain_payment_confirmations: Option<u16>,
1344 pub min_fee_for_0conf: Arc<bitcoin::FeeRate>,
1347 pub refund_onchain_address: Option<bitcoin::Address>,
1349}
1350
1351#[cfg(feature = "uniffi")]
1352impl From<lightning_liquidity::lsps1::msgs::OnchainPaymentInfo> for OnchainPaymentInfo {
1353 fn from(value: lightning_liquidity::lsps1::msgs::OnchainPaymentInfo) -> Self {
1354 Self {
1355 state: value.state,
1356 expires_at: value.expires_at,
1357 fee_total_sat: value.fee_total_sat,
1358 order_total_sat: value.order_total_sat,
1359 address: value.address,
1360 min_onchain_payment_confirmations: value.min_onchain_payment_confirmations,
1361 min_fee_for_0conf: Arc::new(value.min_fee_for_0conf),
1362 refund_onchain_address: value.refund_onchain_address,
1363 }
1364 }
1365}
1366
1367#[derive(Debug, Clone)]
1368pub(crate) struct LSPS2FeeResponse {
1369 opening_fee_params_menu: Vec<OpeningFeeParams>,
1370}
1371
1372#[derive(Debug, Clone)]
1373pub(crate) struct LSPS2BuyResponse {
1374 intercept_scid: u64,
1375 cltv_expiry_delta: u32,
1376}
1377
1378#[derive(Clone)]
1390pub struct LSPS1Liquidity {
1391 runtime: Arc<RwLock<Option<Arc<tokio::runtime::Runtime>>>>,
1392 wallet: Arc<Wallet>,
1393 connection_manager: Arc<ConnectionManager<Arc<Logger>>>,
1394 liquidity_source: Option<Arc<LiquiditySource<Arc<Logger>>>>,
1395 logger: Arc<Logger>,
1396}
1397
1398impl LSPS1Liquidity {
1399 pub(crate) fn new(
1400 runtime: Arc<RwLock<Option<Arc<tokio::runtime::Runtime>>>>, wallet: Arc<Wallet>,
1401 connection_manager: Arc<ConnectionManager<Arc<Logger>>>,
1402 liquidity_source: Option<Arc<LiquiditySource<Arc<Logger>>>>, logger: Arc<Logger>,
1403 ) -> Self {
1404 Self { runtime, wallet, connection_manager, liquidity_source, logger }
1405 }
1406
1407 pub fn request_channel(
1412 &self, lsp_balance_sat: u64, client_balance_sat: u64, channel_expiry_blocks: u32,
1413 announce_channel: bool,
1414 ) -> Result<LSPS1OrderStatus, Error> {
1415 let liquidity_source =
1416 self.liquidity_source.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1417
1418 let (lsp_node_id, lsp_address) =
1419 liquidity_source.get_lsps1_lsp_details().ok_or(Error::LiquiditySourceUnavailable)?;
1420
1421 let rt_lock = self.runtime.read().unwrap();
1422 let runtime = rt_lock.as_ref().unwrap();
1423
1424 let con_node_id = lsp_node_id;
1425 let con_addr = lsp_address.clone();
1426 let con_cm = Arc::clone(&self.connection_manager);
1427
1428 tokio::task::block_in_place(move || {
1431 runtime.block_on(async move {
1432 con_cm.connect_peer_if_necessary(con_node_id, con_addr).await
1433 })
1434 })?;
1435
1436 log_info!(self.logger, "Connected to LSP {}@{}. ", lsp_node_id, lsp_address);
1437
1438 let refund_address = self.wallet.get_new_address()?;
1439
1440 let liquidity_source = Arc::clone(&liquidity_source);
1441 let response = tokio::task::block_in_place(move || {
1442 runtime.block_on(async move {
1443 liquidity_source
1444 .lsps1_request_channel(
1445 lsp_balance_sat,
1446 client_balance_sat,
1447 channel_expiry_blocks,
1448 announce_channel,
1449 refund_address,
1450 )
1451 .await
1452 })
1453 })?;
1454
1455 Ok(response)
1456 }
1457
1458 pub fn check_order_status(&self, order_id: OrderId) -> Result<LSPS1OrderStatus, Error> {
1460 let liquidity_source =
1461 self.liquidity_source.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1462
1463 let (lsp_node_id, lsp_address) =
1464 liquidity_source.get_lsps1_lsp_details().ok_or(Error::LiquiditySourceUnavailable)?;
1465
1466 let rt_lock = self.runtime.read().unwrap();
1467 let runtime = rt_lock.as_ref().unwrap();
1468
1469 let con_node_id = lsp_node_id;
1470 let con_addr = lsp_address.clone();
1471 let con_cm = Arc::clone(&self.connection_manager);
1472
1473 tokio::task::block_in_place(move || {
1476 runtime.block_on(async move {
1477 con_cm.connect_peer_if_necessary(con_node_id, con_addr).await
1478 })
1479 })?;
1480
1481 let liquidity_source = Arc::clone(&liquidity_source);
1482 let response = tokio::task::block_in_place(move || {
1483 runtime
1484 .block_on(async move { liquidity_source.lsps1_check_order_status(order_id).await })
1485 })?;
1486
1487 Ok(response)
1488 }
1489}