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 FundingHistory {
70 coin: String,
71 start_time: u64,
72 end_time: Option<u64>,
73 },
74 #[serde(rename_all = "camelCase")]
75 UserFunding {
76 user: H160,
77 start_time: u64,
78 end_time: Option<u64>,
79 },
80 L2Book {
81 coin: String,
82 },
83 RecentTrades {
84 coin: String,
85 },
86 #[serde(rename_all = "camelCase")]
87 CandleSnapshot {
88 req: CandleSnapshotRequest,
89 },
90 Referral {
91 user: H160,
92 },
93 PerpsAtOpenInterestCap,
94}
95
96pub struct InfoClient {
97 pub http_client: HttpClient,
98 pub(crate) ws_manager: Option<WsManager>,
99}
100
101impl InfoClient {
102 pub async fn new(client: Option<Client>, base_url: Option<BaseUrl>) -> Result<InfoClient> {
103 let client = client.unwrap_or_default();
104 let base_url = base_url.unwrap_or(BaseUrl::Mainnet).get_url();
105
106 Ok(InfoClient {
107 http_client: HttpClient { client, base_url },
108 ws_manager: None,
109 })
110 }
111
112 pub async fn subscribe(
113 &mut self,
114 subscription: Subscription,
115 sender_channel: UnboundedSender<Message>,
116 ) -> Result<u32> {
117 if self.ws_manager.is_none() {
118 let ws_manager =
119 WsManager::new(format!("ws{}/ws", &self.http_client.base_url[4..])).await?;
120 self.ws_manager = Some(ws_manager);
121 }
122
123 let identifier =
124 serde_json::to_string(&subscription).map_err(|e| Error::JsonParse(e.to_string()))?;
125
126 self.ws_manager
127 .as_mut()
128 .ok_or(Error::WsManagerNotFound)?
129 .add_subscription(identifier, sender_channel)
130 .await
131 }
132
133 pub async fn unsubscribe(&mut self, subscription_id: u32) -> Result<()> {
134 if self.ws_manager.is_none() {
135 let ws_manager =
136 WsManager::new(format!("ws{}/ws", &self.http_client.base_url[4..])).await?;
137 self.ws_manager = Some(ws_manager);
138 }
139
140 self.ws_manager
141 .as_mut()
142 .ok_or(Error::WsManagerNotFound)?
143 .remove_subscription(subscription_id)
144 .await
145 }
146
147 async fn send_info_request<T: for<'a> Deserialize<'a>>(
148 &self,
149 info_request: InfoRequest,
150 ) -> Result<T> {
151 let data =
152 serde_json::to_string(&info_request).map_err(|e| Error::JsonParse(e.to_string()))?;
153
154 let return_data = self.http_client.post("/info", data).await?;
155 serde_json::from_str(&return_data).map_err(|e| Error::JsonParse(e.to_string()))
156 }
157
158 pub async fn open_orders(&self, address: H160) -> Result<Vec<OpenOrdersResponse>> {
159 let input = InfoRequest::OpenOrders { user: address };
160 self.send_info_request(input).await
161 }
162
163 pub async fn user_state(&self, address: H160) -> Result<UserStateResponse> {
164 let input = InfoRequest::UserState { user: address };
165 self.send_info_request(input).await
166 }
167
168 pub async fn user_states(&self, addresses: Vec<H160>) -> Result<Vec<UserStateResponse>> {
169 let input = InfoRequest::UserStates { users: addresses };
170 self.send_info_request(input).await
171 }
172
173 pub async fn user_token_balances(&self, address: H160) -> Result<UserTokenBalanceResponse> {
174 let input = InfoRequest::UserTokenBalances { user: address };
175 self.send_info_request(input).await
176 }
177
178 pub async fn user_fees(&self, address: H160) -> Result<UserFeesResponse> {
179 let input = InfoRequest::UserFees { user: address };
180 self.send_info_request(input).await
181 }
182
183 pub async fn meta(&self) -> Result<Meta> {
184 let input = InfoRequest::Meta;
185 self.send_info_request(input).await
186 }
187
188 pub async fn spot_meta(&self) -> Result<SpotMeta> {
189 let input = InfoRequest::SpotMeta;
190 self.send_info_request(input).await
191 }
192
193 pub async fn meta_and_asset_contexts(&self) -> Result<MetaAndAssetCtxs> {
194 let input = InfoRequest::MetaAndAssetCtxs;
195 self.send_info_request(input).await
196 }
197
198 pub async fn spot_meta_and_asset_contexts(&self) -> Result<Vec<SpotMetaAndAssetCtxs>> {
199 let input = InfoRequest::SpotMetaAndAssetCtxs;
200 self.send_info_request(input).await
201 }
202
203 pub async fn all_mids(&self) -> Result<HashMap<String, String>> {
204 let input = InfoRequest::AllMids;
205 self.send_info_request(input).await
206 }
207
208 pub async fn user_fills(&self, address: H160) -> Result<Vec<UserFillsResponse>> {
209 let input = InfoRequest::UserFills { user: address };
210 self.send_info_request(input).await
211 }
212
213 pub async fn funding_history(
214 &self,
215 coin: String,
216 start_time: u64,
217 end_time: Option<u64>,
218 ) -> Result<Vec<FundingHistoryResponse>> {
219 let input = InfoRequest::FundingHistory {
220 coin,
221 start_time,
222 end_time,
223 };
224 self.send_info_request(input).await
225 }
226
227 pub async fn user_funding_history(
228 &self,
229 user: H160,
230 start_time: u64,
231 end_time: Option<u64>,
232 ) -> Result<Vec<UserFundingResponse>> {
233 let input = InfoRequest::UserFunding {
234 user,
235 start_time,
236 end_time,
237 };
238 self.send_info_request(input).await
239 }
240
241 pub async fn recent_trades(&self, coin: String) -> Result<Vec<RecentTradesResponse>> {
242 let input = InfoRequest::RecentTrades { coin };
243 self.send_info_request(input).await
244 }
245
246 pub async fn l2_snapshot(&self, coin: String) -> Result<L2SnapshotResponse> {
247 let input = InfoRequest::L2Book { coin };
248 self.send_info_request(input).await
249 }
250
251 pub async fn candles_snapshot(
252 &self,
253 coin: String,
254 interval: String,
255 start_time: u64,
256 end_time: u64,
257 ) -> Result<Vec<CandlesSnapshotResponse>> {
258 let input = InfoRequest::CandleSnapshot {
259 req: CandleSnapshotRequest {
260 coin,
261 interval,
262 start_time,
263 end_time,
264 },
265 };
266 self.send_info_request(input).await
267 }
268
269 pub async fn query_order_by_oid(&self, address: H160, oid: u64) -> Result<OrderStatusResponse> {
270 let input = InfoRequest::OrderStatus { user: address, oid };
271 self.send_info_request(input).await
272 }
273
274 pub async fn query_order_by_cloid(
275 &self,
276 address: H160,
277 cloid: String,
278 ) -> Result<OrderStatusResponse> {
279 let input = InfoRequest::OrderStatusByCloid {
280 user: address,
281 oid: cloid,
282 };
283 self.send_info_request(input).await
284 }
285
286 pub async fn query_referral_state(&self, address: H160) -> Result<ReferralResponse> {
287 let input = InfoRequest::Referral { user: address };
288 self.send_info_request(input).await
289 }
290
291 pub async fn perps_at_open_interest_cap(&self) -> Result<Vec<String>> {
292 let input = InfoRequest::PerpsAtOpenInterestCap;
293 self.send_info_request(input).await
294 }
295}