Skip to main content

clear_signing/
error.rs

1//! Error types for decoding, resolution, and rendering failures.
2
3use thiserror::Error;
4
5#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
6#[derive(Debug, Clone, PartialEq, Eq, Error, serde::Serialize)]
7pub enum FormatFailure {
8    #[error("invalid input: {message}")]
9    InvalidInput { message: String, retryable: bool },
10
11    #[error("invalid descriptor: {message}")]
12    InvalidDescriptor { message: String, retryable: bool },
13
14    #[error("resolution failed: {message}")]
15    ResolutionFailed { message: String, retryable: bool },
16
17    #[error("internal error: {message}")]
18    Internal { message: String, retryable: bool },
19}
20
21/// Unified error type for the ERC-7730 library.
22#[derive(Debug, Error)]
23pub enum Error {
24    #[error("decode error: {0}")]
25    Decode(#[from] DecodeError),
26
27    #[error("descriptor error: {0}")]
28    Descriptor(String),
29
30    #[error("resolve error: {0}")]
31    Resolve(#[from] ResolveError),
32
33    #[error("token registry error: {0}")]
34    TokenRegistry(String),
35
36    #[error("render error: {0}")]
37    Render(String),
38}
39
40/// Errors during signature parsing and calldata decoding.
41#[derive(Debug, Error)]
42pub enum DecodeError {
43    #[error("invalid function signature: {0}")]
44    InvalidSignature(String),
45
46    #[error("calldata too short: expected at least {expected} bytes, got {actual}")]
47    CalldataTooShort { expected: usize, actual: usize },
48
49    #[error("selector mismatch: expected {expected}, got {actual}")]
50    SelectorMismatch { expected: String, actual: String },
51
52    #[error("invalid ABI encoding: {0}")]
53    InvalidEncoding(String),
54
55    #[error("unsupported type: {0}")]
56    UnsupportedType(String),
57}
58
59/// Errors during descriptor resolution.
60#[derive(Debug, Error)]
61pub enum ResolveError {
62    #[error("descriptor not found for chain_id={chain_id}, address={address}")]
63    NotFound { chain_id: u64, address: String },
64
65    #[error("registry index missing: {url}")]
66    RegistryIndexMissing { url: String },
67
68    #[error("registry descriptor missing: {url}")]
69    RegistryDescriptorMissing { url: String },
70
71    #[error("registry io error: {0}")]
72    RegistryIo(String),
73
74    #[error("parse error: {0}")]
75    Parse(String),
76}
77
78impl From<Error> for FormatFailure {
79    fn from(value: Error) -> Self {
80        match value {
81            Error::Decode(err) => Self::InvalidInput {
82                message: err.to_string(),
83                retryable: false,
84            },
85            Error::Descriptor(message) => Self::InvalidDescriptor {
86                message,
87                retryable: false,
88            },
89            Error::Resolve(err) => err.into(),
90            Error::TokenRegistry(message) => Self::ResolutionFailed {
91                message: format!("token registry error: {message}"),
92                retryable: true,
93            },
94            Error::Render(message) => Self::InvalidDescriptor {
95                message,
96                retryable: false,
97            },
98        }
99    }
100}
101
102impl From<ResolveError> for FormatFailure {
103    fn from(value: ResolveError) -> Self {
104        match value {
105            ResolveError::NotFound { chain_id, address } => Self::InvalidDescriptor {
106                message: format!("descriptor not found for chain_id={chain_id}, address={address}"),
107                retryable: false,
108            },
109            ResolveError::RegistryIndexMissing { url } => Self::ResolutionFailed {
110                message: format!("registry index missing: {url}"),
111                retryable: true,
112            },
113            ResolveError::RegistryDescriptorMissing { url } => Self::ResolutionFailed {
114                message: format!("registry descriptor missing: {url}"),
115                retryable: true,
116            },
117            ResolveError::RegistryIo(message) => Self::ResolutionFailed {
118                message: format!("registry io error: {message}"),
119                retryable: true,
120            },
121            ResolveError::Parse(message) => Self::ResolutionFailed {
122                message: format!("parse error: {message}"),
123                retryable: false,
124            },
125        }
126    }
127}