Skip to main content

walletkit_core/
error.rs

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