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