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 =
65        Arc::new(StellarSignerFactory::create_stellar_signer(signer.into()).await?);
66
67    let transaction_counter_service = Arc::new(TransactionCounterService::new(
68        relayer.id.clone(),
69        relayer.address.clone(),
70        transaction_counter_store,
71    ));
72
73    // Create DEX services based on configured strategies
74    let horizon_url = network.horizon_url.clone().unwrap_or_else(|| {
75        if network.is_testnet() {
76            STELLAR_HORIZON_TESTNET_URL.to_string()
77        } else {
78            STELLAR_HORIZON_MAINNET_URL.to_string()
79        }
80    });
81    let provider_arc = Arc::new(provider.clone());
82    let signer_arc = stellar_signer.clone();
83
84    // Get strategies from policy (default to OrderBook if none specified)
85    let strategies = relayer
86        .policies
87        .get_stellar_policy()
88        .get_swap_config()
89        .and_then(|config| {
90            if config.strategies.is_empty() {
91                None
92            } else {
93                Some(config.strategies.clone())
94            }
95        })
96        .unwrap_or_else(|| vec![StellarSwapStrategy::OrderBook]);
97
98    // Create DEX services for each strategy
99    // Type parameters are inferred from provider and signer_arc
100    let mut dex_services: Vec<DexServiceWrapper<_, _>> = Vec::new();
101    for strategy in &strategies {
102        match strategy {
103            StellarSwapStrategy::OrderBook => {
104                let order_book_service = Arc::new(
105                    OrderBookService::new(
106                        horizon_url.clone(),
107                        provider_arc.clone(),
108                        signer_arc.clone(),
109                    )
110                    .map_err(|e| {
111                        RelayerError::NetworkConfiguration(format!(
112                            "Failed to create OrderBook DEX service: {e}"
113                        ))
114                    })?,
115                );
116                dex_services.push(DexServiceWrapper::OrderBook(order_book_service));
117            }
118            StellarSwapStrategy::Soroswap => {
119                let is_testnet = network.is_testnet();
120                let network_label = if is_testnet { "TESTNET" } else { "MAINNET" };
121
122                let router_address =
123                    crate::config::ServerConfig::resolve_stellar_soroswap_router_address(
124                        is_testnet,
125                    )
126                    .ok_or_else(|| {
127                        RelayerError::NetworkConfiguration(format!(
128                            "Soroswap router address not configured. Set STELLAR_{network_label}_SOROSWAP_ROUTER_ADDRESS env var."
129                        ))
130                    })?;
131
132                let factory_address =
133                    crate::config::ServerConfig::resolve_stellar_soroswap_factory_address(
134                        is_testnet,
135                    )
136                    .ok_or_else(|| {
137                        RelayerError::NetworkConfiguration(format!(
138                            "Soroswap factory address not configured. Set STELLAR_{network_label}_SOROSWAP_FACTORY_ADDRESS env var."
139                        ))
140                    })?;
141
142                let native_wrapper_address =
143                    crate::config::ServerConfig::resolve_stellar_soroswap_native_wrapper_address(
144                        is_testnet,
145                    )
146                    .ok_or_else(|| {
147                        RelayerError::NetworkConfiguration(format!(
148                            "Soroswap native wrapper address not configured. Set STELLAR_{network_label}_SOROSWAP_NATIVE_WRAPPER_ADDRESS env var."
149                        ))
150                    })?;
151
152                let soroswap_service = Arc::new(SoroswapService::new(
153                    router_address,
154                    factory_address,
155                    native_wrapper_address,
156                    provider_arc.clone(),
157                    network.passphrase.clone(),
158                ));
159                dex_services.push(DexServiceWrapper::Soroswap(soroswap_service));
160                tracing::info!("Soroswap DEX service initialized");
161            }
162        }
163    }
164
165    // Create multi-strategy DEX service with the configured strategies
166    let dex_service = Arc::new(StellarDexService::new(dex_services));
167
168    let relayer = DefaultStellarRelayer::<J, TR, NR, RR, TCR>::new(
169        relayer,
170        stellar_signer.clone(),
171        provider,
172        StellarRelayerDependencies::new(
173            relayer_repository,
174            network_repository,
175            transaction_repository,
176            transaction_counter_service,
177            job_producer,
178        ),
179        dex_service,
180    )
181    .await?;
182
183    Ok(relayer)
184}