Skip to content

Commit 5f1b187

Browse files
committed
Add LSPS5 webhook notification support
Integrates LSPS5 (BLIP-0055) from lightning-liquidity to enable webhook-based push notifications for clients. - Add event system integration for LSPS5 events - Expose public API for webhook management This allows client developers to register webhook endpoints with their LSP to receive notifications when their app is offline.
1 parent 5d0fb14 commit 5f1b187

File tree

8 files changed

+1308
-10
lines changed

8 files changed

+1308
-10
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "
8686
proptest = "1.0.0"
8787
regex = "1.5.6"
8888
criterion = { version = "0.7.0", features = ["async_tokio"] }
89+
rcgen = "0.14.6"
90+
tokio-rustls = "0.26"
8991

9092
[target.'cfg(not(no_download))'.dev-dependencies]
9193
electrsd = { version = "0.36.1", default-features = false, features = ["legacy", "esplora_a33e97e1", "corepc-node_27_2"] }

bindings/ldk_node.udl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,9 @@ enum NodeError {
346346
"LiquidityFeeTooHigh",
347347
"InvalidBlindedPaths",
348348
"AsyncPaymentServicesDisabled",
349+
"LiquiditySetWebhookFailed",
350+
"LiquidityRemoveWebhookFailed",
351+
"LiquidityListWebhooksFailed"
349352
};
350353

351354
dictionary NodeStatus {

src/builder.rs

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ use crate::io::{
6161
self, PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
6262
};
6363
use crate::liquidity::{
64-
LSPS1ClientConfig, LSPS2ClientConfig, LSPS2ServiceConfig, LiquiditySourceBuilder,
64+
LSPS1ClientConfig, LSPS2ClientConfig, LSPS2ServiceConfig, LSPS5ClientConfig,
65+
LiquiditySourceBuilder,
6566
};
6667
use crate::logger::{log_error, LdkLogger, LogLevel, LogWriter, Logger};
6768
use crate::message_handler::NodeCustomMessageHandler;
@@ -71,7 +72,8 @@ use crate::runtime::Runtime;
7172
use crate::tx_broadcaster::TransactionBroadcaster;
7273
use crate::types::{
7374
ChainMonitor, ChannelManager, DynStore, DynStoreWrapper, GossipSync, Graph, KeysManager,
74-
MessageRouter, OnionMessenger, PaymentStore, PeerManager, Persister, SyncAndAsyncKVStore,
75+
LSPS5ServiceConfig, MessageRouter, OnionMessenger, PaymentStore, PeerManager, Persister,
76+
SyncAndAsyncKVStore,
7577
};
7678
use crate::wallet::persist::KVStoreWalletPersister;
7779
use crate::wallet::Wallet;
@@ -119,6 +121,12 @@ struct LiquiditySourceConfig {
119121
lsps2_client: Option<LSPS2ClientConfig>,
120122
// Act as an LSPS2 service.
121123
lsps2_service: Option<LSPS2ServiceConfig>,
124+
// Act as an LSPS5 client connecting to the given service.
125+
lsps5_client: Option<LSPS5ClientConfig>,
126+
// Act as an LSPS5 service.
127+
lsps5_service: Option<LSPS5ServiceConfig>,
128+
// Optional custom HTTP client to be used by LSPS5 service.
129+
http_client: Option<reqwest::Client>,
122130
}
123131

124132
#[derive(Clone)]
@@ -444,6 +452,44 @@ impl NodeBuilder {
444452
self
445453
}
446454

455+
/// Configures the [`Node`] instance to source webhook notifications from the given
456+
/// [bLIP-55 / LSPS5] service.
457+
///
458+
/// This allows the client to register webhook endpoints with the LSP to receive
459+
/// push notifications for Lightning events when the client is offline.
460+
///
461+
/// [bLIP-55 / LSPS5]: https://github.com/lightning/blips/blob/master/blip-0055.md
462+
pub fn set_liquidity_source_lsps5(
463+
&mut self, node_id: PublicKey, address: SocketAddress,
464+
) -> &mut Self {
465+
let liquidity_source_config =
466+
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
467+
let lsps5_client_config = LSPS5ClientConfig { node_id, address };
468+
liquidity_source_config.lsps5_client = Some(lsps5_client_config);
469+
self
470+
}
471+
472+
/// Configures the [`Node`] instance to provide an [LSPS5] service, enabling clients
473+
/// to register webhooks for push notifications.
474+
///
475+
/// [LSPS5]: https://github.com/lightning/blips/blob/master/blip-0055.md
476+
pub fn set_liquidity_provider_lsps5(
477+
&mut self, service_config: LSPS5ServiceConfig,
478+
) -> &mut Self {
479+
let liquidity_source_config =
480+
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
481+
liquidity_source_config.lsps5_service = Some(service_config);
482+
self
483+
}
484+
485+
/// Sets a custom HTTP client to be used by the LSPS5 service.
486+
pub fn set_liquidity_http_client(&mut self, http_client: reqwest::Client) -> &mut Self {
487+
let liquidity_source_config =
488+
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
489+
liquidity_source_config.http_client = Some(http_client);
490+
self
491+
}
492+
447493
/// Sets the used storage directory path.
448494
pub fn set_storage_dir_path(&mut self, storage_dir_path: String) -> &mut Self {
449495
self.config.storage_dir_path = storage_dir_path;
@@ -845,6 +891,30 @@ impl ArcedNodeBuilder {
845891
self.inner.write().unwrap().set_liquidity_provider_lsps2(service_config);
846892
}
847893

894+
/// Configures the [`Node`] instance to source webhook notifications from the given
895+
/// [bLIP-55 / LSPS5] service.
896+
///
897+
/// This allows the client to register webhook endpoints with the LSP to receive
898+
/// push notifications for Lightning events when the client is offline.
899+
///
900+
/// [bLIP-55 / LSPS5]: https://github.com/lightning/blips/blob/master/blip-0055.md
901+
pub fn set_liquidity_source_lsps5(&self, node_id: PublicKey, address: SocketAddress) {
902+
self.inner.write().unwrap().set_liquidity_source_lsps5(node_id, address);
903+
}
904+
905+
/// Configures the [`Node`] instance to provide an [LSPS5] service, enabling clients
906+
/// to register webhooks for push notifications.
907+
///
908+
/// [LSPS5]: https://github.com/lightning/blips/blob/master/blip-0055.md
909+
pub fn set_liquidity_provider_lsps5(&self, service_config: LSPS5ServiceConfig) {
910+
self.inner.write().unwrap().set_liquidity_provider_lsps5(service_config);
911+
}
912+
913+
/// Sets a custom HTTP client to be used by the LSPS5 service.
914+
pub fn set_liquidity_http_client(&self, http_client: reqwest::Client) {
915+
self.inner.write().unwrap().set_liquidity_http_client(http_client);
916+
}
917+
848918
/// Sets the used storage directory path.
849919
pub fn set_storage_dir_path(&self, storage_dir_path: String) {
850920
self.inner.write().unwrap().set_storage_dir_path(storage_dir_path);
@@ -1547,6 +1617,15 @@ fn build_with_store_internal(
15471617
liquidity_source_builder.lsps2_service(promise_secret, config.clone())
15481618
});
15491619

1620+
lsc.lsps5_client.as_ref().map(|config| {
1621+
liquidity_source_builder.lsps5_client(config.node_id, config.address.clone())
1622+
});
1623+
1624+
lsc.lsps5_service.as_ref().map(|config| {
1625+
let http_client = lsc.http_client.clone().unwrap_or_else(|| reqwest::Client::new());
1626+
liquidity_source_builder.lsps5_service_with_http_client(config.clone(), http_client)
1627+
});
1628+
15501629
let liquidity_source = runtime
15511630
.block_on(async move { liquidity_source_builder.build().await.map(Arc::new) })?;
15521631
let custom_message_handler =

src/error.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ pub enum Error {
127127
InvalidBlindedPaths,
128128
/// Asynchronous payment services are disabled.
129129
AsyncPaymentServicesDisabled,
130+
/// Failed to set a webhook with the LSP.
131+
LiquiditySetWebhookFailed,
132+
/// Failed to remove a webhook with the LSP.
133+
LiquidityRemoveWebhookFailed,
134+
/// Failed to list webhooks with the LSP.
135+
LiquidityListWebhooksFailed,
130136
}
131137

132138
impl fmt::Display for Error {
@@ -205,6 +211,15 @@ impl fmt::Display for Error {
205211
Self::AsyncPaymentServicesDisabled => {
206212
write!(f, "Asynchronous payment services are disabled.")
207213
},
214+
Self::LiquiditySetWebhookFailed => {
215+
write!(f, "Failed to set a webhook with the LSP.")
216+
},
217+
Self::LiquidityRemoveWebhookFailed => {
218+
write!(f, "Failed to remove a webhook with the LSP.")
219+
},
220+
Self::LiquidityListWebhooksFailed => {
221+
write!(f, "Failed to list webhooks with the LSP.")
222+
},
208223
}
209224
}
210225
}

src/lib.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ use lightning::ln::msgs::SocketAddress;
146146
use lightning::routing::gossip::NodeAlias;
147147
use lightning::util::persist::KVStoreSync;
148148
use lightning_background_processor::process_events_async;
149-
use liquidity::{LSPS1Liquidity, LiquiditySource};
149+
use liquidity::{LSPS1Liquidity, LSPS5Liquidity, LiquiditySource};
150150
use logger::{log_debug, log_error, log_info, log_trace, LdkLogger, Logger};
151151
use payment::asynchronous::om_mailbox::OnionMessageMailbox;
152152
use payment::asynchronous::static_invoice_store::StaticInvoiceStore;
@@ -1004,6 +1004,32 @@ impl Node {
10041004
))
10051005
}
10061006

1007+
/// Returns a liquidity handler allowing to handle webhooks and notifications via the [bLIP-55 / LSPS5] protocol.
1008+
///
1009+
/// [bLIP-55 / LSPS5]: https://github.com/lightning/blips/blob/master/blip-0055.md
1010+
#[cfg(not(feature = "uniffi"))]
1011+
pub fn lsps5_liquidity(&self) -> LSPS5Liquidity {
1012+
LSPS5Liquidity::new(
1013+
Arc::clone(&self.runtime),
1014+
Arc::clone(&self.connection_manager),
1015+
self.liquidity_source.clone(),
1016+
Arc::clone(&self.logger),
1017+
)
1018+
}
1019+
1020+
/// Returns a liquidity handler allowing to handle webhooks and notifications via the [bLIP-55 / LSPS5] protocol.
1021+
///
1022+
/// [bLIP-55 / LSPS5]: https://github.com/lightning/blips/blob/master/blip-0055.md
1023+
#[cfg(feature = "uniffi")]
1024+
pub fn lsps5_liquidity(&self) -> Arc<LSPS5Liquidity> {
1025+
Arc::new(LSPS5Liquidity::new(
1026+
Arc::clone(&self.runtime),
1027+
Arc::clone(&self.connection_manager),
1028+
self.liquidity_source.clone(),
1029+
Arc::clone(&self.logger),
1030+
))
1031+
}
1032+
10071033
/// Retrieve a list of known channels.
10081034
pub fn list_channels(&self) -> Vec<ChannelDetails> {
10091035
self.channel_manager.list_channels().into_iter().map(|c| c.into()).collect()

0 commit comments

Comments
 (0)