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, RelayerHealthCheck, TransactionRequest},
37 models::{
38 produce_relayer_disabled_payload, DeletePendingTransactionsResponse, DisabledReason,
39 EvmNetwork, HealthCheckFailure, JsonRpcRequest, JsonRpcResponse, NetworkRepoModel,
40 NetworkRpcRequest, NetworkRpcResult, NetworkTransactionRequest, NetworkType,
41 RelayerRepoModel, RelayerStatus, RepositoryError, RpcErrorCodes, TransactionRepoModel,
42 TransactionStatus,
43 },
44 repositories::{NetworkRepository, RelayerRepository, Repository, TransactionRepository},
45 services::{
46 DataSignerTrait, EvmProvider, EvmProviderTrait, EvmSigner, TransactionCounterService,
47 TransactionCounterServiceTrait,
48 },
49 utils::calculate_scheduled_timestamp,
50};
51use async_trait::async_trait;
52use eyre::Result;
53use tracing::{debug, info, warn};
54
55use super::{
56 create_error_response, create_success_response, map_provider_error, EvmTransactionValidator,
57};
58
59#[allow(dead_code)]
60pub struct EvmRelayer<P, RR, NR, TR, J, S, TCS>
61where
62 P: EvmProviderTrait + Send + Sync,
63 RR: Repository<RelayerRepoModel, String> + RelayerRepository + Send + Sync + 'static,
64 NR: NetworkRepository + Repository<NetworkRepoModel, String> + Send + Sync + 'static,
65 TR: Repository<TransactionRepoModel, String> + TransactionRepository + Send + Sync + 'static,
66 J: JobProducerTrait + Send + Sync + 'static,
67 S: DataSignerTrait + Send + Sync + 'static,
68{
69 relayer: RelayerRepoModel,
70 signer: S,
71 network: EvmNetwork,
72 provider: P,
73 relayer_repository: Arc<RR>,
74 network_repository: Arc<NR>,
75 transaction_repository: Arc<TR>,
76 job_producer: Arc<J>,
77 transaction_counter_service: Arc<TCS>,
78}
79
80#[allow(clippy::too_many_arguments)]
81impl<P, RR, NR, TR, J, S, TCS> EvmRelayer<P, RR, NR, TR, J, S, TCS>
82where
83 P: EvmProviderTrait + Send + Sync,
84 RR: Repository<RelayerRepoModel, String> + RelayerRepository + Send + Sync + 'static,
85 NR: NetworkRepository + Repository<NetworkRepoModel, String> + Send + Sync + 'static,
86 TR: Repository<TransactionRepoModel, String> + TransactionRepository + Send + Sync + 'static,
87 J: JobProducerTrait + Send + Sync + 'static,
88 S: DataSignerTrait + Send + Sync + 'static,
89 TCS: TransactionCounterServiceTrait + Send + Sync + 'static,
90{
91 pub fn new(
108 relayer: RelayerRepoModel,
109 signer: S,
110 provider: P,
111 network: EvmNetwork,
112 relayer_repository: Arc<RR>,
113 network_repository: Arc<NR>,
114 transaction_repository: Arc<TR>,
115 transaction_counter_service: Arc<TCS>,
116 job_producer: Arc<J>,
117 ) -> Result<Self, RelayerError> {
118 Ok(Self {
119 relayer,
120 signer,
121 network,
122 provider,
123 relayer_repository,
124 network_repository,
125 transaction_repository,
126 transaction_counter_service,
127 job_producer,
128 })
129 }
130
131 async fn sync_nonce(&self) -> Result<(), RelayerError> {
137 let on_chain_nonce = self
138 .provider
139 .get_transaction_count(&self.relayer.address)
140 .await
141 .map_err(|e| RelayerError::ProviderError(e.to_string()))?;
142
143 let transaction_counter_nonce = self
144 .transaction_counter_service
145 .get()
146 .await
147 .unwrap_or(Some(0))
148 .unwrap_or(0);
149
150 let nonce = std::cmp::max(on_chain_nonce, transaction_counter_nonce);
151
152 debug!(
153 "Relayer: {} - On-chain nonce: {}, Transaction counter nonce: {}",
154 self.relayer.id, on_chain_nonce, transaction_counter_nonce
155 );
156
157 debug!(nonce = %nonce, "setting nonce for relayer");
158
159 self.transaction_counter_service.set(nonce).await?;
160
161 Ok(())
162 }
163
164 async fn validate_rpc(&self) -> Result<(), RelayerError> {
170 self.provider
171 .health_check()
172 .await
173 .map_err(|e| RelayerError::ProviderError(e.to_string()))?;
174
175 Ok(())
176 }
177
178 async fn cancel_transaction_via_job(
188 &self,
189 transaction: TransactionRepoModel,
190 ) -> Result<(), RelayerError> {
191 use crate::jobs::TransactionSend;
192
193 let cancel_job = TransactionSend::cancel(
194 transaction.id.clone(),
195 transaction.relayer_id.clone(),
196 "Cancelled via delete_pending_transactions".to_string(),
197 );
198
199 self.job_producer
200 .produce_submit_transaction_job(cancel_job, None)
201 .await
202 .map_err(RelayerError::from)?;
203
204 Ok(())
205 }
206}
207
208pub type DefaultEvmRelayer<J, T, RR, NR, TCR> =
210 EvmRelayer<EvmProvider, RR, NR, T, J, EvmSigner, TransactionCounterService<TCR>>;
211
212#[async_trait]
213impl<P, RR, NR, TR, J, S, TCS> Relayer for EvmRelayer<P, RR, NR, TR, J, S, TCS>
214where
215 P: EvmProviderTrait + Send + Sync,
216 RR: Repository<RelayerRepoModel, String> + RelayerRepository + Send + Sync + 'static,
217 NR: NetworkRepository + Repository<NetworkRepoModel, String> + Send + Sync + 'static,
218 TR: Repository<TransactionRepoModel, String> + TransactionRepository + Send + Sync + 'static,
219 J: JobProducerTrait + Send + Sync + 'static,
220 S: DataSignerTrait + Send + Sync + 'static,
221 TCS: TransactionCounterServiceTrait + Send + Sync + 'static,
222{
223 async fn process_transaction_request(
233 &self,
234 network_transaction: NetworkTransactionRequest,
235 ) -> Result<TransactionRepoModel, RelayerError> {
236 let network_model = self
237 .network_repository
238 .get_by_name(NetworkType::Evm, &self.relayer.network)
239 .await?
240 .ok_or_else(|| {
241 RelayerError::NetworkConfiguration(format!(
242 "Network {} not found",
243 self.relayer.network
244 ))
245 })?;
246 let transaction =
247 TransactionRepoModel::try_from((&network_transaction, &self.relayer, &network_model))?;
248
249 self.transaction_repository
250 .create(transaction.clone())
251 .await
252 .map_err(|e| RepositoryError::TransactionFailure(e.to_string()))?;
253
254 self.job_producer
255 .produce_transaction_request_job(
256 TransactionRequest::new(transaction.id.clone(), transaction.relayer_id.clone()),
257 None,
258 )
259 .await?;
260
261 Ok(transaction)
262 }
263
264 async fn get_balance(&self) -> Result<BalanceResponse, RelayerError> {
270 let balance: u128 = self
271 .provider
272 .get_balance(&self.relayer.address)
273 .await
274 .map_err(|e| RelayerError::ProviderError(e.to_string()))?
275 .try_into()
276 .map_err(|_| {
277 RelayerError::ProviderError("Failed to convert balance to u128".to_string())
278 })?;
279
280 Ok(BalanceResponse {
281 balance,
282 unit: EVM_SMALLEST_UNIT_NAME.to_string(),
283 })
284 }
285
286 async fn get_status(&self) -> Result<RelayerStatus, RelayerError> {
292 let relayer_model = &self.relayer;
293
294 let nonce_u256 = self
295 .provider
296 .get_transaction_count(&relayer_model.address)
297 .await
298 .map_err(|e| RelayerError::ProviderError(format!("Failed to get nonce: {}", e)))?;
299 let nonce_str = nonce_u256.to_string();
300
301 let balance_response = self.get_balance().await?;
302
303 let pending_statuses = [TransactionStatus::Pending, TransactionStatus::Submitted];
304 let pending_transactions = self
305 .transaction_repository
306 .find_by_status(&relayer_model.id, &pending_statuses[..])
307 .await
308 .map_err(RelayerError::from)?;
309 let pending_transactions_count = pending_transactions.len() as u64;
310
311 let confirmed_statuses = [TransactionStatus::Confirmed];
312 let confirmed_transactions = self
313 .transaction_repository
314 .find_by_status(&relayer_model.id, &confirmed_statuses[..])
315 .await
316 .map_err(RelayerError::from)?;
317
318 let last_confirmed_transaction_timestamp = confirmed_transactions
319 .iter()
320 .filter_map(|tx| tx.confirmed_at.as_ref())
321 .max()
322 .cloned();
323
324 Ok(RelayerStatus::Evm {
325 balance: balance_response.balance.to_string(),
326 pending_transactions_count,
327 last_confirmed_transaction_timestamp,
328 system_disabled: relayer_model.system_disabled,
329 paused: relayer_model.paused,
330 nonce: nonce_str,
331 })
332 }
333
334 async fn delete_pending_transactions(
341 &self,
342 ) -> Result<DeletePendingTransactionsResponse, RelayerError> {
343 let pending_statuses = [
344 TransactionStatus::Pending,
345 TransactionStatus::Sent,
346 TransactionStatus::Submitted,
347 ];
348
349 let pending_transactions = self
351 .transaction_repository
352 .find_by_status(&self.relayer.id, &pending_statuses[..])
353 .await
354 .map_err(RelayerError::from)?;
355
356 let transaction_count = pending_transactions.len();
357
358 if transaction_count == 0 {
359 info!(
360 "No pending transactions found for relayer: {}",
361 self.relayer.id
362 );
363 return Ok(DeletePendingTransactionsResponse {
364 queued_for_cancellation_transaction_ids: vec![],
365 failed_to_queue_transaction_ids: vec![],
366 total_processed: 0,
367 });
368 }
369
370 info!(
371 "Processing {} pending transactions for relayer: {}",
372 transaction_count, self.relayer.id
373 );
374
375 let mut cancelled_transaction_ids = Vec::new();
376 let mut failed_transaction_ids = Vec::new();
377
378 for transaction in pending_transactions {
380 match self.cancel_transaction_via_job(transaction.clone()).await {
381 Ok(_) => {
382 cancelled_transaction_ids.push(transaction.id.clone());
383 info!(
384 "Initiated cancellation for transaction {} with status {:?} for relayer {}",
385 transaction.id, transaction.status, self.relayer.id
386 );
387 }
388 Err(e) => {
389 failed_transaction_ids.push(transaction.id.clone());
390 warn!(
391 "Failed to cancel transaction {} for relayer {}: {}",
392 transaction.id, self.relayer.id, e
393 );
394 }
395 }
396 }
397
398 let total_processed = cancelled_transaction_ids.len() + failed_transaction_ids.len();
399
400 debug!(
401 queued_for_cancellation = %cancelled_transaction_ids.len(),
402 failed_to_queue = %failed_transaction_ids.len(),
403 "completed processing pending transactions for relayer"
404 );
405
406 Ok(DeletePendingTransactionsResponse {
407 queued_for_cancellation_transaction_ids: cancelled_transaction_ids,
408 failed_to_queue_transaction_ids: failed_transaction_ids,
409 total_processed: total_processed as u32,
410 })
411 }
412
413 async fn sign_data(&self, request: SignDataRequest) -> Result<SignDataResponse, RelayerError> {
423 let result = self.signer.sign_data(request).await?;
424
425 Ok(result)
426 }
427
428 async fn sign_typed_data(
438 &self,
439 request: SignTypedDataRequest,
440 ) -> Result<SignDataResponse, RelayerError> {
441 let result = self.signer.sign_typed_data(request).await?;
442
443 Ok(result)
444 }
445
446 async fn rpc(
456 &self,
457 request: JsonRpcRequest<NetworkRpcRequest>,
458 ) -> Result<JsonRpcResponse<NetworkRpcResult>, RelayerError> {
459 let evm_request = match request.params {
460 NetworkRpcRequest::Evm(evm_req) => evm_req,
461 _ => {
462 return Ok(create_error_response(
463 request.id,
464 RpcErrorCodes::INVALID_PARAMS,
465 "Invalid params",
466 "Expected EVM network request",
467 ))
468 }
469 };
470
471 let (method, params_json) = match evm_request {
473 crate::models::EvmRpcRequest::GenericRpcRequest { method, params } => {
474 (method, serde_json::Value::String(params))
475 }
476 crate::models::EvmRpcRequest::RawRpcRequest { method, params } => (method, params),
477 };
478
479 match self.provider.raw_request_dyn(&method, params_json).await {
481 Ok(result_value) => Ok(create_success_response(request.id, result_value)),
482 Err(provider_error) => {
483 let (error_code, error_message) = map_provider_error(&provider_error);
484 Ok(create_error_response(
485 request.id,
486 error_code,
487 error_message,
488 &provider_error.to_string(),
489 ))
490 }
491 }
492 }
493
494 async fn validate_min_balance(&self) -> Result<(), RelayerError> {
500 let policy = self.relayer.policies.get_evm_policy();
501 EvmTransactionValidator::init_balance_validation(
502 &self.relayer.address,
503 &policy,
504 &self.provider,
505 )
506 .await
507 .map_err(|e| RelayerError::InsufficientBalanceError(e.to_string()))?;
508
509 Ok(())
510 }
511
512 async fn check_health(&self) -> Result<(), Vec<HealthCheckFailure>> {
518 debug!("running health checks for EVM relayer {}", self.relayer.id);
519
520 let nonce_sync_result = self.sync_nonce().await;
521 let validate_rpc_result = self.validate_rpc().await;
522 let validate_min_balance_result = self.validate_min_balance().await;
523
524 let failures: Vec<HealthCheckFailure> = vec![
526 nonce_sync_result
527 .err()
528 .map(|e| HealthCheckFailure::NonceSyncFailed(e.to_string())),
529 validate_rpc_result
530 .err()
531 .map(|e| HealthCheckFailure::RpcValidationFailed(e.to_string())),
532 validate_min_balance_result
533 .err()
534 .map(|e| HealthCheckFailure::BalanceCheckFailed(e.to_string())),
535 ]
536 .into_iter()
537 .flatten()
538 .collect();
539
540 if failures.is_empty() {
541 info!("all health checks passed");
542 Ok(())
543 } else {
544 warn!("health checks failed: {:?}", failures);
545 Err(failures)
546 }
547 }
548
549 async fn initialize_relayer(&self) -> Result<(), RelayerError> {
550 debug!("initializing EVM relayer {}", self.relayer.id);
551
552 match self.check_health().await {
553 Ok(_) => {
554 if self.relayer.system_disabled {
556 self.relayer_repository
558 .enable_relayer(self.relayer.id.clone())
559 .await?;
560 }
561 Ok(())
562 }
563 Err(failures) => {
564 let reason = DisabledReason::from_health_failures(failures).unwrap_or_else(|| {
566 DisabledReason::RpcValidationFailed("Unknown error".to_string())
567 });
568
569 warn!(reason = %reason, "disabling relayer");
570 let updated_relayer = self
571 .relayer_repository
572 .disable_relayer(self.relayer.id.clone(), reason.clone())
573 .await?;
574
575 if let Some(notification_id) = &self.relayer.notification_id {
577 self.job_producer
578 .produce_send_notification_job(
579 produce_relayer_disabled_payload(
580 notification_id,
581 &updated_relayer,
582 &reason.safe_description(),
583 ),
584 None,
585 )
586 .await?;
587 }
588
589 self.job_producer
591 .produce_relayer_health_check_job(
592 RelayerHealthCheck::new(self.relayer.id.clone()),
593 Some(calculate_scheduled_timestamp(10)),
594 )
595 .await?;
596
597 Ok(())
598 }
599 }
600 }
601
602 async fn sign_transaction(
603 &self,
604 _request: &SignTransactionRequest,
605 ) -> Result<SignTransactionExternalResponse, RelayerError> {
606 Err(RelayerError::NotSupported(
607 "Transaction signing not supported for EVM".to_string(),
608 ))
609 }
610}
611
612#[cfg(test)]
613mod tests {
614 use super::*;
615 use crate::{
616 jobs::MockJobProducerTrait,
617 models::{
618 EvmRpcRequest, EvmRpcResult, JsonRpcId, NetworkRepoModel, NetworkType,
619 RelayerEvmPolicy, RelayerNetworkPolicy, RepositoryError, SignerError,
620 TransactionStatus, U256,
621 },
622 repositories::{MockNetworkRepository, MockRelayerRepository, MockTransactionRepository},
623 services::{MockEvmProviderTrait, MockTransactionCounterServiceTrait, ProviderError},
624 };
625 use mockall::predicate::*;
626 use std::future::ready;
627
628 mockall::mock! {
629 pub DataSigner {}
630
631 #[async_trait]
632 impl DataSignerTrait for DataSigner {
633 async fn sign_data(&self, request: SignDataRequest) -> Result<SignDataResponse, SignerError>;
634 async fn sign_typed_data(&self, request: SignTypedDataRequest) -> Result<SignDataResponse, SignerError>;
635 }
636 }
637
638 fn create_test_evm_network() -> EvmNetwork {
639 EvmNetwork {
640 network: "mainnet".to_string(),
641 rpc_urls: vec!["https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY".to_string()],
642 explorer_urls: None,
643 average_blocktime_ms: 12000,
644 is_testnet: false,
645 tags: vec!["mainnet".to_string()],
646 chain_id: 1,
647 required_confirmations: 1,
648 features: vec!["eip1559".to_string()],
649 symbol: "ETH".to_string(),
650 gas_price_cache: None,
651 }
652 }
653
654 fn create_test_network_repo_model() -> NetworkRepoModel {
655 use crate::config::{EvmNetworkConfig, NetworkConfigCommon};
656
657 let config = EvmNetworkConfig {
658 common: NetworkConfigCommon {
659 network: "mainnet".to_string(),
660 from: None,
661 rpc_urls: Some(vec![
662 "https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY".to_string()
663 ]),
664 explorer_urls: None,
665 average_blocktime_ms: Some(12000),
666 is_testnet: Some(false),
667 tags: Some(vec!["mainnet".to_string()]),
668 },
669 chain_id: Some(1),
670 required_confirmations: Some(1),
671 features: Some(vec!["eip1559".to_string()]),
672 symbol: Some("ETH".to_string()),
673 gas_price_cache: None,
674 };
675
676 NetworkRepoModel::new_evm(config)
677 }
678
679 fn create_test_relayer() -> RelayerRepoModel {
680 RelayerRepoModel {
681 id: "test-relayer-id".to_string(),
682 name: "Test Relayer".to_string(),
683 network: "mainnet".to_string(), address: "0xSender".to_string(),
685 paused: false,
686 system_disabled: false,
687 signer_id: "test-signer-id".to_string(),
688 notification_id: Some("test-notification-id".to_string()),
689 policies: RelayerNetworkPolicy::Evm(RelayerEvmPolicy {
690 min_balance: Some(100000000000000000u128), whitelist_receivers: Some(vec!["0xRecipient".to_string()]),
692 gas_price_cap: Some(100000000000), eip1559_pricing: Some(true),
694 private_transactions: Some(false),
695 gas_limit_estimation: Some(true),
696 }),
697 network_type: NetworkType::Evm,
698 custom_rpc_urls: None,
699 ..Default::default()
700 }
701 }
702
703 fn setup_mocks() -> (
704 MockEvmProviderTrait,
705 MockRelayerRepository,
706 MockNetworkRepository,
707 MockTransactionRepository,
708 MockJobProducerTrait,
709 MockDataSigner,
710 MockTransactionCounterServiceTrait,
711 ) {
712 (
713 MockEvmProviderTrait::new(),
714 MockRelayerRepository::new(),
715 MockNetworkRepository::new(),
716 MockTransactionRepository::new(),
717 MockJobProducerTrait::new(),
718 MockDataSigner::new(),
719 MockTransactionCounterServiceTrait::new(),
720 )
721 }
722
723 #[tokio::test]
724 async fn test_get_balance() {
725 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
726 setup_mocks();
727 let relayer_model = create_test_relayer();
728
729 provider
730 .expect_get_balance()
731 .with(eq("0xSender"))
732 .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64))))); let relayer = EvmRelayer::new(
735 relayer_model,
736 signer,
737 provider,
738 create_test_evm_network(),
739 Arc::new(relayer_repo),
740 Arc::new(network_repo),
741 Arc::new(tx_repo),
742 Arc::new(counter),
743 Arc::new(job_producer),
744 )
745 .unwrap();
746
747 let balance = relayer.get_balance().await.unwrap();
748 assert_eq!(balance.balance, 1000000000000000000u128);
749 assert_eq!(balance.unit, EVM_SMALLEST_UNIT_NAME);
750 }
751
752 #[tokio::test]
753 async fn test_process_transaction_request() {
754 let (
755 provider,
756 relayer_repo,
757 mut network_repo,
758 mut tx_repo,
759 mut job_producer,
760 signer,
761 counter,
762 ) = setup_mocks();
763 let relayer_model = create_test_relayer();
764
765 let network_tx = NetworkTransactionRequest::Evm(crate::models::EvmTransactionRequest {
766 to: Some("0xRecipient".to_string()),
767 value: U256::from(1000000000000000000u64),
768 data: Some("0xData".to_string()),
769 gas_limit: Some(21000),
770 gas_price: Some(20000000000),
771 max_fee_per_gas: None,
772 max_priority_fee_per_gas: None,
773 speed: None,
774 valid_until: None,
775 });
776
777 network_repo
778 .expect_get_by_name()
779 .with(eq(NetworkType::Evm), eq("mainnet"))
780 .returning(|_, _| Ok(Some(create_test_network_repo_model())));
781
782 tx_repo.expect_create().returning(Ok);
783 job_producer
784 .expect_produce_transaction_request_job()
785 .returning(|_, _| Box::pin(ready(Ok(()))));
786
787 let relayer = EvmRelayer::new(
788 relayer_model,
789 signer,
790 provider,
791 create_test_evm_network(),
792 Arc::new(relayer_repo),
793 Arc::new(network_repo),
794 Arc::new(tx_repo),
795 Arc::new(counter),
796 Arc::new(job_producer),
797 )
798 .unwrap();
799
800 let result = relayer.process_transaction_request(network_tx).await;
801 assert!(result.is_ok());
802 }
803
804 #[tokio::test]
805 async fn test_validate_min_balance_sufficient() {
806 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
807 setup_mocks();
808 let relayer_model = create_test_relayer();
809
810 provider
811 .expect_get_balance()
812 .returning(|_| Box::pin(ready(Ok(U256::from(200000000000000000u64))))); let relayer = EvmRelayer::new(
815 relayer_model,
816 signer,
817 provider,
818 create_test_evm_network(),
819 Arc::new(relayer_repo),
820 Arc::new(network_repo),
821 Arc::new(tx_repo),
822 Arc::new(counter),
823 Arc::new(job_producer),
824 )
825 .unwrap();
826
827 let result = relayer.validate_min_balance().await;
828 assert!(result.is_ok());
829 }
830
831 #[tokio::test]
832 async fn test_validate_min_balance_insufficient() {
833 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
834 setup_mocks();
835 let relayer_model = create_test_relayer();
836
837 provider
838 .expect_get_balance()
839 .returning(|_| Box::pin(ready(Ok(U256::from(50000000000000000u64))))); let relayer = EvmRelayer::new(
842 relayer_model,
843 signer,
844 provider,
845 create_test_evm_network(),
846 Arc::new(relayer_repo),
847 Arc::new(network_repo),
848 Arc::new(tx_repo),
849 Arc::new(counter),
850 Arc::new(job_producer),
851 )
852 .unwrap();
853
854 let result = relayer.validate_min_balance().await;
855 assert!(matches!(
856 result,
857 Err(RelayerError::InsufficientBalanceError(_))
858 ));
859 }
860
861 #[tokio::test]
862 async fn test_sync_nonce() {
863 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, mut counter) =
864 setup_mocks();
865 let relayer_model = create_test_relayer();
866
867 provider
868 .expect_get_transaction_count()
869 .returning(|_| Box::pin(ready(Ok(42u64))));
870
871 counter
872 .expect_set()
873 .returning(|_nonce| Box::pin(ready(Ok(()))));
874
875 counter
876 .expect_get()
877 .returning(|| Box::pin(ready(Ok(Some(42u64)))));
878
879 let relayer = EvmRelayer::new(
880 relayer_model,
881 signer,
882 provider,
883 create_test_evm_network(),
884 Arc::new(relayer_repo),
885 Arc::new(network_repo),
886 Arc::new(tx_repo),
887 Arc::new(counter),
888 Arc::new(job_producer),
889 )
890 .unwrap();
891
892 let result = relayer.sync_nonce().await;
893 assert!(result.is_ok());
894 }
895
896 #[tokio::test]
897 async fn test_sync_nonce_lower_on_chain_nonce() {
898 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, mut counter) =
899 setup_mocks();
900 let relayer_model = create_test_relayer();
901
902 provider
903 .expect_get_transaction_count()
904 .returning(|_| Box::pin(ready(Ok(40u64))));
905
906 counter
907 .expect_set()
908 .with(eq(42u64))
909 .returning(|_nonce| Box::pin(ready(Ok(()))));
910
911 counter
912 .expect_get()
913 .returning(|| Box::pin(ready(Ok(Some(42u64)))));
914
915 let relayer = EvmRelayer::new(
916 relayer_model,
917 signer,
918 provider,
919 create_test_evm_network(),
920 Arc::new(relayer_repo),
921 Arc::new(network_repo),
922 Arc::new(tx_repo),
923 Arc::new(counter),
924 Arc::new(job_producer),
925 )
926 .unwrap();
927
928 let result = relayer.sync_nonce().await;
929 assert!(result.is_ok());
930 }
931
932 #[tokio::test]
933 async fn test_sync_nonce_lower_transaction_counter_nonce() {
934 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, mut counter) =
935 setup_mocks();
936 let relayer_model = create_test_relayer();
937
938 provider
939 .expect_get_transaction_count()
940 .returning(|_| Box::pin(ready(Ok(42u64))));
941
942 counter
943 .expect_set()
944 .with(eq(42u64))
945 .returning(|_nonce| Box::pin(ready(Ok(()))));
946
947 counter
948 .expect_get()
949 .returning(|| Box::pin(ready(Ok(Some(40u64)))));
950
951 let relayer = EvmRelayer::new(
952 relayer_model,
953 signer,
954 provider,
955 create_test_evm_network(),
956 Arc::new(relayer_repo),
957 Arc::new(network_repo),
958 Arc::new(tx_repo),
959 Arc::new(counter),
960 Arc::new(job_producer),
961 )
962 .unwrap();
963
964 let result = relayer.sync_nonce().await;
965 assert!(result.is_ok());
966 }
967
968 #[tokio::test]
969 async fn test_validate_rpc() {
970 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
971 setup_mocks();
972 let relayer_model = create_test_relayer();
973
974 provider
975 .expect_health_check()
976 .returning(|| Box::pin(ready(Ok(true))));
977
978 let relayer = EvmRelayer::new(
979 relayer_model,
980 signer,
981 provider,
982 create_test_evm_network(),
983 Arc::new(relayer_repo),
984 Arc::new(network_repo),
985 Arc::new(tx_repo),
986 Arc::new(counter),
987 Arc::new(job_producer),
988 )
989 .unwrap();
990
991 let result = relayer.validate_rpc().await;
992 assert!(result.is_ok());
993 }
994
995 #[tokio::test]
996 async fn test_get_status_success() {
997 let (mut provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
998 setup_mocks();
999 let relayer_model = create_test_relayer();
1000
1001 provider
1002 .expect_get_transaction_count()
1003 .returning(|_| Box::pin(ready(Ok(10u64))))
1004 .once();
1005 provider
1006 .expect_get_balance()
1007 .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64)))))
1008 .once();
1009
1010 let pending_txs_clone = vec![];
1011 tx_repo
1012 .expect_find_by_status()
1013 .withf(|relayer_id, statuses| {
1014 relayer_id == "test-relayer-id"
1015 && statuses == [TransactionStatus::Pending, TransactionStatus::Submitted]
1016 })
1017 .returning(move |_, _| {
1018 Ok(pending_txs_clone.clone()) as Result<Vec<TransactionRepoModel>, RepositoryError>
1019 })
1020 .once();
1021
1022 let confirmed_txs_clone = vec![
1023 TransactionRepoModel {
1024 id: "tx1".to_string(),
1025 relayer_id: relayer_model.id.clone(),
1026 status: TransactionStatus::Confirmed,
1027 confirmed_at: Some("2023-01-01T12:00:00Z".to_string()),
1028 ..TransactionRepoModel::default()
1029 },
1030 TransactionRepoModel {
1031 id: "tx2".to_string(),
1032 relayer_id: relayer_model.id.clone(),
1033 status: TransactionStatus::Confirmed,
1034 confirmed_at: Some("2023-01-01T10:00:00Z".to_string()),
1035 ..TransactionRepoModel::default()
1036 },
1037 ];
1038 tx_repo
1039 .expect_find_by_status()
1040 .withf(|relayer_id, statuses| {
1041 relayer_id == "test-relayer-id" && statuses == [TransactionStatus::Confirmed]
1042 })
1043 .returning(move |_, _| {
1044 Ok(confirmed_txs_clone.clone())
1045 as Result<Vec<TransactionRepoModel>, RepositoryError>
1046 })
1047 .once();
1048
1049 let relayer = EvmRelayer::new(
1050 relayer_model.clone(),
1051 signer,
1052 provider,
1053 create_test_evm_network(),
1054 Arc::new(relayer_repo),
1055 Arc::new(network_repo),
1056 Arc::new(tx_repo),
1057 Arc::new(counter),
1058 Arc::new(job_producer),
1059 )
1060 .unwrap();
1061
1062 let status = relayer.get_status().await.unwrap();
1063
1064 match status {
1065 RelayerStatus::Evm {
1066 balance,
1067 pending_transactions_count,
1068 last_confirmed_transaction_timestamp,
1069 system_disabled,
1070 paused,
1071 nonce,
1072 } => {
1073 assert_eq!(balance, "1000000000000000000");
1074 assert_eq!(pending_transactions_count, 0);
1075 assert_eq!(
1076 last_confirmed_transaction_timestamp,
1077 Some("2023-01-01T12:00:00Z".to_string())
1078 );
1079 assert_eq!(system_disabled, relayer_model.system_disabled);
1080 assert_eq!(paused, relayer_model.paused);
1081 assert_eq!(nonce, "10");
1082 }
1083 _ => panic!("Expected EVM RelayerStatus"),
1084 }
1085 }
1086
1087 #[tokio::test]
1088 async fn test_get_status_provider_nonce_error() {
1089 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1090 setup_mocks();
1091 let relayer_model = create_test_relayer();
1092
1093 provider.expect_get_transaction_count().returning(|_| {
1094 Box::pin(ready(Err(ProviderError::Other(
1095 "Nonce fetch failed".to_string(),
1096 ))))
1097 });
1098
1099 let relayer = EvmRelayer::new(
1100 relayer_model.clone(),
1101 signer,
1102 provider,
1103 create_test_evm_network(),
1104 Arc::new(relayer_repo),
1105 Arc::new(network_repo),
1106 Arc::new(tx_repo),
1107 Arc::new(counter),
1108 Arc::new(job_producer),
1109 )
1110 .unwrap();
1111
1112 let result = relayer.get_status().await;
1113 assert!(result.is_err());
1114 match result.err().unwrap() {
1115 RelayerError::ProviderError(msg) => assert!(msg.contains("Failed to get nonce")),
1116 _ => panic!("Expected ProviderError for nonce failure"),
1117 }
1118 }
1119
1120 #[tokio::test]
1121 async fn test_get_status_repository_pending_error() {
1122 let (mut provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
1123 setup_mocks();
1124 let relayer_model = create_test_relayer();
1125
1126 provider
1127 .expect_get_transaction_count()
1128 .returning(|_| Box::pin(ready(Ok(10u64))));
1129 provider
1130 .expect_get_balance()
1131 .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64)))));
1132
1133 tx_repo
1134 .expect_find_by_status()
1135 .withf(|relayer_id, statuses| {
1136 relayer_id == "test-relayer-id"
1137 && statuses == [TransactionStatus::Pending, TransactionStatus::Submitted]
1138 })
1139 .returning(|_, _| {
1140 Err(RepositoryError::Unknown("DB down".to_string()))
1141 as Result<Vec<TransactionRepoModel>, RepositoryError>
1142 })
1143 .once();
1144
1145 let relayer = EvmRelayer::new(
1146 relayer_model.clone(),
1147 signer,
1148 provider,
1149 create_test_evm_network(),
1150 Arc::new(relayer_repo),
1151 Arc::new(network_repo),
1152 Arc::new(tx_repo),
1153 Arc::new(counter),
1154 Arc::new(job_producer),
1155 )
1156 .unwrap();
1157
1158 let result = relayer.get_status().await;
1159 assert!(result.is_err());
1160 match result.err().unwrap() {
1161 RelayerError::NetworkConfiguration(msg) => assert!(msg.contains("DB down")),
1163 _ => panic!("Expected NetworkConfiguration error for repo failure"),
1164 }
1165 }
1166
1167 #[tokio::test]
1168 async fn test_get_status_no_confirmed_transactions() {
1169 let (mut provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
1170 setup_mocks();
1171 let relayer_model = create_test_relayer();
1172
1173 provider
1174 .expect_get_transaction_count()
1175 .returning(|_| Box::pin(ready(Ok(10u64))));
1176 provider
1177 .expect_get_balance()
1178 .returning(|_| Box::pin(ready(Ok(U256::from(1000000000000000000u64)))));
1179 provider
1180 .expect_health_check()
1181 .returning(|| Box::pin(ready(Ok(true))));
1182
1183 let pending_txs_empty_clone = vec![];
1184 tx_repo
1185 .expect_find_by_status()
1186 .withf(|relayer_id, statuses| {
1187 relayer_id == "test-relayer-id"
1188 && statuses == [TransactionStatus::Pending, TransactionStatus::Submitted]
1189 })
1190 .returning(move |_, _| {
1191 Ok(pending_txs_empty_clone.clone())
1192 as Result<Vec<TransactionRepoModel>, RepositoryError>
1193 })
1194 .once();
1195
1196 let confirmed_txs_empty_clone = vec![];
1197 tx_repo
1198 .expect_find_by_status()
1199 .withf(|relayer_id, statuses| {
1200 relayer_id == "test-relayer-id" && statuses == [TransactionStatus::Confirmed]
1201 })
1202 .returning(move |_, _| {
1203 Ok(confirmed_txs_empty_clone.clone())
1204 as Result<Vec<TransactionRepoModel>, RepositoryError>
1205 })
1206 .once();
1207
1208 let relayer = EvmRelayer::new(
1209 relayer_model.clone(),
1210 signer,
1211 provider,
1212 create_test_evm_network(),
1213 Arc::new(relayer_repo),
1214 Arc::new(network_repo),
1215 Arc::new(tx_repo),
1216 Arc::new(counter),
1217 Arc::new(job_producer),
1218 )
1219 .unwrap();
1220
1221 let status = relayer.get_status().await.unwrap();
1222 match status {
1223 RelayerStatus::Evm {
1224 balance,
1225 pending_transactions_count,
1226 last_confirmed_transaction_timestamp,
1227 system_disabled,
1228 paused,
1229 nonce,
1230 } => {
1231 assert_eq!(balance, "1000000000000000000");
1232 assert_eq!(pending_transactions_count, 0);
1233 assert_eq!(last_confirmed_transaction_timestamp, None);
1234 assert_eq!(system_disabled, relayer_model.system_disabled);
1235 assert_eq!(paused, relayer_model.paused);
1236 assert_eq!(nonce, "10");
1237 }
1238 _ => panic!("Expected EVM RelayerStatus"),
1239 }
1240 }
1241
1242 #[tokio::test]
1243 async fn test_cancel_transaction_via_job_success() {
1244 let (provider, relayer_repo, network_repo, tx_repo, mut job_producer, signer, counter) =
1245 setup_mocks();
1246 let relayer_model = create_test_relayer();
1247
1248 let test_transaction = TransactionRepoModel {
1249 id: "test-tx-id".to_string(),
1250 relayer_id: relayer_model.id.clone(),
1251 status: TransactionStatus::Pending,
1252 ..TransactionRepoModel::default()
1253 };
1254
1255 job_producer
1256 .expect_produce_submit_transaction_job()
1257 .withf(|job, delay| {
1258 matches!(job.command, crate::jobs::TransactionCommand::Cancel { ref reason }
1259 if job.transaction_id == "test-tx-id"
1260 && job.relayer_id == "test-relayer-id"
1261 && reason == "Cancelled via delete_pending_transactions")
1262 && delay.is_none()
1263 })
1264 .returning(|_, _| Box::pin(ready(Ok(()))))
1265 .once();
1266
1267 let relayer = EvmRelayer::new(
1268 relayer_model,
1269 signer,
1270 provider,
1271 create_test_evm_network(),
1272 Arc::new(relayer_repo),
1273 Arc::new(network_repo),
1274 Arc::new(tx_repo),
1275 Arc::new(counter),
1276 Arc::new(job_producer),
1277 )
1278 .unwrap();
1279
1280 let result = relayer.cancel_transaction_via_job(test_transaction).await;
1281 assert!(result.is_ok());
1282 }
1283
1284 #[tokio::test]
1285 async fn test_cancel_transaction_via_job_failure() {
1286 let (provider, relayer_repo, network_repo, tx_repo, mut job_producer, signer, counter) =
1287 setup_mocks();
1288 let relayer_model = create_test_relayer();
1289
1290 let test_transaction = TransactionRepoModel {
1291 id: "test-tx-id".to_string(),
1292 relayer_id: relayer_model.id.clone(),
1293 status: TransactionStatus::Pending,
1294 ..TransactionRepoModel::default()
1295 };
1296
1297 job_producer
1298 .expect_produce_submit_transaction_job()
1299 .returning(|_, _| {
1300 Box::pin(ready(Err(crate::jobs::JobProducerError::QueueError(
1301 "Queue is full".to_string(),
1302 ))))
1303 })
1304 .once();
1305
1306 let relayer = EvmRelayer::new(
1307 relayer_model,
1308 signer,
1309 provider,
1310 create_test_evm_network(),
1311 Arc::new(relayer_repo),
1312 Arc::new(network_repo),
1313 Arc::new(tx_repo),
1314 Arc::new(counter),
1315 Arc::new(job_producer),
1316 )
1317 .unwrap();
1318
1319 let result = relayer.cancel_transaction_via_job(test_transaction).await;
1320 assert!(result.is_err());
1321 match result.err().unwrap() {
1322 RelayerError::QueueError(_) => (),
1323 _ => panic!("Expected QueueError"),
1324 }
1325 }
1326
1327 #[tokio::test]
1328 async fn test_delete_pending_transactions_no_pending() {
1329 let (provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
1330 setup_mocks();
1331 let relayer_model = create_test_relayer();
1332
1333 tx_repo
1334 .expect_find_by_status()
1335 .withf(|relayer_id, statuses| {
1336 relayer_id == "test-relayer-id"
1337 && statuses
1338 == [
1339 TransactionStatus::Pending,
1340 TransactionStatus::Sent,
1341 TransactionStatus::Submitted,
1342 ]
1343 })
1344 .returning(|_, _| Ok(vec![]))
1345 .once();
1346
1347 let relayer = EvmRelayer::new(
1348 relayer_model,
1349 signer,
1350 provider,
1351 create_test_evm_network(),
1352 Arc::new(relayer_repo),
1353 Arc::new(network_repo),
1354 Arc::new(tx_repo),
1355 Arc::new(counter),
1356 Arc::new(job_producer),
1357 )
1358 .unwrap();
1359
1360 let result = relayer.delete_pending_transactions().await.unwrap();
1361 assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 0);
1362 assert_eq!(result.failed_to_queue_transaction_ids.len(), 0);
1363 assert_eq!(result.total_processed, 0);
1364 }
1365
1366 #[tokio::test]
1367 async fn test_delete_pending_transactions_all_successful() {
1368 let (provider, relayer_repo, network_repo, mut tx_repo, mut job_producer, signer, counter) =
1369 setup_mocks();
1370 let relayer_model = create_test_relayer();
1371
1372 let pending_transactions = vec![
1373 TransactionRepoModel {
1374 id: "tx1".to_string(),
1375 relayer_id: relayer_model.id.clone(),
1376 status: TransactionStatus::Pending,
1377 ..TransactionRepoModel::default()
1378 },
1379 TransactionRepoModel {
1380 id: "tx2".to_string(),
1381 relayer_id: relayer_model.id.clone(),
1382 status: TransactionStatus::Sent,
1383 ..TransactionRepoModel::default()
1384 },
1385 TransactionRepoModel {
1386 id: "tx3".to_string(),
1387 relayer_id: relayer_model.id.clone(),
1388 status: TransactionStatus::Submitted,
1389 ..TransactionRepoModel::default()
1390 },
1391 ];
1392
1393 tx_repo
1394 .expect_find_by_status()
1395 .withf(|relayer_id, statuses| {
1396 relayer_id == "test-relayer-id"
1397 && statuses
1398 == [
1399 TransactionStatus::Pending,
1400 TransactionStatus::Sent,
1401 TransactionStatus::Submitted,
1402 ]
1403 })
1404 .returning(move |_, _| Ok(pending_transactions.clone()))
1405 .once();
1406
1407 job_producer
1408 .expect_produce_submit_transaction_job()
1409 .returning(|_, _| Box::pin(ready(Ok(()))))
1410 .times(3);
1411
1412 let relayer = EvmRelayer::new(
1413 relayer_model,
1414 signer,
1415 provider,
1416 create_test_evm_network(),
1417 Arc::new(relayer_repo),
1418 Arc::new(network_repo),
1419 Arc::new(tx_repo),
1420 Arc::new(counter),
1421 Arc::new(job_producer),
1422 )
1423 .unwrap();
1424
1425 let result = relayer.delete_pending_transactions().await.unwrap();
1426 assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 3);
1427 assert_eq!(result.failed_to_queue_transaction_ids.len(), 0);
1428 assert_eq!(result.total_processed, 3);
1429
1430 let expected_ids = vec!["tx1", "tx2", "tx3"];
1431 for id in expected_ids {
1432 assert!(result
1433 .queued_for_cancellation_transaction_ids
1434 .contains(&id.to_string()));
1435 }
1436 }
1437
1438 #[tokio::test]
1439 async fn test_delete_pending_transactions_partial_failures() {
1440 let (provider, relayer_repo, network_repo, mut tx_repo, mut job_producer, signer, counter) =
1441 setup_mocks();
1442 let relayer_model = create_test_relayer();
1443
1444 let pending_transactions = vec![
1445 TransactionRepoModel {
1446 id: "tx1".to_string(),
1447 relayer_id: relayer_model.id.clone(),
1448 status: TransactionStatus::Pending,
1449 ..TransactionRepoModel::default()
1450 },
1451 TransactionRepoModel {
1452 id: "tx2".to_string(),
1453 relayer_id: relayer_model.id.clone(),
1454 status: TransactionStatus::Sent,
1455 ..TransactionRepoModel::default()
1456 },
1457 TransactionRepoModel {
1458 id: "tx3".to_string(),
1459 relayer_id: relayer_model.id.clone(),
1460 status: TransactionStatus::Submitted,
1461 ..TransactionRepoModel::default()
1462 },
1463 ];
1464
1465 tx_repo
1466 .expect_find_by_status()
1467 .withf(|relayer_id, statuses| {
1468 relayer_id == "test-relayer-id"
1469 && statuses
1470 == [
1471 TransactionStatus::Pending,
1472 TransactionStatus::Sent,
1473 TransactionStatus::Submitted,
1474 ]
1475 })
1476 .returning(move |_, _| Ok(pending_transactions.clone()))
1477 .once();
1478
1479 job_producer
1481 .expect_produce_submit_transaction_job()
1482 .returning(|_, _| Box::pin(ready(Ok(()))))
1483 .times(1);
1484 job_producer
1485 .expect_produce_submit_transaction_job()
1486 .returning(|_, _| {
1487 Box::pin(ready(Err(crate::jobs::JobProducerError::QueueError(
1488 "Queue is full".to_string(),
1489 ))))
1490 })
1491 .times(1);
1492 job_producer
1493 .expect_produce_submit_transaction_job()
1494 .returning(|_, _| Box::pin(ready(Ok(()))))
1495 .times(1);
1496
1497 let relayer = EvmRelayer::new(
1498 relayer_model,
1499 signer,
1500 provider,
1501 create_test_evm_network(),
1502 Arc::new(relayer_repo),
1503 Arc::new(network_repo),
1504 Arc::new(tx_repo),
1505 Arc::new(counter),
1506 Arc::new(job_producer),
1507 )
1508 .unwrap();
1509
1510 let result = relayer.delete_pending_transactions().await.unwrap();
1511 assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 2);
1512 assert_eq!(result.failed_to_queue_transaction_ids.len(), 1);
1513 assert_eq!(result.total_processed, 3);
1514 }
1515
1516 #[tokio::test]
1517 async fn test_delete_pending_transactions_repository_error() {
1518 let (provider, relayer_repo, network_repo, mut tx_repo, job_producer, signer, counter) =
1519 setup_mocks();
1520 let relayer_model = create_test_relayer();
1521
1522 tx_repo
1523 .expect_find_by_status()
1524 .withf(|relayer_id, statuses| {
1525 relayer_id == "test-relayer-id"
1526 && statuses
1527 == [
1528 TransactionStatus::Pending,
1529 TransactionStatus::Sent,
1530 TransactionStatus::Submitted,
1531 ]
1532 })
1533 .returning(|_, _| {
1534 Err(RepositoryError::Unknown(
1535 "Database connection failed".to_string(),
1536 ))
1537 })
1538 .once();
1539
1540 let relayer = EvmRelayer::new(
1541 relayer_model,
1542 signer,
1543 provider,
1544 create_test_evm_network(),
1545 Arc::new(relayer_repo),
1546 Arc::new(network_repo),
1547 Arc::new(tx_repo),
1548 Arc::new(counter),
1549 Arc::new(job_producer),
1550 )
1551 .unwrap();
1552
1553 let result = relayer.delete_pending_transactions().await;
1554 assert!(result.is_err());
1555 match result.err().unwrap() {
1556 RelayerError::NetworkConfiguration(msg) => {
1557 assert!(msg.contains("Database connection failed"))
1558 }
1559 _ => panic!("Expected NetworkConfiguration error for repository failure"),
1560 }
1561 }
1562
1563 #[tokio::test]
1564 async fn test_delete_pending_transactions_all_failures() {
1565 let (provider, relayer_repo, network_repo, mut tx_repo, mut job_producer, signer, counter) =
1566 setup_mocks();
1567 let relayer_model = create_test_relayer();
1568
1569 let pending_transactions = vec![
1570 TransactionRepoModel {
1571 id: "tx1".to_string(),
1572 relayer_id: relayer_model.id.clone(),
1573 status: TransactionStatus::Pending,
1574 ..TransactionRepoModel::default()
1575 },
1576 TransactionRepoModel {
1577 id: "tx2".to_string(),
1578 relayer_id: relayer_model.id.clone(),
1579 status: TransactionStatus::Sent,
1580 ..TransactionRepoModel::default()
1581 },
1582 ];
1583
1584 tx_repo
1585 .expect_find_by_status()
1586 .withf(|relayer_id, statuses| {
1587 relayer_id == "test-relayer-id"
1588 && statuses
1589 == [
1590 TransactionStatus::Pending,
1591 TransactionStatus::Sent,
1592 TransactionStatus::Submitted,
1593 ]
1594 })
1595 .returning(move |_, _| Ok(pending_transactions.clone()))
1596 .once();
1597
1598 job_producer
1599 .expect_produce_submit_transaction_job()
1600 .returning(|_, _| {
1601 Box::pin(ready(Err(crate::jobs::JobProducerError::QueueError(
1602 "Queue is full".to_string(),
1603 ))))
1604 })
1605 .times(2);
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 result = relayer.delete_pending_transactions().await.unwrap();
1621 assert_eq!(result.queued_for_cancellation_transaction_ids.len(), 0);
1622 assert_eq!(result.failed_to_queue_transaction_ids.len(), 2);
1623 assert_eq!(result.total_processed, 2);
1624
1625 let expected_failed_ids = vec!["tx1", "tx2"];
1626 for id in expected_failed_ids {
1627 assert!(result
1628 .failed_to_queue_transaction_ids
1629 .contains(&id.to_string()));
1630 }
1631 }
1632
1633 #[tokio::test]
1634 async fn test_rpc_eth_get_balance() {
1635 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1636 setup_mocks();
1637 let relayer_model = create_test_relayer();
1638
1639 provider
1640 .expect_raw_request_dyn()
1641 .withf(|method, params| {
1642 method == "eth_getBalance"
1643 && params.as_str()
1644 == Some(r#"["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]"#)
1645 })
1646 .returning(|_, _| Box::pin(async { Ok(serde_json::json!("0xde0b6b3a7640000")) }));
1647
1648 let relayer = EvmRelayer::new(
1649 relayer_model,
1650 signer,
1651 provider,
1652 create_test_evm_network(),
1653 Arc::new(relayer_repo),
1654 Arc::new(network_repo),
1655 Arc::new(tx_repo),
1656 Arc::new(counter),
1657 Arc::new(job_producer),
1658 )
1659 .unwrap();
1660
1661 let request = JsonRpcRequest {
1662 jsonrpc: "2.0".to_string(),
1663 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1664 method: "eth_getBalance".to_string(),
1665 params: r#"["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]"#.to_string(),
1666 }),
1667 id: Some(JsonRpcId::Number(1)),
1668 };
1669
1670 let response = relayer.rpc(request).await.unwrap();
1671 assert!(response.error.is_none());
1672 assert!(response.result.is_some());
1673
1674 if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
1675 assert_eq!(result, serde_json::json!("0xde0b6b3a7640000")); }
1677 }
1678
1679 #[tokio::test]
1680 async fn test_rpc_eth_block_number() {
1681 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1682 setup_mocks();
1683 let relayer_model = create_test_relayer();
1684
1685 provider
1686 .expect_raw_request_dyn()
1687 .withf(|method, params| method == "eth_blockNumber" && params.as_str() == Some("[]"))
1688 .returning(|_, _| Box::pin(async { Ok(serde_json::json!("0x3039")) }));
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::Evm(EvmRpcRequest::GenericRpcRequest {
1706 method: "eth_blockNumber".to_string(),
1707 params: "[]".to_string(),
1708 }),
1709 id: Some(JsonRpcId::Number(1)),
1710 };
1711
1712 let response = relayer.rpc(request).await.unwrap();
1713 assert!(response.error.is_none());
1714 assert!(response.result.is_some());
1715
1716 if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
1717 assert_eq!(result, serde_json::json!("0x3039")); }
1719 }
1720
1721 #[tokio::test]
1722 async fn test_rpc_unsupported_method() {
1723 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1724 setup_mocks();
1725 let relayer_model = create_test_relayer();
1726
1727 provider
1728 .expect_raw_request_dyn()
1729 .withf(|method, _| method == "eth_unsupportedMethod")
1730 .returning(|_, _| {
1731 Box::pin(async {
1732 Err(ProviderError::Other(
1733 "Unsupported method: eth_unsupportedMethod".to_string(),
1734 ))
1735 })
1736 });
1737
1738 let relayer = EvmRelayer::new(
1739 relayer_model,
1740 signer,
1741 provider,
1742 create_test_evm_network(),
1743 Arc::new(relayer_repo),
1744 Arc::new(network_repo),
1745 Arc::new(tx_repo),
1746 Arc::new(counter),
1747 Arc::new(job_producer),
1748 )
1749 .unwrap();
1750
1751 let request = JsonRpcRequest {
1752 jsonrpc: "2.0".to_string(),
1753 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1754 method: "eth_unsupportedMethod".to_string(),
1755 params: "[]".to_string(),
1756 }),
1757 id: Some(JsonRpcId::Number(1)),
1758 };
1759
1760 let response = relayer.rpc(request).await.unwrap();
1761 assert!(response.result.is_none());
1762 assert!(response.error.is_some());
1763
1764 let error = response.error.unwrap();
1765 assert_eq!(error.code, -32603); }
1767
1768 #[tokio::test]
1769 async fn test_rpc_invalid_params() {
1770 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1771 setup_mocks();
1772 let relayer_model = create_test_relayer();
1773
1774 provider
1775 .expect_raw_request_dyn()
1776 .withf(|method, params| method == "eth_getBalance" && params.as_str() == Some("[]"))
1777 .returning(|_, _| {
1778 Box::pin(async {
1779 Err(ProviderError::Other(
1780 "Missing address parameter".to_string(),
1781 ))
1782 })
1783 });
1784
1785 let relayer = EvmRelayer::new(
1786 relayer_model,
1787 signer,
1788 provider,
1789 create_test_evm_network(),
1790 Arc::new(relayer_repo),
1791 Arc::new(network_repo),
1792 Arc::new(tx_repo),
1793 Arc::new(counter),
1794 Arc::new(job_producer),
1795 )
1796 .unwrap();
1797
1798 let request = JsonRpcRequest {
1799 jsonrpc: "2.0".to_string(),
1800 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1801 method: "eth_getBalance".to_string(),
1802 params: "[]".to_string(), }),
1804 id: Some(JsonRpcId::Number(1)),
1805 };
1806
1807 let response = relayer.rpc(request).await.unwrap();
1808 assert!(response.result.is_none());
1809 assert!(response.error.is_some());
1810
1811 let error = response.error.unwrap();
1812 assert_eq!(error.code, -32603); }
1814
1815 #[tokio::test]
1816 async fn test_rpc_non_evm_request() {
1817 let (provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1818 setup_mocks();
1819 let relayer_model = create_test_relayer();
1820
1821 let relayer = EvmRelayer::new(
1822 relayer_model,
1823 signer,
1824 provider,
1825 create_test_evm_network(),
1826 Arc::new(relayer_repo),
1827 Arc::new(network_repo),
1828 Arc::new(tx_repo),
1829 Arc::new(counter),
1830 Arc::new(job_producer),
1831 )
1832 .unwrap();
1833
1834 let request = JsonRpcRequest {
1835 jsonrpc: "2.0".to_string(),
1836 params: NetworkRpcRequest::Solana(crate::models::SolanaRpcRequest::GetSupportedTokens(
1837 crate::models::GetSupportedTokensRequestParams {},
1838 )),
1839 id: Some(JsonRpcId::Number(1)),
1840 };
1841
1842 let response = relayer.rpc(request).await.unwrap();
1843 assert!(response.result.is_none());
1844 assert!(response.error.is_some());
1845
1846 let error = response.error.unwrap();
1847 assert_eq!(error.code, -32602); }
1849
1850 #[tokio::test]
1851 async fn test_rpc_raw_request_with_array_params() {
1852 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1853 setup_mocks();
1854 let relayer_model = create_test_relayer();
1855
1856 provider
1857 .expect_raw_request_dyn()
1858 .withf(|method, params| {
1859 method == "eth_getTransactionByHash"
1860 && params.as_array().is_some_and(|arr| {
1861 arr.len() == 1 && arr[0].as_str() == Some("0x1234567890abcdef")
1862 })
1863 })
1864 .returning(|_, _| {
1865 Box::pin(async {
1866 Ok(serde_json::json!({
1867 "hash": "0x1234567890abcdef",
1868 "blockNumber": "0x1",
1869 "gasUsed": "0x5208"
1870 }))
1871 })
1872 });
1873
1874 let relayer = EvmRelayer::new(
1875 relayer_model,
1876 signer,
1877 provider,
1878 create_test_evm_network(),
1879 Arc::new(relayer_repo),
1880 Arc::new(network_repo),
1881 Arc::new(tx_repo),
1882 Arc::new(counter),
1883 Arc::new(job_producer),
1884 )
1885 .unwrap();
1886
1887 let request = JsonRpcRequest {
1888 jsonrpc: "2.0".to_string(),
1889 params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
1890 method: "eth_getTransactionByHash".to_string(),
1891 params: serde_json::json!(["0x1234567890abcdef"]),
1892 }),
1893 id: Some(JsonRpcId::Number(42)),
1894 };
1895
1896 let response = relayer.rpc(request).await.unwrap();
1897 assert!(response.error.is_none());
1898 assert!(response.result.is_some());
1899 assert_eq!(response.id, Some(JsonRpcId::Number(42)));
1900
1901 if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
1902 assert!(result.get("hash").is_some());
1903 assert!(result.get("blockNumber").is_some());
1904 }
1905 }
1906
1907 #[tokio::test]
1908 async fn test_rpc_raw_request_with_object_params() {
1909 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1910 setup_mocks();
1911 let relayer_model = create_test_relayer();
1912
1913 provider
1914 .expect_raw_request_dyn()
1915 .withf(|method, params| {
1916 method == "eth_call"
1917 && params
1918 .as_object()
1919 .is_some_and(|obj| obj.contains_key("to") && obj.contains_key("data"))
1920 })
1921 .returning(|_, _| {
1922 Box::pin(async {
1923 Ok(serde_json::json!(
1924 "0x0000000000000000000000000000000000000000000000000000000000000001"
1925 ))
1926 })
1927 });
1928
1929 let relayer = EvmRelayer::new(
1930 relayer_model,
1931 signer,
1932 provider,
1933 create_test_evm_network(),
1934 Arc::new(relayer_repo),
1935 Arc::new(network_repo),
1936 Arc::new(tx_repo),
1937 Arc::new(counter),
1938 Arc::new(job_producer),
1939 )
1940 .unwrap();
1941
1942 let request = JsonRpcRequest {
1943 jsonrpc: "2.0".to_string(),
1944 params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
1945 method: "eth_call".to_string(),
1946 params: serde_json::json!({
1947 "to": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
1948 "data": "0x70a08231000000000000000000000000742d35cc6634c0532925a3b844bc454e4438f44e"
1949 }),
1950 }),
1951 id: Some(JsonRpcId::Number(123)),
1952 };
1953
1954 let response = relayer.rpc(request).await.unwrap();
1955 assert!(response.error.is_none());
1956 assert!(response.result.is_some());
1957 assert_eq!(response.id, Some(JsonRpcId::Number(123)));
1958 }
1959
1960 #[tokio::test]
1961 async fn test_rpc_generic_request_with_empty_params() {
1962 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
1963 setup_mocks();
1964 let relayer_model = create_test_relayer();
1965
1966 provider
1967 .expect_raw_request_dyn()
1968 .withf(|method, params| method == "net_version" && params.as_str() == Some("[]"))
1969 .returning(|_, _| Box::pin(async { Ok(serde_json::json!("1")) }));
1970
1971 let relayer = EvmRelayer::new(
1972 relayer_model,
1973 signer,
1974 provider,
1975 create_test_evm_network(),
1976 Arc::new(relayer_repo),
1977 Arc::new(network_repo),
1978 Arc::new(tx_repo),
1979 Arc::new(counter),
1980 Arc::new(job_producer),
1981 )
1982 .unwrap();
1983
1984 let request = JsonRpcRequest {
1985 jsonrpc: "2.0".to_string(),
1986 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
1987 method: "net_version".to_string(),
1988 params: "[]".to_string(),
1989 }),
1990 id: Some(JsonRpcId::Number(999)),
1991 };
1992
1993 let response = relayer.rpc(request).await.unwrap();
1994 assert!(response.error.is_none());
1995 assert!(response.result.is_some());
1996 assert_eq!(response.id, Some(JsonRpcId::Number(999)));
1997 }
1998
1999 #[tokio::test]
2000 async fn test_rpc_provider_invalid_address_error() {
2001 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2002 setup_mocks();
2003 let relayer_model = create_test_relayer();
2004
2005 provider.expect_raw_request_dyn().returning(|_, _| {
2006 Box::pin(async {
2007 Err(ProviderError::InvalidAddress(
2008 "Invalid address format".to_string(),
2009 ))
2010 })
2011 });
2012
2013 let relayer = EvmRelayer::new(
2014 relayer_model,
2015 signer,
2016 provider,
2017 create_test_evm_network(),
2018 Arc::new(relayer_repo),
2019 Arc::new(network_repo),
2020 Arc::new(tx_repo),
2021 Arc::new(counter),
2022 Arc::new(job_producer),
2023 )
2024 .unwrap();
2025
2026 let request = JsonRpcRequest {
2027 jsonrpc: "2.0".to_string(),
2028 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2029 method: "eth_getBalance".to_string(),
2030 params: r#"["invalid_address", "latest"]"#.to_string(),
2031 }),
2032 id: Some(JsonRpcId::Number(1)),
2033 };
2034
2035 let response = relayer.rpc(request).await.unwrap();
2036 assert!(response.result.is_none());
2037 assert!(response.error.is_some());
2038
2039 let error = response.error.unwrap();
2040 assert_eq!(error.code, -32602); }
2042
2043 #[tokio::test]
2044 async fn test_rpc_provider_network_configuration_error() {
2045 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2046 setup_mocks();
2047 let relayer_model = create_test_relayer();
2048
2049 provider.expect_raw_request_dyn().returning(|_, _| {
2050 Box::pin(async {
2051 Err(ProviderError::NetworkConfiguration(
2052 "Network not reachable".to_string(),
2053 ))
2054 })
2055 });
2056
2057 let relayer = EvmRelayer::new(
2058 relayer_model,
2059 signer,
2060 provider,
2061 create_test_evm_network(),
2062 Arc::new(relayer_repo),
2063 Arc::new(network_repo),
2064 Arc::new(tx_repo),
2065 Arc::new(counter),
2066 Arc::new(job_producer),
2067 )
2068 .unwrap();
2069
2070 let request = JsonRpcRequest {
2071 jsonrpc: "2.0".to_string(),
2072 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2073 method: "eth_chainId".to_string(),
2074 params: "[]".to_string(),
2075 }),
2076 id: Some(JsonRpcId::Number(2)),
2077 };
2078
2079 let response = relayer.rpc(request).await.unwrap();
2080 assert!(response.result.is_none());
2081 assert!(response.error.is_some());
2082
2083 let error = response.error.unwrap();
2084 assert_eq!(error.code, -33004); }
2086
2087 #[tokio::test]
2088 async fn test_rpc_provider_timeout_error() {
2089 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2090 setup_mocks();
2091 let relayer_model = create_test_relayer();
2092
2093 provider
2094 .expect_raw_request_dyn()
2095 .returning(|_, _| Box::pin(async { Err(ProviderError::Timeout) }));
2096
2097 let relayer = EvmRelayer::new(
2098 relayer_model,
2099 signer,
2100 provider,
2101 create_test_evm_network(),
2102 Arc::new(relayer_repo),
2103 Arc::new(network_repo),
2104 Arc::new(tx_repo),
2105 Arc::new(counter),
2106 Arc::new(job_producer),
2107 )
2108 .unwrap();
2109
2110 let request = JsonRpcRequest {
2111 jsonrpc: "2.0".to_string(),
2112 params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
2113 method: "eth_blockNumber".to_string(),
2114 params: serde_json::json!([]),
2115 }),
2116 id: Some(JsonRpcId::Number(3)),
2117 };
2118
2119 let response = relayer.rpc(request).await.unwrap();
2120 assert!(response.result.is_none());
2121 assert!(response.error.is_some());
2122
2123 let error = response.error.unwrap();
2124 assert_eq!(error.code, -33000); }
2126
2127 #[tokio::test]
2128 async fn test_rpc_provider_rate_limited_error() {
2129 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2130 setup_mocks();
2131 let relayer_model = create_test_relayer();
2132
2133 provider
2134 .expect_raw_request_dyn()
2135 .returning(|_, _| Box::pin(async { Err(ProviderError::RateLimited) }));
2136
2137 let relayer = EvmRelayer::new(
2138 relayer_model,
2139 signer,
2140 provider,
2141 create_test_evm_network(),
2142 Arc::new(relayer_repo),
2143 Arc::new(network_repo),
2144 Arc::new(tx_repo),
2145 Arc::new(counter),
2146 Arc::new(job_producer),
2147 )
2148 .unwrap();
2149
2150 let request = JsonRpcRequest {
2151 jsonrpc: "2.0".to_string(),
2152 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2153 method: "eth_getBalance".to_string(),
2154 params: r#"["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]"#.to_string(),
2155 }),
2156 id: Some(JsonRpcId::Number(4)),
2157 };
2158
2159 let response = relayer.rpc(request).await.unwrap();
2160 assert!(response.result.is_none());
2161 assert!(response.error.is_some());
2162
2163 let error = response.error.unwrap();
2164 assert_eq!(error.code, -33001); }
2166
2167 #[tokio::test]
2168 async fn test_rpc_provider_bad_gateway_error() {
2169 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2170 setup_mocks();
2171 let relayer_model = create_test_relayer();
2172
2173 provider
2174 .expect_raw_request_dyn()
2175 .returning(|_, _| Box::pin(async { Err(ProviderError::BadGateway) }));
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::RawRpcRequest {
2193 method: "eth_gasPrice".to_string(),
2194 params: serde_json::json!([]),
2195 }),
2196 id: Some(JsonRpcId::Number(5)),
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, -33002); }
2206
2207 #[tokio::test]
2208 async fn test_rpc_provider_request_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::RequestError {
2216 error: "Bad request".to_string(),
2217 status_code: 400,
2218 })
2219 })
2220 });
2221
2222 let relayer = EvmRelayer::new(
2223 relayer_model,
2224 signer,
2225 provider,
2226 create_test_evm_network(),
2227 Arc::new(relayer_repo),
2228 Arc::new(network_repo),
2229 Arc::new(tx_repo),
2230 Arc::new(counter),
2231 Arc::new(job_producer),
2232 )
2233 .unwrap();
2234
2235 let request = JsonRpcRequest {
2236 jsonrpc: "2.0".to_string(),
2237 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2238 method: "invalid_method".to_string(),
2239 params: "{}".to_string(),
2240 }),
2241 id: Some(JsonRpcId::Number(6)),
2242 };
2243
2244 let response = relayer.rpc(request).await.unwrap();
2245 assert!(response.result.is_none());
2246 assert!(response.error.is_some());
2247
2248 let error = response.error.unwrap();
2249 assert_eq!(error.code, -33003); }
2251
2252 #[tokio::test]
2253 async fn test_rpc_provider_other_error() {
2254 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2255 setup_mocks();
2256 let relayer_model = create_test_relayer();
2257
2258 provider.expect_raw_request_dyn().returning(|_, _| {
2259 Box::pin(async {
2260 Err(ProviderError::Other(
2261 "Unexpected error occurred".to_string(),
2262 ))
2263 })
2264 });
2265
2266 let relayer = EvmRelayer::new(
2267 relayer_model,
2268 signer,
2269 provider,
2270 create_test_evm_network(),
2271 Arc::new(relayer_repo),
2272 Arc::new(network_repo),
2273 Arc::new(tx_repo),
2274 Arc::new(counter),
2275 Arc::new(job_producer),
2276 )
2277 .unwrap();
2278
2279 let request = JsonRpcRequest {
2280 jsonrpc: "2.0".to_string(),
2281 params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
2282 method: "eth_getBalance".to_string(),
2283 params: serde_json::json!(["0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "latest"]),
2284 }),
2285 id: Some(JsonRpcId::Number(7)),
2286 };
2287
2288 let response = relayer.rpc(request).await.unwrap();
2289 assert!(response.result.is_none());
2290 assert!(response.error.is_some());
2291
2292 let error = response.error.unwrap();
2293 assert_eq!(error.code, -32603); }
2295
2296 #[tokio::test]
2297 async fn test_rpc_response_preserves_request_id() {
2298 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2299 setup_mocks();
2300 let relayer_model = create_test_relayer();
2301
2302 provider
2303 .expect_raw_request_dyn()
2304 .returning(|_, _| Box::pin(async { Ok(serde_json::json!("0x1")) }));
2305
2306 let relayer = EvmRelayer::new(
2307 relayer_model,
2308 signer,
2309 provider,
2310 create_test_evm_network(),
2311 Arc::new(relayer_repo),
2312 Arc::new(network_repo),
2313 Arc::new(tx_repo),
2314 Arc::new(counter),
2315 Arc::new(job_producer),
2316 )
2317 .unwrap();
2318
2319 let request_id = u64::MAX;
2320 let request = JsonRpcRequest {
2321 jsonrpc: "2.0".to_string(),
2322 params: NetworkRpcRequest::Evm(EvmRpcRequest::GenericRpcRequest {
2323 method: "eth_chainId".to_string(),
2324 params: "[]".to_string(),
2325 }),
2326 id: Some(JsonRpcId::Number(request_id as i64)),
2327 };
2328
2329 let response = relayer.rpc(request).await.unwrap();
2330 assert_eq!(response.id, Some(JsonRpcId::Number(request_id as i64)));
2331 assert_eq!(response.jsonrpc, "2.0");
2332 }
2333
2334 #[tokio::test]
2335 async fn test_rpc_handles_complex_json_response() {
2336 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, counter) =
2337 setup_mocks();
2338 let relayer_model = create_test_relayer();
2339
2340 let complex_response = serde_json::json!({
2341 "number": "0x1b4",
2342 "hash": "0xdc0818cf78f21a8e70579cb46a43643f78291264dda342ae31049421c82d21ae",
2343 "parentHash": "0xe99e022112df268ce40b8b654759b4f39c3cc1b8c86b2f4c7da48ba6d8a6ae8b",
2344 "transactions": [
2345 {
2346 "hash": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060",
2347 "from": "0xa7d9ddbe1f17865597fbd27ec712455208b6b76d",
2348 "to": "0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb",
2349 "value": "0xf3dbb76162000"
2350 }
2351 ],
2352 "gasUsed": "0x5208"
2353 });
2354
2355 provider.expect_raw_request_dyn().returning(move |_, _| {
2356 let response = complex_response.clone();
2357 Box::pin(async move { Ok(response) })
2358 });
2359
2360 let relayer = EvmRelayer::new(
2361 relayer_model,
2362 signer,
2363 provider,
2364 create_test_evm_network(),
2365 Arc::new(relayer_repo),
2366 Arc::new(network_repo),
2367 Arc::new(tx_repo),
2368 Arc::new(counter),
2369 Arc::new(job_producer),
2370 )
2371 .unwrap();
2372
2373 let request = JsonRpcRequest {
2374 jsonrpc: "2.0".to_string(),
2375 params: NetworkRpcRequest::Evm(EvmRpcRequest::RawRpcRequest {
2376 method: "eth_getBlockByNumber".to_string(),
2377 params: serde_json::json!(["0x1b4", true]),
2378 }),
2379 id: Some(JsonRpcId::Number(8)),
2380 };
2381
2382 let response = relayer.rpc(request).await.unwrap();
2383 assert!(response.error.is_none());
2384 assert!(response.result.is_some());
2385
2386 if let Some(NetworkRpcResult::Evm(EvmRpcResult::RawRpcResult(result))) = response.result {
2387 assert!(result.get("transactions").is_some());
2388 assert!(result.get("hash").is_some());
2389 assert!(result.get("gasUsed").is_some());
2390 }
2391 }
2392
2393 #[tokio::test]
2394 async fn test_initialize_relayer_disables_when_validation_fails() {
2395 let (
2396 mut provider,
2397 mut relayer_repo,
2398 network_repo,
2399 tx_repo,
2400 mut job_producer,
2401 signer,
2402 mut counter,
2403 ) = setup_mocks();
2404 let mut relayer_model = create_test_relayer();
2405 relayer_model.system_disabled = false; relayer_model.notification_id = Some("test-notification-id".to_string());
2407
2408 provider
2410 .expect_get_transaction_count()
2411 .returning(|_| Box::pin(ready(Err(ProviderError::Other("RPC error".to_string())))));
2412
2413 counter
2414 .expect_get()
2415 .returning(|| Box::pin(ready(Ok(Some(0u64)))));
2416
2417 provider
2419 .expect_get_balance()
2420 .returning(|_| Box::pin(ready(Ok(U256::from(200000000000000000u64)))));
2421
2422 provider
2423 .expect_health_check()
2424 .returning(|| Box::pin(ready(Ok(true))));
2425
2426 let mut disabled_relayer = relayer_model.clone();
2428 disabled_relayer.system_disabled = true;
2429 relayer_repo
2430 .expect_disable_relayer()
2431 .with(eq("test-relayer-id".to_string()), always())
2432 .returning(move |_, _| Ok(disabled_relayer.clone()));
2433
2434 job_producer
2436 .expect_produce_send_notification_job()
2437 .returning(|_, _| Box::pin(ready(Ok(()))));
2438
2439 job_producer
2441 .expect_produce_relayer_health_check_job()
2442 .returning(|_, _| Box::pin(ready(Ok(()))));
2443
2444 let relayer = EvmRelayer::new(
2445 relayer_model,
2446 signer,
2447 provider,
2448 create_test_evm_network(),
2449 Arc::new(relayer_repo),
2450 Arc::new(network_repo),
2451 Arc::new(tx_repo),
2452 Arc::new(counter),
2453 Arc::new(job_producer),
2454 )
2455 .unwrap();
2456
2457 let result = relayer.initialize_relayer().await;
2458 assert!(result.is_ok());
2459 }
2460
2461 #[tokio::test]
2462 async fn test_initialize_relayer_enables_when_validation_passes_and_was_disabled() {
2463 let (
2464 mut provider,
2465 mut relayer_repo,
2466 network_repo,
2467 tx_repo,
2468 job_producer,
2469 signer,
2470 mut counter,
2471 ) = setup_mocks();
2472 let mut relayer_model = create_test_relayer();
2473 relayer_model.system_disabled = true; provider
2477 .expect_get_transaction_count()
2478 .returning(|_| Box::pin(ready(Ok(42u64))));
2479
2480 counter.expect_set().returning(|_| Box::pin(ready(Ok(()))));
2481
2482 counter
2483 .expect_get()
2484 .returning(|| Box::pin(ready(Ok(Some(42u64)))));
2485
2486 provider
2487 .expect_get_balance()
2488 .returning(|_| Box::pin(ready(Ok(U256::from(200000000000000000u64))))); provider
2491 .expect_health_check()
2492 .returning(|| Box::pin(ready(Ok(true))));
2493
2494 let mut enabled_relayer = relayer_model.clone();
2496 enabled_relayer.system_disabled = false;
2497 relayer_repo
2498 .expect_enable_relayer()
2499 .with(eq("test-relayer-id".to_string()))
2500 .returning(move |_| Ok(enabled_relayer.clone()));
2501
2502 let relayer = EvmRelayer::new(
2503 relayer_model,
2504 signer,
2505 provider,
2506 create_test_evm_network(),
2507 Arc::new(relayer_repo),
2508 Arc::new(network_repo),
2509 Arc::new(tx_repo),
2510 Arc::new(counter),
2511 Arc::new(job_producer),
2512 )
2513 .unwrap();
2514
2515 let result = relayer.initialize_relayer().await;
2516 assert!(result.is_ok());
2517 }
2518
2519 #[tokio::test]
2520 async fn test_initialize_relayer_no_action_when_enabled_and_validation_passes() {
2521 let (mut provider, relayer_repo, network_repo, tx_repo, job_producer, signer, mut counter) =
2522 setup_mocks();
2523 let mut relayer_model = create_test_relayer();
2524 relayer_model.system_disabled = false; provider
2528 .expect_get_transaction_count()
2529 .returning(|_| Box::pin(ready(Ok(42u64))));
2530
2531 counter.expect_set().returning(|_| Box::pin(ready(Ok(()))));
2532
2533 counter
2534 .expect_get()
2535 .returning(|| Box::pin(ready(Ok(Some(42u64)))));
2536
2537 provider
2538 .expect_get_balance()
2539 .returning(|_| Box::pin(ready(Ok(U256::from(200000000000000000u64))))); provider
2542 .expect_health_check()
2543 .returning(|| Box::pin(ready(Ok(true))));
2544
2545 let relayer = EvmRelayer::new(
2548 relayer_model,
2549 signer,
2550 provider,
2551 create_test_evm_network(),
2552 Arc::new(relayer_repo),
2553 Arc::new(network_repo),
2554 Arc::new(tx_repo),
2555 Arc::new(counter),
2556 Arc::new(job_producer),
2557 )
2558 .unwrap();
2559
2560 let result = relayer.initialize_relayer().await;
2561 assert!(result.is_ok());
2562 }
2563
2564 #[tokio::test]
2565 async fn test_initialize_relayer_sends_notification_when_disabled() {
2566 let (
2567 mut provider,
2568 mut relayer_repo,
2569 network_repo,
2570 tx_repo,
2571 mut job_producer,
2572 signer,
2573 mut counter,
2574 ) = setup_mocks();
2575 let mut relayer_model = create_test_relayer();
2576 relayer_model.system_disabled = false; relayer_model.notification_id = Some("test-notification-id".to_string());
2578
2579 provider
2581 .expect_get_transaction_count()
2582 .returning(|_| Box::pin(ready(Ok(42u64))));
2583
2584 counter.expect_set().returning(|_| Box::pin(ready(Ok(()))));
2585
2586 counter
2587 .expect_get()
2588 .returning(|| Box::pin(ready(Ok(Some(42u64)))));
2589
2590 provider
2591 .expect_get_balance()
2592 .returning(|_| Box::pin(ready(Ok(U256::from(200000000000000000u64))))); provider.expect_health_check().returning(|| {
2595 Box::pin(ready(Err(ProviderError::Other(
2596 "RPC validation failed".to_string(),
2597 ))))
2598 });
2599
2600 let mut disabled_relayer = relayer_model.clone();
2602 disabled_relayer.system_disabled = true;
2603 relayer_repo
2604 .expect_disable_relayer()
2605 .with(eq("test-relayer-id".to_string()), always())
2606 .returning(move |_, _| Ok(disabled_relayer.clone()));
2607
2608 job_producer
2610 .expect_produce_send_notification_job()
2611 .returning(|_, _| Box::pin(ready(Ok(()))));
2612
2613 job_producer
2615 .expect_produce_relayer_health_check_job()
2616 .returning(|_, _| Box::pin(ready(Ok(()))));
2617
2618 let relayer = EvmRelayer::new(
2619 relayer_model,
2620 signer,
2621 provider,
2622 create_test_evm_network(),
2623 Arc::new(relayer_repo),
2624 Arc::new(network_repo),
2625 Arc::new(tx_repo),
2626 Arc::new(counter),
2627 Arc::new(job_producer),
2628 )
2629 .unwrap();
2630
2631 let result = relayer.initialize_relayer().await;
2632 assert!(result.is_ok());
2633 }
2634
2635 #[tokio::test]
2636 async fn test_initialize_relayer_no_notification_when_no_notification_id() {
2637 let (
2638 mut provider,
2639 mut relayer_repo,
2640 network_repo,
2641 tx_repo,
2642 mut job_producer,
2643 signer,
2644 mut counter,
2645 ) = setup_mocks();
2646 let mut relayer_model = create_test_relayer();
2647 relayer_model.system_disabled = false; relayer_model.notification_id = None; provider
2652 .expect_get_transaction_count()
2653 .returning(|_| Box::pin(ready(Ok(42u64))));
2654
2655 counter.expect_set().returning(|_| Box::pin(ready(Ok(()))));
2656
2657 counter
2658 .expect_get()
2659 .returning(|| Box::pin(ready(Ok(Some(42u64)))));
2660
2661 provider
2662 .expect_get_balance()
2663 .returning(|_| Box::pin(ready(Ok(U256::from(50000000000000000u64))))); provider
2666 .expect_health_check()
2667 .returning(|| Box::pin(ready(Ok(true))));
2668
2669 let mut disabled_relayer = relayer_model.clone();
2671 disabled_relayer.system_disabled = true;
2672 relayer_repo
2673 .expect_disable_relayer()
2674 .with(eq("test-relayer-id".to_string()), always())
2675 .returning(move |_, _| Ok(disabled_relayer.clone()));
2676
2677 job_producer
2680 .expect_produce_relayer_health_check_job()
2681 .returning(|_, _| Box::pin(ready(Ok(()))));
2682
2683 let relayer = EvmRelayer::new(
2684 relayer_model,
2685 signer,
2686 provider,
2687 create_test_evm_network(),
2688 Arc::new(relayer_repo),
2689 Arc::new(network_repo),
2690 Arc::new(tx_repo),
2691 Arc::new(counter),
2692 Arc::new(job_producer),
2693 )
2694 .unwrap();
2695
2696 let result = relayer.initialize_relayer().await;
2697 assert!(result.is_ok());
2698 }
2699}