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
16mod 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 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 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 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}