feat: add finish related error

This commit is contained in:
Matthew 2024-04-22 15:33:52 -05:00
parent 282fcfce0a
commit e609b57bff
No known key found for this signature in database
GPG Key ID: 8D4FCD82DD54DDD2
4 changed files with 172 additions and 21 deletions

View File

@ -51,6 +51,32 @@ interface WalletCreationError {
LoadedNetworkDoesNotMatch(Network expected, Network? got);
};
[Error]
interface CreateTxError {
Descriptor(string e);
Persist(string e);
Policy(string e);
SpendingPolicyRequired(string kind);
Version0();
Version1Csv();
LockTime(string requested, string required);
RbfSequence();
RbfSequenceCsv(string rbf, string csv);
FeeTooLow(u64 required);
FeeRateTooLow(string required);
NoUtxosSelected();
OutputBelowDustLimit(u64 index);
ChangePolicyDescriptor();
CoinSelection(string e);
InsufficientFunds(u64 needed, u64 available);
NoRecipients();
Psbt(string e);
MissingKeyOrigin(string key);
UnknownUtxo(string outpoint);
MissingNonWitnessUtxo(string outpoint);
MiniscriptPsbt(string e);
};
[Error]
interface PersistenceError {
Write(string e);
@ -302,7 +328,7 @@ interface TxBuilder {
TxBuilder enable_rbf_with_sequence(u32 nsequence);
[Throws=Alpha3Error]
[Throws=CreateTxError]
Psbt finish([ByRef] Wallet wallet);
};

View File

@ -4,7 +4,7 @@ use bdk::bitcoin::psbt::PsbtParseError as BdkPsbtParseError;
use bdk::bitcoin::Network;
use bdk::chain::tx_graph::CalculateFeeError as BdkCalculateFeeError;
use bdk::descriptor::DescriptorError as BdkDescriptorError;
use bdk::wallet::error::{BuildFeeBumpError, CreateTxError};
use bdk::wallet::error::BuildFeeBumpError;
use bdk::wallet::signer::SignerError as BdkSignerError;
use bdk::wallet::tx_builder::{AddUtxoError, AllowShrinkingError};
use bdk::wallet::{NewError, NewOrLoadError};
@ -19,7 +19,7 @@ use bdk::keys::bip39::Error as BdkBip39Error;
use bdk::bitcoin::bip32;
use std::convert::Infallible;
use bdk::wallet::error::CreateTxError as BdkCreateTxError;
use std::convert::TryInto;
#[derive(Debug, thiserror::Error)]
@ -64,6 +64,75 @@ pub enum Bip32Error {
UnknownError { e: String },
}
#[derive(Debug, thiserror::Error)]
pub enum CreateTxError {
#[error("Descriptor error: {e}")]
Descriptor { e: String },
#[error("Persistence failure: {e}")]
Persist { e: String },
#[error("Policy error: {e}")]
Policy { e: String },
#[error("Spending policy required for {kind}")]
SpendingPolicyRequired { kind: String },
#[error("Unsupported version 0")]
Version0,
#[error("Unsupported version 1 with CSV")]
Version1Csv,
#[error("Lock time conflict: requested {requested}, but required {required}")]
LockTime { requested: String, required: String },
#[error("Transaction requires RBF sequence number")]
RbfSequence,
#[error("RBF sequence: {rbf}, CSV sequence: {csv}")]
RbfSequenceCsv { rbf: String, csv: String },
#[error("Fee too low: {required} sat required")]
FeeTooLow { required: u64 },
#[error("Fee rate too low: {required}")]
FeeRateTooLow { required: String },
#[error("No UTXOs selected for the transaction")]
NoUtxosSelected,
#[error("Output value below dust limit at index {index}")]
OutputBelowDustLimit { index: u64 },
#[error("Change policy descriptor error")]
ChangePolicyDescriptor,
#[error("Coin selection failed: {e}")]
CoinSelection { e: String },
#[error("Insufficient funds: needed {needed} sat, available {available} sat")]
InsufficientFunds { needed: u64, available: u64 },
#[error("Transaction has no recipients")]
NoRecipients,
#[error("PSBT creation error: {e}")]
Psbt { e: String },
#[error("Missing key origin for: {key}")]
MissingKeyOrigin { key: String },
#[error("Reference to an unknown UTXO: {outpoint}")]
UnknownUtxo { outpoint: String },
#[error("Missing non-witness UTXO for outpoint: {outpoint}")]
MissingNonWitnessUtxo { outpoint: String },
#[error("Miniscript PSBT error: {e}")]
MiniscriptPsbt { e: String },
}
#[derive(Debug, thiserror::Error)]
pub enum CalculateFeeError {
#[error("missing transaction output: {out_points:?}")]
@ -362,6 +431,72 @@ pub enum ExtractTxError {
OtherExtractTxErr,
}
impl From<BdkCreateTxError<std::io::Error>> for CreateTxError {
fn from(error: BdkCreateTxError<std::io::Error>) -> Self {
match error {
BdkCreateTxError::Descriptor(e) => CreateTxError::Descriptor { e: e.to_string() },
BdkCreateTxError::Persist(e) => CreateTxError::Persist { e: e.to_string() },
BdkCreateTxError::Policy(e) => CreateTxError::Policy { e: e.to_string() },
BdkCreateTxError::SpendingPolicyRequired(kind) => {
CreateTxError::SpendingPolicyRequired {
kind: format!("{:?}", kind),
}
}
BdkCreateTxError::Version0 => CreateTxError::Version0,
BdkCreateTxError::Version1Csv => CreateTxError::Version1Csv,
BdkCreateTxError::LockTime {
requested,
required,
} => CreateTxError::LockTime {
requested: requested.to_string(),
required: required.to_string(),
},
BdkCreateTxError::RbfSequence => CreateTxError::RbfSequence,
BdkCreateTxError::RbfSequenceCsv { rbf, csv } => CreateTxError::RbfSequenceCsv {
rbf: rbf.to_string(),
csv: csv.to_string(),
},
BdkCreateTxError::FeeTooLow { required } => CreateTxError::FeeTooLow { required },
BdkCreateTxError::FeeRateTooLow { required } => CreateTxError::FeeRateTooLow {
required: required.to_string(),
},
BdkCreateTxError::NoUtxosSelected => CreateTxError::NoUtxosSelected,
BdkCreateTxError::OutputBelowDustLimit(index) => CreateTxError::OutputBelowDustLimit {
index: index as u64,
},
BdkCreateTxError::ChangePolicyDescriptor => CreateTxError::ChangePolicyDescriptor,
BdkCreateTxError::CoinSelection(e) => CreateTxError::CoinSelection { e: e.to_string() },
BdkCreateTxError::InsufficientFunds { needed, available } => {
CreateTxError::InsufficientFunds { needed, available }
}
BdkCreateTxError::NoRecipients => CreateTxError::NoRecipients,
BdkCreateTxError::Psbt(e) => CreateTxError::Psbt { e: e.to_string() },
BdkCreateTxError::MissingKeyOrigin(key) => CreateTxError::MissingKeyOrigin { key },
BdkCreateTxError::UnknownUtxo => CreateTxError::UnknownUtxo {
outpoint: "Unknown".to_string(),
},
BdkCreateTxError::MissingNonWitnessUtxo(outpoint) => {
CreateTxError::MissingNonWitnessUtxo {
outpoint: outpoint.to_string(),
}
}
BdkCreateTxError::MiniscriptPsbt(e) => {
CreateTxError::MiniscriptPsbt { e: e.to_string() }
}
}
}
}
impl From<AddUtxoError> for CreateTxError {
fn from(error: AddUtxoError) -> Self {
match error {
AddUtxoError::UnknownUtxo(outpoint) => CreateTxError::UnknownUtxo {
outpoint: outpoint.to_string(),
},
}
}
}
impl From<BdkDescriptorError> for DescriptorError {
fn from(error: BdkDescriptorError) -> Self {
match error {
@ -492,12 +627,6 @@ impl From<BuildFeeBumpError> for Alpha3Error {
}
}
impl From<CreateTxError<Infallible>> for Alpha3Error {
fn from(_: CreateTxError<Infallible>) -> Self {
Alpha3Error::Generic
}
}
impl From<AddUtxoError> for Alpha3Error {
fn from(_: AddUtxoError) -> Self {
Alpha3Error::Generic
@ -544,12 +673,6 @@ impl From<NewError<std::io::Error>> for Alpha3Error {
}
}
impl From<CreateTxError<std::io::Error>> for Alpha3Error {
fn from(_: CreateTxError<std::io::Error>) -> Self {
Alpha3Error::Generic
}
}
impl From<BdkCalculateFeeError> for CalculateFeeError {
fn from(error: BdkCalculateFeeError) -> Self {
match error {

View File

@ -20,6 +20,7 @@ use crate::error::Bip32Error;
use crate::error::Bip39Error;
use crate::error::CalculateFeeError;
use crate::error::CannotConnectError;
use crate::error::CreateTxError;
use crate::error::DescriptorError;
use crate::error::EsploraError;
use crate::error::ExtractTxError;

View File

@ -1,8 +1,8 @@
use crate::bitcoin::{FeeRate, OutPoint, Psbt, Script, Transaction};
use crate::descriptor::Descriptor;
use crate::error::{
Alpha3Error, CalculateFeeError, CannotConnectError, PersistenceError, SignerError,
TxidParseError, WalletCreationError,
Alpha3Error, CalculateFeeError, CannotConnectError, CreateTxError, PersistenceError,
SignerError, TxidParseError, WalletCreationError,
};
use crate::types::{AddressIndex, AddressInfo, Balance, CanonicalTx, LocalOutput, ScriptAmount};
@ -489,7 +489,7 @@ impl TxBuilder {
// })
// }
pub(crate) fn finish(&self, wallet: &Arc<Wallet>) -> Result<Arc<Psbt>, Alpha3Error> {
pub(crate) fn finish(&self, wallet: &Arc<Wallet>) -> Result<Arc<Psbt>, CreateTxError> {
// TODO: I had to change the wallet here to be mutable. Why is that now required with the 1.0 API?
let mut wallet = wallet.get_wallet();
let mut tx_builder = wallet.build_tx();
@ -499,8 +499,9 @@ impl TxBuilder {
tx_builder.change_policy(self.change_policy);
if !self.utxos.is_empty() {
let bdk_utxos: Vec<BdkOutPoint> = self.utxos.iter().map(BdkOutPoint::from).collect();
let utxos: &[BdkOutPoint] = &bdk_utxos;
tx_builder.add_utxos(utxos)?;
tx_builder
.add_utxos(&bdk_utxos)
.map_err(CreateTxError::from)?;
}
if !self.unspendable.is_empty() {
let bdk_unspendable: Vec<BdkOutPoint> =
@ -536,7 +537,7 @@ impl TxBuilder {
// tx_builder.add_data(self.data.as_slice());
// }
let psbt = tx_builder.finish()?;
let psbt = tx_builder.finish().map_err(CreateTxError::from)?;
Ok(Arc::new(psbt.into()))
}