|
43 | 43 | use alloc::{boxed::Box, rc::Rc, string::String, vec::Vec};
|
44 | 44 | use core::cell::RefCell;
|
45 | 45 | use core::fmt;
|
46 |
| -use core::marker::PhantomData; |
47 | 46 |
|
48 | 47 | use bdk_chain::PersistBackend;
|
49 | 48 | use bitcoin::psbt::{self, PartiallySignedTransaction as Psbt};
|
50 | 49 | use bitcoin::script::PushBytes;
|
51 | 50 | use bitcoin::{absolute, FeeRate, OutPoint, ScriptBuf, Sequence, Transaction, Txid};
|
52 | 51 |
|
53 |
| -use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm}; |
| 52 | +use super::coin_selection::CoinSelectionAlgorithm; |
54 | 53 | use super::{ChangeSet, CreateTxError, Wallet};
|
55 | 54 | use crate::collections::{BTreeMap, HashSet};
|
56 | 55 | use crate::{KeychainKind, LocalOutput, Utxo, WeightedUtxo};
|
@@ -124,11 +123,10 @@ impl TxBuilderContext for BumpFee {}
|
124 | 123 | /// [`finish`]: Self::finish
|
125 | 124 | /// [`coin_selection`]: Self::coin_selection
|
126 | 125 | #[derive(Debug)]
|
127 |
| -pub struct TxBuilder<'a, D, Cs, Ctx> { |
| 126 | +pub struct TxBuilder<'a, D, Cs> { |
128 | 127 | pub(crate) wallet: Rc<RefCell<&'a mut Wallet<D>>>,
|
129 | 128 | pub(crate) params: TxParams,
|
130 | 129 | pub(crate) coin_selection: Cs,
|
131 |
| - pub(crate) phantom: PhantomData<Ctx>, |
132 | 130 | }
|
133 | 131 |
|
134 | 132 | /// The parameters for transaction creation sans coin selection algorithm.
|
@@ -176,19 +174,18 @@ impl Default for FeePolicy {
|
176 | 174 | }
|
177 | 175 | }
|
178 | 176 |
|
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> { |
180 | 178 | fn clone(&self) -> Self {
|
181 | 179 | TxBuilder {
|
182 | 180 | wallet: self.wallet.clone(),
|
183 | 181 | params: self.params.clone(),
|
184 | 182 | coin_selection: self.coin_selection.clone(),
|
185 |
| - phantom: PhantomData, |
186 | 183 | }
|
187 | 184 | }
|
188 | 185 | }
|
189 | 186 |
|
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> { |
192 | 189 | /// Set a custom fee rate.
|
193 | 190 | ///
|
194 | 191 | /// 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> {
|
557 | 554 | ///
|
558 | 555 | /// Overrides the [`DefaultCoinSelectionAlgorithm`].
|
559 | 556 | ///
|
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 |
561 | 560 | pub fn coin_selection<P: CoinSelectionAlgorithm>(
|
562 | 561 | self,
|
563 | 562 | coin_selection: P,
|
564 |
| - ) -> TxBuilder<'a, D, P, Ctx> { |
| 563 | + ) -> TxBuilder<'a, D, P> { |
565 | 564 | TxBuilder {
|
566 | 565 | wallet: self.wallet,
|
567 | 566 | params: self.params,
|
568 | 567 | coin_selection,
|
569 |
| - phantom: PhantomData, |
570 | 568 | }
|
571 | 569 | }
|
572 | 570 |
|
@@ -614,9 +612,80 @@ impl<'a, D, Cs, Ctx> TxBuilder<'a, D, Cs, Ctx> {
|
614 | 612 | self.params.allow_dust = allow_dust;
|
615 | 613 | self
|
616 | 614 | }
|
| 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 | + } |
617 | 686 | }
|
618 | 687 |
|
619 |
| -impl<'a, D, Cs: CoinSelectionAlgorithm, Ctx> TxBuilder<'a, D, Cs, Ctx> { |
| 688 | +impl<'a, D, Cs: CoinSelectionAlgorithm> TxBuilder<'a, D, Cs> { |
620 | 689 | /// Finish building the transaction.
|
621 | 690 | ///
|
622 | 691 | /// Returns a new [`Psbt`] per [`BIP174`].
|
@@ -694,137 +763,6 @@ impl fmt::Display for AddForeignUtxoError {
|
694 | 763 | #[cfg(feature = "std")]
|
695 | 764 | impl std::error::Error for AddForeignUtxoError {}
|
696 | 765 |
|
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 |
| - |
828 | 766 | /// Ordering of the transaction's inputs and outputs
|
829 | 767 | #[derive(Default, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
|
830 | 768 | pub enum TxOrdering {
|
|
0 commit comments