hyperliquid_rust_sdk_abrkn/info/
info_client.rs1use crate::{
2 info::{
3 CandlesSnapshotResponse, FundingHistoryResponse, L2SnapshotResponse, OpenOrdersResponse,
4 RecentTradesResponse, UserFillsResponse, UserStateResponse,
5 },
6 meta::{Meta, MetaAndAssetCtxs, SpotMeta, SpotMetaAndAssetCtxs},
7 prelude::*,
8 req::HttpClient,
9 ws::{Subscription, WsManager},
10 BaseUrl, Error, Message, OrderStatusResponse, ReferralResponse, UserFeesResponse,
11 UserFundingResponse, UserTokenBalanceResponse,
12};
13
14use ethers::types::H160;
15use reqwest::Client;
16use serde::{Deserialize, Serialize};
17use std::collections::HashMap;
18use tokio::sync::mpsc::UnboundedSender;
19
20#[derive(Deserialize, Serialize, Debug, Clone)]
21#[serde(rename_all = "camelCase")]
22pub struct CandleSnapshotRequest {
23 coin: String,
24 interval: String,
25 start_time: u64,
26 end_time: u64,
27}
28
29#[derive(Deserialize, Serialize, Debug, Clone)]
30#[serde(tag = "type")]
31#[serde(rename_all = "camelCase")]
32pub enum InfoRequest {
33 #[serde(rename = "clearinghouseState")]
34 UserState {
35 user: H160,
36 },
37 #[serde(rename = "batchClearinghouseStates")]
38 UserStates {
39 users: Vec<H160>,
40 },
41 #[serde(rename = "spotClearinghouseState")]
42 UserTokenBalances {
43 user: H160,
44 },
45 UserFees {
46 user: H160,
47 },
48 OpenOrders {
49 user: H160,
50 },
51 OrderStatus {
52 user: H160,
53 oid: u64,
54 },
55 #[serde(rename = "orderStatus")]
56 OrderStatusByCloid {
57 user: H160,
58 oid: String,
59 },
60 Meta,
61 SpotMeta,
62 MetaAndAssetCtxs,
63 SpotMetaAndAssetCtxs,
64 AllMids,
65 UserFills {
66 user: H160,
67 },
68 #[serde(rename_all = "camelCase")]
69 UserFillsByTime {
70 user: H160,
71 start_time: u64,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 end_time: Option<u64>,
76 #[serde(skip_serializing_if = "Option::is_none")]
78 aggregate_by_time: Option<bool>,
79 },
80 #[serde(rename_all = "camelCase")]
81 FundingHistory {
82 coin: String,
83 start_time: u64,
84 end_time: Option<u64>,
85 },
86 #[serde(rename_all = "camelCase")]
87 UserFunding {
88 user: H160,
89 start_time: u64,
90 end_time: Option<u64>,
91 },
92 L2Book {
93 coin: String,
94 },
95 RecentTrades {
96 coin: String,
97 },
98 #[serde(rename_all = "camelCase")]
99 CandleSnapshot {
100 req: CandleSnapshotRequest,
101 },
102 Referral {
103 user: H160,
104 },
105 PerpsAtOpenInterestCap,
106}
107
108pub struct InfoClient {
109 pub http_client: HttpClient,
110 pub(crate) ws_manager: Option<WsManager>,
111}
112
113impl InfoClient {
114 pub async fn new(client: Option<Client>, base_url: Option<BaseUrl>) -> Result<InfoClient> {
115 let client = client.unwrap_or_default();
116 let base_url = base_url.unwrap_or(BaseUrl::Mainnet).get_url();
117
118 Ok(InfoClient {
119 http_client: HttpClient { client, base_url },
120 ws_manager: None,
121 })
122 }
123
124 pub async fn subscribe(
125 &mut self,
126 subscription: Subscription,
127 sender_channel: UnboundedSender<Message>,
128 ) -> Result<u32> {
129 if self.ws_manager.is_none() {
130 let ws_manager =
131 WsManager::new(format!("ws{}/ws", &self.http_client.base_url[4..])).await?;
132 self.ws_manager = Some(ws_manager);
133 }
134
135 let identifier =
136 serde_json::to_string(&subscription).map_err(|e| Error::JsonParse(e.to_string()))?;
137
138 self.ws_manager
139 .as_mut()
140 .ok_or(Error::WsManagerNotFound)?
141 .add_subscription(identifier, sender_channel)
142 .await
143 }
144
145 pub async fn unsubscribe(&mut self, subscription_id: u32) -> Result<()> {
146 if self.ws_manager.is_none() {
147 let ws_manager =
148 WsManager::new(format!("ws{}/ws", &self.http_client.base_url[4..])).await?;
149 self.ws_manager = Some(ws_manager);
150 }
151
152 self.ws_manager
153 .as_mut()
154 .ok_or(Error::WsManagerNotFound)?
155 .remove_subscription(subscription_id)
156 .await
157 }
158
159 async fn send_info_request<T: for<'a> Deserialize<'a>>(
160 &self,
161 info_request: InfoRequest,
162 ) -> Result<T> {
163 let data =
164 serde_json::to_string(&info_request).map_err(|e| Error::JsonParse(e.to_string()))?;
165
166 let return_data = self.http_client.post("/info", data).await?;
167 serde_json::from_str(&return_data).map_err(|e| Error::JsonParse(e.to_string()))
168 }
169
170 pub async fn open_orders(&self, address: H160) -> Result<Vec<OpenOrdersResponse>> {
171 let input = InfoRequest::OpenOrders { user: address };
172 self.send_info_request(input).await
173 }
174
175 pub async fn user_state(&self, address: H160) -> Result<UserStateResponse> {
176 let input = InfoRequest::UserState { user: address };
177 self.send_info_request(input).await
178 }
179
180 pub async fn user_states(&self, addresses: Vec<H160>) -> Result<Vec<UserStateResponse>> {
181 let input = InfoRequest::UserStates { users: addresses };
182 self.send_info_request(input).await
183 }
184
185 pub async fn user_token_balances(&self, address: H160) -> Result<UserTokenBalanceResponse> {
186 let input = InfoRequest::UserTokenBalances { user: address };
187 self.send_info_request(input).await
188 }
189
190 pub async fn user_fees(&self, address: H160) -> Result<UserFeesResponse> {
191 let input = InfoRequest::UserFees { user: address };
192 self.send_info_request(input).await
193 }
194
195 pub async fn meta(&self) -> Result<Meta> {
196 let input = InfoRequest::Meta;
197 self.send_info_request(input).await
198 }
199
200 pub async fn spot_meta(&self) -> Result<SpotMeta> {
201 let input = InfoRequest::SpotMeta;
202 self.send_info_request(input).await
203 }
204
205 pub async fn meta_and_asset_contexts(&self) -> Result<MetaAndAssetCtxs> {
206 let input = InfoRequest::MetaAndAssetCtxs;
207 self.send_info_request(input).await
208 }
209
210 pub async fn spot_meta_and_asset_contexts(&self) -> Result<Vec<SpotMetaAndAssetCtxs>> {
211 let input = InfoRequest::SpotMetaAndAssetCtxs;
212 self.send_info_request(input).await
213 }
214
215 pub async fn all_mids(&self) -> Result<HashMap<String, String>> {
216 let input = InfoRequest::AllMids;
217 self.send_info_request(input).await
218 }
219
220 pub async fn user_fills(&self, address: H160) -> Result<Vec<UserFillsResponse>> {
221 let input = InfoRequest::UserFills { user: address };
222 self.send_info_request(input).await
223 }
224
225 pub async fn user_fills_by_time(
226 &self,
227 address: H160,
228 start_time: u64,
229 end_time: Option<u64>,
230 aggregate_by_time: Option<bool>,
231 ) -> Result<Vec<UserFillsResponse>> {
232 let input = InfoRequest::UserFillsByTime {
233 user: address,
234 start_time,
235 end_time,
236 aggregate_by_time,
237 };
238
239 self.send_info_request(input).await
240 }
241
242 pub async fn funding_history(
243 &self,
244 coin: String,
245 start_time: u64,
246 end_time: Option<u64>,
247 ) -> Result<Vec<FundingHistoryResponse>> {
248 let input = InfoRequest::FundingHistory {
249 coin,
250 start_time,
251 end_time,
252 };
253 self.send_info_request(input).await
254 }
255
256 pub async fn user_funding_history(
257 &self,
258 user: H160,
259 start_time: u64,
260 end_time: Option<u64>,
261 ) -> Result<Vec<UserFundingResponse>> {
262 let input = InfoRequest::UserFunding {
263 user,
264 start_time,
265 end_time,
266 };
267 self.send_info_request(input).await
268 }
269
270 pub async fn recent_trades(&self, coin: String) -> Result<Vec<RecentTradesResponse>> {
271 let input = InfoRequest::RecentTrades { coin };
272 self.send_info_request(input).await
273 }
274
275 pub async fn l2_snapshot(&self, coin: String) -> Result<L2SnapshotResponse> {
276 let input = InfoRequest::L2Book { coin };
277 self.send_info_request(input).await
278 }
279
280 pub async fn candles_snapshot(
281 &self,
282 coin: String,
283 interval: String,
284 start_time: u64,
285 end_time: u64,
286 ) -> Result<Vec<CandlesSnapshotResponse>> {
287 let input = InfoRequest::CandleSnapshot {
288 req: CandleSnapshotRequest {
289 coin,
290 interval,
291 start_time,
292 end_time,
293 },
294 };
295 self.send_info_request(input).await
296 }
297
298 pub async fn query_order_by_oid(&self, address: H160, oid: u64) -> Result<OrderStatusResponse> {
299 let input = InfoRequest::OrderStatus { user: address, oid };
300 self.send_info_request(input).await
301 }
302
303 pub async fn query_order_by_cloid(
304 &self,
305 address: H160,
306 cloid: String,
307 ) -> Result<OrderStatusResponse> {
308 let input = InfoRequest::OrderStatusByCloid {
309 user: address,
310 oid: cloid,
311 };
312 self.send_info_request(input).await
313 }
314
315 pub async fn query_referral_state(&self, address: H160) -> Result<ReferralResponse> {
316 let input = InfoRequest::Referral { user: address };
317 self.send_info_request(input).await
318 }
319
320 pub async fn perps_at_open_interest_cap(&self) -> Result<Vec<String>> {
321 let input = InfoRequest::PerpsAtOpenInterestCap;
322 self.send_info_request(input).await
323 }
324}