Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/liquidity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use lightning_liquidity::lsps1::client::LSPS1ClientConfig as LdkLSPS1ClientConfi
use lightning_liquidity::lsps2::client::LSPS2ClientConfig as LdkLSPS2ClientConfig;
use lightning_liquidity::lsps2::service::LSPS2ServiceConfig as LdkLSPS2ServiceConfig;
use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig};
pub use service::lsps2::LSPS2ServiceConfig;
pub use service::lsps2::{LSPS2ChannelConfig, LSPS2ServiceConfig};
use tokio::sync::oneshot;

use crate::builder::BuildError;
Expand Down
48 changes: 45 additions & 3 deletions src/liquidity/service/lsps2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use lightning_liquidity::lsps2::msgs::LSPS2RawOpeningFeeParams;
use lightning_liquidity::lsps2::service::LSPS2ServiceConfig as LdkLSPS2ServiceConfig;
use lightning_types::payment::PaymentHash;

use crate::config::MaxDustHTLCExposure;
use crate::logger::{log_error, LdkLogger};
use crate::types::{ChannelManager, KeysManager, LiquidityManager, PeerManager, Wallet};
use crate::{total_anchor_channels_reserve_sats, Config};
Expand Down Expand Up @@ -106,6 +107,31 @@ pub struct LSPS2ServiceConfig {
///
/// [`Node::open_0reserve_channel`]: crate::Node::open_0reserve_channel
pub disable_client_reserve: bool,
/// The channel config we'll apply to the JIT channels we open to clients, allowing to
/// configure them separately from regular channels.
///
/// Any unset fields, or if set to `None` entirely, fall back to the node-wide config.
pub channel_config: Option<LSPS2ChannelConfig>,
}

/// A subset of channel configuration options applied to the JIT channels opened towards
/// clients when acting as an LSPS2 service.
///
/// Any fields set to `None` fall back to the node-wide config.
///
/// Note that the forwarding fees of JIT channels are always set to zero, as we're
/// compensated via the channel opening fee.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
pub struct LSPS2ChannelConfig {
/// The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded
/// over the channel.
pub cltv_expiry_delta: Option<u16>,
/// The total exposure we're willing to allow to potential loss due to dust HTLCs.
pub max_dust_htlc_exposure: Option<MaxDustHTLCExposure>,
/// The additional fee we're willing to pay to avoid waiting for the counterparty's
/// `to_self_delay` to reclaim funds.
pub force_close_avoidance_max_fee_satoshis: Option<u64>,
}

impl<L: Deref> LSPS2ServiceLiquiditySource<L>
Expand Down Expand Up @@ -487,12 +513,28 @@ where
debug_assert!(!config.channel_handshake_config.announce_for_forwarding);
debug_assert!(config.accept_forwards_to_priv_channels);

// We set the forwarding fee to 0 for now as we're getting paid by the channel fee.
//
// TODO: revisit this decision eventually.
// We set the forwarding fees to 0 as we're getting paid by the channel opening
// fee.
config.channel_config.forwarding_fee_base_msat = 0;
config.channel_config.forwarding_fee_proportional_millionths = 0;

if let Some(jit_channel_config) = service_config.channel_config.as_ref() {
if let Some(cltv_expiry_delta) = jit_channel_config.cltv_expiry_delta {
config.channel_config.cltv_expiry_delta = cltv_expiry_delta;
}
if let Some(max_dust_htlc_exposure) = jit_channel_config.max_dust_htlc_exposure
{
config.channel_config.max_dust_htlc_exposure =
max_dust_htlc_exposure.into();
}
if let Some(force_close_avoidance_max_fee_satoshis) =
jit_channel_config.force_close_avoidance_max_fee_satoshis
{
config.channel_config.force_close_avoidance_max_fee_satoshis =
force_close_avoidance_max_fee_satoshis;
}
}

let result = if service_config.disable_client_reserve {
self.channel_manager.create_channel_to_trusted_peer_0reserve(
their_network_key,
Expand Down
21 changes: 20 additions & 1 deletion tests/integration_tests_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use electrsd::corepc_node::{self, Node as BitcoinD};
use electrsd::ElectrsD;
use ldk_node::config::{AsyncPaymentsRole, EsploraSyncConfig, DEFAULT_FULL_SCAN_STOP_GAP};
use ldk_node::entropy::NodeEntropy;
use ldk_node::liquidity::LSPS2ServiceConfig;
use ldk_node::liquidity::{LSPS2ChannelConfig, LSPS2ServiceConfig};
use ldk_node::payment::{
ConfirmationStatus, PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus,
TransactionType, UnifiedPaymentResult,
Expand Down Expand Up @@ -2787,6 +2787,12 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
// Setup three nodes: service, client, and payer
let channel_opening_fee_ppm = 10_000;
let channel_over_provisioning_ppm = 100_000;

let jit_channel_config = LSPS2ChannelConfig {
cltv_expiry_delta: None,
max_dust_htlc_exposure: None,
force_close_avoidance_max_fee_satoshis: Some(1337),
};
let lsps2_service_config = LSPS2ServiceConfig {
require_token: None,
advertise_service: false,
Expand All @@ -2799,6 +2805,7 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
max_client_to_self_delay: 1024,
client_trusts_lsp,
disable_client_reserve: false,
channel_config: Some(jit_channel_config),
};

let service_config = random_config(true);
Expand Down Expand Up @@ -2890,6 +2897,14 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
let channel_value_sats = client_node.list_channels().first().unwrap().channel_value_sats;
assert_eq!(channel_value_sats, expected_channel_size_sat);

let jit_channel = service_node
.list_channels()
.into_iter()
.find(|c| c.counterparty.node_id == client_node.node_id())
.unwrap();
assert_eq!(jit_channel.config.force_close_avoidance_max_fee_satoshis, 1337);
assert_eq!(jit_channel.config.forwarding_fee_base_msat, 0);

println!("Generating regular invoice!");
let invoice_description =
Bolt11InvoiceDescription::Direct(Description::new(String::from("asdf")).unwrap()).into();
Expand Down Expand Up @@ -3118,6 +3133,7 @@ async fn lsps2_client_trusts_lsp() {
max_client_to_self_delay: 1024,
client_trusts_lsp: true,
disable_client_reserve: false,
channel_config: None,
};

let service_config = random_config(true);
Expand Down Expand Up @@ -3293,6 +3309,7 @@ async fn lsps2_lsp_trusts_client_but_client_does_not_claim() {
max_client_to_self_delay: 1024,
client_trusts_lsp: false,
disable_client_reserve: false,
channel_config: None,
};

let service_config = random_config(true);
Expand Down Expand Up @@ -4092,6 +4109,7 @@ async fn do_lsps2_multi_lsp_picks_cheapest(reverse_order: bool) {
max_client_to_self_delay: 1024,
client_trusts_lsp: true,
disable_client_reserve: false,
channel_config: None,
};
let cheap_node_config = random_config(true);
setup_builder!(cheap_builder, cheap_node_config.node_config);
Expand All @@ -4115,6 +4133,7 @@ async fn do_lsps2_multi_lsp_picks_cheapest(reverse_order: bool) {
max_client_to_self_delay: 1024,
client_trusts_lsp: true,
disable_client_reserve: false,
channel_config: None,
};
let expensive_node_config = random_config(true);
setup_builder!(expensive_builder, expensive_node_config.node_config);
Expand Down
Loading