diff --git a/crates/bdk/src/error.rs b/crates/bdk/src/error.rs index 105e642a04..7a164120f9 100644 --- a/crates/bdk/src/error.rs +++ b/crates/bdk/src/error.rs @@ -9,13 +9,17 @@ // You may not use this file except in accordance with one or both of these // licenses. -use crate::bitcoin::Network; -use crate::{descriptor, wallet}; -use alloc::{string::String, vec::Vec}; -use bitcoin::{OutPoint, Txid}; +//! Errors that can be thrown by the [`Wallet`](crate::wallet::Wallet) + +use crate::descriptor::policy::PolicyError; +use crate::descriptor::DescriptorError; +use crate::wallet::coin_selection; +use crate::{descriptor, wallet, FeeRate, KeychainKind}; +use alloc::string::String; +use bitcoin::{absolute, psbt, OutPoint, Sequence}; use core::fmt; -/// Errors that can be thrown by the [`Wallet`](crate::wallet::Wallet) +/// Old catch-all errors enum that can be thrown by the [`Wallet`](crate::wallet::Wallet) #[derive(Debug)] pub enum Error { /// Generic error @@ -53,8 +57,11 @@ pub enum Error { /// Errors returned by miniscript when updating inconsistent PSBTs #[derive(Debug, Clone)] pub enum MiniscriptPsbtError { + /// Descriptor key conversion error Conversion(miniscript::descriptor::ConversionError), + /// Return error type for PsbtExt::update_input_with_descriptor UtxoUpdate(miniscript::psbt::UtxoUpdateError), + /// Return error type for PsbtExt::update_output_with_descriptor OutputUpdate(miniscript::psbt::OutputUpdateError), } @@ -134,3 +141,204 @@ impl_error!(miniscript::Error, Miniscript); impl_error!(MiniscriptPsbtError, MiniscriptPsbt); impl_error!(bitcoin::bip32::Error, Bip32); impl_error!(bitcoin::psbt::Error, Psbt); + +#[derive(Debug)] +/// Error returned from [`TxBuilder::finish`] +pub enum CreateTxError
{ + /// There was a problem with the descriptors passed in + Descriptor(DescriptorError), + /// We were unable to write wallet data to the persistence backend + Persist(P), + /// There was a problem while extracting and manipulating policies + Policy(PolicyError), + /// Spending policy is not compatible with this [`KeychainKind`](crate::types::KeychainKind) + SpendingPolicyRequired(KeychainKind), + /// Requested invalid transaction version '0' + Version0, + /// Requested transaction version `1`, but at least `2` is needed to use OP_CSV + Version1Csv, + /// Requested `LockTime` is less than is required to spend from this script + LockTime { + /// Requested `LockTime` + requested: absolute::LockTime, + /// Required `LockTime` + required: absolute::LockTime, + }, + /// Cannot enable RBF with a `Sequence` >= 0xFFFFFFFE + RbfSequence, + /// Cannot enable RBF with `Sequence` given a required OP_CSV + RbfSequenceCsv { + /// Given RBF `Sequence` + rbf: Sequence, + /// Required OP_CSV `Sequence` + csv: Sequence, + }, + /// When bumping a tx the absolute fee requested is lower than replaced tx absolute fee + FeeTooLow { + /// Required fee absolute value (satoshi) + required: u64, + }, + /// When bumping a tx the fee rate requested is lower than required + FeeRateTooLow { + /// Required fee rate (satoshi/vbyte) + required: FeeRate, + }, + /// `manually_selected_only` option is selected but no utxo has been passed + NoUtxosSelected, + /// Output created is under the dust limit, 546 satoshis + OutputBelowDustLimit(usize), + /// The `change_policy` was set but the wallet does not have a change_descriptor + ChangePolicyDescriptor, + /// There was an error with coin selection + CoinSelection(coin_selection::Error), + /// Wallet's UTXO set is not enough to cover recipient's requested plus fee + InsufficientFunds { + /// Sats needed for some transaction + needed: u64, + /// Sats available for spending + available: u64, + }, + /// Cannot build a tx without recipients + NoRecipients, + /// Partially signed bitcoin transaction error + Psbt(psbt::Error), + /// In order to use the [`TxBuilder::add_global_xpubs`] option every extended + /// key in the descriptor must either be a master key itself (having depth = 0) or have an + /// explicit origin provided + /// + /// [`TxBuilder::add_global_xpubs`]: crate::wallet::tx_builder::TxBuilder::add_global_xpubs + MissingKeyOrigin(String), + /// Happens when trying to spend an UTXO that is not in the internal database + UnknownUtxo, + /// Missing non_witness_utxo on foreign utxo for given `OutPoint` + MissingNonWitnessUtxo(OutPoint), + /// Miniscript PSBT error + MiniscriptPsbt(MiniscriptPsbtError), +} + +#[cfg(feature = "std")] +impl
fmt::Display for CreateTxError
+where + P: fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Descriptor(e) => e.fmt(f), + Self::Persist(e) => { + write!( + f, + "failed to write wallet data to persistence backend: {}", + e + ) + } + Self::Policy(e) => e.fmt(f), + CreateTxError::SpendingPolicyRequired(keychain_kind) => { + write!(f, "Spending policy required: {:?}", keychain_kind) + } + CreateTxError::Version0 => { + write!(f, "Invalid version `0`") + } + CreateTxError::Version1Csv => { + write!( + f, + "TxBuilder requested version `1`, but at least `2` is needed to use OP_CSV" + ) + } + CreateTxError::LockTime { + requested, + required, + } => { + write!(f, "TxBuilder requested timelock of `{:?}`, but at least `{:?}` is required to spend from this script", required, requested) + } + CreateTxError::RbfSequence => { + write!(f, "Cannot enable RBF with a nSequence >= 0xFFFFFFFE") + } + CreateTxError::RbfSequenceCsv { rbf, csv } => { + write!( + f, + "Cannot enable RBF with nSequence `{:?}` given a required OP_CSV of `{:?}`", + rbf, csv + ) + } + CreateTxError::FeeTooLow { required } => { + write!(f, "Fee to low: required {} sat", required) + } + CreateTxError::FeeRateTooLow { required } => { + write!( + f, + "Fee rate too low: required {} sat/vbyte", + required.as_sat_per_vb() + ) + } + CreateTxError::NoUtxosSelected => { + write!(f, "No UTXO selected") + } + CreateTxError::OutputBelowDustLimit(limit) => { + write!(f, "Output below the dust limit: {}", limit) + } + CreateTxError::ChangePolicyDescriptor => { + write!( + f, + "The `change_policy` can be set only if the wallet has a change_descriptor" + ) + } + CreateTxError::CoinSelection(e) => e.fmt(f), + CreateTxError::InsufficientFunds { needed, available } => { + write!( + f, + "Insufficient funds: {} sat available of {} sat needed", + available, needed + ) + } + CreateTxError::NoRecipients => { + write!(f, "Cannot build tx without recipients") + } + CreateTxError::Psbt(e) => e.fmt(f), + CreateTxError::MissingKeyOrigin(err) => { + write!(f, "Missing key origin: {}", err) + } + CreateTxError::UnknownUtxo => { + write!(f, "UTXO not found in the internal database") + } + CreateTxError::MissingNonWitnessUtxo(outpoint) => { + write!(f, "Missing non_witness_utxo on foreign utxo {}", outpoint) + } + CreateTxError::MiniscriptPsbt(err) => { + write!(f, "Miniscript PSBT error: {}", err) + } + } + } +} + +impl
From {
+ fn from(err: descriptor::error::Error) -> Self {
+ CreateTxError::Descriptor(err)
+ }
+}
+
+impl From {
+ fn from(err: PolicyError) -> Self {
+ CreateTxError::Policy(err)
+ }
+}
+
+impl From {
+ fn from(err: MiniscriptPsbtError) -> Self {
+ CreateTxError::MiniscriptPsbt(err)
+ }
+}
+
+impl From {
+ fn from(err: psbt::Error) -> Self {
+ CreateTxError::Psbt(err)
+ }
+}
+
+impl From {
+ fn from(err: coin_selection::Error) -> Self {
+ CreateTxError::CoinSelection(err)
+ }
+}
+
+#[cfg(feature = "std")]
+impl {}
diff --git a/crates/bdk/src/lib.rs b/crates/bdk/src/lib.rs
index 012a868a61..3b68395976 100644
--- a/crates/bdk/src/lib.rs
+++ b/crates/bdk/src/lib.rs
@@ -27,9 +27,8 @@ extern crate serde_json;
#[cfg(feature = "keys-bip39")]
extern crate bip39;
-#[allow(unused_imports)]
#[macro_use]
-pub(crate) mod error;
+pub mod error;
pub mod descriptor;
pub mod keys;
pub mod psbt;
diff --git a/crates/bdk/src/wallet/coin_selection.rs b/crates/bdk/src/wallet/coin_selection.rs
index 0ce38242fd..7803c55091 100644
--- a/crates/bdk/src/wallet/coin_selection.rs
+++ b/crates/bdk/src/wallet/coin_selection.rs
@@ -26,7 +26,8 @@
//! ```
//! # use std::str::FromStr;
//! # use bitcoin::*;
-//! # use bdk::wallet::{self, ChangeSet, coin_selection::*, coin_selection, CreateTxError};
+//! # use bdk::wallet::{self, ChangeSet, coin_selection::*, coin_selection};
+//! # use bdk::error::CreateTxError;
//! # use bdk_chain::PersistBackend;
//! # use bdk::*;
//! # use bdk::wallet::coin_selection::decide_change;
diff --git a/crates/bdk/src/wallet/mod.rs b/crates/bdk/src/wallet/mod.rs
index 58c5f1002c..cc41addc6e 100644
--- a/crates/bdk/src/wallet/mod.rs
+++ b/crates/bdk/src/wallet/mod.rs
@@ -56,19 +56,18 @@ pub mod hardwaresigner;
pub use utils::IsDust;
-use crate::descriptor;
#[allow(deprecated)]
use coin_selection::DefaultCoinSelectionAlgorithm;
use signer::{SignOptions, SignerOrdering, SignersContainer, TransactionSigner};
use tx_builder::{BumpFee, CreateTx, FeePolicy, TxBuilder, TxParams};
use utils::{check_nsequence_rbf, After, Older, SecpCtx};
-use crate::descriptor::policy::{BuildSatisfaction, PolicyError};
+use crate::descriptor::policy::BuildSatisfaction;
use crate::descriptor::{
- calc_checksum, into_wallet_descriptor_checked, DerivedDescriptor, DescriptorError,
- DescriptorMeta, ExtendedDescriptor, ExtractPolicy, IntoWalletDescriptor, Policy, XKeyUtils,
+ calc_checksum, into_wallet_descriptor_checked, DerivedDescriptor, DescriptorMeta,
+ ExtendedDescriptor, ExtractPolicy, IntoWalletDescriptor, Policy, XKeyUtils,
};
-use crate::error::{Error, MiniscriptPsbtError};
+use crate::error::{CreateTxError, Error, MiniscriptPsbtError};
use crate::psbt::PsbtUtils;
use crate::signer::SignerError;
use crate::types::*;
@@ -284,207 +283,6 @@ pub enum InsertTxError {
#[cfg(feature = "std")]
impl {}
-#[derive(Debug)]
-/// Error returned from [`TxBuilder::finish`]
-pub enum CreateTxError {
- /// There was a problem with the descriptors passed in
- Descriptor(DescriptorError),
- /// We were unable to write wallet data to the persistence backend
- Persist(P),
- /// There was a problem while extracting and manipulating policies
- Policy(PolicyError),
- /// Spending policy is not compatible with this [`KeychainKind`](crate::types::KeychainKind)
- SpendingPolicyRequired(KeychainKind),
- /// Requested invalid transaction version '0'
- Version0,
- /// Requested transaction version `1`, but at least `2` is needed to use OP_CSV
- Version1Csv,
- /// Requested `LockTime` is less than is required to spend from this script
- LockTime {
- /// Requested `LockTime`
- requested: absolute::LockTime,
- /// Required `LockTime`
- required: absolute::LockTime,
- },
- /// Cannot enable RBF with a `Sequence` >= 0xFFFFFFFE
- RbfSequence,
- /// Cannot enable RBF with `Sequence` given a required OP_CSV
- RbfSequenceCsv {
- /// Given RBF `Sequence`
- rbf: Sequence,
- /// Required OP_CSV `Sequence`
- csv: Sequence,
- },
- /// When bumping a tx the absolute fee requested is lower than replaced tx absolute fee
- FeeTooLow {
- /// Required fee absolute value (satoshi)
- required: u64,
- },
- /// When bumping a tx the fee rate requested is lower than required
- FeeRateTooLow {
- /// Required fee rate (satoshi/vbyte)
- required: FeeRate,
- },
- /// `manually_selected_only` option is selected but no utxo has been passed
- NoUtxosSelected,
- /// Output created is under the dust limit, 546 satoshis
- OutputBelowDustLimit(usize),
- /// The `change_policy` was set but the wallet does not have a change_descriptor
- ChangePolicyDescriptor,
- /// There was an error with coin selection
- CoinSelection(coin_selection::Error),
- /// Wallet's UTXO set is not enough to cover recipient's requested plus fee
- InsufficientFunds {
- /// Sats needed for some transaction
- needed: u64,
- /// Sats available for spending
- available: u64,
- },
- /// Cannot build a tx without recipients
- NoRecipients,
- /// Partially signed bitcoin transaction error
- Psbt(psbt::Error),
- /// In order to use the [`TxBuilder::add_global_xpubs`] option every extended
- /// key in the descriptor must either be a master key itself (having depth = 0) or have an
- /// explicit origin provided
- ///
- /// [`TxBuilder::add_global_xpubs`]: crate::wallet::tx_builder::TxBuilder::add_global_xpubs
- MissingKeyOrigin(String),
- /// Happens when trying to spend an UTXO that is not in the internal database
- UnknownUtxo,
- /// Missing non_witness_utxo on foreign utxo for given `OutPoint`
- MissingNonWitnessUtxo(OutPoint),
- /// Miniscript PSBT error
- MiniscriptPsbt(MiniscriptPsbtError),
-}
-
-#[cfg(feature = "std")]
-impl fmt::Display for CreateTxError
-where
- P: fmt::Display,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- Self::Descriptor(e) => e.fmt(f),
- Self::Persist(e) => {
- write!(
- f,
- "failed to write wallet data to persistence backend: {}",
- e
- )
- }
- Self::Policy(e) => e.fmt(f),
- CreateTxError::SpendingPolicyRequired(keychain_kind) => {
- write!(f, "Spending policy required: {:?}", keychain_kind)
- }
- CreateTxError::Version0 => {
- write!(f, "Invalid version `0`")
- }
- CreateTxError::Version1Csv => {
- write!(
- f,
- "TxBuilder requested version `1`, but at least `2` is needed to use OP_CSV"
- )
- }
- CreateTxError::LockTime {
- requested,
- required,
- } => {
- write!(f, "TxBuilder requested timelock of `{:?}`, but at least `{:?}` is required to spend from this script", required, requested)
- }
- CreateTxError::RbfSequence => {
- write!(f, "Cannot enable RBF with a nSequence >= 0xFFFFFFFE")
- }
- CreateTxError::RbfSequenceCsv { rbf, csv } => {
- write!(
- f,
- "Cannot enable RBF with nSequence `{:?}` given a required OP_CSV of `{:?}`",
- rbf, csv
- )
- }
- CreateTxError::FeeTooLow { required } => {
- write!(f, "Fee to low: required {} sat", required)
- }
- CreateTxError::FeeRateTooLow { required } => {
- write!(
- f,
- "Fee rate too low: required {} sat/vbyte",
- required.as_sat_per_vb()
- )
- }
- CreateTxError::NoUtxosSelected => {
- write!(f, "No UTXO selected")
- }
- CreateTxError::OutputBelowDustLimit(limit) => {
- write!(f, "Output below the dust limit: {}", limit)
- }
- CreateTxError::ChangePolicyDescriptor => {
- write!(
- f,
- "The `change_policy` can be set only if the wallet has a change_descriptor"
- )
- }
- CreateTxError::CoinSelection(e) => e.fmt(f),
- CreateTxError::InsufficientFunds { needed, available } => {
- write!(
- f,
- "Insufficient funds: {} sat available of {} sat needed",
- available, needed
- )
- }
- CreateTxError::NoRecipients => {
- write!(f, "Cannot build tx without recipients")
- }
- CreateTxError::Psbt(e) => e.fmt(f),
- CreateTxError::MissingKeyOrigin(err) => {
- write!(f, "Missing key origin: {}", err)
- }
- CreateTxError::UnknownUtxo => {
- write!(f, "UTXO not found in the internal database")
- }
- CreateTxError::MissingNonWitnessUtxo(outpoint) => {
- write!(f, "Missing non_witness_utxo on foreign utxo {}", outpoint)
- }
- CreateTxError::MiniscriptPsbt(err) => {
- write!(f, "Miniscript PSBT error: {}", err)
- }
- }
- }
-}
-
-impl From {
- fn from(err: descriptor::error::Error) -> Self {
- CreateTxError::Descriptor(err)
- }
-}
-
-impl From {
- fn from(err: PolicyError) -> Self {
- CreateTxError::Policy(err)
- }
-}
-
-impl From {
- fn from(err: MiniscriptPsbtError) -> Self {
- CreateTxError::MiniscriptPsbt(err)
- }
-}
-
-impl From {
- fn from(err: psbt::Error) -> Self {
- CreateTxError::Psbt(err)
- }
-}
-
-impl From {
- fn from(err: coin_selection::Error) -> Self {
- CreateTxError::CoinSelection(err)
- }
-}
-
-#[cfg(feature = "std")]
-impl {}
-
impl