1use std::sync::Arc;
28
29use crate::{
30 constants::EVM_SMALLEST_UNIT_NAME,
31 domain::{
32 relayer::{Relayer, RelayerError},
33 BalanceResponse, SignDataRequest, SignDataResponse, SignTransactionExternalResponse,
34 SignTransactionRequest, SignTypedDataRequest,
35 },
36 jobs::{JobProducerTrait, TransactionRequest},
37 models::{
38 produce_relayer_disabled_payload, DeletePendingTransactionsResponse, EvmNetwork,
39 JsonRpcRequest, JsonRpcResponse, NetworkRepoModel, NetworkRpcRequest, NetworkRpcResult,
40 NetworkTransactionRequest, NetworkType, RelayerRepoModel, RelayerStatus, RepositoryError,
41 RpcErrorCodes, TransactionRepoModel, TransactionStatus,
42 },
43 repositories::{NetworkRepository, RelayerRepository, Repository, TransactionRepository},
44 services::{
45 DataSignerTrait, EvmProvider, EvmProviderTrait, EvmSigner, TransactionCounterService,
46 TransactionCounterServiceTrait,
47 },
48};
49use async_trait::async_trait;
50use eyre::Result;
51use log::{debug, info, warn};
52
53use super::{
54 create_error_response, create_success_response, map_provider_error, EvmTransactionValidator,
55};
56
57#[allow(dead_code)]
58pub struct EvmRelayer<P, RR, NR, TR, J, S, TCS>
59where
60 P: EvmProviderTrait + Send + Sync,
61 RR: Repository<RelayerRepoModel, String> + RelayerRepository + Send + Sync + 'static,
62 NR: NetworkRepository + Repository<NetworkRepoModel, String> + Send + Sync + 'static,
63 TR: Repository<TransactionRepoModel, String> + TransactionRepository + Send + Sync + 'static,
64 J: JobProducerTrait + Send + Sync + 'static,
65 S: DataSignerTrait + Send + Sync + 'static,
66{
67 relayer: RelayerRepoModel,
68 signer: S,
69 network: EvmNetwork,
70 provider: P,
71 relayer_repository: Arc<RR>,
72 network_repository: Arc<NR>,
73 transaction_repository: Arc<TR>,
74 job_producer: Arc<J>,
75 transaction_counter_service: Arc<TCS>,
76}
77
78#[allow(clippy::too_many_arguments)]
79impl<P, RR, NR, TR, J, S, TCS> EvmRelayer<P, RR, NR, TR, J, S, TCS>
80where
81 P: EvmProviderTrait + Send + Sync,
82 RR: Repository<RelayerRepoModel, String> + RelayerRepository + Send + Sync + 'static,
83 NR: NetworkRepository + Repository<NetworkRepoModel, String> + Send + Sync + 'static,
84 TR: Repository<TransactionRepoModel, String> + TransactionRepository + Send + Sync + 'static,
85 J: JobProducerTrait + Send + Sync + 'static,
86 S: DataSignerTrait + Send + Sync + 'static,
87 TCS: TransactionCounterServiceTrait + Send + Sync + 'static,
88{
89 pub fn new(
106 relayer: RelayerRepoModel,
107 signer: S,
108 provider: P,
109 network: EvmNetwork,
110 relayer_repository: Arc<RR>,
111 network_repository: Arc<NR>,
112 transaction_repository: Arc<TR>,
113 transaction_counter_service: Arc<TCS>,
114 job_producer: Arc<J>,
115 ) -> Result<Self, RelayerError> {
116 Ok(Self {
117 relayer,
118 signer,
119 network,
120 provider,
121 relayer_repository,
122 network_repository,
123 transaction_repository,
124 transaction_counter_service,
125 job_producer,
126 })
127 }
128
129 async fn sync_nonce(&self) -> Result<(), RelayerError> {
135 let on_chain_nonce = self
136 .provider
137 .get_transaction_count(&self.relayer.address)
138 .await
139 .map_err(|e| RelayerError::ProviderError(e.to_string()))?;
140
141 let transaction_counter_nonce = self
142 .transaction_counter_service
143 .get()
144 .await
145 .unwrap_or(Some(0))
146 .unwrap_or(0);
147
148 let nonce = std::cmp::max(on_chain_nonce, transaction_counter_nonce);
149
150 debug!(
151 "Relayer: {} - On-chain nonce: {}, Transaction counter nonce: {}",
152 self.relayer.id, on_chain_nonce, transaction_counter_nonce
153 );
154
155 info!("Setting nonce: {} for relayer: {}", nonce, self.relayer.id);
156
157 self.transaction_counter_service.set(nonce).await?;
158
159 Ok(())
160 }
161
162 async fn validate_rpc(&self) -> Result<(), RelayerError> {
168 self.provider
169 .health_check()
170 .await
171 .map_err(|e| RelayerError::ProviderError(e.to_string()))?;
172
173 Ok(())
174 }
175
176 async fn cancel_transaction_via_job(
186 &self,
187 transaction: TransactionRepoModel,
188 ) -> Result<(), RelayerError> {
189 use crate::jobs::TransactionSend;
190
191 let cancel_job = TransactionSend::cancel(
192 transaction.id.clone(),
193 transaction.relayer_id.clone(),
194 "Cancelled via delete_pending_transactions".to_string(),
195 );
196
197 self.job_producer
198 .produce_submit_transaction_job(cancel_job, None)
199 .await
200 .map_err(RelayerError::from)?;
201
202 Ok(())
203 }
204}
205
206pub type DefaultEvmRelayer<J, T, RR, NR, TCR> =
208 EvmRelayer<EvmProvider, RR, NR, T, J, EvmSigner, TransactionCounterService<TCR>>;
209
210#[async_trait]
211impl<P, RR, NR, TR, J, S, TCS> Relayer for EvmRelayer<P, RR, NR, TR, J, S, TCS>
212where
213 P: EvmProviderTrait + Send + Sync,
214 RR: Repository<RelayerRepoModel, String> + RelayerRepository + Send + Sync + 'static,
215 NR: NetworkRepository + Repository<NetworkRepoModel, String> + Send + Sync + 'static,
216 TR: Repository<TransactionRepoModel, String> + TransactionRepository + Send + Sync + 'static,
217 J: JobProducerTrait + Send + Sync + 'static,
218 S: DataSignerTrait + Send + Sync + 'static,
219 TCS: TransactionCounterServiceTrait + Send + Sync + 'static,
220{
221 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 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 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 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 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 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 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 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 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 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 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 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 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 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 async fn sign_transaction(
561 &self,
562 _request: &SignTransactionRequest,
563 ) -> Result<SignTransactionExternalResponse, RelayerError> {
564 Err(RelayerError::NotSupported(
565 "Transaction signing not supported for EVM".to_string(),
566 ))
567 }
568}
569
570#[cfg(test)]
571mod tests {
572 use super::*;
573 use crate::{
574 jobs::MockJobProducerTrait,
575 models::{
576 EvmRpcRequest, EvmRpcResult, JsonRpcId, NetworkRepoModel, NetworkType,
577 RelayerEvmPolicy, RelayerNetworkPolicy, RepositoryError, SignerError,
578 TransactionStatus, U256,
579 },
580 repositories::{MockNetworkRepository, MockRelayerRepository, MockTransactionRepository},
581 services::{MockEvmProviderTrait, MockTransactionCounterServiceTrait, ProviderError},
582 };
583 use mockall::predicate::*;
584 use std::future::ready;
585
586 mockall::mock! {
587 pub DataSigner {}
588
589 #[async_trait]
590 impl DataSignerTrait for DataSigner {
591 async fn sign_data(&self, request: SignDataRequest) -> Result<SignDataResponse, SignerError>;
592 async fn sign_typed_data(&self, request: SignTypedDataRequest) -> Result<SignDataResponse, SignerError>;
593 }
594 }
595
596 fn create_test_evm_network() -> EvmNetwork {
597 EvmNetwork {
598 network: "mainnet".to_string(),
599 rpc_urls: vec!["https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY".to_string()],
600 explorer_urls: None,
601 average_blocktime_ms: 12000,
602 is_testnet: false,
603 tags: vec!["mainnet".to_string()],
604 chain_id: 1,
605 required_confirmations: 1,
606 features: vec!["eip1559".to_string()],
607 symbol: "ETH".to_string(),
608 }
609 }
610
611 fn create_test_network_repo_model() -> NetworkRepoModel {
612 use crate::config::{EvmNetworkConfig, NetworkConfigCommon};
613
614 let config = EvmNetworkConfig {
615 common: NetworkConfigCommon {
616 network: "mainnet".to_string(),
617 from: None,
618 rpc_urls: Some(vec![
619 "https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY".to_string()
620 ]),
621 explorer_urls: None,
622 average_blocktime_ms: Some(12000),
623 is_testnet: Some(false),
624 tags: Some(vec!["mainnet".to_string()]),
625 },
626 chain_id: Some(1),
627 required_confirmations: Some(1),
628 features: Some(vec!["eip1559".to_string()]),
629 symbol: Some("ETH".to_string()),
630 };
631
632 NetworkRepoModel::new_evm(config)
633 }
634
635 fn create_test_relayer() -> RelayerRepoModel {
636 RelayerRepoModel {
637 id: "test-relayer-id".to_string(),
638 name: "Test Relayer".to_string(),
639 network: "mainnet".to_string(), address: "0xSender".to_string(),
641 paused: false,
642 system_disabled: false,
643 signer_id: "test-signer-id".to_string(),
644 notification_id: Some("test-notification-id".to_string()),
645 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
646 min_balance: Some(100000000000000000u128), whitelist_receivers: Some(vec!["0xRecipient".to_string()]),
648 gas_price_cap: Some(100000000000), eip1559_pricing: Some(true),
650 private_transactions: Some(false),
651 gas_limit_estimation: Some(true),
652 }),
653 network_type: NetworkType::Evm,
654 custom_rpc_urls: None,
655 }
656 }
657
658 fn setup_mocks() -> (
659 MockEvmProviderTrait,
660 MockRelayerRepository,
661 MockNetworkRepository,
662 MockTransactionRepository,
663 MockJobProducerTrait,
664 MockDataSigner,
665 MockTransactionCounterServiceTrait,
666 ) {
667 (
668 MockEvmProviderTrait::new(),
669 MockRelayerRepository::new(),
670 MockNetworkRepository::new(),
671 MockTransactionRepository::new(),
672 MockJobProducerTrait::new(),
673 MockDataSigner::new(),
674 MockTransactionCounterServiceTrait::new(),
675 )
676 }
677
678 #[tokio::test]
679 async fn test_get_balance() {
680 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
681 setup_mocks();
682 let relayer_model = create_test_relayer();
683
684 provider
685 .expect_get_balance()
686 .with(eq("0xSender"))
687 .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64))))); let relayer = EvmRelayer::new(
690 relayer_model,
691 signer,
692 provider,
693 create_test_evm_network(),
694 Arc::new(relayer_repo),
695 Arc::new(network_repo),
696 Arc::new(tx_repo),
697 Arc::new(counter),
698 Arc::new(job_producer),
699 )
700 .unwrap();
701
702 let balance = relayer.get_balance().await.unwrap();
703 assert_eq!(balance.balance, 1000000000000000000u128);
704 assert_eq!(balance.unit, EVM_SMALLEST_UNIT_NAME);
705 }
706
707 #[tokio::test]
708 async fn test_process_transaction_request() {
709 let (
710 provider,
711 relayer_repo,
712 mut network_repo,
713 mut tx_repo,
714 mut job_producer,
715 signer,
716 counter,
717 ) = setup_mocks();
718 let relayer_model = create_test_relayer();
719
720 let network_tx = NetworkTransactionRequest::Evm(crate::models::EvmTransactionRequest {
721 to: Some("0xRecipient".to_string()),
722 value: U256::from(1000000000000000000u64),
723 data: Some("0xData".to_string()),
724 gas_limit: Some(21000),
725 gas_price: Some(20000000000),
726 max_fee_per_gas: None,
727 max_priority_fee_per_gas: None,
728 speed: None,
729 valid_until: None,
730 });
731
732 network_repo
733 .expect_get_by_name()
734 .with(eq(NetworkType::Evm), eq("mainnet"))
735 .returning(|_, _| Ok(Some(create_test_network_repo_model())));
736
737 tx_repo.expect_create().returning(Ok);
738 job_producer
739 .expect_produce_transaction_request_job()
740 .returning(|_, _| Box::pin(ready(Ok(()))));
741
742 let relayer = EvmRelayer::new(
743 relayer_model,
744 signer,
745 provider,
746 create_test_evm_network(),
747 Arc::new(relayer_repo),
748 Arc::new(network_repo),
749 Arc::new(tx_repo),
750 Arc::new(counter),
751 Arc::new(job_producer),
752 )
753 .unwrap();
754
755 let result = relayer.process_transaction_request(network_tx).await;
756 assert!(result.is_ok());
757 }
758
759 #[tokio::test]
760 async fn test_validate_min_balance_sufficient() {
761 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
762 setup_mocks();
763 let relayer_model = create_test_relayer();
764
765 provider
766 .expect_get_balance()
767 .returning(|_| Box::pin(ready(Ok(U256::from(200000000000000000u64))))); let relayer = EvmRelayer::new(
770 relayer_model,
771 signer,
772 provider,
773 create_test_evm_network(),
774 Arc::new(relayer_repo),
775 Arc::new(network_repo),
776 Arc::new(tx_repo),
777 Arc::new(counter),
778 Arc::new(job_producer),
779 )
780 .unwrap();
781
782 let result = relayer.validate_min_balance().await;
783 assert!(result.is_ok());
784 }
785
786 #[tokio::test]
787 async fn test_validate_min_balance_insufficient() {
788 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
789 setup_mocks();
790 let relayer_model = create_test_relayer();
791
792 provider
793 .expect_get_balance()
794 .returning(|_| Box::pin(ready(Ok(U256::from(50000000000000000u64))))); let relayer = EvmRelayer::new(
797 relayer_model,
798 signer,
799 provider,
800 create_test_evm_network(),
801 Arc::new(relayer_repo),
802 Arc::new(network_repo),
803 Arc::new(tx_repo),
804 Arc::new(counter),
805 Arc::new(job_producer),
806 )
807 .unwrap();
808
809 let result = relayer.validate_min_balance().await;
810 assert!(matches!(
811 result,
812 Err(RelayerError::InsufficientBalanceError(_))
813 ));
814 }
815
816 #[tokio::test]
817 async fn test_sync_nonce() {
818 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, mut counter) =
819 setup_mocks();
820 let relayer_model = create_test_relayer();
821
822 provider
823 .expect_get_transaction_count()
824 .returning(|_| Box::pin(ready(Ok(42u64))));
825
826 counter
827 .expect_set()
828 .returning(|_nonce| Box::pin(ready(Ok(()))));
829
830 counter
831 .expect_get()
832 .returning(|| Box::pin(ready(Ok(Some(42u64)))));
833
834 let relayer = EvmRelayer::new(
835 relayer_model,
836 signer,
837 provider,
838 create_test_evm_network(),
839 Arc::new(relayer_repo),
840 Arc::new(network_repo),
841 Arc::new(tx_repo),
842 Arc::new(counter),
843 Arc::new(job_producer),
844 )
845 .unwrap();
846
847 let result = relayer.sync_nonce().await;
848 assert!(result.is_ok());
849 }
850
851 #[tokio::test]
852 async fn test_sync_nonce_lower_on_chain_nonce() {
853 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, mut counter) =
854 setup_mocks();
855 let relayer_model = create_test_relayer();
856
857 provider
858 .expect_get_transaction_count()
859 .returning(|_| Box::pin(ready(Ok(40u64))));
860
861 counter
862 .expect_set()
863 .with(eq(42u64))
864 .returning(|_nonce| Box::pin(ready(Ok(()))));
865
866 counter
867 .expect_get()
868 .returning(|| Box::pin(ready(Ok(Some(42u64)))));
869
870 let relayer = EvmRelayer::new(
871 relayer_model,
872 signer,
873 provider,
874 create_test_evm_network(),
875 Arc::new(relayer_repo),
876 Arc::new(network_repo),
877 Arc::new(tx_repo),
878 Arc::new(counter),
879 Arc::new(job_producer),
880 )
881 .unwrap();
882
883 let result = relayer.sync_nonce().await;
884 assert!(result.is_ok());
885 }
886
887 #[tokio::test]
888 async fn test_sync_nonce_lower_transaction_counter_nonce() {
889 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, mut counter) =
890 setup_mocks();
891 let relayer_model = create_test_relayer();
892
893 provider
894 .expect_get_transaction_count()
895 .returning(|_| Box::pin(ready(Ok(42u64))));
896
897 counter
898 .expect_set()
899 .with(eq(42u64))
900 .returning(|_nonce| Box::pin(ready(Ok(()))));
901
902 counter
903 .expect_get()
904 .returning(|| Box::pin(ready(Ok(Some(40u64)))));
905
906 let relayer = EvmRelayer::new(
907 relayer_model,
908 signer,
909 provider,
910 create_test_evm_network(),
911 Arc::new(relayer_repo),
912 Arc::new(network_repo),
913 Arc::new(tx_repo),
914 Arc::new(counter),
915 Arc::new(job_producer),
916 )
917 .unwrap();
918
919 let result = relayer.sync_nonce().await;
920 assert!(result.is_ok());
921 }
922
923 #[tokio::test]
924 async fn test_validate_rpc() {
925 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
926 setup_mocks();
927 let relayer_model = create_test_relayer();
928
929 provider
930 .expect_health_check()
931 .returning(|| Box::pin(ready(Ok(true))));
932
933 let relayer = EvmRelayer::new(
934 relayer_model,
935 signer,
936 provider,
937 create_test_evm_network(),
938 Arc::new(relayer_repo),
939 Arc::new(network_repo),
940 Arc::new(tx_repo),
941 Arc::new(counter),
942 Arc::new(job_producer),
943 )
944 .unwrap();
945
946 let result = relayer.validate_rpc().await;
947 assert!(result.is_ok());
948 }
949
950 #[tokio::test]
951 async fn test_get_status_success() {
952 let (mut provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
953 setup_mocks();
954 let relayer_model = create_test_relayer();
955
956 provider
957 .expect_get_transaction_count()
958 .returning(|_| Box::pin(ready(Ok(10u64))))
959 .once();
960 provider
961 .expect_get_balance()
962 .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64)))))
963 .once();
964
965 let pending_txs_clone = vec![];
966 tx_repo
967 .expect_find_by_status()
968 .withf(|relayer_id, statuses| {
969 relayer_id == "test-relayer-id"
970 && statuses == [TransactionStatus::Pending, TransactionStatus::Submitted]
971 })
972 .returning(move |_, _| {
973 Ok(pending_txs_clone.clone()) as Result<Vec<TransactionRepoModel>, RepositoryError>
974 })
975 .once();
976
977 let confirmed_txs_clone = vec![
978 TransactionRepoModel {
979 id: "tx1".to_string(),
980 relayer_id: relayer_model.id.clone(),
981 status: TransactionStatus::Confirmed,
982 confirmed_at: Some("2023-01-01T12:00:00Z".to_string()),
983 ..TransactionRepoModel::default()
984 },
985 TransactionRepoModel {
986 id: "tx2".to_string(),
987 relayer_id: relayer_model.id.clone(),
988 status: TransactionStatus::Confirmed,
989 confirmed_at: Some("2023-01-01T10:00:00Z".to_string()),
990 ..TransactionRepoModel::default()
991 },
992 ];
993 tx_repo
994 .expect_find_by_status()
995 .withf(|relayer_id, statuses| {
996 relayer_id == "test-relayer-id" && statuses == [TransactionStatus::Confirmed]
997 })
998 .returning(move |_, _| {
999 Ok(confirmed_txs_clone.clone())
1000 as Result<Vec<TransactionRepoModel>, RepositoryError>
1001 })
1002 .once();
1003
1004 let relayer = EvmRelayer::new(
1005 relayer_model.clone(),
1006 signer,
1007 provider,
1008 create_test_evm_network(),
1009 Arc::new(relayer_repo),
1010 Arc::new(network_repo),
1011 Arc::new(tx_repo),
1012 Arc::new(counter),
1013 Arc::new(job_producer),
1014 )
1015 .unwrap();
1016
1017 let status = relayer.get_status().await.unwrap();
1018
1019 match status {
1020 RelayerStatus::Evm {
1021 balance,
1022 pending_transactions_count,
1023 last_confirmed_transaction_timestamp,
1024 system_disabled,
1025 paused,
1026 nonce,
1027 } => {
1028 assert_eq!(balance, "1000000000000000000");
1029 assert_eq!(pending_transactions_count, 0);
1030 assert_eq!(
1031 last_confirmed_transaction_timestamp,
1032 Some("2023-01-01T12:00:00Z".to_string())
1033 );
1034 assert_eq!(system_disabled, relayer_model.system_disabled);
1035 assert_eq!(paused, relayer_model.paused);
1036 assert_eq!(nonce, "10");
1037 }
1038 _ => panic!("Expected EVM RelayerStatus"),
1039 }
1040 }
1041
1042 #[tokio::test]
1043 async fn test_get_status_provider_nonce_error() {
1044 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1045 setup_mocks();
1046 let relayer_model = create_test_relayer();
1047
1048 provider.expect_get_transaction_count().returning(|_| {
1049 Box::pin(ready(Err(ProviderError::Other(
1050 "Nonce fetch failed".to_string(),
1051 ))))
1052 });
1053
1054 let relayer = EvmRelayer::new(
1055 relayer_model.clone(),
1056 signer,
1057 provider,
1058 create_test_evm_network(),
1059 Arc::new(relayer_repo),
1060 Arc::new(network_repo),
1061 Arc::new(tx_repo),
1062 Arc::new(counter),
1063 Arc::new(job_producer),
1064 )
1065 .unwrap();
1066
1067 let result = relayer.get_status().await;
1068 assert!(result.is_err());
1069 match result.err().unwrap() {
1070 RelayerError::ProviderError(msg) => assert!(msg.contains("Failed to get nonce")),
1071 _ => panic!("Expected ProviderError for nonce failure"),
1072 }
1073 }
1074
1075 #[tokio::test]
1076 async fn test_get_status_repository_pending_error() {
1077 let (mut provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
1078 setup_mocks();
1079 let relayer_model = create_test_relayer();
1080
1081 provider
1082 .expect_get_transaction_count()
1083 .returning(|_| Box::pin(ready(Ok(10u64))));
1084 provider
1085 .expect_get_balance()
1086 .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64)))));
1087
1088 tx_repo
1089 .expect_find_by_status()
1090 .withf(|relayer_id, statuses| {
1091 relayer_id == "test-relayer-id"
1092 && statuses == [TransactionStatus::Pending, TransactionStatus::Submitted]
1093 })
1094 .returning(|_, _| {
1095 Err(RepositoryError::Unknown("DB down".to_string()))
1096 as Result<Vec<TransactionRepoModel>, RepositoryError>
1097 })
1098 .once();
1099
1100 let relayer = EvmRelayer::new(
1101 relayer_model.clone(),
1102 signer,
1103 provider,
1104 create_test_evm_network(),
1105 Arc::new(relayer_repo),
1106 Arc::new(network_repo),
1107 Arc::new(tx_repo),
1108 Arc::new(counter),
1109 Arc::new(job_producer),
1110 )
1111 .unwrap();
1112
1113 let result = relayer.get_status().await;
1114 assert!(result.is_err());
1115 match result.err().unwrap() {
1116 RelayerError::NetworkConfiguration(msg) => assert!(msg.contains("DB down")),
1118 _ => panic!("Expected NetworkConfiguration error for repo failure"),
1119 }
1120 }
1121
1122 #[tokio::test]
1123 async fn test_get_status_no_confirmed_transactions() {
1124 let (mut provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
1125 setup_mocks();
1126 let relayer_model = create_test_relayer();
1127
1128 provider
1129 .expect_get_transaction_count()
1130 .returning(|_| Box::pin(ready(Ok(10u64))));
1131 provider
1132 .expect_get_balance()
1133 .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64)))));
1134 provider
1135 .expect_health_check()
1136 .returning(|| Box::pin(ready(Ok(true))));
1137
1138 let pending_txs_empty_clone = vec![];
1139 tx_repo
1140 .expect_find_by_status()
1141 .withf(|relayer_id, statuses| {
1142 relayer_id == "test-relayer-id"
1143 && statuses == [TransactionStatus::Pending, TransactionStatus::Submitted]
1144 })
1145 .returning(move |_, _| {
1146 Ok(pending_txs_empty_clone.clone())
1147 as Result<Vec<TransactionRepoModel>, RepositoryError>
1148 })
1149 .once();
1150
1151 let confirmed_txs_empty_clone = vec![];
1152 tx_repo
1153 .expect_find_by_status()
1154 .withf(|relayer_id, statuses| {
1155 relayer_id == "test-relayer-id" && statuses == [TransactionStatus::Confirmed]
1156 })
1157 .returning(move |_, _| {
1158 Ok(confirmed_txs_empty_clone.clone())
1159 as Result<Vec<TransactionRepoModel>, RepositoryError>
1160 })
1161 .once();
1162
1163 let relayer = EvmRelayer::new(
1164 relayer_model.clone(),
1165 signer,
1166 provider,
1167 create_test_evm_network(),
1168 Arc::new(relayer_repo),
1169 Arc::new(network_repo),
1170 Arc::new(tx_repo),
1171 Arc::new(counter),
1172 Arc::new(job_producer),
1173 )
1174 .unwrap();
1175
1176 let status = relayer.get_status().await.unwrap();
1177 match status {
1178 RelayerStatus::Evm {
1179 balance,
1180 pending_transactions_count,
1181 last_confirmed_transaction_timestamp,
1182 system_disabled,
1183 paused,
1184 nonce,
1185 } => {
1186 assert_eq!(balance, "1000000000000000000");
1187 assert_eq!(pending_transactions_count, 0);
1188 assert_eq!(last_confirmed_transaction_timestamp, None);
1189 assert_eq!(system_disabled, relayer_model.system_disabled);
1190 assert_eq!(paused, relayer_model.paused);
1191 assert_eq!(nonce, "10");
1192 }
1193 _ => panic!("Expected EVM RelayerStatus"),
1194 }
1195 }
1196
1197 #[tokio::test]
1198 async fn test_cancel_transaction_via_job_success() {
1199 let (provider, relayer_repo, network_repo, tx_repo, mut job_producer, signer, counter) =
1200 setup_mocks();
1201 let relayer_model = create_test_relayer();
1202
1203 let test_transaction = TransactionRepoModel {
1204 id: "test-tx-id".to_string(),
1205 relayer_id: relayer_model.id.clone(),
1206 status: TransactionStatus::Pending,
1207 ..TransactionRepoModel::default()
1208 };
1209
1210 job_producer
1211 .expect_produce_submit_transaction_job()
1212 .withf(|job, delay| {
1213 matches!(job.command, crate::jobs::TransactionCommand::Cancel { ref reason }
1214 if job.transaction_id == "test-tx-id"
1215 && job.relayer_id == "test-relayer-id"
1216 && reason == "Cancelled via delete_pending_transactions")
1217 && delay.is_none()
1218 })
1219 .returning(|_, _| Box::pin(ready(Ok(()))))
1220 .once();
1221
1222 let relayer = EvmRelayer::new(
1223 relayer_model,
1224 signer,
1225 provider,
1226 create_test_evm_network(),
1227 Arc::new(relayer_repo),
1228 Arc::new(network_repo),
1229 Arc::new(tx_repo),
1230 Arc::new(counter),
1231 Arc::new(job_producer),
1232 )
1233 .unwrap();
1234
1235 let result = relayer.cancel_transaction_via_job(test_transaction).await;
1236 assert!(result.is_ok());
1237 }
1238
1239 #[tokio::test]
1240 async fn test_cancel_transaction_via_job_failure() {
1241 let (provider, relayer_repo, network_repo, tx_repo, mut job_producer, signer, counter) =
1242 setup_mocks();
1243 let relayer_model = create_test_relayer();
1244
1245 let test_transaction = TransactionRepoModel {
1246 id: "test-tx-id".to_string(),
1247 relayer_id: relayer_model.id.clone(),
1248 status: TransactionStatus::Pending,
1249 ..TransactionRepoModel::default()
1250 };
1251
1252 job_producer
1253 .expect_produce_submit_transaction_job()
1254 .returning(|_, _| {
1255 Box::pin(ready(Err(crate::jobs::JobProducerError::QueueError(
1256 "Queue is full".to_string(),
1257 ))))
1258 })
1259 .once();
1260
1261 let relayer = EvmRelayer::new(
1262 relayer_model,
1263 signer,
1264 provider,
1265 create_test_evm_network(),
1266 Arc::new(relayer_repo),
1267 Arc::new(network_repo),
1268 Arc::new(tx_repo),
1269 Arc::new(counter),
1270 Arc::new(job_producer),
1271 )
1272 .unwrap();
1273
1274 let result = relayer.cancel_transaction_via_job(test_transaction).await;
1275 assert!(result.is_err());
1276 match result.err().unwrap() {
1277 RelayerError::QueueError(_) => (),
1278 _ => panic!("Expected QueueError"),
1279 }
1280 }
1281
1282 #[tokio::test]
1283 async fn test_delete_pending_transactions_no_pending() {
1284 let (provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
1285 setup_mocks();
1286 let relayer_model = create_test_relayer();
1287
1288 tx_repo
1289 .expect_find_by_status()
1290 .withf(|relayer_id, statuses| {
1291 relayer_id == "test-relayer-id"
1292 && statuses
1293 == [
1294 TransactionStatus::Pending,
1295 TransactionStatus::Sent,
1296 TransactionStatus::Submitted,
1297 ]
1298 })
1299 .returning(|_, _| Ok(vec![]))
1300 .once();
1301
1302 let relayer = EvmRelayer::new(
1303 relayer_model,
1304 signer,
1305 provider,
1306 create_test_evm_network(),
1307 Arc::new(relayer_repo),
1308 Arc::new(network_repo),
1309 Arc::new(tx_repo),
1310 Arc::new(counter),
1311 Arc::new(job_producer),
1312 )
1313 .unwrap();
1314
1315 let result = relayer.delete_pending_transactions().await.unwrap();
1316 assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 0);
1317 assert_eq!(result.failed_to_queue_transaction_ids.len(), 0);
1318 assert_eq!(result.total_processed, 0);
1319 }
1320
1321 #[tokio::test]
1322 async fn test_delete_pending_transactions_all_successful() {
1323 let (provider, relayer_repo, network_repo, mut tx_repo, mut job_producer, signer, counter) =
1324 setup_mocks();
1325 let relayer_model = create_test_relayer();
1326
1327 let pending_transactions = vec![
1328 TransactionRepoModel {
1329 id: "tx1".to_string(),
1330 relayer_id: relayer_model.id.clone(),
1331 status: TransactionStatus::Pending,
1332 ..TransactionRepoModel::default()
1333 },
1334 TransactionRepoModel {
1335 id: "tx2".to_string(),
1336 relayer_id: relayer_model.id.clone(),
1337 status: TransactionStatus::Sent,
1338 ..TransactionRepoModel::default()
1339 },
1340 TransactionRepoModel {
1341 id: "tx3".to_string(),
1342 relayer_id: relayer_model.id.clone(),
1343 status: TransactionStatus::Submitted,
1344 ..TransactionRepoModel::default()
1345 },
1346 ];
1347
1348 tx_repo
1349 .expect_find_by_status()
1350 .withf(|relayer_id, statuses| {
1351 relayer_id == "test-relayer-id"
1352 && statuses
1353 == [
1354 TransactionStatus::Pending,
1355 TransactionStatus::Sent,
1356 TransactionStatus::Submitted,
1357 ]
1358 })
1359 .returning(move |_, _| Ok(pending_transactions.clone()))
1360 .once();
1361
1362 job_producer
1363 .expect_produce_submit_transaction_job()
1364 .returning(|_, _| Box::pin(ready(Ok(()))))
1365 .times(3);
1366
1367 let relayer = EvmRelayer::new(
1368 relayer_model,
1369 signer,
1370 provider,
1371 create_test_evm_network(),
1372 Arc::new(relayer_repo),
1373 Arc::new(network_repo),
1374 Arc::new(tx_repo),
1375 Arc::new(counter),
1376 Arc::new(job_producer),
1377 )
1378 .unwrap();
1379
1380 let result = relayer.delete_pending_transactions().await.unwrap();
1381 assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 3);
1382 assert_eq!(result.failed_to_queue_transaction_ids.len(), 0);
1383 assert_eq!(result.total_processed, 3);
1384
1385 let expected_ids = vec!["tx1", "tx2", "tx3"];
1386 for id in expected_ids {
1387 assert!(result
1388 .queued_for_cancellation_transaction_ids
1389 .contains(&id.to_string()));
1390 }
1391 }
1392
1393 #[tokio::test]
1394 async fn test_delete_pending_transactions_partial_failures() {
1395 let (provider, relayer_repo, network_repo, mut tx_repo, mut job_producer, signer, counter) =
1396 setup_mocks();
1397 let relayer_model = create_test_relayer();
1398
1399 let pending_transactions = vec![
1400 TransactionRepoModel {
1401 id: "tx1".to_string(),
1402 relayer_id: relayer_model.id.clone(),
1403 status: TransactionStatus::Pending,
1404 ..TransactionRepoModel::default()
1405 },
1406 TransactionRepoModel {
1407 id: "tx2".to_string(),
1408 relayer_id: relayer_model.id.clone(),
1409 status: TransactionStatus::Sent,
1410 ..TransactionRepoModel::default()
1411 },
1412 TransactionRepoModel {
1413 id: "tx3".to_string(),
1414 relayer_id: relayer_model.id.clone(),
1415 status: TransactionStatus::Submitted,
1416 ..TransactionRepoModel::default()
1417 },
1418 ];
1419
1420 tx_repo
1421 .expect_find_by_status()
1422 .withf(|relayer_id, statuses| {
1423 relayer_id == "test-relayer-id"
1424 && statuses
1425 == [
1426 TransactionStatus::Pending,
1427 TransactionStatus::Sent,
1428 TransactionStatus::Submitted,
1429 ]
1430 })
1431 .returning(move |_, _| Ok(pending_transactions.clone()))
1432 .once();
1433
1434 job_producer
1436 .expect_produce_submit_transaction_job()
1437 .returning(|_, _| Box::pin(ready(Ok(()))))
1438 .times(1);
1439 job_producer
1440 .expect_produce_submit_transaction_job()
1441 .returning(|_, _| {
1442 Box::pin(ready(Err(crate::jobs::JobProducerError::QueueError(
1443 "Queue is full".to_string(),
1444 ))))
1445 })
1446 .times(1);
1447 job_producer
1448 .expect_produce_submit_transaction_job()
1449 .returning(|_, _| Box::pin(ready(Ok(()))))
1450 .times(1);
1451
1452 let relayer = EvmRelayer::new(
1453 relayer_model,
1454 signer,
1455 provider,
1456 create_test_evm_network(),
1457 Arc::new(relayer_repo),
1458 Arc::new(network_repo),
1459 Arc::new(tx_repo),
1460 Arc::new(counter),
1461 Arc::new(job_producer),
1462 )
1463 .unwrap();
1464
1465 let result = relayer.delete_pending_transactions().await.unwrap();
1466 assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 2);
1467 assert_eq!(result.failed_to_queue_transaction_ids.len(), 1);
1468 assert_eq!(result.total_processed, 3);
1469 }
1470
1471 #[tokio::test]
1472 async fn test_delete_pending_transactions_repository_error() {
1473 let (provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
1474 setup_mocks();
1475 let relayer_model = create_test_relayer();
1476
1477 tx_repo
1478 .expect_find_by_status()
1479 .withf(|relayer_id, statuses| {
1480 relayer_id == "test-relayer-id"
1481 && statuses
1482 == [
1483 TransactionStatus::Pending,
1484 TransactionStatus::Sent,
1485 TransactionStatus::Submitted,
1486 ]
1487 })
1488 .returning(|_, _| {
1489 Err(RepositoryError::Unknown(
1490 "Database connection failed".to_string(),
1491 ))
1492 })
1493 .once();
1494
1495 let relayer = EvmRelayer::new(
1496 relayer_model,
1497 signer,
1498 provider,
1499 create_test_evm_network(),
1500 Arc::new(relayer_repo),
1501 Arc::new(network_repo),
1502 Arc::new(tx_repo),
1503 Arc::new(counter),
1504 Arc::new(job_producer),
1505 )
1506 .unwrap();
1507
1508 let result = relayer.delete_pending_transactions().await;
1509 assert!(result.is_err());
1510 match result.err().unwrap() {
1511 RelayerError::NetworkConfiguration(msg) => {
1512 assert!(msg.contains("Database connection failed"))
1513 }
1514 _ => panic!("Expected NetworkConfiguration error for repository failure"),
1515 }
1516 }
1517
1518 #[tokio::test]
1519 async fn test_delete_pending_transactions_all_failures() {
1520 let (provider, relayer_repo, network_repo, mut tx_repo, mut job_producer, signer, counter) =
1521 setup_mocks();
1522 let relayer_model = create_test_relayer();
1523
1524 let pending_transactions = vec![
1525 TransactionRepoModel {
1526 id: "tx1".to_string(),
1527 relayer_id: relayer_model.id.clone(),
1528 status: TransactionStatus::Pending,
1529 ..TransactionRepoModel::default()
1530 },
1531 TransactionRepoModel {
1532 id: "tx2".to_string(),
1533 relayer_id: relayer_model.id.clone(),
1534 status: TransactionStatus::Sent,
1535 ..TransactionRepoModel::default()
1536 },
1537 ];
1538
1539 tx_repo
1540 .expect_find_by_status()
1541 .withf(|relayer_id, statuses| {
1542 relayer_id == "test-relayer-id"
1543 && statuses
1544 == [
1545 TransactionStatus::Pending,
1546 TransactionStatus::Sent,
1547 TransactionStatus::Submitted,
1548 ]
1549 })
1550 .returning(move |_, _| Ok(pending_transactions.clone()))
1551 .once();
1552
1553 job_producer
1554 .expect_produce_submit_transaction_job()
1555 .returning(|_, _| {
1556 Box::pin(ready(Err(crate::jobs::JobProducerError::QueueError(
1557 "Queue is full".to_string(),
1558 ))))
1559 })
1560 .times(2);
1561
1562 let relayer = EvmRelayer::new(
1563 relayer_model,
1564 signer,
1565 provider,
1566 create_test_evm_network(),
1567 Arc::new(relayer_repo),
1568 Arc::new(network_repo),
1569 Arc::new(tx_repo),
1570 Arc::new(counter),
1571 Arc::new(job_producer),
1572 )
1573 .unwrap();
1574
1575 let result = relayer.delete_pending_transactions().await.unwrap();
1576 assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 0);
1577 assert_eq!(result.failed_to_queue_transaction_ids.len(), 2);
1578 assert_eq!(result.total_processed, 2);
1579
1580 let expected_failed_ids = vec!["tx1", "tx2"];
1581 for id in expected_failed_ids {
1582 assert!(result
1583 .failed_to_queue_transaction_ids
1584 .contains(&id.to_string()));
1585 }
1586 }
1587
1588 #[tokio::test]
1589 async fn test_rpc_eth_get_balance() {
1590 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1591 setup_mocks();
1592 let relayer_model = create_test_relayer();
1593
1594 provider
1595 .expect_raw_request_dyn()
1596 .withf(|method, params| {
1597 method == "eth_getBalance"
1598 && params.as_str()
1599 == Some(r#"["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]"#)
1600 })
1601 .returning(|_, _| Box::pin(async { Ok(serde_json::json!("0xde0b6b3a7640000")) }));
1602
1603 let relayer = EvmRelayer::new(
1604 relayer_model,
1605 signer,
1606 provider,
1607 create_test_evm_network(),
1608 Arc::new(relayer_repo),
1609 Arc::new(network_repo),
1610 Arc::new(tx_repo),
1611 Arc::new(counter),
1612 Arc::new(job_producer),
1613 )
1614 .unwrap();
1615
1616 let request = JsonRpcRequest {
1617 jsonrpc: "2.0".to_string(),
1618 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1619 method: "eth_getBalance".to_string(),
1620 params: r#"["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]"#.to_string(),
1621 }),
1622 id: Some(JsonRpcId::Number(1)),
1623 };
1624
1625 let response = relayer.rpc(request).await.unwrap();
1626 assert!(response.error.is_none());
1627 assert!(response.result.is_some());
1628
1629 if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
1630 assert_eq!(result, serde_json::json!("0xde0b6b3a7640000")); }
1632 }
1633
1634 #[tokio::test]
1635 async fn test_rpc_eth_block_number() {
1636 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1637 setup_mocks();
1638 let relayer_model = create_test_relayer();
1639
1640 provider
1641 .expect_raw_request_dyn()
1642 .withf(|method, params| method == "eth_blockNumber" && params.as_str() == Some("[]"))
1643 .returning(|_, _| Box::pin(async { Ok(serde_json::json!("0x3039")) }));
1644
1645 let relayer = EvmRelayer::new(
1646 relayer_model,
1647 signer,
1648 provider,
1649 create_test_evm_network(),
1650 Arc::new(relayer_repo),
1651 Arc::new(network_repo),
1652 Arc::new(tx_repo),
1653 Arc::new(counter),
1654 Arc::new(job_producer),
1655 )
1656 .unwrap();
1657
1658 let request = JsonRpcRequest {
1659 jsonrpc: "2.0".to_string(),
1660 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1661 method: "eth_blockNumber".to_string(),
1662 params: "[]".to_string(),
1663 }),
1664 id: Some(JsonRpcId::Number(1)),
1665 };
1666
1667 let response = relayer.rpc(request).await.unwrap();
1668 assert!(response.error.is_none());
1669 assert!(response.result.is_some());
1670
1671 if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
1672 assert_eq!(result, serde_json::json!("0x3039")); }
1674 }
1675
1676 #[tokio::test]
1677 async fn test_rpc_unsupported_method() {
1678 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1679 setup_mocks();
1680 let relayer_model = create_test_relayer();
1681
1682 provider
1683 .expect_raw_request_dyn()
1684 .withf(|method, _| method == "eth_unsupportedMethod")
1685 .returning(|_, _| {
1686 Box::pin(async {
1687 Err(ProviderError::Other(
1688 "Unsupported method: eth_unsupportedMethod".to_string(),
1689 ))
1690 })
1691 });
1692
1693 let relayer = EvmRelayer::new(
1694 relayer_model,
1695 signer,
1696 provider,
1697 create_test_evm_network(),
1698 Arc::new(relayer_repo),
1699 Arc::new(network_repo),
1700 Arc::new(tx_repo),
1701 Arc::new(counter),
1702 Arc::new(job_producer),
1703 )
1704 .unwrap();
1705
1706 let request = JsonRpcRequest {
1707 jsonrpc: "2.0".to_string(),
1708 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1709 method: "eth_unsupportedMethod".to_string(),
1710 params: "[]".to_string(),
1711 }),
1712 id: Some(JsonRpcId::Number(1)),
1713 };
1714
1715 let response = relayer.rpc(request).await.unwrap();
1716 assert!(response.result.is_none());
1717 assert!(response.error.is_some());
1718
1719 let error = response.error.unwrap();
1720 assert_eq!(error.code, -32603); }
1722
1723 #[tokio::test]
1724 async fn test_rpc_invalid_params() {
1725 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1726 setup_mocks();
1727 let relayer_model = create_test_relayer();
1728
1729 provider
1730 .expect_raw_request_dyn()
1731 .withf(|method, params| method == "eth_getBalance" && params.as_str() == Some("[]"))
1732 .returning(|_, _| {
1733 Box::pin(async {
1734 Err(ProviderError::Other(
1735 "Missing address parameter".to_string(),
1736 ))
1737 })
1738 });
1739
1740 let relayer = EvmRelayer::new(
1741 relayer_model,
1742 signer,
1743 provider,
1744 create_test_evm_network(),
1745 Arc::new(relayer_repo),
1746 Arc::new(network_repo),
1747 Arc::new(tx_repo),
1748 Arc::new(counter),
1749 Arc::new(job_producer),
1750 )
1751 .unwrap();
1752
1753 let request = JsonRpcRequest {
1754 jsonrpc: "2.0".to_string(),
1755 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1756 method: "eth_getBalance".to_string(),
1757 params: "[]".to_string(), }),
1759 id: Some(JsonRpcId::Number(1)),
1760 };
1761
1762 let response = relayer.rpc(request).await.unwrap();
1763 assert!(response.result.is_none());
1764 assert!(response.error.is_some());
1765
1766 let error = response.error.unwrap();
1767 assert_eq!(error.code, -32603); }
1769
1770 #[tokio::test]
1771 async fn test_rpc_non_evm_request() {
1772 let (provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1773 setup_mocks();
1774 let relayer_model = create_test_relayer();
1775
1776 let relayer = EvmRelayer::new(
1777 relayer_model,
1778 signer,
1779 provider,
1780 create_test_evm_network(),
1781 Arc::new(relayer_repo),
1782 Arc::new(network_repo),
1783 Arc::new(tx_repo),
1784 Arc::new(counter),
1785 Arc::new(job_producer),
1786 )
1787 .unwrap();
1788
1789 let request = JsonRpcRequest {
1790 jsonrpc: "2.0".to_string(),
1791 params: NetworkRpcRequest::Solana(crate::models::SolanaRpcRequest::GetSupportedTokens(
1792 crate::models::GetSupportedTokensRequestParams {},
1793 )),
1794 id: Some(JsonRpcId::Number(1)),
1795 };
1796
1797 let response = relayer.rpc(request).await.unwrap();
1798 assert!(response.result.is_none());
1799 assert!(response.error.is_some());
1800
1801 let error = response.error.unwrap();
1802 assert_eq!(error.code, -32602); }
1804
1805 #[tokio::test]
1806 async fn test_rpc_raw_request_with_array_params() {
1807 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1808 setup_mocks();
1809 let relayer_model = create_test_relayer();
1810
1811 provider
1812 .expect_raw_request_dyn()
1813 .withf(|method, params| {
1814 method == "eth_getTransactionByHash"
1815 && params.as_array().is_some_and(|arr| {
1816 arr.len() == 1 && arr[0].as_str() == Some("0x1234567890abcdef")
1817 })
1818 })
1819 .returning(|_, _| {
1820 Box::pin(async {
1821 Ok(serde_json::json!({
1822 "hash": "0x1234567890abcdef",
1823 "blockNumber": "0x1",
1824 "gasUsed": "0x5208"
1825 }))
1826 })
1827 });
1828
1829 let relayer = EvmRelayer::new(
1830 relayer_model,
1831 signer,
1832 provider,
1833 create_test_evm_network(),
1834 Arc::new(relayer_repo),
1835 Arc::new(network_repo),
1836 Arc::new(tx_repo),
1837 Arc::new(counter),
1838 Arc::new(job_producer),
1839 )
1840 .unwrap();
1841
1842 let request = JsonRpcRequest {
1843 jsonrpc: "2.0".to_string(),
1844 params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
1845 method: "eth_getTransactionByHash".to_string(),
1846 params: serde_json::json!(["0x1234567890abcdef"]),
1847 }),
1848 id: Some(JsonRpcId::Number(42)),
1849 };
1850
1851 let response = relayer.rpc(request).await.unwrap();
1852 assert!(response.error.is_none());
1853 assert!(response.result.is_some());
1854 assert_eq!(response.id, Some(JsonRpcId::Number(42)));
1855
1856 if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
1857 assert!(result.get("hash").is_some());
1858 assert!(result.get("blockNumber").is_some());
1859 }
1860 }
1861
1862 #[tokio::test]
1863 async fn test_rpc_raw_request_with_object_params() {
1864 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1865 setup_mocks();
1866 let relayer_model = create_test_relayer();
1867
1868 provider
1869 .expect_raw_request_dyn()
1870 .withf(|method, params| {
1871 method == "eth_call"
1872 && params
1873 .as_object()
1874 .is_some_and(|obj| obj.contains_key("to") && obj.contains_key("data"))
1875 })
1876 .returning(|_, _| {
1877 Box::pin(async {
1878 Ok(serde_json::json!(
1879 "0x0000000000000000000000000000000000000000000000000000000000000001"
1880 ))
1881 })
1882 });
1883
1884 let relayer = EvmRelayer::new(
1885 relayer_model,
1886 signer,
1887 provider,
1888 create_test_evm_network(),
1889 Arc::new(relayer_repo),
1890 Arc::new(network_repo),
1891 Arc::new(tx_repo),
1892 Arc::new(counter),
1893 Arc::new(job_producer),
1894 )
1895 .unwrap();
1896
1897 let request = JsonRpcRequest {
1898 jsonrpc: "2.0".to_string(),
1899 params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
1900 method: "eth_call".to_string(),
1901 params: serde_json::json!({
1902 "to": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
1903 "data": "0x70a08231000000000000000000000000742d35cc6634c0532925a3b844bc454e4438f44e"
1904 }),
1905 }),
1906 id: Some(JsonRpcId::Number(123)),
1907 };
1908
1909 let response = relayer.rpc(request).await.unwrap();
1910 assert!(response.error.is_none());
1911 assert!(response.result.is_some());
1912 assert_eq!(response.id, Some(JsonRpcId::Number(123)));
1913 }
1914
1915 #[tokio::test]
1916 async fn test_rpc_generic_request_with_empty_params() {
1917 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1918 setup_mocks();
1919 let relayer_model = create_test_relayer();
1920
1921 provider
1922 .expect_raw_request_dyn()
1923 .withf(|method, params| method == "net_version" && params.as_str() == Some("[]"))
1924 .returning(|_, _| Box::pin(async { Ok(serde_json::json!("1")) }));
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: "net_version".to_string(),
1943 params: "[]".to_string(),
1944 }),
1945 id: Some(JsonRpcId::Number(999)),
1946 };
1947
1948 let response = relayer.rpc(request).await.unwrap();
1949 assert!(response.error.is_none());
1950 assert!(response.result.is_some());
1951 assert_eq!(response.id, Some(JsonRpcId::Number(999)));
1952 }
1953
1954 #[tokio::test]
1955 async fn test_rpc_provider_invalid_address_error() {
1956 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1957 setup_mocks();
1958 let relayer_model = create_test_relayer();
1959
1960 provider.expect_raw_request_dyn().returning(|_, _| {
1961 Box::pin(async {
1962 Err(ProviderError::InvalidAddress(
1963 "Invalid address format".to_string(),
1964 ))
1965 })
1966 });
1967
1968 let relayer = EvmRelayer::new(
1969 relayer_model,
1970 signer,
1971 provider,
1972 create_test_evm_network(),
1973 Arc::new(relayer_repo),
1974 Arc::new(network_repo),
1975 Arc::new(tx_repo),
1976 Arc::new(counter),
1977 Arc::new(job_producer),
1978 )
1979 .unwrap();
1980
1981 let request = JsonRpcRequest {
1982 jsonrpc: "2.0".to_string(),
1983 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1984 method: "eth_getBalance".to_string(),
1985 params: r#"["invalid_address", "latest"]"#.to_string(),
1986 }),
1987 id: Some(JsonRpcId::Number(1)),
1988 };
1989
1990 let response = relayer.rpc(request).await.unwrap();
1991 assert!(response.result.is_none());
1992 assert!(response.error.is_some());
1993
1994 let error = response.error.unwrap();
1995 assert_eq!(error.code, -32602); }
1997
1998 #[tokio::test]
1999 async fn test_rpc_provider_network_configuration_error() {
2000 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2001 setup_mocks();
2002 let relayer_model = create_test_relayer();
2003
2004 provider.expect_raw_request_dyn().returning(|_, _| {
2005 Box::pin(async {
2006 Err(ProviderError::NetworkConfiguration(
2007 "Network not reachable".to_string(),
2008 ))
2009 })
2010 });
2011
2012 let relayer = EvmRelayer::new(
2013 relayer_model,
2014 signer,
2015 provider,
2016 create_test_evm_network(),
2017 Arc::new(relayer_repo),
2018 Arc::new(network_repo),
2019 Arc::new(tx_repo),
2020 Arc::new(counter),
2021 Arc::new(job_producer),
2022 )
2023 .unwrap();
2024
2025 let request = JsonRpcRequest {
2026 jsonrpc: "2.0".to_string(),
2027 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2028 method: "eth_chainId".to_string(),
2029 params: "[]".to_string(),
2030 }),
2031 id: Some(JsonRpcId::Number(2)),
2032 };
2033
2034 let response = relayer.rpc(request).await.unwrap();
2035 assert!(response.result.is_none());
2036 assert!(response.error.is_some());
2037
2038 let error = response.error.unwrap();
2039 assert_eq!(error.code, -33004); }
2041
2042 #[tokio::test]
2043 async fn test_rpc_provider_timeout_error() {
2044 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2045 setup_mocks();
2046 let relayer_model = create_test_relayer();
2047
2048 provider
2049 .expect_raw_request_dyn()
2050 .returning(|_, _| Box::pin(async { Err(ProviderError::Timeout) }));
2051
2052 let relayer = EvmRelayer::new(
2053 relayer_model,
2054 signer,
2055 provider,
2056 create_test_evm_network(),
2057 Arc::new(relayer_repo),
2058 Arc::new(network_repo),
2059 Arc::new(tx_repo),
2060 Arc::new(counter),
2061 Arc::new(job_producer),
2062 )
2063 .unwrap();
2064
2065 let request = JsonRpcRequest {
2066 jsonrpc: "2.0".to_string(),
2067 params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
2068 method: "eth_blockNumber".to_string(),
2069 params: serde_json::json!([]),
2070 }),
2071 id: Some(JsonRpcId::Number(3)),
2072 };
2073
2074 let response = relayer.rpc(request).await.unwrap();
2075 assert!(response.result.is_none());
2076 assert!(response.error.is_some());
2077
2078 let error = response.error.unwrap();
2079 assert_eq!(error.code, -33000); }
2081
2082 #[tokio::test]
2083 async fn test_rpc_provider_rate_limited_error() {
2084 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2085 setup_mocks();
2086 let relayer_model = create_test_relayer();
2087
2088 provider
2089 .expect_raw_request_dyn()
2090 .returning(|_, _| Box::pin(async { Err(ProviderError::RateLimited) }));
2091
2092 let relayer = EvmRelayer::new(
2093 relayer_model,
2094 signer,
2095 provider,
2096 create_test_evm_network(),
2097 Arc::new(relayer_repo),
2098 Arc::new(network_repo),
2099 Arc::new(tx_repo),
2100 Arc::new(counter),
2101 Arc::new(job_producer),
2102 )
2103 .unwrap();
2104
2105 let request = JsonRpcRequest {
2106 jsonrpc: "2.0".to_string(),
2107 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2108 method: "eth_getBalance".to_string(),
2109 params: r#"["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]"#.to_string(),
2110 }),
2111 id: Some(JsonRpcId::Number(4)),
2112 };
2113
2114 let response = relayer.rpc(request).await.unwrap();
2115 assert!(response.result.is_none());
2116 assert!(response.error.is_some());
2117
2118 let error = response.error.unwrap();
2119 assert_eq!(error.code, -33001); }
2121
2122 #[tokio::test]
2123 async fn test_rpc_provider_bad_gateway_error() {
2124 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2125 setup_mocks();
2126 let relayer_model = create_test_relayer();
2127
2128 provider
2129 .expect_raw_request_dyn()
2130 .returning(|_, _| Box::pin(async { Err(ProviderError::BadGateway) }));
2131
2132 let relayer = EvmRelayer::new(
2133 relayer_model,
2134 signer,
2135 provider,
2136 create_test_evm_network(),
2137 Arc::new(relayer_repo),
2138 Arc::new(network_repo),
2139 Arc::new(tx_repo),
2140 Arc::new(counter),
2141 Arc::new(job_producer),
2142 )
2143 .unwrap();
2144
2145 let request = JsonRpcRequest {
2146 jsonrpc: "2.0".to_string(),
2147 params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
2148 method: "eth_gasPrice".to_string(),
2149 params: serde_json::json!([]),
2150 }),
2151 id: Some(JsonRpcId::Number(5)),
2152 };
2153
2154 let response = relayer.rpc(request).await.unwrap();
2155 assert!(response.result.is_none());
2156 assert!(response.error.is_some());
2157
2158 let error = response.error.unwrap();
2159 assert_eq!(error.code, -33002); }
2161
2162 #[tokio::test]
2163 async fn test_rpc_provider_request_error() {
2164 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2165 setup_mocks();
2166 let relayer_model = create_test_relayer();
2167
2168 provider.expect_raw_request_dyn().returning(|_, _| {
2169 Box::pin(async {
2170 Err(ProviderError::RequestError {
2171 error: "Bad request".to_string(),
2172 status_code: 400,
2173 })
2174 })
2175 });
2176
2177 let relayer = EvmRelayer::new(
2178 relayer_model,
2179 signer,
2180 provider,
2181 create_test_evm_network(),
2182 Arc::new(relayer_repo),
2183 Arc::new(network_repo),
2184 Arc::new(tx_repo),
2185 Arc::new(counter),
2186 Arc::new(job_producer),
2187 )
2188 .unwrap();
2189
2190 let request = JsonRpcRequest {
2191 jsonrpc: "2.0".to_string(),
2192 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2193 method: "invalid_method".to_string(),
2194 params: "{}".to_string(),
2195 }),
2196 id: Some(JsonRpcId::Number(6)),
2197 };
2198
2199 let response = relayer.rpc(request).await.unwrap();
2200 assert!(response.result.is_none());
2201 assert!(response.error.is_some());
2202
2203 let error = response.error.unwrap();
2204 assert_eq!(error.code, -33003); }
2206
2207 #[tokio::test]
2208 async fn test_rpc_provider_other_error() {
2209 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2210 setup_mocks();
2211 let relayer_model = create_test_relayer();
2212
2213 provider.expect_raw_request_dyn().returning(|_, _| {
2214 Box::pin(async {
2215 Err(ProviderError::Other(
2216 "Unexpected error occurred".to_string(),
2217 ))
2218 })
2219 });
2220
2221 let relayer = EvmRelayer::new(
2222 relayer_model,
2223 signer,
2224 provider,
2225 create_test_evm_network(),
2226 Arc::new(relayer_repo),
2227 Arc::new(network_repo),
2228 Arc::new(tx_repo),
2229 Arc::new(counter),
2230 Arc::new(job_producer),
2231 )
2232 .unwrap();
2233
2234 let request = JsonRpcRequest {
2235 jsonrpc: "2.0".to_string(),
2236 params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
2237 method: "eth_getBalance".to_string(),
2238 params: serde_json::json!(["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]),
2239 }),
2240 id: Some(JsonRpcId::Number(7)),
2241 };
2242
2243 let response = relayer.rpc(request).await.unwrap();
2244 assert!(response.result.is_none());
2245 assert!(response.error.is_some());
2246
2247 let error = response.error.unwrap();
2248 assert_eq!(error.code, -32603); }
2250
2251 #[tokio::test]
2252 async fn test_rpc_response_preserves_request_id() {
2253 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2254 setup_mocks();
2255 let relayer_model = create_test_relayer();
2256
2257 provider
2258 .expect_raw_request_dyn()
2259 .returning(|_, _| Box::pin(async { Ok(serde_json::json!("0x1")) }));
2260
2261 let relayer = EvmRelayer::new(
2262 relayer_model,
2263 signer,
2264 provider,
2265 create_test_evm_network(),
2266 Arc::new(relayer_repo),
2267 Arc::new(network_repo),
2268 Arc::new(tx_repo),
2269 Arc::new(counter),
2270 Arc::new(job_producer),
2271 )
2272 .unwrap();
2273
2274 let request_id = u64::MAX;
2275 let request = JsonRpcRequest {
2276 jsonrpc: "2.0".to_string(),
2277 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2278 method: "eth_chainId".to_string(),
2279 params: "[]".to_string(),
2280 }),
2281 id: Some(JsonRpcId::Number(request_id as i64)),
2282 };
2283
2284 let response = relayer.rpc(request).await.unwrap();
2285 assert_eq!(response.id, Some(JsonRpcId::Number(request_id as i64)));
2286 assert_eq!(response.jsonrpc, "2.0");
2287 }
2288
2289 #[tokio::test]
2290 async fn test_rpc_handles_complex_json_response() {
2291 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2292 setup_mocks();
2293 let relayer_model = create_test_relayer();
2294
2295 let complex_response = serde_json::json!({
2296 "number": "0x1b4",
2297 "hash": "0xdc0818cf78f21a8e70579cb46a43643f78291264dda342ae31049421c82d21ae",
2298 "parentHash": "0xe99e022112df268ce40b8b654759b4f39c3cc1b8c86b2f4c7da48ba6d8a6ae8b",
2299 "transactions": [
2300 {
2301 "hash": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060",
2302 "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d",
2303 "to": "0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb",
2304 "value": "0xf3dbb76162000"
2305 }
2306 ],
2307 "gasUsed": "0x5208"
2308 });
2309
2310 provider.expect_raw_request_dyn().returning(move |_, _| {
2311 let response = complex_response.clone();
2312 Box::pin(async move { Ok(response) })
2313 });
2314
2315 let relayer = EvmRelayer::new(
2316 relayer_model,
2317 signer,
2318 provider,
2319 create_test_evm_network(),
2320 Arc::new(relayer_repo),
2321 Arc::new(network_repo),
2322 Arc::new(tx_repo),
2323 Arc::new(counter),
2324 Arc::new(job_producer),
2325 )
2326 .unwrap();
2327
2328 let request = JsonRpcRequest {
2329 jsonrpc: "2.0".to_string(),
2330 params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
2331 method: "eth_getBlockByNumber".to_string(),
2332 params: serde_json::json!(["0x1b4", true]),
2333 }),
2334 id: Some(JsonRpcId::Number(8)),
2335 };
2336
2337 let response = relayer.rpc(request).await.unwrap();
2338 assert!(response.error.is_none());
2339 assert!(response.result.is_some());
2340
2341 if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
2342 assert!(result.get("transactions").is_some());
2343 assert!(result.get("hash").is_some());
2344 assert!(result.get("gasUsed").is_some());
2345 }
2346 }
2347}