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