nautilus_hyperliquid/http/
models.rs1use serde::{Deserialize, Serialize};
17
18use crate::common::enums::HyperliquidSide;
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct HyperliquidMeta {
23 #[serde(default)]
24 pub universe: Vec<HyperliquidAssetInfo>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct HyperliquidAssetInfo {
30 pub name: String,
32 #[serde(rename = "szDecimals")]
34 pub sz_decimals: u32,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct HyperliquidL2Book {
40 pub coin: String,
42 pub levels: Vec<Vec<HyperliquidLevel>>,
44 pub time: u64,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct HyperliquidLevel {
51 pub px: String,
53 pub sz: String,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct HyperliquidFills {
60 #[serde(default)]
61 pub fills: Vec<HyperliquidFill>,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct HyperliquidFill {
67 pub coin: String,
69 pub px: String,
71 pub sz: String,
73 pub side: HyperliquidSide,
75 pub time: u64,
77 #[serde(rename = "startPosition")]
79 pub start_position: String,
80 pub dir: String,
82 #[serde(rename = "closedPnl")]
84 pub closed_pnl: String,
85 pub hash: String,
87 pub oid: u64,
89 pub crossed: bool,
91 pub fee: String,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct HyperliquidOrderStatus {
98 #[serde(default)]
99 pub statuses: Vec<HyperliquidOrderStatusEntry>,
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct HyperliquidOrderStatusEntry {
105 pub order: HyperliquidOrderInfo,
107 pub status: String,
109 #[serde(rename = "statusTimestamp")]
111 pub status_timestamp: u64,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct HyperliquidOrderInfo {
117 pub coin: String,
119 pub side: HyperliquidSide,
121 #[serde(rename = "limitPx")]
123 pub limit_px: String,
124 pub sz: String,
126 pub oid: u64,
128 pub timestamp: u64,
130 #[serde(rename = "origSz")]
132 pub orig_sz: String,
133}
134
135#[derive(Debug, Clone, Serialize)]
137pub struct HyperliquidExchangeRequest<T> {
138 pub action: T,
140 #[serde(rename = "nonce")]
142 pub nonce: u64,
143 #[serde(rename = "signature")]
145 pub signature: String,
146 #[serde(rename = "vaultAddress", skip_serializing_if = "Option::is_none")]
148 pub vault_address: Option<String>,
149}
150
151impl<T> HyperliquidExchangeRequest<T>
152where
153 T: Serialize,
154{
155 pub fn new(action: T, nonce: u64, signature: String) -> Self {
157 Self {
158 action,
159 nonce,
160 signature,
161 vault_address: None,
162 }
163 }
164
165 pub fn with_vault(action: T, nonce: u64, signature: String, vault_address: String) -> Self {
167 Self {
168 action,
169 nonce,
170 signature,
171 vault_address: Some(vault_address),
172 }
173 }
174
175 pub fn to_sign_value(&self) -> serde_json::Result<serde_json::Value> {
177 serde_json::to_value(self)
178 }
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
183#[serde(untagged)]
184pub enum HyperliquidExchangeResponse {
185 Status {
187 status: String,
189 response: serde_json::Value,
191 },
192 Error {
194 error: String,
196 },
197}
198
199#[cfg(test)]
204mod tests {
205 use rstest::rstest;
206
207 use super::*;
208
209 #[rstest]
210 fn test_meta_deserialization() {
211 let json = r#"{"universe": [{"name": "BTC", "szDecimals": 5}]}"#;
212
213 let meta: HyperliquidMeta = serde_json::from_str(json).unwrap();
214
215 assert_eq!(meta.universe.len(), 1);
216 assert_eq!(meta.universe[0].name, "BTC");
217 assert_eq!(meta.universe[0].sz_decimals, 5);
218 }
219
220 #[rstest]
221 fn test_l2_book_deserialization() {
222 let json = r#"{"coin": "BTC", "levels": [[{"px": "50000", "sz": "1.5"}], [{"px": "50100", "sz": "2.0"}]], "time": 1234567890}"#;
223
224 let book: HyperliquidL2Book = serde_json::from_str(json).unwrap();
225
226 assert_eq!(book.coin, "BTC");
227 assert_eq!(book.levels.len(), 2);
228 assert_eq!(book.time, 1234567890);
229 }
230
231 #[rstest]
232 fn test_exchange_response_deserialization() {
233 let json = r#"{"status": "ok", "response": {"type": "order"}}"#;
234
235 let response: HyperliquidExchangeResponse = serde_json::from_str(json).unwrap();
236
237 match response {
238 HyperliquidExchangeResponse::Status { status, .. } => assert_eq!(status, "ok"),
239 _ => panic!("Expected status response"),
240 }
241 }
242}