riglr_core/signer/
error.rs

1//! Error types for signer operations
2//!
3//! This module defines all error conditions that can occur during signer operations,
4//! including context management, transaction signing, and blockchain interactions.
5
6use thiserror::Error;
7
8/// Error types for signer operations
9#[derive(Error, Debug, Clone)]
10pub enum SignerError {
11    /// No signer context is currently available
12    #[error("No signer context available - must be called within SignerContext::with_signer")]
13    NoSignerContext,
14
15    /// Blockchain transaction error (generic, preserves error as string)
16    #[error("Blockchain transaction error: {0}")]
17    BlockchainTransaction(String),
18
19    /// EVM blockchain transaction error
20    #[error("EVM transaction error: {0}")]
21    EvmTransaction(String),
22
23    /// Invalid signer configuration
24    #[error("Invalid configuration: {0}")]
25    Configuration(String),
26
27    /// Transaction signing operation failed
28    #[error("Signing error: {0}")]
29    Signing(String),
30
31    /// Blockchain client creation failed
32    #[error("Client creation error: {0}")]
33    ClientCreation(String),
34
35    /// Private key format or content is invalid
36    #[error("Invalid private key: {0}")]
37    InvalidPrivateKey(String),
38
39    /// Blockchain provider error
40    #[error("Provider error: {0}")]
41    ProviderError(String),
42
43    /// Transaction execution failed on blockchain
44    #[error("Transaction failed: {0}")]
45    TransactionFailed(String),
46
47    /// Operation not supported by current signer
48    #[error("Unsupported operation: {0}")]
49    UnsupportedOperation(String),
50
51    /// Blockchain hash retrieval or validation error
52    #[error("Blockhash error: {0}")]
53    BlockhashError(String),
54
55    /// Network not supported by signer
56    #[error("Unsupported network: {0}")]
57    UnsupportedNetwork(String),
58
59    /// RPC URL format is invalid or unreachable
60    #[error("Invalid RPC URL: {0}")]
61    InvalidRpcUrl(String),
62}
63
64// Note: Chain-specific From implementations have been moved to their respective
65// tools crates to maintain chain-agnostic nature of riglr-core
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70
71    #[test]
72    fn test_no_signer_context_error_display() {
73        let error = SignerError::NoSignerContext;
74        assert_eq!(
75            error.to_string(),
76            "No signer context available - must be called within SignerContext::with_signer"
77        );
78    }
79
80    #[test]
81    fn test_blockchain_transaction_error_display() {
82        let error = SignerError::BlockchainTransaction("Connection refused".to_string());
83        assert!(error.to_string().contains("Blockchain transaction error:"));
84        assert!(error.to_string().contains("Connection refused"));
85    }
86
87    #[test]
88    fn test_evm_transaction_error_display() {
89        let error = SignerError::EvmTransaction("Transaction reverted".to_string());
90        assert_eq!(
91            error.to_string(),
92            "EVM transaction error: Transaction reverted"
93        );
94    }
95
96    #[test]
97    fn test_configuration_error_display() {
98        let error = SignerError::Configuration("Invalid network config".to_string());
99        assert_eq!(
100            error.to_string(),
101            "Invalid configuration: Invalid network config"
102        );
103    }
104
105    #[test]
106    fn test_signing_error_display() {
107        let error = SignerError::Signing("Key derivation failed".to_string());
108        assert_eq!(error.to_string(), "Signing error: Key derivation failed");
109    }
110
111    #[test]
112    fn test_client_creation_error_display() {
113        let error = SignerError::ClientCreation("Failed to initialize RPC client".to_string());
114        assert_eq!(
115            error.to_string(),
116            "Client creation error: Failed to initialize RPC client"
117        );
118    }
119
120    #[test]
121    fn test_invalid_private_key_error_display() {
122        let error = SignerError::InvalidPrivateKey("Invalid hex format".to_string());
123        assert_eq!(error.to_string(), "Invalid private key: Invalid hex format");
124    }
125
126    #[test]
127    fn test_provider_error_display() {
128        let error = SignerError::ProviderError("Provider timeout".to_string());
129        assert_eq!(error.to_string(), "Provider error: Provider timeout");
130    }
131
132    #[test]
133    fn test_transaction_failed_error_display() {
134        let error = SignerError::TransactionFailed("Insufficient funds".to_string());
135        assert_eq!(error.to_string(), "Transaction failed: Insufficient funds");
136    }
137
138    #[test]
139    fn test_unsupported_operation_error_display() {
140        let error = SignerError::UnsupportedOperation("Multi-sig not supported".to_string());
141        assert_eq!(
142            error.to_string(),
143            "Unsupported operation: Multi-sig not supported"
144        );
145    }
146
147    #[test]
148    fn test_blockhash_error_display() {
149        let error = SignerError::BlockhashError("Failed to fetch recent blockhash".to_string());
150        assert_eq!(
151            error.to_string(),
152            "Blockhash error: Failed to fetch recent blockhash"
153        );
154    }
155
156    #[test]
157    fn test_unsupported_network_error_display() {
158        let error = SignerError::UnsupportedNetwork("Polygon".to_string());
159        assert_eq!(error.to_string(), "Unsupported network: Polygon");
160    }
161
162    #[test]
163    fn test_invalid_rpc_url_error_display() {
164        let error = SignerError::InvalidRpcUrl("malformed://url".to_string());
165        assert_eq!(error.to_string(), "Invalid RPC URL: malformed://url");
166    }
167
168    // Chain-specific From trait tests have been moved to their respective tools crates
169
170    #[test]
171    fn test_error_variants_are_debug() {
172        let error = SignerError::NoSignerContext;
173        let debug_string = format!("{:?}", error);
174        assert!(debug_string.contains("NoSignerContext"));
175    }
176
177    #[test]
178    fn test_all_error_variants_with_empty_strings() {
179        let errors = vec![
180            SignerError::EvmTransaction(String::new()),
181            SignerError::Configuration(String::new()),
182            SignerError::Signing(String::new()),
183            SignerError::ClientCreation(String::new()),
184            SignerError::InvalidPrivateKey(String::new()),
185            SignerError::ProviderError(String::new()),
186            SignerError::TransactionFailed(String::new()),
187            SignerError::UnsupportedOperation(String::new()),
188            SignerError::BlockhashError(String::new()),
189            SignerError::UnsupportedNetwork(String::new()),
190            SignerError::InvalidRpcUrl(String::new()),
191        ];
192
193        for error in errors {
194            // Test that all variants can be created with empty strings
195            let _error_string = error.to_string();
196            let _debug_string = format!("{:?}", error);
197        }
198    }
199
200    #[test]
201    fn test_blockchain_transaction_error_creation() {
202        let error = SignerError::BlockchainTransaction("Request timed out".to_string());
203        match error {
204            SignerError::BlockchainTransaction(msg) => {
205                assert_eq!(msg, "Request timed out");
206            }
207            _ => panic!("Expected SignerError::BlockchainTransaction variant"),
208        }
209    }
210
211    #[test]
212    fn test_error_variants_with_special_characters() {
213        let special_chars = "特殊文字 🚀 \n\t\"'\\";
214        let errors = vec![
215            SignerError::EvmTransaction(special_chars.to_string()),
216            SignerError::Configuration(special_chars.to_string()),
217            SignerError::Signing(special_chars.to_string()),
218            SignerError::ClientCreation(special_chars.to_string()),
219            SignerError::InvalidPrivateKey(special_chars.to_string()),
220            SignerError::ProviderError(special_chars.to_string()),
221            SignerError::TransactionFailed(special_chars.to_string()),
222            SignerError::UnsupportedOperation(special_chars.to_string()),
223            SignerError::BlockhashError(special_chars.to_string()),
224            SignerError::UnsupportedNetwork(special_chars.to_string()),
225            SignerError::InvalidRpcUrl(special_chars.to_string()),
226        ];
227
228        for error in errors {
229            let error_string = error.to_string();
230            assert!(error_string.contains(special_chars));
231        }
232    }
233}