diff --git a/ldk-server/src/api/mod.rs b/ldk-server/src/api/mod.rs index 04a92c87..f2abc4b9 100644 --- a/ldk-server/src/api/mod.rs +++ b/ldk-server/src/api/mod.rs @@ -170,6 +170,17 @@ pub(crate) fn build_route_parameters_config_from_proto( } } +pub(crate) fn with_default_max_routing_fee( + route_parameters: Option, amount_msat: u64, +) -> Option { + route_parameters.map(|params| RouteParametersConfig { + max_total_routing_fee_msat: params + .max_total_routing_fee_msat + .or_else(|| Some((amount_msat / 100).saturating_add(50_000))), + ..params + }) +} + pub(crate) fn proto_to_node_custom_tlv(proto: &ProtoCustomTlvRecord) -> NodeCustomTlvRecord { NodeCustomTlvRecord { type_num: proto.type_num, value: proto.value.to_vec() } } @@ -198,6 +209,47 @@ mod tests { } } + #[test] + fn missing_routing_fee_limit_defaults_to_one_percent_plus_fifty_sats() { + let params = RouteParametersConfig { + max_total_routing_fee_msat: None, + max_total_cltv_expiry_delta: 144, + max_path_count: 3, + max_channel_saturation_power_of_half: 1, + }; + + let resolved = with_default_max_routing_fee(Some(params), 1_000_000).unwrap(); + assert_eq!(resolved.max_total_routing_fee_msat, Some(10_000 + 50_000)); + assert_eq!(resolved.max_total_cltv_expiry_delta, 144); + assert_eq!(resolved.max_path_count, 3); + assert_eq!(resolved.max_channel_saturation_power_of_half, 1); + + let resolved = with_default_max_routing_fee(Some(params), 0).unwrap(); + assert_eq!(resolved.max_total_routing_fee_msat, Some(50_000)); + + let resolved = with_default_max_routing_fee(Some(params), u64::MAX).unwrap(); + assert_eq!(resolved.max_total_routing_fee_msat, Some(u64::MAX / 100 + 50_000)); + } + + #[test] + fn explicit_routing_fee_limit_is_kept() { + for limit in [0, 1_000, u64::MAX] { + let params = RouteParametersConfig { + max_total_routing_fee_msat: Some(limit), + max_total_cltv_expiry_delta: 1008, + max_path_count: 10, + max_channel_saturation_power_of_half: 2, + }; + let resolved = with_default_max_routing_fee(Some(params), 1_000_000).unwrap(); + assert_eq!(resolved.max_total_routing_fee_msat, Some(limit)); + } + } + + #[test] + fn absent_route_parameters_stay_absent() { + assert!(with_default_max_routing_fee(None, 1_000_000).is_none()); + } + #[test] fn payment_id_is_parsed() { let payment_id = "01".repeat(PaymentId::LENGTH); diff --git a/ldk-server/src/api/spontaneous_send.rs b/ldk-server/src/api/spontaneous_send.rs index 80875a3f..544bec36 100644 --- a/ldk-server/src/api/spontaneous_send.rs +++ b/ldk-server/src/api/spontaneous_send.rs @@ -18,7 +18,10 @@ use ldk_server_grpc::api::{SpontaneousSendRequest, SpontaneousSendResponse}; use crate::api::error::LdkServerError; use crate::api::error::LdkServerErrorCode::InvalidRequestError; -use crate::api::{build_route_parameters_config_from_proto, proto_to_node_custom_tlv}; +use crate::api::{ + build_route_parameters_config_from_proto, proto_to_node_custom_tlv, + with_default_max_routing_fee, +}; use crate::service::Context; pub(crate) async fn handle_spontaneous_send_request( @@ -28,7 +31,10 @@ pub(crate) async fn handle_spontaneous_send_request( LdkServerError::new(InvalidRequestError, "Invalid node_id provided.".to_string()) })?; - let route_parameters = build_route_parameters_config_from_proto(request.route_parameters)?; + let route_parameters = with_default_max_routing_fee( + build_route_parameters_config_from_proto(request.route_parameters)?, + request.amount_msat, + ); let preimage = request .preimage