nym_credential_proxy_lib/
error.rs

1// Copyright 2025 Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: GPL-3.0-only
3
4use nym_crypto::asymmetric::ed25519;
5use nym_ecash_signer_check::SignerCheckError;
6use nym_validator_client::coconut::EcashApiError;
7use nym_validator_client::nym_api::{EpochId, error::NymAPIError};
8use nym_validator_client::nyxd::error::NyxdError;
9use std::io;
10use std::net::SocketAddr;
11use thiserror::Error;
12use time::OffsetDateTime;
13
14#[derive(Debug, Error)]
15pub enum CredentialProxyError {
16    #[error("encountered an internal io error: {source}")]
17    IoError {
18        #[from]
19        source: io::Error,
20    },
21
22    #[error("could not derive valid client url with the provided webhook parameters")]
23    InvalidWebhookUrl,
24
25    #[error("failed to serialise recovery data: {source}")]
26    SerdeJsonFailure {
27        #[from]
28        source: serde_json::Error,
29    },
30
31    #[error("the provided expiration date is too late")]
32    ExpirationDateTooLate,
33
34    #[error("the provided expiration date is too early")]
35    ExpirationDateTooEarly,
36
37    #[error(
38        "failed to bind to {address}: {source}. Are you sure nothing else is running on the specified port and your user has sufficient permission to bind to the requested address?"
39    )]
40    SocketBindFailure {
41        address: SocketAddr,
42        source: io::Error,
43    },
44
45    #[error("the api server failed with the following message: {source}")]
46    HttpServerFailure { source: io::Error },
47
48    #[error("the ecash contract address is not set")]
49    UnavailableEcashContract,
50
51    #[error("the DKG contract address is not set")]
52    UnavailableDKGContract,
53
54    #[error("the bandwidth contract doesn't have any admin set")]
55    MissingBandwidthContractAdmin,
56
57    #[error(
58        "the provided mnemonic does not correspond to the current admin of the bandwidth contract"
59    )]
60    MismatchedMnemonic,
61
62    #[error("failed to interact with the nyx chain: {source}")]
63    NyxdFailure {
64        #[from]
65        source: NyxdError,
66    },
67
68    #[error("validator client error: {0}")]
69    ValidatorClientError(#[from] nym_validator_client::ValidatorClientError),
70
71    #[error("failed to perform ecash operation: {source}")]
72    EcashApiFailure {
73        #[from]
74        source: EcashApiError,
75    },
76
77    #[error("Nym API request failed: {source}")]
78    NymApiFailure { source: Box<NymAPIError> },
79
80    #[error("Compact ecash internal error: {0}")]
81    CompactEcashInternalError(#[from] nym_compact_ecash::error::CompactEcashError),
82
83    #[error("there are no rpc endpoints provided in the environment")]
84    NoNyxEndpointsAvailable,
85
86    #[error("the threshold value for epoch {epoch_id} is not available")]
87    UnavailableThreshold { epoch_id: EpochId },
88
89    #[error(
90        "we have only {available} api clients available while the minimum threshold is {threshold}"
91    )]
92    InsufficientNumberOfSigners { available: usize, threshold: u64 },
93
94    #[error(
95        "we have only managed to obtain {available} partial credentials while the minimum threshold is {threshold}"
96    )]
97    InsufficientNumberOfCredentials { available: usize, threshold: u64 },
98
99    #[error("failed to interact with the credentials: {source}")]
100    CredentialsFailure {
101        #[from]
102        source: nym_credentials::Error,
103    },
104
105    #[error("the DKG has not yet been initialised in the system")]
106    UninitialisedDkg,
107
108    #[error(
109        "credentials can't yet be issued in the system. approximate expected availability: {availability}"
110    )]
111    CredentialsNotYetIssuable { availability: OffsetDateTime },
112
113    #[error("reached seemingly impossible ecash failure")]
114    UnknownEcashFailure,
115
116    #[error("experienced internal database error: {0}")]
117    InternalDatabaseError(#[from] sqlx::Error),
118
119    #[error("experienced internal storage error: {reason}")]
120    DatabaseInconsistency { reason: String },
121
122    #[error("failed to perform startup SQL migration: {0}")]
123    StartupMigrationFailure(#[from] sqlx::migrate::MigrateError),
124
125    #[error("timed out while attempting to obtain partial wallet from {client_repr}")]
126    EcashApiRequestTimeout { client_repr: String },
127
128    #[error("failed to create deposit")]
129    DepositFailure,
130
131    #[error("failed to load jwt signing key from {path}: {err}")]
132    JWTSigningKeyLoadFailure {
133        path: String,
134        #[source]
135        err: std::io::Error,
136    },
137
138    #[error("can't obtain sufficient number of credential shares due to unavailable quorum")]
139    UnavailableSigningQuorum,
140
141    #[error("failed to perform quorum check: {source}")]
142    QuorumCheckFailure {
143        #[from]
144        source: SignerCheckError,
145    },
146
147    #[error(
148        "this operation couldn't be completed as the program is in the process of shutting down"
149    )]
150    ShutdownInProgress,
151
152    #[error("failed to obtain wallet shares with id {id}: {message}")]
153    ShareByIdLoadError { message: String, id: i64 },
154
155    #[error(
156        "failed to obtain wallet shares with device_id {device_id} and credential_id: {credential_id}: {message}"
157    )]
158    ShareByDeviceLoadError {
159        message: String,
160        device_id: String,
161        credential_id: String,
162    },
163
164    #[error("could not find shares with id {id}")]
165    SharesByIdNotFound { id: i64 },
166
167    #[error("could not find shares with device_id {device_id} and credential_id: {credential_id}")]
168    SharesByDeviceNotFound {
169        device_id: String,
170        credential_id: String,
171    },
172
173    #[error(
174        "the attestation check url has not been provided through either the CLI nor the default .env config"
175    )]
176    AttestationCheckUrlNotSet,
177
178    #[error("the provided attester public key is malformed: {source}")]
179    MalformedAttestationCheckUrl { source: url::ParseError },
180
181    #[error(
182        "the attester public key has not been provided through either the CLI nor the default .env config"
183    )]
184    AttesterPublicKeyNotSet,
185
186    #[error("the provided attester public key is malformed: {source}")]
187    MalformedAttesterPublicKey {
188        source: ed25519::Ed25519RecoveryError,
189    },
190}
191
192impl From<NymAPIError> for CredentialProxyError {
193    fn from(source: NymAPIError) -> Self {
194        CredentialProxyError::NymApiFailure {
195            source: Box::new(source),
196        }
197    }
198}
199
200impl CredentialProxyError {
201    pub fn database_inconsistency<S: Into<String>>(reason: S) -> CredentialProxyError {
202        CredentialProxyError::DatabaseInconsistency {
203            reason: reason.into(),
204        }
205    }
206}