nautilus_blockchain/python/
config.rs1use std::sync::Arc;
19
20use nautilus_core::{python::to_pyvalue_err, string::secret::REDACTED};
21use nautilus_infrastructure::sql::pg::PostgresConnectOptions;
22use nautilus_model::{
23 defi::{Chain, DexType},
24 identifiers::AccountId,
25};
26use nautilus_network::websocket::TransportBackend;
27use pyo3::prelude::*;
28
29use crate::config::{
30 BlockchainChainAnchorConfig, BlockchainDataClientConfig, BlockchainExecutionClientConfig,
31 BlockchainProviderIdentity, BlockchainVerificationConfig, BlockchainVerificationProviderConfig,
32 DexPoolFilters, QuoteSpendLimit,
33};
34
35#[pymethods]
36#[pyo3_stub_gen::derive::gen_stub_pymethods(module = "nautilus_trader.adapters.blockchain")]
37impl DexPoolFilters {
38 #[new]
40 #[must_use]
41 pub fn py_new(remove_pools_with_empty_erc20_fields: Option<bool>) -> Self {
42 Self::builder()
43 .maybe_remove_pools_with_empty_erc20fields(remove_pools_with_empty_erc20_fields)
44 .build()
45 }
46}
47
48#[pymethods]
49#[pyo3_stub_gen::derive::gen_stub_pymethods(module = "nautilus_trader.adapters.blockchain")]
50impl QuoteSpendLimit {
51 #[new]
53 #[must_use]
54 fn py_new(
55 token_in: String,
56 token_out: String,
57 spend_token: String,
58 spend_token_decimals: u8,
59 max_amount: String,
60 ) -> Self {
61 Self::builder()
62 .token_in(token_in)
63 .token_out(token_out)
64 .spend_token(spend_token)
65 .spend_token_decimals(spend_token_decimals)
66 .max_amount(max_amount)
67 .build()
68 }
69}
70
71#[pymethods]
72#[pyo3_stub_gen::derive::gen_stub_pymethods(module = "nautilus_trader.adapters.blockchain")]
73impl BlockchainProviderIdentity {
74 #[new]
76 #[must_use]
77 fn py_new(provider_id: String, operator_id: String, failure_domain_ids: Vec<String>) -> Self {
78 Self::builder()
79 .provider_id(provider_id)
80 .operator_id(operator_id)
81 .failure_domain_ids(failure_domain_ids)
82 .build()
83 }
84}
85
86#[pymethods]
87#[pyo3_stub_gen::derive::gen_stub_pymethods(module = "nautilus_trader.adapters.blockchain")]
88impl BlockchainVerificationProviderConfig {
89 #[new]
91 #[must_use]
92 fn py_new(identity: BlockchainProviderIdentity, http_rpc_url: String) -> Self {
93 Self::builder()
94 .identity(identity)
95 .http_rpc_url(http_rpc_url)
96 .build()
97 }
98
99 fn __repr__(&self) -> String {
100 format!(
101 "BlockchainVerificationProviderConfig(identity={:?}, http_rpc_url={REDACTED})",
102 self.identity
103 )
104 }
105}
106
107#[pymethods]
108#[pyo3_stub_gen::derive::gen_stub_pymethods(module = "nautilus_trader.adapters.blockchain")]
109impl BlockchainChainAnchorConfig {
110 #[new]
112 #[expect(clippy::too_many_arguments)]
113 #[must_use]
114 fn py_new(
115 chain_id: u32,
116 chain_name: String,
117 checkpoint_height: u64,
118 checkpoint_hash: String,
119 checkpoint_timestamp: u64,
120 max_head_skew_blocks: u64,
121 max_head_age_secs: u64,
122 max_future_drift_secs: u64,
123 ) -> Self {
124 Self::builder()
125 .chain_id(chain_id)
126 .chain_name(chain_name)
127 .checkpoint_height(checkpoint_height)
128 .checkpoint_hash(checkpoint_hash)
129 .checkpoint_timestamp(checkpoint_timestamp)
130 .max_head_skew_blocks(max_head_skew_blocks)
131 .max_head_age_secs(max_head_age_secs)
132 .max_future_drift_secs(max_future_drift_secs)
133 .build()
134 }
135}
136
137#[pymethods]
138#[pyo3_stub_gen::derive::gen_stub_pymethods(module = "nautilus_trader.adapters.blockchain")]
139impl BlockchainVerificationConfig {
140 #[new]
142 fn py_new(
143 authoritative: BlockchainProviderIdentity,
144 verifiers: Vec<BlockchainVerificationProviderConfig>,
145 chain_anchor: BlockchainChainAnchorConfig,
146 manifest_version: String,
147 manifest_digest: String,
148 deployment_manifest_json: String,
149 ) -> PyResult<Self> {
150 let deployment_manifest = serde_json::from_str(&deployment_manifest_json)
151 .map_err(|_| to_pyvalue_err("Invalid deployment manifest JSON"))?;
152 Ok(Self::builder()
153 .authoritative(authoritative)
154 .verifiers(verifiers)
155 .chain_anchor(chain_anchor)
156 .manifest_version(manifest_version)
157 .manifest_digest(manifest_digest)
158 .deployment_manifest(deployment_manifest)
159 .build())
160 }
161
162 #[getter]
163 fn deployment_manifest_json(&self) -> PyResult<String> {
164 serde_json::to_string(&self.deployment_manifest).map_err(to_pyvalue_err)
165 }
166}
167
168#[pymethods]
169#[pyo3_stub_gen::derive::gen_stub_pymethods(module = "nautilus_trader.adapters.blockchain")]
170impl BlockchainDataClientConfig {
171 #[new]
173 #[expect(clippy::too_many_arguments)]
174 #[pyo3(signature = (chain, dex_ids, http_rpc_url, rpc_requests_per_second=None, multicall_calls_per_rpc_request=None, wss_rpc_url=None, use_hypersync_for_live_data=true, from_block=None, pool_filters=None, postgres_cache_database_config=None, proxy_url=None, transport_backend=None))]
175 fn py_new(
176 #[gen_stub(
177 override_type(
178 type_repr = "nautilus_trader.model.Chain",
179 imports = ("nautilus_trader.model",),
180 ),
181 )]
182 chain: &Chain,
183 #[gen_stub(
184 override_type(
185 type_repr = "typing.Sequence[nautilus_trader.model.DexType]",
186 imports = ("typing", "nautilus_trader.model"),
187 ),
188 )]
189 dex_ids: Vec<DexType>,
190 http_rpc_url: String,
191 rpc_requests_per_second: Option<u32>,
192 multicall_calls_per_rpc_request: Option<u32>,
193 wss_rpc_url: Option<String>,
194 use_hypersync_for_live_data: bool,
195 from_block: Option<u64>,
196 pool_filters: Option<DexPoolFilters>,
197 #[gen_stub(
198 override_type(
199 type_repr = "typing.Optional[nautilus_trader.infrastructure.PostgresConnectOptions]",
200 imports = ("typing", "nautilus_trader.infrastructure"),
201 ),
202 )]
203 postgres_cache_database_config: Option<PostgresConnectOptions>,
204 proxy_url: Option<String>,
205 transport_backend: Option<TransportBackend>,
206 ) -> Self {
207 Self::builder()
208 .chain(Arc::new(chain.clone()))
209 .dex_ids(dex_ids)
210 .http_rpc_url(http_rpc_url)
211 .maybe_rpc_requests_per_second(rpc_requests_per_second)
212 .maybe_multicall_calls_per_rpc_request(multicall_calls_per_rpc_request)
213 .maybe_wss_rpc_url(wss_rpc_url)
214 .use_hypersync_for_live_data(use_hypersync_for_live_data)
215 .maybe_from_block(from_block)
216 .maybe_pool_filters(pool_filters)
217 .maybe_postgres_cache_database_config(postgres_cache_database_config)
218 .maybe_proxy_url(proxy_url)
219 .transport_backend(transport_backend.unwrap_or_default())
220 .build()
221 }
222
223 #[getter]
225 #[gen_stub(
226 override_return_type(
227 type_repr = "nautilus_trader.model.Chain",
228 imports = ("nautilus_trader.model",),
229 ),
230 )]
231 fn chain(&self) -> Chain {
232 (*self.chain).clone()
233 }
234
235 #[getter]
237 fn http_rpc_url(&self) -> String {
238 self.http_rpc_url.clone()
239 }
240
241 #[getter]
243 fn wss_rpc_url(&self) -> Option<String> {
244 self.wss_rpc_url.clone()
245 }
246
247 #[getter]
249 const fn rpc_requests_per_second(&self) -> Option<u32> {
250 self.rpc_requests_per_second
251 }
252
253 #[getter]
255 const fn use_hypersync_for_live_data(&self) -> bool {
256 self.use_hypersync_for_live_data
257 }
258
259 #[getter]
261 #[expect(clippy::wrong_self_convention)]
262 const fn from_block(&self) -> Option<u64> {
263 self.from_block
264 }
265
266 #[getter]
267 const fn has_postgres_cache_database_config(&self) -> bool {
268 self.postgres_cache_database_config.is_some()
269 }
270
271 #[getter]
272 const fn has_proxy_url(&self) -> bool {
273 self.proxy_url.is_some()
274 }
275
276 fn __repr__(&self) -> String {
278 format!(
279 "BlockchainDataClientConfig(chain={:?}, http_rpc_url={REDACTED}, wss_rpc_url={:?}, use_hypersync_for_live_data={}, from_block={:?})",
280 self.chain.name,
281 self.wss_rpc_url.as_ref().map(|_| REDACTED),
282 self.use_hypersync_for_live_data,
283 self.from_block
284 )
285 }
286}
287
288#[pymethods]
289#[pyo3_stub_gen::derive::gen_stub_pymethods(module = "nautilus_trader.adapters.blockchain")]
290impl BlockchainExecutionClientConfig {
291 #[new]
293 #[expect(clippy::too_many_arguments)]
294 #[pyo3(signature = (client_id, chain, wallet_address, http_rpc_url, signer_private_key_env, router_addresses, weth_address, max_fee_per_gas_wei, base_fee_buffer_bps, gas_limit, gas_buffer_bps, tokens=None, rpc_requests_per_second=None, unlimited_approval=false, postgres_cache_database_config=None, transport_backend=None, *, allowed_token_pairs=None, quote_spend_limits=None, slippage_bps=None, max_slippage_bps=None, max_order_amount=None, deadline_seconds=None, max_quote_age_blocks=None, receipt_timeout_secs=None, payload_key_env=None, payload_key_retired_env=None, payload_deployment_id=None, verification=None))]
295 fn py_new(
296 client_id: AccountId,
297 #[gen_stub(
298 override_type(
299 type_repr = "nautilus_trader.model.Chain",
300 imports = ("nautilus_trader.model",),
301 ),
302 )]
303 chain: &Chain,
304 wallet_address: String,
305 http_rpc_url: String,
306 signer_private_key_env: String,
307 router_addresses: Vec<String>,
308 weth_address: String,
309 max_fee_per_gas_wei: u64,
310 base_fee_buffer_bps: u32,
311 gas_limit: u64,
312 gas_buffer_bps: u32,
313 tokens: Option<Vec<String>>,
314 rpc_requests_per_second: Option<u32>,
315 unlimited_approval: bool,
316 #[gen_stub(
317 override_type(
318 type_repr = "typing.Optional[nautilus_trader.infrastructure.PostgresConnectOptions]",
319 imports = ("typing", "nautilus_trader.infrastructure"),
320 ),
321 )]
322 postgres_cache_database_config: Option<PostgresConnectOptions>,
323 transport_backend: Option<TransportBackend>,
324 allowed_token_pairs: Option<Vec<(String, String)>>,
325 quote_spend_limits: Option<Vec<QuoteSpendLimit>>,
326 slippage_bps: Option<u32>,
327 max_slippage_bps: Option<u32>,
328 max_order_amount: Option<u64>,
329 deadline_seconds: Option<u64>,
330 max_quote_age_blocks: Option<u64>,
331 receipt_timeout_secs: Option<u64>,
332 payload_key_env: Option<String>,
333 payload_key_retired_env: Option<Vec<String>>,
334 payload_deployment_id: Option<String>,
335 verification: Option<BlockchainVerificationConfig>,
336 ) -> Self {
337 Self::builder()
338 .client_id(client_id)
339 .chain(chain.clone())
340 .wallet_address(wallet_address)
341 .http_rpc_url(http_rpc_url)
342 .signer_private_key_env(signer_private_key_env)
343 .router_addresses(router_addresses)
344 .weth_address(weth_address)
345 .max_fee_per_gas_wei(max_fee_per_gas_wei)
346 .base_fee_buffer_bps(base_fee_buffer_bps)
347 .gas_limit(gas_limit)
348 .gas_buffer_bps(gas_buffer_bps)
349 .maybe_allowed_token_pairs(allowed_token_pairs)
350 .maybe_quote_spend_limits(quote_spend_limits)
351 .maybe_slippage_bps(slippage_bps)
352 .maybe_max_slippage_bps(max_slippage_bps)
353 .maybe_max_order_amount(max_order_amount)
354 .maybe_deadline_seconds(deadline_seconds)
355 .maybe_max_quote_age_blocks(max_quote_age_blocks)
356 .maybe_receipt_timeout_secs(receipt_timeout_secs)
357 .maybe_payload_key_env(payload_key_env)
358 .payload_key_retired_env(payload_key_retired_env.unwrap_or_default())
359 .maybe_payload_deployment_id(payload_deployment_id)
360 .maybe_verification(verification)
361 .maybe_tokens(tokens)
362 .maybe_rpc_requests_per_second(rpc_requests_per_second)
363 .unlimited_approval(unlimited_approval)
364 .maybe_postgres_cache_database_config(postgres_cache_database_config)
365 .transport_backend(transport_backend.unwrap_or_default())
366 .build()
367 }
368
369 #[getter]
371 #[gen_stub(override_return_type(type_repr = "list[tuple[str, str]] | None",))]
372 fn allowed_token_pairs(&self) -> Option<Vec<(String, String)>> {
373 self.allowed_token_pairs.clone()
374 }
375
376 #[getter]
378 const fn client_id(&self) -> AccountId {
379 self.client_id
380 }
381
382 #[getter]
384 #[gen_stub(
385 override_return_type(
386 type_repr = "nautilus_trader.model.Chain",
387 imports = ("nautilus_trader.model",),
388 ),
389 )]
390 fn chain(&self) -> Chain {
391 self.chain.clone()
392 }
393
394 #[getter]
396 const fn rpc_requests_per_second(&self) -> Option<u32> {
397 self.rpc_requests_per_second
398 }
399
400 #[getter]
401 const fn has_postgres_cache_database_config(&self) -> bool {
402 self.postgres_cache_database_config.is_some()
403 }
404
405 fn __repr__(&self) -> String {
407 format!(
408 "BlockchainExecutionClientConfig(chain={:?}, wallet_address={}, http_rpc_url={REDACTED})",
409 self.chain.name, self.wallet_address
410 )
411 }
412}