Skip to content

Commit

Permalink
Merge pull request #418 from tnull/2024-07-lsps1-integration
Browse files Browse the repository at this point in the history
  • Loading branch information
tnull authored Feb 6, 2025
2 parents 5f0ab5d + b1a277c commit f1fdee5
Show file tree
Hide file tree
Showing 8 changed files with 870 additions and 69 deletions.
72 changes: 71 additions & 1 deletion bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ interface Builder {
void set_chain_source_bitcoind_rpc(string rpc_host, u16 rpc_port, string rpc_user, string rpc_password);
void set_gossip_source_p2p();
void set_gossip_source_rgs(string rgs_server_url);
void set_liquidity_source_lsps2(SocketAddress address, PublicKey node_id, string? token);
void set_liquidity_source_lsps1(PublicKey node_id, SocketAddress address, string? token);
void set_liquidity_source_lsps2(PublicKey node_id, SocketAddress address, string? token);
void set_storage_dir_path(string storage_dir_path);
void set_filesystem_logger(string? log_file_path, LogLevel? max_log_level);
void set_log_facade_logger(LogLevel? max_log_level);
Expand Down Expand Up @@ -100,6 +101,7 @@ interface Node {
SpontaneousPayment spontaneous_payment();
OnchainPayment onchain_payment();
UnifiedQrPayment unified_qr_payment();
LSPS1Liquidity lsps1_liquidity();
[Throws=NodeError]
void connect(PublicKey node_id, SocketAddress address, boolean persist);
[Throws=NodeError]
Expand Down Expand Up @@ -213,6 +215,13 @@ interface UnifiedQrPayment {
QrPaymentResult send([ByRef]string uri_str);
};

interface LSPS1Liquidity {
[Throws=NodeError]
LSPS1OrderStatus request_channel(u64 lsp_balance_sat, u64 client_balance_sat, u32 channel_expiry_blocks, boolean announce_channel);
[Throws=NodeError]
LSPS1OrderStatus check_order_status(OrderId order_id);
};

[Error]
enum NodeError {
"AlreadyRunning",
Expand Down Expand Up @@ -260,6 +269,8 @@ enum NodeError {
"InvalidUri",
"InvalidQuantity",
"InvalidNodeAlias",
"InvalidDateTime",
"InvalidFeeRate",
"DuplicatePayment",
"UnsupportedCurrency",
"InsufficientFunds",
Expand Down Expand Up @@ -418,6 +429,59 @@ dictionary CustomTlvRecord {
sequence<u8> value;
};

dictionary LSPS1OrderStatus {
OrderId order_id;
OrderParameters order_params;
PaymentInfo payment_options;
ChannelOrderInfo? channel_state;
};

dictionary OrderParameters {
u64 lsp_balance_sat;
u64 client_balance_sat;
u16 required_channel_confirmations;
u16 funding_confirms_within_blocks;
u32 channel_expiry_blocks;
string? token;
boolean announce_channel;
};

dictionary PaymentInfo {
Bolt11PaymentInfo? bolt11;
OnchainPaymentInfo? onchain;
};

dictionary Bolt11PaymentInfo {
PaymentState state;
DateTime expires_at;
u64 fee_total_sat;
u64 order_total_sat;
Bolt11Invoice invoice;
};

dictionary OnchainPaymentInfo {
PaymentState state;
DateTime expires_at;
u64 fee_total_sat;
u64 order_total_sat;
Address address;
u16? min_onchain_payment_confirmations;
FeeRate min_fee_for_0conf;
Address? refund_onchain_address;
};

dictionary ChannelOrderInfo {
DateTime funded_at;
OutPoint funding_outpoint;
DateTime expires_at;
};

enum PaymentState {
"ExpectPayment",
"Paid",
"Refunded",
};

[Enum]
interface MaxTotalRoutingFeeLimit {
None ();
Expand Down Expand Up @@ -664,3 +728,9 @@ typedef string UntrustedString;

[Custom]
typedef string NodeAlias;

[Custom]
typedef string OrderId;

[Custom]
typedef string DateTime;
111 changes: 70 additions & 41 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::gossip::GossipSource;
use crate::io::sqlite_store::SqliteStore;
use crate::io::utils::{read_node_metrics, write_node_metrics};
use crate::io::vss_store::VssStore;
use crate::liquidity::LiquiditySource;
use crate::liquidity::LiquiditySourceBuilder;
use crate::logger::{log_error, log_info, LdkLogger, LogLevel, LogWriter, Logger};
use crate::message_handler::NodeCustomMessageHandler;
use crate::payment::store::PaymentStore;
Expand Down Expand Up @@ -54,9 +54,6 @@ use lightning::util::sweep::OutputSweeper;

use lightning_persister::fs_store::FilesystemStore;

use lightning_liquidity::lsps2::client::LSPS2ClientConfig;
use lightning_liquidity::{LiquidityClientConfig, LiquidityManager};

use bdk_wallet::template::Bip84;
use bdk_wallet::KeychainKind;
use bdk_wallet::Wallet as BdkWallet;
Expand Down Expand Up @@ -99,13 +96,15 @@ enum GossipSourceConfig {

#[derive(Debug, Clone)]
struct LiquiditySourceConfig {
// LSPS2 service's (address, node_id, token)
lsps2_service: Option<(SocketAddress, PublicKey, Option<String>)>,
// LSPS1 service's (node_id, address, token)
lsps1_service: Option<(PublicKey, SocketAddress, Option<String>)>,
// LSPS2 service's (node_id, address, token)
lsps2_service: Option<(PublicKey, SocketAddress, Option<String>)>,
}

impl Default for LiquiditySourceConfig {
fn default() -> Self {
Self { lsps2_service: None }
Self { lsps1_service: None, lsps2_service: None }
}
}

Expand Down Expand Up @@ -304,22 +303,43 @@ impl NodeBuilder {
self
}

/// Configures the [`Node`] instance to source its inbound liquidity from the given
/// [LSPS2](https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md)
/// service.
/// Configures the [`Node`] instance to source inbound liquidity from the given
/// [bLIP-51 / LSPS1] service.
///
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
///
/// The given `token` will be used by the LSP to authenticate the user.
///
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
pub fn set_liquidity_source_lsps1(
&mut self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
) -> &mut Self {
// Mark the LSP as trusted for 0conf
self.config.trusted_peers_0conf.push(node_id.clone());

let liquidity_source_config =
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
liquidity_source_config.lsps1_service = Some((node_id, address, token));
self
}

/// Configures the [`Node`] instance to source just-in-time inbound liquidity from the given
/// [bLIP-52 / LSPS2] service.
///
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
///
/// The given `token` will be used by the LSP to authenticate the user.
///
/// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
pub fn set_liquidity_source_lsps2(
&mut self, address: SocketAddress, node_id: PublicKey, token: Option<String>,
&mut self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
) -> &mut Self {
// Mark the LSP as trusted for 0conf
self.config.trusted_peers_0conf.push(node_id.clone());

let liquidity_source_config =
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
liquidity_source_config.lsps2_service = Some((address, node_id, token));
liquidity_source_config.lsps2_service = Some((node_id, address, token));
self
}

Expand Down Expand Up @@ -643,17 +663,32 @@ impl ArcedNodeBuilder {
self.inner.write().unwrap().set_gossip_source_rgs(rgs_server_url);
}

/// Configures the [`Node`] instance to source its inbound liquidity from the given
/// [LSPS2](https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md)
/// service.
/// Configures the [`Node`] instance to source inbound liquidity from the given
/// [bLIP-51 / LSPS1] service.
///
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
///
/// The given `token` will be used by the LSP to authenticate the user.
///
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
pub fn set_liquidity_source_lsps1(
&self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
) {
self.inner.write().unwrap().set_liquidity_source_lsps1(node_id, address, token);
}

/// Configures the [`Node`] instance to source just-in-time inbound liquidity from the given
/// [bLIP-52 / LSPS2] service.
///
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
///
/// The given `token` will be used by the LSP to authenticate the user.
///
/// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
pub fn set_liquidity_source_lsps2(
&self, address: SocketAddress, node_id: PublicKey, token: Option<String>,
&self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
) {
self.inner.write().unwrap().set_liquidity_source_lsps2(address, node_id, token);
self.inner.write().unwrap().set_liquidity_source_lsps2(node_id, address, token);
}

/// Sets the used storage directory path.
Expand Down Expand Up @@ -1136,30 +1171,24 @@ fn build_with_store_internal(
},
};

let liquidity_source = liquidity_source_config.as_ref().and_then(|lsc| {
lsc.lsps2_service.as_ref().map(|(address, node_id, token)| {
let lsps2_client_config = Some(LSPS2ClientConfig {});
let liquidity_client_config =
Some(LiquidityClientConfig { lsps1_client_config: None, lsps2_client_config });
let liquidity_manager = Arc::new(LiquidityManager::new(
Arc::clone(&keys_manager),
Arc::clone(&channel_manager),
Some(Arc::clone(&chain_source)),
None,
None,
liquidity_client_config,
));
Arc::new(LiquiditySource::new_lsps2(
address.clone(),
*node_id,
token.clone(),
Arc::clone(&channel_manager),
Arc::clone(&keys_manager),
liquidity_manager,
Arc::clone(&config),
Arc::clone(&logger),
))
})
let liquidity_source = liquidity_source_config.as_ref().map(|lsc| {
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
Arc::clone(&channel_manager),
Arc::clone(&keys_manager),
Arc::clone(&chain_source),
Arc::clone(&config),
Arc::clone(&logger),
);

lsc.lsps1_service.as_ref().map(|(node_id, address, token)| {
liquidity_source_builder.lsps1_service(*node_id, address.clone(), token.clone())
});

lsc.lsps2_service.as_ref().map(|(node_id, address, token)| {
liquidity_source_builder.lsps2_service(*node_id, address.clone(), token.clone())
});

Arc::new(liquidity_source_builder.build())
});

let custom_message_handler = if let Some(liquidity_source) = liquidity_source.as_ref() {
Expand Down
6 changes: 6 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ pub enum Error {
InvalidQuantity,
/// The given node alias is invalid.
InvalidNodeAlias,
/// The given date time is invalid.
InvalidDateTime,
/// The given fee rate is invalid.
InvalidFeeRate,
/// A payment with the given hash has already been initiated.
DuplicatePayment,
/// The provided offer was denonminated in an unsupported currency.
Expand Down Expand Up @@ -172,6 +176,8 @@ impl fmt::Display for Error {
Self::InvalidUri => write!(f, "The given URI is invalid."),
Self::InvalidQuantity => write!(f, "The given quantity is invalid."),
Self::InvalidNodeAlias => write!(f, "The given node alias is invalid."),
Self::InvalidDateTime => write!(f, "The given date time is invalid."),
Self::InvalidFeeRate => write!(f, "The given fee rate is invalid."),
Self::DuplicatePayment => {
write!(f, "A payment with the given hash has already been initiated.")
},
Expand Down
33 changes: 31 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ mod gossip;
pub mod graph;
mod hex_utils;
pub mod io;
mod liquidity;
pub mod liquidity;
pub mod logger;
mod message_handler;
pub mod payment;
Expand All @@ -100,6 +100,7 @@ pub use bip39;
pub use bitcoin;
pub use lightning;
pub use lightning_invoice;
pub use lightning_liquidity;
pub use lightning_types;
pub use vss_client;

Expand Down Expand Up @@ -130,7 +131,7 @@ use event::{EventHandler, EventQueue};
use gossip::GossipSource;
use graph::NetworkGraph;
use io::utils::write_node_metrics;
use liquidity::LiquiditySource;
use liquidity::{LSPS1Liquidity, LiquiditySource};
use payment::store::PaymentStore;
use payment::{
Bolt11Payment, Bolt12Payment, OnchainPayment, PaymentDetails, SpontaneousPayment,
Expand Down Expand Up @@ -949,6 +950,34 @@ impl Node {
))
}

/// Returns a liquidity handler allowing to request channels via the [bLIP-51 / LSPS1] protocol.
///
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
#[cfg(not(feature = "uniffi"))]
pub fn lsps1_liquidity(&self) -> LSPS1Liquidity {
LSPS1Liquidity::new(
Arc::clone(&self.runtime),
Arc::clone(&self.wallet),
Arc::clone(&self.connection_manager),
self.liquidity_source.clone(),
Arc::clone(&self.logger),
)
}

/// Returns a liquidity handler allowing to request channels via the [bLIP-51 / LSPS1] protocol.
///
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
#[cfg(feature = "uniffi")]
pub fn lsps1_liquidity(&self) -> Arc<LSPS1Liquidity> {
Arc::new(LSPS1Liquidity::new(
Arc::clone(&self.runtime),
Arc::clone(&self.wallet),
Arc::clone(&self.connection_manager),
self.liquidity_source.clone(),
Arc::clone(&self.logger),
))
}

/// Retrieve a list of known channels.
pub fn list_channels(&self) -> Vec<ChannelDetails> {
self.channel_manager.list_channels().into_iter().map(|c| c.into()).collect()
Expand Down
Loading

0 comments on commit f1fdee5

Please sign in to comment.