1919//! # use bdk_wallet::*;
2020//! # use bdk_wallet::wallet::ChangeSet;
2121//! # use bdk_wallet::wallet::error::CreateTxError;
22- //! # use bdk_wallet::wallet::tx_builder::CreateTx;
2322//! # use bdk_persist::PersistBackend;
2423//! # use anyhow::Error;
2524//! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
4342use alloc:: { boxed:: Box , rc:: Rc , string:: String , vec:: Vec } ;
4443use core:: cell:: RefCell ;
4544use core:: fmt;
46- use core:: marker:: PhantomData ;
4745
4846use bitcoin:: psbt:: { self , Psbt } ;
4947use bitcoin:: script:: PushBytes ;
5048use bitcoin:: { absolute, Amount , FeeRate , OutPoint , ScriptBuf , Sequence , Transaction , Txid } ;
5149
52- use super :: coin_selection:: { CoinSelectionAlgorithm , DefaultCoinSelectionAlgorithm } ;
50+ use super :: coin_selection:: CoinSelectionAlgorithm ;
5351use super :: { CreateTxError , Wallet } ;
5452use crate :: collections:: { BTreeMap , HashSet } ;
5553use crate :: { KeychainKind , LocalOutput , Utxo , WeightedUtxo } ;
5654
57- /// Context in which the [`TxBuilder`] is valid
58- pub trait TxBuilderContext : core:: fmt:: Debug + Default + Clone { }
59-
60- /// Marker type to indicate the [`TxBuilder`] is being used to create a new transaction (as opposed
61- /// to bumping the fee of an existing one).
62- #[ derive( Debug , Default , Clone ) ]
63- pub struct CreateTx ;
64- impl TxBuilderContext for CreateTx { }
65-
66- /// Marker type to indicate the [`TxBuilder`] is being used to bump the fee of an existing transaction.
67- #[ derive( Debug , Default , Clone ) ]
68- pub struct BumpFee ;
69- impl TxBuilderContext for BumpFee { }
70-
7155/// A transaction builder
7256///
7357/// A `TxBuilder` is created by calling [`build_tx`] or [`build_fee_bump`] on a wallet. After
@@ -123,11 +107,10 @@ impl TxBuilderContext for BumpFee {}
123107/// [`finish`]: Self::finish
124108/// [`coin_selection`]: Self::coin_selection
125109#[ derive( Debug ) ]
126- pub struct TxBuilder < ' a , Cs , Ctx > {
110+ pub struct TxBuilder < ' a , Cs > {
127111 pub ( crate ) wallet : Rc < RefCell < & ' a mut Wallet > > ,
128112 pub ( crate ) params : TxParams ,
129113 pub ( crate ) coin_selection : Cs ,
130- pub ( crate ) phantom : PhantomData < Ctx > ,
131114}
132115
133116/// The parameters for transaction creation sans coin selection algorithm.
@@ -175,19 +158,18 @@ impl Default for FeePolicy {
175158 }
176159}
177160
178- impl < ' a , Cs : Clone , Ctx > Clone for TxBuilder < ' a , Cs , Ctx > {
161+ impl < ' a , Cs : Clone > Clone for TxBuilder < ' a , Cs > {
179162 fn clone ( & self ) -> Self {
180163 TxBuilder {
181164 wallet : self . wallet . clone ( ) ,
182165 params : self . params . clone ( ) ,
183166 coin_selection : self . coin_selection . clone ( ) ,
184- phantom : PhantomData ,
185167 }
186168 }
187169}
188170
189- // methods supported by both contexts, for any CoinSelectionAlgorithm
190- impl < ' a , Cs , Ctx > TxBuilder < ' a , Cs , Ctx > {
171+ // Methods supported for any CoinSelectionAlgorithm.
172+ impl < ' a , Cs > TxBuilder < ' a , Cs > {
191173 /// Set a custom fee rate.
192174 ///
193175 /// This method sets the mining fee paid by the transaction as a rate on its size.
@@ -212,8 +194,8 @@ impl<'a, Cs, Ctx> TxBuilder<'a, Cs, Ctx> {
212194 /// Note that this is really a minimum absolute fee -- it's possible to
213195 /// overshoot it slightly since adding a change output to drain the remaining
214196 /// excess might not be viable.
215- pub fn fee_absolute ( & mut self , fee_amount : u64 ) -> & mut Self {
216- self . params . fee_policy = Some ( FeePolicy :: FeeAmount ( fee_amount) ) ;
197+ pub fn fee_absolute ( & mut self , fee_amount : Amount ) -> & mut Self {
198+ self . params . fee_policy = Some ( FeePolicy :: FeeAmount ( fee_amount. to_sat ( ) ) ) ;
217199 self
218200 }
219201
@@ -553,18 +535,14 @@ impl<'a, Cs, Ctx> TxBuilder<'a, Cs, Ctx> {
553535
554536 /// Choose the coin selection algorithm
555537 ///
556- /// Overrides the [`DefaultCoinSelectionAlgorithm `].
538+ /// Overrides the [`CoinSelectionAlgorithm `].
557539 ///
558540 /// 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.
559- pub fn coin_selection < P : CoinSelectionAlgorithm > (
560- self ,
561- coin_selection : P ,
562- ) -> TxBuilder < ' a , P , Ctx > {
541+ pub fn coin_selection < P : CoinSelectionAlgorithm > ( self , coin_selection : P ) -> TxBuilder < ' a , P > {
563542 TxBuilder {
564543 wallet : self . wallet ,
565544 params : self . params ,
566545 coin_selection,
567- phantom : PhantomData ,
568546 }
569547 }
570548
@@ -612,106 +590,7 @@ impl<'a, Cs, Ctx> TxBuilder<'a, Cs, Ctx> {
612590 self . params . allow_dust = allow_dust;
613591 self
614592 }
615- }
616-
617- impl < ' a , Cs : CoinSelectionAlgorithm , Ctx > TxBuilder < ' a , Cs , Ctx > {
618- /// Finish building the transaction.
619- ///
620- /// Returns a new [`Psbt`] per [`BIP174`].
621- ///
622- /// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
623- pub fn finish ( self ) -> Result < Psbt , CreateTxError > {
624- self . wallet
625- . borrow_mut ( )
626- . create_tx ( self . coin_selection , self . params )
627- }
628- }
629-
630- #[ derive( Debug ) ]
631- /// Error returned from [`TxBuilder::add_utxo`] and [`TxBuilder::add_utxos`]
632- pub enum AddUtxoError {
633- /// Happens when trying to spend an UTXO that is not in the internal database
634- UnknownUtxo ( OutPoint ) ,
635- }
636-
637- impl fmt:: Display for AddUtxoError {
638- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
639- match self {
640- Self :: UnknownUtxo ( outpoint) => write ! (
641- f,
642- "UTXO not found in the internal database for txid: {} with vout: {}" ,
643- outpoint. txid, outpoint. vout
644- ) ,
645- }
646- }
647- }
648-
649- #[ cfg( feature = "std" ) ]
650- impl std:: error:: Error for AddUtxoError { }
651-
652- #[ derive( Debug ) ]
653- /// Error returned from [`TxBuilder::add_foreign_utxo`].
654- pub enum AddForeignUtxoError {
655- /// Foreign utxo outpoint txid does not match PSBT input txid
656- InvalidTxid {
657- /// PSBT input txid
658- input_txid : Txid ,
659- /// Foreign UTXO outpoint
660- foreign_utxo : OutPoint ,
661- } ,
662- /// Requested outpoint doesn't exist in the tx (vout greater than available outputs)
663- InvalidOutpoint ( OutPoint ) ,
664- /// Foreign utxo missing witness_utxo or non_witness_utxo
665- MissingUtxo ,
666- }
667-
668- impl fmt:: Display for AddForeignUtxoError {
669- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
670- match self {
671- Self :: InvalidTxid {
672- input_txid,
673- foreign_utxo,
674- } => write ! (
675- f,
676- "Foreign UTXO outpoint txid: {} does not match PSBT input txid: {}" ,
677- foreign_utxo. txid, input_txid,
678- ) ,
679- Self :: InvalidOutpoint ( outpoint) => write ! (
680- f,
681- "Requested outpoint doesn't exist for txid: {} with vout: {}" ,
682- outpoint. txid, outpoint. vout,
683- ) ,
684- Self :: MissingUtxo => write ! ( f, "Foreign utxo missing witness_utxo or non_witness_utxo" ) ,
685- }
686- }
687- }
688-
689- #[ cfg( feature = "std" ) ]
690- impl std:: error:: Error for AddForeignUtxoError { }
691-
692- #[ derive( Debug ) ]
693- /// Error returned from [`TxBuilder::allow_shrinking`]
694- pub enum AllowShrinkingError {
695- /// Script/PubKey was not in the original transaction
696- MissingScriptPubKey ( ScriptBuf ) ,
697- }
698-
699- impl fmt:: Display for AllowShrinkingError {
700- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
701- match self {
702- Self :: MissingScriptPubKey ( script_buf) => write ! (
703- f,
704- "Script/PubKey was not in the original transaction: {}" ,
705- script_buf,
706- ) ,
707- }
708- }
709- }
710-
711- #[ cfg( feature = "std" ) ]
712- impl std:: error:: Error for AllowShrinkingError { }
713593
714- impl < ' a , Cs : CoinSelectionAlgorithm > TxBuilder < ' a , Cs , CreateTx > {
715594 /// Replace the recipients already added with a new list
716595 pub fn set_recipients ( & mut self , recipients : Vec < ( ScriptBuf , Amount ) > ) -> & mut Self {
717596 self . params . recipients = recipients
@@ -745,11 +624,8 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
745624 /// difference is that it is valid to use `drain_to` without setting any ordinary recipients
746625 /// with [`add_recipient`] (but it is perfectly fine to add recipients as well).
747626 ///
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.
627+ /// If you choose not to set any recipients, you should provide the utxos that the
628+ /// transaction should spend via [`add_utxos`].
753629 ///
754630 /// # Example
755631 ///
@@ -762,7 +638,6 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
762638 /// # use bdk_wallet::*;
763639 /// # use bdk_wallet::wallet::ChangeSet;
764640 /// # use bdk_wallet::wallet::error::CreateTxError;
765- /// # use bdk_wallet::wallet::tx_builder::CreateTx;
766641 /// # use bdk_persist::PersistBackend;
767642 /// # use anyhow::Error;
768643 /// # let to_address =
@@ -783,7 +658,6 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
783658 /// # Ok::<(), anyhow::Error>(())
784659 /// ```
785660 ///
786- /// [`allow_shrinking`]: Self::allow_shrinking
787661 /// [`add_recipient`]: Self::add_recipient
788662 /// [`add_utxos`]: Self::add_utxos
789663 /// [`drain_wallet`]: Self::drain_wallet
@@ -793,38 +667,81 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
793667 }
794668}
795669
796- // methods supported only by bump_fee
797- impl < ' a > TxBuilder < ' a , 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.
670+ impl < ' a , Cs : CoinSelectionAlgorithm > TxBuilder < ' a , Cs > {
671+ /// Finish building the transaction.
801672 ///
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.
673+ /// Returns a new [`Psbt`] per [`BIP174`].
805674 ///
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) ) ,
675+ /// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
676+ pub fn finish ( self ) -> Result < Psbt , CreateTxError > {
677+ self . wallet
678+ . borrow_mut ( )
679+ . create_tx ( self . coin_selection , self . params )
680+ }
681+ }
682+
683+ #[ derive( Debug ) ]
684+ /// Error returned from [`TxBuilder::add_utxo`] and [`TxBuilder::add_utxos`]
685+ pub enum AddUtxoError {
686+ /// Happens when trying to spend an UTXO that is not in the internal database
687+ UnknownUtxo ( OutPoint ) ,
688+ }
689+
690+ impl fmt:: Display for AddUtxoError {
691+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
692+ match self {
693+ Self :: UnknownUtxo ( outpoint) => write ! (
694+ f,
695+ "UTXO not found in the internal database for txid: {} with vout: {}" ,
696+ outpoint. txid, outpoint. vout
697+ ) ,
698+ }
699+ }
700+ }
701+
702+ #[ cfg( feature = "std" ) ]
703+ impl std:: error:: Error for AddUtxoError { }
704+
705+ #[ derive( Debug ) ]
706+ /// Error returned from [`TxBuilder::add_foreign_utxo`].
707+ pub enum AddForeignUtxoError {
708+ /// Foreign utxo outpoint txid does not match PSBT input txid
709+ InvalidTxid {
710+ /// PSBT input txid
711+ input_txid : Txid ,
712+ /// Foreign UTXO outpoint
713+ foreign_utxo : OutPoint ,
714+ } ,
715+ /// Requested outpoint doesn't exist in the tx (vout greater than available outputs)
716+ InvalidOutpoint ( OutPoint ) ,
717+ /// Foreign utxo missing witness_utxo or non_witness_utxo
718+ MissingUtxo ,
719+ }
720+
721+ impl fmt:: Display for AddForeignUtxoError {
722+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
723+ match self {
724+ Self :: InvalidTxid {
725+ input_txid,
726+ foreign_utxo,
727+ } => write ! (
728+ f,
729+ "Foreign UTXO outpoint txid: {} does not match PSBT input txid: {}" ,
730+ foreign_utxo. txid, input_txid,
731+ ) ,
732+ Self :: InvalidOutpoint ( outpoint) => write ! (
733+ f,
734+ "Requested outpoint doesn't exist for txid: {} with vout: {}" ,
735+ outpoint. txid, outpoint. vout,
736+ ) ,
737+ Self :: MissingUtxo => write ! ( f, "Foreign utxo missing witness_utxo or non_witness_utxo" ) ,
824738 }
825739 }
826740}
827741
742+ #[ cfg( feature = "std" ) ]
743+ impl std:: error:: Error for AddForeignUtxoError { }
744+
828745/// Ordering of the transaction's inputs and outputs
829746#[ derive( Default , Debug , Ord , PartialOrd , Eq , PartialEq , Hash , Clone , Copy ) ]
830747pub enum TxOrdering {
0 commit comments