nautilus_blockchain/
factories.rs1use std::{any::Any, cell::RefCell, rc::Rc};
19
20use nautilus_common::{
21 cache::CacheView,
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, TraderId},
30};
31
32use crate::{
33 config::{BlockchainDataClientConfig, BlockchainExecutionClientConfig},
34 constants::{BLOCKCHAIN, 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.adapters.blockchain", from_py_object)
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: CacheView,
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(ClientId::from(name), 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.adapters.blockchain", from_py_object)
110)]
111pub struct BlockchainExecutionClientFactory;
112
113impl BlockchainExecutionClientFactory {
114 #[must_use]
116 pub const fn new() -> Self {
117 Self
118 }
119}
120
121impl Default for BlockchainExecutionClientFactory {
122 fn default() -> Self {
123 Self::new()
124 }
125}
126
127impl ExecutionClientFactory for BlockchainExecutionClientFactory {
128 fn create(
129 &self,
130 trader_id: TraderId,
131 name: &str,
132 config: &dyn ClientConfig,
133 cache: CacheView,
134 ) -> anyhow::Result<Box<dyn ExecutionClient>> {
135 let blockchain_execution_config = config
136 .as_any()
137 .downcast_ref::<BlockchainExecutionClientConfig>()
138 .ok_or_else(|| {
139 anyhow::anyhow!(
140 "Invalid config type for BlockchainExecutionClientFactory. Expected `BlockchainExecutionClientConfig`, was {config:?}"
141 )
142 })?;
143
144 let core_execution_client = ExecutionClientCore::new(
145 trader_id,
146 ClientId::from(name),
147 *BLOCKCHAIN_VENUE,
148 OmsType::Netting,
149 blockchain_execution_config.client_id,
150 AccountType::Wallet,
151 None,
152 cache,
153 );
154
155 let client = BlockchainExecutionClient::new(
156 core_execution_client,
157 blockchain_execution_config.clone(),
158 )?;
159
160 Ok(Box::new(client))
161 }
162
163 fn name(&self) -> &'static str {
164 BLOCKCHAIN
165 }
166
167 fn config_type(&self) -> &'static str {
168 "BlockchainExecutionClientConfig"
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use std::sync::Arc;
175
176 use nautilus_common::factories::DataClientFactory;
177 use nautilus_model::defi::chain::{Blockchain, chains};
178 use rstest::rstest;
179
180 use crate::{
181 config::BlockchainDataClientConfig, constants::BLOCKCHAIN,
182 factories::BlockchainDataClientFactory,
183 };
184
185 #[rstest]
186 fn test_blockchain_data_client_config_creation() {
187 let chain = Arc::new(chains::ETHEREUM.clone());
188 let config = BlockchainDataClientConfig::builder()
189 .chain(chain)
190 .http_rpc_url("https://eth-mainnet.example.com".to_string())
191 .build();
192
193 assert_eq!(config.chain.name, Blockchain::Ethereum);
194 assert_eq!(config.http_rpc_url, "https://eth-mainnet.example.com");
195 }
196
197 #[rstest]
198 fn test_factory_creation() {
199 let factory = BlockchainDataClientFactory::new();
200 assert_eq!(factory.name(), BLOCKCHAIN);
201 assert_eq!(factory.config_type(), "BlockchainDataClientConfig");
202 }
203}