nautilus_dydx/common/consts.rs
1// -------------------------------------------------------------------------------------------------
2// Copyright (C) 2015-2026 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//! Core constants shared across the dYdX adapter components.
17
18use std::sync::LazyLock;
19
20use nautilus_model::identifiers::{ClientId, Venue};
21use nautilus_network::http::StatusCode;
22use ustr::Ustr;
23
24/// dYdX adapter name.
25pub const DYDX: &str = "DYDX";
26
27/// dYdX venue identifier.
28pub static DYDX_VENUE: LazyLock<Venue> = LazyLock::new(|| Venue::new(Ustr::from(DYDX)));
29
30/// dYdX client ID.
31pub static DYDX_CLIENT_ID: LazyLock<ClientId> = LazyLock::new(|| ClientId::new(Ustr::from(DYDX)));
32
33/// dYdX mainnet chain ID.
34pub const DYDX_CHAIN_ID: &str = "dydx-mainnet-1";
35
36/// dYdX testnet chain ID.
37pub const DYDX_TESTNET_CHAIN_ID: &str = "dydx-testnet-4";
38
39/// Cosmos SDK bech32 address prefix for dYdX.
40pub const DYDX_BECH32_PREFIX: &str = "dydx";
41
42/// Order router address for the NautilusTrader order attribution.
43/// Defined by dYdX governance proposal 381 (<https://mintscan.io/dydx/proposals/381>).
44pub const DYDX_NAUTILUS_ORDER_ROUTER_ADDRESS: &str = "dydx1pahjv32ex740hahnp5dc4hnmlchkeea6ndqat5";
45
46/// USDC gas denomination (native chain token).
47pub const USDC_GAS_DENOM: &str =
48 "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5";
49
50/// USDC asset denomination for transfers.
51pub const USDC_DENOM: &str = "uusdc";
52
53/// HD wallet derivation path for dYdX accounts (Cosmos SLIP-0044).
54/// Format: m/44'/118'/0'/0/{account_index}
55pub const DYDX_DERIVATION_PATH_PREFIX: &str = "m/44'/118'/0'/0";
56
57/// Coin type for Cosmos ecosystem (SLIP-0044).
58pub const COSMOS_COIN_TYPE: u32 = 118;
59
60/// Default WebSocket heartbeat interval in seconds.
61pub const DYDX_WS_HEARTBEAT_SECS: u64 = 20;
62
63// Mainnet URLs
64/// dYdX v4 mainnet HTTP API base URL.
65pub const DYDX_HTTP_URL: &str = "https://indexer.dydx.trade";
66
67/// dYdX v4 mainnet WebSocket URL.
68pub const DYDX_WS_URL: &str = "wss://indexer.dydx.trade/v4/ws";
69
70/// dYdX v4 mainnet REST API URL (Cosmos LCD for chain queries).
71///
72/// Used for querying on-chain state like authenticators.
73pub const DYDX_REST_URL: &str = "https://dydx-ops-rest.kingnodes.com";
74
75/// dYdX v4 mainnet gRPC URLs (public validator nodes with fallbacks).
76///
77/// Multiple nodes are provided for redundancy. The client should attempt to connect
78/// to nodes in order, falling back to the next if connection fails. This is critical
79/// for DEX environments where individual nodes can fail or become unavailable.
80///
81/// Endpoints sourced from:
82/// - <https://docs.dydx.xyz/interaction/endpoints#node>
83///
84/// # Notes
85///
86/// URLs use domain:port format for tonic gRPC client (TLS is automatic on port 443).
87pub const DYDX_GRPC_URLS: &[&str] = &[
88 "https://dydx-ops-grpc.kingnodes.com:443",
89 "https://dydx-dao-grpc-1.polkachu.com:443",
90 "https://dydx-grpc.publicnode.com:443",
91];
92
93/// dYdX v4 mainnet gRPC URL (primary public node).
94///
95/// # Notes
96///
97/// For production use, consider using `DYDX_GRPC_URLS` array with fallback logic
98/// via `DydxGrpcClient::new_with_fallback()`.
99pub const DYDX_GRPC_URL: &str = DYDX_GRPC_URLS[0];
100
101// Testnet URLs
102/// dYdX v4 testnet HTTP API base URL.
103pub const DYDX_TESTNET_HTTP_URL: &str = "https://indexer.v4testnet.dydx.exchange";
104
105/// dYdX v4 testnet WebSocket URL.
106pub const DYDX_TESTNET_WS_URL: &str = "wss://indexer.v4testnet.dydx.exchange/v4/ws";
107
108/// dYdX v4 testnet REST API URL (Cosmos LCD for chain queries).
109///
110/// Used for querying on-chain state like authenticators.
111pub const DYDX_TESTNET_REST_URL: &str = "https://test-dydx-rest.kingnodes.com";
112
113/// dYdX v4 testnet gRPC URLs (public validator nodes with fallbacks).
114///
115/// Multiple nodes are provided for redundancy. The client should attempt to connect
116/// to nodes in order, falling back to the next if connection fails.
117///
118/// Endpoints sourced from:
119/// - <https://docs.dydx.xyz/interaction/endpoints#node>
120///
121/// # Notes
122///
123/// URLs use domain:port format for tonic gRPC client (TLS is automatic on port 443).
124pub const DYDX_TESTNET_GRPC_URLS: &[&str] = &[
125 "https://test-dydx-grpc.kingnodes.com:443",
126 "https://testnet-dydx.lavenderfive.com:443",
127];
128
129/// dYdX v4 testnet gRPC URL (primary public node).
130///
131/// # Notes
132///
133/// For production use, consider using `DYDX_TESTNET_GRPC_URLS` array with fallback logic
134/// via `DydxGrpcClient::new_with_fallback()`.
135pub const DYDX_TESTNET_GRPC_URL: &str = DYDX_TESTNET_GRPC_URLS[0];
136
137/// Determines if an HTTP status code should trigger a retry.
138///
139/// Retries on:
140/// - 429 (Too Many Requests)
141/// - 500-599 (Server Errors)
142///
143/// Does NOT retry on:
144/// - 400 (Bad Request) - indicates client error that won't be fixed by retrying
145/// - 401 (Unauthorized) - not applicable for dYdX Indexer (no auth required)
146/// - 403 (Forbidden) - typically compliance/screening issues
147/// - 404 (Not Found) - resource doesn't exist
148#[must_use]
149pub const fn should_retry_error_code(status: &StatusCode) -> bool {
150 matches!(status.as_u16(), 429 | 500..=599)
151}
152
153#[cfg(test)]
154mod tests {
155 use rstest::rstest;
156
157 use super::*;
158
159 #[rstest]
160 fn test_should_retry_429() {
161 assert!(should_retry_error_code(&StatusCode::TOO_MANY_REQUESTS));
162 }
163
164 #[rstest]
165 fn test_should_retry_server_errors() {
166 assert!(should_retry_error_code(&StatusCode::INTERNAL_SERVER_ERROR));
167 assert!(should_retry_error_code(&StatusCode::BAD_GATEWAY));
168 assert!(should_retry_error_code(&StatusCode::SERVICE_UNAVAILABLE));
169 assert!(should_retry_error_code(&StatusCode::GATEWAY_TIMEOUT));
170 }
171
172 #[rstest]
173 fn test_should_not_retry_client_errors() {
174 assert!(!should_retry_error_code(&StatusCode::BAD_REQUEST));
175 assert!(!should_retry_error_code(&StatusCode::UNAUTHORIZED));
176 assert!(!should_retry_error_code(&StatusCode::FORBIDDEN));
177 assert!(!should_retry_error_code(&StatusCode::NOT_FOUND));
178 }
179
180 #[rstest]
181 fn test_should_not_retry_success() {
182 assert!(!should_retry_error_code(&StatusCode::OK));
183 assert!(!should_retry_error_code(&StatusCode::CREATED));
184 }
185}