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 ) -> anyhow::Result<Box<dyn ExecutionClient>> {
141 let blockchain_execution_config = config
142 .as_any()
143 .downcast_ref::<BlockchainExecutionClientConfig>()
144 .ok_or_else(|| {
145 anyhow::anyhow!(
146 "Invalid config type for BlockchainDataClientFactory. Expected `BlockchainDataClientConfig`, was {config:?}"
147 )
148 })?;
149
150 let core_execution_client = ExecutionClientCore::new(
151 blockchain_execution_config.trader_id,
152 ClientId::from(name),
153 *BLOCKCHAIN_VENUE,
154 OmsType::Netting,
155 blockchain_execution_config.client_id,
156 AccountType::Wallet,
157 None,
158 cache,
159 );
160
161 let client = BlockchainExecutionClient::new(
162 core_execution_client,
163 blockchain_execution_config.clone(),
164 )?;
165
166 Ok(Box::new(client))
167 }
168
169 fn name(&self) -> &'static str {
170 "BLOCKCHAIN"
171 }
172
173 fn config_type(&self) -> &'static str {
174 "BlockchainExecutionClientConfig"
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use std::sync::Arc;
181
182 use nautilus_model::defi::chain::{Blockchain, chains};
183 use nautilus_system::factories::DataClientFactory;
184 use rstest::rstest;
185
186 use crate::{config::BlockchainDataClientConfig, factories::BlockchainDataClientFactory};
187
188 #[rstest]
189 fn test_blockchain_data_client_config_creation() {
190 let chain = Arc::new(chains::ETHEREUM.clone());
191 let config = BlockchainDataClientConfig::new(
192 chain,
193 vec![],
194 "https://eth-mainnet.example.com".to_string(),
195 None,
196 None,
197 None,
198 false,
199 None,
200 None,
201 None,
202 );
203
204 assert_eq!(config.chain.name, Blockchain::Ethereum);
205 assert_eq!(config.http_rpc_url, "https://eth-mainnet.example.com");
206 }
207
208 #[rstest]
209 fn test_factory_creation() {
210 let factory = BlockchainDataClientFactory::new();
211 assert_eq!(factory.name(), "BLOCKCHAIN");
212 assert_eq!(factory.config_type(), "BlockchainDataClientConfig");
213 }
214}