Skip to content
Merged
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
39 changes: 38 additions & 1 deletion e2e-tests/tests/e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ use ldk_node::lightning::offers::offer::Offer;
use ldk_node::lightning_invoice::Bolt11Invoice;
use ldk_server_client::client::EventStream;
use ldk_server_client::ldk_server_grpc::api::{
Bolt11ReceiveRequest, Bolt12ReceiveRequest, OnchainReceiveRequest, OpenChannelRequest,
Bolt11ReceiveRequest, Bolt12ReceiveRequest, GetBalancesRequest, OnchainReceiveRequest,
OpenChannelRequest,
};
use ldk_server_client::ldk_server_grpc::events::event_envelope::Event;
use ldk_server_client::ldk_server_grpc::events::{
Expand Down Expand Up @@ -360,6 +361,42 @@ async fn test_cli_onchain_send() {
assert!(!output["txid"].as_str().unwrap().is_empty());
}

#[tokio::test]
async fn test_cli_onchain_send_all() {
let bitcoind = TestBitcoind::new();
let server = LdkServerHandle::start(&bitcoind).await;

let funding_address =
server.client().onchain_receive(OnchainReceiveRequest {}).await.unwrap().address;
bitcoind.fund_address(&funding_address, 1.0);
mine_and_sync(&bitcoind, &[&server], 6).await;
wait_for_onchain_balance(server.client(), Duration::from_secs(30)).await;

let balances_before = server.client().get_balances(GetBalancesRequest {}).await.unwrap();

let address = bitcoind.bitcoind.client.new_address().unwrap().to_string();
let output = run_cli(&server, &["onchain-send", &address, "--send-all", "true"]);
assert!(!output["txid"].as_str().unwrap().is_empty());

mine_and_sync(&bitcoind, &[&server], 6).await;

let timeout = Duration::from_secs(30);
let start = std::time::Instant::now();
let balances = loop {
let balances = server.client().get_balances(GetBalancesRequest {}).await.unwrap();
if balances.total_onchain_balance_sats != balances_before.total_onchain_balance_sats {
break balances;
}
if start.elapsed() > timeout {
panic!("Timed out waiting for on-chain balance to change");
}
tokio::time::sleep(Duration::from_millis(500)).await;
};

assert_eq!(balances.spendable_onchain_balance_sats, 0);
assert_eq!(balances.total_onchain_balance_sats, 0);
}

#[tokio::test]
async fn test_cli_connect_peer() {
let bitcoind = TestBitcoind::new();
Expand Down
2 changes: 1 addition & 1 deletion ldk-server-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ enum Commands {
amount: Option<Amount>,
#[arg(
long,
help = "Send full balance to the address. Warning: will not retain on-chain reserves for anchor channels"
help = "Send all available balance to the address while retaining on-chain reserves for anchor channels"
)]
send_all: Option<bool>,
#[arg(
Expand Down
6 changes: 2 additions & 4 deletions ldk-server-grpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,9 @@ pub struct OnchainSendRequest {
#[prost(uint64, optional, tag = "2")]
pub amount_sats: ::core::option::Option<u64>,
/// If set, the amount_sats field should be unset.
/// It indicates that node will send full balance to the specified address.
/// It indicates that the node will send all available balance to the specified address.
///
/// Please note that when send_all is used this operation will **not** retain any on-chain reserves,
/// which might be potentially dangerous if you have open Anchor channels for which you can't trust
/// the counterparty to spend the Anchor output after channel closure.
/// Any on-chain reserves needed for Anchor channels will be retained.
/// See more: <https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.send_all_to_address>
#[prost(bool, optional, tag = "3")]
pub send_all: ::core::option::Option<bool>,
Expand Down
6 changes: 2 additions & 4 deletions ldk-server-grpc/src/proto/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,9 @@ message OnchainSendRequest {
optional uint64 amount_sats = 2;

// If set, the amount_sats field should be unset.
// It indicates that node will send full balance to the specified address.
// It indicates that the node will send all available balance to the specified address.
//
// Please note that when send_all is used this operation will **not** retain any on-chain reserves,
// which might be potentially dangerous if you have open Anchor channels for which you can't trust
// the counterparty to spend the Anchor output after channel closure.
// Any on-chain reserves needed for Anchor channels will be retained.
// See more: https://docs.rs/ldk-node/latest/ldk_node/payment/struct.OnchainPayment.html#method.send_all_to_address
optional bool send_all = 3;

Expand Down
2 changes: 1 addition & 1 deletion ldk-server-mcp/src/tools/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ pub fn onchain_send_schema() -> Value {
},
"send_all": {
"type": "boolean",
"description": "If true, send full balance (ignores amount_sats). Warning: will not retain on-chain reserves for anchor channels"
"description": "If true, send all available balance while retaining on-chain reserves for anchor channels (amount_sats must be unset)"
},
"fee_rate_sat_per_vb": {
"type": "integer",
Expand Down
3 changes: 1 addition & 2 deletions ldk-server/src/api/onchain_send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ pub(crate) async fn handle_onchain_send_request(
(Some(amount_sats), None) => {
context.node.onchain_payment().send_to_address(&address, amount_sats, fee_rate)?
},
// Retain existing api behaviour to not retain reserves on `send_all_to_address`.
(None, Some(true)) => {
context.node.onchain_payment().send_all_to_address(&address, false, fee_rate)?
context.node.onchain_payment().send_all_to_address(&address, true, fee_rate)?
},
_ => {
return Err(LdkServerError::new(
Expand Down