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