From d147f663f875e3871f16928734fd1c934b6c41cd Mon Sep 17 00:00:00 2001 From: Steve Myers Date: Wed, 26 Jul 2023 19:46:40 -0500 Subject: [PATCH] feat(bdk)!: remove TransactionDetails, change Wallet::get_tx, TxBuilder::finish return types BREAKING CHANGES: Removed - TransactionDetails struct Changed - Wallet::get_tx now returns CanonicalTx instead of TransactionDetails - TxBuilder::finish now returns only a PartiallySignedTransaction Added - TransactionAmount struct with tx sent and received amounts - Wallet::sent_and_received function returns TransactionAmount - Wallet::fee_amount and Wallet::fee_rate functions for tx fees - Wallet::get_txout function for all known wallet txouts Fixed - impacted tests --- crates/bdk/src/keys/mod.rs | 2 +- crates/bdk/src/types.rs | 39 +- crates/bdk/src/wallet/coin_selection.rs | 2 +- crates/bdk/src/wallet/mod.rs | 182 +++---- crates/bdk/src/wallet/tx_builder.rs | 15 +- crates/bdk/tests/common.rs | 70 ++- crates/bdk/tests/psbt.rs | 16 +- crates/bdk/tests/wallet.rs | 446 ++++++++++-------- example-crates/wallet_electrum/src/main.rs | 2 +- example-crates/wallet_esplora/src/main.rs | 2 +- .../wallet_esplora_async/src/main.rs | 2 +- 11 files changed, 441 insertions(+), 337 deletions(-) diff --git a/crates/bdk/src/keys/mod.rs b/crates/bdk/src/keys/mod.rs index b4cfb6dee3..80eaf4fb2d 100644 --- a/crates/bdk/src/keys/mod.rs +++ b/crates/bdk/src/keys/mod.rs @@ -754,7 +754,7 @@ fn expand_multi_keys, Ctx: ScriptContext>( let (key_map, valid_networks) = key_maps_networks.into_iter().fold( (KeyMap::default(), any_network()), |(mut keys_acc, net_acc), (key, net)| { - keys_acc.extend(key.into_iter()); + keys_acc.extend(key); let net_acc = merge_networks(&net_acc, &net); (keys_acc, net_acc) diff --git a/crates/bdk/src/types.rs b/crates/bdk/src/types.rs index e21bef9066..9488debbfc 100644 --- a/crates/bdk/src/types.rs +++ b/crates/bdk/src/types.rs @@ -14,8 +14,8 @@ use core::convert::AsRef; use core::ops::Sub; use bdk_chain::ConfirmationTime; -use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut}; -use bitcoin::{hash_types::Txid, util::psbt}; +use bitcoin::blockdata::transaction::{OutPoint, TxOut}; +use bitcoin::util::psbt; use serde::{Deserialize, Serialize}; @@ -234,38 +234,13 @@ impl Utxo { } } -/// A wallet transaction +/// A `Transaction` sent and received amounts. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] -pub struct TransactionDetails { - /// Optional transaction - pub transaction: Option, - /// Transaction id - pub txid: Txid, - /// Received value (sats) - /// Sum of owned outputs of this transaction. - pub received: u64, - /// Sent value (sats) - /// Sum of owned inputs of this transaction. +pub struct TransactionAmounts { + /// amount sent, in sats pub sent: u64, - /// Fee value in sats if it was available. - pub fee: Option, - /// If the transaction is confirmed, contains height and Unix timestamp of the block containing the - /// transaction, unconfirmed transaction contains `None`. - pub confirmation_time: ConfirmationTime, -} - -impl PartialOrd for TransactionDetails { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for TransactionDetails { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.confirmation_time - .cmp(&other.confirmation_time) - .then_with(|| self.txid.cmp(&other.txid)) - } + /// amount received, in sats + pub received: u64, } #[cfg(test)] diff --git a/crates/bdk/src/wallet/coin_selection.rs b/crates/bdk/src/wallet/coin_selection.rs index e7927cabb3..49a7502daf 100644 --- a/crates/bdk/src/wallet/coin_selection.rs +++ b/crates/bdk/src/wallet/coin_selection.rs @@ -81,7 +81,7 @@ //! // create wallet, sync, ... //! //! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); -//! let (psbt, details) = { +//! let psbt = { //! let mut builder = wallet.build_tx().coin_selection(AlwaysSpendEverything); //! builder.add_recipient(to_address.script_pubkey(), 50_000); //! builder.finish()? diff --git a/crates/bdk/src/wallet/mod.rs b/crates/bdk/src/wallet/mod.rs index f2f717d9fe..b6de281eb0 100644 --- a/crates/bdk/src/wallet/mod.rs +++ b/crates/bdk/src/wallet/mod.rs @@ -39,6 +39,7 @@ use core::fmt; use core::ops::Deref; use miniscript::psbt::{PsbtExt, PsbtInputExt, PsbtInputSatisfier}; +use bdk_chain::indexed_tx_graph::Indexer; #[allow(unused_imports)] use log::{debug, error, info, trace}; @@ -427,27 +428,97 @@ impl Wallet { .next() } - /// Return a single transactions made and received by the wallet - /// - /// Optionally fill the [`TransactionDetails::transaction`] field with the raw transaction if - /// `include_raw` is `true`. - pub fn get_tx(&self, txid: Txid, include_raw: bool) -> Option { + /// Returns a `TxOut` known by this wallet corresponding to `outpoint` if it exists in the + /// wallet's database whether spent or not. + pub fn get_txout(&self, outpoint: &OutPoint) -> Option { + self.indexed_graph + .graph() + .all_txouts() + .filter_map(|(op, txo)| { + if op.eq(outpoint) { + Some(txo.clone()) + } else { + None + } + }) + .next() + } + + /// The total transaction fee amount, sum of input amounts minus sum of output amounts, in sats. + /// If the `Wallet` is missing a TxOut for an input returns None. + pub fn fee_amount(&self, tx: &Transaction) -> Option { + let txouts: Option> = tx + .input + .iter() + .map(|txin| self.get_txout(&txin.previous_output)) + .collect(); + + txouts.map(|inputs| { + let input_amount: u64 = inputs.iter().map(|i| i.value).sum(); + let output_amount: u64 = tx.output.iter().map(|o| o.value).sum(); + input_amount + .checked_sub(output_amount) + .expect("input amount must be greater than output amount") + }) + } + + /// The transaction's `FeeRate`. If the `Wallet` is missing a `TxOut` for an input returns None. + pub fn fee_rate(&self, tx: &Transaction) -> Option { + let fee_amount = self.fee_amount(tx); + fee_amount.map(|fee| { + let weight = tx.weight(); + FeeRate::from_wu(fee, weight) + }) + } + + /// Return `TransactionAmounts` for a `Transaction` in relation to the `Wallet` and it's + /// descriptors. + pub fn sent_and_received(&self, tx: &Transaction) -> TransactionAmounts { + let index = &self.indexed_graph.index; + + let received = tx + .output + .iter() + .map(|txout| { + if index.index_of_spk(&txout.script_pubkey).is_some() { + txout.value + } else { + 0 + } + }) + .sum(); + + let sent = tx + .input + .iter() + .map(|txin| { + if let Some((_, txout)) = index.txout(txin.previous_output) { + txout.value + } else { + 0 + } + }) + .sum(); + + TransactionAmounts { sent, received } + } + + /// Return a single `CanonicalTx` made and received by the wallet or `None` if it doesn't + /// exist in the wallet + pub fn get_tx( + &self, + txid: Txid, + ) -> Option> { let graph = self.indexed_graph.graph(); - let canonical_tx = CanonicalTx { + Some(CanonicalTx { observed_as: graph.get_chain_position( &self.chain, self.chain.tip().unwrap_or_default(), txid, )?, node: graph.get_tx_node(txid)?, - }; - - Some(new_tx_details( - &self.indexed_graph, - canonical_tx, - include_raw, - )) + }) } /// Add a new checkpoint to the wallet's internal view of the chain. @@ -524,6 +595,10 @@ impl Wallet { let changeset: ChangeSet = self.indexed_graph.insert_tx(&tx, anchor, last_seen).into(); let changed = !changeset.is_empty(); self.persist.stage(changeset); + + let additions = self.indexed_graph.index.index_tx(&tx); + self.indexed_graph.index.apply_additions(additions); + Ok(changed) } @@ -599,7 +674,7 @@ impl Wallet { /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let mut wallet = doctest_wallet!(); /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); - /// let (psbt, details) = { + /// let psbt = { /// let mut builder = wallet.build_tx(); /// builder /// .add_recipient(to_address.script_pubkey(), 50_000); @@ -624,7 +699,7 @@ impl Wallet { &mut self, coin_selection: Cs, params: TxParams, - ) -> Result<(psbt::PartiallySignedTransaction, TransactionDetails), Error> + ) -> Result where D: PersistBackend, { @@ -969,20 +1044,8 @@ impl Wallet { // sort input/outputs according to the chosen algorithm params.ordering.sort_tx(&mut tx); - let txid = tx.txid(); - let sent = coin_selection.local_selected_amount(); let psbt = self.complete_transaction(tx, coin_selection.selected, params)?; - - let transaction_details = TransactionDetails { - transaction: None, - txid, - confirmation_time: ConfirmationTime::Unconfirmed { last_seen: 0 }, - received, - sent, - fee: Some(fee_amount), - }; - - Ok((psbt, transaction_details)) + Ok(psbt) } /// Bump the fee of a transaction previously created with this wallet. @@ -1001,7 +1064,7 @@ impl Wallet { /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let mut wallet = doctest_wallet!(); /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); - /// let (mut psbt, _) = { + /// let mut psbt = { /// let mut builder = wallet.build_tx(); /// builder /// .add_recipient(to_address.script_pubkey(), 50_000) @@ -1011,7 +1074,7 @@ impl Wallet { /// let _ = wallet.sign(&mut psbt, SignOptions::default())?; /// let tx = psbt.extract_tx(); /// // broadcast tx but it's taking too long to confirm so we want to bump the fee - /// let (mut psbt, _) = { + /// let mut psbt = { /// let mut builder = wallet.build_fee_bump(tx.txid())?; /// builder /// .fee_rate(FeeRate::from_sat_per_vb(5.0)); @@ -1171,7 +1234,7 @@ impl Wallet { /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let mut wallet = doctest_wallet!(); /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); - /// let (mut psbt, _) = { + /// let mut psbt = { /// let mut builder = wallet.build_tx(); /// builder.add_recipient(to_address.script_pubkey(), 50_000); /// builder.finish()? @@ -1721,7 +1784,7 @@ impl Wallet { Ok(changed) } - /// Commits all curently [`staged`] changed to the persistence backend returning and error when + /// Commits all currently [`staged`] changed to the persistence backend returning and error when /// this fails. /// /// This returns whether the `update` resulted in any changes. @@ -1812,61 +1875,6 @@ fn new_local_utxo( } } -fn new_tx_details( - indexed_graph: &IndexedTxGraph>, - canonical_tx: CanonicalTx<'_, Transaction, ConfirmationTimeAnchor>, - include_raw: bool, -) -> TransactionDetails { - let graph = indexed_graph.graph(); - let index = &indexed_graph.index; - let tx = canonical_tx.node.tx; - - let received = tx - .output - .iter() - .map(|txout| { - if index.index_of_spk(&txout.script_pubkey).is_some() { - txout.value - } else { - 0 - } - }) - .sum(); - - let sent = tx - .input - .iter() - .map(|txin| { - if let Some((_, txout)) = index.txout(txin.previous_output) { - txout.value - } else { - 0 - } - }) - .sum(); - - let inputs = tx - .input - .iter() - .map(|txin| { - graph - .get_txout(txin.previous_output) - .map(|txout| txout.value) - }) - .sum::>(); - let outputs = tx.output.iter().map(|txout| txout.value).sum(); - let fee = inputs.map(|inputs| inputs.saturating_sub(outputs)); - - TransactionDetails { - transaction: if include_raw { Some(tx.clone()) } else { None }, - txid: canonical_tx.node.txid, - received, - sent, - fee, - confirmation_time: canonical_tx.observed_as.cloned().into(), - } -} - #[macro_export] #[doc(hidden)] /// Macro for getting a wallet for use in a doctest diff --git a/crates/bdk/src/wallet/tx_builder.rs b/crates/bdk/src/wallet/tx_builder.rs index 165f01f25f..b43880fb76 100644 --- a/crates/bdk/src/wallet/tx_builder.rs +++ b/crates/bdk/src/wallet/tx_builder.rs @@ -32,7 +32,7 @@ //! .do_not_spend_change() //! // Turn on RBF signaling //! .enable_rbf(); -//! let (psbt, tx_details) = tx_builder.finish()?; +//! let psbt = tx_builder.finish()?; //! # Ok::<(), bdk::Error>(()) //! ``` @@ -48,10 +48,7 @@ use bitcoin::{LockTime, OutPoint, Script, Sequence, Transaction}; use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm}; use super::ChangeSet; -use crate::{ - types::{FeeRate, KeychainKind, LocalUtxo, WeightedUtxo}, - TransactionDetails, -}; +use crate::types::{FeeRate, KeychainKind, LocalUtxo, WeightedUtxo}; use crate::{Error, Utxo, Wallet}; /// Context in which the [`TxBuilder`] is valid pub trait TxBuilderContext: core::fmt::Debug + Default + Clone {} @@ -85,7 +82,7 @@ impl TxBuilderContext for BumpFee {} /// # let addr1 = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); /// # let addr2 = addr1.clone(); /// // chaining -/// let (psbt1, details) = { +/// let psbt1 = { /// let mut builder = wallet.build_tx(); /// builder /// .ordering(TxOrdering::Untouched) @@ -95,7 +92,7 @@ impl TxBuilderContext for BumpFee {} /// }; /// /// // non-chaining -/// let (psbt2, details) = { +/// let psbt2 = { /// let mut builder = wallet.build_tx(); /// builder.ordering(TxOrdering::Untouched); /// for addr in &[addr1, addr2] { @@ -527,7 +524,7 @@ impl<'a, D, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderContext> TxBuilder<'a, D, /// Returns the [`BIP174`] "PSBT" and summary details about the transaction. /// /// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki - pub fn finish(self) -> Result<(Psbt, TransactionDetails), Error> + pub fn finish(self) -> Result where D: PersistBackend, { @@ -637,7 +634,7 @@ impl<'a, D, Cs: CoinSelectionAlgorithm> TxBuilder<'a, D, Cs, CreateTx> { /// .drain_to(to_address.script_pubkey()) /// .fee_rate(FeeRate::from_sat_per_vb(5.0)) /// .enable_rbf(); - /// let (psbt, tx_details) = tx_builder.finish()?; + /// let psbt = tx_builder.finish()?; /// # Ok::<(), bdk::Error>(()) /// ``` /// diff --git a/crates/bdk/tests/common.rs b/crates/bdk/tests/common.rs index de94670321..d91f3e2b21 100644 --- a/crates/bdk/tests/common.rs +++ b/crates/bdk/tests/common.rs @@ -1,8 +1,11 @@ #![allow(unused)] -use bdk::{wallet::AddressIndex, Wallet}; + +use bdk::{wallet::AddressIndex, KeychainKind, LocalUtxo, Wallet}; +use bdk_chain::indexed_tx_graph::Indexer; use bdk_chain::{BlockId, ConfirmationTime}; use bitcoin::hashes::Hash; -use bitcoin::{BlockHash, Network, Transaction, TxOut}; +use bitcoin::{Address, BlockHash, Network, OutPoint, Transaction, TxIn, TxOut, Txid}; +use std::str::FromStr; /// Return a fake wallet that appears to be funded for testing. pub fn get_funded_wallet_with_change( @@ -10,35 +13,84 @@ pub fn get_funded_wallet_with_change( change: Option<&str>, ) -> (Wallet, bitcoin::Txid) { let mut wallet = Wallet::new_no_persist(descriptor, change, Network::Regtest).unwrap(); - let address = wallet.get_address(AddressIndex::New).address; + let change_address = wallet.get_address(AddressIndex::New).address; + let sendto_address = + Address::from_str("tb1qeua3n9t076zntxj64cz7qywwtwxd0lwvmtcmtd").expect("address"); - let tx = Transaction { + let tx0 = Transaction { version: 1, lock_time: bitcoin::PackedLockTime(0), - input: vec![], + input: vec![TxIn { + previous_output: OutPoint { + txid: Txid::all_zeros(), + vout: 0, + }, + script_sig: Default::default(), + sequence: Default::default(), + witness: Default::default(), + }], output: vec![TxOut { - value: 50_000, - script_pubkey: address.script_pubkey(), + value: 76_000, + script_pubkey: change_address.script_pubkey(), }], }; + let tx1 = Transaction { + version: 1, + lock_time: bitcoin::PackedLockTime(0), + input: vec![TxIn { + previous_output: OutPoint { + txid: tx0.txid(), + vout: 0, + }, + script_sig: Default::default(), + sequence: Default::default(), + witness: Default::default(), + }], + output: vec![ + TxOut { + value: 50_000, + script_pubkey: change_address.script_pubkey(), + }, + TxOut { + value: 25_000, + script_pubkey: sendto_address.script_pubkey(), + }, + ], + }; + wallet .insert_checkpoint(BlockId { height: 1_000, hash: BlockHash::all_zeros(), }) .unwrap(); + wallet + .insert_checkpoint(BlockId { + height: 2_000, + hash: BlockHash::all_zeros(), + }) + .unwrap(); wallet .insert_tx( - tx.clone(), + tx0.clone(), ConfirmationTime::Confirmed { height: 1_000, time: 100, }, ) .unwrap(); + wallet + .insert_tx( + tx1.clone(), + ConfirmationTime::Confirmed { + height: 2_000, + time: 200, + }, + ) + .unwrap(); - (wallet, tx.txid()) + (wallet, tx1.txid()) } pub fn get_funded_wallet(descriptor: &str) -> (Wallet, bitcoin::Txid) { diff --git a/crates/bdk/tests/psbt.rs b/crates/bdk/tests/psbt.rs index 8d399f5fea..aae8528ea7 100644 --- a/crates/bdk/tests/psbt.rs +++ b/crates/bdk/tests/psbt.rs @@ -18,7 +18,7 @@ fn test_psbt_malformed_psbt_input_legacy() { let send_to = wallet.get_address(AddressIndex::New); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), 10_000); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); psbt.inputs.push(psbt_bip.inputs[0].clone()); let options = SignOptions { trust_witness_utxo: true, @@ -35,7 +35,7 @@ fn test_psbt_malformed_psbt_input_segwit() { let send_to = wallet.get_address(AddressIndex::New); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), 10_000); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); psbt.inputs.push(psbt_bip.inputs[1].clone()); let options = SignOptions { trust_witness_utxo: true, @@ -51,7 +51,7 @@ fn test_psbt_malformed_tx_input() { let send_to = wallet.get_address(AddressIndex::New); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), 10_000); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); psbt.unsigned_tx.input.push(TxIn::default()); let options = SignOptions { trust_witness_utxo: true, @@ -67,7 +67,7 @@ fn test_psbt_sign_with_finalized() { let send_to = wallet.get_address(AddressIndex::New); let mut builder = wallet.build_tx(); builder.add_recipient(send_to.script_pubkey(), 10_000); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); // add a finalized input psbt.inputs.push(psbt_bip.inputs[0].clone()); @@ -89,7 +89,7 @@ fn test_psbt_fee_rate_with_witness_utxo() { let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); builder.fee_rate(FeeRate::from_sat_per_vb(expected_fee_rate)); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let fee_amount = psbt.fee_amount(); assert!(fee_amount.is_some()); @@ -114,7 +114,7 @@ fn test_psbt_fee_rate_with_nonwitness_utxo() { let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); builder.fee_rate(FeeRate::from_sat_per_vb(expected_fee_rate)); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let fee_amount = psbt.fee_amount(); assert!(fee_amount.is_some()); let unfinalized_fee_rate = psbt.fee_rate().unwrap(); @@ -138,7 +138,7 @@ fn test_psbt_fee_rate_with_missing_txout() { let mut builder = wpkh_wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); builder.fee_rate(FeeRate::from_sat_per_vb(expected_fee_rate)); - let (mut wpkh_psbt, _) = builder.finish().unwrap(); + let mut wpkh_psbt = builder.finish().unwrap(); wpkh_psbt.inputs[0].witness_utxo = None; wpkh_psbt.inputs[0].non_witness_utxo = None; @@ -150,7 +150,7 @@ fn test_psbt_fee_rate_with_missing_txout() { let mut builder = pkh_wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); builder.fee_rate(FeeRate::from_sat_per_vb(expected_fee_rate)); - let (mut pkh_psbt, _) = builder.finish().unwrap(); + let mut pkh_psbt = builder.finish().unwrap(); pkh_psbt.inputs[0].non_witness_utxo = None; assert!(pkh_psbt.fee_amount().is_none()); diff --git a/crates/bdk/tests/wallet.rs b/crates/bdk/tests/wallet.rs index 282a74fcb9..6c785f075e 100644 --- a/crates/bdk/tests/wallet.rs +++ b/crates/bdk/tests/wallet.rs @@ -1,23 +1,21 @@ use assert_matches::assert_matches; use bdk::descriptor::calc_checksum; +use bdk::psbt::PsbtUtils; use bdk::signer::{SignOptions, SignerError}; use bdk::wallet::coin_selection::LargestFirstCoinSelection; use bdk::wallet::AddressIndex::*; use bdk::wallet::{AddressIndex, AddressInfo, Balance, Wallet}; -use bdk::Error; -use bdk::FeeRate; -use bdk::KeychainKind; -use bdk_chain::BlockId; -use bdk_chain::ConfirmationTime; +use bdk::{Error, FeeRate, KeychainKind, TransactionAmounts}; use bdk_chain::COINBASE_MATURITY; +use bdk_chain::{BlockId, ConfirmationTime}; use bitcoin::hashes::Hash; -use bitcoin::BlockHash; use bitcoin::Script; use bitcoin::{util::psbt, Network}; use bitcoin::{ Address, EcdsaSighashType, LockTime, OutPoint, PackedLockTime, SchnorrSighashType, Sequence, Transaction, TxIn, TxOut, }; +use bitcoin::{BlockHash, Txid}; use core::str::FromStr; mod common; @@ -84,6 +82,44 @@ fn test_get_funded_wallet_balance() { assert_eq!(wallet.get_balance().confirmed, 50000); } +#[test] +fn test_get_funded_wallet_tx_amounts() { + let (wallet, _) = get_funded_wallet(get_test_wpkh()); + assert_eq!(wallet.get_balance().confirmed, 50000); + let mut tx_amounts: Vec<(Txid, TransactionAmounts)> = wallet + .transactions() + .map(|ct| (ct.node.txid, wallet.sent_and_received(ct.node.tx))) + .collect(); + tx_amounts.sort_by(|a1, a2| a1.0.cmp(&a2.0)); + + assert_eq!(tx_amounts.len(), 2); + assert_matches!( + tx_amounts.get(1), + Some(( + _, + TransactionAmounts { + received: 50_000, + sent: 76_000, + } + )) + ) +} + +#[test] +fn test_get_funded_wallet_tx_fees() { + let (wallet, _) = get_funded_wallet(get_test_wpkh()); + assert_eq!(wallet.get_balance().confirmed, 50000); + let mut tx_fee_amounts: Vec<(Txid, Option)> = wallet + .transactions() + .map(|ct| (ct.node.txid, wallet.fee_amount(ct.node.tx))) + .collect(); + tx_fee_amounts.sort_by(|a1, a2| a1.0.cmp(&a2.0)); + + assert_eq!(tx_fee_amounts.len(), 2); + assert_matches!(tx_fee_amounts.get(0), Some((_, None))); + assert_matches!(tx_fee_amounts.get(1), Some((_, Some(1000)))) +} + macro_rules! assert_fee_rate { ($psbt:expr, $fees:expr, $fee_rate:expr $( ,@dust_change $( $dust_change:expr )* )* $( ,@add_signature $( $add_signature:expr )* )* ) => ({ let psbt = $psbt.clone(); @@ -191,7 +227,7 @@ fn test_create_tx_custom_version() { builder .add_recipient(addr.script_pubkey(), 25_000) .version(42); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.version, 42); } @@ -203,11 +239,11 @@ fn test_create_tx_default_locktime_is_last_sync_height() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); // Since we never synced the wallet we don't have a last_sync_height // we could use to try to prevent fee sniping. We default to 0. - assert_eq!(psbt.unsigned_tx.lock_time.0, 1_000); + assert_eq!(psbt.unsigned_tx.lock_time.0, 2_000); } #[test] @@ -217,7 +253,7 @@ fn test_create_tx_fee_sniping_locktime_last_sync() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); // If there's no current_height we're left with using the last sync height assert_eq!( @@ -232,7 +268,7 @@ fn test_create_tx_default_locktime_cltv() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.lock_time.0, 100_000); } @@ -246,7 +282,7 @@ fn test_create_tx_custom_locktime() { .add_recipient(addr.script_pubkey(), 25_000) .current_height(630_001) .nlocktime(LockTime::from_height(630_000).unwrap()); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); // When we explicitly specify a nlocktime // we don't try any fee sniping prevention trick @@ -262,7 +298,7 @@ fn test_create_tx_custom_locktime_compatible_with_cltv() { builder .add_recipient(addr.script_pubkey(), 25_000) .nlocktime(LockTime::from_height(630_000).unwrap()); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.lock_time.0, 630_000); } @@ -287,7 +323,7 @@ fn test_create_tx_no_rbf_csv() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(6)); } @@ -300,7 +336,7 @@ fn test_create_tx_with_default_rbf_csv() { builder .add_recipient(addr.script_pubkey(), 25_000) .enable_rbf(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); // When CSV is enabled it takes precedence over the rbf value (unless forced by the user). // It will be set to the OP_CSV value, in this case 6 assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(6)); @@ -326,7 +362,7 @@ fn test_create_tx_no_rbf_cltv() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFE)); } @@ -351,7 +387,7 @@ fn test_create_tx_custom_rbf_sequence() { builder .add_recipient(addr.script_pubkey(), 25_000) .enable_rbf_with_sequence(Sequence(0xDEADBEEF)); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xDEADBEEF)); } @@ -362,7 +398,7 @@ fn test_create_tx_default_sequence() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFE)); } @@ -387,13 +423,11 @@ fn test_create_tx_drain_wallet_and_drain_to() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); assert_eq!(psbt.unsigned_tx.output.len(), 1); - assert_eq!( - psbt.unsigned_tx.output[0].value, - 50_000 - details.fee.unwrap_or(0) - ); + assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0)); } #[test] @@ -406,7 +440,8 @@ fn test_create_tx_drain_wallet_and_drain_to_and_with_recipient() { .add_recipient(addr.script_pubkey(), 20_000) .drain_to(drain_addr.script_pubkey()) .drain_wallet(); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); let outputs = psbt.unsigned_tx.output; assert_eq!(outputs.len(), 2); @@ -419,7 +454,7 @@ fn test_create_tx_drain_wallet_and_drain_to_and_with_recipient() { .find(|x| x.script_pubkey == drain_addr.script_pubkey()) .unwrap(); assert_eq!(main_output.value, 20_000,); - assert_eq!(drain_output.value, 30_000 - details.fee.unwrap_or(0)); + assert_eq!(drain_output.value, 30_000 - fee.unwrap_or(0)); } #[test] @@ -436,13 +471,11 @@ fn test_create_tx_drain_to_and_utxos() { .drain_to(addr.script_pubkey()) .add_utxos(&utxos) .unwrap(); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); assert_eq!(psbt.unsigned_tx.output.len(), 1); - assert_eq!( - psbt.unsigned_tx.output[0].value, - 50_000 - details.fee.unwrap_or(0) - ); + assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0)); } #[test] @@ -461,9 +494,10 @@ fn test_create_tx_default_fee_rate() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); - assert_fee_rate!(psbt, details.fee.unwrap_or(0), FeeRate::default(), @add_signature); + assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::default(), @add_signature); } #[test] @@ -474,9 +508,10 @@ fn test_create_tx_custom_fee_rate() { builder .add_recipient(addr.script_pubkey(), 25_000) .fee_rate(FeeRate::from_sat_per_vb(5.0)); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); - assert_fee_rate!(psbt, details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(5.0), @add_signature); + assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb(5.0), @add_signature); } #[test] @@ -488,14 +523,12 @@ fn test_create_tx_absolute_fee() { .drain_to(addr.script_pubkey()) .drain_wallet() .fee_absolute(100); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); - assert_eq!(details.fee.unwrap_or(0), 100); + assert_eq!(fee.unwrap_or(0), 100); assert_eq!(psbt.unsigned_tx.output.len(), 1); - assert_eq!( - psbt.unsigned_tx.output[0].value, - 50_000 - details.fee.unwrap_or(0) - ); + assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0)); } #[test] @@ -507,14 +540,12 @@ fn test_create_tx_absolute_zero_fee() { .drain_to(addr.script_pubkey()) .drain_wallet() .fee_absolute(0); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); - assert_eq!(details.fee.unwrap_or(0), 0); + assert_eq!(fee.unwrap_or(0), 0); assert_eq!(psbt.unsigned_tx.output.len(), 1); - assert_eq!( - psbt.unsigned_tx.output[0].value, - 50_000 - details.fee.unwrap_or(0) - ); + assert_eq!(psbt.unsigned_tx.output[0].value, 50_000 - fee.unwrap_or(0)); } #[test] @@ -527,7 +558,7 @@ fn test_create_tx_absolute_high_fee() { .drain_to(addr.script_pubkey()) .drain_wallet() .fee_absolute(60_000); - let (_psbt, _details) = builder.finish().unwrap(); + let _ = builder.finish().unwrap(); } #[test] @@ -540,14 +571,12 @@ fn test_create_tx_add_change() { builder .add_recipient(addr.script_pubkey(), 25_000) .ordering(TxOrdering::Untouched); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); assert_eq!(psbt.unsigned_tx.output.len(), 2); assert_eq!(psbt.unsigned_tx.output[0].value, 25_000); - assert_eq!( - psbt.unsigned_tx.output[1].value, - 25_000 - details.fee.unwrap_or(0) - ); + assert_eq!(psbt.unsigned_tx.output[1].value, 25_000 - fee.unwrap_or(0)); } #[test] @@ -556,11 +585,12 @@ fn test_create_tx_skip_change_dust() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 49_800); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); assert_eq!(psbt.unsigned_tx.output.len(), 1); assert_eq!(psbt.unsigned_tx.output[0].value, 49_800); - assert_eq!(details.fee.unwrap_or(0), 200); + assert_eq!(fee.unwrap_or(0), 200); } #[test] @@ -586,13 +616,11 @@ fn test_create_tx_ordering_respected() { .add_recipient(addr.script_pubkey(), 30_000) .add_recipient(addr.script_pubkey(), 10_000) .ordering(bdk::wallet::tx_builder::TxOrdering::Bip69Lexicographic); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); assert_eq!(psbt.unsigned_tx.output.len(), 3); - assert_eq!( - psbt.unsigned_tx.output[0].value, - 10_000 - details.fee.unwrap_or(0) - ); + assert_eq!(psbt.unsigned_tx.output[0].value, 10_000 - fee.unwrap_or(0)); assert_eq!(psbt.unsigned_tx.output[1].value, 10_000); assert_eq!(psbt.unsigned_tx.output[2].value, 30_000); } @@ -603,7 +631,7 @@ fn test_create_tx_default_sighash() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 30_000); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.inputs[0].sighash_type, None); } @@ -616,7 +644,7 @@ fn test_create_tx_custom_sighash() { builder .add_recipient(addr.script_pubkey(), 30_000) .sighash(bitcoin::EcdsaSighashType::Single.into()); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!( psbt.inputs[0].sighash_type, @@ -633,7 +661,7 @@ fn test_create_tx_input_hd_keypaths() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.inputs[0].bip32_derivation.len(), 1); assert_eq!( @@ -655,7 +683,7 @@ fn test_create_tx_output_hd_keypaths() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.outputs[0].bip32_derivation.len(), 1); let expected_derivation_path = format!("m/44'/0'/0'/0/{}", addr.index); @@ -677,7 +705,7 @@ fn test_create_tx_set_redeem_script_p2sh() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!( psbt.inputs[0].redeem_script, @@ -700,7 +728,7 @@ fn test_create_tx_set_witness_script_p2wsh() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.inputs[0].redeem_script, None); assert_eq!( @@ -723,7 +751,7 @@ fn test_create_tx_set_redeem_witness_script_p2wsh_p2sh() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let script = Script::from( Vec::::from_hex( @@ -743,7 +771,7 @@ fn test_create_tx_non_witness_utxo() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert!(psbt.inputs[0].non_witness_utxo.is_some()); assert!(psbt.inputs[0].witness_utxo.is_none()); @@ -759,7 +787,7 @@ fn test_create_tx_only_witness_utxo() { .drain_to(addr.script_pubkey()) .only_witness_utxo() .drain_wallet(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert!(psbt.inputs[0].non_witness_utxo.is_none()); assert!(psbt.inputs[0].witness_utxo.is_some()); @@ -772,7 +800,7 @@ fn test_create_tx_shwpkh_has_witness_utxo() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert!(psbt.inputs[0].witness_utxo.is_some()); } @@ -784,7 +812,7 @@ fn test_create_tx_both_non_witness_utxo_and_witness_utxo_default() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert!(psbt.inputs[0].non_witness_utxo.is_some()); assert!(psbt.inputs[0].witness_utxo.is_some()); @@ -818,7 +846,8 @@ fn test_create_tx_add_utxo() { vout: 0, }) .unwrap(); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let details = wallet.sent_and_received(&psbt.clone().extract_tx()); assert_eq!( psbt.unsigned_tx.input.len(), @@ -901,7 +930,7 @@ fn test_create_tx_policy_path_no_csv() { builder .add_recipient(addr.script_pubkey(), 30_000) .policy_path(path, KeychainKind::External); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFF)); } @@ -920,7 +949,7 @@ fn test_create_tx_policy_path_use_csv() { builder .add_recipient(addr.script_pubkey(), 30_000) .policy_path(path, KeychainKind::External); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(144)); } @@ -939,7 +968,7 @@ fn test_create_tx_policy_path_ignored_subtree_with_csv() { builder .add_recipient(addr.script_pubkey(), 30_000) .policy_path(path, KeychainKind::External); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFE)); } @@ -955,7 +984,7 @@ fn test_create_tx_global_xpubs_with_origin() { builder .add_recipient(addr.script_pubkey(), 25_000) .add_global_xpubs(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let key = bip32::ExtendedPubKey::from_str("tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3").unwrap(); let fingerprint = bip32::Fingerprint::from_hex("73756c7f").unwrap(); @@ -989,11 +1018,13 @@ fn test_add_foreign_utxo() { .only_witness_utxo() .add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction) .unwrap(); - let (mut psbt, details) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); + let details = wallet1.sent_and_received(&psbt.clone().extract_tx()); assert_eq!( details.sent - details.received, - 10_000 + details.fee.unwrap_or(0), + 10_000 + fee.unwrap_or(0), "we should have only net spent ~10_000" ); @@ -1055,8 +1086,8 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() { get_funded_wallet("wpkh(cVbZ8ovhye9AoAHFsqobCf7LxbXDAECy9Kb8TZdfsDYMZGBUyCnm)"); let utxo2 = wallet2.list_unspent().next().unwrap(); - let tx1 = wallet1.get_tx(txid1, true).unwrap().transaction.unwrap(); - let tx2 = wallet2.get_tx(txid2, true).unwrap().transaction.unwrap(); + let tx1 = wallet1.get_tx(txid1).unwrap().node.tx.clone(); + let tx2 = wallet2.get_tx(txid2).unwrap().node.tx.clone(); let satisfaction_weight = wallet2 .get_descriptor_for_keychain(KeychainKind::External) @@ -1069,10 +1100,10 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() { .add_foreign_utxo( utxo2.outpoint, psbt::Input { - non_witness_utxo: Some(tx1), + non_witness_utxo: Some(tx1.clone()), ..Default::default() }, - satisfaction_weight + satisfaction_weight.clone() ) .is_err(), "should fail when outpoint doesn't match psbt_input" @@ -1082,7 +1113,7 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() { .add_foreign_utxo( utxo2.outpoint, psbt::Input { - non_witness_utxo: Some(tx2), + non_witness_utxo: Some(tx2.clone()), ..Default::default() }, satisfaction_weight @@ -1141,9 +1172,9 @@ fn test_add_foreign_utxo_only_witness_utxo() { { let mut builder = builder.clone(); - let tx2 = wallet2.get_tx(txid2, true).unwrap().transaction.unwrap(); + let tx2 = wallet2.get_tx(txid2).unwrap().node.tx; let psbt_input = psbt::Input { - non_witness_utxo: Some(tx2), + non_witness_utxo: Some(tx2.clone()), ..Default::default() }; builder @@ -1191,7 +1222,7 @@ fn test_create_tx_global_xpubs_master_without_origin() { builder .add_recipient(addr.script_pubkey(), 25_000) .add_global_xpubs(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let key = bip32::ExtendedPubKey::from_str("tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL").unwrap(); let fingerprint = bip32::Fingerprint::from_hex("997a323b").unwrap(); @@ -1210,7 +1241,7 @@ fn test_bump_fee_irreplaceable_tx() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx(); let txid = tx.txid(); @@ -1227,7 +1258,7 @@ fn test_bump_fee_confirmed_tx() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx(); let txid = tx.txid(); @@ -1254,7 +1285,7 @@ fn test_bump_fee_low_fee_rate() { builder .add_recipient(addr.script_pubkey(), 25_000) .enable_rbf(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx(); let txid = tx.txid(); @@ -1277,7 +1308,7 @@ fn test_bump_fee_low_abs() { builder .add_recipient(addr.script_pubkey(), 25_000) .enable_rbf(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx(); let txid = tx.txid(); @@ -1300,7 +1331,7 @@ fn test_bump_fee_zero_abs() { builder .add_recipient(addr.script_pubkey(), 25_000) .enable_rbf(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx(); let txid = tx.txid(); @@ -1321,7 +1352,10 @@ fn test_bump_fee_reduce_change() { builder .add_recipient(addr.script_pubkey(), 25_000) .enable_rbf(); - let (psbt, original_details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let original_details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let original_fee = psbt.fee_amount(); + let tx = psbt.extract_tx(); let txid = tx.txid(); wallet @@ -1330,14 +1364,16 @@ fn test_bump_fee_reduce_change() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::from_sat_per_vb(2.5)).enable_rbf(); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let fee = psbt.fee_amount(); assert_eq!(details.sent, original_details.sent); assert_eq!( - details.received + details.fee.unwrap_or(0), - original_details.received + original_details.fee.unwrap_or(0) + details.received + fee.unwrap_or(0), + original_details.received + original_fee.unwrap_or(0) ); - assert!(details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0)); + assert!(fee.unwrap_or(0) > original_fee.unwrap_or(0)); let tx = &psbt.unsigned_tx; assert_eq!(tx.output.len(), 2); @@ -1358,23 +1394,25 @@ fn test_bump_fee_reduce_change() { details.received ); - assert_fee_rate!(psbt, details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(2.5), @add_signature); + assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb(2.5), @add_signature); let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_absolute(200); builder.enable_rbf(); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let fee = psbt.fee_amount(); assert_eq!(details.sent, original_details.sent); assert_eq!( - details.received + details.fee.unwrap_or(0), - original_details.received + original_details.fee.unwrap_or(0) + details.received + fee.unwrap_or(0), + original_details.received + original_fee.unwrap_or(0) ); assert!( - details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0), + fee.unwrap_or(0) > original_fee.unwrap_or(0), "{} > {}", - details.fee.unwrap_or(0), - original_details.fee.unwrap_or(0) + fee.unwrap_or(0), + original_fee.unwrap_or(0) ); let tx = &psbt.unsigned_tx; @@ -1396,7 +1434,7 @@ fn test_bump_fee_reduce_change() { details.received ); - assert_eq!(details.fee.unwrap_or(0), 200); + assert_eq!(fee.unwrap_or(0), 200); } #[test] @@ -1408,8 +1446,10 @@ fn test_bump_fee_reduce_single_recipient() { .drain_to(addr.script_pubkey()) .drain_wallet() .enable_rbf(); - let (psbt, original_details) = builder.finish().unwrap(); - let tx = psbt.extract_tx(); + let psbt = builder.finish().unwrap(); + let tx = psbt.clone().extract_tx(); + let original_details = wallet.sent_and_received(&tx); + let original_fee = psbt.fee_amount(); let txid = tx.txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) @@ -1420,16 +1460,18 @@ fn test_bump_fee_reduce_single_recipient() { .fee_rate(FeeRate::from_sat_per_vb(2.5)) .allow_shrinking(addr.script_pubkey()) .unwrap(); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let fee = psbt.fee_amount(); assert_eq!(details.sent, original_details.sent); - assert!(details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0)); + assert!(fee.unwrap_or(0) > original_fee.unwrap_or(0)); let tx = &psbt.unsigned_tx; assert_eq!(tx.output.len(), 1); - assert_eq!(tx.output[0].value + details.fee.unwrap_or(0), details.sent); + assert_eq!(tx.output[0].value + fee.unwrap_or(0), details.sent); - assert_fee_rate!(psbt, details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(2.5), @add_signature); + assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb(2.5), @add_signature); } #[test] @@ -1441,8 +1483,10 @@ fn test_bump_fee_absolute_reduce_single_recipient() { .drain_to(addr.script_pubkey()) .drain_wallet() .enable_rbf(); - let (psbt, original_details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let original_fee = psbt.fee_amount(); let tx = psbt.extract_tx(); + let original_details = wallet.sent_and_received(&tx); let txid = tx.txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) @@ -1453,16 +1497,18 @@ fn test_bump_fee_absolute_reduce_single_recipient() { .allow_shrinking(addr.script_pubkey()) .unwrap() .fee_absolute(300); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let tx = &psbt.unsigned_tx; + let details = wallet.sent_and_received(&tx); + let fee = psbt.fee_amount(); assert_eq!(details.sent, original_details.sent); - assert!(details.fee.unwrap_or(0) > original_details.fee.unwrap_or(0)); + assert!(fee.unwrap_or(0) > original_fee.unwrap_or(0)); - let tx = &psbt.unsigned_tx; assert_eq!(tx.output.len(), 1); - assert_eq!(tx.output[0].value + details.fee.unwrap_or(0), details.sent); + assert_eq!(tx.output[0].value + fee.unwrap_or(0), details.sent); - assert_eq!(details.fee.unwrap_or(0), 300); + assert_eq!(fee.unwrap_or(0), 300); } #[test] @@ -1499,8 +1545,10 @@ fn test_bump_fee_drain_wallet() { .unwrap() .manually_selected_only() .enable_rbf(); - let (psbt, original_details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx(); + let original_details = wallet.sent_and_received(&tx); + let txid = tx.txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) @@ -1515,7 +1563,8 @@ fn test_bump_fee_drain_wallet() { .allow_shrinking(addr.script_pubkey()) .unwrap() .fee_rate(FeeRate::from_sat_per_vb(5.0)); - let (_, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let details = wallet.sent_and_received(&psbt.extract_tx()); assert_eq!(details.sent, 75_000); } @@ -1562,8 +1611,9 @@ fn test_bump_fee_remove_output_manually_selected_only() { .unwrap() .manually_selected_only() .enable_rbf(); - let (psbt, original_details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx(); + let original_details = wallet.sent_and_received(&tx); let txid = tx.txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) @@ -1603,8 +1653,9 @@ fn test_bump_fee_add_input() { builder .add_recipient(addr.script_pubkey(), 45_000) .enable_rbf(); - let (psbt, original_details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx(); + let original_details = wallet.sent_and_received(&tx); let txid = tx.txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) @@ -1612,10 +1663,11 @@ fn test_bump_fee_add_input() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::from_sat_per_vb(50.0)); - let (psbt, details) = builder.finish().unwrap(); - + let psbt = builder.finish().unwrap(); + let details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let fee = psbt.fee_amount(); assert_eq!(details.sent, original_details.sent + 25_000); - assert_eq!(details.fee.unwrap_or(0) + details.received, 30_000); + assert_eq!(fee.unwrap_or(0) + details.received, 30_000); let tx = &psbt.unsigned_tx; assert_eq!(tx.input.len(), 2); @@ -1637,7 +1689,7 @@ fn test_bump_fee_add_input() { details.received ); - assert_fee_rate!(psbt, details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(50.0), @add_signature); + assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb(50.0), @add_signature); } #[test] @@ -1649,8 +1701,9 @@ fn test_bump_fee_absolute_add_input() { builder .add_recipient(addr.script_pubkey(), 45_000) .enable_rbf(); - let (psbt, original_details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let tx = psbt.extract_tx(); + let original_details = wallet.sent_and_received(&tx); let txid = tx.txid(); wallet .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) @@ -1658,10 +1711,12 @@ fn test_bump_fee_absolute_add_input() { let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_absolute(6_000); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let fee = psbt.fee_amount(); assert_eq!(details.sent, original_details.sent + 25_000); - assert_eq!(details.fee.unwrap_or(0) + details.received, 30_000); + assert_eq!(fee.unwrap_or(0) + details.received, 30_000); let tx = &psbt.unsigned_tx; assert_eq!(tx.input.len(), 2); @@ -1683,7 +1738,7 @@ fn test_bump_fee_absolute_add_input() { details.received ); - assert_eq!(details.fee.unwrap_or(0), 6_000); + assert_eq!(fee.unwrap_or(0), 6_000); } #[test] @@ -1700,7 +1755,9 @@ fn test_bump_fee_no_change_add_input_and_change() { .unwrap() .manually_selected_only() .enable_rbf(); - let (psbt, original_details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let original_details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let original_fee = psbt.fee_amount(); let tx = psbt.extract_tx(); let txid = tx.txid(); @@ -1712,13 +1769,15 @@ fn test_bump_fee_no_change_add_input_and_change() { // extra input and a change output, and leave the original output untouched let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.fee_rate(FeeRate::from_sat_per_vb(50.0)); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let fee = psbt.fee_amount(); - let original_send_all_amount = original_details.sent - original_details.fee.unwrap_or(0); + let original_send_all_amount = original_details.sent - original_fee.unwrap_or(0); assert_eq!(details.sent, original_details.sent + 50_000); assert_eq!( details.received, - 75_000 - original_send_all_amount - details.fee.unwrap_or(0) + 75_000 - original_send_all_amount - fee.unwrap_or(0) ); let tx = &psbt.unsigned_tx; @@ -1738,10 +1797,10 @@ fn test_bump_fee_no_change_add_input_and_change() { .find(|txout| txout.script_pubkey != addr.script_pubkey()) .unwrap() .value, - 75_000 - original_send_all_amount - details.fee.unwrap_or(0) + 75_000 - original_send_all_amount - fee.unwrap_or(0) ); - assert_fee_rate!(psbt, details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(50.0), @add_signature); + assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb(50.0), @add_signature); } #[test] @@ -1753,7 +1812,10 @@ fn test_bump_fee_add_input_change_dust() { builder .add_recipient(addr.script_pubkey(), 45_000) .enable_rbf(); - let (psbt, original_details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let original_details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let original_fee = psbt.fee_amount(); + let mut tx = psbt.extract_tx(); for txin in &mut tx.input { txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // to get realisitc weight @@ -1781,15 +1843,14 @@ fn test_bump_fee_add_input_change_dust() { // We use epsilon here to avoid asking for a slightly too high feerate let fee_abs = 50_000 + 25_000 - 45_000 - 10; builder.fee_rate(FeeRate::from_wu(fee_abs, new_tx_weight)); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let fee = psbt.fee_amount(); - assert_eq!( - original_details.received, - 5_000 - original_details.fee.unwrap_or(0) - ); + assert_eq!(original_details.received, 5_000 - original_fee.unwrap_or(0)); assert_eq!(details.sent, original_details.sent + 25_000); - assert_eq!(details.fee.unwrap_or(0), 30_000); + assert_eq!(fee.unwrap_or(0), 30_000); assert_eq!(details.received, 0); let tx = &psbt.unsigned_tx; @@ -1804,7 +1865,7 @@ fn test_bump_fee_add_input_change_dust() { 45_000 ); - assert_fee_rate!(psbt, details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(140.0), @dust_change, @add_signature); + assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb(140.0), @dust_change, @add_signature); } #[test] @@ -1817,8 +1878,9 @@ fn test_bump_fee_force_add_input() { builder .add_recipient(addr.script_pubkey(), 45_000) .enable_rbf(); - let (psbt, original_details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); + let original_details = wallet.sent_and_received(&tx); let txid = tx.txid(); for txin in &mut tx.input { txin.witness.push([0x00; P2WPKH_FAKE_WITNESS_SIZE]); // fake signature @@ -1833,10 +1895,12 @@ fn test_bump_fee_force_add_input() { .add_utxo(incoming_op) .unwrap() .fee_rate(FeeRate::from_sat_per_vb(5.0)); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let fee = psbt.fee_amount(); assert_eq!(details.sent, original_details.sent + 25_000); - assert_eq!(details.fee.unwrap_or(0) + details.received, 30_000); + assert_eq!(fee.unwrap_or(0) + details.received, 30_000); let tx = &psbt.unsigned_tx; assert_eq!(tx.input.len(), 2); @@ -1858,7 +1922,7 @@ fn test_bump_fee_force_add_input() { details.received ); - assert_fee_rate!(psbt, details.fee.unwrap_or(0), FeeRate::from_sat_per_vb(5.0), @add_signature); + assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb(5.0), @add_signature); } #[test] @@ -1871,8 +1935,9 @@ fn test_bump_fee_absolute_force_add_input() { builder .add_recipient(addr.script_pubkey(), 45_000) .enable_rbf(); - let (psbt, original_details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); + let original_details = wallet.sent_and_received(&tx); let txid = tx.txid(); // skip saving the new utxos, we know they can't be used anyways for txin in &mut tx.input { @@ -1886,10 +1951,12 @@ fn test_bump_fee_absolute_force_add_input() { // the addition of an extra input with `add_utxo()` let mut builder = wallet.build_fee_bump(txid).unwrap(); builder.add_utxo(incoming_op).unwrap().fee_absolute(250); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let details = wallet.sent_and_received(&psbt.clone().extract_tx()); + let fee = psbt.fee_amount(); assert_eq!(details.sent, original_details.sent + 25_000); - assert_eq!(details.fee.unwrap_or(0) + details.received, 30_000); + assert_eq!(fee.unwrap_or(0) + details.received, 30_000); let tx = &psbt.unsigned_tx; assert_eq!(tx.input.len(), 2); @@ -1911,7 +1978,7 @@ fn test_bump_fee_absolute_force_add_input() { details.received ); - assert_eq!(details.fee.unwrap_or(0), 250); + assert_eq!(fee.unwrap_or(0), 250); } #[test] @@ -1930,7 +1997,7 @@ fn test_bump_fee_unconfirmed_inputs_only() { .drain_wallet() .drain_to(addr.script_pubkey()) .enable_rbf(); - let (psbt, __details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); // Now we receive one transaction with 0 confirmations. We won't be able to use that for // fee bumping, as it's still unconfirmed! receive_output( @@ -1968,7 +2035,7 @@ fn test_bump_fee_unconfirmed_input() { .drain_wallet() .drain_to(addr.script_pubkey()) .enable_rbf(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); for txin in &mut tx.input { @@ -2008,10 +2075,11 @@ fn test_fee_amount_negative_drain_val() { .unwrap() .enable_rbf() .fee_rate(fee_rate); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); - assert!(psbt.inputs.len() == 1); - assert_fee_rate!(psbt, details.fee.unwrap_or(0), fee_rate, @add_signature); + assert_eq!(psbt.inputs.len(), 1); + assert_fee_rate!(psbt, fee.unwrap_or(0), fee_rate, @add_signature); } #[test] @@ -2020,7 +2088,7 @@ fn test_sign_single_xprv() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); @@ -2035,7 +2103,7 @@ fn test_sign_single_xprv_with_master_fingerprint_and_path() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); @@ -2050,7 +2118,7 @@ fn test_sign_single_xprv_bip44_path() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); @@ -2065,7 +2133,7 @@ fn test_sign_single_xprv_sh_wpkh() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); @@ -2081,7 +2149,7 @@ fn test_sign_single_wif() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); assert!(finalized); @@ -2096,7 +2164,7 @@ fn test_sign_single_xprv_no_hd_keypaths() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); psbt.inputs[0].bip32_derivation.clear(); assert_eq!(psbt.inputs[0].bip32_derivation.len(), 0); @@ -2116,7 +2184,7 @@ fn test_include_output_redeem_witness_script() { builder .add_recipient(addr.script_pubkey(), 45_000) .include_output_redeem_witness_script(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); // p2sh-p2wsh transaction should contain both witness and redeem scripts assert!(psbt @@ -2133,7 +2201,7 @@ fn test_signing_only_one_of_multiple_inputs() { builder .add_recipient(addr.script_pubkey(), 45_000) .include_output_redeem_witness_script(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); // add another input to the psbt that is at least passable. let dud_input = bitcoin::util::psbt::Input { @@ -2177,7 +2245,7 @@ fn test_remove_partial_sigs_after_finalize_sign_option() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap().0; + let mut psbt = builder.finish().unwrap(); assert!(wallet .sign( @@ -2207,7 +2275,7 @@ fn test_try_finalize_sign_option() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let mut psbt = builder.finish().unwrap().0; + let mut psbt = builder.finish().unwrap(); let finalized = wallet .sign( @@ -2244,7 +2312,7 @@ fn test_sign_nonstandard_sighash() { .drain_to(addr.script_pubkey()) .sighash(sighash.into()) .drain_wallet(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let result = wallet.sign(&mut psbt, Default::default()); assert!( @@ -2500,7 +2568,7 @@ fn test_taproot_psbt_populate_tap_key_origins() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!( psbt.inputs[0] @@ -2541,7 +2609,7 @@ fn test_taproot_psbt_populate_tap_key_origins_repeated_key() { builder .add_recipient(addr.script_pubkey(), 25_000) .policy_path(path, KeychainKind::External); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); let mut input_key_origins = psbt.inputs[0] .tap_key_origins @@ -2603,7 +2671,7 @@ fn test_taproot_psbt_input_tap_tree() { let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); assert_eq!( psbt.inputs[0].tap_merkle_root, @@ -2645,7 +2713,7 @@ fn test_taproot_sign_missing_witness_utxo() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let witness_utxo = psbt.inputs[0].witness_utxo.take(); let result = wallet.sign( @@ -2685,10 +2753,10 @@ fn test_taproot_sign_using_non_witness_utxo() { let addr = wallet.get_address(New); let mut builder = wallet.build_tx(); builder.drain_to(addr.script_pubkey()).drain_wallet(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); psbt.inputs[0].witness_utxo = None; - psbt.inputs[0].non_witness_utxo = wallet.get_tx(prev_txid, true).unwrap().transaction; + psbt.inputs[0].non_witness_utxo = Some(wallet.get_tx(prev_txid).unwrap().node.tx.clone()); assert!( psbt.inputs[0].non_witness_utxo.is_some(), "Previous tx should be present in the database" @@ -2725,11 +2793,13 @@ fn test_taproot_foreign_utxo() { .add_recipient(addr.script_pubkey(), 60_000) .add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction) .unwrap(); - let (psbt, details) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); + let details = wallet1.sent_and_received(&psbt.clone().extract_tx()); + let fee = psbt.fee_amount(); assert_eq!( details.sent - details.received, - 10_000 + details.fee.unwrap_or(0), + 10_000 + fee.unwrap_or(0), "we should have only net spent ~10_000" ); @@ -2747,7 +2817,7 @@ fn test_spend_from_wallet(mut wallet: Wallet) { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); assert!( wallet.sign(&mut psbt, Default::default()).unwrap(), @@ -2771,7 +2841,7 @@ fn test_taproot_no_key_spend() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); assert!( wallet @@ -2806,7 +2876,7 @@ fn test_taproot_script_spend_sign_all_leaves() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); assert!( wallet @@ -2837,7 +2907,7 @@ fn test_taproot_script_spend_sign_include_some_leaves() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let mut script_leaves: Vec<_> = psbt.inputs[0] .tap_scripts .clone() @@ -2877,7 +2947,7 @@ fn test_taproot_script_spend_sign_exclude_some_leaves() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let mut script_leaves: Vec<_> = psbt.inputs[0] .tap_scripts .clone() @@ -2915,7 +2985,7 @@ fn test_taproot_script_spend_sign_no_leaves() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); wallet .sign( @@ -2938,7 +3008,7 @@ fn test_taproot_sign_derive_index_from_psbt() { let mut builder = wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 25_000); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); // re-create the wallet with an empty db let wallet_empty = @@ -2961,7 +3031,7 @@ fn test_taproot_sign_explicit_sighash_all() { .drain_to(addr.script_pubkey()) .sighash(SchnorrSighashType::All.into()) .drain_wallet(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let result = wallet.sign(&mut psbt, Default::default()); assert!( @@ -2981,7 +3051,7 @@ fn test_taproot_sign_non_default_sighash() { .drain_to(addr.script_pubkey()) .sighash(sighash.into()) .drain_wallet(); - let (mut psbt, _) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); let witness_utxo = psbt.inputs[0].witness_utxo.take(); @@ -3174,7 +3244,8 @@ fn test_fee_rate_sign_no_grinding_high_r() { .drain_wallet() .fee_rate(fee_rate) .add_data(&data); - let (mut psbt, details) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); let (op_return_vout, _) = psbt .unsigned_tx .output @@ -3220,7 +3291,7 @@ fn test_fee_rate_sign_no_grinding_high_r() { ) .unwrap(); // ...and checking that everything is fine - assert_fee_rate!(psbt, details.fee.unwrap_or(0), fee_rate); + assert_fee_rate!(psbt, fee.unwrap_or(0), fee_rate); } #[test] @@ -3237,7 +3308,8 @@ fn test_fee_rate_sign_grinding_low_r() { .drain_to(addr.script_pubkey()) .drain_wallet() .fee_rate(fee_rate); - let (mut psbt, details) = builder.finish().unwrap(); + let mut psbt = builder.finish().unwrap(); + let fee = psbt.fee_amount(); wallet .sign( @@ -3253,7 +3325,7 @@ fn test_fee_rate_sign_grinding_low_r() { let key = psbt.inputs[0].partial_sigs.keys().next().unwrap(); let sig_len = psbt.inputs[0].partial_sigs[key].sig.serialize_der().len(); assert_eq!(sig_len, 70); - assert_fee_rate!(psbt, details.fee.unwrap_or(0), fee_rate); + assert_fee_rate!(psbt, fee.unwrap_or(0), fee_rate); } // #[cfg(feature = "test-hardware-signer")] @@ -3315,7 +3387,7 @@ fn test_tx_cancellation() { let mut builder = $wallet.build_tx(); builder.add_recipient(addr.script_pubkey(), 10_000); - let (psbt, _) = builder.finish().unwrap(); + let psbt = builder.finish().unwrap(); psbt }}; diff --git a/example-crates/wallet_electrum/src/main.rs b/example-crates/wallet_electrum/src/main.rs index db80f106d1..a60150e2ae 100644 --- a/example-crates/wallet_electrum/src/main.rs +++ b/example-crates/wallet_electrum/src/main.rs @@ -81,7 +81,7 @@ fn main() -> Result<(), Box> { .add_recipient(faucet_address.script_pubkey(), SEND_AMOUNT) .enable_rbf(); - let (mut psbt, _) = tx_builder.finish()?; + let mut psbt = tx_builder.finish()?; let finalized = wallet.sign(&mut psbt, SignOptions::default())?; assert!(finalized); diff --git a/example-crates/wallet_esplora/src/main.rs b/example-crates/wallet_esplora/src/main.rs index 119d9cbd79..a1c17986ee 100644 --- a/example-crates/wallet_esplora/src/main.rs +++ b/example-crates/wallet_esplora/src/main.rs @@ -82,7 +82,7 @@ fn main() -> Result<(), Box> { .add_recipient(faucet_address.script_pubkey(), SEND_AMOUNT) .enable_rbf(); - let (mut psbt, _) = tx_builder.finish()?; + let mut psbt = tx_builder.finish()?; let finalized = wallet.sign(&mut psbt, SignOptions::default())?; assert!(finalized); diff --git a/example-crates/wallet_esplora_async/src/main.rs b/example-crates/wallet_esplora_async/src/main.rs index 7cb218ec24..7aae79b8fd 100644 --- a/example-crates/wallet_esplora_async/src/main.rs +++ b/example-crates/wallet_esplora_async/src/main.rs @@ -85,7 +85,7 @@ async fn main() -> Result<(), Box> { .add_recipient(faucet_address.script_pubkey(), SEND_AMOUNT) .enable_rbf(); - let (mut psbt, _) = tx_builder.finish()?; + let mut psbt = tx_builder.finish()?; let finalized = wallet.sign(&mut psbt, SignOptions::default())?; assert!(finalized);