openzeppelin_relayer/domain/transaction/solana/
solana_transaction.rs1use async_trait::async_trait;
7use eyre::Result;
8use log::info;
9use std::sync::Arc;
10
11use crate::{
12 domain::transaction::Transaction,
13 jobs::{JobProducer, JobProducerTrait},
14 models::{NetworkTransactionRequest, RelayerRepoModel, TransactionError, TransactionRepoModel},
15 repositories::{
16 RelayerRepository, RelayerRepositoryStorage, Repository, TransactionRepository,
17 TransactionRepositoryStorage,
18 },
19 services::{SolanaProvider, SolanaProviderTrait},
20};
21
22#[allow(dead_code)]
23pub struct SolanaRelayerTransaction<P, RR, TR, J>
24where
25 P: SolanaProviderTrait,
26 RR: RelayerRepository + Repository<RelayerRepoModel, String> + Send + Sync + 'static,
27 TR: TransactionRepository + Repository<TransactionRepoModel, String> + Send + Sync + 'static,
28 J: JobProducerTrait + Send + Sync + 'static,
29{
30 relayer: RelayerRepoModel,
31 relayer_repository: Arc<RR>,
32 provider: Arc<P>,
33 job_producer: Arc<J>,
34 transaction_repository: Arc<TR>,
35}
36
37pub type DefaultSolanaTransaction = SolanaRelayerTransaction<
38 SolanaProvider,
39 RelayerRepositoryStorage,
40 TransactionRepositoryStorage,
41 JobProducer,
42>;
43
44#[allow(dead_code)]
45impl<P, RR, TR, J> SolanaRelayerTransaction<P, RR, TR, J>
46where
47 P: SolanaProviderTrait,
48 RR: RelayerRepository + Repository<RelayerRepoModel, String> + Send + Sync + 'static,
49 TR: TransactionRepository + Repository<TransactionRepoModel, String> + Send + Sync + 'static,
50 J: JobProducerTrait + Send + Sync + 'static,
51{
52 pub fn new(
53 relayer: RelayerRepoModel,
54 relayer_repository: Arc<RR>,
55 provider: Arc<P>,
56 transaction_repository: Arc<TR>,
57 job_producer: Arc<J>,
58 ) -> Result<Self, TransactionError> {
59 Ok(Self {
60 relayer,
61 relayer_repository,
62 provider,
63 transaction_repository,
64 job_producer,
65 })
66 }
67
68 pub(super) fn provider(&self) -> &P {
70 &self.provider
71 }
72
73 pub(super) fn transaction_repository(&self) -> &TR {
74 &self.transaction_repository
75 }
76
77 pub(super) fn relayer(&self) -> &RelayerRepoModel {
78 &self.relayer
79 }
80
81 pub(super) fn job_producer(&self) -> &J {
82 &self.job_producer
83 }
84}
85
86#[async_trait]
87impl<P, RR, TR, J> Transaction for SolanaRelayerTransaction<P, RR, TR, J>
88where
89 P: SolanaProviderTrait,
90 RR: RelayerRepository + Repository<RelayerRepoModel, String> + Send + Sync + 'static,
91 TR: TransactionRepository + Repository<TransactionRepoModel, String> + Send + Sync + 'static,
92 J: JobProducerTrait + Send + Sync + 'static,
93{
94 async fn prepare_transaction(
95 &self,
96 tx: TransactionRepoModel,
97 ) -> Result<TransactionRepoModel, TransactionError> {
98 info!("preparing transaction");
99 Ok(tx)
100 }
101
102 async fn submit_transaction(
103 &self,
104 tx: TransactionRepoModel,
105 ) -> Result<TransactionRepoModel, TransactionError> {
106 info!("submitting transaction");
107 Ok(tx)
108 }
109
110 async fn resubmit_transaction(
111 &self,
112 tx: TransactionRepoModel,
113 ) -> Result<TransactionRepoModel, TransactionError> {
114 info!("resubmitting transaction");
115 Ok(tx)
116 }
117
118 async fn handle_transaction_status(
120 &self,
121 tx: TransactionRepoModel,
122 ) -> Result<TransactionRepoModel, TransactionError> {
123 self.handle_transaction_status_impl(tx).await
124 }
125
126 async fn cancel_transaction(
127 &self,
128 tx: TransactionRepoModel,
129 ) -> Result<TransactionRepoModel, TransactionError> {
130 Ok(tx)
131 }
132
133 async fn replace_transaction(
134 &self,
135 _old_tx: TransactionRepoModel,
136 _new_tx_request: NetworkTransactionRequest,
137 ) -> Result<TransactionRepoModel, TransactionError> {
138 Ok(_old_tx)
139 }
140
141 async fn sign_transaction(
142 &self,
143 tx: TransactionRepoModel,
144 ) -> Result<TransactionRepoModel, TransactionError> {
145 Ok(tx)
146 }
147
148 async fn validate_transaction(
149 &self,
150 _tx: TransactionRepoModel,
151 ) -> Result<bool, TransactionError> {
152 Ok(true)
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159 use crate::{
160 jobs::MockJobProducerTrait,
161 repositories::{MockRelayerRepository, MockTransactionRepository},
162 services::MockSolanaProviderTrait,
163 utils::mocks::mockutils::{create_mock_solana_relayer, create_mock_solana_transaction},
164 };
165
166 #[tokio::test]
167 async fn test_solana_transaction_creation() {
168 let relayer = create_mock_solana_relayer("test-solana-relayer".to_string(), false);
169 let relayer_repository = Arc::new(MockRelayerRepository::new());
170 let provider = Arc::new(MockSolanaProviderTrait::new());
171 let transaction_repository = Arc::new(MockTransactionRepository::new());
172 let job_producer = Arc::new(MockJobProducerTrait::new());
173
174 let transaction = SolanaRelayerTransaction::new(
175 relayer,
176 relayer_repository,
177 provider,
178 transaction_repository,
179 job_producer,
180 );
181
182 assert!(transaction.is_ok());
183 }
184
185 #[tokio::test]
186 async fn test_handle_transaction_status_calls_impl() {
187 let relayer = create_mock_solana_relayer("test-solana-relayer".to_string(), false);
189 let relayer_repository = Arc::new(MockRelayerRepository::new());
190 let provider = Arc::new(MockSolanaProviderTrait::new());
191 let transaction_repository = Arc::new(MockTransactionRepository::new());
192 let job_producer = Arc::new(MockJobProducerTrait::new());
193
194 let test_tx = create_mock_solana_transaction();
196
197 let transaction_handler = SolanaRelayerTransaction::new(
199 relayer,
200 relayer_repository,
201 provider,
202 transaction_repository,
203 job_producer,
204 )
205 .unwrap();
206
207 let result = transaction_handler
209 .handle_transaction_status(test_tx.clone())
210 .await;
211
212 assert!(result.is_err());
214 let error = result.unwrap_err();
215 assert_eq!(
216 error.to_string(),
217 "Transaction validation error: Transaction signature is missing".to_string()
218 );
219 }
220}