Skip to content

Commit

Permalink
f Allow to withdraw all funds
Browse files Browse the repository at this point in the history
  • Loading branch information
tnull committed Apr 7, 2023
1 parent 167583e commit 4ca987c
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 19 deletions.
42 changes: 25 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,31 @@ impl Node {
self.wallet.get_balance()
}

/// Send an on-chain payment to the given address.
pub fn withdraw(&self, address: &bitcoin::Address, amount_sats: u64) -> Result<Txid, Error> {
let runtime_lock = self.running.read().unwrap();
if runtime_lock.is_none() {
return Err(Error::NotRunning);
}

let cur_balance = self.wallet.get_balance()?;
if cur_balance.get_spendable() < amount_sats {
log_error!(self.logger, "Unable to send payment due to insufficient funds.");
return Err(Error::InsufficientFunds);
}
self.wallet.send_to_address(address, amount_sats)
}

/// Send an on-chain payment to the given address, draining all the available funds.
pub fn withdraw_all(&self, address: &bitcoin::Address) -> Result<Txid, Error> {
let runtime_lock = self.running.read().unwrap();
if runtime_lock.is_none() {
return Err(Error::NotRunning);
}

self.wallet.drain_to_address(address)
}

/// Retrieve a list of known channels.
pub fn list_channels(&self) -> Vec<ChannelDetails> {
self.channel_manager.list_channels()
Expand Down Expand Up @@ -1213,23 +1238,6 @@ impl Node {
}
}

/// Send an on-chain payment to the given address.
pub fn send_onchain_payment(
&self, address: &bitcoin::Address, amount_sats: u64,
) -> Result<Txid, Error> {
let runtime_lock = self.running.read().unwrap();
if runtime_lock.is_none() {
return Err(Error::NotRunning);
}

let cur_balance = self.wallet.get_balance()?;
if cur_balance.get_spendable() < amount_sats {
log_error!(self.logger, "Unable to send payment due to insufficient funds.");
return Err(Error::InsufficientFunds);
}
self.wallet.send_to_address(address, amount_sats)
}

/// Returns a payable invoice that can be used to request and receive a payment of the amount
/// given.
pub fn receive_payment(
Expand Down
16 changes: 14 additions & 2 deletions src/test/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,9 @@ fn onchain_spend_receive() {
node_b.sync_wallets().unwrap();
assert_eq!(node_b.onchain_balance().unwrap().get_spendable(), 100000);

assert_eq!(Err(Error::InsufficientFunds), node_a.send_onchain_payment(&addr_b, 1000));
assert_eq!(Err(Error::InsufficientFunds), node_a.withdraw(&addr_b, 1000));

let txid = node_b.send_onchain_payment(&addr_a, 1000).unwrap();
let txid = node_b.withdraw(&addr_a, 1000).unwrap();
generate_blocks_and_wait(&bitcoind, &electrsd, 6);
wait_for_tx(&electrsd, txid);

Expand All @@ -318,4 +318,16 @@ fn onchain_spend_receive() {
assert_eq!(node_a.onchain_balance().unwrap().get_spendable(), 1000);
assert!(node_b.onchain_balance().unwrap().get_spendable() > 98000);
assert!(node_b.onchain_balance().unwrap().get_spendable() < 100000);

let addr_b = node_b.new_funding_address().unwrap();
let txid = node_a.withdraw_all(&addr_b).unwrap();
generate_blocks_and_wait(&bitcoind, &electrsd, 6);
wait_for_tx(&electrsd, txid);

node_a.sync_wallets().unwrap();
node_b.sync_wallets().unwrap();

assert_eq!(node_a.onchain_balance().unwrap().get_total(), 0);
assert!(node_b.onchain_balance().unwrap().get_spendable() > 99000);
assert!(node_b.onchain_balance().unwrap().get_spendable() < 100000);
}
52 changes: 52 additions & 0 deletions src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,58 @@ where
Ok(txid)
}

pub(crate) fn drain_to_address(&self, address: &bitcoin::Address) -> Result<Txid, Error> {
let confirmation_target = ConfirmationTarget::Normal;
let fee_rate = self.estimate_fee_rate(confirmation_target);

let tx = {
let locked_wallet = self.inner.lock().unwrap();
let mut tx_builder = locked_wallet.build_tx();

tx_builder
.drain_wallet()
.drain_to(address.script_pubkey())
.fee_rate(fee_rate)
.enable_rbf();

let mut psbt = match tx_builder.finish() {
Ok((psbt, _)) => {
log_trace!(self.logger, "Created PSBT: {:?}", psbt);
psbt
}
Err(err) => {
log_error!(self.logger, "Failed to create transaction: {}", err);
return Err(err.into());
}
};

match locked_wallet.sign(&mut psbt, SignOptions::default()) {
Ok(finalized) => {
if !finalized {
return Err(Error::OnchainTxCreationFailed);
}
}
Err(err) => {
log_error!(self.logger, "Failed to create transaction: {}", err);
return Err(err.into());
}
}
psbt.extract_tx()
};

self.broadcast_transaction(&tx);

let txid = tx.txid();
log_info!(
self.logger,
"Created new transaction {} sending all available on-chain funds to address {}",
txid,
address
);

Ok(txid)
}

fn estimate_fee_rate(&self, confirmation_target: ConfirmationTarget) -> FeeRate {
let locked_fee_rate_cache = self.fee_rate_cache.read().unwrap();

Expand Down

0 comments on commit 4ca987c

Please sign in to comment.