openzeppelin_relayer/domain/relayer/stellar/
mod.rs

1mod stellar_relayer;
2pub use stellar_relayer::*;
3
4mod gas_abstraction;
5mod token_swap;
6
7pub mod utils;
8pub mod xdr_utils;
9pub use xdr_utils::*;
10
11pub use crate::services::stellar_dex::StellarDexServiceTrait;
12
13use std::sync::Arc;
14
15use crate::{
16    constants::{STELLAR_HORIZON_MAINNET_URL, STELLAR_HORIZON_TESTNET_URL},
17    jobs::JobProducerTrait,
18    models::{
19        NetworkRepoModel, NetworkType, RelayerError, RelayerRepoModel, SignerRepoModel,
20        StellarNetwork, StellarSwapStrategy, TransactionRepoModel,
21    },
22    repositories::{
23        NetworkRepository, RelayerRepository, Repository, TransactionCounterTrait,
24        TransactionRepository,
25    },
26    services::{
27        provider::get_network_provider,
28        signer::StellarSignerFactory,
29        stellar_dex::{DexServiceWrapper, OrderBookService, SoroswapService, StellarDexService},
30        TransactionCounterService,
31    },
32};
33
34/// Function to create a Stellar relayer instance
35pub async fn create_stellar_relayer<
36    J: JobProducerTrait + 'static,
37    TR: TransactionRepository + Repository<TransactionRepoModel, String> + Send + Sync + 'static,
38    NR: NetworkRepository + Repository<NetworkRepoModel, String> + Send + Sync + 'static,
39    RR: RelayerRepository + Repository<RelayerRepoModel, String> + Send + Sync + 'static,
40    TCR: TransactionCounterTrait + Send + Sync + 'static,
41>(
42    relayer: RelayerRepoModel,
43    signer: SignerRepoModel,
44    relayer_repository: Arc<RR>,
45    network_repository: Arc<NR>,
46    transaction_repository: Arc<TR>,
47    job_producer: Arc<J>,
48    transaction_counter_store: Arc<TCR>,
49) -> Result<DefaultStellarRelayer<J, TR, NR, RR, TCR>, RelayerError> {
50    let network_repo = network_repository
51        .get_by_name(NetworkType::Stellar, &relayer.network)
52        .await
53        .ok()
54        .flatten()
55        .ok_or_else(|| {
56            RelayerError::NetworkConfiguration(format!("Network {} not found", relayer.network))
57        })?;
58
59    let network = StellarNetwork::try_from(network_repo.clone())?;
60    let provider = get_network_provider(&network, relayer.custom_rpc_urls.clone())
61        .map_err(|e| RelayerError::NetworkConfiguration(e.to_string()))?;
62
63    // Create signer once and wrap in Arc for shared use
64    let stellar_signer = Arc::new(StellarSignerFactory::create_stellar_signer(&signer.into())?);
65
66    let transaction_counter_service = Arc::new(TransactionCounterService::new(
67        relayer.id.clone(),
68        relayer.address.clone(),
69        transaction_counter_store,
70    ));
71
72    // Create DEX services based on configured strategies
73    let horizon_url = network.horizon_url.clone().unwrap_or_else(|| {
74        if network.is_testnet() {
75            STELLAR_HORIZON_TESTNET_URL.to_string()
76        } else {
77            STELLAR_HORIZON_MAINNET_URL.to_string()
78        }
79    });
80    let provider_arc = Arc::new(provider.clone());
81    let signer_arc = stellar_signer.clone();
82
83    // Get strategies from policy (default to OrderBook if none specified)
84    let strategies = relayer
85        .policies
86        .get_stellar_policy()
87        .get_swap_config()
88        .and_then(|config| {
89            if config.strategies.is_empty() {
90                None
91            } else {
92                Some(config.strategies.clone())
93            }
94        })
95        .unwrap_or_else(|| vec![StellarSwapStrategy::OrderBook]);
96
97    // Create DEX services for each strategy
98    // Type parameters are inferred from provider and signer_arc
99    let mut dex_services: Vec<DexServiceWrapper<_, _>> = Vec::new();
100    for strategy in &strategies {
101        match strategy {
102            StellarSwapStrategy::OrderBook => {
103                let order_book_service = Arc::new(
104                    OrderBookService::new(
105                        horizon_url.clone(),
106                        provider_arc.clone(),
107                        signer_arc.clone(),
108                    )
109                    .map_err(|e| {
110                        RelayerError::NetworkConfiguration(format!(
111                            "Failed to create OrderBook DEX service: {e}"
112                        ))
113                    })?,
114                );
115                dex_services.push(DexServiceWrapper::OrderBook(order_book_service));
116            }
117            StellarSwapStrategy::Soroswap => {
118                let is_testnet = network.is_testnet();
119                let network_label = if is_testnet { "TESTNET" } else { "MAINNET" };
120
121                let router_address =
122                    crate::config::ServerConfig::resolve_stellar_soroswap_router_address(
123                        is_testnet,
124                    )
125                    .ok_or_else(|| {
126                        RelayerError::NetworkConfiguration(format!(
127                            "Soroswap router address not configured. Set STELLAR_{network_label}_SOROSWAP_ROUTER_ADDRESS env var."
128                        ))
129                    })?;
130
131                let factory_address =
132                    crate::config::ServerConfig::resolve_stellar_soroswap_factory_address(
133                        is_testnet,
134                    )
135                    .ok_or_else(|| {
136                        RelayerError::NetworkConfiguration(format!(
137                            "Soroswap factory address not configured. Set STELLAR_{network_label}_SOROSWAP_FACTORY_ADDRESS env var."
138                        ))
139                    })?;
140
141                let native_wrapper_address =
142                    crate::config::ServerConfig::resolve_stellar_soroswap_native_wrapper_address(
143                        is_testnet,
144                    )
145                    .ok_or_else(|| {
146                        RelayerError::NetworkConfiguration(format!(
147                            "Soroswap native wrapper address not configured. Set STELLAR_{network_label}_SOROSWAP_NATIVE_WRAPPER_ADDRESS env var."
148                        ))
149                    })?;
150
151                let soroswap_service = Arc::new(SoroswapService::new(
152                    router_address,
153                    factory_address,
154                    native_wrapper_address,
155                    provider_arc.clone(),
156                    network.passphrase.clone(),
157                ));
158                dex_services.push(DexServiceWrapper::Soroswap(soroswap_service));
159                tracing::info!("Soroswap DEX service initialized");
160            }
161        }
162    }
163
164    // Create multi-strategy DEX service with the configured strategies
165    let dex_service = Arc::new(StellarDexService::new(dex_services));
166
167    let relayer = DefaultStellarRelayer::<J, TR, NR, RR, TCR>::new(
168        relayer,
169        stellar_signer.clone(),
170        provider,
171        StellarRelayerDependencies::new(
172            relayer_repository,
173            network_repository,
174            transaction_repository,
175            transaction_counter_service,
176            job_producer,
177        ),
178        dex_service,
179    )
180    .await?;
181
182    Ok(relayer)
183}