// Magical Bitcoin Library // Written in 2020 by // Alekos Filini // // Copyright (c) 2020 Magical Bitcoin // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. //! Transaction builder //! //! ## Example //! //! ``` //! # use std::str::FromStr; //! # use bitcoin::*; //! # use bdk::*; //! # use bdk::wallet::tx_builder::CreateTx; //! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); //! # let wallet = doctest_wallet!(); //! // create a TxBuilder from a wallet //! let mut tx_builder = wallet.build_tx(); //! //! let (psbt, tx_details) = 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 //! .fee_rate(FeeRate::from_sat_per_vb(5.0)) //! // Only spend non-change outputs //! .do_not_spend_change() //! // Turn on RBF signaling //! .enable_rbf() //! .finish()?; //! //! # Ok::<(), bdk::Error>(()) //! ``` use std::collections::BTreeMap; use std::collections::HashSet; use std::default::Default; use std::marker::PhantomData; use bitcoin::util::psbt::PartiallySignedTransaction as PSBT; use bitcoin::{OutPoint, Script, SigHashType, Transaction}; use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm}; use crate::{database::BatchDatabase, Error, Wallet}; use crate::{ types::{FeeRate, KeychainKind, UTXO}, TransactionDetails, }; /// Context in which the [`TxBuilder`] is valid pub trait TxBuilderContext: std::fmt::Debug + Default + Clone {} /// Marker type to indicate the [`TxBuilder`] is being used to create a new transaction (as opposed /// to bumping the fee of an existing one). #[derive(Debug, Default, Clone)] pub struct CreateTx; impl TxBuilderContext for CreateTx {} /// Marker type to indicate the [`TxBuilder`] is being used to bump the fee of an existing transaction. #[derive(Debug, Default, Clone)] pub struct BumpFee; 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. /// /// 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: /// /// ``` /// # use bdk::*; /// # use bdk::wallet::tx_builder::*; /// # use bitcoin::*; /// # use core::str::FromStr; /// # let wallet = doctest_wallet!(); /// # let addr1 = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap(); /// # let addr2 = addr1.clone(); /// // chaining /// let (psbt1, details) = wallet.build_tx() /// .ordering(TxOrdering::Untouched) /// .add_recipient(addr1.script_pubkey(), 50_000) /// .add_recipient(addr2.script_pubkey(), 50_000) /// .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()?; /// // /// 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. /// /// For further examples see [this module](super::tx_builder)'s documentation; /// /// [`build_tx`]: Wallet::build_tx /// [`build_fee_bump`]: Wallet::build_fee_bump /// [`finish`]: Self::finish /// [`coin_selection`]: Self::coin_selection pub struct TxBuilder<'a, B, D, Cs, Ctx> { pub(crate) wallet: &'a Wallet, // 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) phantom: PhantomData, } /// The parameters for transaction creation sans coin selection algorithm. //TODO: TxParams should eventually be exposed publicly. #[derive(Default, Debug)] pub(crate) struct TxParams { pub(crate) recipients: Vec<(Script, u64)>, pub(crate) drain_wallet: bool, pub(crate) single_recipient: Option