use std::convert::Infallible;
use pepper_sync::{error::ScanError, wallet::OutputId};
use shardtree::error::ShardTreeError;
use zcash_keys::keys::DerivationError;
use zcash_primitives::transaction::TxId;
use zcash_protocol::{PoolType, ShieldedPool, consensus::BlockHeight};
use super::output::OutputRef;
#[derive(Debug, thiserror::Error)]
pub enum WalletError {
#[error("Key error. {0}")]
KeyError(#[from] KeyError),
#[error("Mnemonic not found.")]
MnemonicNotFound,
#[error("Mnemonic error. {0}")]
MnemonicError(#[from] bip0039::Error),
#[error("Value outside valid range of zatoshis. {0:?}")]
InvalidValue(#[from] zcash_protocol::value::BalanceError),
#[error("Failed to read transaction. {0:?}")]
TransactionRead(std::io::Error),
#[error("Failed to write transaction. {0:?}")]
TransactionWrite(std::io::Error),
#[error(
"Removal error. Transaction has not failed. Only failed transactions may be removed from the wallet."
)]
RemovalError,
#[error("Transaction not found in the wallet: {0}")]
TransactionNotFound(TxId),
#[error("Wallet block at height {0} not found in the wallet.")]
BlockNotFound(BlockHeight),
#[error("Minimum confirmations must be non-zero.")]
MinimumConfirmationError,
#[error("Failed to scan calculated transaction. {0}")]
CalculatedTxScanError(#[from] ScanError),
#[error("Address parse error. {0}")]
ParseError(#[from] zcash_address::ParseError),
#[error("No sync data. Wallet has never been synced with the block chain.")]
NoSyncData,
#[error(
"Sync incomplete: the wallet's notes await spend-status confirmation. \
Complete sync and retry."
)]
SyncIncomplete,
#[error("Maximum number of accounts already in use.")]
AccountCreationFailed,
#[error("{shielded_protocol:?} shard store checkpoint not found at anchor height {height}.")]
CheckpointNotFound {
shielded_protocol: ShieldedPool,
height: BlockHeight,
},
#[error("Shard tree error. {0}")]
ShardTreeError(#[from] ShardTreeError<Infallible>),
#[error("Migration: no spendable Orchard note of value {0} zatoshis.")]
MigrationNoteNotFound(u64),
#[error("Migration transaction build failed: {0}")]
MigrationBuild(String),
#[error("Migration: bound note {0:?} not found in the wallet.")]
MigrationBoundNoteMissing(pepper_sync::wallet::OutputId),
#[error("Migration part deviates from the canonical predicate: {0}")]
MigrationDeviation(String),
#[error("Migration part cannot transition from {from} to {to}.")]
MigrationInvalidTransition {
from: &'static str,
to: &'static str,
},
#[error("Migration state corrupt: {0}")]
MigrationStateCorrupt(String),
#[error(
"Migration part cannot anchor in window {window}: no legal anchor bucket \
at or above {lowest_anchor} sits below it."
)]
MigrationNoLegalAnchor {
window: u64,
lowest_anchor: u64,
},
#[error("No spendable Orchard notes to migrate.")]
NothingToMigrate,
#[error("AllFunds(Everything) is not supported: the unspendable-funds audit is unimplemented.")]
AllFundsEverythingUnsupported,
#[error("Conversion failed. {0}")]
ConversionFailed(#[from] crate::utils::error::ConversionError),
#[error(
"birthday {0} below sapling activation height {1}. pre-sapling wallets are not supported!"
)]
BirthdayBelowSapling(u32, u32),
#[error(
"Cannot create a new wallet: a wallet file already exists at this path. Use WalletConfig::Read to load the existing wallet."
)]
WalletAlreadyCreated,
#[error("OP_RETURN send recipient must be a P2PKH, P2SH, or TEX address.")]
OpReturnRecipientNotTransparent,
#[error("Deshield output not found in the deshield transaction.")]
DeshieldOutputNotFound,
#[error("Transparent transaction build failed: {0}")]
TransparentBuild(String),
}
#[cfg(feature = "nym")]
#[derive(Debug, thiserror::Error)]
pub enum PriceError {
#[error("price error.")]
PriceError(#[from] zingo_price::PriceError),
#[error("price race failed.")]
RaceFailed(#[from] zingo_price::PriceRaceFailure),
#[error("price list not initialised. please wait for sync to obtain time of wallet birthday")]
NotInitialised,
#[error("the price run reached no source.")]
Speed(#[source] crate::mixnet::speed::SpeedError),
}
#[derive(Debug, thiserror::Error)]
pub enum SummaryError {
#[error("key error. {0}")]
KeyError(#[from] KeyError),
#[error("address parse error. {0}")]
ParseError(#[from] zcash_address::ParseError),
#[error("spend error. {0}")]
SpendError(#[from] SpendError),
}
#[derive(Debug)]
pub enum FeeError {
SpendNotFound { txid: TxId, spend: String },
BalanceError(zcash_protocol::value::BalanceError),
}
impl std::error::Error for FeeError {}
impl std::fmt::Display for FeeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match &self {
Self::SpendNotFound { txid, spend } => {
write!(
f,
"Transparent spend not found for transaction id {txid}. Is the wallet fully synced? \nMissing spend: {spend}"
)
}
Self::BalanceError(e) => write!(f, "{e}"),
}
}
}
impl From<zcash_protocol::value::BalanceError> for FeeError {
fn from(value: zcash_protocol::value::BalanceError) -> Self {
Self::BalanceError(value)
}
}
#[derive(Debug, thiserror::Error)]
pub enum SpendError {
#[error(
"spend not found for transaction id {txid}. is the wallet fully synced?\nmissing spend: {spend}"
)]
SpendNotFound {
pool: PoolType,
txid: TxId,
spend: String,
},
#[error("output has incorrect spending transaction id: {txid}.\noutput id: {output_id}")]
IncorrectSpendingTransaction { output_id: OutputId, txid: TxId },
}
#[derive(Debug, thiserror::Error)]
pub enum BalanceError {
#[error("key error. {0}")]
KeyError(#[from] KeyError),
#[error("conversion failed. {0}")]
ConversionFailed(#[from] crate::utils::error::ConversionError),
#[error("overflow occured during summation.")]
Overflow,
}
#[derive(Debug, thiserror::Error)]
pub enum KeyError {
#[error("{0}")]
IoError(#[from] std::io::Error),
#[error("Account ID should be at most 31 bits")]
InvalidAccountId(#[from] zip32::TryFromIntError),
#[error("No keys found for the given account id. Try adding the account.")]
NoAccountKeys,
#[error("Key derivation failed")]
KeyDerivationError(#[from] DerivationError),
#[error("Key decoding failed")]
KeyDecodingError,
#[error("Key parsing failed. {0}")]
KeyParseError(#[from] zcash_address::unified::ParseError),
#[error("No spend capability")]
NoSpendCapability,
#[error("No view capability")]
NoViewCapability,
#[error("Outside range of non-hardened child indexes")]
InvalidNonHardenedChildIndex,
#[error("Decoded unified full viewing key does not match current network")]
NetworkMismatch,
#[error("Viewing keys must be imported in the unified format")]
InvalidFormat,
#[error("Unified address must contain a shielded receiver")]
UnifiedAddressError,
#[error(
"Transparent address generation failed. Latest transparent address has not received funds."
)]
GapError,
#[error("Invalid mnemonic phrase: {0}")]
InvalidMnemonicPhrase(#[from] bip0039::Error),
}
impl From<bip32::Error> for KeyError {
fn from(value: bip32::Error) -> Self {
Self::KeyDerivationError(DerivationError::Transparent(value))
}
}
#[allow(missing_docs)] #[derive(Debug, thiserror::Error)]
pub enum CalculateTransactionError<NoteRef> {
#[error("No unified spending key found for this account. {0}")]
NoSpendingKey(#[from] KeyError),
#[error("Failed to load sapling paramaters. {0}")]
SaplingParams(String),
#[error("Failed to calculate transaction. {0}")]
Calculation(
zcash_client_backend::data_api::error::Error<
WalletError,
Infallible,
Infallible,
zcash_primitives::transaction::fees::zip317::FeeError,
zcash_primitives::transaction::fees::zip317::FeeError,
NoteRef,
>,
),
#[error("Only tex multistep transactions are supported!")]
NonTexMultiStep,
}
#[derive(Debug, thiserror::Error)]
pub enum ProposeSendError {
#[error("{0}")]
Proposal(
zcash_client_backend::data_api::error::Error<
WalletError,
WalletError,
zcash_client_backend::data_api::wallet::input_selection::GreedyInputSelectorError,
zcash_primitives::transaction::fees::zip317::FeeError,
zcash_primitives::transaction::fees::zip317::FeeError,
OutputRef,
>,
),
#[error("{0}")]
TransactionRequestFailed(#[from] zcash_client_backend::zip321::Zip321Error),
}
#[derive(Debug, thiserror::Error)]
pub enum ProposeShieldError {
#[error("{0}")]
Component(
zcash_client_backend::data_api::error::Error<
WalletError,
WalletError,
zcash_client_backend::data_api::wallet::input_selection::GreedyInputSelectorError,
zcash_primitives::transaction::fees::zip317::FeeError,
zcash_primitives::transaction::fees::zip317::FeeError,
Infallible,
>,
),
#[error("insufficient transparent funds to shield.")]
InsufficientFunds,
#[error("address parse error. {0}")]
AddressParseError(#[from] zcash_address::ParseError),
}