use crate::esplora::TxSyncError;
use aes::cipher::block_padding::UnpadError;
use bitcoin::Network;
use lightning::ln::peer_handler::PeerHandleError;
use lightning_invoice::payment::PaymentError;
use lightning_invoice::ParseOrSemanticError;
use lightning_rapid_gossip_sync::GraphSyncError;
use std::string::FromUtf8Error;
use thiserror::Error;
#[derive(Error, Debug)]
#[allow(dead_code)]
pub enum MutinyError {
#[error("Mutiny is already running.")]
AlreadyRunning,
#[error("Mutiny is not running.")]
NotRunning,
#[error("Incorrect expected network.")]
NetworkMismatch,
#[error("Resource Not found.")]
NotFound,
#[error("Funding transaction could not be created.")]
FundingTxCreationFailed,
#[error("Network connection closed.")]
ConnectionFailed,
#[error("The invoice or address is on a different network.")]
IncorrectNetwork(Network),
#[error("An invoice must not get payed twice.")]
NonUniquePaymentHash,
#[error("Payment timed out.")]
PaymentTimeout,
#[error("The given invoice is invalid.")]
InvoiceInvalid,
#[error("Failed to create invoice.")]
InvoiceCreationFailed,
#[error("Channel reserve amount is too high.")]
ReserveAmountError,
#[error("We do not have enough balance to pay the given amount.")]
InsufficientBalance,
#[error("Failed to call on the given LNURL.")]
LnUrlFailure,
#[error("Failed to make a request to the LSP.")]
LspGenericError,
#[error("Failed to request channel from LSP due to funding error.")]
LspFundingError,
#[error("Failed to request channel from LSP due to amount being too high.")]
LspAmountTooHighError,
#[error("Failed to have a connection to the LSP node.")]
LspConnectionError,
#[error("Subscription Client Not Configured")]
SubscriptionClientNotConfigured,
#[error("Invalid Arguments were given")]
InvalidArgumentsError,
#[error("Failed to find route.")]
RoutingFailed,
#[error("Failed to parse the given peer information.")]
PeerInfoParseFailed,
#[error("Failed to create channel.")]
ChannelCreationFailed,
#[error("Failed to close channel.")]
ChannelClosingFailed,
#[error("Failed to persist data.")]
PersistenceFailed {
#[from]
source: MutinyStorageError,
},
#[error("Failed to read data from storage.")]
ReadError { source: MutinyStorageError },
#[error("Failed to decode lightning data.")]
LnDecodeError,
#[error("Failed to generate seed")]
SeedGenerationFailed,
#[error("Invalid mnemonic")]
InvalidMnemonic,
#[error("Failed to conduct wallet operation.")]
WalletOperationFailed,
#[error("Failed to sign given transaction.")]
WalletSigningFailed,
#[error("Failed to conduct chain access operation.")]
ChainAccessFailed,
#[error("Failed to to sync on-chain wallet.")]
WalletSyncError,
#[error("Failed to execute a rapid gossip sync function")]
RapidGossipSyncError,
#[error("Failed to execute a dlc function")]
DLCManagerError,
#[error("The given node pubkey is invalid.")]
PubkeyInvalid,
#[error("Called incorrect lnurl function.")]
IncorrectLnUrlFunction,
#[error("Satoshi amount is invalid")]
BadAmountError,
#[error("Failed to get the bitcoin price.")]
BitcoinPriceError,
#[error("Failed to get nostr data.")]
NostrError,
#[error("Incorrect password entered.")]
IncorrectPassword,
#[error("Cannot change password to the same password.")]
SamePassword,
#[error("Failed to create payjoin request.")]
PayjoinCreateRequest,
#[error("Failed to validate payjoin response.")]
PayjoinValidateResponse(payjoin::send::ValidationError),
#[error("Payjoin configuration failed.")]
PayjoinConfigError,
#[error(transparent)]
Other(#[from] anyhow::Error),
}
#[derive(Error, Debug)]
pub enum MutinyStorageError {
#[error("Failed to serialize or deserialize")]
SerdeError {
#[from]
source: serde_json::Error,
},
#[error("Failed to get lock on memory storage")]
LockError,
#[error("Failed to use indexeddb storage")]
IndexedDBError,
#[error(transparent)]
Other(#[from] anyhow::Error),
}
impl PartialEq for MutinyStorageError {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::SerdeError { .. }, Self::SerdeError { .. }) => true,
(Self::LockError, Self::LockError) => true,
(Self::IndexedDBError, Self::IndexedDBError) => true,
(Self::Other(e), Self::Other(e2)) => e.to_string() == e2.to_string(),
_ => false,
}
}
}
impl PartialEq for MutinyError {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::AlreadyRunning, Self::AlreadyRunning) => true,
(Self::NotRunning, Self::NotRunning) => true,
(Self::NetworkMismatch, Self::NetworkMismatch) => true,
(Self::NotFound, Self::NotFound) => true,
(Self::FundingTxCreationFailed, Self::FundingTxCreationFailed) => true,
(Self::ConnectionFailed, Self::ConnectionFailed) => true,
(Self::IncorrectNetwork(net), Self::IncorrectNetwork(net2)) => net == net2,
(Self::NonUniquePaymentHash, Self::NonUniquePaymentHash) => true,
(Self::PaymentTimeout, Self::PaymentTimeout) => true,
(Self::InvoiceInvalid, Self::InvoiceInvalid) => true,
(Self::InvoiceCreationFailed, Self::InvoiceCreationFailed) => true,
(Self::ReserveAmountError, Self::ReserveAmountError) => true,
(Self::InsufficientBalance, Self::InsufficientBalance) => true,
(Self::LnUrlFailure, Self::LnUrlFailure) => true,
(Self::LspGenericError, Self::LspGenericError) => true,
(Self::LspFundingError, Self::LspFundingError) => true,
(Self::LspAmountTooHighError, Self::LspAmountTooHighError) => true,
(Self::LspConnectionError, Self::LspConnectionError) => true,
(Self::SubscriptionClientNotConfigured, Self::SubscriptionClientNotConfigured) => true,
(Self::InvalidArgumentsError, Self::InvalidArgumentsError) => true,
(Self::RoutingFailed, Self::RoutingFailed) => true,
(Self::PeerInfoParseFailed, Self::PeerInfoParseFailed) => true,
(Self::ChannelCreationFailed, Self::ChannelCreationFailed) => true,
(Self::ChannelClosingFailed, Self::ChannelClosingFailed) => true,
(Self::PersistenceFailed { source }, Self::PersistenceFailed { source: source2 }) => {
source == source2
}
(Self::ReadError { source }, Self::ReadError { source: source2 }) => source == source2,
(Self::LnDecodeError, Self::LnDecodeError) => true,
(Self::SeedGenerationFailed, Self::SeedGenerationFailed) => true,
(Self::InvalidMnemonic, Self::InvalidMnemonic) => true,
(Self::WalletOperationFailed, Self::WalletOperationFailed) => true,
(Self::WalletSigningFailed, Self::WalletSigningFailed) => true,
(Self::ChainAccessFailed, Self::ChainAccessFailed) => true,
(Self::WalletSyncError, Self::WalletSyncError) => true,
(Self::RapidGossipSyncError, Self::RapidGossipSyncError) => true,
(Self::PubkeyInvalid, Self::PubkeyInvalid) => true,
(Self::IncorrectLnUrlFunction, Self::IncorrectLnUrlFunction) => true,
(Self::BadAmountError, Self::BadAmountError) => true,
(Self::BitcoinPriceError, Self::BitcoinPriceError) => true,
(Self::DLCManagerError, Self::DLCManagerError) => true,
(Self::NostrError, Self::NostrError) => true,
(Self::IncorrectPassword, Self::IncorrectPassword) => true,
(Self::SamePassword, Self::SamePassword) => true,
(Self::Other(e), Self::Other(e2)) => e.to_string() == e2.to_string(),
_ => false,
}
}
}
impl MutinyError {
pub fn read_err(e: MutinyStorageError) -> Self {
MutinyError::ReadError { source: e }
}
pub fn write_err(e: MutinyStorageError) -> Self {
MutinyError::PersistenceFailed { source: e }
}
}
impl From<UnpadError> for MutinyError {
fn from(_e: UnpadError) -> Self {
Self::IncorrectPassword
}
}
impl From<base64::DecodeError> for MutinyError {
fn from(_e: base64::DecodeError) -> Self {
Self::IncorrectPassword
}
}
impl From<FromUtf8Error> for MutinyError {
fn from(_e: FromUtf8Error) -> Self {
Self::IncorrectPassword
}
}
impl From<aes_gcm::Error> for MutinyError {
fn from(_: aes_gcm::Error) -> Self {
Self::IncorrectPassword
}
}
impl From<aes_gcm::aes::cipher::InvalidLength> for MutinyError {
fn from(_: aes_gcm::aes::cipher::InvalidLength) -> Self {
Self::IncorrectPassword
}
}
impl From<bdk::Error> for MutinyError {
fn from(e: bdk::Error) -> Self {
match e {
bdk::Error::Signer(_) => Self::WalletSigningFailed,
bdk::Error::InsufficientFunds { .. } => Self::InsufficientBalance,
_ => Self::WalletOperationFailed,
}
}
}
impl From<bdk::descriptor::error::Error> for MutinyError {
fn from(_: bdk::descriptor::error::Error) -> Self {
Self::WalletOperationFailed
}
}
impl From<bdk::wallet::NewError<MutinyError>> for MutinyError {
fn from(e: bdk::wallet::NewError<MutinyError>) -> Self {
match e {
bdk::wallet::NewError::Persist(e) => e,
bdk::wallet::NewError::Descriptor(e) => e.into(),
}
}
}
impl From<bip39::Error> for MutinyError {
fn from(_e: bip39::Error) -> Self {
Self::InvalidMnemonic
}
}
impl From<bitcoin::util::bip32::Error> for MutinyError {
fn from(_e: bitcoin::util::bip32::Error) -> Self {
Self::InvalidMnemonic
}
}
impl From<url::ParseError> for MutinyError {
fn from(_e: url::ParseError) -> Self {
Self::LnUrlFailure
}
}
impl From<lnurl::Error> for MutinyError {
fn from(_e: lnurl::Error) -> Self {
Self::LnUrlFailure
}
}
impl From<TxSyncError> for MutinyError {
fn from(_e: TxSyncError) -> Self {
MutinyError::ChainAccessFailed
}
}
impl From<lightning::ln::msgs::DecodeError> for MutinyError {
fn from(_e: lightning::ln::msgs::DecodeError) -> Self {
MutinyError::LnDecodeError
}
}
impl From<lightning::ln::script::InvalidShutdownScript> for MutinyError {
fn from(_e: lightning::ln::script::InvalidShutdownScript) -> Self {
MutinyError::InvalidArgumentsError
}
}
impl From<ParseOrSemanticError> for MutinyError {
fn from(_e: ParseOrSemanticError) -> Self {
Self::InvoiceInvalid
}
}
impl From<PeerHandleError> for MutinyError {
fn from(_e: PeerHandleError) -> Self {
Self::ConnectionFailed
}
}
impl From<PaymentError> for MutinyError {
fn from(e: PaymentError) -> Self {
match e {
PaymentError::Invoice(_) => Self::InvoiceInvalid,
PaymentError::Sending(_) => Self::RoutingFailed,
}
}
}
impl From<GraphSyncError> for MutinyError {
fn from(_e: GraphSyncError) -> Self {
MutinyError::RapidGossipSyncError
}
}
impl From<std::io::Error> for MutinyError {
fn from(e: std::io::Error) -> Self {
MutinyError::PersistenceFailed {
source: MutinyStorageError::Other(e.into()),
}
}
}
impl From<serde_json::Error> for MutinyError {
fn from(_: serde_json::Error) -> Self {
Self::ReadError {
source: MutinyStorageError::Other(anyhow::anyhow!("Failed to deserialize")),
}
}
}
impl<G> From<std::sync::PoisonError<G>> for MutinyStorageError {
fn from(_e: std::sync::PoisonError<G>) -> Self {
MutinyStorageError::LockError
}
}
impl<G> From<std::sync::TryLockError<G>> for MutinyError {
fn from(_e: std::sync::TryLockError<G>) -> Self {
MutinyStorageError::LockError.into()
}
}
impl<G> From<std::sync::TryLockError<G>> for MutinyStorageError {
fn from(_e: std::sync::TryLockError<G>) -> Self {
MutinyStorageError::LockError
}
}
impl From<bitcoin::hashes::hex::Error> for MutinyError {
fn from(_e: bitcoin::hashes::hex::Error) -> Self {
MutinyError::ReadError {
source: MutinyStorageError::Other(anyhow::anyhow!("Failed to decode hex")),
}
}
}
impl From<bitcoin::util::address::Error> for MutinyError {
fn from(_e: bitcoin::util::address::Error) -> Self {
MutinyError::ReadError {
source: MutinyStorageError::Other(anyhow::anyhow!("Failed to decode address")),
}
}
}
impl From<esplora_client::Error> for MutinyError {
fn from(_e: esplora_client::Error) -> Self {
Self::ChainAccessFailed
}
}
impl From<bdk_chain::local_chain::InsertBlockNotMatchingError> for MutinyError {
fn from(_e: bdk_chain::local_chain::InsertBlockNotMatchingError) -> Self {
Self::WalletSyncError
}
}
impl From<bdk::wallet::InsertTxError> for MutinyError {
fn from(_e: bdk::wallet::InsertTxError) -> Self {
Self::WalletSyncError
}
}
impl From<nostr_sdk::client::Error> for MutinyError {
fn from(_e: nostr_sdk::client::Error) -> Self {
Self::NostrError
}
}
impl From<nostr::nips::nip04::Error> for MutinyError {
fn from(_e: nostr::nips::nip04::Error) -> Self {
Self::NostrError
}
}
impl From<nostr::event::builder::Error> for MutinyError {
fn from(_e: nostr::event::builder::Error) -> Self {
Self::NostrError
}
}
impl From<payjoin::send::CreateRequestError> for MutinyError {
fn from(_e: payjoin::send::CreateRequestError) -> Self {
Self::PayjoinCreateRequest
}
}
impl From<payjoin::send::ValidationError> for MutinyError {
fn from(e: payjoin::send::ValidationError) -> Self {
Self::PayjoinValidateResponse(e)
}
}