|
9 | 9 | // You may not use this file except in accordance with one or both of these |
10 | 10 | // licenses. |
11 | 11 |
|
12 | | -use crate::bitcoin::Network; |
13 | | -use crate::{descriptor, wallet}; |
14 | | -use alloc::{string::String, vec::Vec}; |
15 | | -use bitcoin::{OutPoint, Txid}; |
| 12 | +//! Errors that can be thrown by the [`Wallet`](crate::wallet::Wallet) |
| 13 | +
|
| 14 | +use crate::descriptor::policy::PolicyError; |
| 15 | +use crate::descriptor::DescriptorError; |
| 16 | +use crate::wallet::coin_selection; |
| 17 | +use crate::{descriptor, wallet, FeeRate, KeychainKind}; |
| 18 | +use alloc::string::String; |
| 19 | +use bitcoin::{absolute, psbt, OutPoint, Sequence}; |
16 | 20 | use core::fmt; |
17 | 21 |
|
18 | | -/// Errors that can be thrown by the [`Wallet`](crate::wallet::Wallet) |
| 22 | +/// Old catch-all errors enum that can be thrown by the [`Wallet`](crate::wallet::Wallet) |
19 | 23 | #[derive(Debug)] |
20 | 24 | pub enum Error { |
21 | 25 | /// Generic error |
@@ -53,8 +57,11 @@ pub enum Error { |
53 | 57 | /// Errors returned by miniscript when updating inconsistent PSBTs |
54 | 58 | #[derive(Debug, Clone)] |
55 | 59 | pub enum MiniscriptPsbtError { |
| 60 | + /// Descriptor key conversion error |
56 | 61 | Conversion(miniscript::descriptor::ConversionError), |
| 62 | + /// Return error type for PsbtExt::update_input_with_descriptor |
57 | 63 | UtxoUpdate(miniscript::psbt::UtxoUpdateError), |
| 64 | + /// Return error type for PsbtExt::update_output_with_descriptor |
58 | 65 | OutputUpdate(miniscript::psbt::OutputUpdateError), |
59 | 66 | } |
60 | 67 |
|
@@ -134,3 +141,204 @@ impl_error!(miniscript::Error, Miniscript); |
134 | 141 | impl_error!(MiniscriptPsbtError, MiniscriptPsbt); |
135 | 142 | impl_error!(bitcoin::bip32::Error, Bip32); |
136 | 143 | impl_error!(bitcoin::psbt::Error, Psbt); |
| 144 | + |
| 145 | +#[derive(Debug)] |
| 146 | +/// Error returned from [`TxBuilder::finish`] |
| 147 | +pub enum CreateTxError<P> { |
| 148 | + /// There was a problem with the descriptors passed in |
| 149 | + Descriptor(DescriptorError), |
| 150 | + /// We were unable to write wallet data to the persistence backend |
| 151 | + Persist(P), |
| 152 | + /// There was a problem while extracting and manipulating policies |
| 153 | + Policy(PolicyError), |
| 154 | + /// Spending policy is not compatible with this [`KeychainKind`](crate::types::KeychainKind) |
| 155 | + SpendingPolicyRequired(KeychainKind), |
| 156 | + /// Requested invalid transaction version '0' |
| 157 | + Version0, |
| 158 | + /// Requested transaction version `1`, but at least `2` is needed to use OP_CSV |
| 159 | + Version1Csv, |
| 160 | + /// Requested `LockTime` is less than is required to spend from this script |
| 161 | + LockTime { |
| 162 | + /// Requested `LockTime` |
| 163 | + requested: absolute::LockTime, |
| 164 | + /// Required `LockTime` |
| 165 | + required: absolute::LockTime, |
| 166 | + }, |
| 167 | + /// Cannot enable RBF with a `Sequence` >= 0xFFFFFFFE |
| 168 | + RbfSequence, |
| 169 | + /// Cannot enable RBF with `Sequence` given a required OP_CSV |
| 170 | + RbfSequenceCsv { |
| 171 | + /// Given RBF `Sequence` |
| 172 | + rbf: Sequence, |
| 173 | + /// Required OP_CSV `Sequence` |
| 174 | + csv: Sequence, |
| 175 | + }, |
| 176 | + /// When bumping a tx the absolute fee requested is lower than replaced tx absolute fee |
| 177 | + FeeTooLow { |
| 178 | + /// Required fee absolute value (satoshi) |
| 179 | + required: u64, |
| 180 | + }, |
| 181 | + /// When bumping a tx the fee rate requested is lower than required |
| 182 | + FeeRateTooLow { |
| 183 | + /// Required fee rate (satoshi/vbyte) |
| 184 | + required: FeeRate, |
| 185 | + }, |
| 186 | + /// `manually_selected_only` option is selected but no utxo has been passed |
| 187 | + NoUtxosSelected, |
| 188 | + /// Output created is under the dust limit, 546 satoshis |
| 189 | + OutputBelowDustLimit(usize), |
| 190 | + /// The `change_policy` was set but the wallet does not have a change_descriptor |
| 191 | + ChangePolicyDescriptor, |
| 192 | + /// There was an error with coin selection |
| 193 | + CoinSelection(coin_selection::Error), |
| 194 | + /// Wallet's UTXO set is not enough to cover recipient's requested plus fee |
| 195 | + InsufficientFunds { |
| 196 | + /// Sats needed for some transaction |
| 197 | + needed: u64, |
| 198 | + /// Sats available for spending |
| 199 | + available: u64, |
| 200 | + }, |
| 201 | + /// Cannot build a tx without recipients |
| 202 | + NoRecipients, |
| 203 | + /// Partially signed bitcoin transaction error |
| 204 | + Psbt(psbt::Error), |
| 205 | + /// In order to use the [`TxBuilder::add_global_xpubs`] option every extended |
| 206 | + /// key in the descriptor must either be a master key itself (having depth = 0) or have an |
| 207 | + /// explicit origin provided |
| 208 | + /// |
| 209 | + /// [`TxBuilder::add_global_xpubs`]: crate::wallet::tx_builder::TxBuilder::add_global_xpubs |
| 210 | + MissingKeyOrigin(String), |
| 211 | + /// Happens when trying to spend an UTXO that is not in the internal database |
| 212 | + UnknownUtxo, |
| 213 | + /// Missing non_witness_utxo on foreign utxo for given `OutPoint` |
| 214 | + MissingNonWitnessUtxo(OutPoint), |
| 215 | + /// Miniscript PSBT error |
| 216 | + MiniscriptPsbt(MiniscriptPsbtError), |
| 217 | +} |
| 218 | + |
| 219 | +#[cfg(feature = "std")] |
| 220 | +impl<P> fmt::Display for CreateTxError<P> |
| 221 | +where |
| 222 | + P: fmt::Display, |
| 223 | +{ |
| 224 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 225 | + match self { |
| 226 | + Self::Descriptor(e) => e.fmt(f), |
| 227 | + Self::Persist(e) => { |
| 228 | + write!( |
| 229 | + f, |
| 230 | + "failed to write wallet data to persistence backend: {}", |
| 231 | + e |
| 232 | + ) |
| 233 | + } |
| 234 | + Self::Policy(e) => e.fmt(f), |
| 235 | + CreateTxError::SpendingPolicyRequired(keychain_kind) => { |
| 236 | + write!(f, "Spending policy required: {:?}", keychain_kind) |
| 237 | + } |
| 238 | + CreateTxError::Version0 => { |
| 239 | + write!(f, "Invalid version `0`") |
| 240 | + } |
| 241 | + CreateTxError::Version1Csv => { |
| 242 | + write!( |
| 243 | + f, |
| 244 | + "TxBuilder requested version `1`, but at least `2` is needed to use OP_CSV" |
| 245 | + ) |
| 246 | + } |
| 247 | + CreateTxError::LockTime { |
| 248 | + requested, |
| 249 | + required, |
| 250 | + } => { |
| 251 | + write!(f, "TxBuilder requested timelock of `{:?}`, but at least `{:?}` is required to spend from this script", required, requested) |
| 252 | + } |
| 253 | + CreateTxError::RbfSequence => { |
| 254 | + write!(f, "Cannot enable RBF with a nSequence >= 0xFFFFFFFE") |
| 255 | + } |
| 256 | + CreateTxError::RbfSequenceCsv { rbf, csv } => { |
| 257 | + write!( |
| 258 | + f, |
| 259 | + "Cannot enable RBF with nSequence `{:?}` given a required OP_CSV of `{:?}`", |
| 260 | + rbf, csv |
| 261 | + ) |
| 262 | + } |
| 263 | + CreateTxError::FeeTooLow { required } => { |
| 264 | + write!(f, "Fee to low: required {} sat", required) |
| 265 | + } |
| 266 | + CreateTxError::FeeRateTooLow { required } => { |
| 267 | + write!( |
| 268 | + f, |
| 269 | + "Fee rate too low: required {} sat/vbyte", |
| 270 | + required.as_sat_per_vb() |
| 271 | + ) |
| 272 | + } |
| 273 | + CreateTxError::NoUtxosSelected => { |
| 274 | + write!(f, "No UTXO selected") |
| 275 | + } |
| 276 | + CreateTxError::OutputBelowDustLimit(limit) => { |
| 277 | + write!(f, "Output below the dust limit: {}", limit) |
| 278 | + } |
| 279 | + CreateTxError::ChangePolicyDescriptor => { |
| 280 | + write!( |
| 281 | + f, |
| 282 | + "The `change_policy` can be set only if the wallet has a change_descriptor" |
| 283 | + ) |
| 284 | + } |
| 285 | + CreateTxError::CoinSelection(e) => e.fmt(f), |
| 286 | + CreateTxError::InsufficientFunds { needed, available } => { |
| 287 | + write!( |
| 288 | + f, |
| 289 | + "Insufficient funds: {} sat available of {} sat needed", |
| 290 | + available, needed |
| 291 | + ) |
| 292 | + } |
| 293 | + CreateTxError::NoRecipients => { |
| 294 | + write!(f, "Cannot build tx without recipients") |
| 295 | + } |
| 296 | + CreateTxError::Psbt(e) => e.fmt(f), |
| 297 | + CreateTxError::MissingKeyOrigin(err) => { |
| 298 | + write!(f, "Missing key origin: {}", err) |
| 299 | + } |
| 300 | + CreateTxError::UnknownUtxo => { |
| 301 | + write!(f, "UTXO not found in the internal database") |
| 302 | + } |
| 303 | + CreateTxError::MissingNonWitnessUtxo(outpoint) => { |
| 304 | + write!(f, "Missing non_witness_utxo on foreign utxo {}", outpoint) |
| 305 | + } |
| 306 | + CreateTxError::MiniscriptPsbt(err) => { |
| 307 | + write!(f, "Miniscript PSBT error: {}", err) |
| 308 | + } |
| 309 | + } |
| 310 | + } |
| 311 | +} |
| 312 | + |
| 313 | +impl<P> From<descriptor::error::Error> for CreateTxError<P> { |
| 314 | + fn from(err: descriptor::error::Error) -> Self { |
| 315 | + CreateTxError::Descriptor(err) |
| 316 | + } |
| 317 | +} |
| 318 | + |
| 319 | +impl<P> From<PolicyError> for CreateTxError<P> { |
| 320 | + fn from(err: PolicyError) -> Self { |
| 321 | + CreateTxError::Policy(err) |
| 322 | + } |
| 323 | +} |
| 324 | + |
| 325 | +impl<P> From<MiniscriptPsbtError> for CreateTxError<P> { |
| 326 | + fn from(err: MiniscriptPsbtError) -> Self { |
| 327 | + CreateTxError::MiniscriptPsbt(err) |
| 328 | + } |
| 329 | +} |
| 330 | + |
| 331 | +impl<P> From<psbt::Error> for CreateTxError<P> { |
| 332 | + fn from(err: psbt::Error) -> Self { |
| 333 | + CreateTxError::Psbt(err) |
| 334 | + } |
| 335 | +} |
| 336 | + |
| 337 | +impl<P> From<coin_selection::Error> for CreateTxError<P> { |
| 338 | + fn from(err: coin_selection::Error) -> Self { |
| 339 | + CreateTxError::CoinSelection(err) |
| 340 | + } |
| 341 | +} |
| 342 | + |
| 343 | +#[cfg(feature = "std")] |
| 344 | +impl<P: core::fmt::Display + core::fmt::Debug> std::error::Error for CreateTxError<P> {} |
0 commit comments