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