pub struct TxBuilder<'a, Cs> { /* private fields */ }
Expand description
A transaction builder
A TxBuilder
is created by calling build_tx
or build_fee_bump
on a wallet. After
assigning it, you set options on it until finally calling finish
to consume the builder and
generate the transaction.
Each option setting method on TxBuilder
takes and returns &mut self
so you can chain calls
as in the following example:
// chaining
let psbt1 = {
let mut builder = wallet.build_tx();
builder
.ordering(TxOrdering::Untouched)
.add_recipient(addr1.script_pubkey(), Amount::from_sat(50_000))
.add_recipient(addr2.script_pubkey(), Amount::from_sat(50_000));
builder.finish()?
};
// non-chaining
let psbt2 = {
let mut builder = wallet.build_tx();
builder.ordering(TxOrdering::Untouched);
for addr in &[addr1, addr2] {
builder.add_recipient(addr.script_pubkey(), Amount::from_sat(50_000));
}
builder.finish()?
};
assert_eq!(psbt1.unsigned_tx.output[..2], psbt2.unsigned_tx.output[..2]);
At the moment coin_selection
is an exception to the rule as it consumes self
.
This means it is usually best to call coin_selection
on the return value of build_tx
before assigning it.
For further examples see this module’s documentation;
Implementations§
Source§impl<'a, Cs> TxBuilder<'a, Cs>
impl<'a, Cs> TxBuilder<'a, Cs>
Sourcepub fn fee_rate(&mut self, fee_rate: FeeRate) -> &mut Self
pub fn fee_rate(&mut self, fee_rate: FeeRate) -> &mut Self
Set a custom fee rate.
This method sets the mining fee paid by the transaction as a rate on its size.
This means that the total fee paid is equal to fee_rate
times the size
of the transaction. Default is 1 sat/vB in accordance with Bitcoin Core’s default
relay policy.
Note that this is really a minimum feerate – it’s possible to overshoot it slightly since adding a change output to drain the remaining excess might not be viable.
Sourcepub fn fee_absolute(&mut self, fee_amount: Amount) -> &mut Self
pub fn fee_absolute(&mut self, fee_amount: Amount) -> &mut Self
Set an absolute fee
The fee_absolute method refers to the absolute transaction fee in [Amount
].
If anyone sets both the fee_absolute
method and the fee_rate
method,
the FeePolicy
enum will be set by whichever method was called last,
as the [FeeRate
] and FeeAmount
are mutually exclusive.
Note that this is really a minimum absolute fee – it’s possible to overshoot it slightly since adding a change output to drain the remaining excess might not be viable.
Sourcepub fn policy_path(
&mut self,
policy_path: BTreeMap<String, Vec<usize>>,
keychain: KeychainKind,
) -> &mut Self
pub fn policy_path( &mut self, policy_path: BTreeMap<String, Vec<usize>>, keychain: KeychainKind, ) -> &mut Self
Set the policy path to use while creating the transaction for a given keychain.
This method accepts a map where the key is the policy node id (see
Policy::id
) and the value is the list of the indexes of
the items that are intended to be satisfied from the policy node (see
SatisfiableItem::Thresh::items
).
§Example
An example of when the policy path is needed is the following descriptor:
wsh(thresh(2,pk(A),sj:and_v(v:pk(B),n:older(6)),snj:and_v(v:pk(C),after(630000))))
,
derived from the miniscript policy thresh(2,pk(A),and(pk(B),older(6)),and(pk(C),after(630000)))
.
It declares three descriptor fragments, and at the top level it uses thresh()
to
ensure that at least two of them are satisfied. The individual fragments are:
pk(A)
and(pk(B),older(6))
and(pk(C),after(630000))
When those conditions are combined in pairs, it’s clear that the transaction needs to be created differently depending on how the user intends to satisfy the policy afterwards:
- If fragments
1
and2
are used, the transaction will need to use a specificn_sequence
in order to spend anOP_CSV
branch. - If fragments
1
and3
are used, the transaction will need to use a specificlocktime
in order to spend anOP_CLTV
branch. - If fragments
2
and3
are used, the transaction will need both.
When the spending policy is represented as a tree (see
Wallet::policies
), every node
is assigned a unique identifier that can be used in the policy path to specify which of
the node’s children the user intends to satisfy: for instance, assuming the thresh()
root node of this example has an id of aabbccdd
, the policy path map would look like:
{ "aabbccdd" => [0, 1] }
where the key is the node’s id, and the value is a list of the children that should be used, in no particular order.
If a particularly complex descriptor has multiple ambiguous thresholds in its structure, multiple entries can be added to the map, one for each node that requires an explicit path.
Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
.unwrap()
.assume_checked();
let mut path = BTreeMap::new();
path.insert("aabbccdd".to_string(), vec![0, 1]);
let builder = wallet
.build_tx()
.add_recipient(to_address.script_pubkey(), Amount::from_sat(50_000))
.policy_path(path, KeychainKind::External);
Sourcepub fn add_utxos(
&mut self,
outpoints: &[OutPoint],
) -> Result<&mut Self, AddUtxoError>
pub fn add_utxos( &mut self, outpoints: &[OutPoint], ) -> Result<&mut Self, AddUtxoError>
Add the list of outpoints to the internal list of UTXOs that must be spent.
If an error occurs while adding any of the UTXOs then none of them are added and the error is returned.
These have priority over the “unspendable” utxos, meaning that if a utxo is present both in the “utxos” and the “unspendable” list, it will be spent.
Sourcepub fn add_utxo(
&mut self,
outpoint: OutPoint,
) -> Result<&mut Self, AddUtxoError>
pub fn add_utxo( &mut self, outpoint: OutPoint, ) -> Result<&mut Self, AddUtxoError>
Add a utxo to the internal list of utxos that must be spent
These have priority over the “unspendable” utxos, meaning that if a utxo is present both in the “utxos” and the “unspendable” list, it will be spent.
Sourcepub fn add_foreign_utxo(
&mut self,
outpoint: OutPoint,
psbt_input: Input,
satisfaction_weight: Weight,
) -> Result<&mut Self, AddForeignUtxoError>
pub fn add_foreign_utxo( &mut self, outpoint: OutPoint, psbt_input: Input, satisfaction_weight: Weight, ) -> Result<&mut Self, AddForeignUtxoError>
Add a foreign UTXO i.e. a UTXO not owned by this wallet.
At a minimum to add a foreign UTXO we need:
outpoint
: To add it to the raw transaction.psbt_input
: To know the value.satisfaction_weight
: To know how much weight/vbytes the input will add to the transaction for fee calculation.
There are several security concerns about adding foreign UTXOs that application
developers should consider. First, how do you know the value of the input is correct? If a
non_witness_utxo
is provided in the psbt_input
then this method implicitly verifies the
value by checking it against the transaction. If only a witness_utxo
is provided then this
method doesn’t verify the value but just takes it as a given – it is up to you to check
that whoever sent you the input_psbt
was not lying!
Secondly, you must somehow provide satisfaction_weight
of the input. Depending on your
application it may be important that this be known precisely. If not, a malicious
counterparty may fool you into putting in a value that is too low, giving the transaction a
lower than expected feerate. They could also fool you into putting a value that is too high
causing you to pay a fee that is too high. The party who is broadcasting the transaction can
of course check the real input weight matches the expected weight prior to broadcasting.
To guarantee the max_weight_to_satisfy
is correct, you can require the party providing the
psbt_input
provide a miniscript descriptor for the input so you can check it against the
script_pubkey
and then ask it for the max_weight_to_satisfy
.
This is an EXPERIMENTAL feature, API and other major changes are expected.
In order to use Wallet::calculate_fee
or Wallet::calculate_fee_rate
for a transaction
created with foreign UTXO(s) you must manually insert the corresponding TxOut(s) into the tx
graph using the Wallet::insert_txout
function.
§Errors
This method returns errors in the following circumstances:
- The
psbt_input
does not contain awitness_utxo
ornon_witness_utxo
. - The data in
non_witness_utxo
does not match what is inoutpoint
.
Note unless you set only_witness_utxo
any non-taproot psbt_input
you pass to this
method must have non_witness_utxo
set otherwise you will get an error when finish
is called.
Sourcepub fn add_foreign_utxo_with_sequence(
&mut self,
outpoint: OutPoint,
psbt_input: Input,
satisfaction_weight: Weight,
sequence: Sequence,
) -> Result<&mut Self, AddForeignUtxoError>
pub fn add_foreign_utxo_with_sequence( &mut self, outpoint: OutPoint, psbt_input: Input, satisfaction_weight: Weight, sequence: Sequence, ) -> Result<&mut Self, AddForeignUtxoError>
Same as add_foreign_utxo but allows to set the nSequence value.
Sourcepub fn manually_selected_only(&mut self) -> &mut Self
pub fn manually_selected_only(&mut self) -> &mut Self
Only spend utxos added by add_utxo
.
The wallet will not add additional utxos to the transaction even if they are needed to make the transaction valid.
Sourcepub fn unspendable(&mut self, unspendable: Vec<OutPoint>) -> &mut Self
pub fn unspendable(&mut self, unspendable: Vec<OutPoint>) -> &mut Self
Replace the internal list of unspendable utxos with a new list
It’s important to note that the “must-be-spent” utxos added with TxBuilder::add_utxo
have priority over these. See the docs of the two linked methods for more details.
Sourcepub fn add_unspendable(&mut self, unspendable: OutPoint) -> &mut Self
pub fn add_unspendable(&mut self, unspendable: OutPoint) -> &mut Self
Add a utxo to the internal list of unspendable utxos
It’s important to note that the “must-be-spent” utxos added with TxBuilder::add_utxo
have priority over this. See the docs of the two linked methods for more details.
Sourcepub fn sighash(&mut self, sighash: PsbtSighashType) -> &mut Self
pub fn sighash(&mut self, sighash: PsbtSighashType) -> &mut Self
Sign with a specific sig hash
Use this option very carefully
Sourcepub fn ordering(&mut self, ordering: TxOrdering) -> &mut Self
pub fn ordering(&mut self, ordering: TxOrdering) -> &mut Self
Choose the ordering for inputs and outputs of the transaction
Sourcepub fn nlocktime(&mut self, locktime: LockTime) -> &mut Self
pub fn nlocktime(&mut self, locktime: LockTime) -> &mut Self
Use a specific nLockTime while creating the transaction
This can cause conflicts if the wallet’s descriptors contain an “after” (OP_CLTV) operator.
Sourcepub fn version(&mut self, version: i32) -> &mut Self
pub fn version(&mut self, version: i32) -> &mut Self
Build a transaction with a specific version
The version
should always be greater than 0
and greater than 1
if the wallet’s
descriptors contain an “older” (OP_CSV) operator.
Sourcepub fn do_not_spend_change(&mut self) -> &mut Self
pub fn do_not_spend_change(&mut self) -> &mut Self
Do not spend change outputs
This effectively adds all the change outputs to the “unspendable” list. See
TxBuilder::unspendable
. This method assumes the presence of an internal
keychain, otherwise it has no effect.
Sourcepub fn only_spend_change(&mut self) -> &mut Self
pub fn only_spend_change(&mut self) -> &mut Self
Only spend change outputs
This effectively adds all the non-change outputs to the “unspendable” list. See
TxBuilder::unspendable
. This method assumes the presence of an internal
keychain, otherwise it has no effect.
Sourcepub fn change_policy(&mut self, change_policy: ChangeSpendPolicy) -> &mut Self
pub fn change_policy(&mut self, change_policy: ChangeSpendPolicy) -> &mut Self
Set a specific ChangeSpendPolicy
. See TxBuilder::do_not_spend_change
and
TxBuilder::only_spend_change
for some shortcuts. This method assumes the presence
of an internal keychain, otherwise it has no effect.
Sourcepub fn only_witness_utxo(&mut self) -> &mut Self
pub fn only_witness_utxo(&mut self) -> &mut Self
Only Fill-in the psbt::Input::witness_utxo
field when spending from
SegWit descriptors.
This reduces the size of the PSBT, but some signers might reject them due to the lack of
the non_witness_utxo
.
Sourcepub fn include_output_redeem_witness_script(&mut self) -> &mut Self
pub fn include_output_redeem_witness_script(&mut self) -> &mut Self
Fill-in the psbt::Output::redeem_script
and
psbt::Output::witness_script
fields.
This is useful for signers which always require it, like ColdCard hardware wallets.
Sourcepub fn add_global_xpubs(&mut self) -> &mut Self
pub fn add_global_xpubs(&mut self) -> &mut Self
Fill-in the PSBT_GLOBAL_XPUB
field with the extended keys contained in both the external
and internal descriptors
This is useful for offline signers that take part to a multisig. Some hardware wallets like BitBox and ColdCard are known to require this.
Sourcepub fn drain_wallet(&mut self) -> &mut Self
pub fn drain_wallet(&mut self) -> &mut Self
Spend all the available inputs. This respects filters like TxBuilder::unspendable
and the change policy.
Sourcepub fn coin_selection<P: CoinSelectionAlgorithm>(
self,
coin_selection: P,
) -> TxBuilder<'a, P>
pub fn coin_selection<P: CoinSelectionAlgorithm>( self, coin_selection: P, ) -> TxBuilder<'a, P>
Choose the coin selection algorithm
Overrides the CoinSelectionAlgorithm
.
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.
Sourcepub fn set_exact_sequence(&mut self, n_sequence: Sequence) -> &mut Self
pub fn set_exact_sequence(&mut self, n_sequence: Sequence) -> &mut Self
Set an exact nSequence value
This can cause conflicts if the wallet’s descriptors contain an
“older” (OP_CSV) operator and the given nsequence
is lower than the CSV value.
Sourcepub fn current_height(&mut self, height: u32) -> &mut Self
pub fn current_height(&mut self, height: u32) -> &mut Self
Set the current blockchain height.
This will be used to:
- Set the nLockTime for preventing fee sniping.
Note: This will be ignored if you manually specify a nlocktime using
TxBuilder::nlocktime
. - Decide whether coinbase outputs are mature or not. If the coinbase outputs are not
mature at
current_height
, we ignore them in the coin selection. If you want to create a transaction that spends immature coinbase inputs, manually add them usingTxBuilder::add_utxos
.
In both cases, if you don’t provide a current height, we use the last sync height.
Sourcepub fn allow_dust(&mut self, allow_dust: bool) -> &mut Self
pub fn allow_dust(&mut self, allow_dust: bool) -> &mut Self
Set whether or not the dust limit is checked.
Note: by avoiding a dust limit check you may end up with a transaction that is non-standard.
Sourcepub fn set_recipients(
&mut self,
recipients: Vec<(ScriptBuf, Amount)>,
) -> &mut Self
pub fn set_recipients( &mut self, recipients: Vec<(ScriptBuf, Amount)>, ) -> &mut Self
Replace the recipients already added with a new list
Sourcepub fn add_recipient(
&mut self,
script_pubkey: ScriptBuf,
amount: Amount,
) -> &mut Self
pub fn add_recipient( &mut self, script_pubkey: ScriptBuf, amount: Amount, ) -> &mut Self
Add a recipient to the internal list
Sourcepub fn add_data<T: AsRef<PushBytes>>(&mut self, data: &T) -> &mut Self
pub fn add_data<T: AsRef<PushBytes>>(&mut self, data: &T) -> &mut Self
Add data as an output, using OP_RETURN
Sourcepub fn drain_to(&mut self, script_pubkey: ScriptBuf) -> &mut Self
pub fn drain_to(&mut self, script_pubkey: ScriptBuf) -> &mut Self
Sets the address to drain excess coins to.
Usually, when there are excess coins they are sent to a change address generated by the
wallet. This option replaces the usual change address with an arbitrary script_pubkey
of
your choosing. Just as with a change output, if the drain output is not needed (the excess
coins are too small) it will not be included in the resulting transaction. The only
difference is that it is valid to use drain_to
without setting any ordinary recipients
with add_recipient
(but it is perfectly fine to add recipients as well).
If you choose not to set any recipients, you should provide the utxos that the
transaction should spend via add_utxos
.
§Example
drain_to
is very useful for draining all the coins in a wallet with drain_wallet
to a
single address.
Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt")
.unwrap()
.assume_checked();
let mut tx_builder = wallet.build_tx();
tx_builder
// Spend all outputs in this wallet.
.drain_wallet()
// Send the excess (which is all the coins minus the fee) to this address.
.drain_to(to_address.script_pubkey())
.fee_rate(FeeRate::from_sat_per_vb(5).expect("valid feerate"));
let psbt = tx_builder.finish()?;
Source§impl<Cs: CoinSelectionAlgorithm> TxBuilder<'_, Cs>
impl<Cs: CoinSelectionAlgorithm> TxBuilder<'_, Cs>
Sourcepub fn finish(self) -> Result<Psbt, CreateTxError>
pub fn finish(self) -> Result<Psbt, CreateTxError>
Finish building the transaction.
Uses the thread-local random number generator (rng).
Returns a new [Psbt
] per BIP174
.
WARNING: To avoid change address reuse you must persist the changes resulting from one
or more calls to this method before closing the wallet. See Wallet::reveal_next_address
.
Sourcepub fn finish_with_aux_rand(
self,
rng: &mut impl RngCore,
) -> Result<Psbt, CreateTxError>
pub fn finish_with_aux_rand( self, rng: &mut impl RngCore, ) -> Result<Psbt, CreateTxError>
Finish building the transaction.
Uses a provided random number generator (rng).
Returns a new [Psbt
] per BIP174
.
WARNING: To avoid change address reuse you must persist the changes resulting from one
or more calls to this method before closing the wallet. See Wallet::reveal_next_address
.