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
52 changes: 50 additions & 2 deletions ldk-server-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ use ldk_server_client::ldk_server_protos::api::{
OpenChannelRequest,
};
use ldk_server_client::ldk_server_protos::types::{
bolt11_invoice_description, Bolt11InvoiceDescription, PageToken, Payment,
bolt11_invoice_description, channel_config, Bolt11InvoiceDescription, ChannelConfig, PageToken,
Payment,
};
use std::fmt::Debug;

Expand Down Expand Up @@ -101,6 +102,22 @@ enum Commands {
push_to_counterparty_msat: Option<u64>,
#[arg(long)]
announce_channel: bool,
// Channel config options
#[arg(
long,
help = "Amount (in millionths of a satoshi) charged per satoshi for payments forwarded outbound over the channel. This can be updated by using update-channel-config."
)]
forwarding_fee_proportional_millionths: Option<u32>,
#[arg(
long,
help = "Amount (in milli-satoshi) charged for payments forwarded outbound over the channel, in excess of forwarding_fee_proportional_millionths. This can be updated by using update-channel-config."
)]
forwarding_fee_base_msat: Option<u32>,
#[arg(
long,
help = "The difference in the CLTV value between incoming HTLCs and an outbound HTLC forwarded over the channel."
)]
cltv_expiry_delta: Option<u32>,
},
ListChannels,
ListPayments {
Expand Down Expand Up @@ -213,15 +230,24 @@ async fn main() {
channel_amount_sats,
push_to_counterparty_msat,
announce_channel,
forwarding_fee_proportional_millionths,
forwarding_fee_base_msat,
cltv_expiry_delta,
} => {
let channel_config = build_open_channel_config(
forwarding_fee_proportional_millionths,
forwarding_fee_base_msat,
cltv_expiry_delta,
);

handle_response_result(
client
.open_channel(OpenChannelRequest {
node_pubkey,
address,
channel_amount_sats,
push_to_counterparty_msat,
channel_config: None,
channel_config,
announce_channel,
})
.await,
Expand All @@ -236,6 +262,28 @@ async fn main() {
}
}

fn build_open_channel_config(
forwarding_fee_proportional_millionths: Option<u32>, forwarding_fee_base_msat: Option<u32>,
cltv_expiry_delta: Option<u32>,
) -> Option<ChannelConfig> {
// Only create a config if at least one field is set
if forwarding_fee_proportional_millionths.is_none()
&& forwarding_fee_base_msat.is_none()
&& cltv_expiry_delta.is_none()
{
return None;
}

Some(ChannelConfig {
forwarding_fee_proportional_millionths,
forwarding_fee_base_msat,
cltv_expiry_delta,
force_close_avoidance_max_fee_satoshis: None,
accept_underpaying_htlcs: None,
max_dust_htlc_exposure: None,
})
}

async fn list_n_payments(
client: LdkServerClient, number_of_payments: Option<u64>,
) -> Result<Vec<Payment>, LdkServerError> {
Expand Down
49 changes: 49 additions & 0 deletions ldk-server/src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
use crate::api::error::LdkServerError;
use crate::api::error::LdkServerErrorCode::InvalidRequestError;
use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure};
use ldk_server_protos::types::channel_config::MaxDustHtlcExposure;

pub(crate) mod bolt11_receive;
pub(crate) mod bolt11_send;
pub(crate) mod bolt12_receive;
Expand All @@ -14,3 +19,47 @@ pub(crate) mod onchain_receive;
pub(crate) mod onchain_send;
pub(crate) mod open_channel;
pub(crate) mod update_channel_config;

pub(crate) fn build_channel_config_from_proto(
default_config: ChannelConfig, proto_channel_config: ldk_server_protos::types::ChannelConfig,
) -> Result<ChannelConfig, LdkServerError> {
let max_dust_htlc_exposure = proto_channel_config
.max_dust_htlc_exposure
.map(|max_dust_htlc_exposure| match max_dust_htlc_exposure {
MaxDustHtlcExposure::FixedLimitMsat(limit_msat) => {
MaxDustHTLCExposure::FixedLimit { limit_msat }
},
MaxDustHtlcExposure::FeeRateMultiplier(multiplier) => {
MaxDustHTLCExposure::FeeRateMultiplier { multiplier }
},
})
.unwrap_or(default_config.max_dust_htlc_exposure);

let cltv_expiry_delta = match proto_channel_config.cltv_expiry_delta {
Some(c) => Some(u16::try_from(c).map_err(|_| {
LdkServerError::new(
InvalidRequestError,
format!("Invalid cltv_expiry_delta, must be between 0 and {}", u16::MAX),
)
})?),
None => None,
}
.unwrap_or(default_config.cltv_expiry_delta);

Ok(ChannelConfig {
forwarding_fee_proportional_millionths: proto_channel_config
.forwarding_fee_proportional_millionths
.unwrap_or(default_config.forwarding_fee_proportional_millionths),
forwarding_fee_base_msat: proto_channel_config
.forwarding_fee_base_msat
.unwrap_or(default_config.forwarding_fee_base_msat),
cltv_expiry_delta,
max_dust_htlc_exposure,
force_close_avoidance_max_fee_satoshis: proto_channel_config
.force_close_avoidance_max_fee_satoshis
.unwrap_or(default_config.force_close_avoidance_max_fee_satoshis),
accept_underpaying_htlcs: proto_channel_config
.accept_underpaying_htlcs
.unwrap_or(default_config.accept_underpaying_htlcs),
})
}
12 changes: 9 additions & 3 deletions ldk-server/src/api/open_channel.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::api::build_channel_config_from_proto;
use crate::api::error::LdkServerError;
use crate::service::Context;
use ldk_node::bitcoin::secp256k1::PublicKey;
use ldk_node::config::ChannelConfig;
use ldk_node::lightning::ln::msgs::SocketAddress;
use ldk_server_protos::api::{OpenChannelRequest, OpenChannelResponse};
use std::str::FromStr;
Expand All @@ -15,22 +17,26 @@ pub(crate) fn handle_open_channel(
let address = SocketAddress::from_str(&request.address)
.map_err(|_| ldk_node::NodeError::InvalidSocketAddress)?;

let channel_config = request
.channel_config
.map(|proto_config| build_channel_config_from_proto(ChannelConfig::default(), proto_config))
.transpose()?;

let user_channel_id = if request.announce_channel {
context.node.open_announced_channel(
node_id,
address,
request.channel_amount_sats,
request.push_to_counterparty_msat,
// TODO: Allow setting ChannelConfig in open-channel.
None,
channel_config,
)?
} else {
context.node.open_channel(
node_id,
address,
request.channel_amount_sats,
request.push_to_counterparty_msat,
None,
channel_config,
)?
};

Expand Down
49 changes: 2 additions & 47 deletions ldk-server/src/api/update_channel_config.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use crate::api::build_channel_config_from_proto;
use crate::api::error::LdkServerError;
use crate::api::error::LdkServerErrorCode::{InvalidRequestError, LightningError};
use crate::service::Context;
use ldk_node::bitcoin::secp256k1::PublicKey;
use ldk_node::config::{ChannelConfig, MaxDustHTLCExposure};
use ldk_node::UserChannelId;
use ldk_server_protos::api::{UpdateChannelConfigRequest, UpdateChannelConfigResponse};
use ldk_server_protos::types::channel_config::MaxDustHtlcExposure;
use std::str::FromStr;

pub(crate) const UPDATE_CHANNEL_CONFIG_PATH: &str = "UpdateChannelConfig";
Expand All @@ -29,7 +28,7 @@ pub(crate) fn handle_update_channel_config_request(
})?
.config;

let updated_channel_config = build_updated_channel_config(
let updated_channel_config = build_channel_config_from_proto(
current_config,
request.channel_config.ok_or_else(|| {
LdkServerError::new(InvalidRequestError, "Channel config must be provided.")
Expand All @@ -56,47 +55,3 @@ pub(crate) fn handle_update_channel_config_request(

Ok(UpdateChannelConfigResponse {})
}

fn build_updated_channel_config(
current_config: ChannelConfig, proto_channel_config: ldk_server_protos::types::ChannelConfig,
) -> Result<ChannelConfig, LdkServerError> {
let max_dust_htlc_exposure = proto_channel_config
.max_dust_htlc_exposure
.map(|max_dust_htlc_exposure| match max_dust_htlc_exposure {
MaxDustHtlcExposure::FixedLimitMsat(limit_msat) => {
MaxDustHTLCExposure::FixedLimit { limit_msat }
},
MaxDustHtlcExposure::FeeRateMultiplier(multiplier) => {
MaxDustHTLCExposure::FeeRateMultiplier { multiplier }
},
})
.unwrap_or(current_config.max_dust_htlc_exposure);

let cltv_expiry_delta = match proto_channel_config.cltv_expiry_delta {
Some(c) => Some(u16::try_from(c).map_err(|_| {
LdkServerError::new(
InvalidRequestError,
format!("Invalid cltv_expiry_delta, must be between 0 and {}", u16::MAX),
)
})?),
None => None,
}
.unwrap_or_else(|| current_config.cltv_expiry_delta);

Ok(ChannelConfig {
forwarding_fee_proportional_millionths: proto_channel_config
.forwarding_fee_proportional_millionths
.unwrap_or(current_config.forwarding_fee_proportional_millionths),
forwarding_fee_base_msat: proto_channel_config
.forwarding_fee_base_msat
.unwrap_or(current_config.forwarding_fee_base_msat),
cltv_expiry_delta,
max_dust_htlc_exposure,
force_close_avoidance_max_fee_satoshis: proto_channel_config
.force_close_avoidance_max_fee_satoshis
.unwrap_or(current_config.force_close_avoidance_max_fee_satoshis),
accept_underpaying_htlcs: proto_channel_config
.accept_underpaying_htlcs
.unwrap_or(current_config.accept_underpaying_htlcs),
})
}