Merge bitcoindevkit/bdk#1411: feat: update keychain::Balance to use bitcoin::Amount

22aa534d7648e5808414ea3adfcfb702572bd6c9 feat: use `Amount` on `TxBuilder::add_recipient` (Leonardo Lima)
d5c0e7200cba0c3b4d3e3fbea168cd07ee6c1d2c feat: use `Amount` on `spk_txout_index` and related (Leonardo Lima)
8a33d98db977a07e130ad57fa9c658a5c90d4a4b feat: update `wallet::Balance` to use `bitcoin::Amount` (Leonardo Lima)

Pull request description:

  fixes #823

  <!-- You can erase any parts of this template not applicable to your Pull Request. -->

  ### Description

  It's being used on `Balance`, and throughout the code, an `u64` represents the amount, which relies on the user to infer its sats, not millisats, or any other representation.

  It updates the usage of `u64` on `Balance`, and other APIs:
  - `TxParams::add_recipient`
  - `KeyChainTxOutIndex::sent_and_received`, `KeyChainTxOutIndex::net_value`
  -  `SpkTxOutIndex::sent_and_received`, `SpkTxOutIndex::net_value`

  <!-- Describe the purpose of this PR, what's being adding and/or fixed -->

  ### Notes to the reviewers

  <!-- In this section you can include notes directed to the reviewers, like explaining why some parts
  of the PR were done in a specific way -->

  It updates some of the APIs to expect the `bitcoin::Amount`, but it does not update internal usage of u64, such as `TxParams` still expects and uses `u64`, please see the PR comments for related discussion.

  ### Changelog notice

  <!-- Notice the release manager should include in the release tag message changelog -->
  <!-- See https://keepachangelog.com/en/1.0.0/ for examples -->

  - Changed the `keychain::Balance` struct fields to use `Amount` instead of `u64`.
  - Changed the `add_recipient` method on `TxBuilder` implementation to expect `bitcoin::Amount`.
  - Changed the `sent_and_received`, and `net_value` methods on `KeyChainTxOutIndex` to expect `bitcoin::Amount`.
  - Changed the `sent_and_received`, and `net_value` methods on `SpkTxOutIndex` to expect `bitcoin::Amount`.

  ### Checklists

  #### All Submissions:

  * [x] I've signed all my commits
  * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
  * [x] I ran `cargo fmt` and `cargo clippy` before committing

  #### New Features:

  * [x] I've added tests for the new feature
  * [x] I've added docs for the new feature

  #### Bugfixes:

  * [x] This pull request breaks the existing API
  * [ ] I've added tests to reproduce the issue which are now passing
  * [x] I'm linking the issue being fixed by this PR

ACKs for top commit:
  evanlinjin:
    ACK 22aa534d7648e5808414ea3adfcfb702572bd6c9

Tree-SHA512: c4e8198d96c0d66cc3d2e4149e8a56bb7565b9cd49ff42113eaebd24b1d7bfeecd7124db0b06524b78b8891ee1bde1546705b80afad408f48495cf3c02446d02
This commit is contained in:
志宇 2024-05-06 20:22:57 +08:00
commit dcd2d4741d
No known key found for this signature in database
GPG Key ID: F6345C9837C2BDE8
18 changed files with 333 additions and 270 deletions

View File

@ -92,7 +92,7 @@
//! .unwrap(); //! .unwrap();
//! let psbt = { //! let psbt = {
//! let mut builder = wallet.build_tx().coin_selection(AlwaysSpendEverything); //! let mut builder = wallet.build_tx().coin_selection(AlwaysSpendEverything);
//! builder.add_recipient(to_address.script_pubkey(), 50_000); //! builder.add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
//! builder.finish()? //! builder.finish()?
//! }; //! };
//! //!

View File

@ -32,14 +32,14 @@ use bdk_chain::{
IndexedTxGraph, IndexedTxGraph,
}; };
use bdk_persist::{Persist, PersistBackend}; use bdk_persist::{Persist, PersistBackend};
use bitcoin::constants::genesis_block;
use bitcoin::secp256k1::{All, Secp256k1}; use bitcoin::secp256k1::{All, Secp256k1};
use bitcoin::sighash::{EcdsaSighashType, TapSighashType}; use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
use bitcoin::{ use bitcoin::{
absolute, psbt, Address, Block, FeeRate, Network, OutPoint, Script, ScriptBuf, Sequence, absolute, psbt, Address, Block, FeeRate, Network, OutPoint, Script, ScriptBuf, Sequence,
Transaction, TxOut, Txid, Witness, Transaction, TxOut, Txid, Witness,
}; };
use bitcoin::{consensus::encode::serialize, transaction, Amount, BlockHash, Psbt}; use bitcoin::{consensus::encode::serialize, transaction, BlockHash, Psbt};
use bitcoin::{constants::genesis_block, Amount};
use core::fmt; use core::fmt;
use core::ops::Deref; use core::ops::Deref;
use descriptor::error::Error as DescriptorError; use descriptor::error::Error as DescriptorError;
@ -950,10 +950,10 @@ impl Wallet {
/// [`insert_txout`]: Self::insert_txout /// [`insert_txout`]: Self::insert_txout
pub fn calculate_fee_rate(&self, tx: &Transaction) -> Result<FeeRate, CalculateFeeError> { pub fn calculate_fee_rate(&self, tx: &Transaction) -> Result<FeeRate, CalculateFeeError> {
self.calculate_fee(tx) self.calculate_fee(tx)
.map(|fee| bitcoin::Amount::from_sat(fee) / tx.weight()) .map(|fee| Amount::from_sat(fee) / tx.weight())
} }
/// Compute the `tx`'s sent and received amounts (in satoshis). /// Compute the `tx`'s sent and received [`Amount`]s.
/// ///
/// This method returns a tuple `(sent, received)`. Sent is the sum of the txin amounts /// This method returns a tuple `(sent, received)`. Sent is the sum of the txin amounts
/// that spend from previous txouts tracked by this wallet. Received is the summation /// that spend from previous txouts tracked by this wallet. Received is the summation
@ -978,7 +978,7 @@ impl Wallet {
/// let tx = &psbt.clone().extract_tx().expect("tx"); /// let tx = &psbt.clone().extract_tx().expect("tx");
/// let (sent, received) = wallet.sent_and_received(tx); /// let (sent, received) = wallet.sent_and_received(tx);
/// ``` /// ```
pub fn sent_and_received(&self, tx: &Transaction) -> (u64, u64) { pub fn sent_and_received(&self, tx: &Transaction) -> (Amount, Amount) {
self.indexed_graph.index.sent_and_received(tx, ..) self.indexed_graph.index.sent_and_received(tx, ..)
} }
@ -1197,7 +1197,7 @@ impl Wallet {
/// let psbt = { /// let psbt = {
/// let mut builder = wallet.build_tx(); /// let mut builder = wallet.build_tx();
/// builder /// builder
/// .add_recipient(to_address.script_pubkey(), 50_000); /// .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
/// builder.finish()? /// builder.finish()?
/// }; /// };
/// ///
@ -1579,7 +1579,7 @@ impl Wallet {
/// let mut psbt = { /// let mut psbt = {
/// let mut builder = wallet.build_tx(); /// let mut builder = wallet.build_tx();
/// builder /// builder
/// .add_recipient(to_address.script_pubkey(), 50_000) /// .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000))
/// .enable_rbf(); /// .enable_rbf();
/// builder.finish()? /// builder.finish()?
/// }; /// };
@ -1752,7 +1752,7 @@ impl Wallet {
/// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked(); /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
/// let mut psbt = { /// let mut psbt = {
/// let mut builder = wallet.build_tx(); /// let mut builder = wallet.build_tx();
/// builder.add_recipient(to_address.script_pubkey(), 50_000); /// builder.add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000));
/// builder.finish()? /// builder.finish()?
/// }; /// };
/// let finalized = wallet.sign(&mut psbt, SignOptions::default())?; /// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;

View File

@ -29,7 +29,7 @@
//! //!
//! tx_builder //! tx_builder
//! // Create a transaction with one output to `to_address` of 50_000 satoshi //! // Create a transaction with one output to `to_address` of 50_000 satoshi
//! .add_recipient(to_address.script_pubkey(), 50_000) //! .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000))
//! // With a custom fee rate of 5.0 satoshi/vbyte //! // With a custom fee rate of 5.0 satoshi/vbyte
//! .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate")) //! .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate"))
//! // Only spend non-change outputs //! // Only spend non-change outputs
@ -47,7 +47,7 @@ use core::marker::PhantomData;
use bitcoin::psbt::{self, Psbt}; use bitcoin::psbt::{self, Psbt};
use bitcoin::script::PushBytes; use bitcoin::script::PushBytes;
use bitcoin::{absolute, FeeRate, OutPoint, ScriptBuf, Sequence, Transaction, Txid}; use bitcoin::{absolute, Amount, FeeRate, OutPoint, ScriptBuf, Sequence, Transaction, Txid};
use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm}; use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm};
use super::{CreateTxError, Wallet}; use super::{CreateTxError, Wallet};
@ -94,8 +94,8 @@ impl TxBuilderContext for BumpFee {}
/// let mut builder = wallet.build_tx(); /// let mut builder = wallet.build_tx();
/// builder /// builder
/// .ordering(TxOrdering::Untouched) /// .ordering(TxOrdering::Untouched)
/// .add_recipient(addr1.script_pubkey(), 50_000) /// .add_recipient(addr1.script_pubkey(), Amount::from_sat(50_000))
/// .add_recipient(addr2.script_pubkey(), 50_000); /// .add_recipient(addr2.script_pubkey(), Amount::from_sat(50_000));
/// builder.finish()? /// builder.finish()?
/// }; /// };
/// ///
@ -104,7 +104,7 @@ impl TxBuilderContext for BumpFee {}
/// let mut builder = wallet.build_tx(); /// let mut builder = wallet.build_tx();
/// builder.ordering(TxOrdering::Untouched); /// builder.ordering(TxOrdering::Untouched);
/// for addr in &[addr1, addr2] { /// for addr in &[addr1, addr2] {
/// builder.add_recipient(addr.script_pubkey(), 50_000); /// builder.add_recipient(addr.script_pubkey(), Amount::from_sat(50_000));
/// } /// }
/// builder.finish()? /// builder.finish()?
/// }; /// };
@ -274,7 +274,7 @@ impl<'a, Cs, Ctx> TxBuilder<'a, Cs, Ctx> {
/// ///
/// let builder = wallet /// let builder = wallet
/// .build_tx() /// .build_tx()
/// .add_recipient(to_address.script_pubkey(), 50_000) /// .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000))
/// .policy_path(path, KeychainKind::External); /// .policy_path(path, KeychainKind::External);
/// ///
/// # Ok::<(), anyhow::Error>(()) /// # Ok::<(), anyhow::Error>(())
@ -713,21 +713,26 @@ impl std::error::Error for AllowShrinkingError {}
impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> { impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
/// Replace the recipients already added with a new list /// Replace the recipients already added with a new list
pub fn set_recipients(&mut self, recipients: Vec<(ScriptBuf, u64)>) -> &mut Self { pub fn set_recipients(&mut self, recipients: Vec<(ScriptBuf, Amount)>) -> &mut Self {
self.params.recipients = recipients; self.params.recipients = recipients
.into_iter()
.map(|(script, amount)| (script, amount.to_sat()))
.collect();
self self
} }
/// Add a recipient to the internal list /// Add a recipient to the internal list
pub fn add_recipient(&mut self, script_pubkey: ScriptBuf, amount: u64) -> &mut Self { pub fn add_recipient(&mut self, script_pubkey: ScriptBuf, amount: Amount) -> &mut Self {
self.params.recipients.push((script_pubkey, amount)); self.params
.recipients
.push((script_pubkey, amount.to_sat()));
self self
} }
/// Add data as an output, using OP_RETURN /// Add data as an output, using OP_RETURN
pub fn add_data<T: AsRef<PushBytes>>(&mut self, data: &T) -> &mut Self { pub fn add_data<T: AsRef<PushBytes>>(&mut self, data: &T) -> &mut Self {
let script = ScriptBuf::new_op_return(data); let script = ScriptBuf::new_op_return(data);
self.add_recipient(script, 0u64); self.add_recipient(script, Amount::ZERO);
self self
} }

View File

@ -14,7 +14,7 @@ fn test_psbt_malformed_psbt_input_legacy() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let send_to = wallet.peek_address(KeychainKind::External, 0); let send_to = wallet.peek_address(KeychainKind::External, 0);
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(send_to.script_pubkey(), 10_000); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000));
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
psbt.inputs.push(psbt_bip.inputs[0].clone()); psbt.inputs.push(psbt_bip.inputs[0].clone());
let options = SignOptions { let options = SignOptions {
@ -31,7 +31,7 @@ fn test_psbt_malformed_psbt_input_segwit() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let send_to = wallet.peek_address(KeychainKind::External, 0); let send_to = wallet.peek_address(KeychainKind::External, 0);
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(send_to.script_pubkey(), 10_000); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000));
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
psbt.inputs.push(psbt_bip.inputs[1].clone()); psbt.inputs.push(psbt_bip.inputs[1].clone());
let options = SignOptions { let options = SignOptions {
@ -47,7 +47,7 @@ fn test_psbt_malformed_tx_input() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let send_to = wallet.peek_address(KeychainKind::External, 0); let send_to = wallet.peek_address(KeychainKind::External, 0);
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(send_to.script_pubkey(), 10_000); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000));
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
psbt.unsigned_tx.input.push(TxIn::default()); psbt.unsigned_tx.input.push(TxIn::default());
let options = SignOptions { let options = SignOptions {
@ -63,7 +63,7 @@ fn test_psbt_sign_with_finalized() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let send_to = wallet.peek_address(KeychainKind::External, 0); let send_to = wallet.peek_address(KeychainKind::External, 0);
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(send_to.script_pubkey(), 10_000); builder.add_recipient(send_to.script_pubkey(), Amount::from_sat(10_000));
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
// add a finalized input // add a finalized input
@ -201,7 +201,7 @@ fn test_psbt_multiple_internalkey_signers() {
// the prevout we're spending // the prevout we're spending
let prevouts = &[TxOut { let prevouts = &[TxOut {
script_pubkey: send_to.script_pubkey(), script_pubkey: send_to.script_pubkey(),
value: Amount::from_sat(to_spend), value: to_spend,
}]; }];
let prevouts = Prevouts::All(prevouts); let prevouts = Prevouts::All(prevouts);
let input_index = 0; let input_index = 0;

View File

@ -200,14 +200,14 @@ fn test_get_funded_wallet_balance() {
// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000 // The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
// to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000 // to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000
// sats are the transaction fee. // sats are the transaction fee.
assert_eq!(wallet.get_balance().confirmed, 50_000); assert_eq!(wallet.get_balance().confirmed, Amount::from_sat(50_000));
} }
#[test] #[test]
fn test_get_funded_wallet_sent_and_received() { fn test_get_funded_wallet_sent_and_received() {
let (wallet, txid) = get_funded_wallet(get_test_wpkh()); let (wallet, txid) = get_funded_wallet(get_test_wpkh());
let mut tx_amounts: Vec<(Txid, (u64, u64))> = wallet let mut tx_amounts: Vec<(Txid, (Amount, Amount))> = wallet
.transactions() .transactions()
.map(|ct| (ct.tx_node.txid, wallet.sent_and_received(&ct.tx_node))) .map(|ct| (ct.tx_node.txid, wallet.sent_and_received(&ct.tx_node)))
.collect(); .collect();
@ -219,8 +219,8 @@ fn test_get_funded_wallet_sent_and_received() {
// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000 // The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
// to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000 // to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000
// sats are the transaction fee. // sats are the transaction fee.
assert_eq!(sent, 76_000); assert_eq!(sent.to_sat(), 76_000);
assert_eq!(received, 50_000); assert_eq!(received.to_sat(), 50_000);
} }
#[test] #[test]
@ -347,7 +347,7 @@ fn test_create_tx_manually_selected_empty_utxos() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.manually_selected_only(); .manually_selected_only();
builder.finish().unwrap(); builder.finish().unwrap();
} }
@ -358,7 +358,7 @@ fn test_create_tx_version_0() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.version(0); .version(0);
assert!(matches!(builder.finish(), Err(CreateTxError::Version0))); assert!(matches!(builder.finish(), Err(CreateTxError::Version0)));
} }
@ -369,7 +369,7 @@ fn test_create_tx_version_1_csv() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.version(1); .version(1);
assert!(matches!(builder.finish(), Err(CreateTxError::Version1Csv))); assert!(matches!(builder.finish(), Err(CreateTxError::Version1Csv)));
} }
@ -380,7 +380,7 @@ fn test_create_tx_custom_version() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.version(42); .version(42);
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -393,7 +393,7 @@ fn test_create_tx_default_locktime_is_last_sync_height() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(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 // Since we never synced the wallet we don't have a last_sync_height
@ -406,7 +406,7 @@ fn test_create_tx_fee_sniping_locktime_last_sync() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -422,7 +422,7 @@ fn test_create_tx_default_locktime_cltv() {
let (mut wallet, _) = get_funded_wallet(get_test_single_sig_cltv()); let (mut wallet, _) = get_funded_wallet(get_test_single_sig_cltv());
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
assert_eq!(psbt.unsigned_tx.lock_time.to_consensus_u32(), 100_000); assert_eq!(psbt.unsigned_tx.lock_time.to_consensus_u32(), 100_000);
@ -434,7 +434,7 @@ fn test_create_tx_custom_locktime() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.current_height(630_001) .current_height(630_001)
.nlocktime(absolute::LockTime::from_height(630_000).unwrap()); .nlocktime(absolute::LockTime::from_height(630_000).unwrap());
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -451,7 +451,7 @@ fn test_create_tx_custom_locktime_compatible_with_cltv() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.nlocktime(absolute::LockTime::from_height(630_000).unwrap()); .nlocktime(absolute::LockTime::from_height(630_000).unwrap());
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -464,7 +464,7 @@ fn test_create_tx_custom_locktime_incompatible_with_cltv() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.nlocktime(absolute::LockTime::from_height(50000).unwrap()); .nlocktime(absolute::LockTime::from_height(50000).unwrap());
assert!(matches!(builder.finish(), assert!(matches!(builder.finish(),
Err(CreateTxError::LockTime { requested, required }) Err(CreateTxError::LockTime { requested, required })
@ -476,7 +476,7 @@ fn test_create_tx_no_rbf_csv() {
let (mut wallet, _) = get_funded_wallet(get_test_single_sig_csv()); let (mut wallet, _) = get_funded_wallet(get_test_single_sig_csv());
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(6)); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(6));
@ -488,7 +488,7 @@ fn test_create_tx_with_default_rbf_csv() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.enable_rbf(); .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). // When CSV is enabled it takes precedence over the rbf value (unless forced by the user).
@ -502,7 +502,7 @@ fn test_create_tx_with_custom_rbf_csv() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.enable_rbf_with_sequence(Sequence(3)); .enable_rbf_with_sequence(Sequence(3));
assert!(matches!(builder.finish(), assert!(matches!(builder.finish(),
Err(CreateTxError::RbfSequenceCsv { rbf, csv }) Err(CreateTxError::RbfSequenceCsv { rbf, csv })
@ -514,7 +514,7 @@ fn test_create_tx_no_rbf_cltv() {
let (mut wallet, _) = get_funded_wallet(get_test_single_sig_cltv()); let (mut wallet, _) = get_funded_wallet(get_test_single_sig_cltv());
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFE)); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFE));
@ -526,7 +526,7 @@ fn test_create_tx_invalid_rbf_sequence() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.enable_rbf_with_sequence(Sequence(0xFFFFFFFE)); .enable_rbf_with_sequence(Sequence(0xFFFFFFFE));
assert!(matches!(builder.finish(), Err(CreateTxError::RbfSequence))); assert!(matches!(builder.finish(), Err(CreateTxError::RbfSequence)));
} }
@ -537,7 +537,7 @@ fn test_create_tx_custom_rbf_sequence() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.enable_rbf_with_sequence(Sequence(0xDEADBEEF)); .enable_rbf_with_sequence(Sequence(0xDEADBEEF));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -549,7 +549,7 @@ fn test_create_tx_default_sequence() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFE)); assert_eq!(psbt.unsigned_tx.input[0].sequence, Sequence(0xFFFFFFFE));
@ -561,7 +561,7 @@ fn test_create_tx_change_policy_no_internal() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.do_not_spend_change(); .do_not_spend_change();
assert!(matches!( assert!(matches!(
builder.finish(), builder.finish(),
@ -603,7 +603,7 @@ fn test_create_tx_drain_wallet_and_drain_to_and_with_recipient() {
let drain_addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let drain_addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 20_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(20_000))
.drain_to(drain_addr.script_pubkey()) .drain_to(drain_addr.script_pubkey())
.drain_wallet(); .drain_wallet();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -658,7 +658,7 @@ fn test_create_tx_default_fee_rate() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let fee = check_fee!(wallet, psbt); let fee = check_fee!(wallet, psbt);
@ -671,7 +671,7 @@ fn test_create_tx_custom_fee_rate() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.fee_rate(FeeRate::from_sat_per_vb_unchecked(5)); .fee_rate(FeeRate::from_sat_per_vb_unchecked(5));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let fee = check_fee!(wallet, psbt); let fee = check_fee!(wallet, psbt);
@ -740,7 +740,7 @@ fn test_create_tx_add_change() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.ordering(TxOrdering::Untouched); .ordering(TxOrdering::Untouched);
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let fee = check_fee!(wallet, psbt); let fee = check_fee!(wallet, psbt);
@ -758,7 +758,7 @@ fn test_create_tx_skip_change_dust() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 49_800); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(49_800));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let fee = check_fee!(wallet, psbt); let fee = check_fee!(wallet, psbt);
@ -787,8 +787,8 @@ fn test_create_tx_ordering_respected() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 30_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000))
.add_recipient(addr.script_pubkey(), 10_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(10_000))
.ordering(bdk::wallet::tx_builder::TxOrdering::Bip69Lexicographic); .ordering(bdk::wallet::tx_builder::TxOrdering::Bip69Lexicographic);
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let fee = check_fee!(wallet, psbt); let fee = check_fee!(wallet, psbt);
@ -807,7 +807,7 @@ fn test_create_tx_default_sighash() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 30_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(30_000));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
assert_eq!(psbt.inputs[0].sighash_type, None); assert_eq!(psbt.inputs[0].sighash_type, None);
@ -819,7 +819,7 @@ fn test_create_tx_custom_sighash() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 30_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000))
.sighash(EcdsaSighashType::Single.into()); .sighash(EcdsaSighashType::Single.into());
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -1018,7 +1018,7 @@ fn test_create_tx_add_utxo() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 30_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000))
.add_utxo(OutPoint { .add_utxo(OutPoint {
txid: small_output_tx.txid(), txid: small_output_tx.txid(),
vout: 0, vout: 0,
@ -1034,7 +1034,8 @@ fn test_create_tx_add_utxo() {
"should add an additional input since 25_000 < 30_000" "should add an additional input since 25_000 < 30_000"
); );
assert_eq!( assert_eq!(
sent_received.0, 75_000, sent_received.0,
Amount::from_sat(75_000),
"total should be sum of both inputs" "total should be sum of both inputs"
); );
} }
@ -1068,7 +1069,7 @@ fn test_create_tx_manually_selected_insufficient() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 30_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000))
.add_utxo(OutPoint { .add_utxo(OutPoint {
txid: small_output_tx.txid(), txid: small_output_tx.txid(),
vout: 0, vout: 0,
@ -1087,7 +1088,7 @@ fn test_create_tx_policy_path_required() {
.unwrap() .unwrap()
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 30_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(10_000));
builder.finish().unwrap(); builder.finish().unwrap();
} }
@ -1122,7 +1123,7 @@ fn test_create_tx_policy_path_no_csv() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 30_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000))
.policy_path(path, KeychainKind::External); .policy_path(path, KeychainKind::External);
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -1143,7 +1144,7 @@ fn test_create_tx_policy_path_use_csv() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 30_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000))
.policy_path(path, KeychainKind::External); .policy_path(path, KeychainKind::External);
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -1164,7 +1165,7 @@ fn test_create_tx_policy_path_ignored_subtree_with_csv() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 30_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(30_000))
.policy_path(path, KeychainKind::External); .policy_path(path, KeychainKind::External);
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -1180,7 +1181,7 @@ fn test_create_tx_global_xpubs_with_origin() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.add_global_xpubs(); .add_global_xpubs();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -1214,7 +1215,7 @@ fn test_add_foreign_utxo() {
let mut builder = wallet1.build_tx(); let mut builder = wallet1.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 60_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(60_000))
.only_witness_utxo() .only_witness_utxo()
.add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction) .add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction)
.unwrap(); .unwrap();
@ -1225,7 +1226,7 @@ fn test_add_foreign_utxo() {
wallet1.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); wallet1.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
assert_eq!( assert_eq!(
sent_received.0 - sent_received.1, (sent_received.0 - sent_received.1).to_sat(),
10_000 + fee.unwrap_or(0), 10_000 + fee.unwrap_or(0),
"we should have only net spent ~10_000" "we should have only net spent ~10_000"
); );
@ -1290,7 +1291,7 @@ fn test_calculate_fee_with_missing_foreign_utxo() {
let mut builder = wallet1.build_tx(); let mut builder = wallet1.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 60_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(60_000))
.only_witness_utxo() .only_witness_utxo()
.add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction) .add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction)
.unwrap(); .unwrap();
@ -1374,7 +1375,7 @@ fn test_add_foreign_utxo_only_witness_utxo() {
.unwrap(); .unwrap();
let mut builder = wallet1.build_tx(); let mut builder = wallet1.build_tx();
builder.add_recipient(addr.script_pubkey(), 60_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(60_000));
{ {
let mut builder = builder.clone(); let mut builder = builder.clone();
@ -1443,7 +1444,7 @@ fn test_create_tx_global_xpubs_origin_missing() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.add_global_xpubs(); .add_global_xpubs();
builder.finish().unwrap(); builder.finish().unwrap();
} }
@ -1457,7 +1458,7 @@ fn test_create_tx_global_xpubs_master_without_origin() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.add_global_xpubs(); .add_global_xpubs();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -1477,7 +1478,7 @@ fn test_bump_fee_irreplaceable_tx() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx"); let tx = psbt.extract_tx().expect("failed to extract tx");
@ -1494,7 +1495,7 @@ fn test_bump_fee_confirmed_tx() {
let (mut wallet, _) = get_funded_wallet(get_test_wpkh()); let (mut wallet, _) = get_funded_wallet(get_test_wpkh());
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx"); let tx = psbt.extract_tx().expect("failed to extract tx");
@ -1519,7 +1520,7 @@ fn test_bump_fee_low_fee_rate() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.enable_rbf(); .enable_rbf();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let feerate = psbt.fee_rate().unwrap(); let feerate = psbt.fee_rate().unwrap();
@ -1553,7 +1554,7 @@ fn test_bump_fee_low_abs() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.enable_rbf(); .enable_rbf();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -1576,7 +1577,7 @@ fn test_bump_fee_zero_abs() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.enable_rbf(); .enable_rbf();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -1599,7 +1600,7 @@ fn test_bump_fee_reduce_change() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.enable_rbf(); .enable_rbf();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let original_sent_received = let original_sent_received =
@ -1622,8 +1623,8 @@ fn test_bump_fee_reduce_change() {
assert_eq!(sent_received.0, original_sent_received.0); assert_eq!(sent_received.0, original_sent_received.0);
assert_eq!( assert_eq!(
sent_received.1 + fee.unwrap_or(0), sent_received.1 + Amount::from_sat(fee.unwrap_or(0)),
original_sent_received.1 + original_fee.unwrap_or(0) original_sent_received.1 + Amount::from_sat(original_fee.unwrap_or(0))
); );
assert!(fee.unwrap_or(0) > original_fee.unwrap_or(0)); assert!(fee.unwrap_or(0) > original_fee.unwrap_or(0));
@ -1642,8 +1643,7 @@ fn test_bump_fee_reduce_change() {
.iter() .iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey()) .find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap() .unwrap()
.value .value,
.to_sat(),
sent_received.1 sent_received.1
); );
@ -1659,8 +1659,8 @@ fn test_bump_fee_reduce_change() {
assert_eq!(sent_received.0, original_sent_received.0); assert_eq!(sent_received.0, original_sent_received.0);
assert_eq!( assert_eq!(
sent_received.1 + fee.unwrap_or(0), sent_received.1 + Amount::from_sat(fee.unwrap_or(0)),
original_sent_received.1 + original_fee.unwrap_or(0) original_sent_received.1 + Amount::from_sat(original_fee.unwrap_or(0))
); );
assert!( assert!(
fee.unwrap_or(0) > original_fee.unwrap_or(0), fee.unwrap_or(0) > original_fee.unwrap_or(0),
@ -1684,8 +1684,7 @@ fn test_bump_fee_reduce_change() {
.iter() .iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey()) .find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap() .unwrap()
.value .value,
.to_sat(),
sent_received.1 sent_received.1
); );
@ -1729,7 +1728,7 @@ fn test_bump_fee_reduce_single_recipient() {
let tx = &psbt.unsigned_tx; let tx = &psbt.unsigned_tx;
assert_eq!(tx.output.len(), 1); assert_eq!(tx.output.len(), 1);
assert_eq!( assert_eq!(
tx.output[0].value.to_sat() + fee.unwrap_or(0), tx.output[0].value + Amount::from_sat(fee.unwrap_or(0)),
sent_received.0 sent_received.0
); );
@ -1771,7 +1770,7 @@ fn test_bump_fee_absolute_reduce_single_recipient() {
assert_eq!(tx.output.len(), 1); assert_eq!(tx.output.len(), 1);
assert_eq!( assert_eq!(
tx.output[0].value.to_sat() + fee.unwrap_or(0), tx.output[0].value + Amount::from_sat(fee.unwrap_or(0)),
sent_received.0 sent_received.0
); );
@ -1825,7 +1824,7 @@ fn test_bump_fee_drain_wallet() {
wallet wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap(); .unwrap();
assert_eq!(original_sent_received.0, 25_000); assert_eq!(original_sent_received.0, Amount::from_sat(25_000));
// for the new feerate, it should be enough to reduce the output, but since we specify // for the new feerate, it should be enough to reduce the output, but since we specify
// `drain_wallet` we expect to spend everything // `drain_wallet` we expect to spend everything
@ -1838,7 +1837,7 @@ fn test_bump_fee_drain_wallet() {
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let sent_received = wallet.sent_and_received(&psbt.extract_tx().expect("failed to extract tx")); let sent_received = wallet.sent_and_received(&psbt.extract_tx().expect("failed to extract tx"));
assert_eq!(sent_received.0, 75_000); assert_eq!(sent_received.0, Amount::from_sat(75_000));
} }
#[test] #[test]
@ -1895,7 +1894,7 @@ fn test_bump_fee_remove_output_manually_selected_only() {
wallet wallet
.insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 }) .insert_tx(tx, ConfirmationTime::Unconfirmed { last_seen: 0 })
.unwrap(); .unwrap();
assert_eq!(original_sent_received.0, 25_000); assert_eq!(original_sent_received.0, Amount::from_sat(25_000));
let mut builder = wallet.build_fee_bump(txid).unwrap(); let mut builder = wallet.build_fee_bump(txid).unwrap();
builder builder
@ -1933,7 +1932,7 @@ fn test_bump_fee_add_input() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection); let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder builder
.add_recipient(addr.script_pubkey(), 45_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000))
.enable_rbf(); .enable_rbf();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx"); let tx = psbt.extract_tx().expect("failed to extract tx");
@ -1949,8 +1948,14 @@ fn test_bump_fee_add_input() {
let sent_received = let sent_received =
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt); let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_details.0 + 25_000); assert_eq!(
assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000); sent_received.0,
original_details.0 + Amount::from_sat(25_000)
);
assert_eq!(
Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
Amount::from_sat(30_000)
);
let tx = &psbt.unsigned_tx; let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2); assert_eq!(tx.input.len(), 2);
@ -1968,8 +1973,7 @@ fn test_bump_fee_add_input() {
.iter() .iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey()) .find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap() .unwrap()
.value .value,
.to_sat(),
sent_received.1 sent_received.1
); );
@ -1985,7 +1989,7 @@ fn test_bump_fee_absolute_add_input() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection); let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder builder
.add_recipient(addr.script_pubkey(), 45_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000))
.enable_rbf(); .enable_rbf();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let tx = psbt.extract_tx().expect("failed to extract tx"); let tx = psbt.extract_tx().expect("failed to extract tx");
@ -2002,8 +2006,14 @@ fn test_bump_fee_absolute_add_input() {
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt); let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_sent_received.0 + 25_000); assert_eq!(
assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000); sent_received.0,
original_sent_received.0 + Amount::from_sat(25_000)
);
assert_eq!(
Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
Amount::from_sat(30_000)
);
let tx = &psbt.unsigned_tx; let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2); assert_eq!(tx.input.len(), 2);
@ -2021,8 +2031,7 @@ fn test_bump_fee_absolute_add_input() {
.iter() .iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey()) .find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap() .unwrap()
.value .value,
.to_sat(),
sent_received.1 sent_received.1
); );
@ -2065,11 +2074,15 @@ fn test_bump_fee_no_change_add_input_and_change() {
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt); let fee = check_fee!(wallet, psbt);
let original_send_all_amount = original_sent_received.0 - original_fee.unwrap_or(0); let original_send_all_amount =
assert_eq!(sent_received.0, original_sent_received.0 + 50_000); original_sent_received.0 - Amount::from_sat(original_fee.unwrap_or(0));
assert_eq!(
sent_received.0,
original_sent_received.0 + Amount::from_sat(50_000)
);
assert_eq!( assert_eq!(
sent_received.1, sent_received.1,
75_000 - original_send_all_amount - fee.unwrap_or(0) Amount::from_sat(75_000) - original_send_all_amount - Amount::from_sat(fee.unwrap_or(0))
); );
let tx = &psbt.unsigned_tx; let tx = &psbt.unsigned_tx;
@ -2081,16 +2094,15 @@ fn test_bump_fee_no_change_add_input_and_change() {
.find(|txout| txout.script_pubkey == addr.script_pubkey()) .find(|txout| txout.script_pubkey == addr.script_pubkey())
.unwrap() .unwrap()
.value, .value,
Amount::from_sat(original_send_all_amount) original_send_all_amount
); );
assert_eq!( assert_eq!(
tx.output tx.output
.iter() .iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey()) .find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap() .unwrap()
.value .value,
.to_sat(), Amount::from_sat(75_000) - original_send_all_amount - Amount::from_sat(fee.unwrap_or(0))
75_000 - original_send_all_amount - fee.unwrap_or(0)
); );
assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb_unchecked(50), @add_signature); assert_fee_rate!(psbt, fee.unwrap_or(0), FeeRate::from_sat_per_vb_unchecked(50), @add_signature);
@ -2105,7 +2117,7 @@ fn test_bump_fee_add_input_change_dust() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection); let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder builder
.add_recipient(addr.script_pubkey(), 45_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000))
.enable_rbf(); .enable_rbf();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let original_sent_received = let original_sent_received =
@ -2145,11 +2157,17 @@ fn test_bump_fee_add_input_change_dust() {
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt); let fee = check_fee!(wallet, psbt);
assert_eq!(original_sent_received.1, 5_000 - original_fee.unwrap_or(0)); assert_eq!(
original_sent_received.1,
Amount::from_sat(5_000 - original_fee.unwrap_or(0))
);
assert_eq!(sent_received.0, original_sent_received.0 + 25_000); assert_eq!(
sent_received.0,
original_sent_received.0 + Amount::from_sat(25_000)
);
assert_eq!(fee.unwrap_or(0), 30_000); assert_eq!(fee.unwrap_or(0), 30_000);
assert_eq!(sent_received.1, 0); assert_eq!(sent_received.1, Amount::ZERO);
let tx = &psbt.unsigned_tx; let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2); assert_eq!(tx.input.len(), 2);
@ -2176,7 +2194,7 @@ fn test_bump_fee_force_add_input() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection); let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder builder
.add_recipient(addr.script_pubkey(), 45_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000))
.enable_rbf(); .enable_rbf();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let mut tx = psbt.extract_tx().expect("failed to extract tx"); let mut tx = psbt.extract_tx().expect("failed to extract tx");
@ -2200,8 +2218,14 @@ fn test_bump_fee_force_add_input() {
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt); let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_sent_received.0 + 25_000); assert_eq!(
assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000); sent_received.0,
original_sent_received.0 + Amount::from_sat(25_000)
);
assert_eq!(
Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
Amount::from_sat(30_000)
);
let tx = &psbt.unsigned_tx; let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2); assert_eq!(tx.input.len(), 2);
@ -2219,8 +2243,7 @@ fn test_bump_fee_force_add_input() {
.iter() .iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey()) .find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap() .unwrap()
.value .value,
.to_sat(),
sent_received.1 sent_received.1
); );
@ -2237,7 +2260,7 @@ fn test_bump_fee_absolute_force_add_input() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection); let mut builder = wallet.build_tx().coin_selection(LargestFirstCoinSelection);
builder builder
.add_recipient(addr.script_pubkey(), 45_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000))
.enable_rbf(); .enable_rbf();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
let mut tx = psbt.extract_tx().expect("failed to extract tx"); let mut tx = psbt.extract_tx().expect("failed to extract tx");
@ -2260,8 +2283,14 @@ fn test_bump_fee_absolute_force_add_input() {
wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx")); wallet.sent_and_received(&psbt.clone().extract_tx().expect("failed to extract tx"));
let fee = check_fee!(wallet, psbt); let fee = check_fee!(wallet, psbt);
assert_eq!(sent_received.0, original_sent_received.0 + 25_000); assert_eq!(
assert_eq!(fee.unwrap_or(0) + sent_received.1, 30_000); sent_received.0,
original_sent_received.0 + Amount::from_sat(25_000)
);
assert_eq!(
Amount::from_sat(fee.unwrap_or(0)) + sent_received.1,
Amount::from_sat(30_000)
);
let tx = &psbt.unsigned_tx; let tx = &psbt.unsigned_tx;
assert_eq!(tx.input.len(), 2); assert_eq!(tx.input.len(), 2);
@ -2279,8 +2308,7 @@ fn test_bump_fee_absolute_force_add_input() {
.iter() .iter()
.find(|txout| txout.script_pubkey != addr.script_pubkey()) .find(|txout| txout.script_pubkey != addr.script_pubkey())
.unwrap() .unwrap()
.value .value,
.to_sat(),
sent_received.1 sent_received.1
); );
@ -2382,7 +2410,7 @@ fn test_fee_amount_negative_drain_val() {
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(send_to.script_pubkey(), 8630) .add_recipient(send_to.script_pubkey(), Amount::from_sat(8630))
.add_utxo(incoming_op) .add_utxo(incoming_op)
.unwrap() .unwrap()
.enable_rbf() .enable_rbf()
@ -2496,7 +2524,7 @@ fn test_include_output_redeem_witness_script() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 45_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000))
.include_output_redeem_witness_script(); .include_output_redeem_witness_script();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -2515,7 +2543,7 @@ fn test_signing_only_one_of_multiple_inputs() {
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 45_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(45_000))
.include_output_redeem_witness_script(); .include_output_redeem_witness_script();
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
@ -2860,7 +2888,7 @@ fn test_sending_to_bip350_bech32m_address() {
.unwrap() .unwrap()
.assume_checked(); .assume_checked();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 45_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(45_000));
builder.finish().unwrap(); builder.finish().unwrap();
} }
@ -2993,7 +3021,7 @@ fn test_taproot_psbt_populate_tap_key_origins() {
let addr = wallet.reveal_next_address(KeychainKind::External).unwrap(); let addr = wallet.reveal_next_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
assert_eq!( assert_eq!(
@ -3033,7 +3061,7 @@ fn test_taproot_psbt_populate_tap_key_origins_repeated_key() {
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 25_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(25_000))
.policy_path(path, KeychainKind::External); .policy_path(path, KeychainKind::External);
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -3217,7 +3245,7 @@ fn test_taproot_foreign_utxo() {
let mut builder = wallet1.build_tx(); let mut builder = wallet1.build_tx();
builder builder
.add_recipient(addr.script_pubkey(), 60_000) .add_recipient(addr.script_pubkey(), Amount::from_sat(60_000))
.add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction) .add_foreign_utxo(utxo.outpoint, psbt_input, foreign_utxo_satisfaction)
.unwrap(); .unwrap();
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();
@ -3228,7 +3256,7 @@ fn test_taproot_foreign_utxo() {
assert_eq!( assert_eq!(
sent_received.0 - sent_received.1, sent_received.0 - sent_received.1,
10_000 + fee.unwrap_or(0), Amount::from_sat(10_000 + fee.unwrap_or(0)),
"we should have only net spent ~10_000" "we should have only net spent ~10_000"
); );
@ -3245,7 +3273,7 @@ fn test_spend_from_wallet(mut wallet: Wallet) {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
assert!( assert!(
@ -3269,7 +3297,7 @@ fn test_taproot_no_key_spend() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
assert!( assert!(
@ -3304,7 +3332,7 @@ fn test_taproot_script_spend_sign_all_leaves() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
assert!( assert!(
@ -3335,7 +3363,7 @@ fn test_taproot_script_spend_sign_include_some_leaves() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
let mut script_leaves: Vec<_> = psbt.inputs[0] let mut script_leaves: Vec<_> = psbt.inputs[0]
.tap_scripts .tap_scripts
@ -3375,7 +3403,7 @@ fn test_taproot_script_spend_sign_exclude_some_leaves() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
let mut script_leaves: Vec<_> = psbt.inputs[0] let mut script_leaves: Vec<_> = psbt.inputs[0]
.tap_scripts .tap_scripts
@ -3413,7 +3441,7 @@ fn test_taproot_script_spend_sign_no_leaves() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
wallet wallet
@ -3436,7 +3464,7 @@ fn test_taproot_sign_derive_index_from_psbt() {
let addr = wallet.next_unused_address(KeychainKind::External).unwrap(); let addr = wallet.next_unused_address(KeychainKind::External).unwrap();
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 25_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(25_000));
let mut psbt = builder.finish().unwrap(); let mut psbt = builder.finish().unwrap();
// re-create the wallet with an empty db // re-create the wallet with an empty db
@ -3582,10 +3610,10 @@ fn test_spend_coinbase() {
assert_eq!( assert_eq!(
balance, balance,
Balance { Balance {
immature: 25_000, immature: Amount::from_sat(25_000),
trusted_pending: 0, trusted_pending: Amount::ZERO,
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 0 confirmed: Amount::ZERO
} }
); );
@ -3633,10 +3661,10 @@ fn test_spend_coinbase() {
assert_eq!( assert_eq!(
balance, balance,
Balance { Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 0, trusted_pending: Amount::ZERO,
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 25_000 confirmed: Amount::from_sat(25_000)
} }
); );
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
@ -3654,7 +3682,7 @@ fn test_allow_dust_limit() {
let mut builder = wallet.build_tx(); let mut builder = wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 0); builder.add_recipient(addr.script_pubkey(), Amount::ZERO);
assert_matches!( assert_matches!(
builder.finish(), builder.finish(),
@ -3665,7 +3693,7 @@ fn test_allow_dust_limit() {
builder builder
.allow_dust(true) .allow_dust(true)
.add_recipient(addr.script_pubkey(), 0); .add_recipient(addr.script_pubkey(), Amount::ZERO);
assert!(builder.finish().is_ok()); assert!(builder.finish().is_ok());
} }
@ -3793,7 +3821,7 @@ fn test_tx_cancellation() {
.unwrap() .unwrap()
.assume_checked(); .assume_checked();
let mut builder = $wallet.build_tx(); let mut builder = $wallet.build_tx();
builder.add_recipient(addr.script_pubkey(), 10_000); builder.add_recipient(addr.script_pubkey(), Amount::from_sat(10_000));
let psbt = builder.finish().unwrap(); let psbt = builder.finish().unwrap();

View File

@ -377,7 +377,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
assert_eq!( assert_eq!(
get_balance(&recv_chain, &recv_graph)?, get_balance(&recv_chain, &recv_graph)?,
Balance { Balance {
confirmed: SEND_AMOUNT.to_sat() * ADDITIONAL_COUNT as u64, confirmed: SEND_AMOUNT * ADDITIONAL_COUNT as u64,
..Balance::default() ..Balance::default()
}, },
"initial balance must be correct", "initial balance must be correct",
@ -391,8 +391,8 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
assert_eq!( assert_eq!(
get_balance(&recv_chain, &recv_graph)?, get_balance(&recv_chain, &recv_graph)?,
Balance { Balance {
confirmed: SEND_AMOUNT.to_sat() * (ADDITIONAL_COUNT - reorg_count) as u64, confirmed: SEND_AMOUNT * (ADDITIONAL_COUNT - reorg_count) as u64,
trusted_pending: SEND_AMOUNT.to_sat() * reorg_count as u64, trusted_pending: SEND_AMOUNT * reorg_count as u64,
..Balance::default() ..Balance::default()
}, },
"reorg_count: {}", "reorg_count: {}",

View File

@ -14,6 +14,7 @@ use crate::{collections::BTreeMap, Append};
#[cfg(feature = "miniscript")] #[cfg(feature = "miniscript")]
mod txout_index; mod txout_index;
use bitcoin::Amount;
#[cfg(feature = "miniscript")] #[cfg(feature = "miniscript")]
pub use txout_index::*; pub use txout_index::*;
@ -90,13 +91,13 @@ impl<K> AsRef<BTreeMap<K, u32>> for ChangeSet<K> {
)] )]
pub struct Balance { pub struct Balance {
/// All coinbase outputs not yet matured /// All coinbase outputs not yet matured
pub immature: u64, pub immature: Amount,
/// Unconfirmed UTXOs generated by a wallet tx /// Unconfirmed UTXOs generated by a wallet tx
pub trusted_pending: u64, pub trusted_pending: Amount,
/// Unconfirmed UTXOs received from an external wallet /// Unconfirmed UTXOs received from an external wallet
pub untrusted_pending: u64, pub untrusted_pending: Amount,
/// Confirmed and immediately spendable balance /// Confirmed and immediately spendable balance
pub confirmed: u64, pub confirmed: Amount,
} }
impl Balance { impl Balance {
@ -104,12 +105,12 @@ impl Balance {
/// ///
/// This is the balance you can spend right now that shouldn't get cancelled via another party /// This is the balance you can spend right now that shouldn't get cancelled via another party
/// double spending it. /// double spending it.
pub fn trusted_spendable(&self) -> u64 { pub fn trusted_spendable(&self) -> Amount {
self.confirmed + self.trusted_pending self.confirmed + self.trusted_pending
} }
/// Get the whole balance visible to the wallet. /// Get the whole balance visible to the wallet.
pub fn total(&self) -> u64 { pub fn total(&self) -> Amount {
self.confirmed + self.trusted_pending + self.untrusted_pending + self.immature self.confirmed + self.trusted_pending + self.untrusted_pending + self.immature
} }
} }

View File

@ -5,7 +5,7 @@ use crate::{
spk_iter::BIP32_MAX_INDEX, spk_iter::BIP32_MAX_INDEX,
SpkIterator, SpkTxOutIndex, SpkIterator, SpkTxOutIndex,
}; };
use bitcoin::{OutPoint, Script, Transaction, TxOut, Txid}; use bitcoin::{Amount, OutPoint, Script, SignedAmount, Transaction, TxOut, Txid};
use core::{ use core::{
fmt::Debug, fmt::Debug,
ops::{Bound, RangeBounds}, ops::{Bound, RangeBounds},
@ -273,7 +273,11 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
/// *received* when it is on an output. For `sent` to be computed correctly, the output being /// *received* when it is on an output. For `sent` to be computed correctly, the output being
/// spent must have already been scanned by the index. Calculating received just uses the /// spent must have already been scanned by the index. Calculating received just uses the
/// [`Transaction`] outputs directly, so it will be correct even if it has not been scanned. /// [`Transaction`] outputs directly, so it will be correct even if it has not been scanned.
pub fn sent_and_received(&self, tx: &Transaction, range: impl RangeBounds<K>) -> (u64, u64) { pub fn sent_and_received(
&self,
tx: &Transaction,
range: impl RangeBounds<K>,
) -> (Amount, Amount) {
self.inner self.inner
.sent_and_received(tx, Self::map_to_inner_bounds(range)) .sent_and_received(tx, Self::map_to_inner_bounds(range))
} }
@ -285,7 +289,7 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
/// This calls [`SpkTxOutIndex::net_value`] internally. /// This calls [`SpkTxOutIndex::net_value`] internally.
/// ///
/// [`sent_and_received`]: Self::sent_and_received /// [`sent_and_received`]: Self::sent_and_received
pub fn net_value(&self, tx: &Transaction, range: impl RangeBounds<K>) -> i64 { pub fn net_value(&self, tx: &Transaction, range: impl RangeBounds<K>) -> SignedAmount {
self.inner.net_value(tx, Self::map_to_inner_bounds(range)) self.inner.net_value(tx, Self::map_to_inner_bounds(range))
} }
} }

View File

@ -4,7 +4,7 @@ use crate::{
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap}, collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap},
indexed_tx_graph::Indexer, indexed_tx_graph::Indexer,
}; };
use bitcoin::{OutPoint, Script, ScriptBuf, Transaction, TxOut, Txid}; use bitcoin::{Amount, OutPoint, Script, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};
/// An index storing [`TxOut`]s that have a script pubkey that matches those in a list. /// An index storing [`TxOut`]s that have a script pubkey that matches those in a list.
/// ///
@ -275,21 +275,25 @@ impl<I: Clone + Ord> SpkTxOutIndex<I> {
/// output. For `sent` to be computed correctly, the output being spent must have already been /// output. For `sent` to be computed correctly, the output being spent must have already been
/// scanned by the index. Calculating received just uses the [`Transaction`] outputs directly, /// scanned by the index. Calculating received just uses the [`Transaction`] outputs directly,
/// so it will be correct even if it has not been scanned. /// so it will be correct even if it has not been scanned.
pub fn sent_and_received(&self, tx: &Transaction, range: impl RangeBounds<I>) -> (u64, u64) { pub fn sent_and_received(
let mut sent = 0; &self,
let mut received = 0; tx: &Transaction,
range: impl RangeBounds<I>,
) -> (Amount, Amount) {
let mut sent = Amount::ZERO;
let mut received = Amount::ZERO;
for txin in &tx.input { for txin in &tx.input {
if let Some((index, txout)) = self.txout(txin.previous_output) { if let Some((index, txout)) = self.txout(txin.previous_output) {
if range.contains(index) { if range.contains(index) {
sent += txout.value.to_sat(); sent += txout.value;
} }
} }
} }
for txout in &tx.output { for txout in &tx.output {
if let Some(index) = self.index_of_spk(&txout.script_pubkey) { if let Some(index) = self.index_of_spk(&txout.script_pubkey) {
if range.contains(index) { if range.contains(index) {
received += txout.value.to_sat(); received += txout.value;
} }
} }
} }
@ -301,9 +305,10 @@ impl<I: Clone + Ord> SpkTxOutIndex<I> {
/// for calling [`sent_and_received`] and subtracting sent from received. /// for calling [`sent_and_received`] and subtracting sent from received.
/// ///
/// [`sent_and_received`]: Self::sent_and_received /// [`sent_and_received`]: Self::sent_and_received
pub fn net_value(&self, tx: &Transaction, range: impl RangeBounds<I>) -> i64 { pub fn net_value(&self, tx: &Transaction, range: impl RangeBounds<I>) -> SignedAmount {
let (sent, received) = self.sent_and_received(tx, range); let (sent, received) = self.sent_and_received(tx, range);
received as i64 - sent as i64 received.to_signed().expect("valid `SignedAmount`")
- sent.to_signed().expect("valid `SignedAmount`")
} }
/// Whether any of the inputs of this transaction spend a txout tracked or whether any output /// Whether any of the inputs of this transaction spend a txout tracked or whether any output

View File

@ -95,7 +95,7 @@ use crate::{
use alloc::collections::vec_deque::VecDeque; use alloc::collections::vec_deque::VecDeque;
use alloc::sync::Arc; use alloc::sync::Arc;
use alloc::vec::Vec; use alloc::vec::Vec;
use bitcoin::{OutPoint, Script, Transaction, TxOut, Txid}; use bitcoin::{Amount, OutPoint, Script, Transaction, TxOut, Txid};
use core::fmt::{self, Formatter}; use core::fmt::{self, Formatter};
use core::{ use core::{
convert::Infallible, convert::Infallible,
@ -1155,10 +1155,10 @@ impl<A: Anchor> TxGraph<A> {
outpoints: impl IntoIterator<Item = (OI, OutPoint)>, outpoints: impl IntoIterator<Item = (OI, OutPoint)>,
mut trust_predicate: impl FnMut(&OI, &Script) -> bool, mut trust_predicate: impl FnMut(&OI, &Script) -> bool,
) -> Result<Balance, C::Error> { ) -> Result<Balance, C::Error> {
let mut immature = 0; let mut immature = Amount::ZERO;
let mut trusted_pending = 0; let mut trusted_pending = Amount::ZERO;
let mut untrusted_pending = 0; let mut untrusted_pending = Amount::ZERO;
let mut confirmed = 0; let mut confirmed = Amount::ZERO;
for res in self.try_filter_chain_unspents(chain, chain_tip, outpoints) { for res in self.try_filter_chain_unspents(chain, chain_tip, outpoints) {
let (spk_i, txout) = res?; let (spk_i, txout) = res?;
@ -1166,16 +1166,16 @@ impl<A: Anchor> TxGraph<A> {
match &txout.chain_position { match &txout.chain_position {
ChainPosition::Confirmed(_) => { ChainPosition::Confirmed(_) => {
if txout.is_confirmed_and_spendable(chain_tip.height) { if txout.is_confirmed_and_spendable(chain_tip.height) {
confirmed += txout.txout.value.to_sat(); confirmed += txout.txout.value;
} else if !txout.is_mature(chain_tip.height) { } else if !txout.is_mature(chain_tip.height) {
immature += txout.txout.value.to_sat(); immature += txout.txout.value;
} }
} }
ChainPosition::Unconfirmed(_) => { ChainPosition::Unconfirmed(_) => {
if trust_predicate(&spk_i, &txout.txout.script_pubkey) { if trust_predicate(&spk_i, &txout.txout.script_pubkey) {
trusted_pending += txout.txout.value.to_sat(); trusted_pending += txout.txout.value;
} else { } else {
untrusted_pending += txout.txout.value.to_sat(); untrusted_pending += txout.txout.value;
} }
} }
} }

View File

@ -341,10 +341,10 @@ fn test_list_owned_txouts() {
assert_eq!( assert_eq!(
balance, balance,
Balance { Balance {
immature: 70000, // immature coinbase immature: Amount::from_sat(70000), // immature coinbase
trusted_pending: 25000, // tx3 + tx5 trusted_pending: Amount::from_sat(25000), // tx3 + tx5
untrusted_pending: 20000, // tx4 untrusted_pending: Amount::from_sat(20000), // tx4
confirmed: 0 // Nothing is confirmed yet confirmed: Amount::ZERO // Nothing is confirmed yet
} }
); );
} }
@ -376,10 +376,10 @@ fn test_list_owned_txouts() {
assert_eq!( assert_eq!(
balance, balance,
Balance { Balance {
immature: 70000, // immature coinbase immature: Amount::from_sat(70000), // immature coinbase
trusted_pending: 25000, // tx3 + tx5 trusted_pending: Amount::from_sat(25000), // tx3 + tx5
untrusted_pending: 20000, // tx4 untrusted_pending: Amount::from_sat(20000), // tx4
confirmed: 0 // Nothing is confirmed yet confirmed: Amount::ZERO // Nothing is confirmed yet
} }
); );
} }
@ -408,10 +408,10 @@ fn test_list_owned_txouts() {
assert_eq!( assert_eq!(
balance, balance,
Balance { Balance {
immature: 70000, // immature coinbase immature: Amount::from_sat(70000), // immature coinbase
trusted_pending: 15000, // tx5 trusted_pending: Amount::from_sat(15000), // tx5
untrusted_pending: 20000, // tx4 untrusted_pending: Amount::from_sat(20000), // tx4
confirmed: 10000 // tx3 got confirmed confirmed: Amount::from_sat(10000) // tx3 got confirmed
} }
); );
} }
@ -439,10 +439,10 @@ fn test_list_owned_txouts() {
assert_eq!( assert_eq!(
balance, balance,
Balance { Balance {
immature: 70000, // immature coinbase immature: Amount::from_sat(70000), // immature coinbase
trusted_pending: 15000, // tx5 trusted_pending: Amount::from_sat(15000), // tx5
untrusted_pending: 20000, // tx4 untrusted_pending: Amount::from_sat(20000), // tx4
confirmed: 10000 // tx1 got matured confirmed: Amount::from_sat(10000) // tx1 got matured
} }
); );
} }
@ -455,10 +455,10 @@ fn test_list_owned_txouts() {
assert_eq!( assert_eq!(
balance, balance,
Balance { Balance {
immature: 0, // coinbase matured immature: Amount::ZERO, // coinbase matured
trusted_pending: 15000, // tx5 trusted_pending: Amount::from_sat(15000), // tx5
untrusted_pending: 20000, // tx4 untrusted_pending: Amount::from_sat(20000), // tx4
confirmed: 80000 // tx1 + tx3 confirmed: Amount::from_sat(80000) // tx1 + tx3
} }
); );
} }

View File

@ -1,5 +1,7 @@
use bdk_chain::{indexed_tx_graph::Indexer, SpkTxOutIndex}; use bdk_chain::{indexed_tx_graph::Indexer, SpkTxOutIndex};
use bitcoin::{absolute, transaction, Amount, OutPoint, ScriptBuf, Transaction, TxIn, TxOut}; use bitcoin::{
absolute, transaction, Amount, OutPoint, ScriptBuf, SignedAmount, Transaction, TxIn, TxOut,
};
#[test] #[test]
fn spk_txout_sent_and_received() { fn spk_txout_sent_and_received() {
@ -20,14 +22,23 @@ fn spk_txout_sent_and_received() {
}], }],
}; };
assert_eq!(index.sent_and_received(&tx1, ..), (0, 42_000)); assert_eq!(
assert_eq!(index.sent_and_received(&tx1, ..1), (0, 42_000)); index.sent_and_received(&tx1, ..),
assert_eq!(index.sent_and_received(&tx1, 1..), (0, 0)); (Amount::from_sat(0), Amount::from_sat(42_000))
assert_eq!(index.net_value(&tx1, ..), 42_000); );
assert_eq!(
index.sent_and_received(&tx1, ..1),
(Amount::from_sat(0), Amount::from_sat(42_000))
);
assert_eq!(
index.sent_and_received(&tx1, 1..),
(Amount::from_sat(0), Amount::from_sat(0))
);
assert_eq!(index.net_value(&tx1, ..), SignedAmount::from_sat(42_000));
index.index_tx(&tx1); index.index_tx(&tx1);
assert_eq!( assert_eq!(
index.sent_and_received(&tx1, ..), index.sent_and_received(&tx1, ..),
(0, 42_000), (Amount::from_sat(0), Amount::from_sat(42_000)),
"shouldn't change after scanning" "shouldn't change after scanning"
); );
@ -53,10 +64,19 @@ fn spk_txout_sent_and_received() {
], ],
}; };
assert_eq!(index.sent_and_received(&tx2, ..), (42_000, 50_000)); assert_eq!(
assert_eq!(index.sent_and_received(&tx2, ..1), (42_000, 30_000)); index.sent_and_received(&tx2, ..),
assert_eq!(index.sent_and_received(&tx2, 1..), (0, 20_000)); (Amount::from_sat(42_000), Amount::from_sat(50_000))
assert_eq!(index.net_value(&tx2, ..), 8_000); );
assert_eq!(
index.sent_and_received(&tx2, ..1),
(Amount::from_sat(42_000), Amount::from_sat(30_000))
);
assert_eq!(
index.sent_and_received(&tx2, 1..),
(Amount::from_sat(0), Amount::from_sat(20_000))
);
assert_eq!(index.net_value(&tx2, ..), SignedAmount::from_sat(8_000));
} }
#[test] #[test]

View File

@ -4,7 +4,7 @@ mod common;
use std::collections::{BTreeSet, HashSet}; use std::collections::{BTreeSet, HashSet};
use bdk_chain::{keychain::Balance, BlockId}; use bdk_chain::{keychain::Balance, BlockId};
use bitcoin::{OutPoint, Script}; use bitcoin::{Amount, OutPoint, Script};
use common::*; use common::*;
#[allow(dead_code)] #[allow(dead_code)]
@ -79,10 +79,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("confirmed_genesis", 0), ("confirmed_conflict", 0)]), exp_chain_txouts: HashSet::from([("confirmed_genesis", 0), ("confirmed_conflict", 0)]),
exp_unspents: HashSet::from([("confirmed_conflict", 0)]), exp_unspents: HashSet::from([("confirmed_conflict", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 0, trusted_pending: Amount::ZERO,
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 20000, confirmed: Amount::from_sat(20000),
}, },
}, },
Scenario { Scenario {
@ -115,10 +115,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("tx1", 0), ("tx_conflict_2", 0)]), exp_chain_txouts: HashSet::from([("tx1", 0), ("tx_conflict_2", 0)]),
exp_unspents: HashSet::from([("tx_conflict_2", 0)]), exp_unspents: HashSet::from([("tx_conflict_2", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 30000, trusted_pending: Amount::from_sat(30000),
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 0, confirmed: Amount::ZERO,
}, },
}, },
Scenario { Scenario {
@ -150,10 +150,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("tx1", 0), ("tx1", 1), ("tx_conflict_2", 0)]), exp_chain_txouts: HashSet::from([("tx1", 0), ("tx1", 1), ("tx_conflict_2", 0)]),
exp_unspents: HashSet::from([("tx_conflict_2", 0)]), exp_unspents: HashSet::from([("tx_conflict_2", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 30000, trusted_pending: Amount::from_sat(30000),
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 0, confirmed: Amount::ZERO,
}, },
}, },
Scenario { Scenario {
@ -192,10 +192,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("tx1", 0), ("tx_conflict_3", 0)]), exp_chain_txouts: HashSet::from([("tx1", 0), ("tx_conflict_3", 0)]),
exp_unspents: HashSet::from([("tx_conflict_3", 0)]), exp_unspents: HashSet::from([("tx_conflict_3", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 40000, trusted_pending: Amount::from_sat(40000),
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 0, confirmed: Amount::ZERO,
}, },
}, },
Scenario { Scenario {
@ -227,10 +227,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("tx1", 0), ("tx_orphaned_conflict", 0)]), exp_chain_txouts: HashSet::from([("tx1", 0), ("tx_orphaned_conflict", 0)]),
exp_unspents: HashSet::from([("tx_orphaned_conflict", 0)]), exp_unspents: HashSet::from([("tx_orphaned_conflict", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 30000, trusted_pending: Amount::from_sat(30000),
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 0, confirmed: Amount::ZERO,
}, },
}, },
Scenario { Scenario {
@ -262,10 +262,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("tx1", 0), ("tx_conflict_1", 0)]), exp_chain_txouts: HashSet::from([("tx1", 0), ("tx_conflict_1", 0)]),
exp_unspents: HashSet::from([("tx_conflict_1", 0)]), exp_unspents: HashSet::from([("tx_conflict_1", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 20000, trusted_pending: Amount::from_sat(20000),
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 0, confirmed: Amount::ZERO,
}, },
}, },
Scenario { Scenario {
@ -311,10 +311,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("tx1", 0), ("tx_confirmed_conflict", 0)]), exp_chain_txouts: HashSet::from([("tx1", 0), ("tx_confirmed_conflict", 0)]),
exp_unspents: HashSet::from([("tx_confirmed_conflict", 0)]), exp_unspents: HashSet::from([("tx_confirmed_conflict", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 0, trusted_pending: Amount::ZERO,
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 50000, confirmed: Amount::from_sat(50000),
}, },
}, },
Scenario { Scenario {
@ -356,10 +356,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("A", 0), ("B", 0), ("C", 0)]), exp_chain_txouts: HashSet::from([("A", 0), ("B", 0), ("C", 0)]),
exp_unspents: HashSet::from([("C", 0)]), exp_unspents: HashSet::from([("C", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 30000, trusted_pending: Amount::from_sat(30000),
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 0, confirmed: Amount::ZERO,
}, },
}, },
Scenario { Scenario {
@ -397,10 +397,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("A", 0), ("B'", 0)]), exp_chain_txouts: HashSet::from([("A", 0), ("B'", 0)]),
exp_unspents: HashSet::from([("B'", 0)]), exp_unspents: HashSet::from([("B'", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 0, trusted_pending: Amount::ZERO,
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 20000, confirmed: Amount::from_sat(20000),
}, },
}, },
Scenario { Scenario {
@ -442,10 +442,10 @@ fn test_tx_conflict_handling() {
]), ]),
exp_unspents: HashSet::from([("C", 0)]), exp_unspents: HashSet::from([("C", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 30000, trusted_pending: Amount::from_sat(30000),
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 0, confirmed: Amount::ZERO,
}, },
}, },
Scenario { Scenario {
@ -487,10 +487,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("A", 0), ("B'", 0)]), exp_chain_txouts: HashSet::from([("A", 0), ("B'", 0)]),
exp_unspents: HashSet::from([("B'", 0)]), exp_unspents: HashSet::from([("B'", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 30000, trusted_pending: Amount::from_sat(30000),
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 0, confirmed: Amount::ZERO,
}, },
}, },
Scenario { Scenario {
@ -532,10 +532,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("A", 0), ("B'", 0)]), exp_chain_txouts: HashSet::from([("A", 0), ("B'", 0)]),
exp_unspents: HashSet::from([("B'", 0)]), exp_unspents: HashSet::from([("B'", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 0, trusted_pending: Amount::ZERO,
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 50000, confirmed: Amount::from_sat(50000),
}, },
}, },
Scenario { Scenario {
@ -583,10 +583,10 @@ fn test_tx_conflict_handling() {
exp_chain_txouts: HashSet::from([("A", 0), ("B'", 0)]), exp_chain_txouts: HashSet::from([("A", 0), ("B'", 0)]),
exp_unspents: HashSet::from([("B'", 0)]), exp_unspents: HashSet::from([("B'", 0)]),
exp_balance: Balance { exp_balance: Balance {
immature: 0, immature: Amount::ZERO,
trusted_pending: 0, trusted_pending: Amount::ZERO,
untrusted_pending: 0, untrusted_pending: Amount::ZERO,
confirmed: 50000, confirmed: Amount::from_sat(50000),
}, },
}, },
]; ];

View File

@ -76,7 +76,7 @@ fn scan_detects_confirmed_tx() -> Result<()> {
assert_eq!( assert_eq!(
get_balance(&recv_chain, &recv_graph)?, get_balance(&recv_chain, &recv_graph)?,
Balance { Balance {
confirmed: SEND_AMOUNT.to_sat(), confirmed: SEND_AMOUNT,
..Balance::default() ..Balance::default()
}, },
); );
@ -145,7 +145,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> Result<()> {
assert_eq!( assert_eq!(
get_balance(&recv_chain, &recv_graph)?, get_balance(&recv_chain, &recv_graph)?,
Balance { Balance {
confirmed: SEND_AMOUNT.to_sat() * REORG_COUNT as u64, confirmed: SEND_AMOUNT * REORG_COUNT as u64,
..Balance::default() ..Balance::default()
}, },
"initial balance must be correct", "initial balance must be correct",
@ -176,8 +176,8 @@ fn tx_can_become_unconfirmed_after_reorg() -> Result<()> {
assert_eq!( assert_eq!(
get_balance(&recv_chain, &recv_graph)?, get_balance(&recv_chain, &recv_graph)?,
Balance { Balance {
confirmed: SEND_AMOUNT.to_sat() * (REORG_COUNT - depth) as u64, confirmed: SEND_AMOUNT * (REORG_COUNT - depth) as u64,
trusted_pending: SEND_AMOUNT.to_sat() * depth as u64, trusted_pending: SEND_AMOUNT * depth as u64,
..Balance::default() ..Balance::default()
}, },
"reorg_count: {}", "reorg_count: {}",

View File

@ -506,11 +506,11 @@ where
let chain = &*chain.lock().unwrap(); let chain = &*chain.lock().unwrap();
fn print_balances<'a>( fn print_balances<'a>(
title_str: &'a str, title_str: &'a str,
items: impl IntoIterator<Item = (&'a str, u64)>, items: impl IntoIterator<Item = (&'a str, Amount)>,
) { ) {
println!("{}:", title_str); println!("{}:", title_str);
for (name, amount) in items.into_iter() { for (name, amount) in items.into_iter() {
println!(" {:<10} {:>12} sats", name, amount) println!(" {:<10} {:>12} sats", name, amount.to_sat())
} }
} }

View File

@ -1,12 +1,12 @@
const DB_MAGIC: &str = "bdk_wallet_electrum_example"; const DB_MAGIC: &str = "bdk_wallet_electrum_example";
const SEND_AMOUNT: u64 = 5000; const SEND_AMOUNT: Amount = Amount::from_sat(5000);
const STOP_GAP: usize = 50; const STOP_GAP: usize = 50;
const BATCH_SIZE: usize = 5; const BATCH_SIZE: usize = 5;
use std::io::Write; use std::io::Write;
use std::str::FromStr; use std::str::FromStr;
use bdk::bitcoin::Address; use bdk::bitcoin::{Address, Amount};
use bdk::wallet::Update; use bdk::wallet::Update;
use bdk::{bitcoin::Network, Wallet}; use bdk::{bitcoin::Network, Wallet};
use bdk::{KeychainKind, SignOptions}; use bdk::{KeychainKind, SignOptions};

View File

@ -1,14 +1,14 @@
use std::{collections::BTreeSet, io::Write, str::FromStr}; use std::{collections::BTreeSet, io::Write, str::FromStr};
use bdk::{ use bdk::{
bitcoin::{Address, Network, Script}, bitcoin::{Address, Amount, Network, Script},
KeychainKind, SignOptions, Wallet, KeychainKind, SignOptions, Wallet,
}; };
use bdk_esplora::{esplora_client, EsploraAsyncExt}; use bdk_esplora::{esplora_client, EsploraAsyncExt};
use bdk_file_store::Store; use bdk_file_store::Store;
const DB_MAGIC: &str = "bdk_wallet_esplora_async_example"; const DB_MAGIC: &str = "bdk_wallet_esplora_async_example";
const SEND_AMOUNT: u64 = 5000; const SEND_AMOUNT: Amount = Amount::from_sat(5000);
const STOP_GAP: usize = 50; const STOP_GAP: usize = 50;
const PARALLEL_REQUESTS: usize = 5; const PARALLEL_REQUESTS: usize = 5;

View File

@ -1,12 +1,12 @@
const DB_MAGIC: &str = "bdk_wallet_esplora_example"; const DB_MAGIC: &str = "bdk_wallet_esplora_example";
const SEND_AMOUNT: u64 = 1000; const SEND_AMOUNT: Amount = Amount::from_sat(1000);
const STOP_GAP: usize = 5; const STOP_GAP: usize = 5;
const PARALLEL_REQUESTS: usize = 1; const PARALLEL_REQUESTS: usize = 1;
use std::{collections::BTreeSet, io::Write, str::FromStr}; use std::{collections::BTreeSet, io::Write, str::FromStr};
use bdk::{ use bdk::{
bitcoin::{Address, Network}, bitcoin::{Address, Amount, Network},
KeychainKind, SignOptions, Wallet, KeychainKind, SignOptions, Wallet,
}; };
use bdk_esplora::{esplora_client, EsploraExt}; use bdk_esplora::{esplora_client, EsploraExt};