Skip to content

Commit 5bd1c61

Browse files
authored
Merge pull request #187 from tankyleo/2026-04-zero-reserve
2 parents d149a1a + 2c0e186 commit 5bd1c61

5 files changed

Lines changed: 41 additions & 7 deletions

File tree

e2e-tests/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ pub async fn setup_funded_channel(
428428
push_to_counterparty_msat: None,
429429
channel_config: None,
430430
announce_channel: true,
431+
disable_counterparty_reserve: false,
431432
})
432433
.await
433434
.unwrap();

ldk-server-cli/src/main.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,11 @@ enum Commands {
389389
push_to_counterparty: Option<Amount>,
390390
#[arg(long, help = "Whether the channel should be public")]
391391
announce_channel: bool,
392+
#[arg(
393+
long,
394+
help = "Allow the counterparty to spend all its channel balance. This cannot be set together with `announce_channel`."
395+
)]
396+
disable_counterparty_reserve: bool,
392397
// Channel config options
393398
#[arg(
394399
long,
@@ -676,7 +681,7 @@ async fn main() {
676681
}),
677682
(Some(_), Some(_)) => {
678683
handle_error(LdkServerError::new(
679-
InternalError,
684+
InvalidRequestError,
680685
"Only one of description or description_hash can be set.".to_string(),
681686
));
682687
},
@@ -914,6 +919,7 @@ async fn main() {
914919
channel_amount,
915920
push_to_counterparty,
916921
announce_channel,
922+
disable_counterparty_reserve,
917923
forwarding_fee_proportional_millionths,
918924
forwarding_fee_base_msat,
919925
cltv_expiry_delta,
@@ -926,6 +932,12 @@ async fn main() {
926932
forwarding_fee_base_msat,
927933
cltv_expiry_delta,
928934
);
935+
if announce_channel && disable_counterparty_reserve {
936+
handle_error(LdkServerError::new(
937+
InvalidRequestError,
938+
"Cannot set both `announce_channel` and `disable_counterparty_reserve`",
939+
));
940+
}
929941

930942
handle_response_result::<_, OpenChannelResponse>(
931943
client
@@ -936,6 +948,7 @@ async fn main() {
936948
push_to_counterparty_msat,
937949
channel_config,
938950
announce_channel,
951+
disable_counterparty_reserve,
939952
})
940953
.await,
941954
);
@@ -1237,7 +1250,7 @@ fn parse_bolt11_invoice_description(
12371250
}),
12381251
(Some(_), Some(_)) => {
12391252
handle_error(LdkServerError::new(
1240-
InternalError,
1253+
InvalidRequestError,
12411254
"Only one of description or description_hash can be set.".to_string(),
12421255
));
12431256
},
@@ -1249,13 +1262,13 @@ fn parse_page_token(token_str: &str) -> Result<PageToken, LdkServerError> {
12491262
let parts: Vec<&str> = token_str.split(':').collect();
12501263
if parts.len() != 2 {
12511264
return Err(LdkServerError::new(
1252-
InternalError,
1265+
InvalidRequestError,
12531266
"Page token must be in format 'token:index'".to_string(),
12541267
));
12551268
}
1256-
let index = parts[1]
1257-
.parse::<i64>()
1258-
.map_err(|_| LdkServerError::new(InternalError, "Invalid page token index".to_string()))?;
1269+
let index = parts[1].parse::<i64>().map_err(|_| {
1270+
LdkServerError::new(InvalidRequestError, "Invalid page token index".to_string())
1271+
})?;
12591272
Ok(PageToken { token: parts[0].to_string(), index })
12601273
}
12611274

ldk-server-grpc/src/api.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,9 @@ pub struct OpenChannelRequest {
478478
/// Whether the channel should be public.
479479
#[prost(bool, tag = "6")]
480480
pub announce_channel: bool,
481+
/// Allow the counterparty to spend all its channel balance. This cannot be set together with `announce_channel`.
482+
#[prost(bool, tag = "7")]
483+
pub disable_counterparty_reserve: bool,
481484
}
482485
/// The response for the `OpenChannel` RPC. On failure, a gRPC error status is returned.
483486
#[cfg_attr(feature = "serde", derive(serde::Serialize))]

ldk-server-grpc/src/proto/api.proto

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,9 @@ message OpenChannelRequest {
395395

396396
// Whether the channel should be public.
397397
bool announce_channel = 6;
398+
399+
// Allow the counterparty to spend all its channel balance. This cannot be set together with `announce_channel`.
400+
bool disable_counterparty_reserve = 7;
398401
}
399402

400403
// The response for the `OpenChannel` RPC. On failure, a gRPC error status is returned.

ldk-server/src/api/open_channel.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use ldk_node::lightning::ln::msgs::SocketAddress;
1616
use ldk_server_grpc::api::{OpenChannelRequest, OpenChannelResponse};
1717

1818
use crate::api::build_channel_config_from_proto;
19-
use crate::api::error::LdkServerError;
19+
use crate::api::error::{LdkServerError, LdkServerErrorCode};
2020
use crate::service::Context;
2121

2222
pub(crate) async fn handle_open_channel(
@@ -26,6 +26,12 @@ pub(crate) async fn handle_open_channel(
2626
.map_err(|_| ldk_node::NodeError::InvalidPublicKey)?;
2727
let address = SocketAddress::from_str(&request.address)
2828
.map_err(|_| ldk_node::NodeError::InvalidSocketAddress)?;
29+
if request.announce_channel && request.disable_counterparty_reserve {
30+
return Err(LdkServerError::new(
31+
LdkServerErrorCode::InvalidRequestError,
32+
"Cannot set both `announce_channel` and `disable_counterparty_reserve`",
33+
));
34+
}
2935

3036
let channel_config = request
3137
.channel_config
@@ -40,6 +46,14 @@ pub(crate) async fn handle_open_channel(
4046
request.push_to_counterparty_msat,
4147
channel_config,
4248
)?
49+
} else if request.disable_counterparty_reserve {
50+
context.node.open_0reserve_channel(
51+
node_id,
52+
address,
53+
request.channel_amount_sats,
54+
request.push_to_counterparty_msat,
55+
channel_config,
56+
)?
4357
} else {
4458
context.node.open_channel(
4559
node_id,

0 commit comments

Comments
 (0)