nautilus_dydx/
config.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Configuration structures for the dYdX adapter.
17
18use serde::{Deserialize, Serialize};
19
20use crate::common::consts::{DYDX_CHAIN_ID, DYDX_GRPC_URLS, DYDX_HTTP_URL, DYDX_WS_URL};
21
22/// Configuration for the dYdX adapter.
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct DydxAdapterConfig {
25    /// Base URL for the HTTP API.
26    pub base_url: String,
27    /// Base URL for the WebSocket API.
28    pub ws_url: String,
29    /// Base URL for the gRPC API (Cosmos SDK transactions).
30    ///
31    /// For backwards compatibility, a single URL can be provided.
32    /// Consider using `grpc_urls` for fallback support.
33    pub grpc_url: String,
34    /// List of gRPC URLs with fallback support.
35    ///
36    /// If provided, the client will attempt to connect to each URL in order
37    /// until a successful connection is established. This is recommended for
38    /// production use in DEX environments where nodes can fail.
39    #[serde(default)]
40    pub grpc_urls: Vec<String>,
41    /// Chain ID (e.g., "dydx-mainnet-1" for mainnet, "dydx-testnet-4" for testnet).
42    pub chain_id: String,
43    /// Request timeout in seconds.
44    pub timeout_secs: u64,
45    /// Wallet address for the account (optional, can be derived from mnemonic).
46    #[serde(default)]
47    pub wallet_address: Option<String>,
48    /// Subaccount number (default: 0).
49    #[serde(default)]
50    pub subaccount: u32,
51    /// Whether this is a testnet configuration.
52    #[serde(default)]
53    pub is_testnet: bool,
54    /// Mnemonic phrase for wallet (optional, loaded from environment if not provided).
55    #[serde(default)]
56    pub mnemonic: Option<String>,
57    /// Maximum number of retries for failed requests (default: 3).
58    #[serde(default = "default_max_retries")]
59    pub max_retries: u32,
60    /// Initial retry delay in milliseconds (default: 1000ms).
61    #[serde(default = "default_retry_delay_initial_ms")]
62    pub retry_delay_initial_ms: u64,
63    /// Maximum retry delay in milliseconds (default: 10000ms).
64    #[serde(default = "default_retry_delay_max_ms")]
65    pub retry_delay_max_ms: u64,
66}
67
68fn default_max_retries() -> u32 {
69    3
70}
71
72fn default_retry_delay_initial_ms() -> u64 {
73    1000
74}
75
76fn default_retry_delay_max_ms() -> u64 {
77    10000
78}
79
80impl DydxAdapterConfig {
81    /// Get the list of gRPC URLs to use for connection with fallback support.
82    ///
83    /// Returns `grpc_urls` if non-empty, otherwise falls back to a single-element
84    /// vector containing `grpc_url`.
85    #[must_use]
86    pub fn get_grpc_urls(&self) -> Vec<String> {
87        if !self.grpc_urls.is_empty() {
88            self.grpc_urls.clone()
89        } else {
90            vec![self.grpc_url.clone()]
91        }
92    }
93}
94
95impl Default for DydxAdapterConfig {
96    fn default() -> Self {
97        Self {
98            base_url: DYDX_HTTP_URL.to_string(),
99            ws_url: DYDX_WS_URL.to_string(),
100            grpc_url: DYDX_GRPC_URLS[0].to_string(),
101            grpc_urls: DYDX_GRPC_URLS.iter().map(|&s| s.to_string()).collect(),
102            chain_id: DYDX_CHAIN_ID.to_string(),
103            timeout_secs: 30,
104            wallet_address: None,
105            subaccount: 0,
106            is_testnet: false,
107            mnemonic: None,
108            max_retries: default_max_retries(),
109            retry_delay_initial_ms: default_retry_delay_initial_ms(),
110            retry_delay_max_ms: default_retry_delay_max_ms(),
111        }
112    }
113}
114
115/// Configuration for the dYdX data client.
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct DydxDataClientConfig {
118    /// Base URL for the HTTP API.
119    pub base_url_http: Option<String>,
120    /// Base URL for the WebSocket API.
121    pub base_url_ws: Option<String>,
122    /// HTTP request timeout in seconds.
123    pub http_timeout_secs: Option<u64>,
124    /// Maximum number of retry attempts for failed HTTP requests.
125    pub max_retries: Option<u64>,
126    /// Initial retry delay in milliseconds.
127    pub retry_delay_initial_ms: Option<u64>,
128    /// Maximum retry delay in milliseconds.
129    pub retry_delay_max_ms: Option<u64>,
130    /// Whether this is a testnet configuration.
131    pub is_testnet: bool,
132    /// HTTP proxy URL.
133    pub http_proxy_url: Option<String>,
134    /// WebSocket proxy URL.
135    pub ws_proxy_url: Option<String>,
136    /// Orderbook snapshot refresh interval in seconds (prevents stale books from missed messages).
137    /// Set to None to disable periodic refresh. Default: 60 seconds.
138    pub orderbook_refresh_interval_secs: Option<u64>,
139    /// Instrument refresh interval in seconds (updates instrument definitions periodically).
140    /// Set to None to disable periodic refresh. Default: 3600 seconds (60 minutes).
141    pub instrument_refresh_interval_secs: Option<u64>,
142}
143
144impl Default for DydxDataClientConfig {
145    fn default() -> Self {
146        Self {
147            base_url_http: None,
148            base_url_ws: None,
149            http_timeout_secs: Some(60),
150            max_retries: Some(3),
151            retry_delay_initial_ms: Some(100),
152            retry_delay_max_ms: Some(5000),
153            is_testnet: false,
154            http_proxy_url: None,
155            ws_proxy_url: None,
156            orderbook_refresh_interval_secs: Some(60),
157            instrument_refresh_interval_secs: Some(3600),
158        }
159    }
160}
161
162/// Configuration for the dYdX execution client.
163#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct DYDXExecClientConfig {
165    /// gRPC endpoint URL.
166    pub grpc_endpoint: String,
167    /// WebSocket endpoint URL.
168    pub ws_endpoint: String,
169    /// Wallet mnemonic for signing transactions.
170    pub mnemonic: Option<String>,
171    /// Wallet address.
172    pub wallet_address: Option<String>,
173    /// Subaccount number (default: 0).
174    pub subaccount_number: u32,
175    /// HTTP request timeout in seconds.
176    pub http_timeout_secs: Option<u64>,
177    /// Maximum number of retry attempts.
178    pub max_retries: Option<u64>,
179    /// Initial retry delay in milliseconds.
180    pub retry_delay_initial_ms: Option<u64>,
181    /// Maximum retry delay in milliseconds.
182    pub retry_delay_max_ms: Option<u64>,
183    /// Whether this is a testnet configuration.
184    pub is_testnet: bool,
185}
186
187impl Default for DYDXExecClientConfig {
188    fn default() -> Self {
189        Self {
190            grpc_endpoint: DYDX_GRPC_URLS[0].to_string(),
191            ws_endpoint: DYDX_WS_URL.to_string(),
192            mnemonic: None,
193            wallet_address: None,
194            subaccount_number: 0,
195            http_timeout_secs: Some(60),
196            max_retries: Some(3),
197            retry_delay_initial_ms: Some(100),
198            retry_delay_max_ms: Some(5000),
199            is_testnet: false,
200        }
201    }
202}