polymarket_rs_client/
lib.rs

1use alloy_primitives::hex::encode_prefixed;
2pub use alloy_primitives::U256;
3use alloy_signer_local::PrivateKeySigner;
4pub use anyhow::{anyhow, Context, Result as ClientResult};
5use config::get_contract_config;
6use orders::OrderBuilder;
7use orders::SignedOrderRequest;
8use reqwest::header::HeaderName;
9use reqwest::Client;
10use reqwest::Method;
11use reqwest::RequestBuilder;
12use rust_decimal::Decimal;
13pub use serde_json::Value;
14use std::collections::HashMap;
15
16// #[cfg(test)]
17// mod tests;
18
19mod config;
20mod data;
21mod eth_utils;
22mod headers;
23mod orders;
24mod utils;
25
26pub use data::*;
27pub use eth_utils::EthSigner;
28use headers::{create_l1_headers, create_l2_headers};
29
30#[derive(Default)]
31pub struct ClobClient {
32    host: String,
33    http_client: Client,
34    signer: Option<Box<dyn EthSigner>>,
35    chain_id: Option<u64>,
36    api_creds: Option<ApiCreds>,
37    order_builder: Option<OrderBuilder>,
38}
39
40const INITIAL_CURSOR: &str = "MA==";
41const END_CURSOR: &str = "LTE=";
42
43impl ClobClient {
44    // TODO: initial headers, gzip
45    pub fn new(host: &str) -> Self {
46        Self {
47            host: host.to_owned(),
48            http_client: Client::new(),
49            ..Default::default()
50        }
51    }
52    pub fn with_l1_headers(host: &str, key: &str, chain_id: u64) -> Self {
53        let signer = Box::new(
54            key.parse::<PrivateKeySigner>()
55                .expect("Invalid private key"),
56        );
57        Self {
58            host: host.to_owned(),
59            http_client: Client::new(),
60            signer: Some(signer.clone()),
61            chain_id: Some(chain_id),
62            api_creds: None,
63            order_builder: Some(OrderBuilder::new(signer, None, None)),
64        }
65    }
66
67    pub fn with_l2_headers(host: &str, key: &str, chain_id: u64, api_creds: ApiCreds) -> Self {
68        let signer = Box::new(
69            key.parse::<PrivateKeySigner>()
70                .expect("Invalid private key"),
71        );
72        Self {
73            host: host.to_owned(),
74            http_client: Client::new(),
75            signer: Some(signer.clone()),
76            chain_id: Some(chain_id),
77            api_creds: Some(api_creds),
78            order_builder: Some(OrderBuilder::new(signer, None, None)),
79        }
80    }
81    pub fn set_api_creds(&mut self, api_creds: ApiCreds) {
82        self.api_creds = Some(api_creds);
83    }
84
85    #[inline]
86    fn get_l1_parameters(&self) -> (&impl EthSigner, u64) {
87        let signer = self.signer.as_ref().expect("Signer is not set");
88        let chain_id = self.chain_id.expect("Chain id is not set");
89        (signer, chain_id)
90    }
91
92    #[inline]
93    fn get_l2_parameters(&self) -> (&impl EthSigner, &ApiCreds) {
94        let signer = self.signer.as_ref().expect("Signer is not set");
95        (
96            signer,
97            self.api_creds.as_ref().expect("API credentials not set."),
98        )
99    }
100
101    pub fn get_address(&self) -> Option<String> {
102        Some(encode_prefixed(self.signer.as_ref()?.address().as_slice()))
103    }
104
105    pub fn get_collateral_address(&self) -> Option<String> {
106        Some(get_contract_config(self.chain_id?, false)?.collateral)
107    }
108
109    pub fn get_conditional_address(&self) -> Option<String> {
110        Some(get_contract_config(self.chain_id?, false)?.conditional_tokens)
111    }
112
113    pub fn get_exchange_address(&self) -> Option<String> {
114        Some(get_contract_config(self.chain_id?, false)?.exchange)
115    }
116
117    fn create_request_with_headers(
118        &self,
119        method: Method,
120        endpoint: &str,
121        headers: impl Iterator<Item = (&'static str, String)>,
122    ) -> RequestBuilder {
123        let req = self
124            .http_client
125            .request(method, format!("{}{endpoint}", &self.host));
126
127        headers.fold(req, |r, (k, v)| r.header(HeaderName::from_static(k), v))
128    }
129
130    pub async fn get_ok(&self) -> bool {
131        self.http_client
132            .get(format!("{}/", &self.host))
133            .send()
134            .await
135            .is_ok()
136    }
137
138    pub async fn get_server_time(&self) -> ClientResult<u64> {
139        let resp = self
140            .http_client
141            .get(format!("{}/time", &self.host))
142            .send()
143            .await?
144            .text()
145            .await?
146            .parse::<u64>()?;
147        Ok(resp)
148    }
149
150    pub async fn create_api_key(&self, nonce: Option<U256>) -> ClientResult<ApiCreds> {
151        let method = Method::POST;
152        let endpoint = "/auth/api-key";
153        let (signer, _) = self.get_l1_parameters();
154        let headers = create_l1_headers(signer, nonce)?;
155
156        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
157
158        Ok(req.send().await?.json::<ApiCreds>().await?)
159    }
160
161    pub async fn derive_api_key(&self, nonce: Option<U256>) -> ClientResult<ApiCreds> {
162        let method = Method::GET;
163        let endpoint = "/auth/derive-api-key";
164        let (signer, _) = self.get_l1_parameters();
165        let headers = create_l1_headers(signer, nonce)?;
166
167        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
168
169        Ok(req.send().await?.json::<ApiCreds>().await?)
170    }
171
172    pub async fn create_or_derive_api_key(&self, nonce: Option<U256>) -> ClientResult<ApiCreds> {
173        let creds = self.create_api_key(nonce).await;
174        if creds.is_err() {
175            return self.derive_api_key(nonce).await;
176        }
177        creds
178    }
179
180    pub async fn get_api_keys(&self) -> ClientResult<Vec<String>> {
181        let method = Method::GET;
182        let endpoint = "/auth/api-keys";
183        let (signer, creds) = self.get_l2_parameters();
184        let headers = create_l2_headers::<Value>(signer, creds, method.as_str(), endpoint, None)?;
185
186        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
187
188        Ok(req.send().await?.json::<ApiKeysResponse>().await?.api_keys)
189    }
190
191    pub async fn delete_api_key(&self) -> ClientResult<String> {
192        let method = Method::DELETE;
193        let endpoint = "/auth/api-key";
194        let (signer, creds) = self.get_l2_parameters();
195        let headers = create_l2_headers::<Value>(signer, creds, method.as_str(), endpoint, None)?;
196        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
197
198        Ok(req.send().await?.text().await?)
199    }
200
201    pub async fn get_midpoint(&self, token_id: &str) -> ClientResult<MidpointResponse> {
202        Ok(self
203            .http_client
204            .get(format!("{}/midpoint", &self.host))
205            .query(&[("token_id", token_id)])
206            .send()
207            .await?
208            .json::<MidpointResponse>()
209            .await?)
210    }
211
212    pub async fn get_midpoints(
213        &self,
214        token_ids: &[String],
215    ) -> ClientResult<HashMap<String, Decimal>> {
216        let v = token_ids
217            .iter()
218            .map(|b| HashMap::from([("token_id", b.clone())]))
219            .collect::<Vec<HashMap<&str, String>>>();
220
221        Ok(self
222            .http_client
223            .post(format!("{}/midpoints", &self.host))
224            .json(&v)
225            .send()
226            .await?
227            .json::<HashMap<String, Decimal>>()
228            .await?)
229    }
230
231    pub async fn get_price(&self, token_id: &str, side: Side) -> ClientResult<PriceResponse> {
232        Ok(self
233            .http_client
234            .get(format!("{}/price", &self.host))
235            .query(&[("token_id", token_id)])
236            .query(&[("side", side.as_str())])
237            .send()
238            .await?
239            .json::<PriceResponse>()
240            .await?)
241    }
242    pub async fn get_prices(
243        &self,
244        book_params: &[BookParams],
245    ) -> ClientResult<HashMap<String, HashMap<Side, Decimal>>> {
246        let v = book_params
247            .iter()
248            .map(|b| {
249                HashMap::from([
250                    ("token_id", b.token_id.clone()),
251                    ("side", b.side.as_str().to_owned()),
252                ])
253            })
254            .collect::<Vec<HashMap<&str, String>>>();
255
256        Ok(self
257            .http_client
258            .post(format!("{}/prices", &self.host))
259            .json(&v)
260            .send()
261            .await?
262            .json::<HashMap<String, HashMap<Side, Decimal>>>()
263            .await?)
264    }
265
266    pub async fn get_spread(&self, token_id: &str) -> ClientResult<SpreadResponse> {
267        Ok(self
268            .http_client
269            .get(format!("{}/spread", &self.host))
270            .query(&[("token_id", token_id)])
271            .send()
272            .await?
273            .json::<SpreadResponse>()
274            .await?)
275    }
276
277    pub async fn get_spreads(
278        &self,
279        token_ids: &[String],
280    ) -> ClientResult<HashMap<String, Decimal>> {
281        let v = token_ids
282            .iter()
283            .map(|b| HashMap::from([("token_id", b.clone())]))
284            .collect::<Vec<HashMap<&str, String>>>();
285
286        Ok(self
287            .http_client
288            .post(format!("{}/spreads", &self.host))
289            .json(&v)
290            .send()
291            .await?
292            .json::<HashMap<String, Decimal>>()
293            .await?)
294    }
295
296    // cache
297    pub async fn get_tick_size(&self, token_id: &str) -> ClientResult<Decimal> {
298        Ok(self
299            .http_client
300            .get(format!("{}/tick-size", &self.host))
301            .query(&[("token_id", token_id)])
302            .send()
303            .await?
304            .json::<TickSizeResponse>()
305            .await?
306            .minimum_tick_size)
307    }
308    // Cache
309    pub async fn get_neg_risk(&self, token_id: &str) -> ClientResult<bool> {
310        Ok(self
311            .http_client
312            .get(format!("{}/neg-risk", &self.host))
313            .query(&[("token_id", token_id)])
314            .send()
315            .await?
316            .json::<NegRiskResponse>()
317            .await?
318            .neg_risk)
319    }
320
321    async fn resolve_tick_size(
322        &self,
323        token_id: &str,
324        tick_size: Option<Decimal>,
325    ) -> ClientResult<Decimal> {
326        let min_tick_size = self
327            .get_tick_size(token_id)
328            .await
329            .context("Error fetching tick size")?;
330
331        match tick_size {
332            None => Ok(min_tick_size),
333            Some(t) => {
334                if t < min_tick_size {
335                    Err(anyhow!("Tick size {t} is smaller than min_tick_size {min_tick_size} for token_id: {token_id}"))
336                } else {
337                    Ok(t)
338                }
339            }
340        }
341    }
342
343    async fn get_filled_order_options(
344        &self,
345        token_id: &str,
346        options: Option<&CreateOrderOptions>,
347    ) -> ClientResult<CreateOrderOptions> {
348        let (tick_size, neg_risk) = match options {
349            Some(o) => (o.tick_size, o.neg_risk),
350            None => (None, None),
351        };
352
353        let tick_size = self.resolve_tick_size(token_id, tick_size).await?;
354
355        let neg_risk = match neg_risk {
356            Some(nr) => nr,
357            None => self.get_neg_risk(token_id).await?,
358        };
359
360        Ok(CreateOrderOptions {
361            neg_risk: Some(neg_risk),
362            tick_size: Some(tick_size),
363        })
364    }
365
366    fn is_price_in_range(&self, price: Decimal, tick_size: Decimal) -> bool {
367        let min_price = tick_size;
368        let max_price = Decimal::ONE - tick_size;
369
370        if price < min_price || price > max_price {
371            return false;
372        }
373        true
374    }
375
376    pub async fn create_order(
377        &self,
378        order_args: &OrderArgs,
379        expiration: Option<u64>,
380        extras: Option<ExtraOrderArgs>,
381        options: Option<&CreateOrderOptions>,
382    ) -> ClientResult<SignedOrderRequest> {
383        let (_, chain_id) = self.get_l1_parameters();
384
385        let create_order_options = self
386            .get_filled_order_options(order_args.token_id.as_ref(), options)
387            .await?;
388        let expiration = expiration.unwrap_or(0);
389        let extras = extras.unwrap_or_default();
390
391        if !self.is_price_in_range(
392            order_args.price,
393            create_order_options.tick_size.expect("Should be filled"),
394        ) {
395            return Err(anyhow!("Price is not in range of tick_size"));
396        }
397
398        self.order_builder
399            .as_ref()
400            .expect("OrderBuilder not set")
401            .create_order(
402                chain_id,
403                order_args,
404                expiration,
405                &extras,
406                create_order_options,
407            )
408    }
409
410    pub async fn get_order_book(&self, token_id: &str) -> ClientResult<OrderBookSummary> {
411        Ok(self
412            .http_client
413            .get(format!("{}/book", &self.host))
414            .query(&[("token_id", token_id)])
415            .send()
416            .await?
417            .json::<OrderBookSummary>()
418            .await?)
419    }
420
421    pub async fn get_order_books(
422        &self,
423        token_ids: &[String],
424    ) -> ClientResult<Vec<OrderBookSummary>> {
425        let v = token_ids
426            .iter()
427            .map(|b| HashMap::from([("token_id", b.clone())]))
428            .collect::<Vec<HashMap<&str, String>>>();
429
430        Ok(self
431            .http_client
432            .post(format!("{}/books", &self.host))
433            .json(&v)
434            .send()
435            .await?
436            .json::<Vec<OrderBookSummary>>()
437            .await?)
438    }
439
440    async fn calculate_market_price(
441        &self,
442        token_id: &str,
443        side: Side,
444        amount: Decimal,
445    ) -> ClientResult<Decimal> {
446        let book = self.get_order_book(token_id).await?;
447        let ob = self
448            .order_builder
449            .as_ref()
450            .expect("No orderBuilder set for client!");
451        match side {
452            Side::BUY => ob.calculate_market_price(&book.asks, amount),
453            Side::SELL => ob.calculate_market_price(&book.bids, amount),
454        }
455    }
456
457    pub async fn create_market_order(
458        &self,
459        order_args: &MarketOrderArgs,
460        extras: Option<ExtraOrderArgs>,
461        options: Option<&CreateOrderOptions>,
462    ) -> ClientResult<SignedOrderRequest> {
463        let (_, chain_id) = self.get_l1_parameters();
464
465        let create_order_options = self
466            .get_filled_order_options(order_args.token_id.as_ref(), options)
467            .await?;
468
469        let extras = extras.unwrap_or_default();
470        let price = self
471            .calculate_market_price(&order_args.token_id, Side::BUY, order_args.amount)
472            .await?;
473        if !self.is_price_in_range(
474            price,
475            create_order_options.tick_size.expect("Should be filled"),
476        ) {
477            return Err(anyhow!("Price is not in range of tick_size"));
478        }
479
480        self.order_builder
481            .as_ref()
482            .expect("OrderBuilder not set")
483            .create_market_order(chain_id, order_args, price, &extras, create_order_options)
484    }
485
486    pub async fn post_order(
487        &self,
488        order: SignedOrderRequest,
489        order_type: OrderType,
490    ) -> ClientResult<Value> {
491        let (signer, creds) = self.get_l2_parameters();
492        let body = PostOrder::new(order, creds.api_key.clone(), order_type);
493
494        let method = Method::POST;
495        let endpoint = "/order";
496
497        let headers = create_l2_headers(signer, creds, method.as_str(), endpoint, Some(&body))?;
498
499        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
500
501        Ok(req.json(&body).send().await?.json::<Value>().await?)
502    }
503
504    pub async fn create_and_post_order(&self, order_args: &OrderArgs) -> ClientResult<Value> {
505        let order = self.create_order(order_args, None, None, None).await?;
506        self.post_order(order, OrderType::GTC).await
507    }
508
509    pub async fn cancel(&self, order_id: &str) -> ClientResult<Value> {
510        let (signer, creds) = self.get_l2_parameters();
511        let body = HashMap::from([("orderID", order_id)]);
512
513        let method = Method::DELETE;
514        let endpoint = "/order";
515
516        let headers = create_l2_headers(signer, creds, method.as_str(), endpoint, Some(&body))?;
517
518        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
519
520        Ok(req.json(&body).send().await?.json::<Value>().await?)
521    }
522
523    pub async fn cancel_orders(&self, order_ids: &[String]) -> ClientResult<Value> {
524        let (signer, creds) = self.get_l2_parameters();
525        let method = Method::DELETE;
526        let endpoint = "/orders";
527
528        let headers = create_l2_headers(signer, creds, method.as_str(), endpoint, Some(order_ids))?;
529
530        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
531
532        Ok(req.json(order_ids).send().await?.json::<Value>().await?)
533    }
534
535    pub async fn cancel_all(&self) -> ClientResult<Value> {
536        let (signer, creds) = self.get_l2_parameters();
537        let method = Method::DELETE;
538        let endpoint = "/cancel-all";
539
540        let headers = create_l2_headers::<Value>(signer, creds, method.as_str(), endpoint, None)?;
541
542        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
543
544        Ok(req.send().await?.json::<Value>().await?)
545    }
546
547    pub async fn cancel_market_orders(
548        &self,
549        market: Option<&str>,
550        asset_id: Option<&str>,
551    ) -> ClientResult<Value> {
552        let (signer, creds) = self.get_l2_parameters();
553        let method = Method::DELETE;
554        let endpoint = "/cancel-market-orders";
555        let body = HashMap::from([
556            ("market", market.unwrap_or("")),
557            ("asset_id", asset_id.unwrap_or("")),
558        ]);
559
560        let headers = create_l2_headers(signer, creds, method.as_str(), endpoint, Some(&body))?;
561
562        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
563
564        Ok(req.json(&body).send().await?.json::<Value>().await?)
565    }
566
567    pub async fn get_orders(
568        &self,
569        params: Option<&OpenOrderParams>,
570        next_cursor: Option<&str>,
571    ) -> ClientResult<Vec<OpenOrder>> {
572        let (signer, creds) = self.get_l2_parameters();
573        let method = Method::GET;
574        let endpoint = "/data/orders";
575        let headers = create_l2_headers::<Value>(signer, creds, method.as_str(), endpoint, None)?;
576
577        let query_params = match params {
578            None => Vec::new(),
579            Some(p) => p.to_query_params(),
580        };
581
582        let mut next_cursor = next_cursor.unwrap_or(INITIAL_CURSOR).to_string();
583        let mut output = Vec::new();
584        while next_cursor != END_CURSOR {
585            let req = self
586                .http_client
587                .request(method.clone(), format!("{}{endpoint}", &self.host))
588                .query(&query_params)
589                .query(&["next_cursor", &next_cursor]);
590
591            let r = headers
592                .clone()
593                .into_iter()
594                .fold(req, |r, (k, v)| r.header(HeaderName::from_static(k), v));
595
596            let resp = r.send().await?.json::<Value>().await?;
597            let new_cursor = resp["next_cursor"]
598                .as_str()
599                .expect("Failed to parse next cursor")
600                .to_owned();
601
602            next_cursor = new_cursor;
603
604            let results = resp["data"].clone();
605            let o = serde_json::from_value::<Vec<OpenOrder>>(results)
606                .expect("Failed to parse data from order response");
607            output.extend(o);
608        }
609        Ok(output)
610    }
611
612    pub async fn get_order(&self, order_id: &str) -> ClientResult<OpenOrder> {
613        let (signer, creds) = self.get_l2_parameters();
614        let method = Method::GET;
615        let endpoint = &format!("/data/order/{order_id}");
616
617        let headers = create_l2_headers::<Value>(signer, creds, method.as_str(), endpoint, None)?;
618
619        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
620
621        Ok(req.send().await?.json::<OpenOrder>().await?)
622    }
623
624    pub async fn get_last_trade_price(&self, token_id: &str) -> ClientResult<Value> {
625        Ok(self
626            .http_client
627            .get(format!("{}/last-trade-price", &self.host))
628            .query(&[("token_id", token_id)])
629            .send()
630            .await?
631            .json::<Value>()
632            .await?)
633    }
634
635    pub async fn get_last_trade_prices(&self, token_ids: &[String]) -> ClientResult<Value> {
636        let v = token_ids
637            .iter()
638            .map(|b| HashMap::from([("token_id", b.clone())]))
639            .collect::<Vec<HashMap<&str, String>>>();
640
641        Ok(self
642            .http_client
643            .post(format!("{}/last-trades-prices", &self.host))
644            .json(&v)
645            .send()
646            .await?
647            .json::<Value>()
648            .await?)
649    }
650
651    pub async fn get_trades(
652        &self,
653        trade_params: Option<&TradeParams>,
654        next_cursor: Option<&str>,
655    ) -> ClientResult<Vec<Value>> {
656        let (signer, creds) = self.get_l2_parameters();
657        let method = Method::GET;
658        let endpoint = "/data/trades";
659        let headers = create_l2_headers::<Value>(signer, creds, method.as_str(), endpoint, None)?;
660
661        let query_params = match trade_params {
662            None => Vec::new(),
663            Some(p) => p.to_query_params(),
664        };
665
666        let mut next_cursor = next_cursor.unwrap_or(INITIAL_CURSOR).to_string();
667
668        let mut output = Vec::new();
669        while next_cursor != END_CURSOR {
670            let req = self
671                .http_client
672                .request(method.clone(), format!("{}{endpoint}", &self.host))
673                .query(&query_params)
674                .query(&["next_cursor", &next_cursor]);
675
676            let r = headers
677                .clone()
678                .into_iter()
679                .fold(req, |r, (k, v)| r.header(HeaderName::from_static(k), v));
680
681            let resp = r.send().await?.json::<Value>().await?;
682            let new_cursor = resp["next_cursor"]
683                .as_str()
684                .expect("Failed to parse next cursor")
685                .to_owned();
686
687            next_cursor = new_cursor;
688
689            let results = resp["data"].clone();
690            output.push(results);
691        }
692        Ok(output)
693    }
694
695    pub async fn get_notifications(&self) -> ClientResult<Value> {
696        let (signer, creds) = self.get_l2_parameters();
697
698        let method = Method::GET;
699        let endpoint = "/notifications";
700        let headers = create_l2_headers::<Value>(signer, creds, method.as_str(), endpoint, None)?;
701
702        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
703
704        Ok(req
705            .query(&[(
706                "signature_type",
707                &self
708                    .order_builder
709                    .as_ref()
710                    .expect("Orderbuilder not set")
711                    .get_sig_type(),
712            )])
713            .send()
714            .await?
715            .json::<Value>()
716            .await?)
717    }
718
719    pub async fn drop_notifications(&self, ids: &[String]) -> ClientResult<Value> {
720        let (signer, creds) = self.get_l2_parameters();
721
722        let method = Method::DELETE;
723        let endpoint = "/notifications";
724        let headers = create_l2_headers::<Value>(signer, creds, method.as_str(), endpoint, None)?;
725
726        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
727
728        Ok(req
729            .query(&[("ids", ids.join(","))])
730            .send()
731            .await?
732            .json::<Value>()
733            .await?)
734    }
735
736    pub async fn get_balance_allowance(
737        &self,
738        params: Option<BalanceAllowanceParams>,
739    ) -> ClientResult<Value> {
740        let mut params = params.unwrap_or_default();
741        if params.signature_type.is_none() {
742            params.set_signature_type(
743                self.order_builder
744                    .as_ref()
745                    .expect("Orderbuilder not set")
746                    .get_sig_type(),
747            )
748        }
749
750        let query_params = params.to_query_params();
751
752        let (signer, creds) = self.get_l2_parameters();
753
754        let method = Method::GET;
755        let endpoint = "/balance-allowance";
756        let headers = create_l2_headers::<Value>(signer, creds, method.as_str(), endpoint, None)?;
757
758        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
759        Ok(req
760            .query(&query_params)
761            .send()
762            .await?
763            .json::<Value>()
764            .await?)
765    }
766
767    pub async fn update_balance_allowance(
768        &self,
769        params: Option<BalanceAllowanceParams>,
770    ) -> ClientResult<Value> {
771        let mut params = params.unwrap_or_default();
772        if params.signature_type.is_none() {
773            params.set_signature_type(
774                self.order_builder
775                    .as_ref()
776                    .expect("Orderbuilder not set")
777                    .get_sig_type(),
778            )
779        }
780
781        let query_params = params.to_query_params();
782
783        let (signer, creds) = self.get_l2_parameters();
784
785        let method = Method::GET;
786        let endpoint = "/balance-allowance/update";
787        let headers = create_l2_headers::<Value>(signer, creds, method.as_str(), endpoint, None)?;
788
789        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
790        Ok(req
791            .query(&query_params)
792            .send()
793            .await?
794            .json::<Value>()
795            .await?)
796    }
797
798    pub async fn is_order_scoring(&self, order_id: &str) -> ClientResult<bool> {
799        let (signer, creds) = self.get_l2_parameters();
800
801        let method = Method::GET;
802        let endpoint = "/order-scoring";
803        let headers = create_l2_headers::<Value>(signer, creds, method.as_str(), endpoint, None)?;
804        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
805
806        Ok(req
807            .query(&[("order_id", order_id)])
808            .send()
809            .await?
810            .json::<Value>()
811            .await?["scoring"]
812            .as_bool()
813            .expect("Unknown scoring value"))
814    }
815
816    pub async fn are_orders_scoring(
817        &self,
818        order_ids: &[&str],
819    ) -> ClientResult<HashMap<String, bool>> {
820        let (signer, creds) = self.get_l2_parameters();
821
822        let method = Method::POST;
823        let endpoint = "/orders-scoring";
824
825        let headers = create_l2_headers(signer, creds, method.as_str(), endpoint, Some(order_ids))?;
826        let req = self.create_request_with_headers(method, endpoint, headers.into_iter());
827
828        Ok(req
829            .json(order_ids)
830            .send()
831            .await?
832            .json::<HashMap<String, bool>>()
833            .await?)
834    }
835
836    pub async fn get_sampling_markets(&self, next_cursor: Option<&str>) -> ClientResult<Value> {
837        let next_cursor = next_cursor.unwrap_or(INITIAL_CURSOR);
838
839        Ok(self
840            .http_client
841            .get(format!("{}/sampling-markets", &self.host))
842            .query(&[("next_cursor", next_cursor)])
843            .send()
844            .await?
845            .json::<Value>()
846            .await?)
847    }
848
849    pub async fn get_sampling_simplified_markets(
850        &self,
851        next_cursor: Option<&str>,
852    ) -> ClientResult<Value> {
853        let next_cursor = next_cursor.unwrap_or(INITIAL_CURSOR);
854
855        Ok(self
856            .http_client
857            .get(format!("{}/sampling-simplified-markets", &self.host))
858            .query(&[("next_cursor", next_cursor)])
859            .send()
860            .await?
861            .json::<Value>()
862            .await?)
863    }
864
865    pub async fn get_markets(&self, next_cursor: Option<&str>) -> ClientResult<Value> {
866        let next_cursor = next_cursor.unwrap_or(INITIAL_CURSOR);
867
868        Ok(self
869            .http_client
870            .get(format!("{}/markets", &self.host))
871            .query(&[("next_cursor", next_cursor)])
872            .send()
873            .await?
874            .json::<Value>()
875            .await?)
876    }
877
878    pub async fn get_simplified_markets(&self, next_cursor: Option<&str>) -> ClientResult<Value> {
879        let next_cursor = next_cursor.unwrap_or(INITIAL_CURSOR);
880
881        Ok(self
882            .http_client
883            .get(format!("{}/simplified-markets", &self.host))
884            .query(&[("next_cursor", next_cursor)])
885            .send()
886            .await?
887            .json::<Value>()
888            .await?)
889    }
890
891    pub async fn get_market(&self, condition_id: &str) -> ClientResult<Value> {
892        Ok(self
893            .http_client
894            .get(format!("{}/markets/{condition_id}", &self.host))
895            .send()
896            .await?
897            .json::<Value>()
898            .await?)
899    }
900
901    pub async fn get_market_trades_events(&self, condition_id: &str) -> ClientResult<Value> {
902        Ok(self
903            .http_client
904            .get(format!(
905                "{}/live-activity/events/{condition_id}",
906                &self.host
907            ))
908            .send()
909            .await?
910            .json::<Value>()
911            .await?)
912    }
913}