Skip to content

Commit 4073c43

Browse files
committed
fix(wallet): remove TxBuilder allow_shrinking function and unneeded context param
1 parent 80e190b commit 4073c43

File tree

3 files changed

+106
-161
lines changed

3 files changed

+106
-161
lines changed

crates/bdk/src/wallet/mod.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub use utils::IsDust;
5757
#[allow(deprecated)]
5858
use coin_selection::DefaultCoinSelectionAlgorithm;
5959
use signer::{SignOptions, SignerOrdering, SignersContainer, TransactionSigner};
60-
use tx_builder::{BumpFee, CreateTx, FeePolicy, TxBuilder, TxParams};
60+
use tx_builder::{FeePolicy, TxBuilder, TxParams};
6161
use utils::{check_nsequence_rbf, After, Older, SecpCtx};
6262

6363
use crate::descriptor::policy::BuildSatisfaction;
@@ -1252,12 +1252,11 @@ impl<D> Wallet<D> {
12521252
/// ```
12531253
///
12541254
/// [`TxBuilder`]: crate::TxBuilder
1255-
pub fn build_tx(&mut self) -> TxBuilder<'_, D, DefaultCoinSelectionAlgorithm, CreateTx> {
1255+
pub fn build_tx(&mut self) -> TxBuilder<'_, D, DefaultCoinSelectionAlgorithm> {
12561256
TxBuilder {
12571257
wallet: alloc::rc::Rc::new(core::cell::RefCell::new(self)),
12581258
params: TxParams::default(),
12591259
coin_selection: DefaultCoinSelectionAlgorithm::default(),
1260-
phantom: core::marker::PhantomData,
12611260
}
12621261
}
12631262

@@ -1431,7 +1430,6 @@ impl<D> Wallet<D> {
14311430
};
14321431

14331432
let (fee_rate, mut fee_amount) = match params.fee_policy.unwrap_or_default() {
1434-
//FIXME: see https://github.com/bitcoindevkit/bdk/issues/256
14351433
FeePolicy::FeeAmount(fee) => {
14361434
if let Some(previous_fee) = params.bumping_fee {
14371435
if fee < previous_fee.absolute {
@@ -1662,7 +1660,7 @@ impl<D> Wallet<D> {
16621660
pub fn build_fee_bump(
16631661
&mut self,
16641662
txid: Txid,
1665-
) -> Result<TxBuilder<'_, D, DefaultCoinSelectionAlgorithm, BumpFee>, BuildFeeBumpError> {
1663+
) -> Result<TxBuilder<'_, D, DefaultCoinSelectionAlgorithm>, BuildFeeBumpError> {
16661664
let graph = self.indexed_graph.graph();
16671665
let txout_index = &self.indexed_graph.index;
16681666
let chain_tip = self.chain.tip().block_id();
@@ -1786,7 +1784,6 @@ impl<D> Wallet<D> {
17861784
wallet: alloc::rc::Rc::new(core::cell::RefCell::new(self)),
17871785
params,
17881786
coin_selection: DefaultCoinSelectionAlgorithm::default(),
1789-
phantom: core::marker::PhantomData,
17901787
})
17911788
}
17921789

crates/bdk/src/wallet/tx_builder.rs

Lines changed: 81 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,13 @@
4343
use alloc::{boxed::Box, rc::Rc, string::String, vec::Vec};
4444
use core::cell::RefCell;
4545
use core::fmt;
46-
use core::marker::PhantomData;
4746

4847
use bdk_chain::PersistBackend;
4948
use bitcoin::psbt::{self, PartiallySignedTransaction as Psbt};
5049
use bitcoin::script::PushBytes;
5150
use bitcoin::{absolute, FeeRate, OutPoint, ScriptBuf, Sequence, Transaction, Txid};
5251

53-
use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm};
52+
use super::coin_selection::CoinSelectionAlgorithm;
5453
use super::{ChangeSet, CreateTxError, Wallet};
5554
use crate::collections::{BTreeMap, HashSet};
5655
use crate::{KeychainKind, LocalOutput, Utxo, WeightedUtxo};
@@ -124,11 +123,10 @@ impl TxBuilderContext for BumpFee {}
124123
/// [`finish`]: Self::finish
125124
/// [`coin_selection`]: Self::coin_selection
126125
#[derive(Debug)]
127-
pub struct TxBuilder<'a, D, Cs, Ctx> {
126+
pub struct TxBuilder<'a, D, Cs> {
128127
pub(crate) wallet: Rc<RefCell<&'a mut Wallet<D>>>,
129128
pub(crate) params: TxParams,
130129
pub(crate) coin_selection: Cs,
131-
pub(crate) phantom: PhantomData<Ctx>,
132130
}
133131

134132
/// The parameters for transaction creation sans coin selection algorithm.
@@ -176,19 +174,18 @@ impl Default for FeePolicy {
176174
}
177175
}
178176

179-
impl<'a, D, Cs: Clone, Ctx> Clone for TxBuilder<'a, D, Cs, Ctx> {
177+
impl<'a, D, Cs: Clone> Clone for TxBuilder<'a, D, Cs> {
180178
fn clone(&self) -> Self {
181179
TxBuilder {
182180
wallet: self.wallet.clone(),
183181
params: self.params.clone(),
184182
coin_selection: self.coin_selection.clone(),
185-
phantom: PhantomData,
186183
}
187184
}
188185
}
189186

190-
// methods supported by both contexts, for any CoinSelectionAlgorithm
191-
impl<'a, D, Cs, Ctx> TxBuilder<'a, D, Cs, Ctx> {
187+
// methods supported for any CoinSelectionAlgorithm
188+
impl<'a, D, Cs> TxBuilder<'a, D, Cs> {
192189
/// Set a custom fee rate.
193190
///
194191
/// This method sets the mining fee paid by the transaction as a rate on its size.
@@ -557,16 +554,17 @@ impl<'a, D, Cs, Ctx> TxBuilder<'a, D, Cs, Ctx> {
557554
///
558555
/// Overrides the [`DefaultCoinSelectionAlgorithm`].
559556
///
560-
/// Note that this function consumes the builder and returns it so it is usually best to put this as the first call on the builder.
557+
/// Note that this function consumes the builder and returns it, so it is usually best to put this as the first call on the builder.
558+
///
559+
/// [`DefaultCoinSelectionAlgorithm`]: super::coin_selection::DefaultCoinSelectionAlgorithm
561560
pub fn coin_selection<P: CoinSelectionAlgorithm>(
562561
self,
563562
coin_selection: P,
564-
) -> TxBuilder<'a, D, P, Ctx> {
563+
) -> TxBuilder<'a, D, P> {
565564
TxBuilder {
566565
wallet: self.wallet,
567566
params: self.params,
568567
coin_selection,
569-
phantom: PhantomData,
570568
}
571569
}
572570

@@ -614,9 +612,80 @@ impl<'a, D, Cs, Ctx> TxBuilder<'a, D, Cs, Ctx> {
614612
self.params.allow_dust = allow_dust;
615613
self
616614
}
615+
616+
/// Replace the recipients already added with a new list
617+
pub fn set_recipients(&mut self, recipients: Vec<(ScriptBuf, u64)>) -> &mut Self {
618+
self.params.recipients = recipients;
619+
self
620+
}
621+
622+
/// Add a recipient to the internal list
623+
pub fn add_recipient(&mut self, script_pubkey: ScriptBuf, amount: u64) -> &mut Self {
624+
self.params.recipients.push((script_pubkey, amount));
625+
self
626+
}
627+
628+
/// Add data as an output, using OP_RETURN
629+
pub fn add_data<T: AsRef<PushBytes>>(&mut self, data: &T) -> &mut Self {
630+
let script = ScriptBuf::new_op_return(data);
631+
self.add_recipient(script, 0u64);
632+
self
633+
}
634+
635+
/// Sets the address to *drain* excess coins to.
636+
///
637+
/// Usually, when there are excess coins they are sent to a change address generated by the
638+
/// wallet. This option replaces the usual change address with an arbitrary `script_pubkey` of
639+
/// your choosing. Just as with a change output, if the drain output is not needed (the excess
640+
/// coins are too small) it will not be included in the resulting transaction. The only
641+
/// difference is that it is valid to use `drain_to` without setting any ordinary recipients
642+
/// with [`add_recipient`] (but it is perfectly fine to add recipients as well).
643+
///
644+
/// If you choose not to set any recipients, you should provide the utxos that the
645+
/// transaction should spend via [`add_utxos`].
646+
///
647+
/// # Example
648+
///
649+
/// `drain_to` is very useful for draining all the coins in a wallet with [`drain_wallet`] to a
650+
/// single address.
651+
///
652+
/// ```
653+
/// # use std::str::FromStr;
654+
/// # use bitcoin::*;
655+
/// # use bdk::*;
656+
/// # use bdk::wallet::ChangeSet;
657+
/// # use bdk::wallet::error::CreateTxError;
658+
/// # use bdk::wallet::tx_builder::CreateTx;
659+
/// # use bdk_chain::PersistBackend;
660+
/// # use anyhow::Error;
661+
/// # let to_address =
662+
/// Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
663+
/// .unwrap()
664+
/// .assume_checked();
665+
/// # let mut wallet = doctest_wallet!();
666+
/// let mut tx_builder = wallet.build_tx();
667+
///
668+
/// tx_builder
669+
/// // Spend all outputs in this wallet.
670+
/// .drain_wallet()
671+
/// // Send the excess (which is all the coins minus the fee) to this address.
672+
/// .drain_to(to_address.script_pubkey())
673+
/// .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate"))
674+
/// .enable_rbf();
675+
/// let psbt = tx_builder.finish()?;
676+
/// # Ok::<(), anyhow::Error>(())
677+
/// ```
678+
///
679+
/// [`add_recipient`]: Self::add_recipient
680+
/// [`add_utxos`]: Self::add_utxos
681+
/// [`drain_wallet`]: Self::drain_wallet
682+
pub fn drain_to(&mut self, script_pubkey: ScriptBuf) -> &mut Self {
683+
self.params.drain_to = Some(script_pubkey);
684+
self
685+
}
617686
}
618687

619-
impl<'a, D, Cs: CoinSelectionAlgorithm, Ctx> TxBuilder<'a, D, Cs, Ctx> {
688+
impl<'a, D, Cs: CoinSelectionAlgorithm> TxBuilder<'a, D, Cs> {
620689
/// Finish building the transaction.
621690
///
622691
/// Returns a new [`Psbt`] per [`BIP174`].
@@ -694,137 +763,6 @@ impl fmt::Display for AddForeignUtxoError {
694763
#[cfg(feature = "std")]
695764
impl std::error::Error for AddForeignUtxoError {}
696765

697-
#[derive(Debug)]
698-
/// Error returned from [`TxBuilder::allow_shrinking`]
699-
pub enum AllowShrinkingError {
700-
/// Script/PubKey was not in the original transaction
701-
MissingScriptPubKey(ScriptBuf),
702-
}
703-
704-
impl fmt::Display for AllowShrinkingError {
705-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
706-
match self {
707-
Self::MissingScriptPubKey(script_buf) => write!(
708-
f,
709-
"Script/PubKey was not in the original transaction: {}",
710-
script_buf,
711-
),
712-
}
713-
}
714-
}
715-
716-
#[cfg(feature = "std")]
717-
impl std::error::Error for AllowShrinkingError {}
718-
719-
impl<'a, D, Cs: CoinSelectionAlgorithm> TxBuilder<'a, D, Cs, CreateTx> {
720-
/// Replace the recipients already added with a new list
721-
pub fn set_recipients(&mut self, recipients: Vec<(ScriptBuf, u64)>) -> &mut Self {
722-
self.params.recipients = recipients;
723-
self
724-
}
725-
726-
/// Add a recipient to the internal list
727-
pub fn add_recipient(&mut self, script_pubkey: ScriptBuf, amount: u64) -> &mut Self {
728-
self.params.recipients.push((script_pubkey, amount));
729-
self
730-
}
731-
732-
/// Add data as an output, using OP_RETURN
733-
pub fn add_data<T: AsRef<PushBytes>>(&mut self, data: &T) -> &mut Self {
734-
let script = ScriptBuf::new_op_return(data);
735-
self.add_recipient(script, 0u64);
736-
self
737-
}
738-
739-
/// Sets the address to *drain* excess coins to.
740-
///
741-
/// Usually, when there are excess coins they are sent to a change address generated by the
742-
/// wallet. This option replaces the usual change address with an arbitrary `script_pubkey` of
743-
/// your choosing. Just as with a change output, if the drain output is not needed (the excess
744-
/// coins are too small) it will not be included in the resulting transaction. The only
745-
/// difference is that it is valid to use `drain_to` without setting any ordinary recipients
746-
/// with [`add_recipient`] (but it is perfectly fine to add recipients as well).
747-
///
748-
/// If you choose not to set any recipients, you should either provide the utxos that the
749-
/// transaction should spend via [`add_utxos`], or set [`drain_wallet`] to spend all of them.
750-
///
751-
/// When bumping the fees of a transaction made with this option, you probably want to
752-
/// use [`allow_shrinking`] to allow this output to be reduced to pay for the extra fees.
753-
///
754-
/// # Example
755-
///
756-
/// `drain_to` is very useful for draining all the coins in a wallet with [`drain_wallet`] to a
757-
/// single address.
758-
///
759-
/// ```
760-
/// # use std::str::FromStr;
761-
/// # use bitcoin::*;
762-
/// # use bdk::*;
763-
/// # use bdk::wallet::ChangeSet;
764-
/// # use bdk::wallet::error::CreateTxError;
765-
/// # use bdk::wallet::tx_builder::CreateTx;
766-
/// # use bdk_chain::PersistBackend;
767-
/// # use anyhow::Error;
768-
/// # let to_address =
769-
/// Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
770-
/// .unwrap()
771-
/// .assume_checked();
772-
/// # let mut wallet = doctest_wallet!();
773-
/// let mut tx_builder = wallet.build_tx();
774-
///
775-
/// tx_builder
776-
/// // Spend all outputs in this wallet.
777-
/// .drain_wallet()
778-
/// // Send the excess (which is all the coins minus the fee) to this address.
779-
/// .drain_to(to_address.script_pubkey())
780-
/// .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate"))
781-
/// .enable_rbf();
782-
/// let psbt = tx_builder.finish()?;
783-
/// # Ok::<(), anyhow::Error>(())
784-
/// ```
785-
///
786-
/// [`allow_shrinking`]: Self::allow_shrinking
787-
/// [`add_recipient`]: Self::add_recipient
788-
/// [`add_utxos`]: Self::add_utxos
789-
/// [`drain_wallet`]: Self::drain_wallet
790-
pub fn drain_to(&mut self, script_pubkey: ScriptBuf) -> &mut Self {
791-
self.params.drain_to = Some(script_pubkey);
792-
self
793-
}
794-
}
795-
796-
// methods supported only by bump_fee
797-
impl<'a, D> TxBuilder<'a, D, DefaultCoinSelectionAlgorithm, BumpFee> {
798-
/// Explicitly tells the wallet that it is allowed to reduce the amount of the output matching this
799-
/// `script_pubkey` in order to bump the transaction fee. Without specifying this the wallet
800-
/// will attempt to find a change output to shrink instead.
801-
///
802-
/// **Note** that the output may shrink to below the dust limit and therefore be removed. If it is
803-
/// preserved then it is currently not guaranteed to be in the same position as it was
804-
/// originally.
805-
///
806-
/// Returns an `Err` if `script_pubkey` can't be found among the recipients of the
807-
/// transaction we are bumping.
808-
pub fn allow_shrinking(
809-
&mut self,
810-
script_pubkey: ScriptBuf,
811-
) -> Result<&mut Self, AllowShrinkingError> {
812-
match self
813-
.params
814-
.recipients
815-
.iter()
816-
.position(|(recipient_script, _)| *recipient_script == script_pubkey)
817-
{
818-
Some(position) => {
819-
self.params.recipients.remove(position);
820-
self.params.drain_to = Some(script_pubkey);
821-
Ok(self)
822-
}
823-
None => Err(AllowShrinkingError::MissingScriptPubKey(script_pubkey)),
824-
}
825-
}
826-
}
827-
828766
/// Ordering of the transaction's inputs and outputs
829767
#[derive(Default, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
830768
pub enum TxOrdering {

0 commit comments

Comments
 (0)