Skip to content

Commit b2fcb95

Browse files
committed
Receive BOLT12 payments through LSPS2 JIT channels
Route BOLT12 payments through the LSPS2-aware router and expose JIT-channel receive flows so offers can carry the LSP invoice parameters needed for intercepted payments. Co-Authored-By: HAL 9000
1 parent ab61bcf commit b2fcb95

5 files changed

Lines changed: 449 additions & 36 deletions

File tree

src/builder.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use lightning::util::persist::{
4343
use lightning::util::ser::ReadableArgs;
4444
use lightning::util::sweep::OutputSweeper;
4545
use lightning_dns_resolver::OMDomainResolver;
46+
use lightning_liquidity::lsps2::router::LSPS2BOLT12Router;
4647
use vss_client::headers::VssHeaderProvider;
4748

4849
use crate::chain::ChainSource;
@@ -75,13 +76,14 @@ use crate::lnurl_auth::LnurlAuth;
7576
use crate::logger::{log_error, LdkLogger, LogLevel, LogWriter, Logger};
7677
use crate::message_handler::NodeCustomMessageHandler;
7778
use crate::payment::asynchronous::om_mailbox::OnionMessageMailbox;
79+
use crate::payment::LdkNodeLSPS2Bolt12PaymentMetadataDecoder;
7880
use crate::peer_store::PeerStore;
7981
use crate::runtime::{Runtime, RuntimeSpawner};
8082
use crate::tx_broadcaster::TransactionBroadcaster;
8183
use crate::types::{
8284
AsyncPersister, ChainMonitor, ChannelManager, DynStore, DynStoreRef, DynStoreWrapper,
83-
GossipSync, Graph, HRNResolver, KeysManager, MessageRouter, OnionMessenger, PaymentStore,
84-
PeerManager, PendingPaymentStore,
85+
GossipSync, Graph, HRNResolver, InnerMessageRouter, KeysManager, MessageRouter, OnionMessenger,
86+
PaymentStore, PeerManager, PendingPaymentStore,
8587
};
8688
use crate::wallet::persist::KVStoreWalletPersister;
8789
use crate::wallet::Wallet;
@@ -1778,12 +1780,19 @@ fn build_with_store_internal(
17781780
}
17791781

17801782
let scoring_fee_params = ProbabilisticScoringFeeParameters::default();
1781-
let router = Arc::new(DefaultRouter::new(
1783+
let inner_router = DefaultRouter::new(
17821784
Arc::clone(&network_graph),
17831785
Arc::clone(&logger),
17841786
Arc::clone(&keys_manager),
17851787
Arc::clone(&scorer),
17861788
scoring_fee_params,
1789+
);
1790+
let inner_message_router =
1791+
InnerMessageRouter::new(Arc::clone(&network_graph), Arc::clone(&keys_manager));
1792+
let router = Arc::new(LSPS2BOLT12Router::new_with_payment_metadata_decoder(
1793+
inner_router,
1794+
Arc::clone(&keys_manager),
1795+
LdkNodeLSPS2Bolt12PaymentMetadataDecoder,
17871796
));
17881797

17891798
let mut user_config = default_user_config(&config);
@@ -1807,8 +1816,7 @@ fn build_with_store_internal(
18071816
}
18081817
}
18091818

1810-
let message_router =
1811-
Arc::new(MessageRouter::new(Arc::clone(&network_graph), Arc::clone(&keys_manager)));
1819+
let message_router: Arc<MessageRouter> = Arc::new(inner_message_router);
18121820

18131821
// Initialize the ChannelManager
18141822
let channel_manager = {
@@ -1927,7 +1935,7 @@ fn build_with_store_internal(
19271935
Arc::clone(&keys_manager),
19281936
Arc::clone(&logger),
19291937
Arc::clone(&channel_manager),
1930-
message_router,
1938+
Arc::clone(&message_router),
19311939
Arc::clone(&channel_manager),
19321940
Arc::clone(&channel_manager),
19331941
Arc::clone(&om_resolver),
@@ -1940,7 +1948,7 @@ fn build_with_store_internal(
19401948
Arc::clone(&keys_manager),
19411949
Arc::clone(&logger),
19421950
Arc::clone(&channel_manager),
1943-
message_router,
1951+
Arc::clone(&message_router),
19441952
Arc::clone(&channel_manager),
19451953
Arc::clone(&channel_manager),
19461954
Arc::clone(&om_resolver),
@@ -2168,6 +2176,7 @@ fn build_with_store_internal(
21682176
output_sweeper,
21692177
peer_manager,
21702178
onion_messenger,
2179+
message_router,
21712180
connection_manager,
21722181
keys_manager,
21732182
network_graph,

src/lib.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
113113
#[cfg(cycle_tests)]
114114
use std::{any::Any, sync::Weak};
115115

116-
use crate::ffi::maybe_wrap;
117116
pub use balance::{BalanceDetails, LightningBalance, PendingSweepBalance};
118117
pub use bip39;
119118
pub use bitcoin;
@@ -177,12 +176,13 @@ use runtime::Runtime;
177176
pub use tokio;
178177
use types::{
179178
Broadcaster, BumpTransactionEventHandler, ChainMonitor, ChannelManager, DynStore, Graph,
180-
HRNResolver, KeysManager, OnionMessenger, PaymentStore, PeerManager, Router, Scorer, Sweeper,
181-
Wallet,
179+
HRNResolver, KeysManager, MessageRouter, OnionMessenger, PaymentStore, PeerManager, Router,
180+
Scorer, Sweeper, Wallet,
182181
};
183182
pub use types::{ChannelDetails, CustomTlvRecord, PeerDetails, UserChannelId};
184183
pub use vss_client;
185184

185+
use crate::ffi::maybe_wrap;
186186
use crate::scoring::setup_background_pathfinding_scores_sync;
187187
use crate::wallet::FundingAmount;
188188

@@ -229,6 +229,7 @@ pub struct Node {
229229
output_sweeper: Arc<Sweeper>,
230230
peer_manager: Arc<PeerManager>,
231231
onion_messenger: Arc<OnionMessenger>,
232+
message_router: Arc<MessageRouter>,
232233
connection_manager: Arc<ConnectionManager<Arc<Logger>>>,
233234
keys_manager: Arc<KeysManager>,
234235
network_graph: Arc<Graph>,
@@ -928,8 +929,12 @@ impl Node {
928929
Bolt12Payment::new(
929930
Arc::clone(&self.runtime),
930931
Arc::clone(&self.channel_manager),
932+
Arc::clone(&self.message_router),
933+
Arc::clone(&self.connection_manager),
934+
self.liquidity_source.clone(),
931935
Arc::clone(&self.keys_manager),
932936
Arc::clone(&self.payment_store),
937+
Arc::clone(&self.peer_store),
933938
Arc::clone(&self.config),
934939
Arc::clone(&self.is_running),
935940
Arc::clone(&self.logger),
@@ -945,8 +950,12 @@ impl Node {
945950
Arc::new(Bolt12Payment::new(
946951
Arc::clone(&self.runtime),
947952
Arc::clone(&self.channel_manager),
953+
Arc::clone(&self.message_router),
954+
Arc::clone(&self.connection_manager),
955+
self.liquidity_source.clone(),
948956
Arc::clone(&self.keys_manager),
949957
Arc::clone(&self.payment_store),
958+
Arc::clone(&self.peer_store),
950959
Arc::clone(&self.config),
951960
Arc::clone(&self.is_running),
952961
Arc::clone(&self.logger),

src/liquidity.rs

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use lightning_liquidity::lsps1::msgs::{
3333
use lightning_liquidity::lsps2::client::LSPS2ClientConfig as LdkLSPS2ClientConfig;
3434
use lightning_liquidity::lsps2::event::{LSPS2ClientEvent, LSPS2ServiceEvent};
3535
use lightning_liquidity::lsps2::msgs::{LSPS2OpeningFeeParams, LSPS2RawOpeningFeeParams};
36+
use lightning_liquidity::lsps2::router::LSPS2Bolt12InvoiceParameters;
3637
use lightning_liquidity::lsps2::service::LSPS2ServiceConfig as LdkLSPS2ServiceConfig;
3738
use lightning_liquidity::lsps2::utils::compute_opening_fee;
3839
use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig};
@@ -1232,6 +1233,114 @@ where
12321233
Ok(invoice)
12331234
}
12341235

1236+
pub(crate) async fn lsps2_bolt12_payment_metadata(
1237+
&self, amount_msat: u64, max_total_lsp_fee_limit_msat: Option<u64>,
1238+
) -> Result<(u64, PaymentMetadata), Error> {
1239+
let fee_response = self.lsps2_request_opening_fee_params().await?;
1240+
1241+
let (min_total_fee_msat, min_opening_params) = fee_response
1242+
.opening_fee_params_menu
1243+
.into_iter()
1244+
.filter_map(|params| {
1245+
if amount_msat < params.min_payment_size_msat
1246+
|| amount_msat > params.max_payment_size_msat
1247+
{
1248+
log_debug!(self.logger,
1249+
"Skipping LSP-offered JIT parameters as the payment of {}msat doesn't meet LSP limits (min: {}msat, max: {}msat)",
1250+
amount_msat,
1251+
params.min_payment_size_msat,
1252+
params.max_payment_size_msat
1253+
);
1254+
None
1255+
} else {
1256+
compute_opening_fee(amount_msat, params.min_fee_msat, params.proportional as u64)
1257+
.map(|fee| (fee, params))
1258+
}
1259+
})
1260+
.min_by_key(|p| p.0)
1261+
.ok_or_else(|| {
1262+
log_error!(self.logger, "Failed to handle response from liquidity service",);
1263+
Error::LiquidityRequestFailed
1264+
})?;
1265+
1266+
if let Some(max_total_lsp_fee_limit_msat) = max_total_lsp_fee_limit_msat {
1267+
if min_total_fee_msat > max_total_lsp_fee_limit_msat {
1268+
log_error!(self.logger,
1269+
"Failed to request inbound JIT channel as LSP's requested total opening fee of {}msat exceeds our fee limit of {}msat",
1270+
min_total_fee_msat, max_total_lsp_fee_limit_msat
1271+
);
1272+
return Err(Error::LiquidityFeeTooHigh);
1273+
}
1274+
}
1275+
1276+
let buy_response =
1277+
self.lsps2_send_buy_request(Some(amount_msat), min_opening_params).await?;
1278+
let metadata = self.lsps2_bolt12_metadata_from_buy_response(
1279+
buy_response,
1280+
LSPS2Parameters {
1281+
max_total_opening_fee_msat: Some(min_total_fee_msat),
1282+
max_proportional_opening_fee_ppm_msat: None,
1283+
},
1284+
)?;
1285+
1286+
Ok((min_total_fee_msat, metadata))
1287+
}
1288+
1289+
pub(crate) async fn lsps2_variable_amount_bolt12_payment_metadata(
1290+
&self, max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
1291+
) -> Result<(u64, PaymentMetadata), Error> {
1292+
let fee_response = self.lsps2_request_opening_fee_params().await?;
1293+
1294+
let (min_prop_fee_ppm_msat, min_opening_params) = fee_response
1295+
.opening_fee_params_menu
1296+
.into_iter()
1297+
.map(|params| (params.proportional as u64, params))
1298+
.min_by_key(|p| p.0)
1299+
.ok_or_else(|| {
1300+
log_error!(self.logger, "Failed to handle response from liquidity service",);
1301+
Error::LiquidityRequestFailed
1302+
})?;
1303+
1304+
if let Some(max_proportional_lsp_fee_limit_ppm_msat) =
1305+
max_proportional_lsp_fee_limit_ppm_msat
1306+
{
1307+
if min_prop_fee_ppm_msat > max_proportional_lsp_fee_limit_ppm_msat {
1308+
log_error!(self.logger,
1309+
"Failed to request inbound JIT channel as LSP's requested proportional opening fee of {} ppm msat exceeds our fee limit of {} ppm msat",
1310+
min_prop_fee_ppm_msat,
1311+
max_proportional_lsp_fee_limit_ppm_msat
1312+
);
1313+
return Err(Error::LiquidityFeeTooHigh);
1314+
}
1315+
}
1316+
1317+
let buy_response = self.lsps2_send_buy_request(None, min_opening_params).await?;
1318+
let metadata = self.lsps2_bolt12_metadata_from_buy_response(
1319+
buy_response,
1320+
LSPS2Parameters {
1321+
max_total_opening_fee_msat: None,
1322+
max_proportional_opening_fee_ppm_msat: Some(min_prop_fee_ppm_msat),
1323+
},
1324+
)?;
1325+
1326+
Ok((min_prop_fee_ppm_msat, metadata))
1327+
}
1328+
1329+
fn lsps2_bolt12_metadata_from_buy_response(
1330+
&self, buy_response: LSPS2BuyResponse, lsps2_parameters: LSPS2Parameters,
1331+
) -> Result<PaymentMetadata, Error> {
1332+
let lsps2_client = self.lsps2_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
1333+
1334+
Ok(PaymentMetadata {
1335+
lsps2_parameters: Some(lsps2_parameters),
1336+
lsps2_bolt12_invoice_parameters: Some(LSPS2Bolt12InvoiceParameters {
1337+
counterparty_node_id: lsps2_client.lsp_node_id,
1338+
intercept_scid: buy_response.intercept_scid,
1339+
cltv_expiry_delta: buy_response.cltv_expiry_delta,
1340+
}),
1341+
})
1342+
}
1343+
12351344
async fn lsps2_request_opening_fee_params(&self) -> Result<LSPS2FeeResponse, Error> {
12361345
let lsps2_client = self.lsps2_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
12371346

@@ -1317,8 +1426,11 @@ where
13171426

13181427
// LSPS2 requires min_final_cltv_expiry_delta to be at least 2 more than usual.
13191428
let min_final_cltv_expiry_delta = MIN_FINAL_CLTV_EXPIRY_DELTA + 2;
1320-
let encoded_payment_metadata =
1321-
PaymentMetadata { lsps2_parameters: Some(lsps2_parameters) }.encode();
1429+
let encoded_payment_metadata = PaymentMetadata {
1430+
lsps2_parameters: Some(lsps2_parameters),
1431+
lsps2_bolt12_invoice_parameters: None,
1432+
}
1433+
.encode();
13221434
let (payment_hash, payment_secret, payment_metadata) = match payment_hash {
13231435
Some(payment_hash) => {
13241436
let (payment_secret, payment_metadata) = self
@@ -1354,7 +1466,7 @@ where
13541466
src_node_id: lsps2_client.lsp_node_id,
13551467
short_channel_id: buy_response.intercept_scid,
13561468
fees: RoutingFees { base_msat: 0, proportional_millionths: 0 },
1357-
cltv_expiry_delta: buy_response.cltv_expiry_delta as u16,
1469+
cltv_expiry_delta: buy_response.cltv_expiry_delta,
13581470
htlc_minimum_msat: None,
13591471
htlc_maximum_msat: None,
13601472
}]);

0 commit comments

Comments
 (0)