Skip to content

Commit f1fdee5

Browse files
authored
Merge pull request #418 from tnull/2024-07-lsps1-integration
2 parents 5f0ab5d + b1a277c commit f1fdee5

File tree

8 files changed

+870
-69
lines changed

8 files changed

+870
-69
lines changed

bindings/ldk_node.udl

+71-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ interface Builder {
5858
void set_chain_source_bitcoind_rpc(string rpc_host, u16 rpc_port, string rpc_user, string rpc_password);
5959
void set_gossip_source_p2p();
6060
void set_gossip_source_rgs(string rgs_server_url);
61-
void set_liquidity_source_lsps2(SocketAddress address, PublicKey node_id, string? token);
61+
void set_liquidity_source_lsps1(PublicKey node_id, SocketAddress address, string? token);
62+
void set_liquidity_source_lsps2(PublicKey node_id, SocketAddress address, string? token);
6263
void set_storage_dir_path(string storage_dir_path);
6364
void set_filesystem_logger(string? log_file_path, LogLevel? max_log_level);
6465
void set_log_facade_logger(LogLevel? max_log_level);
@@ -100,6 +101,7 @@ interface Node {
100101
SpontaneousPayment spontaneous_payment();
101102
OnchainPayment onchain_payment();
102103
UnifiedQrPayment unified_qr_payment();
104+
LSPS1Liquidity lsps1_liquidity();
103105
[Throws=NodeError]
104106
void connect(PublicKey node_id, SocketAddress address, boolean persist);
105107
[Throws=NodeError]
@@ -213,6 +215,13 @@ interface UnifiedQrPayment {
213215
QrPaymentResult send([ByRef]string uri_str);
214216
};
215217

218+
interface LSPS1Liquidity {
219+
[Throws=NodeError]
220+
LSPS1OrderStatus request_channel(u64 lsp_balance_sat, u64 client_balance_sat, u32 channel_expiry_blocks, boolean announce_channel);
221+
[Throws=NodeError]
222+
LSPS1OrderStatus check_order_status(OrderId order_id);
223+
};
224+
216225
[Error]
217226
enum NodeError {
218227
"AlreadyRunning",
@@ -260,6 +269,8 @@ enum NodeError {
260269
"InvalidUri",
261270
"InvalidQuantity",
262271
"InvalidNodeAlias",
272+
"InvalidDateTime",
273+
"InvalidFeeRate",
263274
"DuplicatePayment",
264275
"UnsupportedCurrency",
265276
"InsufficientFunds",
@@ -418,6 +429,59 @@ dictionary CustomTlvRecord {
418429
sequence<u8> value;
419430
};
420431

432+
dictionary LSPS1OrderStatus {
433+
OrderId order_id;
434+
OrderParameters order_params;
435+
PaymentInfo payment_options;
436+
ChannelOrderInfo? channel_state;
437+
};
438+
439+
dictionary OrderParameters {
440+
u64 lsp_balance_sat;
441+
u64 client_balance_sat;
442+
u16 required_channel_confirmations;
443+
u16 funding_confirms_within_blocks;
444+
u32 channel_expiry_blocks;
445+
string? token;
446+
boolean announce_channel;
447+
};
448+
449+
dictionary PaymentInfo {
450+
Bolt11PaymentInfo? bolt11;
451+
OnchainPaymentInfo? onchain;
452+
};
453+
454+
dictionary Bolt11PaymentInfo {
455+
PaymentState state;
456+
DateTime expires_at;
457+
u64 fee_total_sat;
458+
u64 order_total_sat;
459+
Bolt11Invoice invoice;
460+
};
461+
462+
dictionary OnchainPaymentInfo {
463+
PaymentState state;
464+
DateTime expires_at;
465+
u64 fee_total_sat;
466+
u64 order_total_sat;
467+
Address address;
468+
u16? min_onchain_payment_confirmations;
469+
FeeRate min_fee_for_0conf;
470+
Address? refund_onchain_address;
471+
};
472+
473+
dictionary ChannelOrderInfo {
474+
DateTime funded_at;
475+
OutPoint funding_outpoint;
476+
DateTime expires_at;
477+
};
478+
479+
enum PaymentState {
480+
"ExpectPayment",
481+
"Paid",
482+
"Refunded",
483+
};
484+
421485
[Enum]
422486
interface MaxTotalRoutingFeeLimit {
423487
None ();
@@ -664,3 +728,9 @@ typedef string UntrustedString;
664728

665729
[Custom]
666730
typedef string NodeAlias;
731+
732+
[Custom]
733+
typedef string OrderId;
734+
735+
[Custom]
736+
typedef string DateTime;

src/builder.rs

+70-41
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::gossip::GossipSource;
1818
use crate::io::sqlite_store::SqliteStore;
1919
use crate::io::utils::{read_node_metrics, write_node_metrics};
2020
use crate::io::vss_store::VssStore;
21-
use crate::liquidity::LiquiditySource;
21+
use crate::liquidity::LiquiditySourceBuilder;
2222
use crate::logger::{log_error, log_info, LdkLogger, LogLevel, LogWriter, Logger};
2323
use crate::message_handler::NodeCustomMessageHandler;
2424
use crate::payment::store::PaymentStore;
@@ -54,9 +54,6 @@ use lightning::util::sweep::OutputSweeper;
5454

5555
use lightning_persister::fs_store::FilesystemStore;
5656

57-
use lightning_liquidity::lsps2::client::LSPS2ClientConfig;
58-
use lightning_liquidity::{LiquidityClientConfig, LiquidityManager};
59-
6057
use bdk_wallet::template::Bip84;
6158
use bdk_wallet::KeychainKind;
6259
use bdk_wallet::Wallet as BdkWallet;
@@ -99,13 +96,15 @@ enum GossipSourceConfig {
9996

10097
#[derive(Debug, Clone)]
10198
struct LiquiditySourceConfig {
102-
// LSPS2 service's (address, node_id, token)
103-
lsps2_service: Option<(SocketAddress, PublicKey, Option<String>)>,
99+
// LSPS1 service's (node_id, address, token)
100+
lsps1_service: Option<(PublicKey, SocketAddress, Option<String>)>,
101+
// LSPS2 service's (node_id, address, token)
102+
lsps2_service: Option<(PublicKey, SocketAddress, Option<String>)>,
104103
}
105104

106105
impl Default for LiquiditySourceConfig {
107106
fn default() -> Self {
108-
Self { lsps2_service: None }
107+
Self { lsps1_service: None, lsps2_service: None }
109108
}
110109
}
111110

@@ -304,22 +303,43 @@ impl NodeBuilder {
304303
self
305304
}
306305

307-
/// Configures the [`Node`] instance to source its inbound liquidity from the given
308-
/// [LSPS2](https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md)
309-
/// service.
306+
/// Configures the [`Node`] instance to source inbound liquidity from the given
307+
/// [bLIP-51 / LSPS1] service.
308+
///
309+
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
310+
///
311+
/// The given `token` will be used by the LSP to authenticate the user.
312+
///
313+
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
314+
pub fn set_liquidity_source_lsps1(
315+
&mut self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
316+
) -> &mut Self {
317+
// Mark the LSP as trusted for 0conf
318+
self.config.trusted_peers_0conf.push(node_id.clone());
319+
320+
let liquidity_source_config =
321+
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
322+
liquidity_source_config.lsps1_service = Some((node_id, address, token));
323+
self
324+
}
325+
326+
/// Configures the [`Node`] instance to source just-in-time inbound liquidity from the given
327+
/// [bLIP-52 / LSPS2] service.
310328
///
311329
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
312330
///
313331
/// The given `token` will be used by the LSP to authenticate the user.
332+
///
333+
/// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
314334
pub fn set_liquidity_source_lsps2(
315-
&mut self, address: SocketAddress, node_id: PublicKey, token: Option<String>,
335+
&mut self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
316336
) -> &mut Self {
317337
// Mark the LSP as trusted for 0conf
318338
self.config.trusted_peers_0conf.push(node_id.clone());
319339

320340
let liquidity_source_config =
321341
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
322-
liquidity_source_config.lsps2_service = Some((address, node_id, token));
342+
liquidity_source_config.lsps2_service = Some((node_id, address, token));
323343
self
324344
}
325345

@@ -643,17 +663,32 @@ impl ArcedNodeBuilder {
643663
self.inner.write().unwrap().set_gossip_source_rgs(rgs_server_url);
644664
}
645665

646-
/// Configures the [`Node`] instance to source its inbound liquidity from the given
647-
/// [LSPS2](https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md)
648-
/// service.
666+
/// Configures the [`Node`] instance to source inbound liquidity from the given
667+
/// [bLIP-51 / LSPS1] service.
649668
///
650669
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
651670
///
652671
/// The given `token` will be used by the LSP to authenticate the user.
672+
///
673+
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
674+
pub fn set_liquidity_source_lsps1(
675+
&self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
676+
) {
677+
self.inner.write().unwrap().set_liquidity_source_lsps1(node_id, address, token);
678+
}
679+
680+
/// Configures the [`Node`] instance to source just-in-time inbound liquidity from the given
681+
/// [bLIP-52 / LSPS2] service.
682+
///
683+
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
684+
///
685+
/// The given `token` will be used by the LSP to authenticate the user.
686+
///
687+
/// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
653688
pub fn set_liquidity_source_lsps2(
654-
&self, address: SocketAddress, node_id: PublicKey, token: Option<String>,
689+
&self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
655690
) {
656-
self.inner.write().unwrap().set_liquidity_source_lsps2(address, node_id, token);
691+
self.inner.write().unwrap().set_liquidity_source_lsps2(node_id, address, token);
657692
}
658693

659694
/// Sets the used storage directory path.
@@ -1136,30 +1171,24 @@ fn build_with_store_internal(
11361171
},
11371172
};
11381173

1139-
let liquidity_source = liquidity_source_config.as_ref().and_then(|lsc| {
1140-
lsc.lsps2_service.as_ref().map(|(address, node_id, token)| {
1141-
let lsps2_client_config = Some(LSPS2ClientConfig {});
1142-
let liquidity_client_config =
1143-
Some(LiquidityClientConfig { lsps1_client_config: None, lsps2_client_config });
1144-
let liquidity_manager = Arc::new(LiquidityManager::new(
1145-
Arc::clone(&keys_manager),
1146-
Arc::clone(&channel_manager),
1147-
Some(Arc::clone(&chain_source)),
1148-
None,
1149-
None,
1150-
liquidity_client_config,
1151-
));
1152-
Arc::new(LiquiditySource::new_lsps2(
1153-
address.clone(),
1154-
*node_id,
1155-
token.clone(),
1156-
Arc::clone(&channel_manager),
1157-
Arc::clone(&keys_manager),
1158-
liquidity_manager,
1159-
Arc::clone(&config),
1160-
Arc::clone(&logger),
1161-
))
1162-
})
1174+
let liquidity_source = liquidity_source_config.as_ref().map(|lsc| {
1175+
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
1176+
Arc::clone(&channel_manager),
1177+
Arc::clone(&keys_manager),
1178+
Arc::clone(&chain_source),
1179+
Arc::clone(&config),
1180+
Arc::clone(&logger),
1181+
);
1182+
1183+
lsc.lsps1_service.as_ref().map(|(node_id, address, token)| {
1184+
liquidity_source_builder.lsps1_service(*node_id, address.clone(), token.clone())
1185+
});
1186+
1187+
lsc.lsps2_service.as_ref().map(|(node_id, address, token)| {
1188+
liquidity_source_builder.lsps2_service(*node_id, address.clone(), token.clone())
1189+
});
1190+
1191+
Arc::new(liquidity_source_builder.build())
11631192
});
11641193

11651194
let custom_message_handler = if let Some(liquidity_source) = liquidity_source.as_ref() {

src/error.rs

+6
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ pub enum Error {
106106
InvalidQuantity,
107107
/// The given node alias is invalid.
108108
InvalidNodeAlias,
109+
/// The given date time is invalid.
110+
InvalidDateTime,
111+
/// The given fee rate is invalid.
112+
InvalidFeeRate,
109113
/// A payment with the given hash has already been initiated.
110114
DuplicatePayment,
111115
/// The provided offer was denonminated in an unsupported currency.
@@ -172,6 +176,8 @@ impl fmt::Display for Error {
172176
Self::InvalidUri => write!(f, "The given URI is invalid."),
173177
Self::InvalidQuantity => write!(f, "The given quantity is invalid."),
174178
Self::InvalidNodeAlias => write!(f, "The given node alias is invalid."),
179+
Self::InvalidDateTime => write!(f, "The given date time is invalid."),
180+
Self::InvalidFeeRate => write!(f, "The given fee rate is invalid."),
175181
Self::DuplicatePayment => {
176182
write!(f, "A payment with the given hash has already been initiated.")
177183
},

src/lib.rs

+31-2
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,
@@ -949,6 +950,34 @@ impl Node {
949950
))
950951
}
951952

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

0 commit comments

Comments
 (0)