nautilus_blockchain/
factories.rs1use std::{any::Any, cell::RefCell, rc::Rc};
19
20use nautilus_common::{cache::Cache, clock::Clock};
21use nautilus_data::client::DataClient;
22use nautilus_execution::client::{ExecutionClient, base::ExecutionClientCore};
23use nautilus_model::{
24 enums::{AccountType, OmsType},
25 identifiers::ClientId,
26};
27use nautilus_system::{
28 ExecutionClientFactory,
29 factories::{ClientConfig, DataClientFactory},
30};
31
32use crate::{
33 config::{BlockchainDataClientConfig, BlockchainExecutionClientConfig},
34 constants::BLOCKCHAIN_VENUE,
35 data::client::BlockchainDataClient,
36 execution::client::BlockchainExecutionClient,
37};
38
39impl ClientConfig for BlockchainDataClientConfig {
40 fn as_any(&self) -> &dyn Any {
41 self
42 }
43}
44
45#[derive(Debug, Clone)]
50#[cfg_attr(
51 feature = "python",
52 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.blockchain")
53)]
54#[cfg_attr(
55 feature = "python",
56 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.blockchain")
57)]
58pub struct BlockchainDataClientFactory;
59
60impl BlockchainDataClientFactory {
61 #[must_use]
63 pub const fn new() -> Self {
64 Self
65 }
66}
67
68impl Default for BlockchainDataClientFactory {
69 fn default() -> Self {
70 Self::new()
71 }
72}
73
74impl DataClientFactory for BlockchainDataClientFactory {
75 fn create(
76 &self,
77 _name: &str,
78 config: &dyn ClientConfig,
79 _cache: Rc<RefCell<Cache>>,
80 _clock: Rc<RefCell<dyn Clock>>,
81 ) -> anyhow::Result<Box<dyn DataClient>> {
82 let blockchain_config = config
83 .as_any()
84 .downcast_ref::<BlockchainDataClientConfig>()
85 .ok_or_else(|| {
86 anyhow::anyhow!(
87 "Invalid config type for BlockchainDataClientFactory. Expected `BlockchainDataClientConfig`, was {config:?}"
88 )
89 })?;
90
91 let client = BlockchainDataClient::new(blockchain_config.clone());
92
93 Ok(Box::new(client))
94 }
95
96 fn name(&self) -> &'static str {
97 "BLOCKCHAIN"
98 }
99
100 fn config_type(&self) -> &'static str {
101 "BlockchainDataClientConfig"
102 }
103}
104
105#[derive(Debug, Clone)]
107#[cfg_attr(
108 feature = "python",
109 pyo3::pyclass(module = "nautilus_trader.core.nautilus_pyo3.blockchain")
110)]
111#[cfg_attr(
112 feature = "python",
113 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.adapters.blockchain")
114)]
115pub struct BlockchainExecutionClientFactory;
116
117impl BlockchainExecutionClientFactory {
118 #[must_use]
120 pub const fn new() -> Self {
121 Self
122 }
123}
124
125impl Default for BlockchainExecutionClientFactory {
126 fn default() -> Self {
127 Self::new()
128 }
129}
130
131impl ExecutionClientFactory for BlockchainExecutionClientFactory {
132 fn create(
133 &self,
134 name: &str,
135 config: &dyn ClientConfig,
136 cache: Rc<RefCell<Cache>>,
137 clock: Rc<RefCell<dyn Clock>>,
138 ) -> anyhow::Result<Box<dyn ExecutionClient>> {
139 let blockchain_execution_config = config
140 .as_any()
141 .downcast_ref::<BlockchainExecutionClientConfig>()
142 .ok_or_else(|| {
143 anyhow::anyhow!(
144 "Invalid config type for BlockchainDataClientFactory. Expected `BlockchainDataClientConfig`, was {config:?}"
145 )
146 })?;
147
148 let core_execution_client = ExecutionClientCore::new(
149 blockchain_execution_config.trader_id,
150 ClientId::from(name),
151 *BLOCKCHAIN_VENUE,
152 OmsType::Netting,
153 blockchain_execution_config.client_id,
154 AccountType::Wallet,
155 None,
156 clock,
157 cache,
158 );
159
160 let client = BlockchainExecutionClient::new(
161 core_execution_client,
162 blockchain_execution_config.clone(),
163 );
164
165 Ok(Box::new(client))
166 }
167
168 fn name(&self) -> &'static str {
169 "BLOCKCHAIN"
170 }
171
172 fn config_type(&self) -> &'static str {
173 "BlockchainExecutionClientConfig"
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use std::sync::Arc;
180
181 use nautilus_model::defi::chain::{Blockchain, chains};
182 use nautilus_system::factories::DataClientFactory;
183 use rstest::rstest;
184
185 use crate::{config::BlockchainDataClientConfig, factories::BlockchainDataClientFactory};
186
187 #[rstest]
188 fn test_blockchain_data_client_config_creation() {
189 let chain = Arc::new(chains::ETHEREUM.clone());
190 let config = BlockchainDataClientConfig::new(
191 chain,
192 vec![],
193 "https://eth-mainnet.example.com".to_string(),
194 None,
195 None,
196 None,
197 false,
198 None,
199 None,
200 None,
201 );
202
203 assert_eq!(config.chain.name, Blockchain::Ethereum);
204 assert_eq!(config.http_rpc_url, "https://eth-mainnet.example.com");
205 }
206
207 #[rstest]
208 fn test_factory_creation() {
209 let factory = BlockchainDataClientFactory::new();
210 assert_eq!(factory.name(), "BLOCKCHAIN");
211 assert_eq!(factory.config_type(), "BlockchainDataClientConfig");
212 }
213}