• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bitcoindevkit / bdk / 5643476707

pending completion
5643476707

Pull #1023

github

web-flow
Merge de47a98e9 into cb626e9fc
Pull Request #1023: Update rust bitcoin

256 of 256 new or added lines in 21 files covered. (100.0%)

7830 of 9906 relevant lines covered (79.04%)

5143.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.79
/crates/bdk/src/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::*;
20
//! # use bdk::wallet::tx_builder::CreateTx;
21
//! # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
22
//! # let mut wallet = doctest_wallet!();
23
//! // create a TxBuilder from a wallet
24
//! let mut tx_builder = wallet.build_tx();
25
//!
26
//! tx_builder
27
//!     // Create a transaction with one output to `to_address` of 50_000 satoshi
28
//!     .add_recipient(to_address.script_pubkey(), 50_000)
29
//!     // With a custom fee rate of 5.0 satoshi/vbyte
30
//!     .fee_rate(bdk::FeeRate::from_sat_per_vb(5.0))
31
//!     // Only spend non-change outputs
32
//!     .do_not_spend_change()
33
//!     // Turn on RBF signaling
34
//!     .enable_rbf();
35
//! let (psbt, tx_details) = tx_builder.finish()?;
36
//! # Ok::<(), bdk::Error>(())
37
//! ```
38

39
use crate::collections::BTreeMap;
40
use crate::collections::HashSet;
41
use alloc::{boxed::Box, rc::Rc, string::String, vec::Vec};
42
use bdk_chain::PersistBackend;
43
use core::cell::RefCell;
44
use core::marker::PhantomData;
45

46
use bitcoin::psbt::{self, PartiallySignedTransaction as Psbt};
47
use bitcoin::{absolute, script::PushBytes, OutPoint, ScriptBuf, Sequence, Transaction};
48

49
use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm};
50
use super::ChangeSet;
51
use crate::{
52
    types::{FeeRate, KeychainKind, LocalUtxo, WeightedUtxo},
53
    TransactionDetails,
54
};
55
use crate::{Error, Utxo, Wallet};
56
/// Context in which the [`TxBuilder`] is valid
57
pub trait TxBuilderContext: core::fmt::Debug + Default + Clone {}
58

59
/// Marker type to indicate the [`TxBuilder`] is being used to create a new transaction (as opposed
60
/// to bumping the fee of an existing one).
61
#[derive(Debug, Default, Clone)]
×
62
pub struct CreateTx;
63
impl TxBuilderContext for CreateTx {}
64

65
/// Marker type to indicate the [`TxBuilder`] is being used to bump the fee of an existing transaction.
66
#[derive(Debug, Default, Clone)]
×
67
pub struct BumpFee;
68
impl TxBuilderContext for BumpFee {}
69

70
/// A transaction builder
71
///
72
/// A `TxBuilder` is created by calling [`build_tx`] or [`build_fee_bump`] on a wallet. After
73
/// assigning it, you set options on it until finally calling [`finish`] to consume the builder and
74
/// generate the transaction.
75
///
76
/// Each option setting method on `TxBuilder` takes and returns `&mut self` so you can chain calls
77
/// as in the following example:
78
///
79
/// ```
80
/// # use bdk::*;
81
/// # use bdk::wallet::tx_builder::*;
82
/// # use bitcoin::*;
83
/// # use core::str::FromStr;
84
/// # let mut wallet = doctest_wallet!();
85
/// # let addr1 = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap().assume_checked();
86
/// # let addr2 = addr1.clone();
87
/// // chaining
88
/// let (psbt1, details) = {
89
///     let mut builder = wallet.build_tx();
90
///     builder
91
///         .ordering(TxOrdering::Untouched)
92
///         .add_recipient(addr1.script_pubkey(), 50_000)
93
///         .add_recipient(addr2.script_pubkey(), 50_000);
94
///     builder.finish()?
95
/// };
96
///
97
/// // non-chaining
98
/// let (psbt2, details) = {
99
///     let mut builder = wallet.build_tx();
100
///     builder.ordering(TxOrdering::Untouched);
101
///     for addr in &[addr1, addr2] {
102
///         builder.add_recipient(addr.script_pubkey(), 50_000);
103
///     }
104
///     builder.finish()?
105
/// };
106
///
107
/// assert_eq!(psbt1.unsigned_tx.output[..2], psbt2.unsigned_tx.output[..2]);
108
/// # Ok::<(), bdk::Error>(())
109
/// ```
110
///
111
/// At the moment [`coin_selection`] is an exception to the rule as it consumes `self`.
112
/// This means it is usually best to call [`coin_selection`] on the return value of `build_tx` before assigning it.
113
///
114
/// For further examples see [this module](super::tx_builder)'s documentation;
115
///
116
/// [`build_tx`]: Wallet::build_tx
117
/// [`build_fee_bump`]: Wallet::build_fee_bump
118
/// [`finish`]: Self::finish
119
/// [`coin_selection`]: Self::coin_selection
120
#[derive(Debug)]
×
121
pub struct TxBuilder<'a, D, Cs, Ctx> {
122
    pub(crate) wallet: Rc<RefCell<&'a mut Wallet<D>>>,
123
    pub(crate) params: TxParams,
124
    pub(crate) coin_selection: Cs,
125
    pub(crate) phantom: PhantomData<Ctx>,
126
}
127

128
/// The parameters for transaction creation sans coin selection algorithm.
129
//TODO: TxParams should eventually be exposed publicly.
130
#[derive(Default, Debug, Clone)]
142✔
131
pub(crate) struct TxParams {
132
    pub(crate) recipients: Vec<(ScriptBuf, u64)>,
133
    pub(crate) drain_wallet: bool,
134
    pub(crate) drain_to: Option<ScriptBuf>,
135
    pub(crate) fee_policy: Option<FeePolicy>,
136
    pub(crate) internal_policy_path: Option<BTreeMap<String, Vec<usize>>>,
137
    pub(crate) external_policy_path: Option<BTreeMap<String, Vec<usize>>>,
138
    pub(crate) utxos: Vec<WeightedUtxo>,
139
    pub(crate) unspendable: HashSet<OutPoint>,
140
    pub(crate) manually_selected_only: bool,
141
    pub(crate) sighash: Option<psbt::PsbtSighashType>,
142
    pub(crate) ordering: TxOrdering,
143
    pub(crate) locktime: Option<absolute::LockTime>,
144
    pub(crate) rbf: Option<RbfValue>,
145
    pub(crate) version: Option<Version>,
146
    pub(crate) change_policy: ChangeSpendPolicy,
147
    pub(crate) only_witness_utxo: bool,
148
    pub(crate) add_global_xpubs: bool,
149
    pub(crate) include_output_redeem_witness_script: bool,
150
    pub(crate) bumping_fee: Option<PreviousFee>,
151
    pub(crate) current_height: Option<absolute::LockTime>,
152
    pub(crate) allow_dust: bool,
153
}
154

155
#[derive(Clone, Copy, Debug)]
×
156
pub(crate) struct PreviousFee {
157
    pub absolute: u64,
158
    pub rate: f32,
159
}
160

161
#[derive(Debug, Clone, Copy)]
×
162
pub(crate) enum FeePolicy {
163
    FeeRate(FeeRate),
164
    FeeAmount(u64),
165
}
166

167
impl Default for FeePolicy {
168
    fn default() -> Self {
×
169
        FeePolicy::FeeRate(FeeRate::default_min_relay_fee())
×
170
    }
×
171
}
172

173
impl<'a, D, Cs: Clone, Ctx> Clone for TxBuilder<'a, D, Cs, Ctx> {
174
    fn clone(&self) -> Self {
3✔
175
        TxBuilder {
3✔
176
            wallet: self.wallet.clone(),
3✔
177
            params: self.params.clone(),
3✔
178
            coin_selection: self.coin_selection.clone(),
3✔
179
            phantom: PhantomData,
3✔
180
        }
3✔
181
    }
3✔
182
}
183

184
// methods supported by both contexts, for any CoinSelectionAlgorithm
185
impl<'a, D, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderContext> TxBuilder<'a, D, Cs, Ctx> {
186
    /// Set a custom fee rate
187
    pub fn fee_rate(&mut self, fee_rate: FeeRate) -> &mut Self {
20✔
188
        self.params.fee_policy = Some(FeePolicy::FeeRate(fee_rate));
20✔
189
        self
20✔
190
    }
20✔
191

192
    /// Set an absolute fee
193
    /// The fee_absolute method refers to the absolute transaction fee in satoshis (sats).
194
    /// If anyone sets both the fee_absolute method and the fee_rate method,
195
    /// the fee_absolute value will take precedence over the fee_rate.
196
    pub fn fee_absolute(&mut self, fee_amount: u64) -> &mut Self {
9✔
197
        self.params.fee_policy = Some(FeePolicy::FeeAmount(fee_amount));
9✔
198
        self
9✔
199
    }
9✔
200

201
    /// Set the policy path to use while creating the transaction for a given keychain.
202
    ///
203
    /// This method accepts a map where the key is the policy node id (see
204
    /// [`Policy::id`](crate::descriptor::Policy::id)) and the value is the list of the indexes of
205
    /// the items that are intended to be satisfied from the policy node (see
206
    /// [`SatisfiableItem::Thresh::items`](crate::descriptor::policy::SatisfiableItem::Thresh::items)).
207
    ///
208
    /// ## Example
209
    ///
210
    /// An example of when the policy path is needed is the following descriptor:
211
    /// `wsh(thresh(2,pk(A),sj:and_v(v:pk(B),n:older(6)),snj:and_v(v:pk(C),after(630000))))`,
212
    /// derived from the miniscript policy `thresh(2,pk(A),and(pk(B),older(6)),and(pk(C),after(630000)))`.
213
    /// It declares three descriptor fragments, and at the top level it uses `thresh()` to
214
    /// ensure that at least two of them are satisfied. The individual fragments are:
215
    ///
216
    /// 1. `pk(A)`
217
    /// 2. `and(pk(B),older(6))`
218
    /// 3. `and(pk(C),after(630000))`
219
    ///
220
    /// When those conditions are combined in pairs, it's clear that the transaction needs to be created
221
    /// differently depending on how the user intends to satisfy the policy afterwards:
222
    ///
223
    /// * If fragments `1` and `2` are used, the transaction will need to use a specific
224
    ///   `n_sequence` in order to spend an `OP_CSV` branch.
225
    /// * If fragments `1` and `3` are used, the transaction will need to use a specific `locktime`
226
    ///   in order to spend an `OP_CLTV` branch.
227
    /// * If fragments `2` and `3` are used, the transaction will need both.
228
    ///
229
    /// When the spending policy is represented as a tree (see
230
    /// [`Wallet::policies`](super::Wallet::policies)), every node
231
    /// is assigned a unique identifier that can be used in the policy path to specify which of
232
    /// the node's children the user intends to satisfy: for instance, assuming the `thresh()`
233
    /// root node of this example has an id of `aabbccdd`, the policy path map would look like:
234
    ///
235
    /// `{ "aabbccdd" => [0, 1] }`
236
    ///
237
    /// where the key is the node's id, and the value is a list of the children that should be
238
    /// used, in no particular order.
239
    ///
240
    /// If a particularly complex descriptor has multiple ambiguous thresholds in its structure,
241
    /// multiple entries can be added to the map, one for each node that requires an explicit path.
242
    ///
243
    /// ```
244
    /// # use std::str::FromStr;
245
    /// # use std::collections::BTreeMap;
246
    /// # use bitcoin::*;
247
    /// # use bdk::*;
248
    /// # let to_address =
249
    /// Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
250
    ///     .unwrap()
251
    ///     .assume_checked();
252
    /// # let mut wallet = doctest_wallet!();
253
    /// let mut path = BTreeMap::new();
254
    /// path.insert("aabbccdd".to_string(), vec![0, 1]);
255
    ///
256
    /// let builder = wallet
257
    ///     .build_tx()
258
    ///     .add_recipient(to_address.script_pubkey(), 50_000)
259
    ///     .policy_path(path, KeychainKind::External);
260
    ///
261
    /// # Ok::<(), bdk::Error>(())
262
    /// ```
263
    pub fn policy_path(
4✔
264
        &mut self,
4✔
265
        policy_path: BTreeMap<String, Vec<usize>>,
4✔
266
        keychain: KeychainKind,
4✔
267
    ) -> &mut Self {
4✔
268
        let to_update = match keychain {
4✔
269
            KeychainKind::Internal => &mut self.params.internal_policy_path,
×
270
            KeychainKind::External => &mut self.params.external_policy_path,
4✔
271
        };
272

273
        *to_update = Some(policy_path);
4✔
274
        self
4✔
275
    }
4✔
276

277
    /// Add the list of outpoints to the internal list of UTXOs that **must** be spent.
278
    ///
279
    /// If an error occurs while adding any of the UTXOs then none of them are added and the error is returned.
280
    ///
281
    /// These have priority over the "unspendable" utxos, meaning that if a utxo is present both in
282
    /// the "utxos" and the "unspendable" list, it will be spent.
283
    pub fn add_utxos(&mut self, outpoints: &[OutPoint]) -> Result<&mut Self, Error> {
9✔
284
        {
9✔
285
            let wallet = self.wallet.borrow();
9✔
286
            let utxos = outpoints
9✔
287
                .iter()
9✔
288
                .map(|outpoint| wallet.get_utxo(*outpoint).ok_or(Error::UnknownUtxo))
9✔
289
                .collect::<Result<Vec<_>, _>>()?;
9✔
290

291
            for utxo in utxos {
18✔
292
                let descriptor = wallet.get_descriptor_for_keychain(utxo.keychain);
9✔
293
                #[allow(deprecated)]
9✔
294
                let satisfaction_weight = descriptor.max_satisfaction_weight().unwrap();
9✔
295
                self.params.utxos.push(WeightedUtxo {
9✔
296
                    satisfaction_weight,
9✔
297
                    utxo: Utxo::Local(utxo),
9✔
298
                });
9✔
299
            }
9✔
300
        }
301

302
        Ok(self)
9✔
303
    }
9✔
304

305
    /// Add a utxo to the internal list of utxos that **must** be spent
306
    ///
307
    /// These have priority over the "unspendable" utxos, meaning that if a utxo is present both in
308
    /// the "utxos" and the "unspendable" list, it will be spent.
309
    pub fn add_utxo(&mut self, outpoint: OutPoint) -> Result<&mut Self, Error> {
8✔
310
        self.add_utxos(&[outpoint])
8✔
311
    }
8✔
312

313
    /// Add a foreign UTXO i.e. a UTXO not owned by this wallet.
314
    ///
315
    /// At a minimum to add a foreign UTXO we need:
316
    ///
317
    /// 1. `outpoint`: To add it to the raw transaction.
318
    /// 2. `psbt_input`: To know the value.
319
    /// 3. `satisfaction_weight`: To know how much weight/vbytes the input will add to the transaction for fee calculation.
320
    ///
321
    /// There are several security concerns about adding foreign UTXOs that application
322
    /// developers should consider. First, how do you know the value of the input is correct? If a
323
    /// `non_witness_utxo` is provided in the `psbt_input` then this method implicitly verifies the
324
    /// value by checking it against the transaction. If only a `witness_utxo` is provided then this
325
    /// method doesn't verify the value but just takes it as a given -- it is up to you to check
326
    /// that whoever sent you the `input_psbt` was not lying!
327
    ///
328
    /// Secondly, you must somehow provide `satisfaction_weight` of the input. Depending on your
329
    /// application it may be important that this be known precisely. If not, a malicious
330
    /// counterparty may fool you into putting in a value that is too low, giving the transaction a
331
    /// lower than expected feerate. They could also fool you into putting a value that is too high
332
    /// causing you to pay a fee that is too high. The party who is broadcasting the transaction can
333
    /// of course check the real input weight matches the expected weight prior to broadcasting.
334
    ///
335
    /// To guarantee the `satisfaction_weight` is correct, you can require the party providing the
336
    /// `psbt_input` provide a miniscript descriptor for the input so you can check it against the
337
    /// `script_pubkey` and then ask it for the [`max_satisfaction_weight`].
338
    ///
339
    /// This is an **EXPERIMENTAL** feature, API and other major changes are expected.
340
    ///
341
    /// # Errors
342
    ///
343
    /// This method returns errors in the following circumstances:
344
    ///
345
    /// 1. The `psbt_input` does not contain a `witness_utxo` or `non_witness_utxo`.
346
    /// 2. The data in `non_witness_utxo` does not match what is in `outpoint`.
347
    ///
348
    /// Note unless you set [`only_witness_utxo`] any non-taproot `psbt_input` you pass to this
349
    /// method must have `non_witness_utxo` set otherwise you will get an error when [`finish`]
350
    /// is called.
351
    ///
352
    /// [`only_witness_utxo`]: Self::only_witness_utxo
353
    /// [`finish`]: Self::finish
354
    /// [`max_satisfaction_weight`]: miniscript::Descriptor::max_satisfaction_weight
355
    pub fn add_foreign_utxo(
8✔
356
        &mut self,
8✔
357
        outpoint: OutPoint,
8✔
358
        psbt_input: psbt::Input,
8✔
359
        satisfaction_weight: usize,
8✔
360
    ) -> Result<&mut Self, Error> {
8✔
361
        if psbt_input.witness_utxo.is_none() {
8✔
362
            match psbt_input.non_witness_utxo.as_ref() {
4✔
363
                Some(tx) => {
3✔
364
                    if tx.txid() != outpoint.txid {
3✔
365
                        return Err(Error::Generic(
1✔
366
                            "Foreign utxo outpoint does not match PSBT input".into(),
1✔
367
                        ));
1✔
368
                    }
2✔
369
                    if tx.output.len() <= outpoint.vout as usize {
2✔
370
                        return Err(Error::InvalidOutpoint(outpoint));
×
371
                    }
2✔
372
                }
373
                None => {
374
                    return Err(Error::Generic(
1✔
375
                        "Foreign utxo missing witness_utxo or non_witness_utxo".into(),
1✔
376
                    ))
1✔
377
                }
378
            }
379
        }
4✔
380

381
        self.params.utxos.push(WeightedUtxo {
6✔
382
            satisfaction_weight,
6✔
383
            utxo: Utxo::Foreign {
6✔
384
                outpoint,
6✔
385
                psbt_input: Box::new(psbt_input),
6✔
386
            },
6✔
387
        });
6✔
388

6✔
389
        Ok(self)
6✔
390
    }
8✔
391

392
    /// Only spend utxos added by [`add_utxo`].
393
    ///
394
    /// The wallet will **not** add additional utxos to the transaction even if they are needed to
395
    /// make the transaction valid.
396
    ///
397
    /// [`add_utxo`]: Self::add_utxo
398
    pub fn manually_selected_only(&mut self) -> &mut Self {
6✔
399
        self.params.manually_selected_only = true;
6✔
400
        self
6✔
401
    }
6✔
402

403
    /// Replace the internal list of unspendable utxos with a new list
404
    ///
405
    /// It's important to note that the "must-be-spent" utxos added with [`TxBuilder::add_utxo`]
406
    /// have priority over these. See the docs of the two linked methods for more details.
407
    pub fn unspendable(&mut self, unspendable: Vec<OutPoint>) -> &mut Self {
×
408
        self.params.unspendable = unspendable.into_iter().collect();
×
409
        self
×
410
    }
×
411

412
    /// Add a utxo to the internal list of unspendable utxos
413
    ///
414
    /// It's important to note that the "must-be-spent" utxos added with [`TxBuilder::add_utxo`]
415
    /// have priority over this. See the docs of the two linked methods for more details.
416
    pub fn add_unspendable(&mut self, unspendable: OutPoint) -> &mut Self {
×
417
        self.params.unspendable.insert(unspendable);
×
418
        self
×
419
    }
×
420

421
    /// Sign with a specific sig hash
422
    ///
423
    /// **Use this option very carefully**
424
    pub fn sighash(&mut self, sighash: psbt::PsbtSighashType) -> &mut Self {
4✔
425
        self.params.sighash = Some(sighash);
4✔
426
        self
4✔
427
    }
4✔
428

429
    /// Choose the ordering for inputs and outputs of the transaction
430
    pub fn ordering(&mut self, ordering: TxOrdering) -> &mut Self {
2✔
431
        self.params.ordering = ordering;
2✔
432
        self
2✔
433
    }
2✔
434

435
    /// Use a specific nLockTime while creating the transaction
436
    ///
437
    /// This can cause conflicts if the wallet's descriptors contain an "after" (OP_CLTV) operator.
438
    pub fn nlocktime(&mut self, locktime: absolute::LockTime) -> &mut Self {
3✔
439
        self.params.locktime = Some(locktime);
3✔
440
        self
3✔
441
    }
3✔
442

443
    /// Build a transaction with a specific version
444
    ///
445
    /// The `version` should always be greater than `0` and greater than `1` if the wallet's
446
    /// descriptors contain an "older" (OP_CSV) operator.
447
    pub fn version(&mut self, version: i32) -> &mut Self {
3✔
448
        self.params.version = Some(Version(version));
3✔
449
        self
3✔
450
    }
3✔
451

452
    /// Do not spend change outputs
453
    ///
454
    /// This effectively adds all the change outputs to the "unspendable" list. See
455
    /// [`TxBuilder::unspendable`].
456
    pub fn do_not_spend_change(&mut self) -> &mut Self {
1✔
457
        self.params.change_policy = ChangeSpendPolicy::ChangeForbidden;
1✔
458
        self
1✔
459
    }
1✔
460

461
    /// Only spend change outputs
462
    ///
463
    /// This effectively adds all the non-change outputs to the "unspendable" list. See
464
    /// [`TxBuilder::unspendable`].
465
    pub fn only_spend_change(&mut self) -> &mut Self {
×
466
        self.params.change_policy = ChangeSpendPolicy::OnlyChange;
×
467
        self
×
468
    }
×
469

470
    /// Set a specific [`ChangeSpendPolicy`]. See [`TxBuilder::do_not_spend_change`] and
471
    /// [`TxBuilder::only_spend_change`] for some shortcuts.
472
    pub fn change_policy(&mut self, change_policy: ChangeSpendPolicy) -> &mut Self {
×
473
        self.params.change_policy = change_policy;
×
474
        self
×
475
    }
×
476

477
    /// Only Fill-in the [`psbt::Input::witness_utxo`](bitcoin::psbt::Input::witness_utxo) field when spending from
478
    /// SegWit descriptors.
479
    ///
480
    /// This reduces the size of the PSBT, but some signers might reject them due to the lack of
481
    /// the `non_witness_utxo`.
482
    pub fn only_witness_utxo(&mut self) -> &mut Self {
3✔
483
        self.params.only_witness_utxo = true;
3✔
484
        self
3✔
485
    }
3✔
486

487
    /// Fill-in the [`psbt::Output::redeem_script`](bitcoin::psbt::Output::redeem_script) and
488
    /// [`psbt::Output::witness_script`](bitcoin::psbt::Output::witness_script) fields.
489
    ///
490
    /// This is useful for signers which always require it, like ColdCard hardware wallets.
491
    pub fn include_output_redeem_witness_script(&mut self) -> &mut Self {
2✔
492
        self.params.include_output_redeem_witness_script = true;
2✔
493
        self
2✔
494
    }
2✔
495

496
    /// Fill-in the `PSBT_GLOBAL_XPUB` field with the extended keys contained in both the external
497
    /// and internal descriptors
498
    ///
499
    /// This is useful for offline signers that take part to a multisig. Some hardware wallets like
500
    /// BitBox and ColdCard are known to require this.
501
    pub fn add_global_xpubs(&mut self) -> &mut Self {
3✔
502
        self.params.add_global_xpubs = true;
3✔
503
        self
3✔
504
    }
3✔
505

506
    /// Spend all the available inputs. This respects filters like [`TxBuilder::unspendable`] and the change policy.
507
    pub fn drain_wallet(&mut self) -> &mut Self {
42✔
508
        self.params.drain_wallet = true;
42✔
509
        self
42✔
510
    }
42✔
511

512
    /// Choose the coin selection algorithm
513
    ///
514
    /// Overrides the [`DefaultCoinSelectionAlgorithm`](super::coin_selection::DefaultCoinSelectionAlgorithm).
515
    ///
516
    /// 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.
517
    pub fn coin_selection<P: CoinSelectionAlgorithm>(
5✔
518
        self,
5✔
519
        coin_selection: P,
5✔
520
    ) -> TxBuilder<'a, D, P, Ctx> {
5✔
521
        TxBuilder {
5✔
522
            wallet: self.wallet,
5✔
523
            params: self.params,
5✔
524
            coin_selection,
5✔
525
            phantom: PhantomData,
5✔
526
        }
5✔
527
    }
5✔
528

529
    /// Finish building the transaction.
530
    ///
531
    /// Returns the [`BIP174`] "PSBT" and summary details about the transaction.
532
    ///
533
    /// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
534
    pub fn finish(self) -> Result<(Psbt, TransactionDetails), Error>
142✔
535
    where
142✔
536
        D: PersistBackend<ChangeSet>,
142✔
537
    {
142✔
538
        self.wallet
142✔
539
            .borrow_mut()
142✔
540
            .create_tx(self.coin_selection, self.params)
142✔
541
    }
142✔
542

543
    /// Enable signaling RBF
544
    ///
545
    /// This will use the default nSequence value of `0xFFFFFFFD`.
546
    pub fn enable_rbf(&mut self) -> &mut Self {
20✔
547
        self.params.rbf = Some(RbfValue::Default);
20✔
548
        self
20✔
549
    }
20✔
550

551
    /// Enable signaling RBF with a specific nSequence value
552
    ///
553
    /// This can cause conflicts if the wallet's descriptors contain an "older" (OP_CSV) operator
554
    /// and the given `nsequence` is lower than the CSV value.
555
    ///
556
    /// If the `nsequence` is higher than `0xFFFFFFFD` an error will be thrown, since it would not
557
    /// be a valid nSequence to signal RBF.
558
    pub fn enable_rbf_with_sequence(&mut self, nsequence: Sequence) -> &mut Self {
3✔
559
        self.params.rbf = Some(RbfValue::Value(nsequence));
3✔
560
        self
3✔
561
    }
3✔
562

563
    /// Set the current blockchain height.
564
    ///
565
    /// This will be used to:
566
    /// 1. Set the nLockTime for preventing fee sniping.
567
    /// **Note**: This will be ignored if you manually specify a nlocktime using [`TxBuilder::nlocktime`].
568
    /// 2. Decide whether coinbase outputs are mature or not. If the coinbase outputs are not
569
    ///    mature at `current_height`, we ignore them in the coin selection.
570
    ///    If you want to create a transaction that spends immature coinbase inputs, manually
571
    ///    add them using [`TxBuilder::add_utxos`].
572
    ///
573
    /// In both cases, if you don't provide a current height, we use the last sync height.
574
    pub fn current_height(&mut self, height: u32) -> &mut Self {
4✔
575
        self.params.current_height =
4✔
576
            Some(absolute::LockTime::from_height(height).expect("Invalid height"));
4✔
577
        self
4✔
578
    }
4✔
579

580
    /// Set whether or not the dust limit is checked.
581
    ///
582
    /// **Note**: by avoiding a dust limit check you may end up with a transaction that is non-standard.
583
    pub fn allow_dust(&mut self, allow_dust: bool) -> &mut Self {
1✔
584
        self.params.allow_dust = allow_dust;
1✔
585
        self
1✔
586
    }
1✔
587
}
588

589
impl<'a, D, Cs: CoinSelectionAlgorithm> TxBuilder<'a, D, Cs, CreateTx> {
590
    /// Replace the recipients already added with a new list
591
    pub fn set_recipients(&mut self, recipients: Vec<(ScriptBuf, u64)>) -> &mut Self {
×
592
        self.params.recipients = recipients;
×
593
        self
×
594
    }
×
595

596
    /// Add a recipient to the internal list
597
    pub fn add_recipient(&mut self, script_pubkey: ScriptBuf, amount: u64) -> &mut Self {
79✔
598
        self.params.recipients.push((script_pubkey, amount));
79✔
599
        self
79✔
600
    }
79✔
601

602
    /// Add data as an output, using OP_RETURN
603
    pub fn add_data<T: AsRef<PushBytes>>(&mut self, data: &T) -> &mut Self {
1✔
604
        let script = ScriptBuf::new_op_return(data);
1✔
605
        self.add_recipient(script, 0u64);
1✔
606
        self
1✔
607
    }
1✔
608

609
    /// Sets the address to *drain* excess coins to.
610
    ///
611
    /// Usually, when there are excess coins they are sent to a change address generated by the
612
    /// wallet. This option replaces the usual change address with an arbitrary `script_pubkey` of
613
    /// your choosing. Just as with a change output, if the drain output is not needed (the excess
614
    /// coins are too small) it will not be included in the resulting transaction. The only
615
    /// difference is that it is valid to use `drain_to` without setting any ordinary recipients
616
    /// with [`add_recipient`] (but it is perfectly fine to add recipients as well).
617
    ///
618
    /// If you choose not to set any recipients, you should either provide the utxos that the
619
    /// transaction should spend via [`add_utxos`], or set [`drain_wallet`] to spend all of them.
620
    ///
621
    /// When bumping the fees of a transaction made with this option, you probably want to
622
    /// use [`allow_shrinking`] to allow this output to be reduced to pay for the extra fees.
623
    ///
624
    /// # Example
625
    ///
626
    /// `drain_to` is very useful for draining all the coins in a wallet with [`drain_wallet`] to a
627
    /// single address.
628
    ///
629
    /// ```
630
    /// # use std::str::FromStr;
631
    /// # use bitcoin::*;
632
    /// # use bdk::*;
633
    /// # use bdk::wallet::tx_builder::CreateTx;
634
    /// # let to_address =
635
    /// Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
636
    ///     .unwrap()
637
    ///     .assume_checked();
638
    /// # let mut wallet = doctest_wallet!();
639
    /// let mut tx_builder = wallet.build_tx();
640
    ///
641
    /// tx_builder
642
    ///     // Spend all outputs in this wallet.
643
    ///     .drain_wallet()
644
    ///     // Send the excess (which is all the coins minus the fee) to this address.
645
    ///     .drain_to(to_address.script_pubkey())
646
    ///     .fee_rate(bdk::FeeRate::from_sat_per_vb(5.0))
647
    ///     .enable_rbf();
648
    /// let (psbt, tx_details) = tx_builder.finish()?;
649
    /// # Ok::<(), bdk::Error>(())
650
    /// ```
651
    ///
652
    /// [`allow_shrinking`]: Self::allow_shrinking
653
    /// [`add_recipient`]: Self::add_recipient
654
    /// [`add_utxos`]: Self::add_utxos
655
    /// [`drain_wallet`]: Self::drain_wallet
656
    pub fn drain_to(&mut self, script_pubkey: ScriptBuf) -> &mut Self {
46✔
657
        self.params.drain_to = Some(script_pubkey);
46✔
658
        self
46✔
659
    }
46✔
660
}
661

662
// methods supported only by bump_fee
663
impl<'a, D> TxBuilder<'a, D, DefaultCoinSelectionAlgorithm, BumpFee> {
664
    /// Explicitly tells the wallet that it is allowed to reduce the amount of the output matching this
665
    /// `script_pubkey` in order to bump the transaction fee. Without specifying this the wallet
666
    /// will attempt to find a change output to shrink instead.
667
    ///
668
    /// **Note** that the output may shrink to below the dust limit and therefore be removed. If it is
669
    /// preserved then it is currently not guaranteed to be in the same position as it was
670
    /// originally.
671
    ///
672
    /// Returns an `Err` if `script_pubkey` can't be found among the recipients of the
673
    /// transaction we are bumping.
674
    pub fn allow_shrinking(&mut self, script_pubkey: ScriptBuf) -> Result<&mut Self, Error> {
4✔
675
        match self
4✔
676
            .params
4✔
677
            .recipients
4✔
678
            .iter()
4✔
679
            .position(|(recipient_script, _)| *recipient_script == script_pubkey)
4✔
680
        {
681
            Some(position) => {
4✔
682
                self.params.recipients.remove(position);
4✔
683
                self.params.drain_to = Some(script_pubkey);
4✔
684
                Ok(self)
4✔
685
            }
686
            None => Err(Error::Generic(format!(
×
687
                "{} was not in the original transaction",
×
688
                script_pubkey
×
689
            ))),
×
690
        }
691
    }
4✔
692
}
693

694
/// Ordering of the transaction's inputs and outputs
695
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
4✔
696
pub enum TxOrdering {
697
    /// Randomized (default)
698
    Shuffle,
699
    /// Unchanged
700
    Untouched,
701
    /// BIP69 / Lexicographic
702
    Bip69Lexicographic,
703
}
704

705
impl Default for TxOrdering {
706
    fn default() -> Self {
1,201✔
707
        TxOrdering::Shuffle
1,201✔
708
    }
1,201✔
709
}
710

711
impl TxOrdering {
712
    /// Sort transaction inputs and outputs by [`TxOrdering`] variant
713
    pub fn sort_tx(&self, tx: &mut Transaction) {
1,028✔
714
        match self {
1,028✔
715
            TxOrdering::Untouched => {}
25✔
716
            TxOrdering::Shuffle => {
994✔
717
                use rand::seq::SliceRandom;
994✔
718
                let mut rng = rand::thread_rng();
994✔
719
                tx.input.shuffle(&mut rng);
994✔
720
                tx.output.shuffle(&mut rng);
994✔
721
            }
994✔
722
            TxOrdering::Bip69Lexicographic => {
9✔
723
                tx.input.sort_unstable_by_key(|txin| {
14✔
724
                    (txin.previous_output.txid, txin.previous_output.vout)
6✔
725
                });
14✔
726
                tx.output
9✔
727
                    .sort_unstable_by_key(|txout| (txout.value, txout.script_pubkey.clone()));
54✔
728
            }
9✔
729
        }
730
    }
1,028✔
731
}
732

733
/// Transaction version
734
///
735
/// Has a default value of `1`
736
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
×
737
pub(crate) struct Version(pub(crate) i32);
738

739
impl Default for Version {
740
    fn default() -> Self {
1✔
741
        Version(1)
1✔
742
    }
1✔
743
}
744

745
/// RBF nSequence value
746
///
747
/// Has a default value of `0xFFFFFFFD`
748
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
×
749
pub(crate) enum RbfValue {
750
    Default,
751
    Value(Sequence),
752
}
753

754
impl RbfValue {
755
    pub(crate) fn get_value(&self) -> Sequence {
176✔
756
        match self {
176✔
757
            RbfValue::Default => Sequence::ENABLE_RBF_NO_LOCKTIME,
168✔
758
            RbfValue::Value(v) => *v,
8✔
759
        }
760
    }
176✔
761
}
762

763
/// Policy regarding the use of change outputs when creating a transaction
764
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Clone, Copy)]
278✔
765
pub enum ChangeSpendPolicy {
766
    /// Use both change and non-change outputs (default)
767
    ChangeAllowed,
768
    /// Only use change outputs (see [`TxBuilder::only_spend_change`])
769
    OnlyChange,
770
    /// Only use non-change outputs (see [`TxBuilder::do_not_spend_change`])
771
    ChangeForbidden,
772
}
773

774
impl Default for ChangeSpendPolicy {
775
    fn default() -> Self {
1,201✔
776
        ChangeSpendPolicy::ChangeAllowed
1,201✔
777
    }
1,201✔
778
}
779

780
impl ChangeSpendPolicy {
781
    pub(crate) fn is_satisfied_by(&self, utxo: &LocalUtxo) -> bool {
1,102✔
782
        match self {
1,102✔
783
            ChangeSpendPolicy::ChangeAllowed => true,
1,090✔
784
            ChangeSpendPolicy::OnlyChange => utxo.keychain == KeychainKind::Internal,
2✔
785
            ChangeSpendPolicy::ChangeForbidden => utxo.keychain == KeychainKind::External,
10✔
786
        }
787
    }
1,102✔
788
}
789

790
#[cfg(test)]
791
mod test {
792
    const ORDERING_TEST_TX: &str = "0200000003c26f3eb7932f7acddc5ddd26602b77e7516079b03090a16e2c2f54\
793
                                    85d1fd600f0100000000ffffffffc26f3eb7932f7acddc5ddd26602b77e75160\
794
                                    79b03090a16e2c2f5485d1fd600f0000000000ffffffff571fb3e02278217852\
795
                                    dd5d299947e2b7354a639adc32ec1fa7b82cfb5dec530e0500000000ffffffff\
796
                                    03e80300000000000002aaeee80300000000000001aa200300000000000001ff\
797
                                    00000000";
798
    macro_rules! ordering_test_tx {
799
        () => {
800
            deserialize::<bitcoin::Transaction>(&Vec::<u8>::from_hex(ORDERING_TEST_TX).unwrap())
801
                .unwrap()
802
        };
803
    }
804

805
    use bdk_chain::ConfirmationTime;
806
    use bitcoin::consensus::deserialize;
807
    use bitcoin::hashes::hex::FromHex;
808

809
    use super::*;
810

811
    #[test]
1✔
812
    fn test_output_ordering_default_shuffle() {
1✔
813
        assert_eq!(TxOrdering::default(), TxOrdering::Shuffle);
1✔
814
    }
1✔
815

816
    #[test]
1✔
817
    fn test_output_ordering_untouched() {
1✔
818
        let original_tx = ordering_test_tx!();
1✔
819
        let mut tx = original_tx.clone();
1✔
820

1✔
821
        TxOrdering::Untouched.sort_tx(&mut tx);
1✔
822

1✔
823
        assert_eq!(original_tx, tx);
1✔
824
    }
1✔
825

826
    #[test]
1✔
827
    fn test_output_ordering_shuffle() {
1✔
828
        let original_tx = ordering_test_tx!();
1✔
829
        let mut tx = original_tx.clone();
1✔
830

1✔
831
        (0..40)
1✔
832
            .find(|_| {
1✔
833
                TxOrdering::Shuffle.sort_tx(&mut tx);
1✔
834
                original_tx.input != tx.input
1✔
835
            })
1✔
836
            .expect("it should have moved the inputs at least once");
1✔
837

1✔
838
        let mut tx = original_tx.clone();
1✔
839
        (0..40)
1✔
840
            .find(|_| {
1✔
841
                TxOrdering::Shuffle.sort_tx(&mut tx);
1✔
842
                original_tx.output != tx.output
1✔
843
            })
1✔
844
            .expect("it should have moved the outputs at least once");
1✔
845
    }
1✔
846

847
    #[test]
1✔
848
    fn test_output_ordering_bip69() {
1✔
849
        use core::str::FromStr;
1✔
850

1✔
851
        let original_tx = ordering_test_tx!();
1✔
852
        let mut tx = original_tx;
1✔
853

1✔
854
        TxOrdering::Bip69Lexicographic.sort_tx(&mut tx);
1✔
855

1✔
856
        assert_eq!(
1✔
857
            tx.input[0].previous_output,
1✔
858
            bitcoin::OutPoint::from_str(
1✔
859
                "0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57:5"
1✔
860
            )
1✔
861
            .unwrap()
1✔
862
        );
1✔
863
        assert_eq!(
1✔
864
            tx.input[1].previous_output,
1✔
865
            bitcoin::OutPoint::from_str(
1✔
866
                "0f60fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2:0"
1✔
867
            )
1✔
868
            .unwrap()
1✔
869
        );
1✔
870
        assert_eq!(
1✔
871
            tx.input[2].previous_output,
1✔
872
            bitcoin::OutPoint::from_str(
1✔
873
                "0f60fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2:1"
1✔
874
            )
1✔
875
            .unwrap()
1✔
876
        );
1✔
877

878
        assert_eq!(tx.output[0].value, 800);
1✔
879
        assert_eq!(tx.output[1].script_pubkey, ScriptBuf::from(vec![0xAA]));
1✔
880
        assert_eq!(
1✔
881
            tx.output[2].script_pubkey,
1✔
882
            ScriptBuf::from(vec![0xAA, 0xEE])
1✔
883
        );
1✔
884
    }
1✔
885

886
    fn get_test_utxos() -> Vec<LocalUtxo> {
3✔
887
        use bitcoin::hashes::Hash;
3✔
888

3✔
889
        vec![
3✔
890
            LocalUtxo {
3✔
891
                outpoint: OutPoint {
3✔
892
                    txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(),
3✔
893
                    vout: 0,
3✔
894
                },
3✔
895
                txout: Default::default(),
3✔
896
                keychain: KeychainKind::External,
3✔
897
                is_spent: false,
3✔
898
                confirmation_time: ConfirmationTime::Unconfirmed { last_seen: 0 },
3✔
899
                derivation_index: 0,
3✔
900
            },
3✔
901
            LocalUtxo {
3✔
902
                outpoint: OutPoint {
3✔
903
                    txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(),
3✔
904
                    vout: 1,
3✔
905
                },
3✔
906
                txout: Default::default(),
3✔
907
                keychain: KeychainKind::Internal,
3✔
908
                is_spent: false,
3✔
909
                confirmation_time: ConfirmationTime::Confirmed {
3✔
910
                    height: 32,
3✔
911
                    time: 42,
3✔
912
                },
3✔
913
                derivation_index: 1,
3✔
914
            },
3✔
915
        ]
3✔
916
    }
3✔
917

918
    #[test]
1✔
919
    fn test_change_spend_policy_default() {
1✔
920
        let change_spend_policy = ChangeSpendPolicy::default();
1✔
921
        let filtered = get_test_utxos()
1✔
922
            .into_iter()
1✔
923
            .filter(|u| change_spend_policy.is_satisfied_by(u))
2✔
924
            .count();
1✔
925

1✔
926
        assert_eq!(filtered, 2);
1✔
927
    }
1✔
928

929
    #[test]
1✔
930
    fn test_change_spend_policy_no_internal() {
1✔
931
        let change_spend_policy = ChangeSpendPolicy::ChangeForbidden;
1✔
932
        let filtered = get_test_utxos()
1✔
933
            .into_iter()
1✔
934
            .filter(|u| change_spend_policy.is_satisfied_by(u))
2✔
935
            .collect::<Vec<_>>();
1✔
936

1✔
937
        assert_eq!(filtered.len(), 1);
1✔
938
        assert_eq!(filtered[0].keychain, KeychainKind::External);
1✔
939
    }
1✔
940

941
    #[test]
1✔
942
    fn test_change_spend_policy_only_internal() {
1✔
943
        let change_spend_policy = ChangeSpendPolicy::OnlyChange;
1✔
944
        let filtered = get_test_utxos()
1✔
945
            .into_iter()
1✔
946
            .filter(|u| change_spend_policy.is_satisfied_by(u))
2✔
947
            .collect::<Vec<_>>();
1✔
948

1✔
949
        assert_eq!(filtered.len(), 1);
1✔
950
        assert_eq!(filtered[0].keychain, KeychainKind::Internal);
1✔
951
    }
1✔
952

953
    #[test]
1✔
954
    fn test_default_tx_version_1() {
1✔
955
        let version = Version::default();
1✔
956
        assert_eq!(version.0, 1);
1✔
957
    }
1✔
958
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc