// Bitcoin Dev Kit // Written in 2020 by Alekos Filini // // Copyright (c) 2020-2021 Bitcoin Dev Kit Developers // // This file is licensed under the Apache License, Version 2.0 or the MIT license // , at your option. // You may not use this file except in accordance with one or both of these // licenses. //! 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(); //! //! 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(); //! let (psbt, tx_details) = tx_builder.finish()?; //! # Ok::<(), bdk::Error>(()) //! ``` use std::collections::BTreeMap; use std::collections::HashSet; use std::default::Default; use std::marker::PhantomData; use bitcoin::util::psbt::{self, PartiallySignedTransaction as PSBT}; use bitcoin::{OutPoint, Script, SigHashType, Transaction}; use miniscript::descriptor::DescriptorTrait; use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm}; use crate::{database::BatchDatabase, Error, Utxo, Wallet}; use crate::{ types::{FeeRate, KeychainKind, LocalUtxo, WeightedUtxo}, 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 created by calling [`build_tx`] or [`build_fee_bump`] on a wallet. After /// assigning it, you set options on it until finally calling [`finish`] to consume the builder and /// generate the transaction. /// /// Each option setting method on `TxBuilder` takes and returns `&mut self` so you can chain calls /// 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) = { /// let mut builder = wallet.build_tx(); /// builder /// .ordering(TxOrdering::Untouched) /// .add_recipient(addr1.script_pubkey(), 50_000) /// .add_recipient(addr2.script_pubkey(), 50_000); /// builder.finish()? /// }; /// /// // non-chaining /// let (psbt2, details) = { /// let mut builder = wallet.build_tx(); /// builder.ordering(TxOrdering::Untouched); /// for addr in &[addr1, addr2] { /// builder.add_recipient(addr.script_pubkey(), 50_000); /// } /// builder.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 to the rule as it consumes `self`. /// This means it is usually best to call [`coin_selection`] on the return value of `build_tx` before assigning it. /// /// 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 #[derive(Debug)] 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: TxParams, pub(crate) coin_selection: Cs, pub(crate) phantom: PhantomData, } /// The parameters for transaction creation sans coin selection algorithm. //TODO: TxParams should eventually be exposed publicly. #[derive(Default, Debug, Clone)] pub(crate) struct TxParams { pub(crate) recipients: Vec<(Script, u64)>, pub(crate) drain_wallet: bool, pub(crate) single_recipient: Option