Skip to main content

walletkit_core/
error.rs

1use thiserror::Error;
2#[cfg(feature = "v4")]
3use world_id_core::primitives::PrimitiveError;
4
5#[cfg(feature = "storage")]
6use crate::storage::StorageError;
7#[cfg(feature = "v4")]
8use world_id_core::AuthenticatorError;
9
10/// Error outputs from `WalletKit`
11#[derive(Debug, Error, uniffi::Error)]
12pub enum WalletKitError {
13    /// Invalid input provided (e.g., incorrect length, format, etc.)
14    #[error("invalid_input_{attribute}")]
15    InvalidInput {
16        /// The attribute that is invalid
17        attribute: String,
18        /// The reason the input is invalid
19        reason: String,
20    },
21
22    /// The presented data is not a valid U256 integer
23    #[error("invalid_number")]
24    InvalidNumber,
25
26    /// Unexpected error serializing information
27    #[error("serialization_error")]
28    SerializationError {
29        /// The error message from the serialization
30        error: String,
31    },
32
33    /// Network connection error with details
34    #[error("network_error at {url}: {error}")]
35    NetworkError {
36        /// The URL of the request
37        url: String,
38        /// The error message from the request
39        error: String,
40        /// The HTTP status code of the request, if available
41        status: Option<u16>,
42    },
43
44    /// HTTP request failure
45    #[error("request_error")]
46    Reqwest {
47        /// The error message from the request
48        error: String,
49    },
50
51    /// Unhandled error generating a Zero-Knowledge Proof
52    #[error("proof_generation_error")]
53    ProofGeneration {
54        /// The error message from the proof generation
55        error: String,
56    },
57
58    /// The `semaphore` feature flag is not enabled
59    #[error("semaphore_not_enabled")]
60    SemaphoreNotEnabled,
61
62    /// The requested credential is not issued for this World ID
63    #[error("credential_not_issued")]
64    CredentialNotIssued,
65
66    /// The requested credential has not been submitted on-chain
67    #[error("credential_not_mined")]
68    CredentialNotMined,
69
70    /// This operation requires a registered account and an account is not registered
71    /// for this authenticator. Call `create_account` first to register it.
72    #[error("Account is not registered for this authenticator.")]
73    AccountDoesNotExist,
74
75    /// The account already exists for this authenticator. Call `account_index` to get the account index.
76    #[error("Account already exists for this authenticator.")]
77    AccountAlreadyExists,
78
79    /// The public key was not found in the batch, i.e. the authenticator is not authorized to sign for this action
80    #[error("unauthorized_authenticator")]
81    UnauthorizedAuthenticator,
82
83    /// An unexpected error occurred with the Authenticator
84    #[error("unexpected_authenticator_error")]
85    AuthenticatorError {
86        /// The error message from the authenticator
87        error: String,
88    },
89
90    /// An unexpected error occurred
91    #[error("unexpected_error: {error}")]
92    Generic {
93        /// The details of the error
94        error: String,
95    },
96}
97
98impl From<reqwest::Error> for WalletKitError {
99    fn from(error: reqwest::Error) -> Self {
100        Self::Reqwest {
101            error: error.to_string(),
102        }
103    }
104}
105
106#[cfg(feature = "v4")]
107impl From<PrimitiveError> for WalletKitError {
108    fn from(error: PrimitiveError) -> Self {
109        match error {
110            PrimitiveError::InvalidInput { attribute, reason } => {
111                Self::InvalidInput { attribute, reason }
112            }
113            PrimitiveError::Serialization(error) => Self::SerializationError { error },
114            PrimitiveError::Deserialization(reason) => Self::InvalidInput {
115                attribute: "deserialization".to_string(),
116                reason,
117            },
118            PrimitiveError::NotInField => Self::InvalidInput {
119                attribute: "field_element".to_string(),
120                reason: "Provided value is not in the field".to_string(),
121            },
122            PrimitiveError::OutOfBounds => Self::InvalidInput {
123                attribute: "index".to_string(),
124                reason: "Provided index is out of bounds".to_string(),
125            },
126        }
127    }
128}
129
130impl From<semaphore_rs::protocol::ProofError> for WalletKitError {
131    fn from(error: semaphore_rs::protocol::ProofError) -> Self {
132        Self::ProofGeneration {
133            error: error.to_string(),
134        }
135    }
136}
137
138#[cfg(feature = "storage")]
139impl From<StorageError> for WalletKitError {
140    fn from(error: StorageError) -> Self {
141        Self::Generic {
142            error: error.to_string(),
143        }
144    }
145}
146
147#[cfg(feature = "v4")]
148impl From<AuthenticatorError> for WalletKitError {
149    fn from(error: AuthenticatorError) -> Self {
150        match error {
151            AuthenticatorError::AccountDoesNotExist => Self::AccountDoesNotExist,
152            AuthenticatorError::AccountAlreadyExists => Self::AccountAlreadyExists,
153
154            AuthenticatorError::NetworkError(error) => Self::NetworkError {
155                url: error
156                    .url()
157                    .map(std::string::ToString::to_string)
158                    .unwrap_or_default(),
159                error: error.to_string(),
160                status: None,
161            },
162            AuthenticatorError::PublicKeyNotFound => Self::UnauthorizedAuthenticator,
163            AuthenticatorError::GatewayError { status, body } => Self::NetworkError {
164                url: "gateway".to_string(),
165                error: body,
166                status: Some(status.as_u16()),
167            },
168            AuthenticatorError::PrimitiveError(error) => Self::from(error),
169
170            _ => Self::AuthenticatorError {
171                error: error.to_string(),
172            },
173        }
174    }
175}