ldk_node/
liquidity.rs

1// This file is Copyright its original authors, visible in version control history.
2//
3// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
6// accordance with one or both of these licenses.
7
8//! Objects related to liquidity management.
9
10use 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/// Represents the configuration of the LSPS2 service.
99///
100/// See [bLIP-52 / LSPS2] for more information.
101///
102/// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
103#[derive(Debug, Clone)]
104pub struct LSPS2ServiceConfig {
105	/// A token we may require to be sent by the clients.
106	///
107	/// If set, only requests matching this token will be accepted.
108	pub require_token: Option<String>,
109	/// Indicates whether the LSPS service will be announced via the gossip network.
110	pub advertise_service: bool,
111	/// The fee we withhold for the channel open from the initial payment.
112	///
113	/// This fee is proportional to the client-requested amount, in parts-per-million.
114	pub channel_opening_fee_ppm: u32,
115	/// The proportional overprovisioning for the channel.
116	///
117	/// This determines, in parts-per-million, how much value we'll provision on top of the amount
118	/// we need to forward the payment to the client.
119	///
120	/// For example, setting this to `100_000` will result in a channel being opened that is 10%
121	/// larger than then the to-be-forwarded amount (i.e., client-requested amount minus the
122	/// channel opening fee fee).
123	pub channel_over_provisioning_ppm: u32,
124	/// The minimum fee required for opening a channel.
125	pub min_channel_opening_fee_msat: u64,
126	/// The minimum number of blocks after confirmation we promise to keep the channel open.
127	pub min_channel_lifetime: u32,
128	/// The maximum number of blocks that the client is allowed to set its `to_self_delay` parameter.
129	pub max_client_to_self_delay: u32,
130	/// The minimum payment size that we will accept when opening a channel.
131	pub min_payment_size_msat: u64,
132	/// The maximum payment size that we will accept when opening a channel.
133	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		// TODO: allow to set max_channel_fees_msat
179		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						// 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				// We set these LSP-specific values during Node building, here we're making sure it's actually set.
679				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				// We set the forwarding fee to 0 for now as we're getting paid by the channel fee.
688				//
689				// TODO: revisit this decision eventually.
690				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						// TODO: We just silently fail here. Eventually we will need to remember
704						// the pending requests and regularly retry opening the channel until we
705						// succeed.
706						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		// LSPS2 requires min_final_cltv_expiry_delta to be at least 2 more than usual.
1172		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/// Represents the status of an LSPS1 channel request.
1291#[derive(Debug, Clone)]
1292pub struct LSPS1OrderStatus {
1293	/// The id of the channel order.
1294	pub order_id: OrderId,
1295	/// The parameters of channel order.
1296	pub order_params: OrderParameters,
1297	/// Contains details about how to pay for the order.
1298	pub payment_options: PaymentInfo,
1299	/// Contains information about the channel state.
1300	pub channel_state: Option<ChannelInfo>,
1301}
1302
1303#[cfg(not(feature = "uniffi"))]
1304type PaymentInfo = lightning_liquidity::lsps1::msgs::PaymentInfo;
1305
1306/// Details regarding how to pay for an order.
1307#[cfg(feature = "uniffi")]
1308#[derive(Clone, Debug, PartialEq, Eq)]
1309pub struct PaymentInfo {
1310	/// A Lightning payment using BOLT 11.
1311	pub bolt11: Option<crate::uniffi_types::Bolt11PaymentInfo>,
1312	/// An onchain payment.
1313	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/// An onchain payment.
1327#[cfg(feature = "uniffi")]
1328#[derive(Clone, Debug, PartialEq, Eq)]
1329pub struct OnchainPaymentInfo {
1330	/// Indicates the current state of the payment.
1331	pub state: lightning_liquidity::lsps1::msgs::PaymentState,
1332	/// The datetime when the payment option expires.
1333	pub expires_at: chrono::DateTime<chrono::Utc>,
1334	/// The total fee the LSP will charge to open this channel in satoshi.
1335	pub fee_total_sat: u64,
1336	/// The amount the client needs to pay to have the requested channel openend.
1337	pub order_total_sat: u64,
1338	/// An on-chain address the client can send [`Self::order_total_sat`] to to have the channel
1339	/// opened.
1340	pub address: bitcoin::Address,
1341	/// The minimum number of block confirmations that are required for the on-chain payment to be
1342	/// considered confirmed.
1343	pub min_onchain_payment_confirmations: Option<u16>,
1344	/// The minimum fee rate for the on-chain payment in case the client wants the payment to be
1345	/// confirmed without a confirmation.
1346	pub min_fee_for_0conf: Arc<bitcoin::FeeRate>,
1347	/// The address where the LSP will send the funds if the order fails.
1348	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/// A liquidity handler allowing to request channels via the [bLIP-51 / LSPS1] protocol.
1379///
1380/// Should be retrieved by calling [`Node::lsps1_liquidity`].
1381///
1382/// To open [bLIP-52 / LSPS2] JIT channels, please refer to
1383/// [`Bolt11Payment::receive_via_jit_channel`].
1384///
1385/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
1386/// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
1387/// [`Node::lsps1_liquidity`]: crate::Node::lsps1_liquidity
1388/// [`Bolt11Payment::receive_via_jit_channel`]: crate::payment::Bolt11Payment::receive_via_jit_channel
1389#[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	/// Connects to the configured LSP and places an order for an inbound channel.
1408	///
1409	/// The channel will be opened after one of the returned payment options has successfully been
1410	/// paid.
1411	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		// We need to use our main runtime here as a local runtime might not be around to poll
1429		// connection futures going forward.
1430		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	/// Connects to the configured LSP and checks for the status of a previously-placed order.
1459	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		// We need to use our main runtime here as a local runtime might not be around to poll
1474		// connection futures going forward.
1475		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}