Skip to content

Commit 4cc0a4a

Browse files
committed
Add LSPS1 API
We add an `Lsps1Liquidity` API object, mirroring the approach we took with the `payment` APIs.
1 parent ce3b3fa commit 4cc0a4a

File tree

2 files changed

+152
-5
lines changed

2 files changed

+152
-5
lines changed

src/lib.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ mod gossip;
8484
pub mod graph;
8585
mod hex_utils;
8686
pub mod io;
87-
mod liquidity;
87+
pub mod liquidity;
8888
pub mod logger;
8989
mod message_handler;
9090
pub mod payment;
@@ -100,6 +100,7 @@ pub use bip39;
100100
pub use bitcoin;
101101
pub use lightning;
102102
pub use lightning_invoice;
103+
pub use lightning_liquidity;
103104
pub use lightning_types;
104105
pub use vss_client;
105106

@@ -130,7 +131,7 @@ use event::{EventHandler, EventQueue};
130131
use gossip::GossipSource;
131132
use graph::NetworkGraph;
132133
use io::utils::write_node_metrics;
133-
use liquidity::LiquiditySource;
134+
use liquidity::{LSPS1Liquidity, LiquiditySource};
134135
use payment::store::PaymentStore;
135136
use payment::{
136137
Bolt11Payment, Bolt12Payment, OnchainPayment, PaymentDetails, SpontaneousPayment,
@@ -957,6 +958,34 @@ impl Node {
957958
))
958959
}
959960

961+
/// Returns a liquidity handler allowing to request channels via the [bLIP-51 / LSPS1] protocol.
962+
///
963+
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
964+
#[cfg(not(feature = "uniffi"))]
965+
pub fn lsps1_liquidity(&self) -> LSPS1Liquidity {
966+
LSPS1Liquidity::new(
967+
Arc::clone(&self.runtime),
968+
Arc::clone(&self.wallet),
969+
Arc::clone(&self.connection_manager),
970+
self.liquidity_source.clone(),
971+
Arc::clone(&self.logger),
972+
)
973+
}
974+
975+
/// Returns a liquidity handler allowing to request channels via the [bLIP-51 / LSPS1] protocol.
976+
///
977+
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
978+
#[cfg(feature = "uniffi")]
979+
pub fn lsps1_liquidity(&self) -> Arc<LSPS1Liquidity> {
980+
Arc::new(LSPS1Liquidity::new(
981+
Arc::clone(&self.runtime),
982+
Arc::clone(&self.wallet),
983+
Arc::clone(&self.connection_manager),
984+
self.liquidity_source.clone(),
985+
Arc::clone(&self.logger),
986+
))
987+
}
988+
960989
/// Retrieve a list of known channels.
961990
pub fn list_channels(&self) -> Vec<ChannelDetails> {
962991
self.channel_manager.list_channels().into_iter().map(|c| c.into()).collect()

src/liquidity.rs

Lines changed: 121 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66
// accordance with one or both of these licenses.
77

8+
//! Objects related to liquidity management.
9+
810
use crate::chain::ChainSource;
9-
use crate::logger::{log_debug, log_error, log_info, LdkLogger};
10-
use crate::types::{ChannelManager, KeysManager, LiquidityManager, PeerManager};
11+
use crate::connection::ConnectionManager;
12+
use crate::logger::{log_debug, log_error, log_info, LdkLogger, Logger};
13+
use crate::types::{ChannelManager, KeysManager, LiquidityManager, PeerManager, Wallet};
1114
use crate::{Config, Error};
1215

1316
use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA;
@@ -34,7 +37,7 @@ use tokio::sync::oneshot;
3437

3538
use std::collections::HashMap;
3639
use std::ops::Deref;
37-
use std::sync::{Arc, Mutex};
40+
use std::sync::{Arc, Mutex, RwLock};
3841
use std::time::Duration;
3942

4043
const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;
@@ -896,3 +899,118 @@ pub(crate) struct LSPS2BuyResponse {
896899
intercept_scid: u64,
897900
cltv_expiry_delta: u32,
898901
}
902+
903+
/// A liquidity handler allowing to request channels via the [bLIP-51 / LSPS1] protocol.
904+
///
905+
/// Should be retrieved by calling [`Node::lsps1_liquidity`].
906+
///
907+
/// To open [bLIP-52 / LSPS2] JIT channels, please refer to
908+
/// [`Bolt11Payment::receive_via_jit_channel`].
909+
///
910+
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
911+
/// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
912+
/// [`Node::lsps1_liquidity`]: crate::Node::lsps1_liquidity
913+
/// [`Bolt11Payment::receive_via_jit_channel`]: crate::payment::Bolt11Payment::receive_via_jit_channel
914+
#[derive(Clone)]
915+
pub struct LSPS1Liquidity {
916+
runtime: Arc<RwLock<Option<Arc<tokio::runtime::Runtime>>>>,
917+
wallet: Arc<Wallet>,
918+
connection_manager: Arc<ConnectionManager<Arc<Logger>>>,
919+
liquidity_source: Option<Arc<LiquiditySource<Arc<Logger>>>>,
920+
logger: Arc<Logger>,
921+
}
922+
923+
impl LSPS1Liquidity {
924+
pub(crate) fn new(
925+
runtime: Arc<RwLock<Option<Arc<tokio::runtime::Runtime>>>>, wallet: Arc<Wallet>,
926+
connection_manager: Arc<ConnectionManager<Arc<Logger>>>,
927+
liquidity_source: Option<Arc<LiquiditySource<Arc<Logger>>>>, logger: Arc<Logger>,
928+
) -> Self {
929+
Self { runtime, wallet, connection_manager, liquidity_source, logger }
930+
}
931+
932+
/// Connects to the configured LSP and places an order for an inbound channel.
933+
///
934+
/// The channel will be opened after one of the returned payment options has successfully been
935+
/// paid.
936+
pub fn request_channel(
937+
&self, lsp_balance_sat: u64, client_balance_sat: u64, channel_expiry_blocks: u32,
938+
announce_channel: bool,
939+
) -> Result<LSPS1OrderStatus, Error> {
940+
let liquidity_source =
941+
self.liquidity_source.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
942+
943+
let (lsp_node_id, lsp_address) = liquidity_source
944+
.get_lsps1_service_details()
945+
.ok_or(Error::LiquiditySourceUnavailable)?;
946+
947+
let rt_lock = self.runtime.read().unwrap();
948+
let runtime = rt_lock.as_ref().unwrap();
949+
950+
let con_node_id = lsp_node_id;
951+
let con_addr = lsp_address.clone();
952+
let con_cm = Arc::clone(&self.connection_manager);
953+
954+
// We need to use our main runtime here as a local runtime might not be around to poll
955+
// connection futures going forward.
956+
tokio::task::block_in_place(move || {
957+
runtime.block_on(async move {
958+
con_cm.connect_peer_if_necessary(con_node_id, con_addr).await
959+
})
960+
})?;
961+
962+
log_info!(self.logger, "Connected to LSP {}@{}. ", lsp_node_id, lsp_address);
963+
964+
let refund_address = self.wallet.get_new_address()?;
965+
966+
let liquidity_source = Arc::clone(&liquidity_source);
967+
let response = tokio::task::block_in_place(move || {
968+
runtime.block_on(async move {
969+
liquidity_source
970+
.lsps1_request_channel(
971+
lsp_balance_sat,
972+
client_balance_sat,
973+
channel_expiry_blocks,
974+
announce_channel,
975+
refund_address,
976+
)
977+
.await
978+
})
979+
})?;
980+
981+
Ok(response)
982+
}
983+
984+
/// Connects to the configured LSP and checks for the status of a previously-placed order.
985+
pub fn check_order_status(&self, order_id: OrderId) -> Result<LSPS1OrderStatus, Error> {
986+
let liquidity_source =
987+
self.liquidity_source.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
988+
989+
let (lsp_node_id, lsp_address) = liquidity_source
990+
.get_lsps1_service_details()
991+
.ok_or(Error::LiquiditySourceUnavailable)?;
992+
993+
let rt_lock = self.runtime.read().unwrap();
994+
let runtime = rt_lock.as_ref().unwrap();
995+
996+
let con_node_id = lsp_node_id;
997+
let con_addr = lsp_address.clone();
998+
let con_cm = Arc::clone(&self.connection_manager);
999+
1000+
// We need to use our main runtime here as a local runtime might not be around to poll
1001+
// connection futures going forward.
1002+
tokio::task::block_in_place(move || {
1003+
runtime.block_on(async move {
1004+
con_cm.connect_peer_if_necessary(con_node_id, con_addr).await
1005+
})
1006+
})?;
1007+
1008+
let liquidity_source = Arc::clone(&liquidity_source);
1009+
let response = tokio::task::block_in_place(move || {
1010+
runtime
1011+
.block_on(async move { liquidity_source.lsps1_check_order_status(order_id).await })
1012+
})?;
1013+
1014+
Ok(response)
1015+
}
1016+
}

0 commit comments

Comments
 (0)