2021-03-03 13:22:05 -08:00
// Bitcoin Dev Kit
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
2020-08-31 11:26:36 +02:00
//
2021-03-03 13:22:05 -08:00
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
2020-08-31 11:26:36 +02:00
//
2021-03-03 13:22:05 -08:00
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.
2020-08-31 11:26:36 +02:00
2020-09-04 16:29:25 +02:00
//! Wallet
//!
//! This module defines the [`Wallet`] structure.
2023-01-10 15:10:02 +11:00
use crate ::collections ::{ BTreeMap , HashMap , HashSet } ;
use alloc ::{
boxed ::Box ,
string ::{ String , ToString } ,
sync ::Arc ,
vec ::Vec ,
} ;
2023-02-15 12:23:59 +11:00
use bdk_chain ::{
chain_graph ,
keychain ::{ KeychainChangeSet , KeychainScan , KeychainTracker } ,
sparse_chain , BlockId , ConfirmationTime , IntoOwned ,
} ;
2022-11-03 15:59:38 +08:00
use bitcoin ::secp256k1 ::Secp256k1 ;
2023-01-10 15:10:02 +11:00
use core ::fmt ;
use core ::ops ::Deref ;
2020-02-07 23:22:28 +01:00
use bitcoin ::consensus ::encode ::serialize ;
2022-10-25 11:15:43 +02:00
use bitcoin ::util ::psbt ;
2022-04-26 15:11:22 +02:00
use bitcoin ::{
2022-11-03 15:59:38 +08:00
Address , BlockHash , EcdsaSighashType , LockTime , Network , OutPoint , SchnorrSighashType , Script ,
Sequence , Transaction , TxOut , Txid , Witness ,
2022-04-26 15:11:22 +02:00
} ;
2020-02-07 23:22:28 +01:00
2022-10-25 11:15:43 +02:00
use miniscript ::psbt ::{ PsbtExt , PsbtInputExt , PsbtInputSatisfier } ;
2020-02-07 23:22:28 +01:00
#[ allow(unused_imports) ]
use log ::{ debug , error , info , trace } ;
2020-08-06 16:56:41 +02:00
pub mod coin_selection ;
2020-08-07 10:19:06 +02:00
pub mod export ;
2020-08-12 12:51:50 +02:00
pub mod signer ;
2020-08-06 13:09:39 +02:00
pub mod tx_builder ;
2020-08-31 10:49:44 +02:00
pub ( crate ) mod utils ;
2022-07-26 00:07:04 +05:30
#[ cfg(feature = " hardware-signer " ) ]
2022-08-29 16:16:56 +02:00
#[ cfg_attr(docsrs, doc(cfg(feature = " hardware-signer " ))) ]
2022-07-26 00:07:04 +05:30
pub mod hardwaresigner ;
2023-02-15 12:23:59 +11:00
pub mod persist ;
2022-07-26 00:07:04 +05:30
2020-08-31 10:49:44 +02:00
pub use utils ::IsDust ;
2020-02-07 23:22:28 +01:00
2022-11-03 15:59:38 +08:00
#[ allow(deprecated) ]
2021-01-01 13:35:05 +11:00
use coin_selection ::DefaultCoinSelectionAlgorithm ;
2022-04-26 16:54:10 +02:00
use signer ::{ SignOptions , SignerOrdering , SignersContainer , TransactionSigner } ;
2021-01-01 13:35:05 +11:00
use tx_builder ::{ BumpFee , CreateTx , FeePolicy , TxBuilder , TxParams } ;
2022-10-25 11:15:43 +02:00
use utils ::{ check_nsequence_rbf , After , Older , SecpCtx } ;
2020-08-06 11:12:15 +02:00
2021-04-02 16:39:18 +02:00
use crate ::descriptor ::policy ::BuildSatisfaction ;
2020-08-12 12:51:50 +02:00
use crate ::descriptor ::{
2022-10-26 22:01:07 -05:00
calc_checksum , into_wallet_descriptor_checked , DerivedDescriptor , DescriptorMeta ,
2023-02-15 12:23:59 +11:00
ExtendedDescriptor , ExtractPolicy , IntoWalletDescriptor , Policy , XKeyUtils ,
2020-08-12 12:51:50 +02:00
} ;
2022-10-25 11:15:43 +02:00
use crate ::error ::{ Error , MiniscriptPsbtError } ;
2021-03-30 16:33:07 +02:00
use crate ::psbt ::PsbtUtils ;
2021-05-06 15:55:58 +02:00
use crate ::signer ::SignerError ;
2020-02-07 23:22:28 +01:00
use crate ::types ::* ;
2022-06-13 10:49:31 -03:00
use crate ::wallet ::coin_selection ::Excess ::{ Change , NoChange } ;
2020-02-07 23:22:28 +01:00
2022-05-25 18:56:50 +01:00
const COINBASE_MATURITY : u32 = 100 ;
2020-08-06 18:11:07 +02:00
2020-09-04 16:29:25 +02:00
/// A Bitcoin wallet
///
2022-01-26 15:17:48 +11:00
/// The `Wallet` struct acts as a way of coherently interfacing with output descriptors and related transactions.
/// Its main components are:
2020-09-04 16:29:25 +02:00
///
2022-01-26 15:17:48 +11:00
/// 1. output *descriptors* from which it can derive addresses.
/// 2. A [`Database`] where it tracks transactions and utxos related to the descriptors.
2022-04-26 16:54:10 +02:00
/// 3. [`signer`]s that can contribute signatures to addresses instantiated from the descriptors.
2022-01-26 15:17:48 +11:00
///
/// [`Database`]: crate::database::Database
2022-04-26 16:54:10 +02:00
/// [`signer`]: crate::signer
2021-01-22 14:11:29 +11:00
#[ derive(Debug) ]
2023-02-15 12:23:59 +11:00
pub struct Wallet < D = ( ) > {
2020-10-09 12:03:47 +02:00
signers : Arc < SignersContainer > ,
change_signers : Arc < SignersContainer > ,
2022-11-03 15:59:38 +08:00
keychain_tracker : KeychainTracker < KeychainKind , ConfirmationTime > ,
2023-02-15 12:23:59 +11:00
persist : persist ::Persist < D > ,
2020-02-07 23:22:28 +01:00
network : Network ,
2020-11-16 22:07:38 +01:00
secp : SecpCtx ,
2020-02-07 23:22:28 +01:00
}
2023-02-15 12:23:59 +11:00
/// The update to a [`Wallet`] used in [Wallet::apply_update]. This is usually returned from blockchain data sources.
/// The type parameter `T` indicates the kind of transaction contained in the update. It's usually a [`bitcoin::Transaction`].
pub type Update < T > = KeychainScan < KeychainKind , ConfirmationTime , T > ;
/// Error indicating that something was wrong with an [`Update<T>`].
pub type UpdateError = chain_graph ::UpdateError < ConfirmationTime > ;
/// The changeset produced internally by applying an update
pub ( crate ) type ChangeSet = KeychainChangeSet < KeychainKind , ConfirmationTime , Transaction > ;
2021-03-08 16:17:10 -08:00
/// The address index selection strategy to use to derived an address from the wallet's external
2021-03-10 15:58:58 -08:00
/// descriptor. See [`Wallet::get_address`]. If you're unsure which one to use use `WalletIndex::New`.
2021-03-08 16:17:10 -08:00
#[ derive(Debug) ]
pub enum AddressIndex {
/// Return a new address after incrementing the current descriptor index.
New ,
/// Return the address for the current descriptor index if it has not been used in a received
/// transaction. Otherwise return a new address as with [`AddressIndex::New`].
///
/// Use with caution, if the wallet has not yet detected an address has been used it could
/// return an already used address. This function is primarily meant for situations where the
/// caller is untrusted; for example when deriving donation addresses on-demand for a public
/// web page.
LastUnused ,
2021-03-10 15:58:58 -08:00
/// Return the address for a specific descriptor index. Does not change the current descriptor
/// index used by `AddressIndex::New` and `AddressIndex::LastUsed`.
///
/// Use with caution, if an index is given that is less than the current descriptor index
/// then the returned address may have already been used.
Peek ( u32 ) ,
2021-03-08 16:17:10 -08:00
}
2023-01-19 15:03:37 -05:00
/// A derived address and the index it was found at.
2021-05-17 16:31:18 -04:00
/// For convenience this automatically derefs to `Address`
2022-10-25 11:15:43 +02:00
#[ derive(Debug, PartialEq, Eq) ]
2021-05-17 16:31:18 -04:00
pub struct AddressInfo {
/// Child index of this address
pub index : u32 ,
/// Address
pub address : Address ,
2022-03-10 06:22:02 +05:30
/// Type of keychain
pub keychain : KeychainKind ,
2021-05-17 16:31:18 -04:00
}
impl Deref for AddressInfo {
type Target = Address ;
fn deref ( & self ) -> & Self ::Target {
& self . address
}
}
impl fmt ::Display for AddressInfo {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
write! ( f , " {} " , self . address )
}
}
2022-11-03 15:59:38 +08:00
impl Wallet {
2023-02-15 12:23:59 +11:00
/// Creates a wallet that does not persist data.
pub fn new_no_persist < E : IntoWalletDescriptor > (
descriptor : E ,
change_descriptor : Option < E > ,
network : Network ,
) -> Result < Self , crate ::descriptor ::DescriptorError > {
Self ::new ( descriptor , change_descriptor , ( ) , network ) . map_err ( | e | match e {
NewError ::Descriptor ( e ) = > e ,
NewError ::Persist ( _ ) = > unreachable! ( " no persistence so it can't fail " ) ,
} )
}
}
#[ derive(Debug) ]
/// Error returned from [`Wallet::new`]
pub enum NewError < P > {
/// There was problem with the descriptors passed in
Descriptor ( crate ::descriptor ::DescriptorError ) ,
/// We were unable to load the wallet's data from the persistance backend
Persist ( P ) ,
}
impl < P > core ::fmt ::Display for NewError < P >
where
P : core ::fmt ::Display ,
{
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
match self {
NewError ::Descriptor ( e ) = > e . fmt ( f ) ,
NewError ::Persist ( e ) = > {
write! ( f , " failed to load wallet from persistance backend: {} " , e )
}
}
}
}
#[ cfg(feautre = " std " ) ]
impl < P : core ::fmt ::Display > std ::error ::Error for NewError < P > { }
impl < D > Wallet < D > {
/// Create a wallet from a `descriptor` (and an optional `change_descriptor`) and load related
/// transaction data from `db`.
2022-01-26 15:17:48 +11:00
pub fn new < E : IntoWalletDescriptor > (
descriptor : E ,
change_descriptor : Option < E > ,
2023-02-15 12:23:59 +11:00
mut db : D ,
2022-01-26 15:17:48 +11:00
network : Network ,
2023-02-15 12:23:59 +11:00
) -> Result < Self , NewError < D ::LoadError > >
where
D : persist ::Backend ,
{
2022-01-26 15:17:48 +11:00
let secp = Secp256k1 ::new ( ) ;
2022-11-03 15:59:38 +08:00
let mut keychain_tracker = KeychainTracker ::default ( ) ;
2023-02-15 12:23:59 +11:00
let ( descriptor , keymap ) = into_wallet_descriptor_checked ( descriptor , & secp , network )
. map_err ( NewError ::Descriptor ) ? ;
2022-11-03 15:59:38 +08:00
keychain_tracker
. txout_index
. add_keychain ( KeychainKind ::External , descriptor . clone ( ) ) ;
2022-05-12 17:28:41 +02:00
let signers = Arc ::new ( SignersContainer ::build ( keymap , & descriptor , & secp ) ) ;
2022-11-03 15:59:38 +08:00
let change_signers = match change_descriptor {
2022-01-26 15:17:48 +11:00
Some ( desc ) = > {
let ( change_descriptor , change_keymap ) =
2023-02-15 12:23:59 +11:00
into_wallet_descriptor_checked ( desc , & secp , network )
. map_err ( NewError ::Descriptor ) ? ;
2022-01-26 15:17:48 +11:00
2022-05-12 17:28:41 +02:00
let change_signers = Arc ::new ( SignersContainer ::build (
change_keymap ,
& change_descriptor ,
& secp ,
) ) ;
2022-01-26 15:17:48 +11:00
2022-11-03 15:59:38 +08:00
keychain_tracker
. txout_index
. add_keychain ( KeychainKind ::Internal , change_descriptor ) ;
change_signers
2022-01-26 15:17:48 +11:00
}
2022-11-03 15:59:38 +08:00
None = > Arc ::new ( SignersContainer ::new ( ) ) ,
2022-01-26 15:17:48 +11:00
} ;
2023-02-15 12:23:59 +11:00
db . load_into_keychain_tracker ( & mut keychain_tracker )
. map_err ( NewError ::Persist ) ? ;
let persist = persist ::Persist ::new ( db ) ;
2022-01-26 15:17:48 +11:00
Ok ( Wallet {
signers ,
change_signers ,
network ,
2023-02-15 12:23:59 +11:00
persist ,
2022-01-26 15:17:48 +11:00
secp ,
2022-11-03 15:59:38 +08:00
keychain_tracker ,
2022-01-26 15:17:48 +11:00
} )
}
/// Get the Bitcoin network the wallet is using.
pub fn network ( & self ) -> Network {
self . network
}
2022-11-03 15:59:38 +08:00
/// Iterator over all keychains in this wallet
pub fn keychanins ( & self ) -> & BTreeMap < KeychainKind , ExtendedDescriptor > {
self . keychain_tracker . txout_index . keychains ( )
}
2021-03-07 21:57:19 -08:00
2021-03-08 16:17:10 -08:00
/// Return a derived address using the external descriptor, see [`AddressIndex`] for
2021-03-10 15:58:58 -08:00
/// available address index selection strategies. If none of the keys in the descriptor are derivable
2022-08-05 11:39:50 -04:00
/// (i.e. does not end with /*) then the same address will always be returned for any [`AddressIndex`].
2023-02-15 12:23:59 +11:00
pub fn get_address ( & mut self , address_index : AddressIndex ) -> AddressInfo
where
D : persist ::Backend ,
{
2021-08-19 19:57:35 +10:00
self . _get_address ( address_index , KeychainKind ::External )
}
/// Return a derived address using the internal (change) descriptor.
///
/// If the wallet doesn't have an internal descriptor it will use the external descriptor.
///
/// see [`AddressIndex`] for available address index selection strategies. If none of the keys
2022-08-05 11:39:50 -04:00
/// in the descriptor are derivable (i.e. does not end with /*) then the same address will always
2021-08-19 19:57:35 +10:00
/// be returned for any [`AddressIndex`].
2023-02-15 12:23:59 +11:00
pub fn get_internal_address ( & mut self , address_index : AddressIndex ) -> AddressInfo
where
D : persist ::Backend ,
{
2021-08-19 19:57:35 +10:00
self . _get_address ( address_index , KeychainKind ::Internal )
}
2023-02-15 12:23:59 +11:00
fn _get_address ( & mut self , address_index : AddressIndex , keychain : KeychainKind ) -> AddressInfo
where
D : persist ::Backend ,
{
let keychain = self . map_keychain ( keychain ) ;
let txout_index = & mut self . keychain_tracker . txout_index ;
let ( index , spk ) = match address_index {
AddressIndex ::New = > {
let ( ( index , spk ) , changeset ) = txout_index . reveal_next_spk ( & keychain ) ;
let spk = spk . clone ( ) ;
self . persist . stage ( changeset . into ( ) ) ;
self . persist . commit ( ) . expect ( " TODO " ) ;
( index , spk )
}
AddressIndex ::LastUnused = > {
let index = txout_index . last_revealed_index ( & keychain ) ;
match index {
Some ( index ) if ! txout_index . is_used ( & ( keychain , index ) ) = > (
index ,
txout_index
. spk_at_index ( & ( keychain , index ) )
. expect ( " must exist " )
. clone ( ) ,
) ,
_ = > return self . _get_address ( AddressIndex ::New , keychain ) ,
}
}
AddressIndex ::Peek ( index ) = > txout_index
. spks_of_keychain ( & keychain )
. take ( index as usize + 1 )
. last ( )
. unwrap ( ) ,
} ;
let info = AddressInfo {
index ,
address : Address ::from_script ( & spk , self . network )
. expect ( " descriptor must have address form " ) ,
keychain ,
2022-02-02 08:27:53 -05:00
} ;
2022-11-03 15:59:38 +08:00
info
2021-03-08 16:17:10 -08:00
}
2020-09-04 16:29:25 +02:00
/// Return whether or not a `script` is part of this wallet (either internal or external)
2022-11-03 15:59:38 +08:00
pub fn is_mine ( & self , script : & Script ) -> bool {
self . keychain_tracker
. txout_index
. index_of_spk ( script )
. is_some ( )
2020-02-07 23:22:28 +01:00
}
2023-02-15 12:52:10 +11:00
/// Finds how the wallet derived the script pubkey `spk`.
///
/// Will only return `Some(_)` if the wallet has given out the spk.
pub fn derivation_of_spk ( & self , spk : & Script ) -> Option < ( KeychainKind , u32 ) > {
self . keychain_tracker . txout_index . index_of_spk ( spk ) . copied ( )
}
2020-09-04 16:29:25 +02:00
/// Return the list of unspent outputs of this wallet
///
2021-09-23 16:12:53 +05:30
/// Note that this method only operates on the internal database, which first needs to be
2020-09-04 16:29:25 +02:00
/// [`Wallet::sync`] manually.
2022-11-03 15:59:38 +08:00
pub fn list_unspent ( & self ) -> Vec < LocalUtxo > {
self . keychain_tracker
. full_utxos ( )
. map ( | ( & ( keychain , derivation_index ) , utxo ) | LocalUtxo {
outpoint : utxo . outpoint ,
txout : utxo . txout ,
keychain : keychain . clone ( ) ,
is_spent : false ,
derivation_index ,
confirmation_time : utxo . chain_position ,
} )
. collect ( )
}
2023-02-15 12:23:59 +11:00
/// Get all the checkpoints the wallet is currently storing indexed by height.
2022-11-03 15:59:38 +08:00
pub fn checkpoints ( & self ) -> & BTreeMap < u32 , BlockHash > {
self . keychain_tracker . chain ( ) . checkpoints ( )
}
/// Returns the latest checkpoint.
pub fn latest_checkpoint ( & self ) -> Option < BlockId > {
self . keychain_tracker . chain ( ) . latest_checkpoint ( )
}
2023-02-15 12:23:59 +11:00
/// Returns a iterators of all the script pubkeys for the `Internal` and External` variants in `KeychainKind`.
///
/// This is inteded to be used when doing a full scan of your addresses (e.g. after restoring
/// from seed words). You pass the `BTreeMap` of iterators to a blockchain data source (e.g.
/// electrum server) which will go through each address until it reaches a *stop grap*.
///
/// Note carefully that iterators go over **all** script pubkeys on the keychains (not what
/// script pubkeys the wallet is storing internally).
pub fn spks_of_all_keychains (
& self ,
) -> BTreeMap < KeychainKind , impl Iterator < Item = ( u32 , Script ) > + Clone > {
self . keychain_tracker . txout_index . spks_of_all_keychains ( )
2020-02-07 23:22:28 +01:00
}
2023-02-15 12:23:59 +11:00
/// Gets an iterator over all the script pubkeys in a single keychain.
///
/// See [`spks_of_all_keychains`] for more documentation
///
/// [`spks_of_all_keychains`]: Self::spks_of_all_keychains
pub fn spks_of_keychain (
& self ,
keychain : KeychainKind ,
) -> impl Iterator < Item = ( u32 , Script ) > + Clone {
self . keychain_tracker
. txout_index
. spks_of_keychain ( & keychain )
}
/// Returns the utxo owned by this wallet corresponding to `outpoint` if it exists in the
2021-01-01 13:35:05 +11:00
/// wallet's database.
2022-11-03 15:59:38 +08:00
pub fn get_utxo ( & self , op : OutPoint ) -> Option < LocalUtxo > {
self . keychain_tracker
. full_utxos ( )
. find_map ( | ( & ( keychain , derivation_index ) , txo ) | {
if op = = txo . outpoint {
Some ( LocalUtxo {
outpoint : txo . outpoint ,
txout : txo . txout ,
keychain ,
is_spent : txo . spent_by . is_none ( ) ,
derivation_index ,
confirmation_time : txo . chain_position ,
} )
} else {
None
}
} )
2021-01-01 13:35:05 +11:00
}
2021-09-23 16:12:53 +05:30
/// Return a single transactions made and received by the wallet
///
/// Optionally fill the [`TransactionDetails::transaction`] field with the raw transaction if
/// `include_raw` is `true`.
///
/// Note that this method only operates on the internal database, which first needs to be
/// [`Wallet::sync`] manually.
2022-11-03 15:59:38 +08:00
pub fn get_tx ( & self , txid : Txid , include_raw : bool ) -> Option < TransactionDetails > {
let ( & confirmation_time , tx ) = self . keychain_tracker . chain_graph ( ) . get_tx_in_chain ( txid ) ? ;
let graph = self . keychain_tracker . graph ( ) ;
let txout_index = & self . keychain_tracker . txout_index ;
let received = tx
. output
. iter ( )
. map ( | txout | {
if txout_index . index_of_spk ( & txout . script_pubkey ) . is_some ( ) {
txout . value
} else {
0
}
} )
. sum ( ) ;
let sent = tx
. input
. iter ( )
. map ( | txin | {
if let Some ( ( _ , txout ) ) = txout_index . txout ( txin . previous_output ) {
txout . value
} else {
0
}
} )
. sum ( ) ;
let inputs = tx
. input
. iter ( )
. map ( | txin | {
graph
. get_txout ( txin . previous_output )
. map ( | txout | txout . value )
} )
. sum ::< Option < u64 > > ( ) ;
let outputs = tx . output . iter ( ) . map ( | txout | txout . value ) . sum ( ) ;
let fee = inputs . map ( | inputs | inputs . saturating_sub ( outputs ) ) ;
Some ( TransactionDetails {
transaction : if include_raw { Some ( tx . clone ( ) ) } else { None } ,
txid ,
received ,
sent ,
fee ,
confirmation_time ,
} )
2021-09-23 16:12:53 +05:30
}
2023-02-15 12:23:59 +11:00
/// Add a new checkpoint to the wallet's internal view of the chain.
/// This stages but does not [`commit`] the change.
///
/// Returns whether anything changed with the insertion (e.g. `false` if checkpoint was already
/// there).
///
/// [`commit`]: Self::commit
2022-11-03 15:59:38 +08:00
pub fn insert_checkpoint (
& mut self ,
block_id : BlockId ,
) -> Result < bool , sparse_chain ::InsertCheckpointError > {
2023-02-15 12:23:59 +11:00
let changeset = self . keychain_tracker . insert_checkpoint ( block_id ) ? ;
let changed = changeset . is_empty ( ) ;
self . persist . stage ( changeset ) ;
Ok ( changed )
2022-11-03 15:59:38 +08:00
}
2023-02-15 12:23:59 +11:00
/// Add a transaction to the wallet's internal view of the chain.
/// This stages but does not [`commit`] the change.
///
/// There are a number reasons `tx` could be rejected with an `Err(_)`. The most important one
/// is that the transaction is at a height that is greater than [`latest_checkpoint`]. Therefore
/// you should use [`insert_checkpoint`] to insert new checkpoints before manually inserting new
/// transactions.
///
/// Returns whether anything changed with the transaction insertion (e.g. `false` if the
/// transaction was already inserted at the same position).
///
/// [`commit`]: Self::commit
/// [`latest_checkpoint`]: Self::latest_checkpoint
/// [`insert_checkpoint`]: Self::insert_checkpoint
2022-11-03 15:59:38 +08:00
pub fn insert_tx (
& mut self ,
tx : Transaction ,
position : ConfirmationTime ,
) -> Result < bool , chain_graph ::InsertTxError < ConfirmationTime > > {
2023-02-15 12:23:59 +11:00
let changeset = self . keychain_tracker . insert_tx ( tx , position ) ? ;
let changed = changeset . is_empty ( ) ;
self . persist . stage ( changeset ) ;
Ok ( changed )
2022-11-03 15:59:38 +08:00
}
#[ deprecated(note = " use Wallet::transactions instead " ) ]
/// Deprecated. use `Wallet::transactions` instead.
pub fn list_transactions ( & self , include_raw : bool ) -> Vec < TransactionDetails > {
self . keychain_tracker
. chain ( )
. txids ( )
. map ( | & ( _ , txid ) | self . get_tx ( txid , include_raw ) . expect ( " must exist " ) )
. collect ( )
}
/// Iterate over the transactions in the wallet in order of ascending confirmation time with
/// unconfirmed transactions last.
2023-02-14 13:54:07 +11:00
pub fn transactions (
2022-11-03 15:59:38 +08:00
& self ,
) -> impl DoubleEndedIterator < Item = ( ConfirmationTime , & Transaction ) > + '_ {
self . keychain_tracker
2023-02-15 12:23:59 +11:00
. chain_graph ( )
. transactions_in_chain ( )
. map ( | ( pos , tx ) | ( * pos , tx ) )
2020-02-07 23:22:28 +01:00
}
2022-06-22 14:37:29 +05:30
/// Return the balance, separated into available, trusted-pending, untrusted-pending and immature
/// values.
2020-09-04 16:29:25 +02:00
///
2022-08-05 11:39:50 -04:00
/// Note that this method only operates on the internal database, which first needs to be
2020-09-04 16:29:25 +02:00
/// [`Wallet::sync`] manually.
2022-11-03 15:59:38 +08:00
pub fn get_balance ( & self ) -> Balance {
2022-06-22 14:37:29 +05:30
let mut immature = 0 ;
let mut trusted_pending = 0 ;
let mut untrusted_pending = 0 ;
let mut confirmed = 0 ;
2022-11-03 15:59:38 +08:00
let last_sync_height = match self . keychain_tracker . chain ( ) . latest_checkpoint ( ) {
Some ( last_sync_height ) = > last_sync_height . height ,
// TODO: update this when we're allowed to add arbitary stuff to the mempool
None = > return Balance ::default ( ) ,
2022-06-22 14:37:29 +05:30
} ;
2022-11-03 15:59:38 +08:00
for ( ( keychain , _ ) , utxo ) in self . keychain_tracker . full_utxos ( ) {
let confirmation_time = utxo . chain_position ;
let is_coinbase = self
. keychain_tracker
. graph ( )
. get_tx ( utxo . outpoint . txid )
. expect ( " must exist " )
. is_coin_base ( ) ;
match confirmation_time {
ConfirmationTime ::Confirmed { height , .. } = > {
if is_coinbase & & last_sync_height - height < COINBASE_MATURITY {
immature + = utxo . txout . value ;
} else {
confirmed + = utxo . txout . value ;
}
2022-06-22 14:37:29 +05:30
}
2022-11-03 15:59:38 +08:00
ConfirmationTime ::Unconfirmed = > match keychain {
KeychainKind ::External = > untrusted_pending + = utxo . txout . value ,
KeychainKind ::Internal = > trusted_pending + = utxo . txout . value ,
} ,
2022-06-22 14:37:29 +05:30
}
}
2022-11-03 15:59:38 +08:00
Balance {
2022-06-22 14:37:29 +05:30
immature ,
trusted_pending ,
untrusted_pending ,
confirmed ,
2022-11-03 15:59:38 +08:00
}
2020-02-07 23:22:28 +01:00
}
2020-09-04 16:29:25 +02:00
/// Add an external signer
///
/// See [the `signer` module](signer) for an example.
2020-08-15 23:21:13 +02:00
pub fn add_signer (
& mut self ,
2020-12-14 17:14:24 +01:00
keychain : KeychainKind ,
2020-08-17 12:10:51 +02:00
ordering : SignerOrdering ,
2022-04-26 16:54:10 +02:00
signer : Arc < dyn TransactionSigner > ,
2020-08-15 23:21:13 +02:00
) {
2020-12-14 17:14:24 +01:00
let signers = match keychain {
KeychainKind ::External = > Arc ::make_mut ( & mut self . signers ) ,
KeychainKind ::Internal = > Arc ::make_mut ( & mut self . change_signers ) ,
2020-08-15 23:21:13 +02:00
} ;
2021-01-25 15:04:56 -05:00
signers . add_external ( signer . id ( & self . secp ) , ordering , signer ) ;
2020-08-15 23:21:13 +02:00
}
2022-03-09 18:38:11 +01:00
/// Get the signers
///
/// ## Example
///
/// ```
/// # use bdk::{Wallet, KeychainKind};
/// # use bdk::bitcoin::Network;
/// # use bdk::database::MemoryDatabase;
2023-02-15 12:23:59 +11:00
/// let wallet = Wallet::new_no_persist("wpkh(tprv8ZgxMBicQKsPe73PBRSmNbTfbcsZnwWhz5eVmhHpi31HW29Z7mc9B4cWGRQzopNUzZUT391DeDJxL2PefNunWyLgqCKRMDkU1s2s8bAfoSk/84'/0'/0'/0/*)", None, Network::Testnet, MemoryDatabase::new())?;
2022-03-09 18:38:11 +01:00
/// for secret_key in wallet.get_signers(KeychainKind::External).signers().iter().filter_map(|s| s.descriptor_secret_key()) {
/// // secret_key: tprv8ZgxMBicQKsPe73PBRSmNbTfbcsZnwWhz5eVmhHpi31HW29Z7mc9B4cWGRQzopNUzZUT391DeDJxL2PefNunWyLgqCKRMDkU1s2s8bAfoSk/84'/0'/0'/0/*
/// println!("secret_key: {}", secret_key);
/// }
///
/// Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub fn get_signers ( & self , keychain : KeychainKind ) -> Arc < SignersContainer > {
match keychain {
KeychainKind ::External = > Arc ::clone ( & self . signers ) ,
KeychainKind ::Internal = > Arc ::clone ( & self . change_signers ) ,
}
}
2021-01-01 13:35:05 +11:00
/// Start building a transaction.
///
/// This returns a blank [`TxBuilder`] from which you can specify the parameters for the transaction.
2020-09-04 16:29:25 +02:00
///
/// ## Example
///
2021-01-01 14:15:24 +11:00
/// ```
2020-09-04 16:29:25 +02:00
/// # use std::str::FromStr;
/// # use bitcoin::*;
2020-09-14 14:25:38 +02:00
/// # use bdk::*;
/// # use bdk::database::*;
2020-09-04 16:29:25 +02:00
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
2021-01-01 14:15:24 +11:00
/// # let wallet = doctest_wallet!();
2020-09-04 16:29:25 +02:00
/// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
2021-01-11 14:14:14 +11:00
/// let (psbt, details) = {
/// let mut builder = wallet.build_tx();
/// builder
/// .add_recipient(to_address.script_pubkey(), 50_000);
/// builder.finish()?
/// };
2021-01-01 13:35:05 +11:00
///
2020-09-04 16:29:25 +02:00
/// // sign and broadcast ...
2020-09-14 14:25:38 +02:00
/// # Ok::<(), bdk::Error>(())
2020-09-04 16:29:25 +02:00
/// ```
2021-01-01 13:35:05 +11:00
///
/// [`TxBuilder`]: crate::TxBuilder
2023-02-15 12:23:59 +11:00
pub fn build_tx ( & mut self ) -> TxBuilder < '_ , D , DefaultCoinSelectionAlgorithm , CreateTx > {
2021-01-01 13:35:05 +11:00
TxBuilder {
2023-01-10 15:10:02 +11:00
wallet : alloc ::rc ::Rc ::new ( core ::cell ::RefCell ::new ( self ) ) ,
2021-01-11 14:14:14 +11:00
params : TxParams ::default ( ) ,
coin_selection : DefaultCoinSelectionAlgorithm ::default ( ) ,
2021-01-01 13:35:05 +11:00
phantom : core ::marker ::PhantomData ,
}
}
2022-11-03 15:59:38 +08:00
pub ( crate ) fn create_tx < Cs : coin_selection ::CoinSelectionAlgorithm > (
& mut self ,
2021-01-01 13:35:05 +11:00
coin_selection : Cs ,
params : TxParams ,
2023-02-15 12:23:59 +11:00
) -> Result < ( psbt ::PartiallySignedTransaction , TransactionDetails ) , Error >
where
D : persist ::Backend ,
{
2022-11-03 15:59:38 +08:00
let external_descriptor = self
. keychain_tracker
. txout_index
. keychains ( )
. get ( & KeychainKind ::External )
. expect ( " must exist " ) ;
let internal_descriptor = self
. keychain_tracker
. txout_index
. keychains ( )
. get ( & KeychainKind ::Internal ) ;
let external_policy = external_descriptor
2021-04-02 16:39:18 +02:00
. extract_policy ( & self . signers , BuildSatisfaction ::None , & self . secp ) ?
2020-08-12 12:51:50 +02:00
. unwrap ( ) ;
2022-11-03 15:59:38 +08:00
let internal_policy = internal_descriptor
2020-11-10 15:06:14 +01:00
. as_ref ( )
. map ( | desc | {
Ok ::< _ , Error > (
2021-04-02 16:39:18 +02:00
desc . extract_policy ( & self . change_signers , BuildSatisfaction ::None , & self . secp ) ?
2020-11-10 15:06:14 +01:00
. unwrap ( ) ,
)
} )
. transpose ( ) ? ;
// The policy allows spending external outputs, but it requires a policy path that hasn't been
// provided
2021-01-01 13:35:05 +11:00
if params . change_policy ! = tx_builder ::ChangeSpendPolicy ::OnlyChange
2020-11-10 15:06:14 +01:00
& & external_policy . requires_path ( )
2021-01-01 13:35:05 +11:00
& & params . external_policy_path . is_none ( )
2020-11-10 15:06:14 +01:00
{
2020-12-14 17:14:24 +01:00
return Err ( Error ::SpendingPolicyRequired ( KeychainKind ::External ) ) ;
2020-11-10 15:06:14 +01:00
} ;
// Same for the internal_policy path, if present
if let Some ( internal_policy ) = & internal_policy {
2021-01-01 13:35:05 +11:00
if params . change_policy ! = tx_builder ::ChangeSpendPolicy ::ChangeForbidden
2020-11-10 15:06:14 +01:00
& & internal_policy . requires_path ( )
2021-01-01 13:35:05 +11:00
& & params . internal_policy_path . is_none ( )
2020-11-10 15:06:14 +01:00
{
2020-12-14 17:14:24 +01:00
return Err ( Error ::SpendingPolicyRequired ( KeychainKind ::Internal ) ) ;
2020-11-10 15:06:14 +01:00
} ;
2020-02-07 23:22:28 +01:00
}
2020-11-10 15:06:14 +01:00
let external_requirements = external_policy . get_condition (
2021-01-01 13:35:05 +11:00
params
2020-11-10 15:06:14 +01:00
. external_policy_path
. as_ref ( )
. unwrap_or ( & BTreeMap ::new ( ) ) ,
) ? ;
let internal_requirements = internal_policy
. map ( | policy | {
Ok ::< _ , Error > (
policy . get_condition (
2021-01-01 13:35:05 +11:00
params
2020-11-10 15:06:14 +01:00
. internal_policy_path
. as_ref ( )
. unwrap_or ( & BTreeMap ::new ( ) ) ,
) ? ,
)
} )
. transpose ( ) ? ;
2021-05-06 14:29:51 +10:00
let requirements =
external_requirements . merge ( & internal_requirements . unwrap_or_default ( ) ) ? ;
2020-11-10 15:06:14 +01:00
debug! ( " Policy requirements: {:?} " , requirements ) ;
2020-02-07 23:22:28 +01:00
2021-01-01 13:35:05 +11:00
let version = match params . version {
2020-08-10 17:16:47 +02:00
Some ( tx_builder ::Version ( 0 ) ) = > {
return Err ( Error ::Generic ( " Invalid version `0` " . into ( ) ) )
}
Some ( tx_builder ::Version ( 1 ) ) if requirements . csv . is_some ( ) = > {
2020-08-07 16:30:19 +02:00
return Err ( Error ::Generic (
" TxBuilder requested version `1`, but at least `2` is needed to use OP_CSV "
. into ( ) ,
) )
}
2020-08-10 17:16:47 +02:00
Some ( tx_builder ::Version ( x ) ) = > x ,
None if requirements . csv . is_some ( ) = > 2 ,
_ = > 1 ,
2020-08-07 16:30:19 +02:00
} ;
2022-03-30 16:29:31 +02:00
// We use a match here instead of a map_or_else as it's way more readable :)
let current_height = match params . current_height {
// If they didn't tell us the current height, we assume it's the latest sync height.
2022-11-03 15:59:38 +08:00
None = > self
. keychain_tracker
. chain ( )
. latest_checkpoint ( )
. and_then ( | cp | cp . height . into ( ) )
. map ( | height | LockTime ::from_height ( height ) . expect ( " Invalid height " ) ) ,
2022-03-30 16:29:31 +02:00
h = > h ,
} ;
2021-01-01 13:35:05 +11:00
let lock_time = match params . locktime {
2022-03-30 16:29:31 +02:00
// When no nLockTime is specified, we try to prevent fee sniping, if possible
None = > {
// Fee sniping can be partially prevented by setting the timelock
// to current_height. If we don't know the current_height,
// we default to 0.
2022-10-25 11:15:43 +02:00
let fee_sniping_height = current_height . unwrap_or ( LockTime ::ZERO ) ;
2022-03-30 16:29:31 +02:00
// We choose the biggest between the required nlocktime and the fee sniping
// height
2022-10-25 11:15:43 +02:00
match requirements . timelock {
// No requirement, just use the fee_sniping_height
None = > fee_sniping_height ,
// There's a block-based requirement, but the value is lower than the fee_sniping_height
Some ( value @ LockTime ::Blocks ( _ ) ) if value < fee_sniping_height = > fee_sniping_height ,
// There's a time-based requirement or a block-based requirement greater
// than the fee_sniping_height use that value
Some ( value ) = > value ,
}
2022-03-30 16:29:31 +02:00
}
2020-12-07 14:48:17 +01:00
// Specific nLockTime required and we have no constraints, so just set to that value
2020-08-07 16:30:19 +02:00
Some ( x ) if requirements . timelock . is_none ( ) = > x ,
2020-12-07 14:48:17 +01:00
// Specific nLockTime required and it's compatible with the constraints
2022-10-25 11:15:43 +02:00
Some ( x ) if requirements . timelock . unwrap ( ) . is_same_unit ( x ) & & x > = requirements . timelock . unwrap ( ) = > x ,
2020-12-07 14:48:17 +01:00
// Invalid nLockTime required
2022-10-25 11:15:43 +02:00
Some ( x ) = > return Err ( Error ::Generic ( format! ( " TxBuilder requested timelock of ` {:?} `, but at least ` {:?} ` is required to spend from this script " , x , requirements . timelock . unwrap ( ) ) ) )
2020-08-07 16:30:19 +02:00
} ;
2021-01-01 13:35:05 +11:00
let n_sequence = match ( params . rbf , requirements . csv ) {
2020-12-07 14:48:17 +01:00
// No RBF or CSV but there's an nLockTime, so the nSequence cannot be final
2022-10-25 11:15:43 +02:00
( None , None ) if lock_time ! = LockTime ::ZERO = > Sequence ::ENABLE_LOCKTIME_NO_RBF ,
2020-12-07 14:48:17 +01:00
// No RBF, CSV or nLockTime, make the transaction final
2022-10-25 11:15:43 +02:00
( None , None ) = > Sequence ::MAX ,
2020-12-07 14:48:17 +01:00
// No RBF requested, use the value from CSV. Note that this value is by definition
// non-final, so even if a timelock is enabled this nSequence is fine, hence why we
// don't bother checking for it here. The same is true for all the other branches below
2020-08-07 16:30:19 +02:00
( None , Some ( csv ) ) = > csv ,
2020-12-07 14:48:17 +01:00
// RBF with a specific value but that value is too high
2022-10-25 11:15:43 +02:00
( Some ( tx_builder ::RbfValue ::Value ( rbf ) ) , _ ) if ! rbf . is_rbf ( ) = > {
2020-12-07 14:48:17 +01:00
return Err ( Error ::Generic (
" Cannot enable RBF with a nSequence >= 0xFFFFFFFE " . into ( ) ,
) )
}
// RBF with a specific value requested, but the value is incompatible with CSV
2021-03-30 16:33:07 +02:00
( Some ( tx_builder ::RbfValue ::Value ( rbf ) ) , Some ( csv ) )
2020-12-07 14:48:17 +01:00
if ! check_nsequence_rbf ( rbf , csv ) = >
{
return Err ( Error ::Generic ( format! (
2022-10-25 11:15:43 +02:00
" Cannot enable RBF with nSequence `{:?}` given a required OP_CSV of `{:?}` " ,
2020-12-07 14:48:17 +01:00
rbf , csv
) ) )
}
// RBF enabled with the default value with CSV also enabled. CSV takes precedence
2021-03-30 16:33:07 +02:00
( Some ( tx_builder ::RbfValue ::Default ) , Some ( csv ) ) = > csv ,
2020-12-07 14:48:17 +01:00
// Valid RBF, either default or with a specific value. We ignore the `CSV` value
// because we've already checked it before
( Some ( rbf ) , _ ) = > rbf . get_value ( ) ,
2020-08-07 16:30:19 +02:00
} ;
2021-01-01 13:35:05 +11:00
let ( fee_rate , mut fee_amount ) = match params
. fee_policy
. as_ref ( )
. unwrap_or ( & FeePolicy ::FeeRate ( FeeRate ::default ( ) ) )
{
//FIXME: see https://github.com/bitcoindevkit/bdk/issues/256
FeePolicy ::FeeAmount ( fee ) = > {
if let Some ( previous_fee ) = params . bumping_fee {
if * fee < previous_fee . absolute {
return Err ( Error ::FeeTooLow {
required : previous_fee . absolute ,
} ) ;
}
}
2021-07-16 15:14:20 +10:00
( FeeRate ::from_sat_per_vb ( 0.0 ) , * fee )
2021-01-01 13:35:05 +11:00
}
FeePolicy ::FeeRate ( rate ) = > {
if let Some ( previous_fee ) = params . bumping_fee {
let required_feerate = FeeRate ::from_sat_per_vb ( previous_fee . rate + 1.0 ) ;
if * rate < required_feerate {
return Err ( Error ::FeeRateTooLow {
required : required_feerate ,
} ) ;
}
}
2021-07-16 15:14:20 +10:00
( * rate , 0 )
2021-01-01 13:35:05 +11:00
}
} ;
2020-02-07 23:22:28 +01:00
let mut tx = Transaction {
2020-08-07 16:30:19 +02:00
version ,
2022-10-25 11:15:43 +02:00
lock_time : lock_time . into ( ) ,
2020-02-07 23:22:28 +01:00
input : vec ! [ ] ,
output : vec ! [ ] ,
} ;
2021-01-01 13:35:05 +11:00
if params . manually_selected_only & & params . utxos . is_empty ( ) {
2020-10-28 10:37:47 +01:00
return Err ( Error ::NoUtxosSelected ) ;
2020-02-07 23:22:28 +01:00
}
// we keep it as a float while we accumulate it, and only round it at the end
let mut outgoing : u64 = 0 ;
let mut received : u64 = 0 ;
2021-06-16 12:43:32 +10:00
let recipients = params . recipients . iter ( ) . map ( | ( r , v ) | ( r , * v ) ) ;
for ( index , ( script_pubkey , value ) ) in recipients . enumerate ( ) {
2022-07-29 15:30:43 -04:00
if ! params . allow_dust
& & value . is_dust ( script_pubkey )
& & ! script_pubkey . is_provably_unspendable ( )
{
2021-06-16 12:43:32 +10:00
return Err ( Error ::OutputBelowDustLimit ( index ) ) ;
}
2020-02-07 23:22:28 +01:00
2022-11-03 15:59:38 +08:00
if self . is_mine ( script_pubkey ) {
2020-02-07 23:22:28 +01:00
received + = value ;
}
let new_out = TxOut {
2020-09-04 15:45:11 +02:00
script_pubkey : script_pubkey . clone ( ) ,
2020-02-07 23:22:28 +01:00
value ,
} ;
tx . output . push ( new_out ) ;
outgoing + = value ;
}
2022-07-11 21:52:11 +02:00
fee_amount + = fee_rate . fee_wu ( tx . weight ( ) ) ;
2022-07-12 15:51:27 +02:00
// Segwit transactions' header is 2WU larger than legacy txs' header,
// as they contain a witness marker (1WU) and a witness flag (1WU) (see BIP144).
// At this point we really don't know if the resulting transaction will be segwit
// or legacy, so we just add this 2WU to the fee_amount - overshooting the fee amount
// is better than undershooting it.
// If we pass a fee_amount that is slightly higher than the final fee_amount, we
// end up with a transaction with a slightly higher fee rate than the requested one.
// If, instead, we undershoot, we may end up with a feerate lower than the requested one
// - we might come up with non broadcastable txs!
fee_amount + = fee_rate . fee_wu ( 2 ) ;
2021-01-01 13:35:05 +11:00
if params . change_policy ! = tx_builder ::ChangeSpendPolicy ::ChangeAllowed
2022-11-03 15:59:38 +08:00
& & internal_descriptor . is_none ( )
2020-08-10 17:16:47 +02:00
{
return Err ( Error ::Generic (
" The `change_policy` can be set only if the wallet has a change_descriptor " . into ( ) ,
) ) ;
}
2020-10-26 14:23:46 -04:00
let ( required_utxos , optional_utxos ) = self . preselect_utxos (
2021-01-01 13:35:05 +11:00
params . change_policy ,
& params . unspendable ,
2021-01-22 14:04:06 +11:00
params . utxos . clone ( ) ,
2021-01-01 13:35:05 +11:00
params . drain_wallet ,
params . manually_selected_only ,
params . bumping_fee . is_some ( ) , // we mandate confirmed transactions if we're bumping the fee
2022-10-25 11:15:43 +02:00
current_height . map ( LockTime ::to_consensus_u32 ) ,
2022-11-03 15:59:38 +08:00
) ;
2020-10-14 14:03:12 +11:00
2022-06-13 10:49:31 -03:00
// get drain script
let drain_script = match params . drain_to {
Some ( ref drain_recipient ) = > drain_recipient . clone ( ) ,
2023-02-15 12:23:59 +11:00
None = > {
let change_keychain = self . map_keychain ( KeychainKind ::Internal ) ;
let ( ( index , spk ) , changeset ) = self
. keychain_tracker
. txout_index
. next_unused_spk ( & change_keychain ) ;
let spk = spk . clone ( ) ;
self . keychain_tracker
. txout_index
. mark_used ( & change_keychain , index ) ;
self . persist . stage ( changeset . into ( ) ) ;
self . persist . commit ( ) . expect ( " TODO " ) ;
spk
}
2022-06-13 10:49:31 -03:00
} ;
2021-02-08 15:40:56 +11:00
let coin_selection = coin_selection . coin_select (
2020-10-26 14:08:57 -04:00
required_utxos ,
2020-10-26 14:12:46 -04:00
optional_utxos ,
2020-02-07 23:22:28 +01:00
fee_rate ,
2022-07-10 19:57:44 -03:00
outgoing + fee_amount ,
2022-06-13 10:49:31 -03:00
& drain_script ,
2020-02-07 23:22:28 +01:00
) ? ;
2022-07-10 19:57:44 -03:00
fee_amount + = coin_selection . fee_amount ;
2022-06-13 10:49:31 -03:00
let excess = & coin_selection . excess ;
2021-02-08 15:40:56 +11:00
tx . input = coin_selection
. selected
2020-08-08 12:06:40 +02:00
. iter ( )
2020-10-30 14:09:59 +11:00
. map ( | u | bitcoin ::TxIn {
2021-02-08 15:40:56 +11:00
previous_output : u . outpoint ( ) ,
2020-10-30 14:09:59 +11:00
script_sig : Script ::default ( ) ,
sequence : n_sequence ,
2022-04-14 17:20:46 +02:00
witness : Witness ::new ( ) ,
2020-10-30 14:09:59 +11:00
} )
. collect ( ) ;
2020-02-07 23:22:28 +01:00
2021-06-16 12:43:32 +10:00
if tx . output . is_empty ( ) {
2022-06-06 21:45:13 +02:00
// Uh oh, our transaction has no outputs.
// We allow this when:
// - We have a drain_to address and the utxos we must spend (this happens,
// for example, when we RBF)
// - We have a drain_to address and drain_wallet set
// Otherwise, we don't know who we should send the funds to, and how much
// we should send!
if params . drain_to . is_some ( ) & & ( params . drain_wallet | | ! params . utxos . is_empty ( ) ) {
2022-06-13 10:49:31 -03:00
if let NoChange {
dust_threshold ,
remaining_amount ,
change_fee ,
} = excess
{
2021-06-16 12:43:32 +10:00
return Err ( Error ::InsufficientFunds {
2022-06-13 10:49:31 -03:00
needed : * dust_threshold ,
available : remaining_amount . saturating_sub ( * change_fee ) ,
2021-06-16 12:43:32 +10:00
} ) ;
2020-10-28 10:37:47 +01:00
}
2021-06-16 12:43:32 +10:00
} else {
return Err ( Error ::NoRecipients ) ;
2020-02-07 23:22:28 +01:00
}
}
2022-06-13 10:49:31 -03:00
match excess {
NoChange {
remaining_amount , ..
} = > fee_amount + = remaining_amount ,
Change { amount , fee } = > {
2022-11-03 15:59:38 +08:00
if self . is_mine ( & drain_script ) {
2022-06-13 10:49:31 -03:00
received + = amount ;
}
fee_amount + = fee ;
// create drain output
let drain_output = TxOut {
value : * amount ,
script_pubkey : drain_script ,
} ;
2022-07-11 21:52:11 +02:00
// TODO: We should pay attention when adding a new output: this might increase
// the lenght of the "number of vouts" parameter by 2 bytes, potentially making
// our feerate too low
2022-06-13 10:49:31 -03:00
tx . output . push ( drain_output ) ;
2021-06-16 12:43:32 +10:00
}
2022-06-13 10:49:31 -03:00
} ;
2021-06-16 12:43:32 +10:00
2020-08-07 15:35:14 +02:00
// sort input/outputs according to the chosen algorithm
2021-01-01 13:35:05 +11:00
params . ordering . sort_tx ( & mut tx ) ;
2020-02-07 23:22:28 +01:00
let txid = tx . txid ( ) ;
2021-02-08 15:40:56 +11:00
let sent = coin_selection . local_selected_amount ( ) ;
let psbt = self . complete_transaction ( tx , coin_selection . selected , params ) ? ;
2020-02-07 23:22:28 +01:00
2020-08-13 16:51:27 +02:00
let transaction_details = TransactionDetails {
transaction : None ,
txid ,
2022-11-03 15:59:38 +08:00
confirmation_time : ConfirmationTime ::Unconfirmed ,
2020-08-13 16:51:27 +02:00
received ,
2021-02-08 15:40:56 +11:00
sent ,
2021-06-12 15:01:44 +02:00
fee : Some ( fee_amount ) ,
2020-08-13 16:51:27 +02:00
} ;
2020-08-08 12:06:40 +02:00
2020-08-13 16:51:27 +02:00
Ok ( ( psbt , transaction_details ) )
}
2020-02-07 23:22:28 +01:00
2021-01-01 13:35:05 +11:00
/// Bump the fee of a transaction previously created with this wallet.
2020-09-04 16:29:25 +02:00
///
2021-01-01 13:35:05 +11:00
/// Returns an error if the transaction is already confirmed or doesn't explicitly signal
2021-11-23 13:40:58 -05:00
/// *replace by fee* (RBF). If the transaction can be fee bumped then it returns a [`TxBuilder`]
2021-01-01 13:35:05 +11:00
/// pre-populated with the inputs and outputs of the original transaction.
2020-09-04 16:29:25 +02:00
///
/// ## Example
///
/// ```no_run
2021-01-01 14:15:24 +11:00
/// # // TODO: remove norun -- bumping fee seems to need the tx in the wallet database first.
2020-09-04 16:29:25 +02:00
/// # use std::str::FromStr;
/// # use bitcoin::*;
2020-09-14 14:25:38 +02:00
/// # use bdk::*;
/// # use bdk::database::*;
2020-09-04 16:29:25 +02:00
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
2021-01-01 14:15:24 +11:00
/// # let wallet = doctest_wallet!();
/// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
2021-04-28 09:53:03 +10:00
/// let (mut psbt, _) = {
2021-01-11 14:14:14 +11:00
/// let mut builder = wallet.build_tx();
/// builder
/// .add_recipient(to_address.script_pubkey(), 50_000)
/// .enable_rbf();
/// builder.finish()?
/// };
2021-04-19 14:16:39 +02:00
/// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
2021-01-01 14:15:24 +11:00
/// let tx = psbt.extract_tx();
/// // broadcast tx but it's taking too long to confirm so we want to bump the fee
2021-04-28 09:53:03 +10:00
/// let (mut psbt, _) = {
2021-01-11 14:14:14 +11:00
/// let mut builder = wallet.build_fee_bump(tx.txid())?;
/// builder
/// .fee_rate(FeeRate::from_sat_per_vb(5.0));
/// builder.finish()?
/// };
2021-01-01 14:15:24 +11:00
///
2021-04-19 14:16:39 +02:00
/// let _ = wallet.sign(&mut psbt, SignOptions::default())?;
2021-01-01 14:15:24 +11:00
/// let fee_bumped_tx = psbt.extract_tx();
/// // broadcast fee_bumped_tx to replace original
2020-09-14 14:25:38 +02:00
/// # Ok::<(), bdk::Error>(())
2020-09-04 16:29:25 +02:00
/// ```
2020-08-13 16:51:27 +02:00
// TODO: support for merging multiple transactions while bumping the fees
2021-01-01 13:35:05 +11:00
pub fn build_fee_bump (
2022-11-03 15:59:38 +08:00
& mut self ,
2021-01-01 13:35:05 +11:00
txid : Txid ,
2023-02-15 12:23:59 +11:00
) -> Result < TxBuilder < '_ , D , DefaultCoinSelectionAlgorithm , BumpFee > , Error > {
2022-11-03 15:59:38 +08:00
let graph = self . keychain_tracker . graph ( ) ;
let txout_index = & self . keychain_tracker . txout_index ;
let tx_and_height = self . keychain_tracker . chain_graph ( ) . get_tx_in_chain ( txid ) ;
let mut tx = match tx_and_height {
2020-08-13 16:51:27 +02:00
None = > return Err ( Error ::TransactionNotFound ) ,
2022-11-03 15:59:38 +08:00
Some ( ( ConfirmationTime ::Confirmed { .. } , _tx ) ) = > {
return Err ( Error ::TransactionConfirmed )
}
Some ( ( _ , tx ) ) = > tx . clone ( ) ,
2020-08-13 16:51:27 +02:00
} ;
2022-11-03 15:59:38 +08:00
2022-10-25 11:15:43 +02:00
if ! tx
. input
. iter ( )
. any ( | txin | txin . sequence . to_consensus_u32 ( ) < = 0xFFFFFFFD )
{
2020-08-13 16:51:27 +02:00
return Err ( Error ::IrreplaceableTransaction ) ;
}
2020-02-07 23:22:28 +01:00
2023-02-15 12:23:59 +11:00
let fee = graph . calculate_fee ( & tx ) . ok_or ( Error ::FeeRateUnavailable ) ? ;
if fee < 0 {
// It's available but it's wrong so let's say it's unavailable
return Err ( Error ::FeeRateUnavailable ) ? ;
}
let fee = fee as u64 ;
2022-11-03 15:59:38 +08:00
let feerate = FeeRate ::from_wu ( fee , tx . weight ( ) ) ;
2020-08-13 16:51:27 +02:00
2020-10-16 14:27:50 +02:00
// remove the inputs from the tx and process them
let original_txin = tx . input . drain ( .. ) . collect ::< Vec < _ > > ( ) ;
2021-01-01 13:35:05 +11:00
let original_utxos = original_txin
2020-10-16 14:27:50 +02:00
. iter ( )
2021-01-22 14:04:06 +11:00
. map ( | txin | -> Result < _ , Error > {
2022-11-03 15:59:38 +08:00
let ( & confirmation_time , prev_tx ) = self
. keychain_tracker
. chain_graph ( )
. get_tx_in_chain ( txin . previous_output . txid )
2021-03-30 16:33:07 +02:00
. ok_or ( Error ::UnknownUtxo ) ? ;
2022-11-03 15:59:38 +08:00
let txout = & prev_tx . output [ txin . previous_output . vout as usize ] ;
2020-08-13 16:51:27 +02:00
2022-11-03 15:59:38 +08:00
let weighted_utxo = match txout_index . index_of_spk ( & txout . script_pubkey ) {
Some ( & ( keychain , derivation_index ) ) = > {
let satisfaction_weight = self
. get_descriptor_for_keychain ( keychain )
2021-02-02 20:06:40 -05:00
. max_satisfaction_weight ( )
2022-11-03 15:59:38 +08:00
. unwrap ( ) ;
WeightedUtxo {
utxo : Utxo ::Local ( LocalUtxo {
outpoint : txin . previous_output ,
txout : txout . clone ( ) ,
keychain ,
is_spent : true ,
derivation_index ,
confirmation_time ,
} ) ,
satisfaction_weight ,
}
}
2020-10-16 14:27:50 +02:00
None = > {
2022-11-03 15:59:38 +08:00
let satisfaction_weight =
2020-10-16 14:27:50 +02:00
serialize ( & txin . script_sig ) . len ( ) * 4 + serialize ( & txin . witness ) . len ( ) ;
2022-11-03 15:59:38 +08:00
WeightedUtxo {
satisfaction_weight ,
utxo : Utxo ::Foreign {
outpoint : txin . previous_output ,
psbt_input : Box ::new ( psbt ::Input {
witness_utxo : Some ( txout . clone ( ) ) ,
non_witness_utxo : Some ( prev_tx . clone ( ) ) ,
.. Default ::default ( )
} ) ,
} ,
}
2020-08-13 16:51:27 +02:00
}
2020-10-16 14:27:50 +02:00
} ;
2022-11-03 15:59:38 +08:00
Ok ( weighted_utxo )
2020-10-22 12:07:51 +11:00
} )
2021-01-22 14:04:06 +11:00
. collect ::< Result < Vec < _ > , _ > > ( ) ? ;
2020-10-16 14:27:50 +02:00
2021-01-01 13:35:05 +11:00
if tx . output . len ( ) > 1 {
let mut change_index = None ;
for ( index , txout ) in tx . output . iter ( ) . enumerate ( ) {
2022-11-03 15:59:38 +08:00
let change_type = self . map_keychain ( KeychainKind ::Internal ) ;
match txout_index . index_of_spk ( & txout . script_pubkey ) {
Some ( & ( keychain , _ ) ) if keychain = = change_type = > change_index = Some ( index ) ,
2021-01-01 13:35:05 +11:00
_ = > { }
2020-10-22 13:41:26 +02:00
}
2020-10-16 14:27:50 +02:00
}
2020-10-28 10:37:47 +01:00
2021-01-01 13:35:05 +11:00
if let Some ( change_index ) = change_index {
tx . output . remove ( change_index ) ;
2020-10-28 10:37:47 +01:00
}
2020-08-13 16:51:27 +02:00
}
2021-01-01 13:35:05 +11:00
let params = TxParams {
// TODO: figure out what rbf option should be?
version : Some ( tx_builder ::Version ( tx . version ) ) ,
recipients : tx
. output
. into_iter ( )
. map ( | txout | ( txout . script_pubkey , txout . value ) )
. collect ( ) ,
utxos : original_utxos ,
bumping_fee : Some ( tx_builder ::PreviousFee {
2022-11-03 15:59:38 +08:00
absolute : fee ,
2022-07-21 12:58:30 +01:00
rate : feerate . as_sat_per_vb ( ) ,
2021-01-01 13:35:05 +11:00
} ) ,
.. Default ::default ( )
} ;
2020-08-13 16:51:27 +02:00
2021-01-01 13:35:05 +11:00
Ok ( TxBuilder {
2023-01-10 15:10:02 +11:00
wallet : alloc ::rc ::Rc ::new ( core ::cell ::RefCell ::new ( self ) ) ,
2021-01-11 14:14:14 +11:00
params ,
coin_selection : DefaultCoinSelectionAlgorithm ::default ( ) ,
2021-01-01 13:35:05 +11:00
phantom : core ::marker ::PhantomData ,
} )
2020-02-07 23:22:28 +01:00
}
2020-09-04 16:29:25 +02:00
/// Sign a transaction with all the wallet's signers, in the order specified by every signer's
2023-01-13 20:55:38 +09:00
/// [`SignerOrdering`]. This function returns the `Result` type with an encapsulated `bool` that has the value true if the PSBT was finalized, or false otherwise.
2020-09-04 16:29:25 +02:00
///
2021-04-19 14:16:39 +02:00
/// The [`SignOptions`] can be used to tweak the behavior of the software signers, and the way
/// the transaction is finalized at the end. Note that it can't be guaranteed that *every*
/// signers will follow the options, but the "software signers" (WIF keys and `xprv`) defined
/// in this library will.
///
2020-09-04 16:29:25 +02:00
/// ## Example
///
2021-01-01 14:15:24 +11:00
/// ```
2020-09-04 16:29:25 +02:00
/// # use std::str::FromStr;
/// # use bitcoin::*;
2020-09-14 14:25:38 +02:00
/// # use bdk::*;
/// # use bdk::database::*;
2020-09-04 16:29:25 +02:00
/// # let descriptor = "wpkh(tpubD6NzVbkrYhZ4Xferm7Pz4VnjdcDPFyjVu5K4iZXQ4pVN8Cks4pHVowTBXBKRhX64pkRyJZJN5xAKj4UDNnLPb5p2sSKXhewoYx5GbTdUFWq/*)";
2021-01-01 14:15:24 +11:00
/// # let wallet = doctest_wallet!();
/// # let to_address = Address::from_str("2N4eQYCbKUHCCTUjBJeHcJp9ok6J2GZsTDt").unwrap();
2021-04-28 09:53:03 +10:00
/// let (mut psbt, _) = {
2021-01-11 14:14:14 +11:00
/// let mut builder = wallet.build_tx();
/// builder.add_recipient(to_address.script_pubkey(), 50_000);
/// builder.finish()?
/// };
2021-04-19 14:16:39 +02:00
/// let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
2021-01-01 14:15:24 +11:00
/// assert!(finalized, "we should have signed all the inputs");
2020-09-14 14:25:38 +02:00
/// # Ok::<(), bdk::Error>(())
2022-04-14 17:20:46 +02:00
pub fn sign (
& self ,
psbt : & mut psbt ::PartiallySignedTransaction ,
sign_options : SignOptions ,
) -> Result < bool , Error > {
2022-10-25 11:15:43 +02:00
// This adds all the PSBT metadata for the inputs, which will help us later figure out how
// to derive our keys
self . update_psbt_with_descriptor ( psbt ) ? ;
2020-02-17 14:22:53 +01:00
2022-04-29 12:59:09 +02:00
// If we aren't allowed to use `witness_utxo`, ensure that every input (except p2tr and finalized ones)
2021-05-06 17:11:43 +02:00
// has the `non_witness_utxo`
2021-05-06 11:35:58 +02:00
if ! sign_options . trust_witness_utxo
2021-05-06 17:11:43 +02:00
& & psbt
. inputs
. iter ( )
. filter ( | i | i . final_script_witness . is_none ( ) & & i . final_script_sig . is_none ( ) )
2022-04-29 12:59:09 +02:00
. filter ( | i | i . tap_internal_key . is_none ( ) & & i . tap_merkle_root . is_none ( ) )
2021-05-06 17:11:43 +02:00
. any ( | i | i . non_witness_utxo . is_none ( ) )
2021-05-06 11:35:58 +02:00
{
return Err ( Error ::Signer ( signer ::SignerError ::MissingNonWitnessUtxo ) ) ;
2021-04-19 14:16:39 +02:00
}
2021-05-26 10:34:25 +02:00
// If the user hasn't explicitly opted-in, refuse to sign the transaction unless every input
2022-04-29 12:59:09 +02:00
// is using `SIGHASH_ALL` or `SIGHASH_DEFAULT` for taproot
2021-05-26 10:34:25 +02:00
if ! sign_options . allow_all_sighashes
2022-04-14 17:20:46 +02:00
& & ! psbt . inputs . iter ( ) . all ( | i | {
2022-04-29 12:59:09 +02:00
i . sighash_type . is_none ( )
| | i . sighash_type = = Some ( EcdsaSighashType ::All . into ( ) )
| | i . sighash_type = = Some ( SchnorrSighashType ::All . into ( ) )
| | i . sighash_type = = Some ( SchnorrSighashType ::Default . into ( ) )
2022-04-14 17:20:46 +02:00
} )
2021-05-26 10:34:25 +02:00
{
return Err ( Error ::Signer ( signer ::SignerError ::NonStandardSighash ) ) ;
}
2020-08-17 12:10:51 +02:00
for signer in self
. signers
. signers ( )
. iter ( )
. chain ( self . change_signers . signers ( ) . iter ( ) )
{
2022-06-22 18:08:23 +02:00
signer . sign_transaction ( psbt , & sign_options , & self . secp ) ? ;
2020-02-07 23:22:28 +01:00
}
// attempt to finalize
2022-06-04 12:42:52 +07:00
if sign_options . try_finalize {
self . finalize_psbt ( psbt , sign_options )
} else {
Ok ( false )
}
2020-02-07 23:22:28 +01:00
}
2020-09-04 16:29:25 +02:00
/// Return the spending policies for the wallet's descriptor
2020-12-14 17:14:24 +01:00
pub fn policies ( & self , keychain : KeychainKind ) -> Result < Option < Policy > , Error > {
2022-11-03 15:59:38 +08:00
let signers = match keychain {
KeychainKind ::External = > & self . signers ,
KeychainKind ::Internal = > & self . change_signers ,
} ;
match self . public_descriptor ( keychain ) {
Some ( desc ) = > Ok ( desc . extract_policy ( signers , BuildSatisfaction ::None , & self . secp ) ? ) ,
None = > Ok ( None ) ,
2020-02-07 23:22:28 +01:00
}
}
2020-09-04 16:29:25 +02:00
/// Return the "public" version of the wallet's descriptor, meaning a new descriptor that has
/// the same structure but with every secret key removed
///
/// This can be used to build a watch-only version of a wallet
2022-11-03 15:59:38 +08:00
pub fn public_descriptor ( & self , keychain : KeychainKind ) -> Option < & ExtendedDescriptor > {
self . keychain_tracker . txout_index . keychains ( ) . get ( & keychain )
2020-05-10 17:42:02 +02:00
}
2022-09-15 14:32:10 +02:00
/// Finalize a PSBT, i.e., for each input determine if sufficient data is available to pass
/// validation and construct the respective `scriptSig` or `scriptWitness`. Please refer to
/// [BIP174](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#Input_Finalizer)
/// for further information.
///
/// Returns `true` if the PSBT could be finalized, and `false` otherwise.
2021-04-19 14:16:39 +02:00
///
/// The [`SignOptions`] can be used to tweak the behavior of the finalizer.
2022-04-14 17:20:46 +02:00
pub fn finalize_psbt (
& self ,
psbt : & mut psbt ::PartiallySignedTransaction ,
sign_options : SignOptions ,
) -> Result < bool , Error > {
let tx = & psbt . unsigned_tx ;
2020-11-17 17:53:06 +11:00
let mut finished = true ;
2020-05-17 18:01:52 +02:00
2020-11-17 17:53:06 +11:00
for ( n , input ) in tx . input . iter ( ) . enumerate ( ) {
2021-05-06 15:55:58 +02:00
let psbt_input = & psbt
. inputs
. get ( n )
. ok_or ( Error ::Signer ( SignerError ::InputIndexOutOfRange ) ) ? ;
2020-11-17 17:53:06 +11:00
if psbt_input . final_script_sig . is_some ( ) | | psbt_input . final_script_witness . is_some ( ) {
continue ;
}
2022-11-03 15:59:38 +08:00
let confirmation_height = self
. keychain_tracker
. chain ( )
. tx_position ( input . previous_output . txid )
. map ( | conftime | match conftime {
& ConfirmationTime ::Confirmed { height , .. } = > height ,
ConfirmationTime ::Unconfirmed = > u32 ::MAX ,
} ) ;
2022-01-26 15:17:48 +11:00
let last_sync_height = self
2022-11-03 15:59:38 +08:00
. keychain_tracker
. chain ( )
. latest_checkpoint ( )
. map ( | block_id | block_id . height ) ;
2022-01-26 15:17:48 +11:00
let current_height = sign_options . assume_height . or ( last_sync_height ) ;
2020-05-17 18:01:52 +02:00
debug! (
2022-11-03 15:59:38 +08:00
" Input #{} - {}, using `confirmation_height` = {:?}, `current_height` = {:?} " ,
n , input . previous_output , confirmation_height , current_height
2020-05-17 18:01:52 +02:00
) ;
2020-08-12 12:51:50 +02:00
// - Try to derive the descriptor by looking at the txout. If it's in our database, we
2020-12-14 17:14:24 +01:00
// know exactly which `keychain` to use, and which derivation index it is
2020-08-12 12:51:50 +02:00
// - If that fails, try to derive it by looking at the psbt input: the complete logic
2021-02-02 20:06:40 -05:00
// is in `src/descriptor/mod.rs`, but it will basically look at `bip32_derivation`,
2020-08-12 12:51:50 +02:00
// `redeem_script` and `witness_script` to determine the right derivation
// - If that also fails, it will try it on the internal descriptor, if present
2020-11-17 17:53:06 +11:00
let desc = psbt
2020-08-12 12:51:50 +02:00
. get_utxo_for ( n )
. map ( | txout | self . get_descriptor_for_txout ( & txout ) )
. flatten ( )
2020-11-17 17:53:06 +11:00
. or_else ( | | {
2022-11-03 15:59:38 +08:00
self . keychain_tracker
. txout_index
. keychains ( )
. iter ( )
. find_map ( | ( _ , desc ) | {
desc . derive_from_psbt_input (
psbt_input ,
psbt . get_utxo_for ( n ) ,
& self . secp ,
)
} )
2020-11-17 17:53:06 +11:00
} ) ;
match desc {
Some ( desc ) = > {
let mut tmp_input = bitcoin ::TxIn ::default ( ) ;
match desc . satisfy (
& mut tmp_input ,
(
2021-06-08 13:57:55 +10:00
PsbtInputSatisfier ::new ( psbt , n ) ,
2020-11-17 17:53:06 +11:00
After ::new ( current_height , false ) ,
2022-11-03 15:59:38 +08:00
Older ::new ( current_height , confirmation_height , false ) ,
2020-11-17 17:53:06 +11:00
) ,
) {
Ok ( _ ) = > {
let psbt_input = & mut psbt . inputs [ n ] ;
psbt_input . final_script_sig = Some ( tmp_input . script_sig ) ;
psbt_input . final_script_witness = Some ( tmp_input . witness ) ;
2022-05-29 10:53:37 +07:00
if sign_options . remove_partial_sigs {
psbt_input . partial_sigs . clear ( ) ;
}
2020-11-17 17:53:06 +11:00
}
Err ( e ) = > {
debug! ( " satisfy error {:?} for input {} " , e , n ) ;
finished = false
}
}
2020-05-17 18:01:52 +02:00
}
2020-11-17 17:53:06 +11:00
None = > finished = false ,
2020-05-17 18:01:52 +02:00
}
}
2021-04-28 09:53:03 +10:00
Ok ( finished )
2020-05-17 18:01:52 +02:00
}
2020-12-11 14:10:11 -08:00
/// Return the secp256k1 context used for all signing operations
2020-11-16 22:07:38 +01:00
pub fn secp_ctx ( & self ) -> & SecpCtx {
& self . secp
}
2021-11-23 13:40:58 -05:00
/// Returns the descriptor used to create addresses for a particular `keychain`.
2021-01-01 13:35:05 +11:00
pub fn get_descriptor_for_keychain ( & self , keychain : KeychainKind ) -> & ExtendedDescriptor {
2022-11-03 15:59:38 +08:00
self . public_descriptor ( self . map_keychain ( keychain ) )
. expect ( " we mapped it to external if it doesn't exist " )
2021-01-01 13:35:05 +11:00
}
2022-11-03 15:59:38 +08:00
/// The derivation index of this wallet. It will return `None` if it has not derived any addresses.
/// Otherwise, it will return the index of the highest address it has derived.
pub fn derivation_index ( & self , keychain : KeychainKind ) -> Option < u32 > {
self . keychain_tracker
. txout_index
. last_revealed_index ( & keychain )
2020-02-07 23:22:28 +01:00
}
2022-11-03 15:59:38 +08:00
/// The index of the next address that you would get if you were to ask the wallet for a new address
pub fn next_derivation_index ( & self , keychain : KeychainKind ) -> u32 {
self . keychain_tracker . txout_index . next_index ( & keychain ) . 0
2020-02-07 23:22:28 +01:00
}
2023-02-15 12:52:10 +11:00
/// Informs the wallet that you no longer intend to broadcast a tx that was built from it.
///
/// This frees up the change address used when creating the tx for use in future transactions.
///
// TODO: Make this free up reserved utxos when that's implemented
pub fn cancel_tx ( & mut self , tx : & Transaction ) {
let txout_index = & mut self . keychain_tracker . txout_index ;
for txout in & tx . output {
if let Some ( & ( keychain , index ) ) = txout_index . index_of_spk ( & txout . script_pubkey ) {
// NOTE: unmark_used will **not** make something unused if it has actually been used
// by a tx in the tracker. It only removes the superficial marking.
txout_index . unmark_used ( & keychain , index ) ;
}
}
}
2022-11-03 15:59:38 +08:00
fn map_keychain ( & self , keychain : KeychainKind ) -> KeychainKind {
if keychain = = KeychainKind ::Internal
& & self . public_descriptor ( KeychainKind ::Internal ) . is_none ( )
2020-08-06 18:11:07 +02:00
{
2022-11-03 15:59:38 +08:00
return KeychainKind ::External ;
2021-03-07 21:54:30 -08:00
} else {
2022-11-03 15:59:38 +08:00
keychain
2021-03-07 21:54:30 -08:00
}
}
2022-11-03 15:59:38 +08:00
fn get_descriptor_for_txout ( & self , txout : & TxOut ) -> Option < DerivedDescriptor > {
let & ( keychain , child ) = self
. keychain_tracker
. txout_index
. index_of_spk ( & txout . script_pubkey ) ? ;
let descriptor = self . get_descriptor_for_keychain ( keychain ) ;
Some ( descriptor . at_derivation_index ( child ) )
2020-02-07 23:22:28 +01:00
}
2022-11-03 15:59:38 +08:00
fn get_available_utxos ( & self ) -> Vec < ( LocalUtxo , usize ) > {
self . list_unspent ( )
2020-12-04 10:37:58 +11:00
. into_iter ( )
. map ( | utxo | {
2020-12-14 17:14:24 +01:00
let keychain = utxo . keychain ;
2020-12-04 10:37:58 +11:00
(
utxo ,
2020-12-14 17:14:24 +01:00
self . get_descriptor_for_keychain ( keychain )
2021-02-02 20:06:40 -05:00
. max_satisfaction_weight ( )
2020-12-04 10:37:58 +11:00
. unwrap ( ) ,
)
} )
2022-11-03 15:59:38 +08:00
. collect ( )
2020-10-22 12:07:51 +11:00
}
2020-10-21 15:53:00 +11:00
2020-10-22 12:07:51 +11:00
/// Given the options returns the list of utxos that must be used to form the
/// transaction and any further that may be used if needed.
#[ allow(clippy::type_complexity) ]
2022-05-25 18:56:50 +01:00
#[ allow(clippy::too_many_arguments) ]
2020-10-26 14:23:46 -04:00
fn preselect_utxos (
2020-10-22 12:07:51 +11:00
& self ,
change_policy : tx_builder ::ChangeSpendPolicy ,
unspendable : & HashSet < OutPoint > ,
2021-02-08 15:40:56 +11:00
manually_selected : Vec < WeightedUtxo > ,
2020-10-22 12:07:51 +11:00
must_use_all_available : bool ,
manual_only : bool ,
2020-10-23 12:13:05 +11:00
must_only_use_confirmed_tx : bool ,
2022-05-25 18:56:50 +01:00
current_height : Option < u32 > ,
2022-11-03 15:59:38 +08:00
) -> ( Vec < WeightedUtxo > , Vec < WeightedUtxo > ) {
2020-10-22 12:07:51 +11:00
// must_spend <- manually selected utxos
// may_spend <- all other available utxos
2022-11-03 15:59:38 +08:00
let mut may_spend = self . get_available_utxos ( ) ;
2021-05-06 14:32:08 +10:00
2021-01-01 13:35:05 +11:00
may_spend . retain ( | may_spend | {
2021-05-06 14:32:08 +10:00
! manually_selected
2020-10-22 12:07:51 +11:00
. iter ( )
2021-05-06 14:32:08 +10:00
. any ( | manually_selected | manually_selected . utxo . outpoint ( ) = = may_spend . 0. outpoint )
2021-01-01 13:35:05 +11:00
} ) ;
let mut must_spend = manually_selected ;
2020-10-22 12:07:51 +11:00
// NOTE: we are intentionally ignoring `unspendable` here. i.e manual
// selection overrides unspendable.
if manual_only {
2022-11-03 15:59:38 +08:00
return ( must_spend , vec! [ ] ) ;
2020-02-07 23:22:28 +01:00
}
2020-10-22 12:07:51 +11:00
2022-05-25 18:56:50 +01:00
let satisfies_confirmed = may_spend
. iter ( )
. map ( | u | {
2022-11-03 15:59:38 +08:00
let txid = u . 0. outpoint . txid ;
let tx = self . keychain_tracker . chain_graph ( ) . get_tx_in_chain ( txid ) ;
match tx {
// We don't have the tx in the db for some reason,
// so we can't know for sure if it's mature or not.
// We prefer not to spend it.
None = > false ,
Some ( ( confirmation_time , tx ) ) = > {
// Whether the UTXO is mature and, if needed, confirmed
let mut spendable = true ;
if must_only_use_confirmed_tx & & ! confirmation_time . is_confirmed ( ) {
return false ;
}
if tx . is_coin_base ( ) {
debug_assert! (
confirmation_time . is_confirmed ( ) ,
" coinbase must always be confirmed "
) ;
if let Some ( current_height ) = current_height {
match confirmation_time {
ConfirmationTime ::Confirmed { height , .. } = > {
// https://github.com/bitcoin/bitcoin/blob/c5e67be03bb06a5d7885c55db1f016fbf2333fe3/src/validation.cpp#L373-L375
spendable & = ( current_height . saturating_sub ( * height ) )
> = COINBASE_MATURITY ;
2022-05-25 18:56:50 +01:00
}
2022-11-03 15:59:38 +08:00
ConfirmationTime ::Unconfirmed = > spendable = false ,
2022-05-25 18:56:50 +01:00
}
}
}
2022-11-03 15:59:38 +08:00
spendable
}
}
2022-05-25 18:56:50 +01:00
} )
2022-11-03 15:59:38 +08:00
. collect ::< Vec < _ > > ( ) ;
2020-10-23 12:13:05 +11:00
let mut i = 0 ;
2020-10-22 12:07:51 +11:00
may_spend . retain ( | u | {
2020-10-23 12:13:05 +11:00
let retain = change_policy . is_satisfied_by ( & u . 0 )
& & ! unspendable . contains ( & u . 0. outpoint )
& & satisfies_confirmed [ i ] ;
i + = 1 ;
retain
2020-10-22 12:07:51 +11:00
} ) ;
2021-02-08 15:40:56 +11:00
let mut may_spend = may_spend
. into_iter ( )
. map ( | ( local_utxo , satisfaction_weight ) | WeightedUtxo {
satisfaction_weight ,
utxo : Utxo ::Local ( local_utxo ) ,
} )
. collect ( ) ;
2020-10-22 12:07:51 +11:00
if must_use_all_available {
must_spend . append ( & mut may_spend ) ;
}
2022-11-03 15:59:38 +08:00
( must_spend , may_spend )
2020-02-07 23:22:28 +01:00
}
2021-01-01 13:35:05 +11:00
fn complete_transaction (
2020-08-13 16:51:27 +02:00
& self ,
tx : Transaction ,
2021-02-08 15:40:56 +11:00
selected : Vec < Utxo > ,
2021-01-01 13:35:05 +11:00
params : TxParams ,
2022-04-14 17:20:46 +02:00
) -> Result < psbt ::PartiallySignedTransaction , Error > {
let mut psbt = psbt ::PartiallySignedTransaction ::from_unsigned_tx ( tx ) ? ;
2020-11-30 15:13:33 +01:00
2021-01-01 13:35:05 +11:00
if params . add_global_xpubs {
2022-11-03 15:59:38 +08:00
let all_xpubs = self
. keychanins ( )
. iter ( )
. flat_map ( | ( _ , desc ) | desc . get_extended_keys ( ) )
. collect ::< Vec < _ > > ( ) ;
2020-11-30 15:13:33 +01:00
for xpub in all_xpubs {
let origin = match xpub . origin {
Some ( origin ) = > origin ,
None if xpub . xkey . depth = = 0 = > {
( xpub . root_fingerprint ( & self . secp ) , vec! [ ] . into ( ) )
}
_ = > return Err ( Error ::MissingKeyOrigin ( xpub . xkey . to_string ( ) ) ) ,
} ;
2022-04-14 17:20:46 +02:00
psbt . xpub . insert ( xpub . xkey , origin ) ;
2020-11-30 15:13:33 +01:00
}
}
2021-02-08 15:40:56 +11:00
let mut lookup_output = selected
2020-11-17 12:37:53 +11:00
. into_iter ( )
2021-02-08 15:40:56 +11:00
. map ( | utxo | ( utxo . outpoint ( ) , utxo ) )
2020-11-17 12:37:53 +11:00
. collect ::< HashMap < _ , _ > > ( ) ;
2020-08-13 16:51:27 +02:00
// add metadata for the inputs
2022-04-14 17:20:46 +02:00
for ( psbt_input , input ) in psbt . inputs . iter_mut ( ) . zip ( psbt . unsigned_tx . input . iter ( ) ) {
2021-02-08 15:40:56 +11:00
let utxo = match lookup_output . remove ( & input . previous_output ) {
2020-10-30 14:09:59 +11:00
Some ( utxo ) = > utxo ,
2020-08-13 16:51:27 +02:00
None = > continue ,
} ;
2021-02-08 15:40:56 +11:00
match utxo {
Utxo ::Local ( utxo ) = > {
2021-04-20 14:58:33 +02:00
* psbt_input =
match self . get_psbt_input ( utxo , params . sighash , params . only_witness_utxo ) {
Ok ( psbt_input ) = > psbt_input ,
Err ( e ) = > match e {
2022-04-14 17:20:46 +02:00
Error ::UnknownUtxo = > psbt ::Input {
2021-04-20 14:58:33 +02:00
sighash_type : params . sighash ,
2022-04-14 17:20:46 +02:00
.. psbt ::Input ::default ( )
2021-04-20 14:58:33 +02:00
} ,
_ = > return Err ( e ) ,
2021-03-15 21:50:51 -04:00
} ,
2021-04-20 14:58:33 +02:00
}
2020-08-13 16:51:27 +02:00
}
2021-02-08 15:40:56 +11:00
Utxo ::Foreign {
psbt_input : foreign_psbt_input ,
outpoint ,
} = > {
2022-04-28 15:39:31 +02:00
let is_taproot = foreign_psbt_input
. witness_utxo
. as_ref ( )
. map ( | txout | txout . script_pubkey . is_v1_p2tr ( ) )
. unwrap_or ( false ) ;
if ! is_taproot
& & ! params . only_witness_utxo
& & foreign_psbt_input . non_witness_utxo . is_none ( )
{
2021-02-08 15:40:56 +11:00
return Err ( Error ::Generic ( format! (
" Missing non_witness_utxo on foreign utxo {} " ,
outpoint
) ) ) ;
}
* psbt_input = * foreign_psbt_input ;
2020-08-13 16:51:27 +02:00
}
}
}
2022-10-25 11:15:43 +02:00
self . update_psbt_with_descriptor ( & mut psbt ) ? ;
2020-08-13 16:51:27 +02:00
Ok ( psbt )
}
2021-03-15 21:50:51 -04:00
/// get the corresponding PSBT Input for a LocalUtxo
pub fn get_psbt_input (
& self ,
utxo : LocalUtxo ,
2022-04-14 17:20:46 +02:00
sighash_type : Option < psbt ::PsbtSighashType > ,
2021-04-20 14:58:33 +02:00
only_witness_utxo : bool ,
2022-04-14 17:20:46 +02:00
) -> Result < psbt ::Input , Error > {
2021-03-15 21:50:51 -04:00
// Try to find the prev_script in our db to figure out if this is internal or external,
// and the derivation index
2022-11-03 15:59:38 +08:00
let & ( keychain , child ) = self
. keychain_tracker
. txout_index
. index_of_spk ( & utxo . txout . script_pubkey )
2021-03-30 16:33:07 +02:00
. ok_or ( Error ::UnknownUtxo ) ? ;
2021-03-15 21:50:51 -04:00
2022-04-14 17:20:46 +02:00
let mut psbt_input = psbt ::Input {
2021-03-15 21:50:51 -04:00
sighash_type ,
2022-04-14 17:20:46 +02:00
.. psbt ::Input ::default ( )
2021-03-15 21:50:51 -04:00
} ;
let desc = self . get_descriptor_for_keychain ( keychain ) ;
2022-10-25 11:15:43 +02:00
let derived_descriptor = desc . at_derivation_index ( child ) ;
2021-03-15 21:50:51 -04:00
2022-10-25 11:15:43 +02:00
psbt_input
. update_with_descriptor_unchecked ( & derived_descriptor )
. map_err ( MiniscriptPsbtError ::Conversion ) ? ;
2021-03-15 21:50:51 -04:00
let prev_output = utxo . outpoint ;
2022-11-03 15:59:38 +08:00
if let Some ( prev_tx ) = self . keychain_tracker . graph ( ) . get_tx ( prev_output . txid ) {
2022-04-27 16:29:02 +02:00
if desc . is_witness ( ) | | desc . is_taproot ( ) {
2021-03-15 21:50:51 -04:00
psbt_input . witness_utxo = Some ( prev_tx . output [ prev_output . vout as usize ] . clone ( ) ) ;
}
2022-04-27 16:29:02 +02:00
if ! desc . is_taproot ( ) & & ( ! desc . is_witness ( ) | | ! only_witness_utxo ) {
2022-11-03 15:59:38 +08:00
psbt_input . non_witness_utxo = Some ( prev_tx . clone ( ) ) ;
2021-03-15 21:50:51 -04:00
}
}
Ok ( psbt_input )
}
2022-10-25 11:15:43 +02:00
fn update_psbt_with_descriptor (
2022-04-14 17:20:46 +02:00
& self ,
psbt : & mut psbt ::PartiallySignedTransaction ,
) -> Result < ( ) , Error > {
2022-10-25 11:15:43 +02:00
// We need to borrow `psbt` mutably within the loops, so we have to allocate a vec for all
// the input utxos and outputs
//
// Clippy complains that the collect is not required, but that's wrong
#[ allow(clippy::needless_collect) ]
let utxos = ( 0 .. psbt . inputs . len ( ) )
. filter_map ( | i | psbt . get_utxo_for ( i ) . map ( | utxo | ( true , i , utxo ) ) )
. chain (
psbt . unsigned_tx
. output
. iter ( )
. enumerate ( )
. map ( | ( i , out ) | ( false , i , out . clone ( ) ) ) ,
)
. collect ::< Vec < _ > > ( ) ;
2020-06-30 14:01:38 +02:00
2022-10-25 11:15:43 +02:00
// Try to figure out the keychain and derivation for every input and output
for ( is_input , index , out ) in utxos . into_iter ( ) {
2022-11-03 15:59:38 +08:00
if let Some ( & ( keychain , child ) ) = self
. keychain_tracker
. txout_index
. index_of_spk ( & out . script_pubkey )
2022-10-25 11:15:43 +02:00
{
debug! (
" Found descriptor for input #{} {:?}/{} " ,
index , keychain , child
) ;
let desc = self . get_descriptor_for_keychain ( keychain ) ;
let desc = desc . at_derivation_index ( child ) ;
if is_input {
psbt . update_input_with_descriptor ( index , & desc )
. map_err ( MiniscriptPsbtError ::UtxoUpdate ) ? ;
} else {
psbt . update_output_with_descriptor ( index , & desc )
. map_err ( MiniscriptPsbtError ::OutputUpdate ) ? ;
2020-08-06 18:11:07 +02:00
}
2020-06-30 14:01:38 +02:00
}
}
Ok ( ( ) )
}
2021-10-23 15:00:09 +02:00
2022-03-09 18:38:11 +01:00
/// Return the checksum of the public descriptor associated to `keychain`
///
/// Internally calls [`Self::get_descriptor_for_keychain`] to fetch the right descriptor
pub fn descriptor_checksum ( & self , keychain : KeychainKind ) -> String {
self . get_descriptor_for_keychain ( keychain )
. to_string ( )
2022-05-03 12:41:22 +02:00
. split_once ( '#' )
2022-03-09 18:38:11 +01:00
. unwrap ( )
2022-09-27 21:56:25 +08:00
. 1
2022-03-09 18:38:11 +01:00
. to_string ( )
}
2023-02-15 12:23:59 +11:00
/// Applies an update to the wallet and stages the changes (but does not [`commit`] them).
///
/// Usually you create an `update` by interacting with some blockchain data source and inserting
/// transactions related to your wallet into it.
///
/// [`commit`]: Self::commit
pub fn apply_udpate < Tx > ( & mut self , update : Update < Tx > ) -> Result < ( ) , UpdateError >
where
D : persist ::Backend ,
Tx : IntoOwned < Transaction > + Clone ,
{
let changeset = self . keychain_tracker . apply_update ( update ) ? ;
self . persist . stage ( changeset ) ;
Ok ( ( ) )
}
/// Commits all curently [`staged`] changed to the persistence backend returning and error when this fails.
///
/// [`staged`]: Self::staged
pub fn commit ( & mut self ) -> Result < ( ) , D ::WriteError >
where
D : persist ::Backend ,
{
self . persist . commit ( )
}
/// Returns the changes that will be staged with the next call to [`commit`].
///
/// [`commit`]: Self::commit
pub fn staged ( & self ) -> & ChangeSet {
self . persist . staged ( )
}
2020-02-07 23:22:28 +01:00
}
2020-08-06 18:11:07 +02:00
2022-04-15 22:12:34 +02:00
/// Deterministically generate a unique name given the descriptors defining the wallet
///
/// Compatible with [`wallet_name_from_descriptor`]
pub fn wallet_name_from_descriptor < T > (
descriptor : T ,
change_descriptor : Option < T > ,
network : Network ,
secp : & SecpCtx ,
) -> Result < String , Error >
where
T : IntoWalletDescriptor ,
{
//TODO check descriptors contains only public keys
let descriptor = descriptor
. into_wallet_descriptor ( secp , network ) ?
. 0
. to_string ( ) ;
2022-10-24 12:05:49 -05:00
let mut wallet_name = calc_checksum ( & descriptor [ .. descriptor . find ( '#' ) . unwrap ( ) ] ) ? ;
2022-04-15 22:12:34 +02:00
if let Some ( change_descriptor ) = change_descriptor {
let change_descriptor = change_descriptor
. into_wallet_descriptor ( secp , network ) ?
. 0
. to_string ( ) ;
wallet_name . push_str (
2022-10-24 12:05:49 -05:00
calc_checksum ( & change_descriptor [ .. change_descriptor . find ( '#' ) . unwrap ( ) ] ) ? . as_str ( ) ,
2022-04-15 22:12:34 +02:00
) ;
}
Ok ( wallet_name )
}