openzeppelin_relayer/domain/relayer/evm/
evm_relayer.rs

1/// This module defines the `EvmRelayer` struct and its associated functionality for
2/// interacting with Ethereum Virtual Machine (EVM) networks. The `EvmRelayer` is responsible
3/// for managing transactions, signing data, and ensuring the relayer's state is synchronized
4/// with the blockchain.
5///
6/// # Components
7///
8/// - `EvmRelayer`: The main struct that encapsulates the relayer's state and operations.
9/// - `RelayerRepoModel`: Represents the relayer's data model.
10/// - `EvmSigner`: Handles signing of data and transactions.
11/// - `EvmProvider`: Provides blockchain interaction capabilities, such as fetching balances
12///   and transaction counts.
13/// - `TransactionCounterService`: Manages the nonce for transactions to ensure they are
14///   processed in the correct order.
15/// - `JobProducer`: Produces jobs for processing transactions and sending notifications.
16///
17/// # Error Handling
18///
19/// The module uses the `RelayerError` enum to handle various errors that can occur during
20/// operations, such as provider errors, insufficient balance, and transaction failures.
21///
22/// # Usage
23///
24/// To use the `EvmRelayer`, create an instance using the `new` method, providing the necessary
25/// components. Then, call the appropriate methods to process transactions, sign data, and
26/// manage the relayer's state.
27use std::sync::Arc;
28
29use crate::{
30    constants::EVM_SMALLEST_UNIT_NAME,
31    domain::{
32        relayer::{Relayer, RelayerError},
33        BalanceResponse, SignDataRequest, SignDataResponse, SignTypedDataRequest,
34    },
35    jobs::{JobProducerTrait, TransactionRequest},
36    models::{
37        produce_relayer_disabled_payload, DeletePendingTransactionsResponse, EvmNetwork,
38        JsonRpcRequest, JsonRpcResponse, NetworkRpcRequest, NetworkRpcResult,
39        NetworkTransactionRequest, NetworkType, RelayerRepoModel, RelayerStatus, RepositoryError,
40        RpcErrorCodes, TransactionRepoModel, TransactionStatus,
41    },
42    repositories::{
43        InMemoryNetworkRepository, InMemoryRelayerRepository, InMemoryTransactionCounter,
44        InMemoryTransactionRepository, NetworkRepository, RelayerRepository,
45        RelayerRepositoryStorage, Repository, TransactionRepository,
46    },
47    services::{
48        DataSignerTrait, EvmProvider, EvmProviderTrait, EvmSigner, TransactionCounterService,
49        TransactionCounterServiceTrait,
50    },
51};
52use async_trait::async_trait;
53use eyre::Result;
54use log::{info, warn};
55
56use super::{
57    create_error_response, create_success_response, map_provider_error, EvmTransactionValidator,
58};
59
60#[allow(dead_code)]
61pub struct EvmRelayer<P, R, N, T, J, S, C>
62where
63    P: EvmProviderTrait + Send + Sync,
64    R: Repository<RelayerRepoModel, String> + RelayerRepository + Send + Sync,
65    T: Repository<TransactionRepoModel, String> + TransactionRepository + Send + Sync,
66    N: NetworkRepository + Send + Sync,
67    J: JobProducerTrait + Send + Sync,
68    S: DataSignerTrait + Send + Sync,
69    C: TransactionCounterServiceTrait + Send + Sync,
70{
71    relayer: RelayerRepoModel,
72    signer: S,
73    network: EvmNetwork,
74    provider: P,
75    relayer_repository: Arc<R>,
76    network_repository: Arc<N>,
77    transaction_repository: Arc<T>,
78    transaction_counter_service: Arc<C>,
79    job_producer: Arc<J>,
80}
81
82#[allow(clippy::too_many_arguments)]
83impl<P, R, N, T, J, S, C> EvmRelayer<P, R, N, T, J, S, C>
84where
85    P: EvmProviderTrait + Send + Sync,
86    R: Repository<RelayerRepoModel, String> + RelayerRepository + Send + Sync,
87    T: Repository<TransactionRepoModel, String> + TransactionRepository + Send + Sync,
88    N: NetworkRepository + Send + Sync,
89    J: JobProducerTrait + Send + Sync,
90    S: DataSignerTrait + Send + Sync,
91    C: TransactionCounterServiceTrait + Send + Sync,
92{
93    /// Constructs a new `EvmRelayer` instance.
94    ///
95    /// # Arguments
96    ///
97    /// * `relayer` - The relayer's data model.
98    /// * `signer` - The EVM signer for signing data and transactions.
99    /// * `provider` - The EVM provider for blockchain interactions.
100    /// * `network` - The EVM network configuration.
101    /// * `relayer_repository` - The repository for relayer storage.
102    /// * `transaction_repository` - The repository for transaction storage.
103    /// * `transaction_counter_service` - The service for managing transaction nonces.
104    /// * `job_producer` - The job producer for creating transaction jobs.
105    ///
106    /// # Returns
107    ///
108    /// A `Result` containing the new `EvmRelayer` instance or a `RelayerError`
109    pub fn new(
110        relayer: RelayerRepoModel,
111        signer: S,
112        provider: P,
113        network: EvmNetwork,
114        relayer_repository: Arc<R>,
115        network_repository: Arc<N>,
116        transaction_repository: Arc<T>,
117        transaction_counter_service: Arc<C>,
118        job_producer: Arc<J>,
119    ) -> Result<Self, RelayerError> {
120        Ok(Self {
121            relayer,
122            signer,
123            network,
124            provider,
125            relayer_repository,
126            network_repository,
127            transaction_repository,
128            transaction_counter_service,
129            job_producer,
130        })
131    }
132
133    /// Synchronizes the nonce with the blockchain.
134    ///
135    /// # Returns
136    ///
137    /// A `Result` indicating success or a `RelayerError` if the operation fails.
138    async fn sync_nonce(&self) -> Result<(), RelayerError> {
139        let on_chain_nonce = self
140            .provider
141            .get_transaction_count(&self.relayer.address)
142            .await
143            .map_err(|e| RelayerError::ProviderError(e.to_string()))?;
144
145        info!(
146            "Setting nonce: {} for relayer: {}",
147            on_chain_nonce, self.relayer.id
148        );
149
150        self.transaction_counter_service.set(on_chain_nonce).await?;
151
152        Ok(())
153    }
154
155    /// Validates the RPC connection to the blockchain provider.
156    ///
157    /// # Returns
158    ///
159    /// A `Result` indicating success or a `RelayerError` if the operation fails.
160    async fn validate_rpc(&self) -> Result<(), RelayerError> {
161        self.provider
162            .health_check()
163            .await
164            .map_err(|e| RelayerError::ProviderError(e.to_string()))?;
165
166        Ok(())
167    }
168
169    /// Initiates transaction cancellation via the job queue system.
170    ///
171    /// # Arguments
172    ///
173    /// * `transaction` - The transaction model to cancel.
174    ///
175    /// # Returns
176    ///
177    /// A `Result` indicating success or a `RelayerError` if the job creation fails.
178    async fn cancel_transaction_via_job(
179        &self,
180        transaction: TransactionRepoModel,
181    ) -> Result<(), RelayerError> {
182        use crate::jobs::TransactionSend;
183
184        let cancel_job = TransactionSend::cancel(
185            transaction.id.clone(),
186            transaction.relayer_id.clone(),
187            "Cancelled via delete_pending_transactions".to_string(),
188        );
189
190        self.job_producer
191            .produce_submit_transaction_job(cancel_job, None)
192            .await
193            .map_err(RelayerError::from)?;
194
195        Ok(())
196    }
197}
198
199// Define a concrete type alias for common usage
200pub type DefaultEvmRelayer<J> = EvmRelayer<
201    EvmProvider,
202    RelayerRepositoryStorage<InMemoryRelayerRepository>,
203    InMemoryNetworkRepository,
204    InMemoryTransactionRepository,
205    J,
206    EvmSigner,
207    TransactionCounterService<InMemoryTransactionCounter>,
208>;
209
210#[async_trait]
211impl<P, R, N, T, J, S, C> Relayer for EvmRelayer<P, R, N, T, J, S, C>
212where
213    P: EvmProviderTrait + Send + Sync,
214    R: Repository<RelayerRepoModel, String> + RelayerRepository + Send + Sync,
215    N: NetworkRepository + Send + Sync,
216    T: Repository<TransactionRepoModel, String> + TransactionRepository + Send + Sync,
217    J: JobProducerTrait + Send + Sync,
218    S: DataSignerTrait + Send + Sync,
219    C: TransactionCounterServiceTrait + Send + Sync,
220{
221    /// Processes a transaction request and creates a job for it.
222    ///
223    /// # Arguments
224    ///
225    /// * `network_transaction` - The network transaction request to process.
226    ///
227    /// # Returns
228    ///
229    /// A `Result` containing the `TransactionRepoModel` or a `RelayerError`.
230    async fn process_transaction_request(
231        &self,
232        network_transaction: NetworkTransactionRequest,
233    ) -> Result<TransactionRepoModel, RelayerError> {
234        let network_model = self
235            .network_repository
236            .get_by_name(NetworkType::Evm, &self.relayer.network)
237            .await?
238            .ok_or_else(|| {
239                RelayerError::NetworkConfiguration(format!(
240                    "Network {} not found",
241                    self.relayer.network
242                ))
243            })?;
244        let transaction =
245            TransactionRepoModel::try_from((&network_transaction, &self.relayer, &network_model))?;
246
247        self.transaction_repository
248            .create(transaction.clone())
249            .await
250            .map_err(|e| RepositoryError::TransactionFailure(e.to_string()))?;
251
252        self.job_producer
253            .produce_transaction_request_job(
254                TransactionRequest::new(transaction.id.clone(), transaction.relayer_id.clone()),
255                None,
256            )
257            .await?;
258
259        Ok(transaction)
260    }
261
262    /// Retrieves the balance of the relayer's address.
263    ///
264    /// # Returns
265    ///
266    /// A `Result` containing the `BalanceResponse` or a `RelayerError`.
267    async fn get_balance(&self) -> Result<BalanceResponse, RelayerError> {
268        let balance: u128 = self
269            .provider
270            .get_balance(&self.relayer.address)
271            .await
272            .map_err(|e| RelayerError::ProviderError(e.to_string()))?
273            .try_into()
274            .map_err(|_| {
275                RelayerError::ProviderError("Failed to convert balance to u128".to_string())
276            })?;
277
278        Ok(BalanceResponse {
279            balance,
280            unit: EVM_SMALLEST_UNIT_NAME.to_string(),
281        })
282    }
283
284    /// Gets the status of the relayer.
285    ///
286    /// # Returns
287    ///
288    /// A `Result` containing a boolean indicating the status or a `RelayerError`.
289    async fn get_status(&self) -> Result<RelayerStatus, RelayerError> {
290        let relayer_model = &self.relayer;
291
292        let nonce_u256 = self
293            .provider
294            .get_transaction_count(&relayer_model.address)
295            .await
296            .map_err(|e| RelayerError::ProviderError(format!("Failed to get nonce: {}", e)))?;
297        let nonce_str = nonce_u256.to_string();
298
299        let balance_response = self.get_balance().await?;
300
301        let pending_statuses = [TransactionStatus::Pending, TransactionStatus::Submitted];
302        let pending_transactions = self
303            .transaction_repository
304            .find_by_status(&relayer_model.id, &pending_statuses[..])
305            .await
306            .map_err(RelayerError::from)?;
307        let pending_transactions_count = pending_transactions.len() as u64;
308
309        let confirmed_statuses = [TransactionStatus::Confirmed];
310        let confirmed_transactions = self
311            .transaction_repository
312            .find_by_status(&relayer_model.id, &confirmed_statuses[..])
313            .await
314            .map_err(RelayerError::from)?;
315
316        let last_confirmed_transaction_timestamp = confirmed_transactions
317            .iter()
318            .filter_map(|tx| tx.confirmed_at.as_ref())
319            .max()
320            .cloned();
321
322        Ok(RelayerStatus::Evm {
323            balance: balance_response.balance.to_string(),
324            pending_transactions_count,
325            last_confirmed_transaction_timestamp,
326            system_disabled: relayer_model.system_disabled,
327            paused: relayer_model.paused,
328            nonce: nonce_str,
329        })
330    }
331
332    /// Deletes pending transactions.
333    ///
334    /// # Returns
335    ///
336    /// A `Result` containing a `DeletePendingTransactionsResponse` with details
337    /// about which transactions were cancelled and which failed, or a `RelayerError`.
338    async fn delete_pending_transactions(
339        &self,
340    ) -> Result<DeletePendingTransactionsResponse, RelayerError> {
341        let pending_statuses = [
342            TransactionStatus::Pending,
343            TransactionStatus::Sent,
344            TransactionStatus::Submitted,
345        ];
346
347        // Get all pending transactions
348        let pending_transactions = self
349            .transaction_repository
350            .find_by_status(&self.relayer.id, &pending_statuses[..])
351            .await
352            .map_err(RelayerError::from)?;
353
354        let transaction_count = pending_transactions.len();
355
356        if transaction_count == 0 {
357            info!(
358                "No pending transactions found for relayer: {}",
359                self.relayer.id
360            );
361            return Ok(DeletePendingTransactionsResponse {
362                queued_for_cancellation_transaction_ids: vec![],
363                failed_to_queue_transaction_ids: vec![],
364                total_processed: 0,
365            });
366        }
367
368        info!(
369            "Processing {} pending transactions for relayer: {}",
370            transaction_count, self.relayer.id
371        );
372
373        let mut cancelled_transaction_ids = Vec::new();
374        let mut failed_transaction_ids = Vec::new();
375
376        // Process all pending transactions using the proper cancellation logic via job queue
377        for transaction in pending_transactions {
378            match self.cancel_transaction_via_job(transaction.clone()).await {
379                Ok(_) => {
380                    cancelled_transaction_ids.push(transaction.id.clone());
381                    info!(
382                        "Initiated cancellation for transaction {} with status {:?} for relayer {}",
383                        transaction.id, transaction.status, self.relayer.id
384                    );
385                }
386                Err(e) => {
387                    failed_transaction_ids.push(transaction.id.clone());
388                    warn!(
389                        "Failed to cancel transaction {} for relayer {}: {}",
390                        transaction.id, self.relayer.id, e
391                    );
392                }
393            }
394        }
395
396        let total_processed = cancelled_transaction_ids.len() + failed_transaction_ids.len();
397
398        info!("Completed processing pending transactions for relayer {}: {} queued for cancellation, {} failed to queue",
399              self.relayer.id, cancelled_transaction_ids.len(), failed_transaction_ids.len());
400
401        Ok(DeletePendingTransactionsResponse {
402            queued_for_cancellation_transaction_ids: cancelled_transaction_ids,
403            failed_to_queue_transaction_ids: failed_transaction_ids,
404            total_processed: total_processed as u32,
405        })
406    }
407
408    /// Signs data using the relayer's signer.
409    ///
410    /// # Arguments
411    ///
412    /// * `request` - The request containing the data to sign.
413    ///
414    /// # Returns
415    ///
416    /// A `Result` containing the `SignDataResponse` or a `RelayerError`.
417    async fn sign_data(&self, request: SignDataRequest) -> Result<SignDataResponse, RelayerError> {
418        let result = self.signer.sign_data(request).await?;
419
420        Ok(result)
421    }
422
423    /// Signs typed data using the relayer's signer.
424    ///
425    /// # Arguments
426    ///
427    /// * `request` - The request containing the typed data to sign.
428    ///
429    /// # Returns
430    ///
431    /// A `Result` containing the `SignDataResponse` or a `RelayerError`.
432    async fn sign_typed_data(
433        &self,
434        request: SignTypedDataRequest,
435    ) -> Result<SignDataResponse, RelayerError> {
436        let result = self.signer.sign_typed_data(request).await?;
437
438        Ok(result)
439    }
440
441    /// Handles a JSON-RPC request.
442    ///
443    /// # Arguments
444    ///
445    /// * `request` - The JSON-RPC request to handle.
446    ///
447    /// # Returns
448    ///
449    /// A `Result` containing the `JsonRpcResponse` or a `RelayerError`.
450    async fn rpc(
451        &self,
452        request: JsonRpcRequest<NetworkRpcRequest>,
453    ) -> Result<JsonRpcResponse<NetworkRpcResult>, RelayerError> {
454        let evm_request = match request.params {
455            NetworkRpcRequest::Evm(evm_req) => evm_req,
456            _ => {
457                return Ok(create_error_response(
458                    request.id,
459                    RpcErrorCodes::INVALID_PARAMS,
460                    "Invalid params",
461                    "Expected EVM network request",
462                ))
463            }
464        };
465
466        // Parse method and params from the EVM request
467        let (method, params_json) = match evm_request {
468            crate::models::EvmRpcRequest::GenericRpcRequest { method, params } => {
469                (method, serde_json::Value::String(params))
470            }
471            crate::models::EvmRpcRequest::RawRpcRequest { method, params } => (method, params),
472        };
473
474        // Forward the RPC call to the provider
475        match self.provider.raw_request_dyn(&method, params_json).await {
476            Ok(result_value) => Ok(create_success_response(request.id, result_value)),
477            Err(provider_error) => {
478                let (error_code, error_message) = map_provider_error(&provider_error);
479                Ok(create_error_response(
480                    request.id,
481                    error_code,
482                    error_message,
483                    &provider_error.to_string(),
484                ))
485            }
486        }
487    }
488
489    /// Validates that the relayer's balance meets the minimum required balance.
490    ///
491    /// # Returns
492    ///
493    /// A `Result` indicating success or a `RelayerError` if the balance is insufficient.
494    async fn validate_min_balance(&self) -> Result<(), RelayerError> {
495        let policy = self.relayer.policies.get_evm_policy();
496        EvmTransactionValidator::init_balance_validation(
497            &self.relayer.address,
498            &policy,
499            &self.provider,
500        )
501        .await
502        .map_err(|e| RelayerError::InsufficientBalanceError(e.to_string()))?;
503
504        Ok(())
505    }
506
507    /// Initializes the relayer by performing necessary checks and synchronizations.
508    ///
509    /// # Returns
510    ///
511    /// A `Result` indicating success or a `RelayerError` if any initialization step fails.
512    async fn initialize_relayer(&self) -> Result<(), RelayerError> {
513        info!("Initializing relayer: {}", self.relayer.id);
514        let nonce_sync_result = self.sync_nonce().await;
515        let validate_rpc_result = self.validate_rpc().await;
516        let validate_min_balance_result = self.validate_min_balance().await;
517
518        // disable relayer if any check fails
519        if nonce_sync_result.is_err()
520            || validate_rpc_result.is_err()
521            || validate_min_balance_result.is_err()
522        {
523            let reason = vec![
524                nonce_sync_result
525                    .err()
526                    .map(|e| format!("Nonce sync failed: {}", e)),
527                validate_rpc_result
528                    .err()
529                    .map(|e| format!("RPC validation failed: {}", e)),
530                validate_min_balance_result
531                    .err()
532                    .map(|e| format!("Balance check failed: {}", e)),
533            ]
534            .into_iter()
535            .flatten()
536            .collect::<Vec<String>>()
537            .join(", ");
538
539            warn!("Disabling relayer: {} due to: {}", self.relayer.id, reason);
540            let updated_relayer = self
541                .relayer_repository
542                .disable_relayer(self.relayer.id.clone())
543                .await?;
544            if let Some(notification_id) = &self.relayer.notification_id {
545                self.job_producer
546                    .produce_send_notification_job(
547                        produce_relayer_disabled_payload(
548                            notification_id,
549                            &updated_relayer,
550                            &reason,
551                        ),
552                        None,
553                    )
554                    .await?;
555            }
556        }
557        Ok(())
558    }
559}
560
561#[cfg(test)]
562mod tests {
563    use super::*;
564    use crate::{
565        jobs::MockJobProducerTrait,
566        models::{
567            EvmRpcRequest, EvmRpcResult, JsonRpcId, NetworkRepoModel, NetworkType,
568            RelayerEvmPolicy, RelayerNetworkPolicy, RepositoryError, SignerError,
569            TransactionStatus, U256,
570        },
571        repositories::{MockNetworkRepository, MockRelayerRepository, MockTransactionRepository},
572        services::{MockEvmProviderTrait, MockTransactionCounterServiceTrait, ProviderError},
573    };
574    use mockall::predicate::*;
575    use std::future::ready;
576
577    mockall::mock! {
578        pub DataSigner {}
579
580        #[async_trait]
581        impl DataSignerTrait for DataSigner {
582            async fn sign_data(&self, request: SignDataRequest) -> Result<SignDataResponse, SignerError>;
583            async fn sign_typed_data(&self, request: SignTypedDataRequest) -> Result<SignDataResponse, SignerError>;
584        }
585    }
586
587    fn create_test_evm_network() -> EvmNetwork {
588        EvmNetwork {
589            network: "mainnet".to_string(),
590            rpc_urls: vec!["https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY".to_string()],
591            explorer_urls: None,
592            average_blocktime_ms: 12000,
593            is_testnet: false,
594            tags: vec!["mainnet".to_string()],
595            chain_id: 1,
596            required_confirmations: 1,
597            features: vec!["eip1559".to_string()],
598            symbol: "ETH".to_string(),
599        }
600    }
601
602    fn create_test_network_repo_model() -> NetworkRepoModel {
603        use crate::config::{EvmNetworkConfig, NetworkConfigCommon};
604
605        let config = EvmNetworkConfig {
606            common: NetworkConfigCommon {
607                network: "mainnet".to_string(),
608                from: None,
609                rpc_urls: Some(vec![
610                    "https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY".to_string()
611                ]),
612                explorer_urls: None,
613                average_blocktime_ms: Some(12000),
614                is_testnet: Some(false),
615                tags: Some(vec!["mainnet".to_string()]),
616            },
617            chain_id: Some(1),
618            required_confirmations: Some(1),
619            features: Some(vec!["eip1559".to_string()]),
620            symbol: Some("ETH".to_string()),
621        };
622
623        NetworkRepoModel::new_evm(config)
624    }
625
626    fn create_test_relayer() -> RelayerRepoModel {
627        RelayerRepoModel {
628            id: "test-relayer-id".to_string(),
629            name: "Test Relayer".to_string(),
630            network: "mainnet".to_string(), // Changed from "1" to "mainnet"
631            address: "0xSender".to_string(),
632            paused: false,
633            system_disabled: false,
634            signer_id: "test-signer-id".to_string(),
635            notification_id: Some("test-notification-id".to_string()),
636            policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
637                min_balance: 100000000000000000u128, // 0.1 ETH
638                whitelist_receivers: Some(vec!["0xRecipient".to_string()]),
639                gas_price_cap: Some(100000000000), // 100 Gwei
640                eip1559_pricing: Some(false),
641                private_transactions: false,
642            }),
643            network_type: NetworkType::Evm,
644            custom_rpc_urls: None,
645        }
646    }
647
648    fn setup_mocks() -> (
649        MockEvmProviderTrait,
650        MockRelayerRepository,
651        MockNetworkRepository,
652        MockTransactionRepository,
653        MockJobProducerTrait,
654        MockDataSigner,
655        MockTransactionCounterServiceTrait,
656    ) {
657        (
658            MockEvmProviderTrait::new(),
659            MockRelayerRepository::new(),
660            MockNetworkRepository::new(),
661            MockTransactionRepository::new(),
662            MockJobProducerTrait::new(),
663            MockDataSigner::new(),
664            MockTransactionCounterServiceTrait::new(),
665        )
666    }
667
668    #[tokio::test]
669    async fn test_get_balance() {
670        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
671            setup_mocks();
672        let relayer_model = create_test_relayer();
673
674        provider
675            .expect_get_balance()
676            .with(eq("0xSender"))
677            .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64))))); // 1 ETH
678
679        let relayer = EvmRelayer::new(
680            relayer_model,
681            signer,
682            provider,
683            create_test_evm_network(),
684            Arc::new(relayer_repo),
685            Arc::new(network_repo),
686            Arc::new(tx_repo),
687            Arc::new(counter),
688            Arc::new(job_producer),
689        )
690        .unwrap();
691
692        let balance = relayer.get_balance().await.unwrap();
693        assert_eq!(balance.balance, 1000000000000000000u128);
694        assert_eq!(balance.unit, EVM_SMALLEST_UNIT_NAME);
695    }
696
697    #[tokio::test]
698    async fn test_process_transaction_request() {
699        let (
700            provider,
701            relayer_repo,
702            mut network_repo,
703            mut tx_repo,
704            mut job_producer,
705            signer,
706            counter,
707        ) = setup_mocks();
708        let relayer_model = create_test_relayer();
709
710        let network_tx = NetworkTransactionRequest::Evm(crate::models::EvmTransactionRequest {
711            to: Some("0xRecipient".to_string()),
712            value: U256::from(1000000000000000000u64),
713            data: Some("0xData".to_string()),
714            gas_limit: 21000,
715            gas_price: Some(20000000000),
716            max_fee_per_gas: None,
717            max_priority_fee_per_gas: None,
718            speed: None,
719            valid_until: None,
720        });
721
722        network_repo
723            .expect_get_by_name()
724            .with(eq(NetworkType::Evm), eq("mainnet"))
725            .returning(|_, _| Ok(Some(create_test_network_repo_model())));
726
727        tx_repo.expect_create().returning(Ok);
728        job_producer
729            .expect_produce_transaction_request_job()
730            .returning(|_, _| Box::pin(ready(Ok(()))));
731
732        let relayer = EvmRelayer::new(
733            relayer_model,
734            signer,
735            provider,
736            create_test_evm_network(),
737            Arc::new(relayer_repo),
738            Arc::new(network_repo),
739            Arc::new(tx_repo),
740            Arc::new(counter),
741            Arc::new(job_producer),
742        )
743        .unwrap();
744
745        let result = relayer.process_transaction_request(network_tx).await;
746        assert!(result.is_ok());
747    }
748
749    #[tokio::test]
750    async fn test_validate_min_balance_sufficient() {
751        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
752            setup_mocks();
753        let relayer_model = create_test_relayer();
754
755        provider
756            .expect_get_balance()
757            .returning(|_| Box::pin(ready(Ok(U256::from(200000000000000000u64))))); // 0.2 ETH > min_balance
758
759        let relayer = EvmRelayer::new(
760            relayer_model,
761            signer,
762            provider,
763            create_test_evm_network(),
764            Arc::new(relayer_repo),
765            Arc::new(network_repo),
766            Arc::new(tx_repo),
767            Arc::new(counter),
768            Arc::new(job_producer),
769        )
770        .unwrap();
771
772        let result = relayer.validate_min_balance().await;
773        assert!(result.is_ok());
774    }
775
776    #[tokio::test]
777    async fn test_validate_min_balance_insufficient() {
778        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
779            setup_mocks();
780        let relayer_model = create_test_relayer();
781
782        provider
783            .expect_get_balance()
784            .returning(|_| Box::pin(ready(Ok(U256::from(50000000000000000u64))))); // 0.05 ETH < min_balance
785
786        let relayer = EvmRelayer::new(
787            relayer_model,
788            signer,
789            provider,
790            create_test_evm_network(),
791            Arc::new(relayer_repo),
792            Arc::new(network_repo),
793            Arc::new(tx_repo),
794            Arc::new(counter),
795            Arc::new(job_producer),
796        )
797        .unwrap();
798
799        let result = relayer.validate_min_balance().await;
800        assert!(matches!(
801            result,
802            Err(RelayerError::InsufficientBalanceError(_))
803        ));
804    }
805
806    #[tokio::test]
807    async fn test_sync_nonce() {
808        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, mut counter) =
809            setup_mocks();
810        let relayer_model = create_test_relayer();
811
812        provider
813            .expect_get_transaction_count()
814            .returning(|_| Box::pin(ready(Ok(42u64))));
815
816        counter
817            .expect_set()
818            .returning(|_nonce| Box::pin(ready(Ok(()))));
819
820        let relayer = EvmRelayer::new(
821            relayer_model,
822            signer,
823            provider,
824            create_test_evm_network(),
825            Arc::new(relayer_repo),
826            Arc::new(network_repo),
827            Arc::new(tx_repo),
828            Arc::new(counter),
829            Arc::new(job_producer),
830        )
831        .unwrap();
832
833        let result = relayer.sync_nonce().await;
834        assert!(result.is_ok());
835    }
836
837    #[tokio::test]
838    async fn test_validate_rpc() {
839        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
840            setup_mocks();
841        let relayer_model = create_test_relayer();
842
843        provider
844            .expect_health_check()
845            .returning(|| Box::pin(ready(Ok(true))));
846
847        let relayer = EvmRelayer::new(
848            relayer_model,
849            signer,
850            provider,
851            create_test_evm_network(),
852            Arc::new(relayer_repo),
853            Arc::new(network_repo),
854            Arc::new(tx_repo),
855            Arc::new(counter),
856            Arc::new(job_producer),
857        )
858        .unwrap();
859
860        let result = relayer.validate_rpc().await;
861        assert!(result.is_ok());
862    }
863
864    #[tokio::test]
865    async fn test_get_status_success() {
866        let (mut provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
867            setup_mocks();
868        let relayer_model = create_test_relayer();
869
870        provider
871            .expect_get_transaction_count()
872            .returning(|_| Box::pin(ready(Ok(10u64))))
873            .once();
874        provider
875            .expect_get_balance()
876            .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64)))))
877            .once();
878
879        let pending_txs_clone = vec![];
880        tx_repo
881            .expect_find_by_status()
882            .withf(|relayer_id, statuses| {
883                relayer_id == "test-relayer-id"
884                    && statuses == [TransactionStatus::Pending, TransactionStatus::Submitted]
885            })
886            .returning(move |_, _| {
887                Ok(pending_txs_clone.clone()) as Result<Vec<TransactionRepoModel>, RepositoryError>
888            })
889            .once();
890
891        let confirmed_txs_clone = vec![
892            TransactionRepoModel {
893                id: "tx1".to_string(),
894                relayer_id: relayer_model.id.clone(),
895                status: TransactionStatus::Confirmed,
896                confirmed_at: Some("2023-01-01T12:00:00Z".to_string()),
897                ..TransactionRepoModel::default()
898            },
899            TransactionRepoModel {
900                id: "tx2".to_string(),
901                relayer_id: relayer_model.id.clone(),
902                status: TransactionStatus::Confirmed,
903                confirmed_at: Some("2023-01-01T10:00:00Z".to_string()),
904                ..TransactionRepoModel::default()
905            },
906        ];
907        tx_repo
908            .expect_find_by_status()
909            .withf(|relayer_id, statuses| {
910                relayer_id == "test-relayer-id" && statuses == [TransactionStatus::Confirmed]
911            })
912            .returning(move |_, _| {
913                Ok(confirmed_txs_clone.clone())
914                    as Result<Vec<TransactionRepoModel>, RepositoryError>
915            })
916            .once();
917
918        let relayer = EvmRelayer::new(
919            relayer_model.clone(),
920            signer,
921            provider,
922            create_test_evm_network(),
923            Arc::new(relayer_repo),
924            Arc::new(network_repo),
925            Arc::new(tx_repo),
926            Arc::new(counter),
927            Arc::new(job_producer),
928        )
929        .unwrap();
930
931        let status = relayer.get_status().await.unwrap();
932
933        match status {
934            RelayerStatus::Evm {
935                balance,
936                pending_transactions_count,
937                last_confirmed_transaction_timestamp,
938                system_disabled,
939                paused,
940                nonce,
941            } => {
942                assert_eq!(balance, "1000000000000000000");
943                assert_eq!(pending_transactions_count, 0);
944                assert_eq!(
945                    last_confirmed_transaction_timestamp,
946                    Some("2023-01-01T12:00:00Z".to_string())
947                );
948                assert_eq!(system_disabled, relayer_model.system_disabled);
949                assert_eq!(paused, relayer_model.paused);
950                assert_eq!(nonce, "10");
951            }
952            _ => panic!("Expected EVM RelayerStatus"),
953        }
954    }
955
956    #[tokio::test]
957    async fn test_get_status_provider_nonce_error() {
958        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
959            setup_mocks();
960        let relayer_model = create_test_relayer();
961
962        provider.expect_get_transaction_count().returning(|_| {
963            Box::pin(ready(Err(ProviderError::Other(
964                "Nonce fetch failed".to_string(),
965            ))))
966        });
967
968        let relayer = EvmRelayer::new(
969            relayer_model.clone(),
970            signer,
971            provider,
972            create_test_evm_network(),
973            Arc::new(relayer_repo),
974            Arc::new(network_repo),
975            Arc::new(tx_repo),
976            Arc::new(counter),
977            Arc::new(job_producer),
978        )
979        .unwrap();
980
981        let result = relayer.get_status().await;
982        assert!(result.is_err());
983        match result.err().unwrap() {
984            RelayerError::ProviderError(msg) => assert!(msg.contains("Failed to get nonce")),
985            _ => panic!("Expected ProviderError for nonce failure"),
986        }
987    }
988
989    #[tokio::test]
990    async fn test_get_status_repository_pending_error() {
991        let (mut provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
992            setup_mocks();
993        let relayer_model = create_test_relayer();
994
995        provider
996            .expect_get_transaction_count()
997            .returning(|_| Box::pin(ready(Ok(10u64))));
998        provider
999            .expect_get_balance()
1000            .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64)))));
1001
1002        tx_repo
1003            .expect_find_by_status()
1004            .withf(|relayer_id, statuses| {
1005                relayer_id == "test-relayer-id"
1006                    && statuses == [TransactionStatus::Pending, TransactionStatus::Submitted]
1007            })
1008            .returning(|_, _| {
1009                Err(RepositoryError::Unknown("DB down".to_string()))
1010                    as Result<Vec<TransactionRepoModel>, RepositoryError>
1011            })
1012            .once();
1013
1014        let relayer = EvmRelayer::new(
1015            relayer_model.clone(),
1016            signer,
1017            provider,
1018            create_test_evm_network(),
1019            Arc::new(relayer_repo),
1020            Arc::new(network_repo),
1021            Arc::new(tx_repo),
1022            Arc::new(counter),
1023            Arc::new(job_producer),
1024        )
1025        .unwrap();
1026
1027        let result = relayer.get_status().await;
1028        assert!(result.is_err());
1029        match result.err().unwrap() {
1030            // Remember our From<RepositoryError> for RelayerError maps to NetworkConfiguration
1031            RelayerError::NetworkConfiguration(msg) => assert!(msg.contains("DB down")),
1032            _ => panic!("Expected NetworkConfiguration error for repo failure"),
1033        }
1034    }
1035
1036    #[tokio::test]
1037    async fn test_get_status_no_confirmed_transactions() {
1038        let (mut provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
1039            setup_mocks();
1040        let relayer_model = create_test_relayer();
1041
1042        provider
1043            .expect_get_transaction_count()
1044            .returning(|_| Box::pin(ready(Ok(10u64))));
1045        provider
1046            .expect_get_balance()
1047            .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64)))));
1048        provider
1049            .expect_health_check()
1050            .returning(|| Box::pin(ready(Ok(true))));
1051
1052        let pending_txs_empty_clone = vec![];
1053        tx_repo
1054            .expect_find_by_status()
1055            .withf(|relayer_id, statuses| {
1056                relayer_id == "test-relayer-id"
1057                    && statuses == [TransactionStatus::Pending, TransactionStatus::Submitted]
1058            })
1059            .returning(move |_, _| {
1060                Ok(pending_txs_empty_clone.clone())
1061                    as Result<Vec<TransactionRepoModel>, RepositoryError>
1062            })
1063            .once();
1064
1065        let confirmed_txs_empty_clone = vec![];
1066        tx_repo
1067            .expect_find_by_status()
1068            .withf(|relayer_id, statuses| {
1069                relayer_id == "test-relayer-id" && statuses == [TransactionStatus::Confirmed]
1070            })
1071            .returning(move |_, _| {
1072                Ok(confirmed_txs_empty_clone.clone())
1073                    as Result<Vec<TransactionRepoModel>, RepositoryError>
1074            })
1075            .once();
1076
1077        let relayer = EvmRelayer::new(
1078            relayer_model.clone(),
1079            signer,
1080            provider,
1081            create_test_evm_network(),
1082            Arc::new(relayer_repo),
1083            Arc::new(network_repo),
1084            Arc::new(tx_repo),
1085            Arc::new(counter),
1086            Arc::new(job_producer),
1087        )
1088        .unwrap();
1089
1090        let status = relayer.get_status().await.unwrap();
1091        match status {
1092            RelayerStatus::Evm {
1093                balance,
1094                pending_transactions_count,
1095                last_confirmed_transaction_timestamp,
1096                system_disabled,
1097                paused,
1098                nonce,
1099            } => {
1100                assert_eq!(balance, "1000000000000000000");
1101                assert_eq!(pending_transactions_count, 0);
1102                assert_eq!(last_confirmed_transaction_timestamp, None);
1103                assert_eq!(system_disabled, relayer_model.system_disabled);
1104                assert_eq!(paused, relayer_model.paused);
1105                assert_eq!(nonce, "10");
1106            }
1107            _ => panic!("Expected EVM RelayerStatus"),
1108        }
1109    }
1110
1111    #[tokio::test]
1112    async fn test_cancel_transaction_via_job_success() {
1113        let (provider, relayer_repo, network_repo, tx_repo, mut job_producer, signer, counter) =
1114            setup_mocks();
1115        let relayer_model = create_test_relayer();
1116
1117        let test_transaction = TransactionRepoModel {
1118            id: "test-tx-id".to_string(),
1119            relayer_id: relayer_model.id.clone(),
1120            status: TransactionStatus::Pending,
1121            ..TransactionRepoModel::default()
1122        };
1123
1124        job_producer
1125            .expect_produce_submit_transaction_job()
1126            .withf(|job, delay| {
1127                matches!(job.command, crate::jobs::TransactionCommand::Cancel { ref reason }
1128                    if job.transaction_id == "test-tx-id"
1129                    && job.relayer_id == "test-relayer-id"
1130                    && reason == "Cancelled via delete_pending_transactions")
1131                    && delay.is_none()
1132            })
1133            .returning(|_, _| Box::pin(ready(Ok(()))))
1134            .once();
1135
1136        let relayer = EvmRelayer::new(
1137            relayer_model,
1138            signer,
1139            provider,
1140            create_test_evm_network(),
1141            Arc::new(relayer_repo),
1142            Arc::new(network_repo),
1143            Arc::new(tx_repo),
1144            Arc::new(counter),
1145            Arc::new(job_producer),
1146        )
1147        .unwrap();
1148
1149        let result = relayer.cancel_transaction_via_job(test_transaction).await;
1150        assert!(result.is_ok());
1151    }
1152
1153    #[tokio::test]
1154    async fn test_cancel_transaction_via_job_failure() {
1155        let (provider, relayer_repo, network_repo, tx_repo, mut job_producer, signer, counter) =
1156            setup_mocks();
1157        let relayer_model = create_test_relayer();
1158
1159        let test_transaction = TransactionRepoModel {
1160            id: "test-tx-id".to_string(),
1161            relayer_id: relayer_model.id.clone(),
1162            status: TransactionStatus::Pending,
1163            ..TransactionRepoModel::default()
1164        };
1165
1166        job_producer
1167            .expect_produce_submit_transaction_job()
1168            .returning(|_, _| {
1169                Box::pin(ready(Err(crate::jobs::JobProducerError::QueueError(
1170                    "Queue is full".to_string(),
1171                ))))
1172            })
1173            .once();
1174
1175        let relayer = EvmRelayer::new(
1176            relayer_model,
1177            signer,
1178            provider,
1179            create_test_evm_network(),
1180            Arc::new(relayer_repo),
1181            Arc::new(network_repo),
1182            Arc::new(tx_repo),
1183            Arc::new(counter),
1184            Arc::new(job_producer),
1185        )
1186        .unwrap();
1187
1188        let result = relayer.cancel_transaction_via_job(test_transaction).await;
1189        assert!(result.is_err());
1190        match result.err().unwrap() {
1191            RelayerError::QueueError(_) => (),
1192            _ => panic!("Expected QueueError"),
1193        }
1194    }
1195
1196    #[tokio::test]
1197    async fn test_delete_pending_transactions_no_pending() {
1198        let (provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
1199            setup_mocks();
1200        let relayer_model = create_test_relayer();
1201
1202        tx_repo
1203            .expect_find_by_status()
1204            .withf(|relayer_id, statuses| {
1205                relayer_id == "test-relayer-id"
1206                    && statuses
1207                        == [
1208                            TransactionStatus::Pending,
1209                            TransactionStatus::Sent,
1210                            TransactionStatus::Submitted,
1211                        ]
1212            })
1213            .returning(|_, _| Ok(vec![]))
1214            .once();
1215
1216        let relayer = EvmRelayer::new(
1217            relayer_model,
1218            signer,
1219            provider,
1220            create_test_evm_network(),
1221            Arc::new(relayer_repo),
1222            Arc::new(network_repo),
1223            Arc::new(tx_repo),
1224            Arc::new(counter),
1225            Arc::new(job_producer),
1226        )
1227        .unwrap();
1228
1229        let result = relayer.delete_pending_transactions().await.unwrap();
1230        assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 0);
1231        assert_eq!(result.failed_to_queue_transaction_ids.len(), 0);
1232        assert_eq!(result.total_processed, 0);
1233    }
1234
1235    #[tokio::test]
1236    async fn test_delete_pending_transactions_all_successful() {
1237        let (provider, relayer_repo, network_repo, mut tx_repo, mut job_producer, signer, counter) =
1238            setup_mocks();
1239        let relayer_model = create_test_relayer();
1240
1241        let pending_transactions = vec![
1242            TransactionRepoModel {
1243                id: "tx1".to_string(),
1244                relayer_id: relayer_model.id.clone(),
1245                status: TransactionStatus::Pending,
1246                ..TransactionRepoModel::default()
1247            },
1248            TransactionRepoModel {
1249                id: "tx2".to_string(),
1250                relayer_id: relayer_model.id.clone(),
1251                status: TransactionStatus::Sent,
1252                ..TransactionRepoModel::default()
1253            },
1254            TransactionRepoModel {
1255                id: "tx3".to_string(),
1256                relayer_id: relayer_model.id.clone(),
1257                status: TransactionStatus::Submitted,
1258                ..TransactionRepoModel::default()
1259            },
1260        ];
1261
1262        tx_repo
1263            .expect_find_by_status()
1264            .withf(|relayer_id, statuses| {
1265                relayer_id == "test-relayer-id"
1266                    && statuses
1267                        == [
1268                            TransactionStatus::Pending,
1269                            TransactionStatus::Sent,
1270                            TransactionStatus::Submitted,
1271                        ]
1272            })
1273            .returning(move |_, _| Ok(pending_transactions.clone()))
1274            .once();
1275
1276        job_producer
1277            .expect_produce_submit_transaction_job()
1278            .returning(|_, _| Box::pin(ready(Ok(()))))
1279            .times(3);
1280
1281        let relayer = EvmRelayer::new(
1282            relayer_model,
1283            signer,
1284            provider,
1285            create_test_evm_network(),
1286            Arc::new(relayer_repo),
1287            Arc::new(network_repo),
1288            Arc::new(tx_repo),
1289            Arc::new(counter),
1290            Arc::new(job_producer),
1291        )
1292        .unwrap();
1293
1294        let result = relayer.delete_pending_transactions().await.unwrap();
1295        assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 3);
1296        assert_eq!(result.failed_to_queue_transaction_ids.len(), 0);
1297        assert_eq!(result.total_processed, 3);
1298
1299        let expected_ids = vec!["tx1", "tx2", "tx3"];
1300        for id in expected_ids {
1301            assert!(result
1302                .queued_for_cancellation_transaction_ids
1303                .contains(&id.to_string()));
1304        }
1305    }
1306
1307    #[tokio::test]
1308    async fn test_delete_pending_transactions_partial_failures() {
1309        let (provider, relayer_repo, network_repo, mut tx_repo, mut job_producer, signer, counter) =
1310            setup_mocks();
1311        let relayer_model = create_test_relayer();
1312
1313        let pending_transactions = vec![
1314            TransactionRepoModel {
1315                id: "tx1".to_string(),
1316                relayer_id: relayer_model.id.clone(),
1317                status: TransactionStatus::Pending,
1318                ..TransactionRepoModel::default()
1319            },
1320            TransactionRepoModel {
1321                id: "tx2".to_string(),
1322                relayer_id: relayer_model.id.clone(),
1323                status: TransactionStatus::Sent,
1324                ..TransactionRepoModel::default()
1325            },
1326            TransactionRepoModel {
1327                id: "tx3".to_string(),
1328                relayer_id: relayer_model.id.clone(),
1329                status: TransactionStatus::Submitted,
1330                ..TransactionRepoModel::default()
1331            },
1332        ];
1333
1334        tx_repo
1335            .expect_find_by_status()
1336            .withf(|relayer_id, statuses| {
1337                relayer_id == "test-relayer-id"
1338                    && statuses
1339                        == [
1340                            TransactionStatus::Pending,
1341                            TransactionStatus::Sent,
1342                            TransactionStatus::Submitted,
1343                        ]
1344            })
1345            .returning(move |_, _| Ok(pending_transactions.clone()))
1346            .once();
1347
1348        // First job succeeds, second fails, third succeeds
1349        job_producer
1350            .expect_produce_submit_transaction_job()
1351            .returning(|_, _| Box::pin(ready(Ok(()))))
1352            .times(1);
1353        job_producer
1354            .expect_produce_submit_transaction_job()
1355            .returning(|_, _| {
1356                Box::pin(ready(Err(crate::jobs::JobProducerError::QueueError(
1357                    "Queue is full".to_string(),
1358                ))))
1359            })
1360            .times(1);
1361        job_producer
1362            .expect_produce_submit_transaction_job()
1363            .returning(|_, _| Box::pin(ready(Ok(()))))
1364            .times(1);
1365
1366        let relayer = EvmRelayer::new(
1367            relayer_model,
1368            signer,
1369            provider,
1370            create_test_evm_network(),
1371            Arc::new(relayer_repo),
1372            Arc::new(network_repo),
1373            Arc::new(tx_repo),
1374            Arc::new(counter),
1375            Arc::new(job_producer),
1376        )
1377        .unwrap();
1378
1379        let result = relayer.delete_pending_transactions().await.unwrap();
1380        assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 2);
1381        assert_eq!(result.failed_to_queue_transaction_ids.len(), 1);
1382        assert_eq!(result.total_processed, 3);
1383    }
1384
1385    #[tokio::test]
1386    async fn test_delete_pending_transactions_repository_error() {
1387        let (provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
1388            setup_mocks();
1389        let relayer_model = create_test_relayer();
1390
1391        tx_repo
1392            .expect_find_by_status()
1393            .withf(|relayer_id, statuses| {
1394                relayer_id == "test-relayer-id"
1395                    && statuses
1396                        == [
1397                            TransactionStatus::Pending,
1398                            TransactionStatus::Sent,
1399                            TransactionStatus::Submitted,
1400                        ]
1401            })
1402            .returning(|_, _| {
1403                Err(RepositoryError::Unknown(
1404                    "Database connection failed".to_string(),
1405                ))
1406            })
1407            .once();
1408
1409        let relayer = EvmRelayer::new(
1410            relayer_model,
1411            signer,
1412            provider,
1413            create_test_evm_network(),
1414            Arc::new(relayer_repo),
1415            Arc::new(network_repo),
1416            Arc::new(tx_repo),
1417            Arc::new(counter),
1418            Arc::new(job_producer),
1419        )
1420        .unwrap();
1421
1422        let result = relayer.delete_pending_transactions().await;
1423        assert!(result.is_err());
1424        match result.err().unwrap() {
1425            RelayerError::NetworkConfiguration(msg) => {
1426                assert!(msg.contains("Database connection failed"))
1427            }
1428            _ => panic!("Expected NetworkConfiguration error for repository failure"),
1429        }
1430    }
1431
1432    #[tokio::test]
1433    async fn test_delete_pending_transactions_all_failures() {
1434        let (provider, relayer_repo, network_repo, mut tx_repo, mut job_producer, signer, counter) =
1435            setup_mocks();
1436        let relayer_model = create_test_relayer();
1437
1438        let pending_transactions = vec![
1439            TransactionRepoModel {
1440                id: "tx1".to_string(),
1441                relayer_id: relayer_model.id.clone(),
1442                status: TransactionStatus::Pending,
1443                ..TransactionRepoModel::default()
1444            },
1445            TransactionRepoModel {
1446                id: "tx2".to_string(),
1447                relayer_id: relayer_model.id.clone(),
1448                status: TransactionStatus::Sent,
1449                ..TransactionRepoModel::default()
1450            },
1451        ];
1452
1453        tx_repo
1454            .expect_find_by_status()
1455            .withf(|relayer_id, statuses| {
1456                relayer_id == "test-relayer-id"
1457                    && statuses
1458                        == [
1459                            TransactionStatus::Pending,
1460                            TransactionStatus::Sent,
1461                            TransactionStatus::Submitted,
1462                        ]
1463            })
1464            .returning(move |_, _| Ok(pending_transactions.clone()))
1465            .once();
1466
1467        job_producer
1468            .expect_produce_submit_transaction_job()
1469            .returning(|_, _| {
1470                Box::pin(ready(Err(crate::jobs::JobProducerError::QueueError(
1471                    "Queue is full".to_string(),
1472                ))))
1473            })
1474            .times(2);
1475
1476        let relayer = EvmRelayer::new(
1477            relayer_model,
1478            signer,
1479            provider,
1480            create_test_evm_network(),
1481            Arc::new(relayer_repo),
1482            Arc::new(network_repo),
1483            Arc::new(tx_repo),
1484            Arc::new(counter),
1485            Arc::new(job_producer),
1486        )
1487        .unwrap();
1488
1489        let result = relayer.delete_pending_transactions().await.unwrap();
1490        assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 0);
1491        assert_eq!(result.failed_to_queue_transaction_ids.len(), 2);
1492        assert_eq!(result.total_processed, 2);
1493
1494        let expected_failed_ids = vec!["tx1", "tx2"];
1495        for id in expected_failed_ids {
1496            assert!(result
1497                .failed_to_queue_transaction_ids
1498                .contains(&id.to_string()));
1499        }
1500    }
1501
1502    #[tokio::test]
1503    async fn test_rpc_eth_get_balance() {
1504        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1505            setup_mocks();
1506        let relayer_model = create_test_relayer();
1507
1508        provider
1509            .expect_raw_request_dyn()
1510            .withf(|method, params| {
1511                method == "eth_getBalance"
1512                    && params.as_str()
1513                        == Some(r#"["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]"#)
1514            })
1515            .returning(|_, _| Box::pin(async { Ok(serde_json::json!("0xde0b6b3a7640000")) }));
1516
1517        let relayer = EvmRelayer::new(
1518            relayer_model,
1519            signer,
1520            provider,
1521            create_test_evm_network(),
1522            Arc::new(relayer_repo),
1523            Arc::new(network_repo),
1524            Arc::new(tx_repo),
1525            Arc::new(counter),
1526            Arc::new(job_producer),
1527        )
1528        .unwrap();
1529
1530        let request = JsonRpcRequest {
1531            jsonrpc: "2.0".to_string(),
1532            params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1533                method: "eth_getBalance".to_string(),
1534                params: r#"["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]"#.to_string(),
1535            }),
1536            id: Some(JsonRpcId::Number(1)),
1537        };
1538
1539        let response = relayer.rpc(request).await.unwrap();
1540        assert!(response.error.is_none());
1541        assert!(response.result.is_some());
1542
1543        if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
1544            assert_eq!(result, serde_json::json!("0xde0b6b3a7640000")); // 1 ETH in hex
1545        }
1546    }
1547
1548    #[tokio::test]
1549    async fn test_rpc_eth_block_number() {
1550        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1551            setup_mocks();
1552        let relayer_model = create_test_relayer();
1553
1554        provider
1555            .expect_raw_request_dyn()
1556            .withf(|method, params| method == "eth_blockNumber" && params.as_str() == Some("[]"))
1557            .returning(|_, _| Box::pin(async { Ok(serde_json::json!("0x3039")) }));
1558
1559        let relayer = EvmRelayer::new(
1560            relayer_model,
1561            signer,
1562            provider,
1563            create_test_evm_network(),
1564            Arc::new(relayer_repo),
1565            Arc::new(network_repo),
1566            Arc::new(tx_repo),
1567            Arc::new(counter),
1568            Arc::new(job_producer),
1569        )
1570        .unwrap();
1571
1572        let request = JsonRpcRequest {
1573            jsonrpc: "2.0".to_string(),
1574            params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1575                method: "eth_blockNumber".to_string(),
1576                params: "[]".to_string(),
1577            }),
1578            id: Some(JsonRpcId::Number(1)),
1579        };
1580
1581        let response = relayer.rpc(request).await.unwrap();
1582        assert!(response.error.is_none());
1583        assert!(response.result.is_some());
1584
1585        if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
1586            assert_eq!(result, serde_json::json!("0x3039")); // 12345 in hex
1587        }
1588    }
1589
1590    #[tokio::test]
1591    async fn test_rpc_unsupported_method() {
1592        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1593            setup_mocks();
1594        let relayer_model = create_test_relayer();
1595
1596        provider
1597            .expect_raw_request_dyn()
1598            .withf(|method, _| method == "eth_unsupportedMethod")
1599            .returning(|_, _| {
1600                Box::pin(async {
1601                    Err(ProviderError::Other(
1602                        "Unsupported method: eth_unsupportedMethod".to_string(),
1603                    ))
1604                })
1605            });
1606
1607        let relayer = EvmRelayer::new(
1608            relayer_model,
1609            signer,
1610            provider,
1611            create_test_evm_network(),
1612            Arc::new(relayer_repo),
1613            Arc::new(network_repo),
1614            Arc::new(tx_repo),
1615            Arc::new(counter),
1616            Arc::new(job_producer),
1617        )
1618        .unwrap();
1619
1620        let request = JsonRpcRequest {
1621            jsonrpc: "2.0".to_string(),
1622            params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1623                method: "eth_unsupportedMethod".to_string(),
1624                params: "[]".to_string(),
1625            }),
1626            id: Some(JsonRpcId::Number(1)),
1627        };
1628
1629        let response = relayer.rpc(request).await.unwrap();
1630        assert!(response.result.is_none());
1631        assert!(response.error.is_some());
1632
1633        let error = response.error.unwrap();
1634        assert_eq!(error.code, -32603); // RpcErrorCodes::INTERNAL_ERROR
1635    }
1636
1637    #[tokio::test]
1638    async fn test_rpc_invalid_params() {
1639        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1640            setup_mocks();
1641        let relayer_model = create_test_relayer();
1642
1643        provider
1644            .expect_raw_request_dyn()
1645            .withf(|method, params| method == "eth_getBalance" && params.as_str() == Some("[]"))
1646            .returning(|_, _| {
1647                Box::pin(async {
1648                    Err(ProviderError::Other(
1649                        "Missing address parameter".to_string(),
1650                    ))
1651                })
1652            });
1653
1654        let relayer = EvmRelayer::new(
1655            relayer_model,
1656            signer,
1657            provider,
1658            create_test_evm_network(),
1659            Arc::new(relayer_repo),
1660            Arc::new(network_repo),
1661            Arc::new(tx_repo),
1662            Arc::new(counter),
1663            Arc::new(job_producer),
1664        )
1665        .unwrap();
1666
1667        let request = JsonRpcRequest {
1668            jsonrpc: "2.0".to_string(),
1669            params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1670                method: "eth_getBalance".to_string(),
1671                params: "[]".to_string(), // Missing address parameter
1672            }),
1673            id: Some(JsonRpcId::Number(1)),
1674        };
1675
1676        let response = relayer.rpc(request).await.unwrap();
1677        assert!(response.result.is_none());
1678        assert!(response.error.is_some());
1679
1680        let error = response.error.unwrap();
1681        assert_eq!(error.code, -32603); // RpcErrorCodes::INTERNAL_ERROR
1682    }
1683
1684    #[tokio::test]
1685    async fn test_rpc_non_evm_request() {
1686        let (provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1687            setup_mocks();
1688        let relayer_model = create_test_relayer();
1689
1690        let relayer = EvmRelayer::new(
1691            relayer_model,
1692            signer,
1693            provider,
1694            create_test_evm_network(),
1695            Arc::new(relayer_repo),
1696            Arc::new(network_repo),
1697            Arc::new(tx_repo),
1698            Arc::new(counter),
1699            Arc::new(job_producer),
1700        )
1701        .unwrap();
1702
1703        let request = JsonRpcRequest {
1704            jsonrpc: "2.0".to_string(),
1705            params: NetworkRpcRequest::Solana(crate::models::SolanaRpcRequest::GetSupportedTokens(
1706                crate::models::GetSupportedTokensRequestParams {},
1707            )),
1708            id: Some(JsonRpcId::Number(1)),
1709        };
1710
1711        let response = relayer.rpc(request).await.unwrap();
1712        assert!(response.result.is_none());
1713        assert!(response.error.is_some());
1714
1715        let error = response.error.unwrap();
1716        assert_eq!(error.code, -32602); // RpcErrorCodes::INVALID_PARAMS
1717    }
1718
1719    #[tokio::test]
1720    async fn test_rpc_raw_request_with_array_params() {
1721        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1722            setup_mocks();
1723        let relayer_model = create_test_relayer();
1724
1725        provider
1726            .expect_raw_request_dyn()
1727            .withf(|method, params| {
1728                method == "eth_getTransactionByHash"
1729                    && params.as_array().is_some_and(|arr| {
1730                        arr.len() == 1 && arr[0].as_str() == Some("0x1234567890abcdef")
1731                    })
1732            })
1733            .returning(|_, _| {
1734                Box::pin(async {
1735                    Ok(serde_json::json!({
1736                        "hash": "0x1234567890abcdef",
1737                        "blockNumber": "0x1",
1738                        "gasUsed": "0x5208"
1739                    }))
1740                })
1741            });
1742
1743        let relayer = EvmRelayer::new(
1744            relayer_model,
1745            signer,
1746            provider,
1747            create_test_evm_network(),
1748            Arc::new(relayer_repo),
1749            Arc::new(network_repo),
1750            Arc::new(tx_repo),
1751            Arc::new(counter),
1752            Arc::new(job_producer),
1753        )
1754        .unwrap();
1755
1756        let request = JsonRpcRequest {
1757            jsonrpc: "2.0".to_string(),
1758            params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
1759                method: "eth_getTransactionByHash".to_string(),
1760                params: serde_json::json!(["0x1234567890abcdef"]),
1761            }),
1762            id: Some(JsonRpcId::Number(42)),
1763        };
1764
1765        let response = relayer.rpc(request).await.unwrap();
1766        assert!(response.error.is_none());
1767        assert!(response.result.is_some());
1768        assert_eq!(response.id, Some(JsonRpcId::Number(42)));
1769
1770        if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
1771            assert!(result.get("hash").is_some());
1772            assert!(result.get("blockNumber").is_some());
1773        }
1774    }
1775
1776    #[tokio::test]
1777    async fn test_rpc_raw_request_with_object_params() {
1778        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1779            setup_mocks();
1780        let relayer_model = create_test_relayer();
1781
1782        provider
1783            .expect_raw_request_dyn()
1784            .withf(|method, params| {
1785                method == "eth_call"
1786                    && params
1787                        .as_object()
1788                        .is_some_and(|obj| obj.contains_key("to") && obj.contains_key("data"))
1789            })
1790            .returning(|_, _| {
1791                Box::pin(async {
1792                    Ok(serde_json::json!(
1793                        "0x0000000000000000000000000000000000000000000000000000000000000001"
1794                    ))
1795                })
1796            });
1797
1798        let relayer = EvmRelayer::new(
1799            relayer_model,
1800            signer,
1801            provider,
1802            create_test_evm_network(),
1803            Arc::new(relayer_repo),
1804            Arc::new(network_repo),
1805            Arc::new(tx_repo),
1806            Arc::new(counter),
1807            Arc::new(job_producer),
1808        )
1809        .unwrap();
1810
1811        let request = JsonRpcRequest {
1812            jsonrpc: "2.0".to_string(),
1813            params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
1814                method: "eth_call".to_string(),
1815                params: serde_json::json!({
1816                    "to": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
1817                    "data": "0x70a08231000000000000000000000000742d35cc6634c0532925a3b844bc454e4438f44e"
1818                }),
1819            }),
1820            id: Some(JsonRpcId::Number(123)),
1821        };
1822
1823        let response = relayer.rpc(request).await.unwrap();
1824        assert!(response.error.is_none());
1825        assert!(response.result.is_some());
1826        assert_eq!(response.id, Some(JsonRpcId::Number(123)));
1827    }
1828
1829    #[tokio::test]
1830    async fn test_rpc_generic_request_with_empty_params() {
1831        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1832            setup_mocks();
1833        let relayer_model = create_test_relayer();
1834
1835        provider
1836            .expect_raw_request_dyn()
1837            .withf(|method, params| method == "net_version" && params.as_str() == Some("[]"))
1838            .returning(|_, _| Box::pin(async { Ok(serde_json::json!("1")) }));
1839
1840        let relayer = EvmRelayer::new(
1841            relayer_model,
1842            signer,
1843            provider,
1844            create_test_evm_network(),
1845            Arc::new(relayer_repo),
1846            Arc::new(network_repo),
1847            Arc::new(tx_repo),
1848            Arc::new(counter),
1849            Arc::new(job_producer),
1850        )
1851        .unwrap();
1852
1853        let request = JsonRpcRequest {
1854            jsonrpc: "2.0".to_string(),
1855            params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1856                method: "net_version".to_string(),
1857                params: "[]".to_string(),
1858            }),
1859            id: Some(JsonRpcId::Number(999)),
1860        };
1861
1862        let response = relayer.rpc(request).await.unwrap();
1863        assert!(response.error.is_none());
1864        assert!(response.result.is_some());
1865        assert_eq!(response.id, Some(JsonRpcId::Number(999)));
1866    }
1867
1868    #[tokio::test]
1869    async fn test_rpc_provider_invalid_address_error() {
1870        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1871            setup_mocks();
1872        let relayer_model = create_test_relayer();
1873
1874        provider.expect_raw_request_dyn().returning(|_, _| {
1875            Box::pin(async {
1876                Err(ProviderError::InvalidAddress(
1877                    "Invalid address format".to_string(),
1878                ))
1879            })
1880        });
1881
1882        let relayer = EvmRelayer::new(
1883            relayer_model,
1884            signer,
1885            provider,
1886            create_test_evm_network(),
1887            Arc::new(relayer_repo),
1888            Arc::new(network_repo),
1889            Arc::new(tx_repo),
1890            Arc::new(counter),
1891            Arc::new(job_producer),
1892        )
1893        .unwrap();
1894
1895        let request = JsonRpcRequest {
1896            jsonrpc: "2.0".to_string(),
1897            params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1898                method: "eth_getBalance".to_string(),
1899                params: r#"["invalid_address", "latest"]"#.to_string(),
1900            }),
1901            id: Some(JsonRpcId::Number(1)),
1902        };
1903
1904        let response = relayer.rpc(request).await.unwrap();
1905        assert!(response.result.is_none());
1906        assert!(response.error.is_some());
1907
1908        let error = response.error.unwrap();
1909        assert_eq!(error.code, -32602); // RpcErrorCodes::INVALID_PARAMS
1910    }
1911
1912    #[tokio::test]
1913    async fn test_rpc_provider_network_configuration_error() {
1914        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1915            setup_mocks();
1916        let relayer_model = create_test_relayer();
1917
1918        provider.expect_raw_request_dyn().returning(|_, _| {
1919            Box::pin(async {
1920                Err(ProviderError::NetworkConfiguration(
1921                    "Network not reachable".to_string(),
1922                ))
1923            })
1924        });
1925
1926        let relayer = EvmRelayer::new(
1927            relayer_model,
1928            signer,
1929            provider,
1930            create_test_evm_network(),
1931            Arc::new(relayer_repo),
1932            Arc::new(network_repo),
1933            Arc::new(tx_repo),
1934            Arc::new(counter),
1935            Arc::new(job_producer),
1936        )
1937        .unwrap();
1938
1939        let request = JsonRpcRequest {
1940            jsonrpc: "2.0".to_string(),
1941            params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1942                method: "eth_chainId".to_string(),
1943                params: "[]".to_string(),
1944            }),
1945            id: Some(JsonRpcId::Number(2)),
1946        };
1947
1948        let response = relayer.rpc(request).await.unwrap();
1949        assert!(response.result.is_none());
1950        assert!(response.error.is_some());
1951
1952        let error = response.error.unwrap();
1953        assert_eq!(error.code, -33004); // OpenZeppelinErrorCodes::NETWORK_CONFIGURATION
1954    }
1955
1956    #[tokio::test]
1957    async fn test_rpc_provider_timeout_error() {
1958        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1959            setup_mocks();
1960        let relayer_model = create_test_relayer();
1961
1962        provider
1963            .expect_raw_request_dyn()
1964            .returning(|_, _| Box::pin(async { Err(ProviderError::Timeout) }));
1965
1966        let relayer = EvmRelayer::new(
1967            relayer_model,
1968            signer,
1969            provider,
1970            create_test_evm_network(),
1971            Arc::new(relayer_repo),
1972            Arc::new(network_repo),
1973            Arc::new(tx_repo),
1974            Arc::new(counter),
1975            Arc::new(job_producer),
1976        )
1977        .unwrap();
1978
1979        let request = JsonRpcRequest {
1980            jsonrpc: "2.0".to_string(),
1981            params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
1982                method: "eth_blockNumber".to_string(),
1983                params: serde_json::json!([]),
1984            }),
1985            id: Some(JsonRpcId::Number(3)),
1986        };
1987
1988        let response = relayer.rpc(request).await.unwrap();
1989        assert!(response.result.is_none());
1990        assert!(response.error.is_some());
1991
1992        let error = response.error.unwrap();
1993        assert_eq!(error.code, -33000); // OpenZeppelinErrorCodes::TIMEOUT
1994    }
1995
1996    #[tokio::test]
1997    async fn test_rpc_provider_rate_limited_error() {
1998        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1999            setup_mocks();
2000        let relayer_model = create_test_relayer();
2001
2002        provider
2003            .expect_raw_request_dyn()
2004            .returning(|_, _| Box::pin(async { Err(ProviderError::RateLimited) }));
2005
2006        let relayer = EvmRelayer::new(
2007            relayer_model,
2008            signer,
2009            provider,
2010            create_test_evm_network(),
2011            Arc::new(relayer_repo),
2012            Arc::new(network_repo),
2013            Arc::new(tx_repo),
2014            Arc::new(counter),
2015            Arc::new(job_producer),
2016        )
2017        .unwrap();
2018
2019        let request = JsonRpcRequest {
2020            jsonrpc: "2.0".to_string(),
2021            params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2022                method: "eth_getBalance".to_string(),
2023                params: r#"["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]"#.to_string(),
2024            }),
2025            id: Some(JsonRpcId::Number(4)),
2026        };
2027
2028        let response = relayer.rpc(request).await.unwrap();
2029        assert!(response.result.is_none());
2030        assert!(response.error.is_some());
2031
2032        let error = response.error.unwrap();
2033        assert_eq!(error.code, -33001); // OpenZeppelinErrorCodes::RATE_LIMITED
2034    }
2035
2036    #[tokio::test]
2037    async fn test_rpc_provider_bad_gateway_error() {
2038        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2039            setup_mocks();
2040        let relayer_model = create_test_relayer();
2041
2042        provider
2043            .expect_raw_request_dyn()
2044            .returning(|_, _| Box::pin(async { Err(ProviderError::BadGateway) }));
2045
2046        let relayer = EvmRelayer::new(
2047            relayer_model,
2048            signer,
2049            provider,
2050            create_test_evm_network(),
2051            Arc::new(relayer_repo),
2052            Arc::new(network_repo),
2053            Arc::new(tx_repo),
2054            Arc::new(counter),
2055            Arc::new(job_producer),
2056        )
2057        .unwrap();
2058
2059        let request = JsonRpcRequest {
2060            jsonrpc: "2.0".to_string(),
2061            params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
2062                method: "eth_gasPrice".to_string(),
2063                params: serde_json::json!([]),
2064            }),
2065            id: Some(JsonRpcId::Number(5)),
2066        };
2067
2068        let response = relayer.rpc(request).await.unwrap();
2069        assert!(response.result.is_none());
2070        assert!(response.error.is_some());
2071
2072        let error = response.error.unwrap();
2073        assert_eq!(error.code, -33002); // OpenZeppelinErrorCodes::BAD_GATEWAY
2074    }
2075
2076    #[tokio::test]
2077    async fn test_rpc_provider_request_error() {
2078        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2079            setup_mocks();
2080        let relayer_model = create_test_relayer();
2081
2082        provider.expect_raw_request_dyn().returning(|_, _| {
2083            Box::pin(async {
2084                Err(ProviderError::RequestError {
2085                    error: "Bad request".to_string(),
2086                    status_code: 400,
2087                })
2088            })
2089        });
2090
2091        let relayer = EvmRelayer::new(
2092            relayer_model,
2093            signer,
2094            provider,
2095            create_test_evm_network(),
2096            Arc::new(relayer_repo),
2097            Arc::new(network_repo),
2098            Arc::new(tx_repo),
2099            Arc::new(counter),
2100            Arc::new(job_producer),
2101        )
2102        .unwrap();
2103
2104        let request = JsonRpcRequest {
2105            jsonrpc: "2.0".to_string(),
2106            params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2107                method: "invalid_method".to_string(),
2108                params: "{}".to_string(),
2109            }),
2110            id: Some(JsonRpcId::Number(6)),
2111        };
2112
2113        let response = relayer.rpc(request).await.unwrap();
2114        assert!(response.result.is_none());
2115        assert!(response.error.is_some());
2116
2117        let error = response.error.unwrap();
2118        assert_eq!(error.code, -33003); // OpenZeppelinErrorCodes::REQUEST_ERROR
2119    }
2120
2121    #[tokio::test]
2122    async fn test_rpc_provider_other_error() {
2123        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2124            setup_mocks();
2125        let relayer_model = create_test_relayer();
2126
2127        provider.expect_raw_request_dyn().returning(|_, _| {
2128            Box::pin(async {
2129                Err(ProviderError::Other(
2130                    "Unexpected error occurred".to_string(),
2131                ))
2132            })
2133        });
2134
2135        let relayer = EvmRelayer::new(
2136            relayer_model,
2137            signer,
2138            provider,
2139            create_test_evm_network(),
2140            Arc::new(relayer_repo),
2141            Arc::new(network_repo),
2142            Arc::new(tx_repo),
2143            Arc::new(counter),
2144            Arc::new(job_producer),
2145        )
2146        .unwrap();
2147
2148        let request = JsonRpcRequest {
2149            jsonrpc: "2.0".to_string(),
2150            params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
2151                method: "eth_getBalance".to_string(),
2152                params: serde_json::json!(["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]),
2153            }),
2154            id: Some(JsonRpcId::Number(7)),
2155        };
2156
2157        let response = relayer.rpc(request).await.unwrap();
2158        assert!(response.result.is_none());
2159        assert!(response.error.is_some());
2160
2161        let error = response.error.unwrap();
2162        assert_eq!(error.code, -32603); // RpcErrorCodes::INTERNAL_ERROR
2163    }
2164
2165    #[tokio::test]
2166    async fn test_rpc_response_preserves_request_id() {
2167        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2168            setup_mocks();
2169        let relayer_model = create_test_relayer();
2170
2171        provider
2172            .expect_raw_request_dyn()
2173            .returning(|_, _| Box::pin(async { Ok(serde_json::json!("0x1")) }));
2174
2175        let relayer = EvmRelayer::new(
2176            relayer_model,
2177            signer,
2178            provider,
2179            create_test_evm_network(),
2180            Arc::new(relayer_repo),
2181            Arc::new(network_repo),
2182            Arc::new(tx_repo),
2183            Arc::new(counter),
2184            Arc::new(job_producer),
2185        )
2186        .unwrap();
2187
2188        let request_id = u64::MAX;
2189        let request = JsonRpcRequest {
2190            jsonrpc: "2.0".to_string(),
2191            params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2192                method: "eth_chainId".to_string(),
2193                params: "[]".to_string(),
2194            }),
2195            id: Some(JsonRpcId::Number(request_id as i64)),
2196        };
2197
2198        let response = relayer.rpc(request).await.unwrap();
2199        assert_eq!(response.id, Some(JsonRpcId::Number(request_id as i64)));
2200        assert_eq!(response.jsonrpc, "2.0");
2201    }
2202
2203    #[tokio::test]
2204    async fn test_rpc_handles_complex_json_response() {
2205        let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2206            setup_mocks();
2207        let relayer_model = create_test_relayer();
2208
2209        let complex_response = serde_json::json!({
2210            "number": "0x1b4",
2211            "hash": "0xdc0818cf78f21a8e70579cb46a43643f78291264dda342ae31049421c82d21ae",
2212            "parentHash": "0xe99e022112df268ce40b8b654759b4f39c3cc1b8c86b2f4c7da48ba6d8a6ae8b",
2213            "transactions": [
2214                {
2215                    "hash": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060",
2216                    "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d",
2217                    "to": "0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb",
2218                    "value": "0xf3dbb76162000"
2219                }
2220            ],
2221            "gasUsed": "0x5208"
2222        });
2223
2224        provider.expect_raw_request_dyn().returning(move |_, _| {
2225            let response = complex_response.clone();
2226            Box::pin(async move { Ok(response) })
2227        });
2228
2229        let relayer = EvmRelayer::new(
2230            relayer_model,
2231            signer,
2232            provider,
2233            create_test_evm_network(),
2234            Arc::new(relayer_repo),
2235            Arc::new(network_repo),
2236            Arc::new(tx_repo),
2237            Arc::new(counter),
2238            Arc::new(job_producer),
2239        )
2240        .unwrap();
2241
2242        let request = JsonRpcRequest {
2243            jsonrpc: "2.0".to_string(),
2244            params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
2245                method: "eth_getBlockByNumber".to_string(),
2246                params: serde_json::json!(["0x1b4", true]),
2247            }),
2248            id: Some(JsonRpcId::Number(8)),
2249        };
2250
2251        let response = relayer.rpc(request).await.unwrap();
2252        assert!(response.error.is_none());
2253        assert!(response.result.is_some());
2254
2255        if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
2256            assert!(result.get("transactions").is_some());
2257            assert!(result.get("hash").is_some());
2258            assert!(result.get("gasUsed").is_some());
2259        }
2260    }
2261}