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 factories::{ClientConfig, DataClientFactory, ExecutionClientFactory},
25};
26use nautilus_live::ExecutionClientCore;
27use nautilus_model::{
28 enums::{AccountType, OmsType},
29 identifiers::ClientId,
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(
53 module = "nautilus_trader.core.nautilus_pyo3.blockchain",
54 from_py_object
55 )
56)]
57#[cfg_attr(
58 feature = "python",
59 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.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(ClientId::from(name), 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(
113 module = "nautilus_trader.core.nautilus_pyo3.blockchain",
114 from_py_object
115 )
116)]
117#[cfg_attr(
118 feature = "python",
119 pyo3_stub_gen::derive::gen_stub_pyclass(module = "nautilus_trader.blockchain")
120)]
121pub struct BlockchainExecutionClientFactory;
122
123impl BlockchainExecutionClientFactory {
124 #[must_use]
126 pub const fn new() -> Self {
127 Self
128 }
129}
130
131impl Default for BlockchainExecutionClientFactory {
132 fn default() -> Self {
133 Self::new()
134 }
135}
136
137impl ExecutionClientFactory for BlockchainExecutionClientFactory {
138 fn create(
139 &self,
140 name: &str,
141 config: &dyn ClientConfig,
142 cache: Rc<RefCell<Cache>>,
143 ) -> anyhow::Result<Box<dyn ExecutionClient>> {
144 let blockchain_execution_config = config
145 .as_any()
146 .downcast_ref::<BlockchainExecutionClientConfig>()
147 .ok_or_else(|| {
148 anyhow::anyhow!(
149 "Invalid config type for BlockchainExecutionClientFactory. Expected `BlockchainExecutionClientConfig`, was {config:?}"
150 )
151 })?;
152
153 let core_execution_client = ExecutionClientCore::new(
154 blockchain_execution_config.trader_id,
155 ClientId::from(name),
156 *BLOCKCHAIN_VENUE,
157 OmsType::Netting,
158 blockchain_execution_config.client_id,
159 AccountType::Wallet,
160 None,
161 cache,
162 );
163
164 let client = BlockchainExecutionClient::new(
165 core_execution_client,
166 blockchain_execution_config.clone(),
167 )?;
168
169 Ok(Box::new(client))
170 }
171
172 fn name(&self) -> &'static str {
173 "BLOCKCHAIN"
174 }
175
176 fn config_type(&self) -> &'static str {
177 "BlockchainExecutionClientConfig"
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use std::sync::Arc;
184
185 use nautilus_common::factories::DataClientFactory;
186 use nautilus_model::defi::chain::{Blockchain, chains};
187 use rstest::rstest;
188
189 use crate::{config::BlockchainDataClientConfig, factories::BlockchainDataClientFactory};
190
191 #[rstest]
192 fn test_blockchain_data_client_config_creation() {
193 let chain = Arc::new(chains::ETHEREUM.clone());
194 let config = BlockchainDataClientConfig::builder()
195 .chain(chain)
196 .http_rpc_url("https://eth-mainnet.example.com".to_string())
197 .build();
198
199 assert_eq!(config.chain.name, Blockchain::Ethereum);
200 assert_eq!(config.http_rpc_url, "https://eth-mainnet.example.com");
201 }
202
203 #[rstest]
204 fn test_factory_creation() {
205 let factory = BlockchainDataClientFactory::new();
206 assert_eq!(factory.name(), "BLOCKCHAIN");
207 assert_eq!(factory.config_type(), "BlockchainDataClientConfig");
208 }
209}