1use polyte_core::{QueryBuilder, Request, RequestError};
2use reqwest::Client;
3use serde::{Deserialize, Serialize};
4use url::Url;
5
6use crate::{
7 error::DataApiError,
8 types::{
9 Activity, ActivitySortBy, ActivityType, ClosedPosition, ClosedPositionSortBy, Position,
10 PositionSortBy, SortDirection, Trade, TradeFilterType, TradeSide, UserValue,
11 },
12};
13
14#[derive(Clone)]
16pub struct UserApi {
17 pub(crate) client: Client,
18 pub(crate) base_url: Url,
19 pub(crate) user_address: String,
20}
21
22impl UserApi {
23 pub fn list_positions(&self) -> ListPositions {
25 let mut request = Request::new(self.client.clone(), self.base_url.clone(), "/positions");
26 request = request.query("user", &self.user_address);
27
28 ListPositions { request }
29 }
30
31 pub fn positions_value(&self) -> GetPositionValue {
33 let mut request = Request::new(self.client.clone(), self.base_url.clone(), "/value");
34 request = request.query("user", &self.user_address);
35
36 GetPositionValue { request }
37 }
38
39 pub fn closed_positions(&self) -> ListClosedPositions {
41 let mut request = Request::new(
42 self.client.clone(),
43 self.base_url.clone(),
44 "/closed-positions",
45 );
46 request = request.query("user", &self.user_address);
47
48 ListClosedPositions { request }
49 }
50
51 pub fn trades(&self) -> ListUserTrades {
53 let mut request = Request::new(self.client.clone(), self.base_url.clone(), "/trades");
54 request = request.query("user", &self.user_address);
55
56 ListUserTrades { request }
57 }
58
59 pub fn activity(&self) -> ListActivity {
61 let mut request = Request::new(self.client.clone(), self.base_url.clone(), "/activity");
62 request = request.query("user", &self.user_address);
63
64 ListActivity { request }
65 }
66
67 pub async fn traded(&self) -> Result<UserTraded, DataApiError> {
69 let url = self.base_url.join("/traded")?;
70 let response = self
71 .client
72 .get(url)
73 .query(&[("user", &self.user_address)])
74 .send()
75 .await?;
76 let status = response.status();
77
78 if !status.is_success() {
79 return Err(DataApiError::from_response(response).await);
80 }
81
82 let traded: UserTraded = response.json().await?;
83 Ok(traded)
84 }
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct UserTraded {
90 pub user: String,
92 pub traded: u64,
94}
95
96pub struct ListPositions {
98 request: Request<Vec<Position>, DataApiError>,
99}
100
101impl ListPositions {
102 pub fn market(mut self, condition_ids: impl IntoIterator<Item = impl ToString>) -> Self {
104 let ids: Vec<String> = condition_ids.into_iter().map(|s| s.to_string()).collect();
105 if !ids.is_empty() {
106 self.request = self.request.query("market", ids.join(","));
107 }
108 self
109 }
110
111 pub fn event_id(mut self, event_ids: impl IntoIterator<Item = impl ToString>) -> Self {
113 let ids: Vec<String> = event_ids.into_iter().map(|s| s.to_string()).collect();
114 if !ids.is_empty() {
115 self.request = self.request.query("eventId", ids.join(","));
116 }
117 self
118 }
119
120 pub fn size_threshold(mut self, threshold: f64) -> Self {
122 self.request = self.request.query("sizeThreshold", threshold);
123 self
124 }
125
126 pub fn redeemable(mut self, redeemable: bool) -> Self {
128 self.request = self.request.query("redeemable", redeemable);
129 self
130 }
131
132 pub fn mergeable(mut self, mergeable: bool) -> Self {
134 self.request = self.request.query("mergeable", mergeable);
135 self
136 }
137
138 pub fn limit(mut self, limit: u32) -> Self {
140 self.request = self.request.query("limit", limit);
141 self
142 }
143
144 pub fn offset(mut self, offset: u32) -> Self {
146 self.request = self.request.query("offset", offset);
147 self
148 }
149
150 pub fn sort_by(mut self, sort_by: PositionSortBy) -> Self {
152 self.request = self.request.query("sortBy", sort_by);
153 self
154 }
155
156 pub fn sort_direction(mut self, direction: SortDirection) -> Self {
158 self.request = self.request.query("sortDirection", direction);
159 self
160 }
161
162 pub fn title(mut self, title: impl Into<String>) -> Self {
164 self.request = self.request.query("title", title.into());
165 self
166 }
167
168 pub async fn send(self) -> Result<Vec<Position>, DataApiError> {
170 self.request.send().await
171 }
172}
173
174pub struct GetPositionValue {
176 request: Request<Vec<UserValue>, DataApiError>,
177}
178
179impl GetPositionValue {
180 pub fn market(mut self, condition_ids: impl IntoIterator<Item = impl ToString>) -> Self {
182 let ids: Vec<String> = condition_ids.into_iter().map(|s| s.to_string()).collect();
183 if !ids.is_empty() {
184 self.request = self.request.query("market", ids.join(","));
185 }
186 self
187 }
188
189 pub async fn send(self) -> Result<Vec<UserValue>, DataApiError> {
191 self.request.send().await
192 }
193}
194
195pub struct ListClosedPositions {
197 request: Request<Vec<ClosedPosition>, DataApiError>,
198}
199
200impl ListClosedPositions {
201 pub fn market(mut self, condition_ids: impl IntoIterator<Item = impl ToString>) -> Self {
203 let ids: Vec<String> = condition_ids.into_iter().map(|s| s.to_string()).collect();
204 if !ids.is_empty() {
205 self.request = self.request.query("market", ids.join(","));
206 }
207 self
208 }
209
210 pub fn event_id(mut self, event_ids: impl IntoIterator<Item = impl ToString>) -> Self {
212 let ids: Vec<String> = event_ids.into_iter().map(|s| s.to_string()).collect();
213 if !ids.is_empty() {
214 self.request = self.request.query("eventId", ids.join(","));
215 }
216 self
217 }
218
219 pub fn title(mut self, title: impl Into<String>) -> Self {
221 self.request = self.request.query("title", title.into());
222 self
223 }
224
225 pub fn limit(mut self, limit: u32) -> Self {
227 self.request = self.request.query("limit", limit);
228 self
229 }
230
231 pub fn offset(mut self, offset: u32) -> Self {
233 self.request = self.request.query("offset", offset);
234 self
235 }
236
237 pub fn sort_by(mut self, sort_by: ClosedPositionSortBy) -> Self {
239 self.request = self.request.query("sortBy", sort_by);
240 self
241 }
242
243 pub fn sort_direction(mut self, direction: SortDirection) -> Self {
245 self.request = self.request.query("sortDirection", direction);
246 self
247 }
248
249 pub async fn send(self) -> Result<Vec<ClosedPosition>, DataApiError> {
251 self.request.send().await
252 }
253}
254
255pub struct ListUserTrades {
257 request: Request<Vec<Trade>, DataApiError>,
258}
259
260impl ListUserTrades {
261 pub fn market(mut self, condition_ids: impl IntoIterator<Item = impl ToString>) -> Self {
264 let ids: Vec<String> = condition_ids.into_iter().map(|s| s.to_string()).collect();
265 if !ids.is_empty() {
266 self.request = self.request.query("market", ids.join(","));
267 }
268 self
269 }
270
271 pub fn event_id(mut self, event_ids: impl IntoIterator<Item = impl ToString>) -> Self {
274 let ids: Vec<String> = event_ids.into_iter().map(|s| s.to_string()).collect();
275 if !ids.is_empty() {
276 self.request = self.request.query("eventId", ids.join(","));
277 }
278 self
279 }
280
281 pub fn side(mut self, side: TradeSide) -> Self {
283 self.request = self.request.query("side", side);
284 self
285 }
286
287 pub fn taker_only(mut self, taker_only: bool) -> Self {
289 self.request = self.request.query("takerOnly", taker_only);
290 self
291 }
292
293 pub fn filter_type(mut self, filter_type: TradeFilterType) -> Self {
295 self.request = self.request.query("filterType", filter_type);
296 self
297 }
298
299 pub fn filter_amount(mut self, amount: f64) -> Self {
301 self.request = self.request.query("filterAmount", amount);
302 self
303 }
304
305 pub fn limit(mut self, limit: u32) -> Self {
307 self.request = self.request.query("limit", limit);
308 self
309 }
310
311 pub fn offset(mut self, offset: u32) -> Self {
313 self.request = self.request.query("offset", offset);
314 self
315 }
316
317 pub async fn send(self) -> Result<Vec<Trade>, DataApiError> {
319 self.request.send().await
320 }
321}
322
323pub struct ListActivity {
325 request: Request<Vec<Activity>, DataApiError>,
326}
327
328impl ListActivity {
329 pub fn market(mut self, condition_ids: impl IntoIterator<Item = impl ToString>) -> Self {
331 let ids: Vec<String> = condition_ids.into_iter().map(|s| s.to_string()).collect();
332 if !ids.is_empty() {
333 self.request = self.request.query("market", ids.join(","));
334 }
335 self
336 }
337
338 pub fn event_id(mut self, event_ids: impl IntoIterator<Item = impl ToString>) -> Self {
340 let ids: Vec<String> = event_ids.into_iter().map(|s| s.to_string()).collect();
341 if !ids.is_empty() {
342 self.request = self.request.query("eventId", ids.join(","));
343 }
344 self
345 }
346
347 pub fn activity_type(mut self, types: impl IntoIterator<Item = ActivityType>) -> Self {
349 let type_strs: Vec<String> = types.into_iter().map(|t| t.to_string()).collect();
350 if !type_strs.is_empty() {
351 self.request = self.request.query("type", type_strs.join(","));
352 }
353 self
354 }
355
356 pub fn side(mut self, side: TradeSide) -> Self {
358 self.request = self.request.query("side", side);
359 self
360 }
361
362 pub fn start(mut self, timestamp: i64) -> Self {
364 self.request = self.request.query("start", timestamp);
365 self
366 }
367
368 pub fn end(mut self, timestamp: i64) -> Self {
370 self.request = self.request.query("end", timestamp);
371 self
372 }
373
374 pub fn limit(mut self, limit: u32) -> Self {
376 self.request = self.request.query("limit", limit);
377 self
378 }
379
380 pub fn offset(mut self, offset: u32) -> Self {
382 self.request = self.request.query("offset", offset);
383 self
384 }
385
386 pub fn sort_by(mut self, sort_by: ActivitySortBy) -> Self {
388 self.request = self.request.query("sortBy", sort_by);
389 self
390 }
391
392 pub fn sort_direction(mut self, direction: SortDirection) -> Self {
394 self.request = self.request.query("sortDirection", direction);
395 self
396 }
397
398 pub async fn send(self) -> Result<Vec<Activity>, DataApiError> {
400 self.request.send().await
401 }
402}