openzeppelin_relayer/models/error/
relayer.rs

1use crate::{
2    models::{SignerError, SignerFactoryError},
3    repositories::TransactionCounterError,
4    services::provider::{ProviderError, SolanaProviderError},
5};
6
7use super::{ApiError, RepositoryError};
8use crate::models::NetworkError;
9use serde::Serialize;
10use thiserror::Error;
11
12#[derive(Error, Debug, Serialize)]
13pub enum RelayerError {
14    #[error("Network configuration error: {0}")]
15    NetworkConfiguration(String),
16    #[error("Provider error: {0}")]
17    ProviderError(String),
18    #[error("Underlying provider error: {0}")]
19    UnderlyingProvider(#[from] ProviderError),
20    #[error("Underlying Solana provider error: {0}")]
21    UnderlyingSolanaProvider(#[from] SolanaProviderError),
22    #[error("Queue error: {0}")]
23    QueueError(String),
24    #[error("Signer factory error: {0}")]
25    SignerFactoryError(#[from] SignerFactoryError),
26    #[error("Signer error: {0}")]
27    SignerError(#[from] SignerError),
28    #[error("Not supported: {0}")]
29    NotSupported(String),
30    #[error("Relayer is disabled")]
31    RelayerDisabled,
32    #[error("Relayer is paused")]
33    RelayerPaused,
34    #[error("Transaction sequence error: {0}")]
35    TransactionSequenceError(#[from] TransactionCounterError),
36    #[error("Insufficient balance error: {0}")]
37    InsufficientBalanceError(String),
38    #[error("Insufficient relayer balance: {0}")]
39    InsufficientRelayerBalance(String),
40    #[error("Relayer Policy configuration error: {0}")]
41    PolicyConfigurationError(String),
42    #[error("Invalid Dex name : {0}")]
43    InvalidDexName(String),
44    #[error("Dex error : {0}")]
45    DexError(String),
46    #[error("Transaction validation error: {0}")]
47    ValidationError(String),
48    #[error("Internal error: {0}")]
49    Internal(String),
50}
51
52impl From<RelayerError> for ApiError {
53    fn from(error: RelayerError) -> Self {
54        match error {
55            RelayerError::NetworkConfiguration(msg) => ApiError::InternalError(msg),
56            RelayerError::ProviderError(msg) => ApiError::InternalError(msg),
57            RelayerError::QueueError(msg) => ApiError::InternalError(msg),
58            RelayerError::SignerError(err) => ApiError::InternalError(err.to_string()),
59            RelayerError::SignerFactoryError(err) => ApiError::InternalError(err.to_string()),
60            RelayerError::NotSupported(msg) => ApiError::BadRequest(msg),
61            RelayerError::RelayerDisabled => {
62                ApiError::ForbiddenError("Relayer disabled".to_string())
63            }
64            RelayerError::RelayerPaused => ApiError::ForbiddenError("Relayer paused".to_string()),
65            RelayerError::TransactionSequenceError(err) => ApiError::InternalError(err.to_string()),
66            RelayerError::InsufficientBalanceError(msg) => ApiError::BadRequest(msg),
67            RelayerError::InsufficientRelayerBalance(msg) => ApiError::BadRequest(msg),
68            RelayerError::UnderlyingProvider(err) => ApiError::InternalError(err.to_string()),
69            RelayerError::UnderlyingSolanaProvider(err) => ApiError::InternalError(err.to_string()),
70            RelayerError::PolicyConfigurationError(msg) => ApiError::InternalError(msg),
71            RelayerError::InvalidDexName(msg) => ApiError::InternalError(msg),
72            RelayerError::DexError(msg) => ApiError::InternalError(msg),
73            RelayerError::ValidationError(msg) => ApiError::BadRequest(msg),
74            RelayerError::Internal(msg) => ApiError::InternalError(msg),
75        }
76    }
77}
78
79impl From<RepositoryError> for RelayerError {
80    fn from(error: RepositoryError) -> Self {
81        RelayerError::NetworkConfiguration(error.to_string())
82    }
83}
84
85impl From<NetworkError> for RelayerError {
86    fn from(err: NetworkError) -> Self {
87        RelayerError::NetworkConfiguration(err.to_string())
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94    use crate::models::SignerError;
95    use crate::repositories::TransactionCounterError;
96    use crate::services::provider::{ProviderError, SolanaProviderError};
97
98    #[test]
99    fn test_relayer_error_variants() {
100        let network_error = RelayerError::NetworkConfiguration("Invalid network".to_string());
101        assert_eq!(
102            network_error.to_string(),
103            "Network configuration error: Invalid network"
104        );
105
106        let provider_error = RelayerError::ProviderError("Connection failed".to_string());
107        assert_eq!(
108            provider_error.to_string(),
109            "Provider error: Connection failed"
110        );
111
112        let queue_error = RelayerError::QueueError("Queue full".to_string());
113        assert_eq!(queue_error.to_string(), "Queue error: Queue full");
114
115        let not_supported = RelayerError::NotSupported("Feature unavailable".to_string());
116        assert_eq!(
117            not_supported.to_string(),
118            "Not supported: Feature unavailable"
119        );
120
121        let disabled = RelayerError::RelayerDisabled;
122        assert_eq!(disabled.to_string(), "Relayer is disabled");
123
124        let paused = RelayerError::RelayerPaused;
125        assert_eq!(paused.to_string(), "Relayer is paused");
126
127        let insufficient_balance =
128            RelayerError::InsufficientBalanceError("Not enough ETH".to_string());
129        assert_eq!(
130            insufficient_balance.to_string(),
131            "Insufficient balance error: Not enough ETH"
132        );
133
134        let policy_error = RelayerError::PolicyConfigurationError("Invalid policy".to_string());
135        assert_eq!(
136            policy_error.to_string(),
137            "Relayer Policy configuration error: Invalid policy"
138        );
139    }
140
141    #[test]
142    fn test_from_provider_error() {
143        let provider_error = ProviderError::NetworkConfiguration("RPC timeout".to_string());
144        let relayer_error: RelayerError = provider_error.into();
145
146        assert!(matches!(relayer_error, RelayerError::UnderlyingProvider(_)));
147        assert!(relayer_error.to_string().contains("RPC timeout"));
148    }
149
150    #[test]
151    fn test_from_solana_provider_error() {
152        let solana_error = SolanaProviderError::RpcError("Solana RPC down".to_string());
153        let relayer_error: RelayerError = solana_error.into();
154
155        assert!(matches!(
156            relayer_error,
157            RelayerError::UnderlyingSolanaProvider(_)
158        ));
159        assert!(relayer_error.to_string().contains("Solana RPC down"));
160    }
161
162    #[test]
163    fn test_from_signer_factory_error() {
164        let factory_error = SignerFactoryError::InvalidConfig("Unknown chain".to_string());
165        let relayer_error: RelayerError = factory_error.into();
166
167        assert!(matches!(relayer_error, RelayerError::SignerFactoryError(_)));
168        assert!(relayer_error.to_string().contains("Unknown chain"));
169    }
170
171    #[test]
172    fn test_from_signer_error() {
173        let signer_error = SignerError::SigningError("Invalid key".to_string());
174        let relayer_error: RelayerError = signer_error.into();
175
176        assert!(matches!(relayer_error, RelayerError::SignerError(_)));
177        assert!(relayer_error.to_string().contains("Invalid key"));
178    }
179
180    #[test]
181    fn test_from_transaction_counter_error() {
182        let counter_error = TransactionCounterError::NotFound("Nonce not found".to_string());
183        let relayer_error: RelayerError = counter_error.into();
184
185        assert!(matches!(
186            relayer_error,
187            RelayerError::TransactionSequenceError(_)
188        ));
189        assert!(relayer_error.to_string().contains("Nonce not found"));
190    }
191
192    #[test]
193    fn test_conversion_to_api_error() {
194        let network_error = RelayerError::NetworkConfiguration("Invalid network".to_string());
195        let api_error: ApiError = network_error.into();
196        assert!(matches!(api_error, ApiError::InternalError(_)));
197
198        let not_supported = RelayerError::NotSupported("Feature unavailable".to_string());
199        let api_error: ApiError = not_supported.into();
200        assert!(matches!(api_error, ApiError::BadRequest(_)));
201
202        let disabled = RelayerError::RelayerDisabled;
203        let api_error: ApiError = disabled.into();
204        assert!(matches!(api_error, ApiError::ForbiddenError(_)));
205        assert_eq!(api_error.to_string(), "Forbidden: Relayer disabled");
206
207        let insufficient = RelayerError::InsufficientBalanceError("Not enough funds".to_string());
208        let api_error: ApiError = insufficient.into();
209        assert!(matches!(api_error, ApiError::BadRequest(_)));
210    }
211
212    #[test]
213    fn test_from_repository_error() {
214        let repo_error = RepositoryError::ConnectionError("Connection failed".to_string());
215        let relayer_error: RelayerError = repo_error.into();
216
217        assert!(matches!(
218            relayer_error,
219            RelayerError::NetworkConfiguration(_)
220        ));
221        assert!(relayer_error.to_string().contains("Connection failed"));
222    }
223}