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