19
19
//! # use bdk_wallet::*;
20
20
//! # use bdk_wallet::wallet::ChangeSet;
21
21
//! # use bdk_wallet::wallet::error::CreateTxError;
22
- //! # use bdk_wallet::wallet::tx_builder::CreateTx;
23
22
//! # use bdk_persist::PersistBackend;
24
23
//! # use anyhow::Error;
25
24
//! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
43
42
use alloc:: { boxed:: Box , rc:: Rc , string:: String , vec:: Vec } ;
44
43
use core:: cell:: RefCell ;
45
44
use core:: fmt;
46
- use core:: marker:: PhantomData ;
47
45
48
46
use bitcoin:: psbt:: { self , Psbt } ;
49
47
use bitcoin:: script:: PushBytes ;
50
48
use bitcoin:: { absolute, Amount , FeeRate , OutPoint , ScriptBuf , Sequence , Transaction , Txid } ;
51
49
52
- use super :: coin_selection:: { CoinSelectionAlgorithm , DefaultCoinSelectionAlgorithm } ;
50
+ use super :: coin_selection:: CoinSelectionAlgorithm ;
53
51
use super :: { CreateTxError , Wallet } ;
54
52
use crate :: collections:: { BTreeMap , HashSet } ;
55
53
use crate :: { KeychainKind , LocalOutput , Utxo , WeightedUtxo } ;
56
54
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
-
71
55
/// A transaction builder
72
56
///
73
57
/// A `TxBuilder` is created by calling [`build_tx`] or [`build_fee_bump`] on a wallet. After
@@ -123,11 +107,10 @@ impl TxBuilderContext for BumpFee {}
123
107
/// [`finish`]: Self::finish
124
108
/// [`coin_selection`]: Self::coin_selection
125
109
#[ derive( Debug ) ]
126
- pub struct TxBuilder < ' a , Cs , Ctx > {
110
+ pub struct TxBuilder < ' a , Cs > {
127
111
pub ( crate ) wallet : Rc < RefCell < & ' a mut Wallet > > ,
128
112
pub ( crate ) params : TxParams ,
129
113
pub ( crate ) coin_selection : Cs ,
130
- pub ( crate ) phantom : PhantomData < Ctx > ,
131
114
}
132
115
133
116
/// The parameters for transaction creation sans coin selection algorithm.
@@ -175,19 +158,18 @@ impl Default for FeePolicy {
175
158
}
176
159
}
177
160
178
- impl < ' a , Cs : Clone , Ctx > Clone for TxBuilder < ' a , Cs , Ctx > {
161
+ impl < ' a , Cs : Clone > Clone for TxBuilder < ' a , Cs > {
179
162
fn clone ( & self ) -> Self {
180
163
TxBuilder {
181
164
wallet : self . wallet . clone ( ) ,
182
165
params : self . params . clone ( ) ,
183
166
coin_selection : self . coin_selection . clone ( ) ,
184
- phantom : PhantomData ,
185
167
}
186
168
}
187
169
}
188
170
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 > {
191
173
/// Set a custom fee rate.
192
174
///
193
175
/// 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> {
212
194
/// Note that this is really a minimum absolute fee -- it's possible to
213
195
/// overshoot it slightly since adding a change output to drain the remaining
214
196
/// 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 ( ) ) ) ;
217
199
self
218
200
}
219
201
@@ -556,15 +538,11 @@ impl<'a, Cs, Ctx> TxBuilder<'a, Cs, Ctx> {
556
538
/// Overrides the [`DefaultCoinSelectionAlgorithm`].
557
539
///
558
540
/// 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 > {
563
542
TxBuilder {
564
543
wallet : self . wallet ,
565
544
params : self . params ,
566
545
coin_selection,
567
- phantom : PhantomData ,
568
546
}
569
547
}
570
548
@@ -612,106 +590,7 @@ impl<'a, Cs, Ctx> TxBuilder<'a, Cs, Ctx> {
612
590
self . params . allow_dust = allow_dust;
613
591
self
614
592
}
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 { }
713
593
714
- impl < ' a , Cs : CoinSelectionAlgorithm > TxBuilder < ' a , Cs , CreateTx > {
715
594
/// Replace the recipients already added with a new list
716
595
pub fn set_recipients ( & mut self , recipients : Vec < ( ScriptBuf , Amount ) > ) -> & mut Self {
717
596
self . params . recipients = recipients
@@ -745,11 +624,8 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
745
624
/// difference is that it is valid to use `drain_to` without setting any ordinary recipients
746
625
/// with [`add_recipient`] (but it is perfectly fine to add recipients as well).
747
626
///
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`].
753
629
///
754
630
/// # Example
755
631
///
@@ -762,7 +638,6 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
762
638
/// # use bdk_wallet::*;
763
639
/// # use bdk_wallet::wallet::ChangeSet;
764
640
/// # use bdk_wallet::wallet::error::CreateTxError;
765
- /// # use bdk_wallet::wallet::tx_builder::CreateTx;
766
641
/// # use bdk_persist::PersistBackend;
767
642
/// # use anyhow::Error;
768
643
/// # let to_address =
@@ -783,7 +658,6 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
783
658
/// # Ok::<(), anyhow::Error>(())
784
659
/// ```
785
660
///
786
- /// [`allow_shrinking`]: Self::allow_shrinking
787
661
/// [`add_recipient`]: Self::add_recipient
788
662
/// [`add_utxos`]: Self::add_utxos
789
663
/// [`drain_wallet`]: Self::drain_wallet
@@ -793,38 +667,81 @@ impl<'a, Cs: CoinSelectionAlgorithm> TxBuilder<'a, Cs, CreateTx> {
793
667
}
794
668
}
795
669
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.
801
672
///
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`].
805
674
///
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" ) ,
824
738
}
825
739
}
826
740
}
827
741
742
+ #[ cfg( feature = "std" ) ]
743
+ impl std:: error:: Error for AddForeignUtxoError { }
744
+
828
745
/// Ordering of the transaction's inputs and outputs
829
746
#[ derive( Default , Debug , Ord , PartialOrd , Eq , PartialEq , Hash , Clone , Copy ) ]
830
747
pub enum TxOrdering {
0 commit comments