bdk_wallet/wallet/tx_builder.rs
1// Bitcoin Dev Kit
2// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
3//
4// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
5//
6// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
7// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
9// You may not use this file except in accordance with one or both of these
10// licenses.
11
12//! Transaction builder
13//!
14//! ## Example
15//!
16//! ```
17//! # use std::str::FromStr;
18//! # use bitcoin::*;
19//! # use bdk_wallet::*;
20//! # use bdk_wallet::ChangeSet;
21//! # use bdk_wallet::error::CreateTxError;
22//! # use anyhow::Error;
23//! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
24//! # let mut wallet = doctest_wallet!();
25//! // create a TxBuilder from a wallet
26//! let mut tx_builder = wallet.build_tx();
27//!
28//! tx_builder
29//! // Create a transaction with one output to `to_address` of 50_000 satoshi
30//! .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000))
31//! // With a custom fee rate of 5.0 satoshi/vbyte
32//! .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate"))
33//! // Only spend non-change outputs
34//! .do_not_spend_change();
35//! let psbt = tx_builder.finish()?;
36//! # Ok::<(), anyhow::Error>(())
37//! ```
38
39use alloc::{boxed::Box, string::String, vec::Vec};
40use core::fmt;
41
42use alloc::sync::Arc;
43
44use bitcoin::psbt::{self, Psbt};
45use bitcoin::script::PushBytes;
46use bitcoin::{
47 absolute, transaction::Version, Amount, FeeRate, OutPoint, ScriptBuf, Sequence, Transaction,
48 TxIn, TxOut, Txid, Weight,
49};
50use rand_core::RngCore;
51
52use super::coin_selection::CoinSelectionAlgorithm;
53use super::utils::shuffle_slice;
54use super::{CreateTxError, Wallet};
55use crate::collections::{BTreeMap, HashMap, HashSet};
56use crate::{KeychainKind, LocalOutput, Utxo, WeightedUtxo};
57
58/// A transaction builder
59///
60/// A `TxBuilder` is created by calling [`build_tx`] or [`build_fee_bump`] on a wallet. After
61/// assigning it, you set options on it until finally calling [`finish`] to consume the builder and
62/// generate the transaction.
63///
64/// Each option setting method on `TxBuilder` takes and returns `&mut self` so you can chain calls
65/// as in the following example:
66///
67/// ```
68/// # use bdk_wallet::*;
69/// # use bdk_wallet::tx_builder::*;
70/// # use bitcoin::*;
71/// # use core::str::FromStr;
72/// # use bdk_wallet::ChangeSet;
73/// # use bdk_wallet::error::CreateTxError;
74/// # use anyhow::Error;
75/// # let mut wallet = doctest_wallet!();
76/// # let addr1 = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
77/// # let addr2 = addr1.clone();
78/// // chaining
79/// let psbt1 = {
80/// let mut builder = wallet.build_tx();
81/// builder
82/// .ordering(TxOrdering::Untouched)
83/// .add_recipient(addr1.script_pubkey(), Amount::from_sat(50_000))
84/// .add_recipient(addr2.script_pubkey(), Amount::from_sat(50_000));
85/// builder.finish()?
86/// };
87///
88/// // non-chaining
89/// let psbt2 = {
90/// let mut builder = wallet.build_tx();
91/// builder.ordering(TxOrdering::Untouched);
92/// for addr in &[addr1, addr2] {
93/// builder.add_recipient(addr.script_pubkey(), Amount::from_sat(50_000));
94/// }
95/// builder.finish()?
96/// };
97///
98/// assert_eq!(psbt1.unsigned_tx.output[..2], psbt2.unsigned_tx.output[..2]);
99/// # Ok::<(), anyhow::Error>(())
100/// ```
101///
102/// At the moment [`coin_selection`] is an exception to the rule as it consumes `self`.
103/// This means it is usually best to call [`coin_selection`] on the return value of `build_tx`
104/// before assigning it.
105///
106/// For further examples see [this module](super::tx_builder)'s documentation;
107///
108/// [`build_tx`]: Wallet::build_tx
109/// [`build_fee_bump`]: Wallet::build_fee_bump
110/// [`finish`]: Self::finish
111/// [`coin_selection`]: Self::coin_selection
112#[derive(Debug)]
113pub struct TxBuilder<'a, Cs> {
114 pub(crate) wallet: &'a mut Wallet,
115 pub(crate) params: TxParams,
116 pub(crate) coin_selection: Cs,
117}
118
119/// The parameters for transaction creation sans coin selection algorithm.
120//TODO: TxParams should eventually be exposed publicly.
121#[derive(Default, Debug, Clone)]
122pub(crate) struct TxParams {
123 pub(crate) recipients: Vec<(ScriptBuf, Amount)>,
124 pub(crate) drain_wallet: bool,
125 pub(crate) drain_to: Option<ScriptBuf>,
126 pub(crate) fee_policy: Option<FeePolicy>,
127 pub(crate) internal_policy_path: Option<BTreeMap<String, Vec<usize>>>,
128 pub(crate) external_policy_path: Option<BTreeMap<String, Vec<usize>>>,
129 pub(crate) utxos: Vec<WeightedUtxo>,
130 pub(crate) unspendable: HashSet<OutPoint>,
131 pub(crate) manually_selected_only: bool,
132 pub(crate) sighash: Option<psbt::PsbtSighashType>,
133 pub(crate) ordering: TxOrdering,
134 pub(crate) locktime: Option<absolute::LockTime>,
135 pub(crate) sequence: Option<Sequence>,
136 pub(crate) version: Option<Version>,
137 pub(crate) change_policy: ChangeSpendPolicy,
138 pub(crate) only_witness_utxo: bool,
139 pub(crate) add_global_xpubs: bool,
140 pub(crate) include_output_redeem_witness_script: bool,
141 pub(crate) bumping_fee: Option<PreviousFee>,
142 pub(crate) current_height: Option<absolute::LockTime>,
143 pub(crate) allow_dust: bool,
144}
145
146#[derive(Clone, Copy, Debug)]
147pub(crate) struct PreviousFee {
148 pub absolute: Amount,
149 pub rate: FeeRate,
150}
151
152#[derive(Debug, Clone, Copy)]
153pub(crate) enum FeePolicy {
154 FeeRate(FeeRate),
155 FeeAmount(Amount),
156}
157
158impl Default for FeePolicy {
159 fn default() -> Self {
160 FeePolicy::FeeRate(FeeRate::BROADCAST_MIN)
161 }
162}
163
164// Methods supported for any CoinSelectionAlgorithm.
165impl<'a, Cs> TxBuilder<'a, Cs> {
166 /// Set a custom fee rate.
167 ///
168 /// This method sets the mining fee paid by the transaction as a rate on its size.
169 /// This means that the total fee paid is equal to `fee_rate` times the size
170 /// of the transaction. Default is 1 sat/vB in accordance with Bitcoin Core's default
171 /// relay policy.
172 ///
173 /// Note that this is really a minimum feerate -- it's possible to
174 /// overshoot it slightly since adding a change output to drain the remaining
175 /// excess might not be viable.
176 pub fn fee_rate(&mut self, fee_rate: FeeRate) -> &mut Self {
177 self.params.fee_policy = Some(FeePolicy::FeeRate(fee_rate));
178 self
179 }
180
181 /// Set an absolute fee
182 /// The fee_absolute method refers to the absolute transaction fee in [`Amount`].
183 /// If anyone sets both the `fee_absolute` method and the `fee_rate` method,
184 /// the `FeePolicy` enum will be set by whichever method was called last,
185 /// as the [`FeeRate`] and `FeeAmount` are mutually exclusive.
186 ///
187 /// Note that this is really a minimum absolute fee -- it's possible to
188 /// overshoot it slightly since adding a change output to drain the remaining
189 /// excess might not be viable.
190 pub fn fee_absolute(&mut self, fee_amount: Amount) -> &mut Self {
191 self.params.fee_policy = Some(FeePolicy::FeeAmount(fee_amount));
192 self
193 }
194
195 /// Set the policy path to use while creating the transaction for a given keychain.
196 ///
197 /// This method accepts a map where the key is the policy node id (see
198 /// [`Policy::id`](crate::descriptor::Policy::id)) and the value is the list of the indexes of
199 /// the items that are intended to be satisfied from the policy node (see
200 /// [`SatisfiableItem::Thresh::items`](crate::descriptor::policy::SatisfiableItem::Thresh::items)).
201 ///
202 /// ## Example
203 ///
204 /// An example of when the policy path is needed is the following descriptor:
205 /// `wsh(thresh(2,pk(A),sj:and_v(v:pk(B),n:older(6)),snj:and_v(v:pk(C),after(630000))))`,
206 /// derived from the miniscript policy
207 /// `thresh(2,pk(A),and(pk(B),older(6)),and(pk(C),after(630000)))`. It declares three
208 /// descriptor fragments, and at the top level it uses `thresh()` to ensure that at least
209 /// two of them are satisfied. The individual fragments are:
210 ///
211 /// 1. `pk(A)`
212 /// 2. `and(pk(B),older(6))`
213 /// 3. `and(pk(C),after(630000))`
214 ///
215 /// When those conditions are combined in pairs, it's clear that the transaction needs to be
216 /// created differently depending on how the user intends to satisfy the policy afterwards:
217 ///
218 /// * If fragments `1` and `2` are used, the transaction will need to use a specific
219 /// `n_sequence` in order to spend an `OP_CSV` branch.
220 /// * If fragments `1` and `3` are used, the transaction will need to use a specific `locktime`
221 /// in order to spend an `OP_CLTV` branch.
222 /// * If fragments `2` and `3` are used, the transaction will need both.
223 ///
224 /// When the spending policy is represented as a tree (see
225 /// [`Wallet::policies`](super::Wallet::policies)), every node
226 /// is assigned a unique identifier that can be used in the policy path to specify which of
227 /// the node's children the user intends to satisfy: for instance, assuming the `thresh()`
228 /// root node of this example has an id of `aabbccdd`, the policy path map would look like:
229 ///
230 /// `{ "aabbccdd" => [0, 1] }`
231 ///
232 /// where the key is the node's id, and the value is a list of the children that should be
233 /// used, in no particular order.
234 ///
235 /// If a particularly complex descriptor has multiple ambiguous thresholds in its structure,
236 /// multiple entries can be added to the map, one for each node that requires an explicit path.
237 ///
238 /// ```
239 /// # use std::str::FromStr;
240 /// # use std::collections::BTreeMap;
241 /// # use bitcoin::*;
242 /// # use bdk_wallet::*;
243 /// # let to_address =
244 /// Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
245 /// .unwrap()
246 /// .assume_checked();
247 /// # let mut wallet = doctest_wallet!();
248 /// let mut path = BTreeMap::new();
249 /// path.insert("aabbccdd".to_string(), vec![0, 1]);
250 ///
251 /// let builder = wallet
252 /// .build_tx()
253 /// .add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000))
254 /// .policy_path(path, KeychainKind::External);
255 ///
256 /// # Ok::<(), anyhow::Error>(())
257 /// ```
258 pub fn policy_path(
259 &mut self,
260 policy_path: BTreeMap<String, Vec<usize>>,
261 keychain: KeychainKind,
262 ) -> &mut Self {
263 let to_update = match keychain {
264 KeychainKind::Internal => &mut self.params.internal_policy_path,
265 KeychainKind::External => &mut self.params.external_policy_path,
266 };
267
268 *to_update = Some(policy_path);
269 self
270 }
271
272 /// Add the list of outpoints to the internal list of UTXOs that **must** be spent.
273 ///
274 /// If an error occurs while adding any of the UTXOs then none of them are added and the error
275 /// is returned.
276 ///
277 /// These have priority over the "unspendable" UTXOs, meaning that if a UTXO is present both in
278 /// the "UTXOs" and the "unspendable" list, it will be spent.
279 ///
280 /// If a UTXO is inserted multiple times, only the final insertion will take effect.
281 pub fn add_utxos(&mut self, outpoints: &[OutPoint]) -> Result<&mut Self, AddUtxoError> {
282 // Canonicalize once, instead of once for every call to `get_utxo`.
283 let unspent: HashMap<OutPoint, LocalOutput> = self
284 .wallet
285 .list_unspent()
286 .map(|output| (output.outpoint, output))
287 .collect();
288
289 // Ensure that only unique outpoints are added, but keep insertion order.
290 let mut visited = <HashSet<OutPoint>>::new();
291
292 let utxos: Vec<WeightedUtxo> = outpoints
293 .iter()
294 .filter(|&&op| visited.insert(op))
295 .map(|&op| -> Result<_, AddUtxoError> {
296 let output = unspent
297 .get(&op)
298 .cloned()
299 .ok_or(AddUtxoError::UnknownUtxo(op))?;
300 Ok(WeightedUtxo {
301 satisfaction_weight: self
302 .wallet
303 .public_descriptor(output.keychain)
304 .max_weight_to_satisfy()
305 .expect("descriptor should be satisfiable"),
306 utxo: Utxo::Local(output),
307 })
308 })
309 .collect::<Result<_, _>>()?;
310
311 // Remove already inserted UTXOs first.
312 self.params
313 .utxos
314 .retain(|wutxo| !visited.contains(&wutxo.utxo.outpoint()));
315
316 // Update the removed UTXOs in their new positions.
317 self.params.utxos.extend_from_slice(&utxos);
318
319 Ok(self)
320 }
321
322 /// Add a UTXO to the internal list of UTXOs that **must** be spent
323 ///
324 /// These have priority over the "unspendable" UTXOs, meaning that if a UTXO is present both in
325 /// the "UTXOs" and the "unspendable" list, it will be spent.
326 pub fn add_utxo(&mut self, outpoint: OutPoint) -> Result<&mut Self, AddUtxoError> {
327 self.add_utxos(&[outpoint])
328 }
329
330 /// Add a foreign UTXO i.e. a UTXO not known by this wallet.
331 ///
332 /// Foreign UTXOs are not prioritized over local UTXOs. If a local UTXO is added to the
333 /// manually selected list, it will replace any conflicting foreign UTXOs. However, a foreign
334 /// UTXO cannot replace a conflicting local UTXO.
335 ///
336 /// There might be cases where the UTXO belongs to the wallet but it doesn't have knowledge of
337 /// it. This is possible if the wallet is not synced or its not being use to track
338 /// transactions. In those cases is the responsibility of the user to add any possible local
339 /// UTXOs through the [`TxBuilder::add_utxo`] method.
340 /// A manually added local UTXO will always have greater precedence than a foreign UTXO. No
341 /// matter if it was added before or after the foreign UTXO.
342 ///
343 /// At a minimum to add a foreign UTXO we need:
344 ///
345 /// 1. `outpoint`: To add it to the raw transaction.
346 /// 2. `psbt_input`: To know the value.
347 /// 3. `satisfaction_weight`: To know how much weight/vbytes the input will add to the
348 /// transaction for fee calculation.
349 ///
350 /// There are several security concerns about adding foreign UTXOs that application
351 /// developers should consider. First, how do you know the value of the input is correct? If a
352 /// `non_witness_utxo` is provided in the `psbt_input` then this method implicitly verifies the
353 /// value by checking it against the transaction. If only a `witness_utxo` is provided then this
354 /// method doesn't verify the value but just takes it as a given -- it is up to you to check
355 /// that whoever sent you the `input_psbt` was not lying!
356 ///
357 /// Secondly, you must somehow provide `satisfaction_weight` of the input. Depending on your
358 /// application it may be important that this be known precisely. If not, a malicious
359 /// counterparty may fool you into putting in a value that is too low, giving the transaction a
360 /// lower than expected feerate. They could also fool you into putting a value that is too high
361 /// causing you to pay a fee that is too high. The party who is broadcasting the transaction can
362 /// of course check the real input weight matches the expected weight prior to broadcasting.
363 ///
364 /// To guarantee the `max_weight_to_satisfy` is correct, you can require the party providing the
365 /// `psbt_input` provide a miniscript descriptor for the input so you can check it against the
366 /// `script_pubkey` and then ask it for the [`max_weight_to_satisfy`].
367 ///
368 /// This is an **EXPERIMENTAL** feature, API and other major changes are expected.
369 ///
370 /// In order to use [`Wallet::calculate_fee`] or [`Wallet::calculate_fee_rate`] for a
371 /// transaction created with foreign UTXO(s) you must manually insert the corresponding
372 /// TxOut(s) into the tx graph using the [`Wallet::insert_txout`] function.
373 ///
374 /// # Errors
375 ///
376 /// This method returns errors in the following circumstances:
377 ///
378 /// 1. The `psbt_input` does not contain a `witness_utxo` or `non_witness_utxo`.
379 /// 2. The data in `non_witness_utxo` does not match what is in `outpoint`.
380 ///
381 /// Note unless you set [`only_witness_utxo`] any non-taproot `psbt_input` you pass to this
382 /// method must have `non_witness_utxo` set otherwise you will get an error when [`finish`]
383 /// is called.
384 ///
385 /// [`only_witness_utxo`]: Self::only_witness_utxo
386 /// [`finish`]: Self::finish
387 /// [`max_weight_to_satisfy`]: miniscript::Descriptor::max_weight_to_satisfy
388 pub fn add_foreign_utxo(
389 &mut self,
390 outpoint: OutPoint,
391 psbt_input: psbt::Input,
392 satisfaction_weight: Weight,
393 ) -> Result<&mut Self, AddForeignUtxoError> {
394 self.add_foreign_utxo_with_sequence(
395 outpoint,
396 psbt_input,
397 satisfaction_weight,
398 Sequence::MAX,
399 )
400 }
401
402 /// Same as [add_foreign_utxo](TxBuilder::add_foreign_utxo) but allows to set the nSequence
403 /// value.
404 pub fn add_foreign_utxo_with_sequence(
405 &mut self,
406 outpoint: OutPoint,
407 psbt_input: psbt::Input,
408 satisfaction_weight: Weight,
409 sequence: Sequence,
410 ) -> Result<&mut Self, AddForeignUtxoError> {
411 if psbt_input.witness_utxo.is_none() {
412 match psbt_input.non_witness_utxo.as_ref() {
413 Some(tx) => {
414 if tx.compute_txid() != outpoint.txid {
415 return Err(AddForeignUtxoError::InvalidTxid {
416 input_txid: tx.compute_txid(),
417 foreign_utxo: outpoint,
418 });
419 }
420 if tx.output.len() <= outpoint.vout as usize {
421 return Err(AddForeignUtxoError::InvalidOutpoint(outpoint));
422 }
423 }
424 None => {
425 return Err(AddForeignUtxoError::MissingUtxo);
426 }
427 }
428 }
429
430 let mut existing_index: Option<usize> = None;
431
432 for (idx, wutxo) in self.params.utxos.iter().enumerate() {
433 if wutxo.utxo.outpoint() == outpoint {
434 match wutxo.utxo {
435 Utxo::Local(..) => return Ok(self),
436 Utxo::Foreign { .. } => {
437 existing_index = Some(idx);
438 break;
439 }
440 }
441 }
442 }
443
444 if let Some(idx) = existing_index {
445 self.params.utxos.remove(idx);
446 }
447
448 self.params.utxos.push(WeightedUtxo {
449 satisfaction_weight,
450 utxo: Utxo::Foreign {
451 outpoint,
452 sequence,
453 psbt_input: Box::new(psbt_input),
454 },
455 });
456
457 Ok(self)
458 }
459
460 /// Only spend utxos added by [`add_utxo`].
461 ///
462 /// The wallet will **not** add additional utxos to the transaction even if they are needed to
463 /// make the transaction valid.
464 ///
465 /// [`add_utxo`]: Self::add_utxo
466 pub fn manually_selected_only(&mut self) -> &mut Self {
467 self.params.manually_selected_only = true;
468 self
469 }
470
471 /// Replace the internal list of unspendable utxos with a new list
472 ///
473 /// It's important to note that the "must-be-spent" utxos added with [`TxBuilder::add_utxo`]
474 /// have priority over these. See the docs of the two linked methods for more details.
475 pub fn unspendable(&mut self, unspendable: Vec<OutPoint>) -> &mut Self {
476 self.params.unspendable = unspendable.into_iter().collect();
477 self
478 }
479
480 /// Add a utxo to the internal list of unspendable utxos
481 ///
482 /// It's important to note that the "must-be-spent" utxos added with [`TxBuilder::add_utxo`]
483 /// have priority over this. See the docs of the two linked methods for more details.
484 pub fn add_unspendable(&mut self, unspendable: OutPoint) -> &mut Self {
485 self.params.unspendable.insert(unspendable);
486 self
487 }
488
489 /// Excludes any outpoints whose enclosing transaction has fewer than `min_confirms`
490 /// confirmations.
491 ///
492 /// `min_confirms` is the minimum number of confirmations a transaction must have in order for
493 /// its outpoints to remain spendable.
494 /// - Passing `0` will include all transactions (no filtering).
495 /// - Passing `1` will exclude all unconfirmed transactions (equivalent to
496 /// `exclude_unconfirmed`).
497 /// - Passing `6` will only allow outpoints from transactions with at least 6 confirmations.
498 ///
499 /// If you chain this with other filtering methods, the final set of unspendable outpoints will
500 /// be the union of all filters.
501 pub fn exclude_below_confirmations(&mut self, min_confirms: u32) -> &mut Self {
502 let tip_height = self.wallet.latest_checkpoint().height();
503 let to_exclude = self
504 .wallet
505 .list_unspent()
506 .filter(|utxo| {
507 utxo.chain_position
508 .confirmation_height_upper_bound()
509 .map_or(0, |h| tip_height.saturating_add(1).saturating_sub(h))
510 < min_confirms
511 })
512 .map(|utxo| utxo.outpoint);
513 for op in to_exclude {
514 self.params.unspendable.insert(op);
515 }
516 self
517 }
518
519 /// Exclude outpoints whose enclosing transaction is unconfirmed.
520 ///
521 /// This is a shorthand for [`exclude_below_confirmations(1)`].
522 ///
523 /// [`exclude_below_confirmations(1)`]: Self::exclude_below_confirmations
524 pub fn exclude_unconfirmed(&mut self) -> &mut Self {
525 self.exclude_below_confirmations(1)
526 }
527
528 /// Sign with a specific sig hash
529 ///
530 /// **Use this option very carefully**
531 pub fn sighash(&mut self, sighash: psbt::PsbtSighashType) -> &mut Self {
532 self.params.sighash = Some(sighash);
533 self
534 }
535
536 /// Choose the ordering for inputs and outputs of the transaction
537 ///
538 /// When [TxBuilder::ordering] is set to [TxOrdering::Untouched], the insertion order of
539 /// recipients and manually selected UTXOs is preserved and reflected exactly in transaction's
540 /// output and input vectors respectively. If algorithmically selected UTXOs are included, they
541 /// will be placed after all the manually selected ones in the transaction's input vector.
542 pub fn ordering(&mut self, ordering: TxOrdering) -> &mut Self {
543 self.params.ordering = ordering;
544 self
545 }
546
547 /// Use a specific nLockTime while creating the transaction
548 ///
549 /// This can cause conflicts if the wallet's descriptors contain an "after" (OP_CLTV) operator.
550 pub fn nlocktime(&mut self, locktime: absolute::LockTime) -> &mut Self {
551 self.params.locktime = Some(locktime);
552 self
553 }
554
555 /// Build a transaction with a specific version
556 ///
557 /// The `version` should always be greater than `0` and greater than `1` if the wallet's
558 /// descriptors contain an "older" (OP_CSV) operator.
559 pub fn version(&mut self, version: i32) -> &mut Self {
560 self.params.version = Some(Version(version));
561 self
562 }
563
564 /// Do not spend change outputs
565 ///
566 /// This effectively adds all the change outputs to the "unspendable" list. See
567 /// [`TxBuilder::unspendable`]. This method assumes the presence of an internal
568 /// keychain, otherwise it has no effect.
569 pub fn do_not_spend_change(&mut self) -> &mut Self {
570 self.params.change_policy = ChangeSpendPolicy::ChangeForbidden;
571 self
572 }
573
574 /// Only spend change outputs
575 ///
576 /// This effectively adds all the non-change outputs to the "unspendable" list. See
577 /// [`TxBuilder::unspendable`]. This method assumes the presence of an internal
578 /// keychain, otherwise it has no effect.
579 pub fn only_spend_change(&mut self) -> &mut Self {
580 self.params.change_policy = ChangeSpendPolicy::OnlyChange;
581 self
582 }
583
584 /// Set a specific [`ChangeSpendPolicy`]. See [`TxBuilder::do_not_spend_change`] and
585 /// [`TxBuilder::only_spend_change`] for some shortcuts. This method assumes the presence
586 /// of an internal keychain, otherwise it has no effect.
587 pub fn change_policy(&mut self, change_policy: ChangeSpendPolicy) -> &mut Self {
588 self.params.change_policy = change_policy;
589 self
590 }
591
592 /// Only Fill-in the [`psbt::Input::witness_utxo`](bitcoin::psbt::Input::witness_utxo) field
593 /// when spending from SegWit descriptors.
594 ///
595 /// This reduces the size of the PSBT, but some signers might reject them due to the lack of
596 /// the `non_witness_utxo`.
597 pub fn only_witness_utxo(&mut self) -> &mut Self {
598 self.params.only_witness_utxo = true;
599 self
600 }
601
602 /// Fill-in the [`psbt::Output::redeem_script`](bitcoin::psbt::Output::redeem_script) and
603 /// [`psbt::Output::witness_script`](bitcoin::psbt::Output::witness_script) fields.
604 ///
605 /// This is useful for signers which always require it, like ColdCard hardware wallets.
606 pub fn include_output_redeem_witness_script(&mut self) -> &mut Self {
607 self.params.include_output_redeem_witness_script = true;
608 self
609 }
610
611 /// Fill-in the `PSBT_GLOBAL_XPUB` field with the extended keys contained in both the external
612 /// and internal descriptors
613 ///
614 /// This is useful for offline signers that take part to a multisig. Some hardware wallets like
615 /// BitBox and ColdCard are known to require this.
616 pub fn add_global_xpubs(&mut self) -> &mut Self {
617 self.params.add_global_xpubs = true;
618 self
619 }
620
621 /// Spend all the available inputs. This respects filters like [`TxBuilder::unspendable`] and
622 /// the change policy.
623 pub fn drain_wallet(&mut self) -> &mut Self {
624 self.params.drain_wallet = true;
625 self
626 }
627
628 /// Choose the coin selection algorithm
629 ///
630 /// Overrides the [`CoinSelectionAlgorithm`].
631 ///
632 /// Note that this function consumes the builder and returns it so it is usually best to put
633 /// this as the first call on the builder.
634 pub fn coin_selection<P: CoinSelectionAlgorithm>(self, coin_selection: P) -> TxBuilder<'a, P> {
635 TxBuilder {
636 wallet: self.wallet,
637 params: self.params,
638 coin_selection,
639 }
640 }
641
642 /// Set an exact nSequence value
643 ///
644 /// This can cause conflicts if the wallet's descriptors contain an
645 /// "older" (OP_CSV) operator and the given `nsequence` is lower than the CSV value.
646 pub fn set_exact_sequence(&mut self, n_sequence: Sequence) -> &mut Self {
647 self.params.sequence = Some(n_sequence);
648 self
649 }
650
651 /// Set the current blockchain height.
652 ///
653 /// This will be used to:
654 /// 1. Set the nLockTime for preventing fee sniping. **Note**: This will be ignored if you
655 /// manually specify a nlocktime using [`TxBuilder::nlocktime`].
656 /// 2. Decide whether coinbase outputs are mature or not. If the coinbase outputs are not mature
657 /// at spending height, which is `current_height` + 1, we ignore them in the coin selection.
658 /// If you want to create a transaction that spends immature coinbase inputs, manually add
659 /// them using [`TxBuilder::add_utxos`].
660 ///
661 /// In both cases, if you don't provide a current height, we use the last sync height.
662 pub fn current_height(&mut self, height: u32) -> &mut Self {
663 self.params.current_height =
664 Some(absolute::LockTime::from_height(height).expect("Invalid height"));
665 self
666 }
667
668 /// Set whether or not the dust limit is checked.
669 ///
670 /// **Note**: by avoiding a dust limit check you may end up with a transaction that is
671 /// non-standard.
672 pub fn allow_dust(&mut self, allow_dust: bool) -> &mut Self {
673 self.params.allow_dust = allow_dust;
674 self
675 }
676
677 /// Replace the recipients already added with a new list
678 pub fn set_recipients(&mut self, recipients: Vec<(ScriptBuf, Amount)>) -> &mut Self {
679 self.params.recipients = recipients;
680 self
681 }
682
683 /// Add a recipient to the internal list
684 pub fn add_recipient(
685 &mut self,
686 script_pubkey: impl Into<ScriptBuf>,
687 amount: Amount,
688 ) -> &mut Self {
689 self.params.recipients.push((script_pubkey.into(), amount));
690 self
691 }
692
693 /// Add data as an output, using OP_RETURN
694 pub fn add_data<T: AsRef<PushBytes>>(&mut self, data: &T) -> &mut Self {
695 let script = ScriptBuf::new_op_return(data);
696 self.add_recipient(script, Amount::ZERO);
697 self
698 }
699
700 /// Sets the address to *drain* excess coins to.
701 ///
702 /// Usually, when there are excess coins they are sent to a change address generated by the
703 /// wallet. This option replaces the usual change address with an arbitrary `script_pubkey` of
704 /// your choosing. Just as with a change output, if the drain output is not needed (the excess
705 /// coins are too small) it will not be included in the resulting transaction. The only
706 /// difference is that it is valid to use `drain_to` without setting any ordinary recipients
707 /// with [`add_recipient`] (but it is perfectly fine to add recipients as well).
708 ///
709 /// If you choose not to set any recipients, you should provide the utxos that the
710 /// transaction should spend via [`add_utxos`].
711 ///
712 /// # Example
713 ///
714 /// `drain_to` is very useful for draining all the coins in a wallet with [`drain_wallet`] to a
715 /// single address.
716 ///
717 /// ```
718 /// # use std::str::FromStr;
719 /// # use bitcoin::*;
720 /// # use bdk_wallet::*;
721 /// # use bdk_wallet::ChangeSet;
722 /// # use bdk_wallet::error::CreateTxError;
723 /// # use anyhow::Error;
724 /// # let to_address =
725 /// Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
726 /// .unwrap()
727 /// .assume_checked();
728 /// # let mut wallet = doctest_wallet!();
729 /// let mut tx_builder = wallet.build_tx();
730 ///
731 /// tx_builder
732 /// // Spend all outputs in this wallet.
733 /// .drain_wallet()
734 /// // Send the excess (which is all the coins minus the fee) to this address.
735 /// .drain_to(to_address.script_pubkey())
736 /// .fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate"));
737 /// let psbt = tx_builder.finish()?;
738 /// # Ok::<(), anyhow::Error>(())
739 /// ```
740 ///
741 /// [`add_recipient`]: Self::add_recipient
742 /// [`add_utxos`]: Self::add_utxos
743 /// [`drain_wallet`]: Self::drain_wallet
744 pub fn drain_to(&mut self, script_pubkey: ScriptBuf) -> &mut Self {
745 self.params.drain_to = Some(script_pubkey);
746 self
747 }
748}
749
750impl<Cs: CoinSelectionAlgorithm> TxBuilder<'_, Cs> {
751 /// Finish building the transaction.
752 ///
753 /// Uses the thread-local random number generator (rng).
754 ///
755 /// Returns a new [`Psbt`] per [`BIP174`].
756 ///
757 /// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
758 ///
759 /// **WARNING**: To avoid change address reuse you must persist the changes resulting from one
760 /// or more calls to this method before closing the wallet. See [`Wallet::reveal_next_address`].
761 #[cfg(feature = "std")]
762 pub fn finish(self) -> Result<Psbt, CreateTxError> {
763 self.finish_with_aux_rand(&mut bitcoin::key::rand::thread_rng())
764 }
765
766 /// Finish building the transaction.
767 ///
768 /// Uses a provided random number generator (rng).
769 ///
770 /// Returns a new [`Psbt`] per [`BIP174`].
771 ///
772 /// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
773 ///
774 /// **WARNING**: To avoid change address reuse you must persist the changes resulting from one
775 /// or more calls to this method before closing the wallet. See [`Wallet::reveal_next_address`].
776 pub fn finish_with_aux_rand(self, rng: &mut impl RngCore) -> Result<Psbt, CreateTxError> {
777 self.wallet.create_tx(self.coin_selection, self.params, rng)
778 }
779}
780
781#[derive(Debug)]
782/// Error returned from [`TxBuilder::add_utxo`] and [`TxBuilder::add_utxos`]
783pub enum AddUtxoError {
784 /// Happens when trying to spend an UTXO that is not in the internal database
785 UnknownUtxo(OutPoint),
786}
787
788impl fmt::Display for AddUtxoError {
789 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
790 match self {
791 Self::UnknownUtxo(outpoint) => write!(
792 f,
793 "UTXO not found in the internal database for txid: {} with vout: {}",
794 outpoint.txid, outpoint.vout
795 ),
796 }
797 }
798}
799
800#[cfg(feature = "std")]
801impl std::error::Error for AddUtxoError {}
802
803#[derive(Debug)]
804/// Error returned from [`TxBuilder::add_foreign_utxo`].
805pub enum AddForeignUtxoError {
806 /// Foreign utxo outpoint txid does not match PSBT input txid
807 InvalidTxid {
808 /// PSBT input txid
809 input_txid: Txid,
810 /// Foreign UTXO outpoint
811 foreign_utxo: OutPoint,
812 },
813 /// Requested outpoint doesn't exist in the tx (vout greater than available outputs)
814 InvalidOutpoint(OutPoint),
815 /// Foreign utxo missing witness_utxo or non_witness_utxo
816 MissingUtxo,
817}
818
819impl fmt::Display for AddForeignUtxoError {
820 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
821 match self {
822 Self::InvalidTxid {
823 input_txid,
824 foreign_utxo,
825 } => write!(
826 f,
827 "Foreign UTXO outpoint txid: {} does not match PSBT input txid: {}",
828 foreign_utxo.txid, input_txid,
829 ),
830 Self::InvalidOutpoint(outpoint) => write!(
831 f,
832 "Requested outpoint doesn't exist for txid: {} with vout: {}",
833 outpoint.txid, outpoint.vout,
834 ),
835 Self::MissingUtxo => write!(f, "Foreign utxo missing witness_utxo or non_witness_utxo"),
836 }
837 }
838}
839
840#[cfg(feature = "std")]
841impl std::error::Error for AddForeignUtxoError {}
842
843type TxSort<T> = dyn (Fn(&T, &T) -> core::cmp::Ordering) + Send + Sync;
844
845/// Ordering of the transaction's inputs and outputs
846#[derive(Clone, Default)]
847pub enum TxOrdering {
848 /// Randomized (default)
849 #[default]
850 Shuffle,
851 /// Unchanged
852 ///
853 /// Unchanged insertion order for recipients and for manually added UTXOs. This guarantees all
854 /// recipients preserve insertion order in the transaction's output vector and manually added
855 /// UTXOs preserve insertion order in the transaction's input vector, but does not make any
856 /// guarantees about algorithmically selected UTXOs. However, by design they will always be
857 /// placed after the manually selected ones.
858 Untouched,
859 /// Provide custom comparison functions for sorting
860 Custom {
861 /// Transaction inputs sort function
862 input_sort: Arc<TxSort<TxIn>>,
863 /// Transaction outputs sort function
864 output_sort: Arc<TxSort<TxOut>>,
865 },
866}
867
868impl core::fmt::Debug for TxOrdering {
869 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
870 match self {
871 TxOrdering::Shuffle => write!(f, "Shuffle"),
872 TxOrdering::Untouched => write!(f, "Untouched"),
873 TxOrdering::Custom { .. } => write!(f, "Custom"),
874 }
875 }
876}
877
878impl TxOrdering {
879 /// Sort transaction inputs and outputs by [`TxOrdering`] variant.
880 ///
881 /// Uses the thread-local random number generator (rng).
882 #[cfg(feature = "std")]
883 pub fn sort_tx(&self, tx: &mut Transaction) {
884 self.sort_tx_with_aux_rand(tx, &mut bitcoin::key::rand::thread_rng())
885 }
886
887 /// Sort transaction inputs and outputs by [`TxOrdering`] variant.
888 ///
889 /// Uses a provided random number generator (rng).
890 pub fn sort_tx_with_aux_rand(&self, tx: &mut Transaction, rng: &mut impl RngCore) {
891 match self {
892 TxOrdering::Untouched => {}
893 TxOrdering::Shuffle => {
894 shuffle_slice(&mut tx.input, rng);
895 shuffle_slice(&mut tx.output, rng);
896 }
897 TxOrdering::Custom {
898 input_sort,
899 output_sort,
900 } => {
901 tx.input.sort_unstable_by(|a, b| input_sort(a, b));
902 tx.output.sort_unstable_by(|a, b| output_sort(a, b));
903 }
904 }
905 }
906}
907
908/// Policy regarding the use of change outputs when creating a transaction
909#[derive(Default, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
910pub enum ChangeSpendPolicy {
911 /// Use both change and non-change outputs (default)
912 #[default]
913 ChangeAllowed,
914 /// Only use change outputs (see [`TxBuilder::only_spend_change`])
915 OnlyChange,
916 /// Only use non-change outputs (see [`TxBuilder::do_not_spend_change`])
917 ChangeForbidden,
918}
919
920impl ChangeSpendPolicy {
921 pub(crate) fn is_satisfied_by(&self, utxo: &LocalOutput) -> bool {
922 match self {
923 ChangeSpendPolicy::ChangeAllowed => true,
924 ChangeSpendPolicy::OnlyChange => utxo.keychain == KeychainKind::Internal,
925 ChangeSpendPolicy::ChangeForbidden => utxo.keychain == KeychainKind::External,
926 }
927 }
928}
929
930#[cfg(test)]
931mod test {
932 const ORDERING_TEST_TX: &str = "0200000003c26f3eb7932f7acddc5ddd26602b77e7516079b03090a16e2c2f54\
933 85d1fd600f0100000000ffffffffc26f3eb7932f7acddc5ddd26602b77e75160\
934 79b03090a16e2c2f5485d1fd600f0000000000ffffffff571fb3e02278217852\
935 dd5d299947e2b7354a639adc32ec1fa7b82cfb5dec530e0500000000ffffffff\
936 03e80300000000000002aaeee80300000000000001aa200300000000000001ff\
937 00000000";
938 macro_rules! ordering_test_tx {
939 () => {
940 deserialize::<bitcoin::Transaction>(&Vec::<u8>::from_hex(ORDERING_TEST_TX).unwrap())
941 .unwrap()
942 };
943 }
944
945 use bitcoin::consensus::deserialize;
946 use bitcoin::hex::FromHex;
947 use bitcoin::TxOut;
948
949 use super::*;
950 #[test]
951 fn test_output_ordering_untouched() {
952 let original_tx = ordering_test_tx!();
953 let mut tx = original_tx.clone();
954
955 TxOrdering::Untouched.sort_tx(&mut tx);
956
957 assert_eq!(original_tx, tx);
958 }
959
960 #[test]
961 fn test_output_ordering_shuffle() {
962 let original_tx = ordering_test_tx!();
963 let mut tx = original_tx.clone();
964
965 (0..40)
966 .find(|_| {
967 TxOrdering::Shuffle.sort_tx(&mut tx);
968 original_tx.input != tx.input
969 })
970 .expect("it should have moved the inputs at least once");
971
972 let mut tx = original_tx.clone();
973 (0..40)
974 .find(|_| {
975 TxOrdering::Shuffle.sort_tx(&mut tx);
976 original_tx.output != tx.output
977 })
978 .expect("it should have moved the outputs at least once");
979 }
980
981 #[test]
982 fn test_output_ordering_custom_but_bip69() {
983 use core::str::FromStr;
984
985 let original_tx = ordering_test_tx!();
986 let mut tx = original_tx;
987
988 let bip69_txin_cmp = |tx_a: &TxIn, tx_b: &TxIn| {
989 let project_outpoint = |t: &TxIn| (t.previous_output.txid, t.previous_output.vout);
990 project_outpoint(tx_a).cmp(&project_outpoint(tx_b))
991 };
992
993 let bip69_txout_cmp = |tx_a: &TxOut, tx_b: &TxOut| {
994 let project_utxo = |t: &TxOut| (t.value, t.script_pubkey.clone());
995 project_utxo(tx_a).cmp(&project_utxo(tx_b))
996 };
997
998 let custom_bip69_ordering = TxOrdering::Custom {
999 input_sort: Arc::new(bip69_txin_cmp),
1000 output_sort: Arc::new(bip69_txout_cmp),
1001 };
1002
1003 custom_bip69_ordering.sort_tx(&mut tx);
1004
1005 assert_eq!(
1006 tx.input[0].previous_output,
1007 bitcoin::OutPoint::from_str(
1008 "0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57:5"
1009 )
1010 .unwrap()
1011 );
1012 assert_eq!(
1013 tx.input[1].previous_output,
1014 bitcoin::OutPoint::from_str(
1015 "0f60fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2:0"
1016 )
1017 .unwrap()
1018 );
1019 assert_eq!(
1020 tx.input[2].previous_output,
1021 bitcoin::OutPoint::from_str(
1022 "0f60fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2:1"
1023 )
1024 .unwrap()
1025 );
1026
1027 assert_eq!(tx.output[0].value.to_sat(), 800);
1028 assert_eq!(tx.output[1].script_pubkey, ScriptBuf::from(vec![0xAA]));
1029 assert_eq!(
1030 tx.output[2].script_pubkey,
1031 ScriptBuf::from(vec![0xAA, 0xEE])
1032 );
1033 }
1034
1035 #[test]
1036 fn test_output_ordering_custom_with_sha256() {
1037 use bitcoin::hashes::{sha256, Hash};
1038
1039 let original_tx = ordering_test_tx!();
1040 let mut tx_1 = original_tx.clone();
1041 let mut tx_2 = original_tx.clone();
1042 let shared_secret = "secret_tweak";
1043
1044 let hash_txin_with_shared_secret_seed = Arc::new(|tx_a: &TxIn, tx_b: &TxIn| {
1045 let secret_digest_from_txin = |txin: &TxIn| {
1046 sha256::Hash::hash(
1047 &[
1048 &txin.previous_output.txid.to_raw_hash()[..],
1049 &txin.previous_output.vout.to_be_bytes(),
1050 shared_secret.as_bytes(),
1051 ]
1052 .concat(),
1053 )
1054 };
1055 secret_digest_from_txin(tx_a).cmp(&secret_digest_from_txin(tx_b))
1056 });
1057
1058 let hash_txout_with_shared_secret_seed = Arc::new(|tx_a: &TxOut, tx_b: &TxOut| {
1059 let secret_digest_from_txout = |txin: &TxOut| {
1060 sha256::Hash::hash(
1061 &[
1062 &txin.value.to_sat().to_be_bytes(),
1063 &txin.script_pubkey.clone().into_bytes()[..],
1064 shared_secret.as_bytes(),
1065 ]
1066 .concat(),
1067 )
1068 };
1069 secret_digest_from_txout(tx_a).cmp(&secret_digest_from_txout(tx_b))
1070 });
1071
1072 let custom_ordering_from_salted_sha256_1 = TxOrdering::Custom {
1073 input_sort: hash_txin_with_shared_secret_seed.clone(),
1074 output_sort: hash_txout_with_shared_secret_seed.clone(),
1075 };
1076
1077 let custom_ordering_from_salted_sha256_2 = TxOrdering::Custom {
1078 input_sort: hash_txin_with_shared_secret_seed,
1079 output_sort: hash_txout_with_shared_secret_seed,
1080 };
1081
1082 custom_ordering_from_salted_sha256_1.sort_tx(&mut tx_1);
1083 custom_ordering_from_salted_sha256_2.sort_tx(&mut tx_2);
1084
1085 // Check the ordering is consistent between calls
1086 assert_eq!(tx_1, tx_2);
1087 // Check transaction order has changed
1088 assert_ne!(tx_1, original_tx);
1089 assert_ne!(tx_2, original_tx);
1090 }
1091
1092 fn get_test_utxos() -> Vec<LocalOutput> {
1093 use bitcoin::hashes::Hash;
1094
1095 vec![
1096 LocalOutput {
1097 outpoint: OutPoint {
1098 txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(),
1099 vout: 0,
1100 },
1101 txout: TxOut::NULL,
1102 keychain: KeychainKind::External,
1103 is_spent: false,
1104 chain_position: chain::ChainPosition::Unconfirmed {
1105 first_seen: Some(1),
1106 last_seen: Some(1),
1107 },
1108 derivation_index: 0,
1109 },
1110 LocalOutput {
1111 outpoint: OutPoint {
1112 txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(),
1113 vout: 1,
1114 },
1115 txout: TxOut::NULL,
1116 keychain: KeychainKind::Internal,
1117 is_spent: false,
1118 chain_position: chain::ChainPosition::Confirmed {
1119 anchor: chain::ConfirmationBlockTime {
1120 block_id: chain::BlockId {
1121 height: 32,
1122 hash: bitcoin::BlockHash::all_zeros(),
1123 },
1124 confirmation_time: 42,
1125 },
1126 transitively: None,
1127 },
1128 derivation_index: 1,
1129 },
1130 ]
1131 }
1132
1133 #[test]
1134 fn test_change_spend_policy_default() {
1135 let change_spend_policy = ChangeSpendPolicy::default();
1136 let filtered = get_test_utxos()
1137 .into_iter()
1138 .filter(|u| change_spend_policy.is_satisfied_by(u))
1139 .count();
1140
1141 assert_eq!(filtered, 2);
1142 }
1143
1144 #[test]
1145 fn test_change_spend_policy_no_internal() {
1146 let change_spend_policy = ChangeSpendPolicy::ChangeForbidden;
1147 let filtered = get_test_utxos()
1148 .into_iter()
1149 .filter(|u| change_spend_policy.is_satisfied_by(u))
1150 .collect::<Vec<_>>();
1151
1152 assert_eq!(filtered.len(), 1);
1153 assert_eq!(filtered[0].keychain, KeychainKind::External);
1154 }
1155
1156 #[test]
1157 fn test_change_spend_policy_only_internal() {
1158 let change_spend_policy = ChangeSpendPolicy::OnlyChange;
1159 let filtered = get_test_utxos()
1160 .into_iter()
1161 .filter(|u| change_spend_policy.is_satisfied_by(u))
1162 .collect::<Vec<_>>();
1163
1164 assert_eq!(filtered.len(), 1);
1165 assert_eq!(filtered[0].keychain, KeychainKind::Internal);
1166 }
1167
1168 #[test]
1169 fn test_exclude_unconfirmed() {
1170 use crate::test_utils::*;
1171 use bdk_chain::BlockId;
1172 use bitcoin::{hashes::Hash, BlockHash, Network};
1173
1174 let mut wallet = Wallet::create_single(get_test_tr_single_sig())
1175 .network(Network::Regtest)
1176 .create_wallet_no_persist()
1177 .unwrap();
1178 let recipient = wallet.next_unused_address(KeychainKind::External).address;
1179
1180 insert_checkpoint(
1181 &mut wallet,
1182 BlockId {
1183 height: 1,
1184 hash: BlockHash::all_zeros(),
1185 },
1186 );
1187 insert_checkpoint(
1188 &mut wallet,
1189 BlockId {
1190 height: 2,
1191 hash: BlockHash::all_zeros(),
1192 },
1193 );
1194 receive_output(
1195 &mut wallet,
1196 Amount::ONE_BTC,
1197 ReceiveTo::Block(chain::ConfirmationBlockTime {
1198 block_id: BlockId {
1199 height: 1,
1200 hash: BlockHash::all_zeros(),
1201 },
1202 confirmation_time: 1,
1203 }),
1204 );
1205 receive_output(
1206 &mut wallet,
1207 Amount::ONE_BTC * 2,
1208 ReceiveTo::Block(chain::ConfirmationBlockTime {
1209 block_id: BlockId {
1210 height: 2,
1211 hash: BlockHash::all_zeros(),
1212 },
1213 confirmation_time: 2,
1214 }),
1215 );
1216 receive_output(&mut wallet, Amount::ONE_BTC * 3, ReceiveTo::Mempool(100));
1217
1218 // Exclude nothing.
1219 {
1220 let mut builder = wallet.build_tx();
1221 builder
1222 .fee_rate(FeeRate::ZERO)
1223 .exclude_below_confirmations(0)
1224 .drain_wallet()
1225 .drain_to(recipient.script_pubkey());
1226 let tx = builder.finish().unwrap();
1227 let output = tx.unsigned_tx.output.first().expect("must have one output");
1228 assert_eq!(output.value, Amount::ONE_BTC * 6);
1229 }
1230
1231 // Exclude < 1 conf (a.k.a exclude unconfirmed).
1232 {
1233 let mut builder = wallet.build_tx();
1234 builder
1235 .fee_rate(FeeRate::ZERO)
1236 .exclude_below_confirmations(1)
1237 .drain_wallet()
1238 .drain_to(recipient.script_pubkey());
1239 let tx = builder.finish().unwrap();
1240 let output = tx.unsigned_tx.output.first().expect("must have one output");
1241 assert_eq!(output.value, Amount::ONE_BTC * 3);
1242 }
1243
1244 // Exclude < 2 conf (a.k.a need at least 2 conf)
1245 {
1246 let mut builder = wallet.build_tx();
1247 builder
1248 .fee_rate(FeeRate::ZERO)
1249 .exclude_below_confirmations(2)
1250 .drain_wallet()
1251 .drain_to(recipient.script_pubkey());
1252 let tx = builder.finish().unwrap();
1253 let output = tx.unsigned_tx.output.first().expect("must have one output");
1254 assert_eq!(output.value, Amount::ONE_BTC);
1255 }
1256 }
1257
1258 #[test]
1259 fn test_build_fee_bump_remove_change_output_single_desc() {
1260 use crate::test_utils::*;
1261 use bdk_chain::BlockId;
1262 use bitcoin::{hashes::Hash, BlockHash, Network};
1263
1264 let mut wallet = Wallet::create_single(get_test_tr_single_sig())
1265 .network(Network::Regtest)
1266 .create_wallet_no_persist()
1267 .unwrap();
1268
1269 insert_checkpoint(
1270 &mut wallet,
1271 BlockId {
1272 height: 1,
1273 hash: BlockHash::all_zeros(),
1274 },
1275 );
1276
1277 receive_output_in_latest_block(&mut wallet, Amount::ONE_BTC);
1278
1279 // tx1 sending 15k sat to a recipient
1280 let recip = ScriptBuf::from_hex(
1281 "5120e8f5c4dc2f5d6a7595e7b108cb063da9c7550312da1e22875d78b9db62b59cd5",
1282 )
1283 .unwrap();
1284 let mut builder = wallet.build_tx();
1285 builder.add_recipient(recip.clone(), Amount::from_sat(15_000));
1286 builder.fee_absolute(Amount::from_sat(1_000));
1287 let psbt = builder.finish().unwrap();
1288
1289 let tx = psbt.extract_tx().unwrap();
1290 let txid = tx.compute_txid();
1291 let feerate = wallet.calculate_fee_rate(&tx).unwrap().to_sat_per_kwu();
1292 insert_tx(&mut wallet, tx);
1293
1294 // build fee bump
1295 let mut builder = wallet.build_fee_bump(txid).unwrap();
1296 assert_eq!(
1297 builder.params.recipients,
1298 vec![(recip, Amount::from_sat(15_000))]
1299 );
1300 builder.fee_rate(FeeRate::from_sat_per_kwu(feerate + 250));
1301 let _ = builder.finish().unwrap();
1302 }
1303
1304 #[test]
1305 fn duplicated_utxos_in_add_utxos_are_only_added_once() {
1306 use crate::test_utils::get_funded_wallet_wpkh;
1307
1308 let (mut wallet, _) = get_funded_wallet_wpkh();
1309 let utxo = wallet.list_unspent().next().unwrap();
1310 let op = utxo.outpoint;
1311
1312 let mut tx_builder = wallet.build_tx();
1313 tx_builder.add_utxos(&[op, op, op]).unwrap();
1314
1315 assert_eq!(tx_builder.params.utxos.len(), 1);
1316 }
1317
1318 #[test]
1319 fn not_duplicated_utxos_in_required_list() {
1320 use crate::test_utils::get_funded_wallet_wpkh;
1321 let (mut wallet1, _) = get_funded_wallet_wpkh();
1322 let utxo1 @ LocalOutput { outpoint, .. } = wallet1.list_unspent().next().unwrap();
1323 let mut builder = wallet1.build_tx();
1324 let fake_weighted_utxo = WeightedUtxo {
1325 satisfaction_weight: Weight::from_wu(107),
1326 utxo: Utxo::Local(utxo1.clone()),
1327 };
1328
1329 for _ in 0..3 {
1330 builder.add_utxo(outpoint).expect("should add");
1331 }
1332 assert_eq!(vec![fake_weighted_utxo], builder.params.utxos);
1333 }
1334
1335 #[test]
1336 fn not_duplicated_foreign_utxos_with_same_outpoint_but_different_weight() {
1337 use crate::test_utils::{get_funded_wallet_single, get_funded_wallet_wpkh, get_test_wpkh};
1338
1339 // Use two different wallets to avoid adding local UTXOs
1340 let (wallet1, txid1) = get_funded_wallet_wpkh();
1341 let (mut wallet2, txid2) = get_funded_wallet_single(get_test_wpkh());
1342
1343 // if the transactions were produced by the same wallet the following assert should fail
1344 assert_ne!(txid1, txid2);
1345
1346 let utxo1 = wallet1.list_unspent().next().unwrap();
1347 let tx1 = wallet1.get_tx(txid1).unwrap().tx_node.tx.clone();
1348
1349 let satisfaction_weight = wallet1
1350 .public_descriptor(KeychainKind::External)
1351 .max_weight_to_satisfy()
1352 .unwrap();
1353
1354 let mut builder = wallet2.build_tx();
1355
1356 // add foreign UTXO with satisfaction weight x
1357 assert!(builder
1358 .add_foreign_utxo(
1359 utxo1.outpoint,
1360 psbt::Input {
1361 non_witness_utxo: Some(tx1.as_ref().clone()),
1362 ..Default::default()
1363 },
1364 satisfaction_weight,
1365 )
1366 .is_ok());
1367
1368 let modified_satisfaction_weight = satisfaction_weight - Weight::from_wu(6);
1369
1370 assert_ne!(satisfaction_weight, modified_satisfaction_weight);
1371
1372 // add foreign UTXO with same outpoint but satisfaction weight x - 6wu
1373 assert!(builder
1374 .add_foreign_utxo(
1375 utxo1.outpoint,
1376 psbt::Input {
1377 non_witness_utxo: Some(tx1.as_ref().clone()),
1378 ..Default::default()
1379 },
1380 modified_satisfaction_weight,
1381 )
1382 .is_ok());
1383
1384 assert_eq!(builder.params.utxos.len(), 1);
1385 assert_eq!(
1386 builder.params.utxos[0].satisfaction_weight,
1387 modified_satisfaction_weight
1388 );
1389 }
1390
1391 // Test that local outputs have precedence over utxos added via `add_foreign_utxo`
1392 #[test]
1393 fn test_local_utxos_have_precedence_over_foreign_utxos() {
1394 use crate::test_utils::get_funded_wallet_wpkh;
1395 let (mut wallet, _) = get_funded_wallet_wpkh();
1396
1397 let utxo = wallet.list_unspent().next().unwrap();
1398 let outpoint = utxo.outpoint;
1399
1400 // case 1: add foreign after local, expect local is kept
1401 let mut builder = wallet.build_tx();
1402 builder.add_utxo(outpoint).unwrap();
1403
1404 assert_eq!(builder.params.utxos[0].utxo.outpoint(), outpoint);
1405
1406 builder
1407 .add_foreign_utxo(
1408 outpoint,
1409 psbt::Input {
1410 witness_utxo: Some(utxo.txout.clone()),
1411 ..Default::default()
1412 },
1413 Weight::from_wu(107),
1414 )
1415 .unwrap();
1416
1417 assert_eq!(builder.params.utxos.len(), 1);
1418 assert!(matches!(
1419 &builder.params.utxos[0].utxo,
1420 Utxo::Local(output) if output.outpoint == outpoint,
1421 ));
1422
1423 // case 2: add local after foreign, expect foreign is removed
1424 builder.params = TxParams::default();
1425
1426 builder
1427 .add_foreign_utxo(
1428 outpoint,
1429 psbt::Input {
1430 witness_utxo: Some(utxo.txout),
1431 ..Default::default()
1432 },
1433 Weight::from_wu(107),
1434 )
1435 .unwrap();
1436
1437 assert_eq!(builder.params.utxos[0].utxo.outpoint(), outpoint);
1438
1439 builder.add_utxo(outpoint).unwrap();
1440
1441 assert_eq!(builder.params.utxos.len(), 1);
1442 assert!(
1443 matches!(&builder.params.utxos[0].utxo, Utxo::Local(output) if output.outpoint == outpoint)
1444 );
1445 }
1446}