1use std::collections::HashMap;
11use std::ops::Deref;
12use std::sync::{Arc, Mutex, RwLock};
13use std::time::Duration;
14
15use bitcoin::hashes::{sha256, Hash};
16use bitcoin::secp256k1::{PublicKey, Secp256k1};
17use bitcoin::Transaction;
18use chrono::Utc;
19use lightning::events::HTLCHandlingFailureType;
20use lightning::ln::channelmanager::{InterceptId, MIN_FINAL_CLTV_EXPIRY_DELTA};
21use lightning::ln::msgs::SocketAddress;
22use lightning::ln::types::ChannelId;
23use lightning::routing::router::{RouteHint, RouteHintHop};
24use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, InvoiceBuilder, RoutingFees};
25use lightning_liquidity::events::LiquidityEvent;
26use lightning_liquidity::lsps0::ser::{LSPSDateTime, LSPSRequestId};
27use lightning_liquidity::lsps1::client::LSPS1ClientConfig as LdkLSPS1ClientConfig;
28use lightning_liquidity::lsps1::event::LSPS1ClientEvent;
29use lightning_liquidity::lsps1::msgs::{
30 LSPS1ChannelInfo, LSPS1Options, LSPS1OrderId, LSPS1OrderParams,
31};
32use lightning_liquidity::lsps2::client::LSPS2ClientConfig as LdkLSPS2ClientConfig;
33use lightning_liquidity::lsps2::event::{LSPS2ClientEvent, LSPS2ServiceEvent};
34use lightning_liquidity::lsps2::msgs::{LSPS2OpeningFeeParams, LSPS2RawOpeningFeeParams};
35use lightning_liquidity::lsps2::service::LSPS2ServiceConfig as LdkLSPS2ServiceConfig;
36use lightning_liquidity::lsps2::utils::compute_opening_fee;
37use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig};
38use lightning_types::payment::PaymentHash;
39use rand::Rng;
40use tokio::sync::oneshot;
41
42use crate::builder::BuildError;
43use crate::chain::ChainSource;
44use crate::connection::ConnectionManager;
45use crate::logger::{log_debug, log_error, log_info, LdkLogger, Logger};
46use crate::runtime::Runtime;
47use crate::types::{
48 Broadcaster, ChannelManager, DynStore, KeysManager, LiquidityManager, PeerManager, Wallet,
49};
50use crate::{total_anchor_channels_reserve_sats, Config, Error};
51
52const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;
53
54const LSPS2_GETINFO_REQUEST_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
55const LSPS2_CHANNEL_CLTV_EXPIRY_DELTA: u32 = 72;
56
57struct LSPS1Client {
58 lsp_node_id: PublicKey,
59 lsp_address: SocketAddress,
60 token: Option<String>,
61 ldk_client_config: LdkLSPS1ClientConfig,
62 pending_opening_params_requests:
63 Mutex<HashMap<LSPSRequestId, oneshot::Sender<LSPS1OpeningParamsResponse>>>,
64 pending_create_order_requests: Mutex<HashMap<LSPSRequestId, oneshot::Sender<LSPS1OrderStatus>>>,
65 pending_check_order_status_requests:
66 Mutex<HashMap<LSPSRequestId, oneshot::Sender<LSPS1OrderStatus>>>,
67}
68
69#[derive(Debug, Clone)]
70pub(crate) struct LSPS1ClientConfig {
71 pub node_id: PublicKey,
72 pub address: SocketAddress,
73 pub token: Option<String>,
74}
75
76struct LSPS2Client {
77 lsp_node_id: PublicKey,
78 lsp_address: SocketAddress,
79 token: Option<String>,
80 ldk_client_config: LdkLSPS2ClientConfig,
81 pending_fee_requests: Mutex<HashMap<LSPSRequestId, oneshot::Sender<LSPS2FeeResponse>>>,
82 pending_buy_requests: Mutex<HashMap<LSPSRequestId, oneshot::Sender<LSPS2BuyResponse>>>,
83}
84
85#[derive(Debug, Clone)]
86pub(crate) struct LSPS2ClientConfig {
87 pub node_id: PublicKey,
88 pub address: SocketAddress,
89 pub token: Option<String>,
90}
91
92struct LSPS2Service {
93 service_config: LSPS2ServiceConfig,
94 ldk_service_config: LdkLSPS2ServiceConfig,
95}
96
97#[derive(Debug, Clone)]
103pub struct LSPS2ServiceConfig {
104 pub require_token: Option<String>,
108 pub advertise_service: bool,
110 pub channel_opening_fee_ppm: u32,
114 pub channel_over_provisioning_ppm: u32,
123 pub min_channel_opening_fee_msat: u64,
125 pub min_channel_lifetime: u32,
127 pub max_client_to_self_delay: u32,
129 pub min_payment_size_msat: u64,
131 pub max_payment_size_msat: u64,
133 pub client_trusts_lsp: bool,
146}
147
148pub(crate) struct LiquiditySourceBuilder<L: Deref>
149where
150 L::Target: LdkLogger,
151{
152 lsps1_client: Option<LSPS1Client>,
153 lsps2_client: Option<LSPS2Client>,
154 lsps2_service: Option<LSPS2Service>,
155 wallet: Arc<Wallet>,
156 channel_manager: Arc<ChannelManager>,
157 keys_manager: Arc<KeysManager>,
158 chain_source: Arc<ChainSource>,
159 tx_broadcaster: Arc<Broadcaster>,
160 kv_store: Arc<DynStore>,
161 config: Arc<Config>,
162 logger: L,
163}
164
165impl<L: Deref> LiquiditySourceBuilder<L>
166where
167 L::Target: LdkLogger,
168{
169 pub(crate) fn new(
170 wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>, keys_manager: Arc<KeysManager>,
171 chain_source: Arc<ChainSource>, tx_broadcaster: Arc<Broadcaster>, kv_store: Arc<DynStore>,
172 config: Arc<Config>, logger: L,
173 ) -> Self {
174 let lsps1_client = None;
175 let lsps2_client = None;
176 let lsps2_service = None;
177 Self {
178 lsps1_client,
179 lsps2_client,
180 lsps2_service,
181 wallet,
182 channel_manager,
183 keys_manager,
184 chain_source,
185 tx_broadcaster,
186 kv_store,
187 config,
188 logger,
189 }
190 }
191
192 pub(crate) fn lsps1_client(
193 &mut self, lsp_node_id: PublicKey, lsp_address: SocketAddress, token: Option<String>,
194 ) -> &mut Self {
195 let ldk_client_config = LdkLSPS1ClientConfig { max_channel_fees_msat: None };
197 let pending_opening_params_requests = Mutex::new(HashMap::new());
198 let pending_create_order_requests = Mutex::new(HashMap::new());
199 let pending_check_order_status_requests = Mutex::new(HashMap::new());
200 self.lsps1_client = Some(LSPS1Client {
201 lsp_node_id,
202 lsp_address,
203 token,
204 ldk_client_config,
205 pending_opening_params_requests,
206 pending_create_order_requests,
207 pending_check_order_status_requests,
208 });
209 self
210 }
211
212 pub(crate) fn lsps2_client(
213 &mut self, lsp_node_id: PublicKey, lsp_address: SocketAddress, token: Option<String>,
214 ) -> &mut Self {
215 let ldk_client_config = LdkLSPS2ClientConfig {};
216 let pending_fee_requests = Mutex::new(HashMap::new());
217 let pending_buy_requests = Mutex::new(HashMap::new());
218 self.lsps2_client = Some(LSPS2Client {
219 lsp_node_id,
220 lsp_address,
221 token,
222 ldk_client_config,
223 pending_fee_requests,
224 pending_buy_requests,
225 });
226 self
227 }
228
229 pub(crate) fn lsps2_service(
230 &mut self, promise_secret: [u8; 32], service_config: LSPS2ServiceConfig,
231 ) -> &mut Self {
232 let ldk_service_config = LdkLSPS2ServiceConfig { promise_secret };
233 self.lsps2_service = Some(LSPS2Service { service_config, ldk_service_config });
234 self
235 }
236
237 pub(crate) async fn build(self) -> Result<LiquiditySource<L>, BuildError> {
238 let liquidity_service_config = self.lsps2_service.as_ref().map(|s| {
239 let lsps2_service_config = Some(s.ldk_service_config.clone());
240 let lsps5_service_config = None;
241 let advertise_service = s.service_config.advertise_service;
242 LiquidityServiceConfig { lsps2_service_config, lsps5_service_config, advertise_service }
243 });
244
245 let lsps1_client_config = self.lsps1_client.as_ref().map(|s| s.ldk_client_config.clone());
246 let lsps2_client_config = self.lsps2_client.as_ref().map(|s| s.ldk_client_config.clone());
247 let lsps5_client_config = None;
248 let liquidity_client_config = Some(LiquidityClientConfig {
249 lsps1_client_config,
250 lsps2_client_config,
251 lsps5_client_config,
252 });
253
254 let liquidity_manager = Arc::new(
255 LiquidityManager::new(
256 Arc::clone(&self.keys_manager),
257 Arc::clone(&self.keys_manager),
258 Arc::clone(&self.channel_manager),
259 Some(Arc::clone(&self.chain_source)),
260 None,
261 Arc::clone(&self.kv_store),
262 Arc::clone(&self.tx_broadcaster),
263 liquidity_service_config,
264 liquidity_client_config,
265 )
266 .await
267 .map_err(|_| BuildError::ReadFailed)?,
268 );
269
270 Ok(LiquiditySource {
271 lsps1_client: self.lsps1_client,
272 lsps2_client: self.lsps2_client,
273 lsps2_service: self.lsps2_service,
274 wallet: self.wallet,
275 channel_manager: self.channel_manager,
276 peer_manager: RwLock::new(None),
277 keys_manager: self.keys_manager,
278 liquidity_manager,
279 config: self.config,
280 logger: self.logger,
281 })
282 }
283}
284
285pub(crate) struct LiquiditySource<L: Deref>
286where
287 L::Target: LdkLogger,
288{
289 lsps1_client: Option<LSPS1Client>,
290 lsps2_client: Option<LSPS2Client>,
291 lsps2_service: Option<LSPS2Service>,
292 wallet: Arc<Wallet>,
293 channel_manager: Arc<ChannelManager>,
294 peer_manager: RwLock<Option<Arc<PeerManager>>>,
295 keys_manager: Arc<KeysManager>,
296 liquidity_manager: Arc<LiquidityManager>,
297 config: Arc<Config>,
298 logger: L,
299}
300
301impl<L: Deref> LiquiditySource<L>
302where
303 L::Target: LdkLogger,
304{
305 pub(crate) fn set_peer_manager(&self, peer_manager: Arc<PeerManager>) {
306 *self.peer_manager.write().unwrap() = Some(peer_manager);
307 }
308
309 pub(crate) fn liquidity_manager(&self) -> Arc<LiquidityManager> {
310 Arc::clone(&self.liquidity_manager)
311 }
312
313 pub(crate) fn get_lsps1_lsp_details(&self) -> Option<(PublicKey, SocketAddress)> {
314 self.lsps1_client.as_ref().map(|s| (s.lsp_node_id, s.lsp_address.clone()))
315 }
316
317 pub(crate) fn get_lsps2_lsp_details(&self) -> Option<(PublicKey, SocketAddress)> {
318 self.lsps2_client.as_ref().map(|s| (s.lsp_node_id, s.lsp_address.clone()))
319 }
320
321 pub(crate) fn lsps2_channel_needs_manual_broadcast(
322 &self, counterparty_node_id: PublicKey, user_channel_id: u128,
323 ) -> bool {
324 self.lsps2_service.as_ref().map_or(false, |lsps2_service| {
325 lsps2_service.service_config.client_trusts_lsp
326 && self
327 .liquidity_manager()
328 .lsps2_service_handler()
329 .and_then(|handler| {
330 handler
331 .channel_needs_manual_broadcast(user_channel_id, &counterparty_node_id)
332 .ok()
333 })
334 .unwrap_or(false)
335 })
336 }
337
338 pub(crate) fn lsps2_store_funding_transaction(
339 &self, user_channel_id: u128, counterparty_node_id: PublicKey, funding_tx: Transaction,
340 ) {
341 if self.lsps2_service.as_ref().map_or(false, |svc| !svc.service_config.client_trusts_lsp) {
342 return;
344 }
345
346 let lsps2_service_handler = self.liquidity_manager.lsps2_service_handler();
347 if let Some(handler) = lsps2_service_handler {
348 handler
349 .store_funding_transaction(user_channel_id, &counterparty_node_id, funding_tx)
350 .unwrap_or_else(|e| {
351 debug_assert!(false, "Failed to store funding transaction: {:?}", e);
352 log_error!(self.logger, "Failed to store funding transaction: {:?}", e);
353 });
354 } else {
355 log_error!(self.logger, "LSPS2 service handler is not available.");
356 }
357 }
358
359 pub(crate) fn lsps2_funding_tx_broadcast_safe(
360 &self, user_channel_id: u128, counterparty_node_id: PublicKey,
361 ) {
362 if self.lsps2_service.as_ref().map_or(false, |svc| !svc.service_config.client_trusts_lsp) {
363 return;
365 }
366
367 let lsps2_service_handler = self.liquidity_manager.lsps2_service_handler();
368 if let Some(handler) = lsps2_service_handler {
369 handler
370 .set_funding_tx_broadcast_safe(user_channel_id, &counterparty_node_id)
371 .unwrap_or_else(|e| {
372 debug_assert!(
373 false,
374 "Failed to mark funding transaction safe to broadcast: {:?}",
375 e
376 );
377 log_error!(
378 self.logger,
379 "Failed to mark funding transaction safe to broadcast: {:?}",
380 e
381 );
382 });
383 } else {
384 log_error!(self.logger, "LSPS2 service handler is not available.");
385 }
386 }
387
388 pub(crate) async fn handle_next_event(&self) {
389 match self.liquidity_manager.next_event_async().await {
390 LiquidityEvent::LSPS1Client(LSPS1ClientEvent::SupportedOptionsReady {
391 request_id,
392 counterparty_node_id,
393 supported_options,
394 }) => {
395 if let Some(lsps1_client) = self.lsps1_client.as_ref() {
396 if counterparty_node_id != lsps1_client.lsp_node_id {
397 debug_assert!(
398 false,
399 "Received response from unexpected LSP counterparty. This should never happen."
400 );
401 log_error!(
402 self.logger,
403 "Received response from unexpected LSP counterparty. This should never happen."
404 );
405 return;
406 }
407
408 if let Some(sender) = lsps1_client
409 .pending_opening_params_requests
410 .lock()
411 .unwrap()
412 .remove(&request_id)
413 {
414 let response = LSPS1OpeningParamsResponse { supported_options };
415
416 match sender.send(response) {
417 Ok(()) => (),
418 Err(_) => {
419 log_error!(
420 self.logger,
421 "Failed to handle response for request {:?} from liquidity service",
422 request_id
423 );
424 },
425 }
426 } else {
427 debug_assert!(
428 false,
429 "Received response from liquidity service for unknown request."
430 );
431 log_error!(
432 self.logger,
433 "Received response from liquidity service for unknown request."
434 );
435 }
436 } else {
437 log_error!(
438 self.logger,
439 "Received unexpected LSPS1Client::SupportedOptionsReady event!"
440 );
441 }
442 },
443 LiquidityEvent::LSPS1Client(LSPS1ClientEvent::OrderCreated {
444 request_id,
445 counterparty_node_id,
446 order_id,
447 order,
448 payment,
449 channel,
450 }) => {
451 if let Some(lsps1_client) = self.lsps1_client.as_ref() {
452 if counterparty_node_id != lsps1_client.lsp_node_id {
453 debug_assert!(
454 false,
455 "Received response from unexpected LSP counterparty. This should never happen."
456 );
457 log_error!(
458 self.logger,
459 "Received response from unexpected LSP counterparty. This should never happen."
460 );
461 return;
462 }
463
464 if let Some(sender) = lsps1_client
465 .pending_create_order_requests
466 .lock()
467 .unwrap()
468 .remove(&request_id)
469 {
470 let response = LSPS1OrderStatus {
471 order_id,
472 order_params: order,
473 payment_options: payment.into(),
474 channel_state: channel,
475 };
476
477 match sender.send(response) {
478 Ok(()) => (),
479 Err(_) => {
480 log_error!(
481 self.logger,
482 "Failed to handle response for request {:?} from liquidity service",
483 request_id
484 );
485 },
486 }
487 } else {
488 debug_assert!(
489 false,
490 "Received response from liquidity service for unknown request."
491 );
492 log_error!(
493 self.logger,
494 "Received response from liquidity service for unknown request."
495 );
496 }
497 } else {
498 log_error!(self.logger, "Received unexpected LSPS1Client::OrderCreated event!");
499 }
500 },
501 LiquidityEvent::LSPS1Client(LSPS1ClientEvent::OrderStatus {
502 request_id,
503 counterparty_node_id,
504 order_id,
505 order,
506 payment,
507 channel,
508 }) => {
509 if let Some(lsps1_client) = self.lsps1_client.as_ref() {
510 if counterparty_node_id != lsps1_client.lsp_node_id {
511 debug_assert!(
512 false,
513 "Received response from unexpected LSP counterparty. This should never happen."
514 );
515 log_error!(
516 self.logger,
517 "Received response from unexpected LSP counterparty. This should never happen."
518 );
519 return;
520 }
521
522 if let Some(sender) = lsps1_client
523 .pending_check_order_status_requests
524 .lock()
525 .unwrap()
526 .remove(&request_id)
527 {
528 let response = LSPS1OrderStatus {
529 order_id,
530 order_params: order,
531 payment_options: payment.into(),
532 channel_state: channel,
533 };
534
535 match sender.send(response) {
536 Ok(()) => (),
537 Err(_) => {
538 log_error!(
539 self.logger,
540 "Failed to handle response for request {:?} from liquidity service",
541 request_id
542 );
543 },
544 }
545 } else {
546 debug_assert!(
547 false,
548 "Received response from liquidity service for unknown request."
549 );
550 log_error!(
551 self.logger,
552 "Received response from liquidity service for unknown request."
553 );
554 }
555 } else {
556 log_error!(self.logger, "Received unexpected LSPS1Client::OrderStatus event!");
557 }
558 },
559 LiquidityEvent::LSPS2Service(LSPS2ServiceEvent::GetInfo {
560 request_id,
561 counterparty_node_id,
562 token,
563 }) => {
564 if let Some(lsps2_service_handler) =
565 self.liquidity_manager.lsps2_service_handler().as_ref()
566 {
567 let service_config = if let Some(service_config) =
568 self.lsps2_service.as_ref().map(|s| s.service_config.clone())
569 {
570 service_config
571 } else {
572 log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
573 return;
574 };
575
576 if let Some(required) = service_config.require_token {
577 if token != Some(required) {
578 log_error!(
579 self.logger,
580 "Rejecting LSPS2 request {:?} from counterparty {} as the client provided an invalid token.",
581 request_id,
582 counterparty_node_id
583 );
584 lsps2_service_handler.invalid_token_provided(&counterparty_node_id, request_id.clone()).unwrap_or_else(|e| {
585 debug_assert!(false, "Failed to reject LSPS2 request. This should never happen.");
586 log_error!(
587 self.logger,
588 "Failed to reject LSPS2 request {:?} from counterparty {} due to: {:?}. This should never happen.",
589 request_id,
590 counterparty_node_id,
591 e
592 );
593 });
594 return;
595 }
596 }
597
598 let valid_until = LSPSDateTime(Utc::now() + LSPS2_GETINFO_REQUEST_EXPIRY);
599 let opening_fee_params = LSPS2RawOpeningFeeParams {
600 min_fee_msat: service_config.min_channel_opening_fee_msat,
601 proportional: service_config.channel_opening_fee_ppm,
602 valid_until,
603 min_lifetime: service_config.min_channel_lifetime,
604 max_client_to_self_delay: service_config.max_client_to_self_delay,
605 min_payment_size_msat: service_config.min_payment_size_msat,
606 max_payment_size_msat: service_config.max_payment_size_msat,
607 };
608
609 let opening_fee_params_menu = vec![opening_fee_params];
610
611 if let Err(e) = lsps2_service_handler.opening_fee_params_generated(
612 &counterparty_node_id,
613 request_id,
614 opening_fee_params_menu,
615 ) {
616 log_error!(
617 self.logger,
618 "Failed to handle generated opening fee params: {:?}",
619 e
620 );
621 }
622 } else {
623 log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
624 return;
625 }
626 },
627 LiquidityEvent::LSPS2Service(LSPS2ServiceEvent::BuyRequest {
628 request_id,
629 counterparty_node_id,
630 opening_fee_params: _,
631 payment_size_msat,
632 }) => {
633 if let Some(lsps2_service_handler) =
634 self.liquidity_manager.lsps2_service_handler().as_ref()
635 {
636 let service_config = if let Some(service_config) =
637 self.lsps2_service.as_ref().map(|s| s.service_config.clone())
638 {
639 service_config
640 } else {
641 log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
642 return;
643 };
644
645 let user_channel_id: u128 = rand::rng().random();
646 let intercept_scid = self.channel_manager.get_intercept_scid();
647
648 if let Some(payment_size_msat) = payment_size_msat {
649 if payment_size_msat > service_config.max_payment_size_msat
659 || payment_size_msat < service_config.min_payment_size_msat
660 {
661 log_error!(
662 self.logger,
663 "Rejecting to handle LSPS2 buy request {:?} from counterparty {} as the client requested an invalid payment size.",
664 request_id,
665 counterparty_node_id
666 );
667 return;
668 }
669 }
670
671 match lsps2_service_handler
672 .invoice_parameters_generated(
673 &counterparty_node_id,
674 request_id,
675 intercept_scid,
676 LSPS2_CHANNEL_CLTV_EXPIRY_DELTA,
677 service_config.client_trusts_lsp,
678 user_channel_id,
679 )
680 .await
681 {
682 Ok(()) => {},
683 Err(e) => {
684 log_error!(
685 self.logger,
686 "Failed to provide invoice parameters: {:?}",
687 e
688 );
689 return;
690 },
691 }
692 } else {
693 log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
694 return;
695 }
696 },
697 LiquidityEvent::LSPS2Service(LSPS2ServiceEvent::OpenChannel {
698 their_network_key,
699 amt_to_forward_msat,
700 opening_fee_msat: _,
701 user_channel_id,
702 intercept_scid: _,
703 }) => {
704 if self.liquidity_manager.lsps2_service_handler().is_none() {
705 log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
706 return;
707 };
708
709 let service_config = if let Some(service_config) =
710 self.lsps2_service.as_ref().map(|s| s.service_config.clone())
711 {
712 service_config
713 } else {
714 log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
715 return;
716 };
717
718 let init_features = if let Some(peer_manager) =
719 self.peer_manager.read().unwrap().as_ref()
720 {
721 if let Some(peer) = peer_manager.peer_by_node_id(&their_network_key) {
723 peer.init_features
724 } else {
725 log_error!(
729 self.logger,
730 "Failed to open LSPS2 channel to {} due to peer not being not connected.",
731 their_network_key,
732 );
733 return;
734 }
735 } else {
736 debug_assert!(false, "Failed to handle LSPS2ServiceEvent as peer manager isn't available. This should never happen.",);
737 log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as peer manager isn't available. This should never happen.",);
738 return;
739 };
740
741 let over_provisioning_msat = (amt_to_forward_msat
743 * service_config.channel_over_provisioning_ppm as u64)
744 / 1_000_000;
745 let channel_amount_sats = (amt_to_forward_msat + over_provisioning_msat) / 1000;
746 let cur_anchor_reserve_sats =
747 total_anchor_channels_reserve_sats(&self.channel_manager, &self.config);
748 let spendable_amount_sats =
749 self.wallet.get_spendable_amount_sats(cur_anchor_reserve_sats).unwrap_or(0);
750 let required_funds_sats = channel_amount_sats
751 + self.config.anchor_channels_config.as_ref().map_or(0, |c| {
752 if init_features.requires_anchors_zero_fee_htlc_tx()
753 && !c.trusted_peers_no_reserve.contains(&their_network_key)
754 {
755 c.per_channel_reserve_sats
756 } else {
757 0
758 }
759 });
760 if spendable_amount_sats < required_funds_sats {
761 log_error!(self.logger,
762 "Unable to create channel due to insufficient funds. Available: {}sats, Required: {}sats",
763 spendable_amount_sats, channel_amount_sats
764 );
765 return;
769 }
770
771 let mut config = self.channel_manager.get_current_config().clone();
772
773 debug_assert_eq!(
775 config
776 .channel_handshake_config
777 .max_inbound_htlc_value_in_flight_percent_of_channel,
778 100
779 );
780 debug_assert!(config.accept_forwards_to_priv_channels);
781
782 config.channel_config.forwarding_fee_base_msat = 0;
786 config.channel_config.forwarding_fee_proportional_millionths = 0;
787
788 match self.channel_manager.create_channel(
789 their_network_key,
790 channel_amount_sats,
791 0,
792 user_channel_id,
793 None,
794 Some(config),
795 ) {
796 Ok(_) => {},
797 Err(e) => {
798 log_error!(
802 self.logger,
803 "Failed to open LSPS2 channel to {}: {:?}",
804 their_network_key,
805 e
806 );
807 return;
808 },
809 }
810 },
811 LiquidityEvent::LSPS2Client(LSPS2ClientEvent::OpeningParametersReady {
812 request_id,
813 counterparty_node_id,
814 opening_fee_params_menu,
815 }) => {
816 if let Some(lsps2_client) = self.lsps2_client.as_ref() {
817 if counterparty_node_id != lsps2_client.lsp_node_id {
818 debug_assert!(
819 false,
820 "Received response from unexpected LSP counterparty. This should never happen."
821 );
822 log_error!(
823 self.logger,
824 "Received response from unexpected LSP counterparty. This should never happen."
825 );
826 return;
827 }
828
829 if let Some(sender) =
830 lsps2_client.pending_fee_requests.lock().unwrap().remove(&request_id)
831 {
832 let response = LSPS2FeeResponse { opening_fee_params_menu };
833
834 match sender.send(response) {
835 Ok(()) => (),
836 Err(_) => {
837 log_error!(
838 self.logger,
839 "Failed to handle response for request {:?} from liquidity service",
840 request_id
841 );
842 },
843 }
844 } else {
845 debug_assert!(
846 false,
847 "Received response from liquidity service for unknown request."
848 );
849 log_error!(
850 self.logger,
851 "Received response from liquidity service for unknown request."
852 );
853 }
854 } else {
855 log_error!(
856 self.logger,
857 "Received unexpected LSPS2Client::OpeningParametersReady event!"
858 );
859 }
860 },
861 LiquidityEvent::LSPS2Client(LSPS2ClientEvent::InvoiceParametersReady {
862 request_id,
863 counterparty_node_id,
864 intercept_scid,
865 cltv_expiry_delta,
866 ..
867 }) => {
868 if let Some(lsps2_client) = self.lsps2_client.as_ref() {
869 if counterparty_node_id != lsps2_client.lsp_node_id {
870 debug_assert!(
871 false,
872 "Received response from unexpected LSP counterparty. This should never happen."
873 );
874 log_error!(
875 self.logger,
876 "Received response from unexpected LSP counterparty. This should never happen."
877 );
878 return;
879 }
880
881 if let Some(sender) =
882 lsps2_client.pending_buy_requests.lock().unwrap().remove(&request_id)
883 {
884 let response = LSPS2BuyResponse { intercept_scid, cltv_expiry_delta };
885
886 match sender.send(response) {
887 Ok(()) => (),
888 Err(_) => {
889 log_error!(
890 self.logger,
891 "Failed to handle response for request {:?} from liquidity service",
892 request_id
893 );
894 },
895 }
896 } else {
897 debug_assert!(
898 false,
899 "Received response from liquidity service for unknown request."
900 );
901 log_error!(
902 self.logger,
903 "Received response from liquidity service for unknown request."
904 );
905 }
906 } else {
907 log_error!(
908 self.logger,
909 "Received unexpected LSPS2Client::InvoiceParametersReady event!"
910 );
911 }
912 },
913 e => {
914 log_error!(self.logger, "Received unexpected liquidity event: {:?}", e);
915 },
916 }
917 }
918
919 pub(crate) async fn lsps1_request_opening_params(
920 &self,
921 ) -> Result<LSPS1OpeningParamsResponse, Error> {
922 let lsps1_client = self.lsps1_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
923
924 let client_handler = self.liquidity_manager.lsps1_client_handler().ok_or_else(|| {
925 log_error!(self.logger, "LSPS1 liquidity client was not configured.",);
926 Error::LiquiditySourceUnavailable
927 })?;
928
929 let (request_sender, request_receiver) = oneshot::channel();
930 {
931 let mut pending_opening_params_requests_lock =
932 lsps1_client.pending_opening_params_requests.lock().unwrap();
933 let request_id = client_handler.request_supported_options(lsps1_client.lsp_node_id);
934 pending_opening_params_requests_lock.insert(request_id, request_sender);
935 }
936
937 tokio::time::timeout(Duration::from_secs(LIQUIDITY_REQUEST_TIMEOUT_SECS), request_receiver)
938 .await
939 .map_err(|e| {
940 log_error!(self.logger, "Liquidity request timed out: {}", e);
941 Error::LiquidityRequestFailed
942 })?
943 .map_err(|e| {
944 log_error!(self.logger, "Failed to handle response from liquidity service: {}", e);
945 Error::LiquidityRequestFailed
946 })
947 }
948
949 pub(crate) async fn lsps1_request_channel(
950 &self, lsp_balance_sat: u64, client_balance_sat: u64, channel_expiry_blocks: u32,
951 announce_channel: bool, refund_address: bitcoin::Address,
952 ) -> Result<LSPS1OrderStatus, Error> {
953 let lsps1_client = self.lsps1_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
954 let client_handler = self.liquidity_manager.lsps1_client_handler().ok_or_else(|| {
955 log_error!(self.logger, "LSPS1 liquidity client was not configured.",);
956 Error::LiquiditySourceUnavailable
957 })?;
958
959 let lsp_limits = self.lsps1_request_opening_params().await?.supported_options;
960 let channel_size_sat = lsp_balance_sat + client_balance_sat;
961
962 if channel_size_sat < lsp_limits.min_channel_balance_sat
963 || channel_size_sat > lsp_limits.max_channel_balance_sat
964 {
965 log_error!(
966 self.logger,
967 "Requested channel size of {}sat doesn't meet the LSP-provided limits (min: {}sat, max: {}sat).",
968 channel_size_sat,
969 lsp_limits.min_channel_balance_sat,
970 lsp_limits.max_channel_balance_sat
971 );
972 return Err(Error::LiquidityRequestFailed);
973 }
974
975 if lsp_balance_sat < lsp_limits.min_initial_lsp_balance_sat
976 || lsp_balance_sat > lsp_limits.max_initial_lsp_balance_sat
977 {
978 log_error!(
979 self.logger,
980 "Requested LSP-side balance of {}sat doesn't meet the LSP-provided limits (min: {}sat, max: {}sat).",
981 lsp_balance_sat,
982 lsp_limits.min_initial_lsp_balance_sat,
983 lsp_limits.max_initial_lsp_balance_sat
984 );
985 return Err(Error::LiquidityRequestFailed);
986 }
987
988 if client_balance_sat < lsp_limits.min_initial_client_balance_sat
989 || client_balance_sat > lsp_limits.max_initial_client_balance_sat
990 {
991 log_error!(
992 self.logger,
993 "Requested client-side balance of {}sat doesn't meet the LSP-provided limits (min: {}sat, max: {}sat).",
994 client_balance_sat,
995 lsp_limits.min_initial_client_balance_sat,
996 lsp_limits.max_initial_client_balance_sat
997 );
998 return Err(Error::LiquidityRequestFailed);
999 }
1000
1001 let order_params = LSPS1OrderParams {
1002 lsp_balance_sat,
1003 client_balance_sat,
1004 required_channel_confirmations: lsp_limits.min_required_channel_confirmations,
1005 funding_confirms_within_blocks: lsp_limits.min_funding_confirms_within_blocks,
1006 channel_expiry_blocks,
1007 token: lsps1_client.token.clone(),
1008 announce_channel,
1009 };
1010
1011 let (request_sender, request_receiver) = oneshot::channel();
1012 let request_id;
1013 {
1014 let mut pending_create_order_requests_lock =
1015 lsps1_client.pending_create_order_requests.lock().unwrap();
1016 request_id = client_handler.create_order(
1017 &lsps1_client.lsp_node_id,
1018 order_params.clone(),
1019 Some(refund_address),
1020 );
1021 pending_create_order_requests_lock.insert(request_id.clone(), request_sender);
1022 }
1023
1024 let response = tokio::time::timeout(
1025 Duration::from_secs(LIQUIDITY_REQUEST_TIMEOUT_SECS),
1026 request_receiver,
1027 )
1028 .await
1029 .map_err(|e| {
1030 log_error!(self.logger, "Liquidity request with ID {:?} timed out: {}", request_id, e);
1031 Error::LiquidityRequestFailed
1032 })?
1033 .map_err(|e| {
1034 log_error!(self.logger, "Failed to handle response from liquidity service: {}", e);
1035 Error::LiquidityRequestFailed
1036 })?;
1037
1038 if response.order_params != order_params {
1039 log_error!(
1040 self.logger,
1041 "Aborting LSPS1 request as LSP-provided parameters don't match our order. Expected: {:?}, Received: {:?}", order_params, response.order_params
1042 );
1043 return Err(Error::LiquidityRequestFailed);
1044 }
1045
1046 Ok(response)
1047 }
1048
1049 pub(crate) async fn lsps1_check_order_status(
1050 &self, order_id: LSPS1OrderId,
1051 ) -> Result<LSPS1OrderStatus, Error> {
1052 let lsps1_client = self.lsps1_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1053 let client_handler = self.liquidity_manager.lsps1_client_handler().ok_or_else(|| {
1054 log_error!(self.logger, "LSPS1 liquidity client was not configured.",);
1055 Error::LiquiditySourceUnavailable
1056 })?;
1057
1058 let (request_sender, request_receiver) = oneshot::channel();
1059 {
1060 let mut pending_check_order_status_requests_lock =
1061 lsps1_client.pending_check_order_status_requests.lock().unwrap();
1062 let request_id = client_handler.check_order_status(&lsps1_client.lsp_node_id, order_id);
1063 pending_check_order_status_requests_lock.insert(request_id, request_sender);
1064 }
1065
1066 let response = tokio::time::timeout(
1067 Duration::from_secs(LIQUIDITY_REQUEST_TIMEOUT_SECS),
1068 request_receiver,
1069 )
1070 .await
1071 .map_err(|e| {
1072 log_error!(self.logger, "Liquidity request timed out: {}", e);
1073 Error::LiquidityRequestFailed
1074 })?
1075 .map_err(|e| {
1076 log_error!(self.logger, "Failed to handle response from liquidity service: {}", e);
1077 Error::LiquidityRequestFailed
1078 })?;
1079
1080 Ok(response)
1081 }
1082
1083 pub(crate) async fn lsps2_receive_to_jit_channel(
1084 &self, amount_msat: u64, description: &Bolt11InvoiceDescription, expiry_secs: u32,
1085 max_total_lsp_fee_limit_msat: Option<u64>, payment_hash: Option<PaymentHash>,
1086 ) -> Result<(Bolt11Invoice, u64), Error> {
1087 let fee_response = self.lsps2_request_opening_fee_params().await?;
1088
1089 let (min_total_fee_msat, min_opening_params) = fee_response
1090 .opening_fee_params_menu
1091 .into_iter()
1092 .filter_map(|params| {
1093 if amount_msat < params.min_payment_size_msat
1094 || amount_msat > params.max_payment_size_msat
1095 {
1096 log_debug!(self.logger,
1097 "Skipping LSP-offered JIT parameters as the payment of {}msat doesn't meet LSP limits (min: {}msat, max: {}msat)",
1098 amount_msat,
1099 params.min_payment_size_msat,
1100 params.max_payment_size_msat
1101 );
1102 None
1103 } else {
1104 compute_opening_fee(amount_msat, params.min_fee_msat, params.proportional as u64)
1105 .map(|fee| (fee, params))
1106 }
1107 })
1108 .min_by_key(|p| p.0)
1109 .ok_or_else(|| {
1110 log_error!(self.logger, "Failed to handle response from liquidity service",);
1111 Error::LiquidityRequestFailed
1112 })?;
1113
1114 if let Some(max_total_lsp_fee_limit_msat) = max_total_lsp_fee_limit_msat {
1115 if min_total_fee_msat > max_total_lsp_fee_limit_msat {
1116 log_error!(self.logger,
1117 "Failed to request inbound JIT channel as LSP's requested total opening fee of {}msat exceeds our fee limit of {}msat",
1118 min_total_fee_msat, max_total_lsp_fee_limit_msat
1119 );
1120 return Err(Error::LiquidityFeeTooHigh);
1121 }
1122 }
1123
1124 log_debug!(
1125 self.logger,
1126 "Choosing cheapest liquidity offer, will pay {}msat in total LSP fees",
1127 min_total_fee_msat
1128 );
1129
1130 let buy_response =
1131 self.lsps2_send_buy_request(Some(amount_msat), min_opening_params).await?;
1132 let invoice = self.lsps2_create_jit_invoice(
1133 buy_response,
1134 Some(amount_msat),
1135 description,
1136 expiry_secs,
1137 payment_hash,
1138 )?;
1139
1140 log_info!(self.logger, "JIT-channel invoice created: {}", invoice);
1141 Ok((invoice, min_total_fee_msat))
1142 }
1143
1144 pub(crate) async fn lsps2_receive_variable_amount_to_jit_channel(
1145 &self, description: &Bolt11InvoiceDescription, expiry_secs: u32,
1146 max_proportional_lsp_fee_limit_ppm_msat: Option<u64>, payment_hash: Option<PaymentHash>,
1147 ) -> Result<(Bolt11Invoice, u64), Error> {
1148 let fee_response = self.lsps2_request_opening_fee_params().await?;
1149
1150 let (min_prop_fee_ppm_msat, min_opening_params) = fee_response
1151 .opening_fee_params_menu
1152 .into_iter()
1153 .map(|params| (params.proportional as u64, params))
1154 .min_by_key(|p| p.0)
1155 .ok_or_else(|| {
1156 log_error!(self.logger, "Failed to handle response from liquidity service",);
1157 Error::LiquidityRequestFailed
1158 })?;
1159
1160 if let Some(max_proportional_lsp_fee_limit_ppm_msat) =
1161 max_proportional_lsp_fee_limit_ppm_msat
1162 {
1163 if min_prop_fee_ppm_msat > max_proportional_lsp_fee_limit_ppm_msat {
1164 log_error!(self.logger,
1165 "Failed to request inbound JIT channel as LSP's requested proportional opening fee of {} ppm msat exceeds our fee limit of {} ppm msat",
1166 min_prop_fee_ppm_msat,
1167 max_proportional_lsp_fee_limit_ppm_msat
1168 );
1169 return Err(Error::LiquidityFeeTooHigh);
1170 }
1171 }
1172
1173 log_debug!(
1174 self.logger,
1175 "Choosing cheapest liquidity offer, will pay {}ppm msat in proportional LSP fees",
1176 min_prop_fee_ppm_msat
1177 );
1178
1179 let buy_response = self.lsps2_send_buy_request(None, min_opening_params).await?;
1180 let invoice = self.lsps2_create_jit_invoice(
1181 buy_response,
1182 None,
1183 description,
1184 expiry_secs,
1185 payment_hash,
1186 )?;
1187
1188 log_info!(self.logger, "JIT-channel invoice created: {}", invoice);
1189 Ok((invoice, min_prop_fee_ppm_msat))
1190 }
1191
1192 async fn lsps2_request_opening_fee_params(&self) -> Result<LSPS2FeeResponse, Error> {
1193 let lsps2_client = self.lsps2_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1194
1195 let client_handler = self.liquidity_manager.lsps2_client_handler().ok_or_else(|| {
1196 log_error!(self.logger, "Liquidity client was not configured.",);
1197 Error::LiquiditySourceUnavailable
1198 })?;
1199
1200 let (fee_request_sender, fee_request_receiver) = oneshot::channel();
1201 {
1202 let mut pending_fee_requests_lock = lsps2_client.pending_fee_requests.lock().unwrap();
1203 let request_id = client_handler
1204 .request_opening_params(lsps2_client.lsp_node_id, lsps2_client.token.clone());
1205 pending_fee_requests_lock.insert(request_id, fee_request_sender);
1206 }
1207
1208 tokio::time::timeout(
1209 Duration::from_secs(LIQUIDITY_REQUEST_TIMEOUT_SECS),
1210 fee_request_receiver,
1211 )
1212 .await
1213 .map_err(|e| {
1214 log_error!(self.logger, "Liquidity request timed out: {}", e);
1215 Error::LiquidityRequestFailed
1216 })?
1217 .map_err(|e| {
1218 log_error!(self.logger, "Failed to handle response from liquidity service: {}", e);
1219 Error::LiquidityRequestFailed
1220 })
1221 }
1222
1223 async fn lsps2_send_buy_request(
1224 &self, amount_msat: Option<u64>, opening_fee_params: LSPS2OpeningFeeParams,
1225 ) -> Result<LSPS2BuyResponse, Error> {
1226 let lsps2_client = self.lsps2_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1227
1228 let client_handler = self.liquidity_manager.lsps2_client_handler().ok_or_else(|| {
1229 log_error!(self.logger, "Liquidity client was not configured.",);
1230 Error::LiquiditySourceUnavailable
1231 })?;
1232
1233 let (buy_request_sender, buy_request_receiver) = oneshot::channel();
1234 {
1235 let mut pending_buy_requests_lock = lsps2_client.pending_buy_requests.lock().unwrap();
1236 let request_id = client_handler
1237 .select_opening_params(lsps2_client.lsp_node_id, amount_msat, opening_fee_params)
1238 .map_err(|e| {
1239 log_error!(
1240 self.logger,
1241 "Failed to send buy request to liquidity service: {:?}",
1242 e
1243 );
1244 Error::LiquidityRequestFailed
1245 })?;
1246 pending_buy_requests_lock.insert(request_id, buy_request_sender);
1247 }
1248
1249 let buy_response = tokio::time::timeout(
1250 Duration::from_secs(LIQUIDITY_REQUEST_TIMEOUT_SECS),
1251 buy_request_receiver,
1252 )
1253 .await
1254 .map_err(|e| {
1255 log_error!(self.logger, "Liquidity request timed out: {}", e);
1256 Error::LiquidityRequestFailed
1257 })?
1258 .map_err(|e| {
1259 log_error!(self.logger, "Failed to handle response from liquidity service: {:?}", e);
1260 Error::LiquidityRequestFailed
1261 })?;
1262
1263 Ok(buy_response)
1264 }
1265
1266 fn lsps2_create_jit_invoice(
1267 &self, buy_response: LSPS2BuyResponse, amount_msat: Option<u64>,
1268 description: &Bolt11InvoiceDescription, expiry_secs: u32,
1269 payment_hash: Option<PaymentHash>,
1270 ) -> Result<Bolt11Invoice, Error> {
1271 let lsps2_client = self.lsps2_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1272
1273 let min_final_cltv_expiry_delta = MIN_FINAL_CLTV_EXPIRY_DELTA + 2;
1275 let (payment_hash, payment_secret) = match payment_hash {
1276 Some(payment_hash) => {
1277 let payment_secret = self
1278 .channel_manager
1279 .create_inbound_payment_for_hash(
1280 payment_hash,
1281 None,
1282 expiry_secs,
1283 Some(min_final_cltv_expiry_delta),
1284 )
1285 .map_err(|e| {
1286 log_error!(self.logger, "Failed to register inbound payment: {:?}", e);
1287 Error::InvoiceCreationFailed
1288 })?;
1289 (payment_hash, payment_secret)
1290 },
1291 None => self
1292 .channel_manager
1293 .create_inbound_payment(None, expiry_secs, Some(min_final_cltv_expiry_delta))
1294 .map_err(|e| {
1295 log_error!(self.logger, "Failed to register inbound payment: {:?}", e);
1296 Error::InvoiceCreationFailed
1297 })?,
1298 };
1299
1300 let route_hint = RouteHint(vec![RouteHintHop {
1301 src_node_id: lsps2_client.lsp_node_id,
1302 short_channel_id: buy_response.intercept_scid,
1303 fees: RoutingFees { base_msat: 0, proportional_millionths: 0 },
1304 cltv_expiry_delta: buy_response.cltv_expiry_delta as u16,
1305 htlc_minimum_msat: None,
1306 htlc_maximum_msat: None,
1307 }]);
1308
1309 let payment_hash = sha256::Hash::from_slice(&payment_hash.0).map_err(|e| {
1310 log_error!(self.logger, "Invalid payment hash: {:?}", e);
1311 Error::InvoiceCreationFailed
1312 })?;
1313
1314 let currency = self.config.network.into();
1315 let mut invoice_builder = InvoiceBuilder::new(currency)
1316 .invoice_description(description.clone())
1317 .payment_hash(payment_hash)
1318 .payment_secret(payment_secret)
1319 .current_timestamp()
1320 .min_final_cltv_expiry_delta(min_final_cltv_expiry_delta.into())
1321 .expiry_time(Duration::from_secs(expiry_secs.into()))
1322 .private_route(route_hint);
1323
1324 if let Some(amount_msat) = amount_msat {
1325 invoice_builder = invoice_builder.amount_milli_satoshis(amount_msat).basic_mpp();
1326 }
1327
1328 invoice_builder
1329 .build_signed(|hash| {
1330 Secp256k1::new()
1331 .sign_ecdsa_recoverable(hash, &self.keys_manager.get_node_secret_key())
1332 })
1333 .map_err(|e| {
1334 log_error!(self.logger, "Failed to build and sign invoice: {}", e);
1335 Error::InvoiceCreationFailed
1336 })
1337 }
1338
1339 pub(crate) async fn handle_channel_ready(
1340 &self, user_channel_id: u128, channel_id: &ChannelId, counterparty_node_id: &PublicKey,
1341 ) {
1342 if let Some(lsps2_service_handler) = self.liquidity_manager.lsps2_service_handler() {
1343 if let Err(e) = lsps2_service_handler
1344 .channel_ready(user_channel_id, channel_id, counterparty_node_id)
1345 .await
1346 {
1347 log_error!(
1348 self.logger,
1349 "LSPS2 service failed to handle ChannelReady event: {:?}",
1350 e
1351 );
1352 }
1353 }
1354 }
1355
1356 pub(crate) async fn handle_htlc_intercepted(
1357 &self, intercept_scid: u64, intercept_id: InterceptId, expected_outbound_amount_msat: u64,
1358 payment_hash: PaymentHash,
1359 ) {
1360 if let Some(lsps2_service_handler) = self.liquidity_manager.lsps2_service_handler() {
1361 if let Err(e) = lsps2_service_handler
1362 .htlc_intercepted(
1363 intercept_scid,
1364 intercept_id,
1365 expected_outbound_amount_msat,
1366 payment_hash,
1367 )
1368 .await
1369 {
1370 log_error!(
1371 self.logger,
1372 "LSPS2 service failed to handle HTLCIntercepted event: {:?}",
1373 e
1374 );
1375 }
1376 }
1377 }
1378
1379 pub(crate) async fn handle_htlc_handling_failed(&self, failure_type: HTLCHandlingFailureType) {
1380 if let Some(lsps2_service_handler) = self.liquidity_manager.lsps2_service_handler() {
1381 if let Err(e) = lsps2_service_handler.htlc_handling_failed(failure_type).await {
1382 log_error!(
1383 self.logger,
1384 "LSPS2 service failed to handle HTLCHandlingFailed event: {:?}",
1385 e
1386 );
1387 }
1388 }
1389 }
1390
1391 pub(crate) async fn handle_payment_forwarded(
1392 &self, next_channel_id: Option<ChannelId>, skimmed_fee_msat: u64,
1393 ) {
1394 if let Some(next_channel_id) = next_channel_id {
1395 if let Some(lsps2_service_handler) = self.liquidity_manager.lsps2_service_handler() {
1396 if let Err(e) =
1397 lsps2_service_handler.payment_forwarded(next_channel_id, skimmed_fee_msat).await
1398 {
1399 log_error!(
1400 self.logger,
1401 "LSPS2 service failed to handle PaymentForwarded: {:?}",
1402 e
1403 );
1404 }
1405 }
1406 }
1407 }
1408}
1409
1410#[derive(Debug, Clone)]
1411pub(crate) struct LSPS1OpeningParamsResponse {
1412 supported_options: LSPS1Options,
1413}
1414
1415#[derive(Debug, Clone)]
1417pub struct LSPS1OrderStatus {
1418 pub order_id: LSPS1OrderId,
1420 pub order_params: LSPS1OrderParams,
1422 pub payment_options: LSPS1PaymentInfo,
1424 pub channel_state: Option<LSPS1ChannelInfo>,
1426}
1427
1428#[cfg(not(feature = "uniffi"))]
1429type LSPS1PaymentInfo = lightning_liquidity::lsps1::msgs::LSPS1PaymentInfo;
1430
1431#[cfg(feature = "uniffi")]
1432type LSPS1PaymentInfo = crate::ffi::LSPS1PaymentInfo;
1433
1434#[derive(Debug, Clone)]
1435pub(crate) struct LSPS2FeeResponse {
1436 opening_fee_params_menu: Vec<LSPS2OpeningFeeParams>,
1437}
1438
1439#[derive(Debug, Clone)]
1440pub(crate) struct LSPS2BuyResponse {
1441 intercept_scid: u64,
1442 cltv_expiry_delta: u32,
1443}
1444
1445#[derive(Clone)]
1457pub struct LSPS1Liquidity {
1458 runtime: Arc<Runtime>,
1459 wallet: Arc<Wallet>,
1460 connection_manager: Arc<ConnectionManager<Arc<Logger>>>,
1461 liquidity_source: Option<Arc<LiquiditySource<Arc<Logger>>>>,
1462 logger: Arc<Logger>,
1463}
1464
1465impl LSPS1Liquidity {
1466 pub(crate) fn new(
1467 runtime: Arc<Runtime>, wallet: Arc<Wallet>,
1468 connection_manager: Arc<ConnectionManager<Arc<Logger>>>,
1469 liquidity_source: Option<Arc<LiquiditySource<Arc<Logger>>>>, logger: Arc<Logger>,
1470 ) -> Self {
1471 Self { runtime, wallet, connection_manager, liquidity_source, logger }
1472 }
1473
1474 pub fn request_channel(
1479 &self, lsp_balance_sat: u64, client_balance_sat: u64, channel_expiry_blocks: u32,
1480 announce_channel: bool,
1481 ) -> Result<LSPS1OrderStatus, Error> {
1482 let liquidity_source =
1483 self.liquidity_source.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1484
1485 let (lsp_node_id, lsp_address) =
1486 liquidity_source.get_lsps1_lsp_details().ok_or(Error::LiquiditySourceUnavailable)?;
1487
1488 let con_node_id = lsp_node_id;
1489 let con_addr = lsp_address.clone();
1490 let con_cm = Arc::clone(&self.connection_manager);
1491
1492 self.runtime.block_on(async move {
1495 con_cm.connect_peer_if_necessary(con_node_id, con_addr).await
1496 })?;
1497
1498 log_info!(self.logger, "Connected to LSP {}@{}. ", lsp_node_id, lsp_address);
1499
1500 let refund_address = self.wallet.get_new_address()?;
1501
1502 let liquidity_source = Arc::clone(&liquidity_source);
1503 let response = self.runtime.block_on(async move {
1504 liquidity_source
1505 .lsps1_request_channel(
1506 lsp_balance_sat,
1507 client_balance_sat,
1508 channel_expiry_blocks,
1509 announce_channel,
1510 refund_address,
1511 )
1512 .await
1513 })?;
1514
1515 Ok(response)
1516 }
1517
1518 pub fn check_order_status(&self, order_id: LSPS1OrderId) -> Result<LSPS1OrderStatus, Error> {
1520 let liquidity_source =
1521 self.liquidity_source.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1522
1523 let (lsp_node_id, lsp_address) =
1524 liquidity_source.get_lsps1_lsp_details().ok_or(Error::LiquiditySourceUnavailable)?;
1525
1526 let con_node_id = lsp_node_id;
1527 let con_addr = lsp_address.clone();
1528 let con_cm = Arc::clone(&self.connection_manager);
1529
1530 self.runtime.block_on(async move {
1533 con_cm.connect_peer_if_necessary(con_node_id, con_addr).await
1534 })?;
1535
1536 let liquidity_source = Arc::clone(&liquidity_source);
1537 let response = self
1538 .runtime
1539 .block_on(async move { liquidity_source.lsps1_check_order_status(order_id).await })?;
1540 Ok(response)
1541 }
1542}