use ledger_sdk_device_base::LedgerAppError;
use thiserror::Error;
#[derive(Debug, Error, Clone, PartialEq)]
pub enum EthAppError<E: std::error::Error> {
#[error("Transport error: {0}")]
Transport(#[from] LedgerAppError<E>),
#[error("Invalid BIP32 path: {0}")]
InvalidBip32Path(String),
#[error("Invalid Ethereum address: {0}")]
InvalidAddress(String),
#[error("Invalid signature: {0}")]
InvalidSignature(String),
#[error("Transaction data too large: {size} bytes (max {max})")]
TransactionTooLarge { size: usize, max: usize },
#[error("Message data too large: {size} bytes (max {max})")]
MessageTooLarge { size: usize, max: usize },
#[error("Invalid transaction format: {0}")]
InvalidTransaction(String),
#[error("Invalid message format: {0}")]
InvalidMessage(String),
#[error("Hex error: {0}")]
HexError(String),
#[error("Invalid chain ID: {0}")]
InvalidChainId(u64),
#[error("Operation rejected by device")]
UserRejected,
#[error("App configuration error: {0}")]
ConfigurationError(String),
#[error("Feature not supported: {0}")]
FeatureNotSupported(String),
#[error("Chunk error: {0}")]
ChunkError(String),
#[error("Invalid response data: {0}")]
InvalidResponseData(String),
#[error("Invalid EIP-712 data: {0}")]
InvalidEip712Data(String),
#[error("EIP-712 struct error: {0}")]
Eip712StructError(String),
#[error("EIP-712 filter error: {0}")]
Eip712FilterError(String),
#[error("Unsupported version: {0}")]
UnsupportedVersion(String),
#[error("Device status 0x{sw:04X}: {description}")]
DeviceStatus { sw: u16, description: String },
}
impl<E: std::error::Error> EthAppError<E> {
pub fn is_user_rejected(&self) -> bool {
matches!(self, EthAppError::UserRejected)
}
pub fn is_transport_error(&self) -> bool {
matches!(self, EthAppError::Transport(_))
}
pub fn is_invalid_input(&self) -> bool {
matches!(
self,
EthAppError::InvalidBip32Path(_)
| EthAppError::InvalidAddress(_)
| EthAppError::InvalidSignature(_)
| EthAppError::InvalidTransaction(_)
| EthAppError::InvalidMessage(_)
| EthAppError::InvalidChainId(_)
)
}
}
pub type EthAppResult<T, E> = Result<T, EthAppError<E>>;
pub fn map_ledger_error<E: std::error::Error>(err: LedgerAppError<E>) -> EthAppError<E> {
match err {
LedgerAppError::AppSpecific(0x6982, _) => EthAppError::UserRejected,
LedgerAppError::Unknown(0x6982) => EthAppError::UserRejected,
LedgerAppError::AppSpecific(sw, _) | LedgerAppError::Unknown(sw) => {
EthAppError::DeviceStatus {
sw,
description: describe_eth_status(sw).to_string(),
}
}
other => EthAppError::Transport(other),
}
}
fn describe_eth_status(sw: u16) -> &'static str {
match sw {
0x6001 => "Mode check fail",
0x6501 => "TransactionType not supported",
0x6502 => "Output buffer too small for chainId conversion",
0x6982 => "Security status not satisfied (Canceled by user)",
0x6983 => "Wrong Data length",
0x6984 => "Plugin not installed",
0x6985 => "Condition not satisfied",
0x6A00 => "Error without info",
0x6A80 => "Invalid data",
0x6A84 => "Insufficient memory",
0x6A88 => "Data not found",
0x6B00 => "Incorrect parameter P1 or P2",
0x6D00 => "Incorrect parameter INS",
0x6E00 => "Incorrect parameter CLA",
0x9000 => "Normal ending of the command",
0x911C => "Command code not supported (Ledger-PKI not yet available)",
_ if (sw & 0xFF00) == 0x6800 => "Internal error (Please report)",
_ if (sw & 0xFF00) == 0x6F00 => "Technical problem (Internal error, please report)",
_ => "Unknown status",
}
}