From 890d6191a1b61e6493a65ec8b9446bfddcfc747b Mon Sep 17 00:00:00 2001 From: LLFourn Date: Mon, 11 Jan 2021 14:14:14 +1100 Subject: [PATCH] Remove Option trickery from TxBuilder API see: https://github.com/bitcoindevkit/bdk/pull/258#issuecomment-754685962 --- README.md | 15 +- src/wallet/address_validator.rs | 8 +- src/wallet/coin_selection.rs | 9 +- src/wallet/mod.rs | 801 ++++++++++++++------------------ src/wallet/tx_builder.rs | 124 +++-- testutils-macros/src/lib.rs | 44 +- 6 files changed, 455 insertions(+), 546 deletions(-) diff --git a/README.md b/README.md index 716ad2d8..7a173658 100644 --- a/README.md +++ b/README.md @@ -108,12 +108,15 @@ fn main() -> Result<(), bdk::Error> { wallet.sync(noop_progress(), None)?; let send_to = wallet.get_new_address()?; - let (psbt, details) = wallet.build_tx() - .add_recipient(send_to.script_pubkey(), 50_000) - .enable_rbf() - .do_not_spend_change() - .fee_rate(FeeRate::from_sat_per_vb(5.0)) - .finish()?; + let (psbt, details) = { + let mut builder = wallet.build_tx(); + builder + .add_recipient(send_to.script_pubkey(), 50_000) + .enable_rbf() + .do_not_spend_change() + .fee_rate(FeeRate::from_sat_per_vb(5.0)); + builder.finish()? + }; println!("Transaction details: {:#?}", details); println!("Unsigned PSBT: {}", base64::encode(&serialize(&psbt))); diff --git a/src/wallet/address_validator.rs b/src/wallet/address_validator.rs index b77ec4aa..b84bee0c 100644 --- a/src/wallet/address_validator.rs +++ b/src/wallet/address_validator.rs @@ -156,10 +156,8 @@ mod test { wallet.add_address_validator(Arc::new(TestValidator)); let addr = testutils!(@external descriptors, 10); - wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 25_000) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 25_000); + builder.finish().unwrap(); } } diff --git a/src/wallet/coin_selection.rs b/src/wallet/coin_selection.rs index 71a56d8f..c57f251d 100644 --- a/src/wallet/coin_selection.rs +++ b/src/wallet/coin_selection.rs @@ -85,9 +85,12 @@ //! // create wallet, sync, ... //! //! let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); -//! let (psbt, details) = wallet.build_tx().coin_selection(AlwaysSpendEverything) -//! .add_recipient(to_address.script_pubkey(), 50_000) -//! .finish()?; +//! let (psbt, details) = { +//! let mut builder = wallet.build_tx().coin_selection(AlwaysSpendEverything); +//! builder +//! .add_recipient(to_address.script_pubkey(), 50_000); +//! builder.finish()? +//! }; //! //! // inspect, sign, broadcast, ... //! diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index ab73939b..ccebe4f7 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -268,9 +268,12 @@ where /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let wallet = doctest_wallet!(); /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); - /// let (psbt, details) = wallet.build_tx() - /// .add_recipient(to_address.script_pubkey(), 50_000) - /// .finish()?; + /// let (psbt, details) = { + /// let mut builder = wallet.build_tx(); + /// builder + /// .add_recipient(to_address.script_pubkey(), 50_000); + /// builder.finish()? + /// }; /// /// // sign and broadcast ... /// # Ok::<(), bdk::Error>(()) @@ -280,8 +283,8 @@ where pub fn build_tx(&self) -> TxBuilder<'_, B, D, DefaultCoinSelectionAlgorithm, CreateTx> { TxBuilder { wallet: &self, - params: Some(TxParams::default()), - coin_selection: Some(DefaultCoinSelectionAlgorithm::default()), + params: TxParams::default(), + coin_selection: DefaultCoinSelectionAlgorithm::default(), phantom: core::marker::PhantomData, } } @@ -621,16 +624,22 @@ where /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let wallet = doctest_wallet!(); /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); - /// let (psbt, _) = wallet.build_tx() - /// .add_recipient(to_address.script_pubkey(), 50_000) - /// .enable_rbf() - /// .finish()?; + /// let (psbt, _) = { + /// let mut builder = wallet.build_tx(); + /// builder + /// .add_recipient(to_address.script_pubkey(), 50_000) + /// .enable_rbf(); + /// builder.finish()? + /// }; /// let (psbt, _) = wallet.sign(psbt, None)?; /// let tx = psbt.extract_tx(); /// // broadcast tx but it's taking too long to confirm so we want to bump the fee - /// let (psbt, details) = wallet.build_fee_bump(tx.txid())? - /// .fee_rate(FeeRate::from_sat_per_vb(5.0)) - /// .finish()?; + /// let (psbt, _) = { + /// let mut builder = wallet.build_fee_bump(tx.txid())?; + /// builder + /// .fee_rate(FeeRate::from_sat_per_vb(5.0)); + /// builder.finish()? + /// }; /// /// let (psbt, _) = wallet.sign(psbt, None)?; /// let fee_bumped_tx = psbt.extract_tx(); @@ -738,8 +747,8 @@ where Ok(TxBuilder { wallet: &self, - params: Some(params), - coin_selection: Some(DefaultCoinSelectionAlgorithm::default()), + params, + coin_selection: DefaultCoinSelectionAlgorithm::default(), phantom: core::marker::PhantomData, }) } @@ -757,7 +766,11 @@ where /// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)"; /// # let wallet = doctest_wallet!(); /// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); - /// let (psbt, _) = wallet.build_tx().add_recipient(to_address.script_pubkey(), 50_000).finish()?; + /// let (psbt, _) = { + /// let mut builder = wallet.build_tx(); + /// builder.add_recipient(to_address.script_pubkey(), 50_000); + /// builder.finish()? + /// }; /// let (signed_psbt, finalized) = wallet.sign(psbt, None)?; /// assert!(finalized, "we should have signed all the inputs"); /// # Ok::<(), bdk::Error>(()) @@ -1527,12 +1540,11 @@ mod test { fn test_create_tx_manually_selected_empty_utxos() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .manually_selected_only() - .finish() - .unwrap(); + .manually_selected_only(); + builder.finish().unwrap(); } #[test] @@ -1540,12 +1552,11 @@ mod test { fn test_create_tx_version_0() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .version(0) - .finish() - .unwrap(); + .version(0); + builder.finish().unwrap(); } #[test] @@ -1555,24 +1566,22 @@ mod test { fn test_create_tx_version_1_csv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv()); let addr = wallet.get_new_address().unwrap(); - wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .version(1) - .finish() - .unwrap(); + .version(1); + builder.finish().unwrap(); } #[test] fn test_create_tx_custom_version() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .version(42) - .finish() - .unwrap(); + .version(42); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.version, 42); } @@ -1581,11 +1590,9 @@ mod test { fn test_create_tx_default_locktime() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 25_000) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 25_000); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.lock_time, 0); } @@ -1594,11 +1601,9 @@ mod test { fn test_create_tx_default_locktime_cltv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 25_000) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 25_000); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.lock_time, 100_000); } @@ -1607,12 +1612,11 @@ mod test { fn test_create_tx_custom_locktime() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .nlocktime(630_000) - .finish() - .unwrap(); + .nlocktime(630_000); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.lock_time, 630_000); } @@ -1621,12 +1625,11 @@ mod test { fn test_create_tx_custom_locktime_compatible_with_cltv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .nlocktime(630_000) - .finish() - .unwrap(); + .nlocktime(630_000); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.lock_time, 630_000); } @@ -1638,23 +1641,20 @@ mod test { fn test_create_tx_custom_locktime_incompatible_with_cltv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv()); let addr = wallet.get_new_address().unwrap(); - wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .nlocktime(50000) - .finish() - .unwrap(); + .nlocktime(50000); + builder.finish().unwrap(); } #[test] fn test_create_tx_no_rbf_csv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 25_000) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 25_000); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 6); } @@ -1663,12 +1663,11 @@ mod test { fn test_create_tx_with_default_rbf_csv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + 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.global.unsigned_tx.input[0].sequence, 6); @@ -1681,23 +1680,20 @@ mod test { fn test_create_tx_with_custom_rbf_csv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_csv()); let addr = wallet.get_new_address().unwrap(); - wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .enable_rbf_with_sequence(3) - .finish() - .unwrap(); + .enable_rbf_with_sequence(3); + builder.finish().unwrap(); } #[test] fn test_create_tx_no_rbf_cltv() { let (wallet, _, _) = get_funded_wallet(get_test_single_sig_cltv()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 25_000) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 25_000); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 0xFFFFFFFE); } @@ -1707,24 +1703,22 @@ mod test { fn test_create_tx_invalid_rbf_sequence() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .enable_rbf_with_sequence(0xFFFFFFFE) - .finish() - .unwrap(); + .enable_rbf_with_sequence(0xFFFFFFFE); + builder.finish().unwrap(); } #[test] fn test_create_tx_custom_rbf_sequence() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .enable_rbf_with_sequence(0xDEADBEEF) - .finish() - .unwrap(); + .enable_rbf_with_sequence(0xDEADBEEF); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 0xDEADBEEF); } @@ -1733,11 +1727,9 @@ mod test { fn test_create_tx_default_sequence() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 25_000) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 25_000); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 0xFFFFFFFF); } @@ -1749,24 +1741,22 @@ mod test { fn test_create_tx_change_policy_no_internal() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .do_not_spend_change() - .finish() - .unwrap(); + .do_not_spend_change(); + builder.finish().unwrap(); } #[test] fn test_create_tx_single_recipient_drain_wallet() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.output.len(), 1); assert_eq!( @@ -1779,11 +1769,9 @@ mod test { fn test_create_tx_default_fee_rate() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, details) = wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 25_000) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 25_000); + let (psbt, details) = builder.finish().unwrap(); assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::default(), @add_signature); } @@ -1792,12 +1780,11 @@ mod test { fn test_create_tx_custom_fee_rate() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .fee_rate(FeeRate::from_sat_per_vb(5.0)) - .finish() - .unwrap(); + .fee_rate(FeeRate::from_sat_per_vb(5.0)); + let (psbt, details) = builder.finish().unwrap(); assert_fee_rate!(psbt.extract_tx(), details.fees, FeeRate::from_sat_per_vb(5.0), @add_signature); } @@ -1806,13 +1793,12 @@ mod test { fn test_create_tx_absolute_fee() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) .drain_wallet() - .fee_absolute(100) - .finish() - .unwrap(); + .fee_absolute(100); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(details.fees, 100); assert_eq!(psbt.global.unsigned_tx.output.len(), 1); @@ -1826,13 +1812,12 @@ mod test { fn test_create_tx_absolute_zero_fee() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) .drain_wallet() - .fee_absolute(0) - .finish() - .unwrap(); + .fee_absolute(0); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(details.fees, 0); assert_eq!(psbt.global.unsigned_tx.output.len(), 1); @@ -1847,13 +1832,12 @@ mod test { fn test_create_tx_absolute_high_fee() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (_psbt, _details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) .drain_wallet() - .fee_absolute(60_000) - .finish() - .unwrap(); + .fee_absolute(60_000); + let (_psbt, _details) = builder.finish().unwrap(); } #[test] @@ -1862,12 +1846,11 @@ mod test { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .ordering(TxOrdering::Untouched) - .finish() - .unwrap(); + .ordering(TxOrdering::Untouched); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.output.len(), 2); assert_eq!(psbt.global.unsigned_tx.output[0].value, 25_000); @@ -1881,11 +1864,9 @@ mod test { fn test_create_tx_skip_change_dust() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, details) = wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 49_800) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 49_800); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.output.len(), 1); assert_eq!(psbt.global.unsigned_tx.output[0].value, 49_800); @@ -1898,26 +1879,24 @@ mod test { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); // very high fee rate, so that the only output would be below dust - wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) .drain_wallet() - .fee_rate(FeeRate::from_sat_per_vb(453.0)) - .finish() - .unwrap(); + .fee_rate(FeeRate::from_sat_per_vb(453.0)); + builder.finish().unwrap(); } #[test] fn test_create_tx_ordering_respected() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 30_000) .add_recipient(addr.script_pubkey(), 10_000) - .ordering(super::tx_builder::TxOrdering::BIP69Lexicographic) - .finish() - .unwrap(); + .ordering(super::tx_builder::TxOrdering::BIP69Lexicographic); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.output.len(), 3); assert_eq!( @@ -1932,11 +1911,9 @@ mod test { fn test_create_tx_default_sighash() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 30_000) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 30_000); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.inputs[0].sighash_type, None); } @@ -1945,12 +1922,11 @@ mod test { fn test_create_tx_custom_sighash() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 30_000) - .sighash(bitcoin::SigHashType::Single) - .finish() - .unwrap(); + .sighash(bitcoin::SigHashType::Single); + let (psbt, _) = builder.finish().unwrap(); assert_eq!( psbt.inputs[0].sighash_type, @@ -1965,12 +1941,11 @@ mod test { let (wallet, _, _) = get_funded_wallet("wpkh([d34db33f/44'/0'/0']tpubDEnoLuPdBep9bzw5LoGYpsxUQYheRQ9gcgrJhJEcdKFB9cWQRyYmkCyRoTqeD4tJYiVVgt6A3rN6rWn9RYhR9sBsGxji29LYWHuKKbdb1ev/0/*)"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.inputs[0].hd_keypaths.len(), 1); assert_eq!( @@ -1992,12 +1967,11 @@ mod test { wallet.get_new_address().unwrap(); let addr = testutils!(@external descriptors, 5); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.outputs[0].hd_keypaths.len(), 1); assert_eq!( @@ -2016,12 +1990,11 @@ mod test { let (wallet, _, _) = get_funded_wallet("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); assert_eq!( psbt.inputs[0].redeem_script, @@ -2042,12 +2015,11 @@ mod test { let (wallet, _, _) = get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.inputs[0].redeem_script, None); assert_eq!( @@ -2068,12 +2040,11 @@ mod test { let (wallet, _, _) = get_funded_wallet("sh(wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)))"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); let script = Script::from( Vec::::from_hex( @@ -2091,12 +2062,11 @@ mod test { let (wallet, _, _) = get_funded_wallet("sh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); assert!(psbt.inputs[0].non_witness_utxo.is_some()); assert!(psbt.inputs[0].witness_utxo.is_none()); @@ -2107,12 +2077,11 @@ mod test { let (wallet, _, _) = get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); assert!(psbt.inputs[0].non_witness_utxo.is_none()); assert!(psbt.inputs[0].witness_utxo.is_some()); @@ -2123,12 +2092,11 @@ mod test { let (wallet, _, _) = get_funded_wallet("sh(wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); assert!(psbt.inputs[0].non_witness_utxo.is_none()); assert!(psbt.inputs[0].witness_utxo.is_some()); @@ -2139,13 +2107,12 @@ mod test { let (wallet, _, _) = get_funded_wallet("wsh(pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW))"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) .drain_wallet() - .force_non_witness_utxo() - .finish() - .unwrap(); + .force_non_witness_utxo(); + let (psbt, _) = builder.finish().unwrap(); assert!(psbt.inputs[0].non_witness_utxo.is_some()); assert!(psbt.inputs[0].witness_utxo.is_some()); @@ -2161,16 +2128,15 @@ mod test { ); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 30_000) .add_utxo(OutPoint { txid: small_output_txid, vout: 0, }) - .unwrap() - .finish() .unwrap(); + let (psbt, details) = builder.finish().unwrap(); assert_eq!( psbt.global.unsigned_tx.input.len(), @@ -2191,17 +2157,16 @@ mod test { ); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 30_000) .add_utxo(OutPoint { txid: small_output_txid, vout: 0, }) .unwrap() - .manually_selected_only() - .finish() - .unwrap(); + .manually_selected_only(); + builder.finish().unwrap(); } #[test] @@ -2210,11 +2175,9 @@ mod test { let (wallet, _, _) = get_funded_wallet(get_test_a_or_b_plus_csv()); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 30_000) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 30_000); + builder.finish().unwrap(); } #[test] @@ -2227,12 +2190,11 @@ mod test { let path = vec![(root_id, vec![0])].into_iter().collect(); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 30_000) - .policy_path(path, KeychainKind::External) - .finish() - .unwrap(); + .policy_path(path, KeychainKind::External); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 0xFFFFFFFF); } @@ -2247,12 +2209,11 @@ mod test { let path = vec![(root_id, vec![1])].into_iter().collect(); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 30_000) - .policy_path(path, KeychainKind::External) - .finish() - .unwrap(); + .policy_path(path, KeychainKind::External); + let (psbt, _) = builder.finish().unwrap(); assert_eq!(psbt.global.unsigned_tx.input[0].sequence, 144); } @@ -2265,12 +2226,11 @@ mod test { let (wallet, _, _) = get_funded_wallet("wpkh([73756c7f/48'/0'/0'/2']tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .add_global_xpubs() - .finish() - .unwrap(); + .add_global_xpubs(); + let (psbt, _) = builder.finish().unwrap(); let type_value = 0x01; let key = base58::from_check("tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3").unwrap(); @@ -2291,12 +2251,11 @@ mod test { fn test_create_tx_global_xpubs_origin_missing() { let (wallet, _, _) = get_funded_wallet("wpkh(tpubDCKxNyM3bLgbEX13Mcd8mYxbVg9ajDkWXMh29hMWBurKfVmBfWAM96QVP3zaUcN51HvkZ3ar4VwP82kC8JZhhux8vFQoJintSpVBwpFvyU3/0/*)"); let addr = wallet.get_new_address().unwrap(); - wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .add_global_xpubs() - .finish() - .unwrap(); + .add_global_xpubs(); + builder.finish().unwrap(); } #[test] @@ -2307,12 +2266,11 @@ mod test { let (wallet, _, _) = get_funded_wallet("wpkh(tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL/0/*)"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .add_global_xpubs() - .finish() - .unwrap(); + .add_global_xpubs(); + let (psbt, _) = builder.finish().unwrap(); let type_value = 0x01; let key = base58::from_check("tpubD6NzVbkrYhZ4Y55A58Gv9RSNF5hy84b5AJqYy7sCcjFrkcLpPre8kmgfit6kY1Zs3BLgeypTDBZJM222guPpdz7Cup5yzaMu62u7mYGbwFL").unwrap(); @@ -2332,11 +2290,9 @@ mod test { fn test_bump_fee_irreplaceable_tx() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, mut details) = wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 25_000) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 25_000); + let (psbt, mut details) = builder.finish().unwrap(); let tx = psbt.extract_tx(); let txid = tx.txid(); @@ -2352,11 +2308,9 @@ mod test { fn test_bump_fee_confirmed_tx() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, mut details) = wallet - .build_tx() - .add_recipient(addr.script_pubkey(), 25_000) - .finish() - .unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(addr.script_pubkey(), 25_000); + let (psbt, mut details) = builder.finish().unwrap(); let tx = psbt.extract_tx(); let txid = tx.txid(); @@ -2373,12 +2327,11 @@ mod test { fn test_bump_fee_low_fee_rate() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, mut details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut details) = builder.finish().unwrap(); let tx = psbt.extract_tx(); let txid = tx.txid(); @@ -2386,12 +2339,9 @@ mod test { details.transaction = Some(tx); wallet.database.borrow_mut().set_tx(&details).unwrap(); - wallet - .build_fee_bump(txid) - .unwrap() - .fee_rate(FeeRate::from_sat_per_vb(1.0)) - .finish() - .unwrap(); + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder.fee_rate(FeeRate::from_sat_per_vb(1.0)); + builder.finish().unwrap(); } #[test] @@ -2399,12 +2349,11 @@ mod test { fn test_bump_fee_low_abs() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, mut details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut details) = builder.finish().unwrap(); let tx = psbt.extract_tx(); let txid = tx.txid(); @@ -2412,12 +2361,9 @@ mod test { details.transaction = Some(tx); wallet.database.borrow_mut().set_tx(&details).unwrap(); - wallet - .build_fee_bump(txid) - .unwrap() - .fee_absolute(10) - .finish() - .unwrap(); + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder.fee_absolute(10); + builder.finish().unwrap(); } #[test] @@ -2425,12 +2371,11 @@ mod test { fn test_bump_fee_zero_abs() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = wallet.get_new_address().unwrap(); - let (psbt, mut details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut details) = builder.finish().unwrap(); let tx = psbt.extract_tx(); let txid = tx.txid(); @@ -2438,24 +2383,20 @@ mod test { details.transaction = Some(tx); wallet.database.borrow_mut().set_tx(&details).unwrap(); - wallet - .build_fee_bump(txid) - .unwrap() - .fee_absolute(0) - .finish() - .unwrap(); + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder.fee_absolute(0); + builder.finish().unwrap(); } #[test] fn test_bump_fee_reduce_change() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); // skip saving the new utxos, we know they can't be used anyways @@ -2474,12 +2415,9 @@ mod test { .set_tx(&original_details) .unwrap(); - let (psbt, details) = wallet - .build_fee_bump(txid) - .unwrap() - .fee_rate(FeeRate::from_sat_per_vb(2.5)) - .finish() - .unwrap(); + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder.fee_rate(FeeRate::from_sat_per_vb(2.5)); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(details.sent, original_details.sent); assert_eq!( @@ -2514,12 +2452,11 @@ mod test { fn test_bump_fee_absolute_reduce_change() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 25_000) - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); // skip saving the new utxos, we know they can't be used anyways @@ -2538,12 +2475,9 @@ mod test { .set_tx(&original_details) .unwrap(); - let (psbt, details) = wallet - .build_fee_bump(txid) - .unwrap() - .fee_absolute(200) - .finish() - .unwrap(); + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder.fee_absolute(200); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(details.sent, original_details.sent); assert_eq!( @@ -2583,13 +2517,12 @@ mod test { fn test_bump_fee_reduce_single_recipient() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) .drain_wallet() - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); for txin in &mut tx.input { @@ -2607,13 +2540,11 @@ mod test { .set_tx(&original_details) .unwrap(); - let (psbt, details) = wallet - .build_fee_bump(txid) - .unwrap() + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder .fee_rate(FeeRate::from_sat_per_vb(2.5)) - .maintain_single_recipient() - .finish() - .unwrap(); + .maintain_single_recipient(); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(details.sent, original_details.sent); assert!(details.fees > original_details.fees); @@ -2629,13 +2560,12 @@ mod test { fn test_bump_fee_absolute_reduce_single_recipient() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) .drain_wallet() - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); for txin in &mut tx.input { @@ -2653,13 +2583,9 @@ mod test { .set_tx(&original_details) .unwrap(); - let (psbt, details) = wallet - .build_fee_bump(txid) - .unwrap() - .maintain_single_recipient() - .fee_absolute(300) - .finish() - .unwrap(); + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder.maintain_single_recipient().fee_absolute(300); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(details.sent, original_details.sent); assert!(details.fees > original_details.fees); @@ -2685,15 +2611,14 @@ mod test { vout: 0, }; let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) .add_utxo(outpoint) .unwrap() .manually_selected_only() - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); for txin in &mut tx.input { @@ -2714,14 +2639,12 @@ mod test { // for the new feerate, it should be enough to reduce the output, but since we specify // `drain_wallet` we expect to spend everything - let (_, details) = wallet - .build_fee_bump(txid) - .unwrap() + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder .drain_wallet() .maintain_single_recipient() - .fee_rate(FeeRate::from_sat_per_vb(5.0)) - .finish() - .unwrap(); + .fee_rate(FeeRate::from_sat_per_vb(5.0)); + let (_, details) = builder.finish().unwrap(); assert_eq!(details.sent, 75_000); } @@ -2743,15 +2666,14 @@ mod test { vout: 0, }; let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) .add_utxo(outpoint) .unwrap() .manually_selected_only() - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); for txin in &mut tx.input { @@ -2770,15 +2692,13 @@ mod test { .unwrap(); assert_eq!(original_details.sent, 25_000); - wallet - .build_fee_bump(txid) - .unwrap() + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder .add_utxo(outpoint) .unwrap() .manually_selected_only() - .fee_rate(FeeRate::from_sat_per_vb(255.0)) - .finish() - .unwrap(); + .fee_rate(FeeRate::from_sat_per_vb(255.0)); + builder.finish().unwrap(); } #[test] @@ -2791,12 +2711,11 @@ mod test { ); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 45_000) - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); // skip saving the new utxos, we know they can't be used anyways @@ -2815,12 +2734,9 @@ mod test { .set_tx(&original_details) .unwrap(); - let (psbt, details) = wallet - .build_fee_bump(txid) - .unwrap() - .fee_rate(FeeRate::from_sat_per_vb(50.0)) - .finish() - .unwrap(); + 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(); assert_eq!(details.sent, original_details.sent + 25_000); assert_eq!(details.fees + details.received, 30_000); @@ -2858,12 +2774,11 @@ mod test { ); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 45_000) - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); // skip saving the new utxos, we know they can't be used anyways @@ -2882,12 +2797,9 @@ mod test { .set_tx(&original_details) .unwrap(); - let (psbt, details) = wallet - .build_fee_bump(txid) - .unwrap() - .fee_absolute(6_000) - .finish() - .unwrap(); + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder.fee_absolute(6_000); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(details.sent, original_details.sent + 25_000); assert_eq!(details.fees + details.received, 30_000); @@ -2926,8 +2838,8 @@ mod test { // initially make a tx without change by using `set_single_recipient` let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) .add_utxo(OutPoint { txid: incoming_txid, @@ -2935,9 +2847,8 @@ mod test { }) .unwrap() .manually_selected_only() - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); @@ -2959,12 +2870,9 @@ mod test { // now bump the fees without using `maintain_single_recipient`. the wallet should add an // extra input and a change output, and leave the original output untouched - let (psbt, details) = wallet - .build_fee_bump(txid) - .unwrap() - .fee_rate(FeeRate::from_sat_per_vb(50.0)) - .finish() - .unwrap(); + 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 original_send_all_amount = original_details.sent - original_details.fees; assert_eq!(details.sent, original_details.sent + 50_000); @@ -3006,12 +2914,11 @@ mod test { ); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 45_000) - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); assert_eq!(tx.input.len(), 1); assert_eq!(tx.output.len(), 2); @@ -3032,12 +2939,9 @@ mod test { .set_tx(&original_details) .unwrap(); - let (psbt, details) = wallet - .build_fee_bump(txid) - .unwrap() - .fee_rate(FeeRate::from_sat_per_vb(140.0)) - .finish() - .unwrap(); + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder.fee_rate(FeeRate::from_sat_per_vb(140.0)); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(original_details.received, 5_000 - original_details.fees); @@ -3070,12 +2974,11 @@ mod test { ); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 45_000) - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); // skip saving the new utxos, we know they can't be used anyways @@ -3096,17 +2999,15 @@ mod test { // the new fee_rate is low enough that just reducing the change would be fine, but we force // the addition of an extra input with `add_utxo()` - let (psbt, details) = wallet - .build_fee_bump(txid) - .unwrap() + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder .add_utxo(OutPoint { txid: incoming_txid, vout: 0, }) .unwrap() - .fee_rate(FeeRate::from_sat_per_vb(5.0)) - .finish() - .unwrap(); + .fee_rate(FeeRate::from_sat_per_vb(5.0)); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(details.sent, original_details.sent + 25_000); assert_eq!(details.fees + details.received, 30_000); @@ -3144,12 +3045,11 @@ mod test { ); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, mut original_details) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 45_000) - .enable_rbf() - .finish() - .unwrap(); + .enable_rbf(); + let (psbt, mut original_details) = builder.finish().unwrap(); let mut tx = psbt.extract_tx(); let txid = tx.txid(); // skip saving the new utxos, we know they can't be used anyways @@ -3170,17 +3070,15 @@ mod test { // the new fee_rate is low enough that just reducing the change would be fine, but we force // the addition of an extra input with `add_utxo()` - let (psbt, details) = wallet - .build_fee_bump(txid) - .unwrap() + let mut builder = wallet.build_fee_bump(txid).unwrap(); + builder .add_utxo(OutPoint { txid: incoming_txid, vout: 0, }) .unwrap() - .fee_absolute(250) - .finish() - .unwrap(); + .fee_absolute(250); + let (psbt, details) = builder.finish().unwrap(); assert_eq!(details.sent, original_details.sent + 25_000); assert_eq!(details.fees + details.received, 30_000); @@ -3212,12 +3110,11 @@ mod test { fn test_sign_single_xprv() { let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); let (signed_psbt, finalized) = wallet.sign(psbt, None).unwrap(); assert_eq!(finalized, true); @@ -3230,12 +3127,11 @@ mod test { fn test_sign_single_xprv_bip44_path() { let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/44'/0'/0'/0/*)"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); let (signed_psbt, finalized) = wallet.sign(psbt, None).unwrap(); assert_eq!(finalized, true); @@ -3248,12 +3144,11 @@ mod test { fn test_sign_single_xprv_sh_wpkh() { let (wallet, _, _) = get_funded_wallet("sh(wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*))"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); let (signed_psbt, finalized) = wallet.sign(psbt, None).unwrap(); assert_eq!(finalized, true); @@ -3267,12 +3162,11 @@ mod test { let (wallet, _, _) = get_funded_wallet("wpkh(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW)"); let addr = wallet.get_new_address().unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (psbt, _) = builder.finish().unwrap(); let (signed_psbt, finalized) = wallet.sign(psbt, None).unwrap(); assert_eq!(finalized, true); @@ -3285,12 +3179,11 @@ mod test { fn test_sign_single_xprv_no_hd_keypaths() { let (wallet, _, _) = get_funded_wallet("wpkh(tprv8ZgxMBicQKsPd3EupYiPRhaMooHKUHJxNsTfYuScep13go8QFfHdtkG9nRkFGb7busX4isf6X9dURGCoKgitaApQ6MupRhZMcELAxTBRJgS/*)"); let addr = wallet.get_new_address().unwrap(); - let (mut psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .set_single_recipient(addr.script_pubkey()) - .drain_wallet() - .finish() - .unwrap(); + .drain_wallet(); + let (mut psbt, _) = builder.finish().unwrap(); psbt.inputs[0].hd_keypaths.clear(); assert_eq!(psbt.inputs[0].hd_keypaths.len(), 0); @@ -3306,12 +3199,11 @@ mod test { fn test_include_output_redeem_witness_script() { let (wallet, _, _) = get_funded_wallet("sh(wsh(multi(1,cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW,cRjo6jqfVNP33HhSS76UhXETZsGTZYx8FMFvR9kpbtCSV1PmdZdu)))"); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 45_000) - .include_output_redeem_witness_script() - .finish() - .unwrap(); + .include_output_redeem_witness_script(); + let (psbt, _) = builder.finish().unwrap(); // p2sh-p2wsh transaction should contain both witness and redeem scripts assert!(psbt @@ -3324,12 +3216,11 @@ mod test { fn test_signing_only_one_of_multiple_inputs() { let (wallet, _, _) = get_funded_wallet(get_test_wpkh()); let addr = Address::from_str("2N1Ffz3WaNzbeLFBb51xyFMHYSEUXcbiSoX").unwrap(); - let (mut psbt, _) = wallet - .build_tx() + let mut builder = wallet.build_tx(); + builder .add_recipient(addr.script_pubkey(), 45_000) - .include_output_redeem_witness_script() - .finish() - .unwrap(); + .include_output_redeem_witness_script(); + let (mut psbt, _) = builder.finish().unwrap(); // add another input to the psbt that is at least passable. let mut dud_input = bitcoin::util::psbt::Input::default(); diff --git a/src/wallet/tx_builder.rs b/src/wallet/tx_builder.rs index a9ed5d8b..fce15827 100644 --- a/src/wallet/tx_builder.rs +++ b/src/wallet/tx_builder.rs @@ -36,7 +36,7 @@ //! // create a TxBuilder from a wallet //! let mut tx_builder = wallet.build_tx(); //! -//! let (psbt, tx_details) = tx_builder +//! tx_builder //! // Create a transaction with one output to `to_address` of 50_000 satoshi //! .add_recipient(to_address.script_pubkey(), 50_000) //! // With a custom fee rate of 5.0 satoshi/vbyte @@ -44,9 +44,8 @@ //! // Only spend non-change outputs //! .do_not_spend_change() //! // Turn on RBF signaling -//! .enable_rbf() -//! .finish()?; -//! +//! .enable_rbf(); +//! let (psbt, tx_details) = tx_builder.finish()?; //! # Ok::<(), bdk::Error>(()) //! ``` @@ -80,11 +79,12 @@ impl TxBuilderContext for BumpFee {} /// A transaction builder /// -/// A `TxBuilder` is initially created by calling [`build_tx`] or [`build_fee_bump`] on a wallet. -/// From there you set sepcific options on the builder until finally calling [`finish`] to get the transaction. +/// A `TxBuilder` is created by calling [`build_tx`] or [`build_fee_bump`] on a wallet. After +/// assigning it, you set options on it until finally calling [`finish`] to consume the builder and +/// generate the transaction. /// -/// Each method on TxBuilder takes and returns `&mut self` so you can use either use a chaining call -/// or assign the builder and call normally as in the following example: +/// Each option setting method on `TxBuilder` takes and returns `&mut self` so you can chain calls +/// as in the following example: /// /// ``` /// # use bdk::*; @@ -95,27 +95,31 @@ impl TxBuilderContext for BumpFee {} /// # let addr1 = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); /// # let addr2 = addr1.clone(); /// // chaining -/// let (psbt1, details) = wallet.build_tx() +/// let (psbt1, details) = { +/// let mut builder = wallet.build_tx(); +/// builder /// .ordering(TxOrdering::Untouched) /// .add_recipient(addr1.script_pubkey(), 50_000) -/// .add_recipient(addr2.script_pubkey(), 50_000) -/// .finish()?; +/// .add_recipient(addr2.script_pubkey(), 50_000); +/// builder.finish()? +/// }; /// /// // non-chaining -/// let mut builder = wallet.build_tx(); -/// for addr in &[addr1, addr2] { -/// builder.add_recipient(addr.script_pubkey(), 50_000); -/// } -/// let (psbt2, details) = builder.ordering(TxOrdering::Untouched).finish()?; -/// // +/// let (psbt2, details) = { +/// let mut builder = wallet.build_tx(); +/// builder.ordering(TxOrdering::Untouched); +/// for addr in &[addr1, addr2] { +/// builder.add_recipient(addr.script_pubkey(), 50_000); +/// } +/// builder.finish()? +/// }; +/// /// assert_eq!(psbt1.global.unsigned_tx.output[..2], psbt2.global.unsigned_tx.output[..2]); /// # Ok::<(), bdk::Error>(()) /// ``` /// -/// At the moment [`coin_selection`] is an exception - it consumes `self`. -/// This means it is usually best to call [`coin_selection`] first before calling other methods. -/// -/// Note that calling methods on the builder after calling [`finish`] will result in a panic. +/// At the moment [`coin_selection`] is an exception to the rule as it consumes `self`. +/// This means it is usually best to call [`coin_selection`] on the return value of `build_tx` before assigning it. /// /// For further examples see [this module](super::tx_builder)'s documentation; /// @@ -128,8 +132,8 @@ pub struct TxBuilder<'a, B, D, Cs, Ctx> { // params and coin_selection are Options not becasue they are optionally set (they are always // there) but because `.finish()` uses `Option::take` to get an owned value from a &mut self. // They are only `None` after `.finish()` is called. - pub(crate) params: Option, - pub(crate) coin_selection: Option, + pub(crate) params: TxParams, + pub(crate) coin_selection: Cs, pub(crate) phantom: PhantomData, } @@ -180,20 +184,15 @@ impl std::default::Default for FeePolicy { impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderContext> TxBuilder<'a, B, D, Cs, Ctx> { - fn params(&mut self) -> &mut TxParams { - self.params - .as_mut() - .expect("method called on transaction builder after it was finalized") - } /// Set a custom fee rate pub fn fee_rate(&mut self, fee_rate: FeeRate) -> &mut Self { - self.params().fee_policy = Some(FeePolicy::FeeRate(fee_rate)); + self.params.fee_policy = Some(FeePolicy::FeeRate(fee_rate)); self } /// Set an absolute fee pub fn fee_absolute(&mut self, fee_amount: u64) -> &mut Self { - self.params().fee_policy = Some(FeePolicy::FeeAmount(fee_amount)); + self.params.fee_policy = Some(FeePolicy::FeeAmount(fee_amount)); self } @@ -261,8 +260,8 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte keychain: KeychainKind, ) -> &mut Self { let to_update = match keychain { - KeychainKind::Internal => &mut self.params().internal_policy_path, - KeychainKind::External => &mut self.params().external_policy_path, + KeychainKind::Internal => &mut self.params.internal_policy_path, + KeychainKind::External => &mut self.params.external_policy_path, }; *to_update = Some(policy_path); @@ -274,12 +273,12 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// These have priority over the "unspendable" utxos, meaning that if a utxo is present both in /// the "utxos" and the "unspendable" list, it will be spent. pub fn add_utxo(&mut self, outpoint: OutPoint) -> Result<&mut Self, Error> { - if self.params().utxos.get(&outpoint).is_none() { + if self.params.utxos.get(&outpoint).is_none() { let deriv_ctx = crate::wallet::descriptor_to_pk_ctx(self.wallet.secp_ctx()); let utxo = self.wallet.get_utxo(outpoint)?.ok_or(Error::UnknownUTXO)?; let descriptor = self.wallet.get_descriptor_for_keychain(utxo.keychain); let satisfaction_weight = descriptor.max_satisfaction_weight(deriv_ctx).unwrap(); - self.params() + self.params .utxos .insert(outpoint, (utxo, satisfaction_weight)); } @@ -293,7 +292,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// /// [`add_utxo`]: Self::add_utxo pub fn manually_selected_only(&mut self) -> &mut Self { - self.params().manually_selected_only = true; + self.params.manually_selected_only = true; self } @@ -302,7 +301,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// It's important to note that the "must-be-spent" utxos added with [`TxBuilder::add_utxo`] /// have priority over these. See the docs of the two linked methods for more details. pub fn unspendable(&mut self, unspendable: Vec) -> &mut Self { - self.params().unspendable = unspendable.into_iter().collect(); + self.params.unspendable = unspendable.into_iter().collect(); self } @@ -311,7 +310,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// It's important to note that the "must-be-spent" utxos added with [`TxBuilder::add_utxo`] /// have priority over this. See the docs of the two linked methods for more details. pub fn add_unspendable(&mut self, unspendable: OutPoint) -> &mut Self { - self.params().unspendable.insert(unspendable); + self.params.unspendable.insert(unspendable); self } @@ -319,13 +318,13 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// /// **Use this option very carefully** pub fn sighash(&mut self, sighash: SigHashType) -> &mut Self { - self.params().sighash = Some(sighash); + self.params.sighash = Some(sighash); self } /// Choose the ordering for inputs and outputs of the transaction pub fn ordering(&mut self, ordering: TxOrdering) -> &mut Self { - self.params().ordering = ordering; + self.params.ordering = ordering; self } @@ -333,7 +332,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// /// This can cause conflicts if the wallet's descriptors contain an "after" (OP_CLTV) operator. pub fn nlocktime(&mut self, locktime: u32) -> &mut Self { - self.params().locktime = Some(locktime); + self.params.locktime = Some(locktime); self } @@ -342,7 +341,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// The `version` should always be greater than `0` and greater than `1` if the wallet's /// descriptors contain an "older" (OP_CSV) operator. pub fn version(&mut self, version: i32) -> &mut Self { - self.params().version = Some(Version(version)); + self.params.version = Some(Version(version)); self } @@ -351,7 +350,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// This effectively adds all the change outputs to the "unspendable" list. See /// [`TxBuilder::unspendable`]. pub fn do_not_spend_change(&mut self) -> &mut Self { - self.params().change_policy = ChangeSpendPolicy::ChangeForbidden; + self.params.change_policy = ChangeSpendPolicy::ChangeForbidden; self } @@ -360,14 +359,14 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// This effectively adds all the non-change outputs to the "unspendable" list. See /// [`TxBuilder::unspendable`]. pub fn only_spend_change(&mut self) -> &mut Self { - self.params().change_policy = ChangeSpendPolicy::OnlyChange; + self.params.change_policy = ChangeSpendPolicy::OnlyChange; self } /// Set a specific [`ChangeSpendPolicy`]. See [`TxBuilder::do_not_spend_change`] and /// [`TxBuilder::only_spend_change`] for some shortcuts. pub fn change_policy(&mut self, change_policy: ChangeSpendPolicy) -> &mut Self { - self.params().change_policy = change_policy; + self.params.change_policy = change_policy; self } @@ -376,7 +375,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// /// This is useful for signers which always require it, like Trezor hardware wallets. pub fn force_non_witness_utxo(&mut self) -> &mut Self { - self.params().force_non_witness_utxo = true; + self.params.force_non_witness_utxo = true; self } @@ -385,7 +384,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// /// This is useful for signers which always require it, like ColdCard hardware wallets. pub fn include_output_redeem_witness_script(&mut self) -> &mut Self { - self.params().include_output_redeem_witness_script = true; + self.params.include_output_redeem_witness_script = true; self } @@ -395,13 +394,13 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// This is useful for offline signers that take part to a multisig. Some hardware wallets like /// BitBox and ColdCard are known to require this. pub fn add_global_xpubs(&mut self) -> &mut Self { - self.params().add_global_xpubs = true; + self.params.add_global_xpubs = true; self } /// Spend all the available inputs. This respects filters like [`TxBuilder::unspendable`] and the change policy. pub fn drain_wallet(&mut self) -> &mut Self { - self.params().drain_wallet = true; + self.params.drain_wallet = true; self } @@ -414,14 +413,10 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte self, coin_selection: P, ) -> TxBuilder<'a, B, D, P, Ctx> { - assert!( - self.coin_selection.is_some(), - "can't set coin_selection after finish() has been called" - ); TxBuilder { wallet: self.wallet, params: self.params, - coin_selection: Some(coin_selection), + coin_selection, phantom: PhantomData, } } @@ -431,24 +426,21 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderConte /// Returns the [`BIP174`] "PSBT" and summary details about the transaction. /// /// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki - pub fn finish(&mut self) -> Result<(PSBT, TransactionDetails), Error> { - self.wallet.create_tx( - self.coin_selection.take().unwrap(), - self.params.take().unwrap(), - ) + pub fn finish(self) -> Result<(PSBT, TransactionDetails), Error> { + self.wallet.create_tx(self.coin_selection, self.params) } } impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm> TxBuilder<'a, B, D, Cs, CreateTx> { /// Replace the recipients already added with a new list pub fn set_recipients(&mut self, recipients: Vec<(Script, u64)>) -> &mut Self { - self.params().recipients = recipients; + self.params.recipients = recipients; self } /// Add a recipient to the internal list pub fn add_recipient(&mut self, script_pubkey: Script, amount: u64) -> &mut Self { - self.params().recipients.push((script_pubkey, amount)); + self.params.recipients.push((script_pubkey, amount)); self } @@ -467,8 +459,8 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm> TxBuilder<'a, B, D, /// add [`maintain_single_recipient`](Self::maintain_single_recipient) to correctly update the /// single output instead of adding one more for the change. pub fn set_single_recipient(&mut self, recipient: Script) -> &mut Self { - self.params().single_recipient = Some(recipient); - self.params().recipients.clear(); + self.params.single_recipient = Some(recipient); + self.params.recipients.clear(); self } @@ -477,7 +469,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm> TxBuilder<'a, B, D, /// /// This will use the default nSequence value of `0xFFFFFFFD`. pub fn enable_rbf(&mut self) -> &mut Self { - self.params().rbf = Some(RBFValue::Default); + self.params.rbf = Some(RBFValue::Default); self } @@ -489,7 +481,7 @@ impl<'a, B, D: BatchDatabase, Cs: CoinSelectionAlgorithm> TxBuilder<'a, B, D, /// If the `nsequence` is higher than `0xFFFFFFFD` an error will be thrown, since it would not /// be a valid nSequence to signal RBF. pub fn enable_rbf_with_sequence(&mut self, nsequence: u32) -> &mut Self { - self.params().rbf = Some(RBFValue::Value(nsequence)); + self.params.rbf = Some(RBFValue::Value(nsequence)); self } } @@ -509,9 +501,9 @@ impl<'a, B, D: BatchDatabase> TxBuilder<'a, B, D, DefaultCoinSelectionAlgorithm, /// /// [`add_utxo`]: Self::add_utxo pub fn maintain_single_recipient(&mut self) -> &mut Self { - let mut recipients = self.params().recipients.drain(..).collect::>(); + let mut recipients = self.params.recipients.drain(..).collect::>(); assert_eq!(recipients.len(), 1, "maintain_single_recipient must not be called while bumping a transactions with more than one output"); - self.params().single_recipient = Some(recipients.pop().unwrap().0); + self.params.single_recipient = Some(recipients.pop().unwrap().0); // Since we are fee bumping and maintaining a single recipient we never want to add any more non-manual inputs. self } diff --git a/testutils-macros/src/lib.rs b/testutils-macros/src/lib.rs index 7f552853..776fde60 100644 --- a/testutils-macros/src/lib.rs +++ b/testutils-macros/src/lib.rs @@ -307,7 +307,9 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream wallet.sync(noop_progress(), None).unwrap(); assert_eq!(wallet.get_balance().unwrap(), 50_000); - let (psbt, details) = wallet.build_tx().add_recipient(node_addr.script_pubkey(), 25_000).finish().unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(node_addr.script_pubkey(), 25_000); + let (psbt, details) = builder.finish().unwrap(); let (psbt, finalized) = wallet.sign(psbt, None).unwrap(); assert!(finalized, "Cannot finalize transaction"); let tx = psbt.extract_tx(); @@ -334,7 +336,9 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream wallet.sync(noop_progress(), None).unwrap(); assert_eq!(wallet.get_balance().unwrap(), 50_000); - let (psbt, details) = wallet.build_tx().add_recipient(node_addr.script_pubkey(), 25_000).finish().unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(node_addr.script_pubkey(), 25_000); + let (psbt, details) = builder.finish().unwrap(); let (psbt, finalized) = wallet.sign(psbt, None).unwrap(); assert!(finalized, "Cannot finalize transaction"); let sent_txid = wallet.broadcast(psbt.extract_tx()).unwrap(); @@ -373,7 +377,9 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream let mut total_sent = 0; for _ in 0..5 { - let (psbt, details) = wallet.build_tx().add_recipient(node_addr.script_pubkey(), 5_000).finish().unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(node_addr.script_pubkey(), 5_000); + let (psbt, details) = builder.finish().unwrap(); let (psbt, finalized) = wallet.sign(psbt, None).unwrap(); assert!(finalized, "Cannot finalize transaction"); wallet.broadcast(psbt.extract_tx()).unwrap(); @@ -405,7 +411,9 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream wallet.sync(noop_progress(), None).unwrap(); assert_eq!(wallet.get_balance().unwrap(), 50_000); - let (psbt, details) = wallet.build_tx().add_recipient(node_addr.script_pubkey().clone(), 5_000).enable_rbf().finish().unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(node_addr.script_pubkey().clone(), 5_000).enable_rbf(); + let (psbt, details) = builder.finish().unwrap(); let (psbt, finalized) = wallet.sign(psbt, None).unwrap(); assert!(finalized, "Cannot finalize transaction"); wallet.broadcast(psbt.extract_tx()).unwrap(); @@ -413,7 +421,9 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream assert_eq!(wallet.get_balance().unwrap(), 50_000 - details.fees - 5_000); assert_eq!(wallet.get_balance().unwrap(), details.received); - let (new_psbt, new_details) = wallet.build_fee_bump(details.txid).unwrap().fee_rate(FeeRate::from_sat_per_vb(2.1)).finish().unwrap(); + let mut builder = wallet.build_fee_bump(details.txid).unwrap(); + builder.fee_rate(FeeRate::from_sat_per_vb(2.1)); + let (new_psbt, new_details) = builder.finish().unwrap(); let (new_psbt, finalized) = wallet.sign(new_psbt, None).unwrap(); assert!(finalized, "Cannot finalize transaction"); wallet.broadcast(new_psbt.extract_tx()).unwrap(); @@ -437,7 +447,9 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream wallet.sync(noop_progress(), None).unwrap(); assert_eq!(wallet.get_balance().unwrap(), 50_000); - let (psbt, details) = wallet.build_tx().add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf().finish().unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf(); + let (psbt, details) = builder.finish().unwrap(); let (psbt, finalized) = wallet.sign(psbt, None).unwrap(); assert!(finalized, "Cannot finalize transaction"); wallet.broadcast(psbt.extract_tx()).unwrap(); @@ -445,7 +457,9 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream assert_eq!(wallet.get_balance().unwrap(), 1_000 - details.fees); assert_eq!(wallet.get_balance().unwrap(), details.received); - let (new_psbt, new_details) = wallet.build_fee_bump(details.txid).unwrap().fee_rate(FeeRate::from_sat_per_vb(5.0)).finish().unwrap(); + let mut builder = wallet.build_fee_bump(details.txid).unwrap(); + builder.fee_rate(FeeRate::from_sat_per_vb(5.0)); + let (new_psbt, new_details) = builder.finish().unwrap(); let (new_psbt, finalized) = wallet.sign(new_psbt, None).unwrap(); assert!(finalized, "Cannot finalize transaction"); wallet.broadcast(new_psbt.extract_tx()).unwrap(); @@ -469,7 +483,9 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream wallet.sync(noop_progress(), None).unwrap(); assert_eq!(wallet.get_balance().unwrap(), 75_000); - let (psbt, details) = wallet.build_tx().add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf().finish().unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf(); + let (psbt, details) = builder.finish().unwrap(); let (psbt, finalized) = wallet.sign(psbt, None).unwrap(); assert!(finalized, "Cannot finalize transaction"); wallet.broadcast(psbt.extract_tx()).unwrap(); @@ -477,7 +493,9 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fees); assert_eq!(details.received, 1_000 - details.fees); - let (new_psbt, new_details) = wallet.build_fee_bump(details.txid).unwrap().fee_rate(FeeRate::from_sat_per_vb(10.0)).finish().unwrap(); + let mut builder = wallet.build_fee_bump(details.txid).unwrap(); + builder.fee_rate(FeeRate::from_sat_per_vb(10.0)); + let (new_psbt, new_details) = builder.finish().unwrap(); let (new_psbt, finalized) = wallet.sign(new_psbt, None).unwrap(); assert!(finalized, "Cannot finalize transaction"); wallet.broadcast(new_psbt.extract_tx()).unwrap(); @@ -499,7 +517,9 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream wallet.sync(noop_progress(), None).unwrap(); assert_eq!(wallet.get_balance().unwrap(), 75_000); - let (psbt, details) = wallet.build_tx().add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf().finish().unwrap(); + let mut builder = wallet.build_tx(); + builder.add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf(); + let (psbt, details) = builder.finish().unwrap(); let (psbt, finalized) = wallet.sign(psbt, None).unwrap(); assert!(finalized, "Cannot finalize transaction"); wallet.broadcast(psbt.extract_tx()).unwrap(); @@ -507,7 +527,9 @@ pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fees); assert_eq!(details.received, 1_000 - details.fees); - let (new_psbt, new_details) = wallet.build_fee_bump(details.txid).unwrap().fee_rate(FeeRate::from_sat_per_vb(123.0)).finish().unwrap(); + let mut builder = wallet.build_fee_bump(details.txid).unwrap(); + builder.fee_rate(FeeRate::from_sat_per_vb(123.0)); + let (new_psbt, new_details) = builder.finish().unwrap(); println!("{:#?}", new_details); let (new_psbt, finalized) = wallet.sign(new_psbt, None).unwrap();