1use alloy_primitives::{Address, U256};
7use chrono::{DateTime, Utc};
8use rust_decimal::prelude::ToPrimitive;
9use rust_decimal::Decimal;
10use serde::{Deserialize, Serialize};
11
12pub type Price = u32;
43
44pub type Qty = i64;
56
57pub const SCALE_FACTOR: i64 = 10_000;
63
64pub const MAX_PRICE_TICKS: Price = Price::MAX;
67
68pub const MIN_PRICE_TICKS: Price = 1;
70
71pub const MAX_QTY: Qty = Qty::MAX / 2; pub fn decimal_to_price(decimal: Decimal) -> std::result::Result<Price, &'static str> {
93 let scaled = decimal * Decimal::from(SCALE_FACTOR);
95
96 let rounded = scaled.round();
98
99 let as_u64 = rounded.to_u64().ok_or("Price too large or negative")?;
101
102 if as_u64 < MIN_PRICE_TICKS as u64 {
104 return Ok(MIN_PRICE_TICKS); }
106 if as_u64 > MAX_PRICE_TICKS as u64 {
107 return Err("Price exceeds maximum");
108 }
109
110 Ok(as_u64 as Price)
111}
112
113pub fn price_to_decimal(ticks: Price) -> Decimal {
122 Decimal::from(ticks) / Decimal::from(SCALE_FACTOR)
123}
124
125pub fn decimal_to_qty(decimal: Decimal) -> std::result::Result<Qty, &'static str> {
134 let scaled = decimal * Decimal::from(SCALE_FACTOR);
135 let rounded = scaled.round();
136
137 let as_i64 = rounded.to_i64().ok_or("Quantity too large")?;
138
139 if as_i64.abs() > MAX_QTY {
140 return Err("Quantity exceeds maximum");
141 }
142
143 Ok(as_i64)
144}
145
146pub fn qty_to_decimal(units: Qty) -> Decimal {
152 Decimal::from(units) / Decimal::from(SCALE_FACTOR)
153}
154
155pub fn is_price_tick_aligned(decimal: Decimal, tick_size_decimal: Decimal) -> bool {
165 let tick_size_ticks = match decimal_to_price(tick_size_decimal) {
167 Ok(ticks) => ticks,
168 Err(_) => return false,
169 };
170
171 let price_ticks = match decimal_to_price(decimal) {
173 Ok(ticks) => ticks,
174 Err(_) => return false,
175 };
176
177 if tick_size_ticks == 0 {
180 return true;
181 }
182
183 price_ticks % tick_size_ticks == 0
184}
185
186#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
188#[allow(clippy::upper_case_acronyms)]
189pub enum Side {
190 BUY = 0,
191 SELL = 1,
192}
193
194impl Side {
195 pub fn as_str(&self) -> &'static str {
196 match self {
197 Side::BUY => "BUY",
198 Side::SELL => "SELL",
199 }
200 }
201
202 pub fn opposite(&self) -> Self {
203 match self {
204 Side::BUY => Side::SELL,
205 Side::SELL => Side::BUY,
206 }
207 }
208}
209
210#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
212#[allow(clippy::upper_case_acronyms)]
213pub enum OrderType {
214 #[default]
215 GTC,
216 FOK,
217 GTD,
218}
219
220impl OrderType {
221 pub fn as_str(&self) -> &'static str {
222 match self {
223 OrderType::GTC => "GTC",
224 OrderType::FOK => "FOK",
225 OrderType::GTD => "GTD",
226 }
227 }
228}
229
230#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
232pub enum OrderStatus {
233 #[serde(rename = "LIVE")]
234 Live,
235 #[serde(rename = "CANCELLED")]
236 Cancelled,
237 #[serde(rename = "FILLED")]
238 Filled,
239 #[serde(rename = "PARTIAL")]
240 Partial,
241 #[serde(rename = "EXPIRED")]
242 Expired,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
247pub struct MarketSnapshot {
248 pub token_id: String,
249 pub market_id: String,
250 pub timestamp: DateTime<Utc>,
251 pub bid: Option<Decimal>,
252 pub ask: Option<Decimal>,
253 pub mid: Option<Decimal>,
254 pub spread: Option<Decimal>,
255 pub last_price: Option<Decimal>,
256 pub volume_24h: Option<Decimal>,
257}
258
259#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct BookLevel {
265 #[serde(with = "rust_decimal::serde::str")]
266 pub price: Decimal,
267 #[serde(with = "rust_decimal::serde::str")]
268 pub size: Decimal,
269}
270
271#[derive(Debug, Clone, Copy, PartialEq, Eq)]
282pub struct FastBookLevel {
283 pub price: Price, pub size: Qty, }
286
287impl FastBookLevel {
288 pub fn new(price: Price, size: Qty) -> Self {
290 Self { price, size }
291 }
292
293 pub fn to_book_level(self) -> BookLevel {
296 BookLevel {
297 price: price_to_decimal(self.price),
298 size: qty_to_decimal(self.size),
299 }
300 }
301
302 pub fn from_book_level(level: &BookLevel) -> std::result::Result<Self, &'static str> {
305 let price = decimal_to_price(level.price)?;
306 let size = decimal_to_qty(level.size)?;
307 Ok(Self::new(price, size))
308 }
309
310 pub fn notional(self) -> i64 {
317 let price_i64 = self.price as i64;
319 (price_i64 * self.size) / SCALE_FACTOR
321 }
322}
323
324#[derive(Debug, Clone, Serialize, Deserialize)]
326pub struct OrderBook {
327 pub token_id: String,
329 pub timestamp: DateTime<Utc>,
331 pub bids: Vec<BookLevel>,
333 pub asks: Vec<BookLevel>,
335 pub sequence: u64,
337}
338
339#[derive(Debug, Clone, Serialize, Deserialize)]
344pub struct OrderDelta {
345 pub token_id: String,
346 pub timestamp: DateTime<Utc>,
347 pub side: Side,
348 pub price: Decimal,
349 pub size: Decimal, pub sequence: u64,
351}
352
353#[derive(Debug, Clone, Copy, PartialEq, Eq)]
364pub struct FastOrderDelta {
365 pub token_id_hash: u64, pub timestamp: DateTime<Utc>,
367 pub side: Side,
368 pub price: Price, pub size: Qty, pub sequence: u64,
371}
372
373impl FastOrderDelta {
374 pub fn from_order_delta(
380 delta: &OrderDelta,
381 tick_size: Option<Decimal>,
382 ) -> std::result::Result<Self, &'static str> {
383 if let Some(tick_size) = tick_size {
385 if !is_price_tick_aligned(delta.price, tick_size) {
386 return Err("Price not aligned to tick size");
387 }
388 }
389
390 let price = decimal_to_price(delta.price)?;
392 let size = decimal_to_qty(delta.size)?;
393
394 let token_id_hash = {
397 use std::collections::hash_map::DefaultHasher;
398 use std::hash::{Hash, Hasher};
399 let mut hasher = DefaultHasher::new();
400 delta.token_id.hash(&mut hasher);
401 hasher.finish()
402 };
403
404 Ok(Self {
405 token_id_hash,
406 timestamp: delta.timestamp,
407 side: delta.side,
408 price,
409 size,
410 sequence: delta.sequence,
411 })
412 }
413
414 pub fn to_order_delta(self, token_id: String) -> OrderDelta {
417 OrderDelta {
418 token_id,
419 timestamp: self.timestamp,
420 side: self.side,
421 price: price_to_decimal(self.price),
422 size: qty_to_decimal(self.size),
423 sequence: self.sequence,
424 }
425 }
426
427 pub fn is_removal(self) -> bool {
429 self.size == 0
430 }
431}
432
433#[derive(Debug, Clone, Serialize, Deserialize)]
435pub struct FillEvent {
436 pub id: String,
437 pub order_id: String,
438 pub token_id: String,
439 pub side: Side,
440 pub price: Decimal,
441 pub size: Decimal,
442 pub timestamp: DateTime<Utc>,
443 pub maker_address: Address,
444 pub taker_address: Address,
445 pub fee: Decimal,
446}
447
448#[derive(Debug, Clone)]
450pub struct OrderRequest {
451 pub token_id: String,
452 pub side: Side,
453 pub price: Decimal,
454 pub size: Decimal,
455 pub order_type: OrderType,
456 pub expiration: Option<DateTime<Utc>>,
457 pub client_id: Option<String>,
458}
459
460#[derive(Debug, Clone)]
462pub struct MarketOrderRequest {
463 pub token_id: String,
464 pub side: Side,
465 pub amount: Decimal, pub slippage_tolerance: Option<Decimal>,
467 pub client_id: Option<String>,
468}
469
470#[derive(Debug, Clone, Serialize, Deserialize)]
472pub struct Order {
473 pub id: String,
474 pub token_id: String,
475 pub side: Side,
476 pub price: Decimal,
477 pub original_size: Decimal,
478 pub filled_size: Decimal,
479 pub remaining_size: Decimal,
480 pub status: OrderStatus,
481 pub order_type: OrderType,
482 pub created_at: DateTime<Utc>,
483 pub updated_at: DateTime<Utc>,
484 pub expiration: Option<DateTime<Utc>>,
485 pub client_id: Option<String>,
486}
487
488#[derive(Debug, Clone, Serialize, Deserialize, Default)]
490pub struct ApiCredentials {
491 #[serde(rename = "apiKey")]
492 pub api_key: String,
493 pub secret: String,
494 pub passphrase: String,
495}
496
497#[derive(Debug, Clone)]
499pub struct OrderOptions {
500 pub tick_size: Option<Decimal>,
501 pub neg_risk: Option<bool>,
502 pub fee_rate_bps: Option<u32>,
503}
504
505#[derive(Debug, Clone)]
507pub struct ExtraOrderArgs {
508 pub fee_rate_bps: u32,
509 pub nonce: U256,
510 pub taker: String,
511}
512
513impl Default for ExtraOrderArgs {
514 fn default() -> Self {
515 Self {
516 fee_rate_bps: 0,
517 nonce: U256::ZERO,
518 taker: "0x0000000000000000000000000000000000000000".to_string(),
519 }
520 }
521}
522
523#[derive(Debug, Clone)]
525pub struct MarketOrderArgs {
526 pub token_id: String,
527 pub amount: Decimal,
528}
529
530#[derive(Debug, Clone, Serialize, Deserialize)]
532#[serde(rename_all = "camelCase")]
533pub struct SignedOrderRequest {
534 pub salt: u64,
535 pub maker: String,
536 pub signer: String,
537 pub taker: String,
538 pub token_id: String,
539 pub maker_amount: String,
540 pub taker_amount: String,
541 pub expiration: String,
542 pub nonce: String,
543 pub fee_rate_bps: String,
544 pub side: String,
545 pub signature_type: u8,
546 pub signature: String,
547}
548
549#[derive(Debug, Serialize)]
551#[serde(rename_all = "camelCase")]
552pub struct PostOrder {
553 pub order: SignedOrderRequest,
554 pub owner: String,
555 pub order_type: OrderType,
556}
557
558impl PostOrder {
559 pub fn new(order: SignedOrderRequest, owner: String, order_type: OrderType) -> Self {
560 Self {
561 order,
562 owner,
563 order_type,
564 }
565 }
566}
567
568#[derive(Debug, Clone, Serialize, Deserialize)]
570pub struct Market {
571 pub condition_id: String,
572 pub tokens: [Token; 2],
573 pub rewards: Rewards,
574 pub min_incentive_size: Option<String>,
575 pub max_incentive_spread: Option<String>,
576 pub active: bool,
577 pub closed: bool,
578 pub question_id: String,
579 pub minimum_order_size: Decimal,
580 pub minimum_tick_size: Decimal,
581 pub description: String,
582 pub category: Option<String>,
583 pub end_date_iso: Option<String>,
584 pub game_start_time: Option<String>,
585 pub question: String,
586 pub market_slug: String,
587 pub seconds_delay: Decimal,
588 pub icon: String,
589 pub fpmm: String,
590 #[serde(default)]
592 pub enable_order_book: bool,
593 #[serde(default)]
594 pub archived: bool,
595 #[serde(default)]
596 pub accepting_orders: bool,
597 #[serde(default)]
598 pub accepting_order_timestamp: Option<String>,
599 #[serde(default)]
600 pub maker_base_fee: Decimal,
601 #[serde(default)]
602 pub taker_base_fee: Decimal,
603 #[serde(default)]
604 pub notifications_enabled: bool,
605 #[serde(default)]
606 pub neg_risk: bool,
607 #[serde(default)]
608 pub neg_risk_market_id: String,
609 #[serde(default)]
610 pub neg_risk_request_id: String,
611 #[serde(default)]
612 pub image: String,
613 #[serde(default)]
614 pub is_50_50_outcome: bool,
615}
616
617#[derive(Debug, Clone, Serialize, Deserialize)]
619pub struct Token {
620 pub token_id: String,
621 pub outcome: String,
622 pub price: Decimal,
623 #[serde(default)]
624 pub winner: bool,
625}
626
627#[derive(Debug, Clone, Serialize, Deserialize)]
629pub struct ClientConfig {
630 pub base_url: String,
632 pub chain_id: u64,
634 pub private_key: Option<String>,
636 pub api_credentials: Option<ApiCredentials>,
638 pub max_slippage: Option<Decimal>,
640 pub fee_rate: Option<Decimal>,
642 pub timeout: Option<std::time::Duration>,
644 pub max_connections: Option<usize>,
646}
647
648impl Default for ClientConfig {
649 fn default() -> Self {
650 Self {
651 base_url: "https://clob.polymarket.com".to_string(),
652 chain_id: 137, private_key: None,
654 api_credentials: None,
655 timeout: Some(std::time::Duration::from_secs(30)),
656 max_connections: Some(100),
657 max_slippage: None,
658 fee_rate: None,
659 }
660 }
661}
662
663pub type WssAuth = ApiCredentials;
668
669#[derive(Debug, Clone, Serialize, Deserialize)]
671pub struct WssSubscription {
672 #[serde(rename = "type")]
674 pub channel_type: String,
675 #[serde(skip_serializing_if = "Option::is_none")]
677 pub operation: Option<String>,
678 #[serde(default)]
680 pub markets: Vec<String>,
681 #[serde(rename = "assets_ids", default)]
684 pub asset_ids: Vec<String>,
685 #[serde(skip_serializing_if = "Option::is_none")]
687 pub initial_dump: Option<bool>,
688 #[serde(skip_serializing_if = "Option::is_none")]
690 pub custom_feature_enabled: Option<bool>,
691 #[serde(skip_serializing_if = "Option::is_none")]
693 pub auth: Option<WssAuth>,
694}
695
696#[derive(Debug, Clone, Serialize, Deserialize)]
698#[serde(tag = "event_type")]
699pub enum StreamMessage {
700 #[serde(rename = "book")]
702 Book(BookUpdate),
703 #[serde(rename = "price_change")]
705 PriceChange(PriceChange),
706 #[serde(rename = "tick_size_change")]
708 TickSizeChange(TickSizeChange),
709 #[serde(rename = "last_trade_price")]
711 LastTradePrice(LastTradePrice),
712 #[serde(rename = "best_bid_ask")]
714 BestBidAsk(BestBidAsk),
715 #[serde(rename = "new_market")]
717 NewMarket(NewMarket),
718 #[serde(rename = "market_resolved")]
720 MarketResolved(MarketResolved),
721 #[serde(rename = "trade")]
723 Trade(TradeMessage),
724 #[serde(rename = "order")]
726 Order(OrderMessage),
727 #[serde(other)]
729 Unknown,
730}
731
732#[derive(Debug, Clone, Serialize, Deserialize)]
734pub struct BookUpdate {
735 pub asset_id: String,
736 pub market: String,
737 #[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
738 pub timestamp: u64,
739 #[serde(
740 default,
741 deserialize_with = "crate::decode::deserializers::vec_from_null"
742 )]
743 pub bids: Vec<OrderSummary>,
744 #[serde(
745 default,
746 deserialize_with = "crate::decode::deserializers::vec_from_null"
747 )]
748 pub asks: Vec<OrderSummary>,
749 #[serde(default)]
750 pub hash: Option<String>,
751}
752
753#[derive(Debug, Clone, Serialize, Deserialize)]
755pub struct PriceChange {
756 pub market: String,
757 #[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
758 pub timestamp: u64,
759 #[serde(
760 default,
761 deserialize_with = "crate::decode::deserializers::vec_from_null"
762 )]
763 pub price_changes: Vec<PriceChangeEntry>,
764}
765
766#[derive(Debug, Clone, Serialize, Deserialize)]
767pub struct PriceChangeEntry {
768 pub asset_id: String,
769 pub price: Decimal,
770 #[serde(
771 default,
772 deserialize_with = "crate::decode::deserializers::optional_decimal_from_string"
773 )]
774 pub size: Option<Decimal>,
775 pub side: Side,
776 #[serde(default)]
777 pub hash: Option<String>,
778 #[serde(
779 default,
780 deserialize_with = "crate::decode::deserializers::optional_decimal_from_string"
781 )]
782 pub best_bid: Option<Decimal>,
783 #[serde(
784 default,
785 deserialize_with = "crate::decode::deserializers::optional_decimal_from_string"
786 )]
787 pub best_ask: Option<Decimal>,
788}
789
790#[derive(Debug, Clone, Serialize, Deserialize)]
792pub struct TickSizeChange {
793 pub asset_id: String,
794 pub market: String,
795 pub old_tick_size: Decimal,
796 pub new_tick_size: Decimal,
797 #[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
798 pub timestamp: u64,
799}
800
801#[derive(Debug, Clone, Serialize, Deserialize)]
803pub struct LastTradePrice {
804 pub asset_id: String,
805 pub market: String,
806 pub price: Decimal,
807 #[serde(default)]
808 pub side: Option<Side>,
809 #[serde(
810 default,
811 deserialize_with = "crate::decode::deserializers::optional_decimal_from_string"
812 )]
813 pub size: Option<Decimal>,
814 #[serde(
815 default,
816 deserialize_with = "crate::decode::deserializers::optional_decimal_from_string"
817 )]
818 pub fee_rate_bps: Option<Decimal>,
819 #[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
820 pub timestamp: u64,
821}
822
823#[derive(Debug, Clone, Serialize, Deserialize)]
825pub struct BestBidAsk {
826 pub market: String,
827 pub asset_id: String,
828 pub best_bid: Decimal,
829 pub best_ask: Decimal,
830 pub spread: Decimal,
831 #[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
832 pub timestamp: u64,
833}
834
835#[derive(Debug, Clone, Serialize, Deserialize)]
837pub struct NewMarket {
838 pub id: String,
839 pub question: String,
840 pub market: String,
841 pub slug: String,
842 pub description: String,
843 #[serde(rename = "assets_ids", alias = "asset_ids")]
844 pub asset_ids: Vec<String>,
845 #[serde(
846 default,
847 deserialize_with = "crate::decode::deserializers::vec_from_null"
848 )]
849 pub outcomes: Vec<String>,
850 #[serde(default)]
851 pub event_message: Option<EventMessage>,
852 #[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
853 pub timestamp: u64,
854}
855
856#[derive(Debug, Clone, Serialize, Deserialize)]
858pub struct MarketResolved {
859 pub id: String,
860 #[serde(default)]
861 pub question: Option<String>,
862 pub market: String,
863 #[serde(default)]
864 pub slug: Option<String>,
865 #[serde(default)]
866 pub description: Option<String>,
867 #[serde(rename = "assets_ids", alias = "asset_ids")]
868 pub asset_ids: Vec<String>,
869 #[serde(
870 default,
871 deserialize_with = "crate::decode::deserializers::vec_from_null"
872 )]
873 pub outcomes: Vec<String>,
874 pub winning_asset_id: String,
875 pub winning_outcome: String,
876 #[serde(default)]
877 pub event_message: Option<EventMessage>,
878 #[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
879 pub timestamp: u64,
880}
881
882#[derive(Debug, Clone, Serialize, Deserialize)]
884pub struct EventMessage {
885 pub id: String,
886 pub ticker: String,
887 pub slug: String,
888 pub title: String,
889 pub description: String,
890}
891
892#[derive(Debug, Clone, Serialize, Deserialize)]
894pub struct TradeMessage {
895 pub id: String,
896 pub market: String,
897 pub asset_id: String,
898 pub side: Side,
899 pub size: Decimal,
900 pub price: Decimal,
901 #[serde(default)]
902 pub status: Option<String>,
903 #[serde(rename = "type", default)]
904 pub msg_type: Option<String>,
905 #[serde(
906 default,
907 deserialize_with = "crate::decode::deserializers::optional_number_from_string"
908 )]
909 pub last_update: Option<u64>,
910 #[serde(
911 default,
912 alias = "match_time",
913 deserialize_with = "crate::decode::deserializers::optional_number_from_string"
914 )]
915 pub matchtime: Option<u64>,
916 #[serde(
917 default,
918 deserialize_with = "crate::decode::deserializers::optional_number_from_string"
919 )]
920 pub timestamp: Option<u64>,
921}
922
923#[derive(Debug, Clone, Serialize, Deserialize)]
925pub struct OrderMessage {
926 pub id: String,
927 pub market: String,
928 pub asset_id: String,
929 pub side: Side,
930 pub price: Decimal,
931 #[serde(rename = "type", default)]
932 pub msg_type: Option<String>,
933 #[serde(
934 default,
935 deserialize_with = "crate::decode::deserializers::optional_decimal_from_string"
936 )]
937 pub original_size: Option<Decimal>,
938 #[serde(
939 default,
940 deserialize_with = "crate::decode::deserializers::optional_decimal_from_string"
941 )]
942 pub size_matched: Option<Decimal>,
943 #[serde(
944 default,
945 deserialize_with = "crate::decode::deserializers::optional_number_from_string"
946 )]
947 pub timestamp: Option<u64>,
948 #[serde(default)]
949 pub associate_trades: Option<Vec<String>>,
950 #[serde(default)]
951 pub status: Option<String>,
952}
953
954#[derive(Debug, Clone, Serialize, Deserialize)]
956pub struct Subscription {
957 pub token_ids: Vec<String>,
958 pub channels: Vec<String>,
959}
960
961#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
963pub enum WssChannelType {
964 #[serde(rename = "USER")]
965 User,
966 #[serde(rename = "MARKET")]
967 Market,
968}
969
970impl WssChannelType {
971 pub fn as_str(&self) -> &'static str {
972 match self {
973 WssChannelType::User => "USER",
974 WssChannelType::Market => "MARKET",
975 }
976 }
977}
978
979#[derive(Debug, Clone, Serialize, Deserialize)]
981pub struct Quote {
982 pub token_id: String,
983 pub side: Side,
984 #[serde(with = "rust_decimal::serde::str")]
985 pub price: Decimal,
986 pub timestamp: DateTime<Utc>,
987}
988
989#[derive(Debug, Clone, Serialize, Deserialize)]
991pub struct Balance {
992 pub token_id: String,
993 pub available: Decimal,
994 pub locked: Decimal,
995 pub total: Decimal,
996}
997
998#[derive(Debug, Clone)]
1000pub struct Metrics {
1001 pub orders_per_second: f64,
1002 pub avg_latency_ms: f64,
1003 pub error_rate: f64,
1004 pub uptime_pct: f64,
1005}
1006
1007pub type TokenId = String;
1009pub type OrderId = String;
1010pub type MarketId = String;
1011pub type ClientId = String;
1012
1013#[derive(Debug, Clone)]
1015pub struct OpenOrderParams {
1016 pub id: Option<String>,
1017 pub asset_id: Option<String>,
1018 pub market: Option<String>,
1019}
1020
1021impl OpenOrderParams {
1022 pub fn to_query_params(&self) -> Vec<(&str, &String)> {
1023 let mut params = Vec::with_capacity(3);
1024
1025 if let Some(x) = &self.id {
1026 params.push(("id", x));
1027 }
1028
1029 if let Some(x) = &self.asset_id {
1030 params.push(("asset_id", x));
1031 }
1032
1033 if let Some(x) = &self.market {
1034 params.push(("market", x));
1035 }
1036 params
1037 }
1038}
1039
1040#[derive(Debug, Clone)]
1042pub struct TradeParams {
1043 pub id: Option<String>,
1044 pub maker_address: Option<String>,
1045 pub market: Option<String>,
1046 pub asset_id: Option<String>,
1047 pub before: Option<u64>,
1048 pub after: Option<u64>,
1049}
1050
1051impl TradeParams {
1052 pub fn to_query_params(&self) -> Vec<(&str, String)> {
1053 let mut params = Vec::with_capacity(6);
1054
1055 if let Some(x) = &self.id {
1056 params.push(("id", x.clone()));
1057 }
1058
1059 if let Some(x) = &self.asset_id {
1060 params.push(("asset_id", x.clone()));
1061 }
1062
1063 if let Some(x) = &self.market {
1064 params.push(("market", x.clone()));
1065 }
1066
1067 if let Some(x) = &self.maker_address {
1068 params.push(("maker_address", x.clone()));
1069 }
1070
1071 if let Some(x) = &self.before {
1072 params.push(("before", x.to_string()));
1073 }
1074
1075 if let Some(x) = &self.after {
1076 params.push(("after", x.to_string()));
1077 }
1078
1079 params
1080 }
1081}
1082
1083#[derive(Debug, Clone, Serialize, Deserialize)]
1085pub struct OpenOrder {
1086 pub associate_trades: Vec<String>,
1087 pub id: String,
1088 pub status: String,
1089 pub market: String,
1090 #[serde(with = "rust_decimal::serde::str")]
1091 pub original_size: Decimal,
1092 pub outcome: String,
1093 pub maker_address: String,
1094 pub owner: String,
1095 #[serde(with = "rust_decimal::serde::str")]
1096 pub price: Decimal,
1097 pub side: Side,
1098 #[serde(with = "rust_decimal::serde::str")]
1099 pub size_matched: Decimal,
1100 pub asset_id: String,
1101 #[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
1102 pub expiration: u64,
1103 #[serde(rename = "type", alias = "order_type", alias = "orderType", default)]
1104 pub order_type: OrderType,
1105 #[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
1106 pub created_at: u64,
1107}
1108
1109#[derive(Debug, Clone, Serialize, Deserialize)]
1111pub struct BalanceAllowance {
1112 pub asset_id: String,
1113 #[serde(with = "rust_decimal::serde::str")]
1114 pub balance: Decimal,
1115 #[serde(with = "rust_decimal::serde::str")]
1116 pub allowance: Decimal,
1117}
1118
1119#[derive(Default)]
1121pub struct BalanceAllowanceParams {
1122 pub asset_type: Option<AssetType>,
1123 pub token_id: Option<String>,
1124 pub signature_type: Option<u8>,
1125}
1126
1127impl BalanceAllowanceParams {
1128 pub fn to_query_params(&self) -> Vec<(&str, String)> {
1129 let mut params = Vec::with_capacity(3);
1130
1131 if let Some(x) = &self.asset_type {
1132 params.push(("asset_type", x.to_string()));
1133 }
1134
1135 if let Some(x) = &self.token_id {
1136 params.push(("token_id", x.to_string()));
1137 }
1138
1139 if let Some(x) = &self.signature_type {
1140 params.push(("signature_type", x.to_string()));
1141 }
1142 params
1143 }
1144
1145 pub fn set_signature_type(&mut self, s: u8) {
1146 self.signature_type = Some(s);
1147 }
1148}
1149
1150#[allow(clippy::upper_case_acronyms)]
1152pub enum AssetType {
1153 COLLATERAL,
1154 CONDITIONAL,
1155}
1156
1157impl std::fmt::Display for AssetType {
1158 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1159 match self {
1160 AssetType::COLLATERAL => write!(f, "COLLATERAL"),
1161 AssetType::CONDITIONAL => write!(f, "CONDITIONAL"),
1162 }
1163 }
1164}
1165
1166#[derive(Debug, Clone, Serialize, Deserialize)]
1168pub struct NotificationParams {
1169 pub signature: String,
1170 pub timestamp: u64,
1171}
1172
1173#[derive(Debug, Clone, Serialize, Deserialize)]
1175pub struct BatchMidpointRequest {
1176 pub token_ids: Vec<String>,
1177}
1178
1179#[derive(Debug, Clone, Serialize, Deserialize)]
1181pub struct BatchMidpointResponse {
1182 pub midpoints: std::collections::HashMap<String, Option<Decimal>>,
1183}
1184
1185#[derive(Debug, Clone, Serialize, Deserialize)]
1187pub struct BatchPriceRequest {
1188 pub token_ids: Vec<String>,
1189}
1190
1191#[derive(Debug, Clone, Serialize, Deserialize)]
1193pub struct TokenPrice {
1194 pub token_id: String,
1195 #[serde(skip_serializing_if = "Option::is_none")]
1196 pub bid: Option<Decimal>,
1197 #[serde(skip_serializing_if = "Option::is_none")]
1198 pub ask: Option<Decimal>,
1199 #[serde(skip_serializing_if = "Option::is_none")]
1200 pub mid: Option<Decimal>,
1201}
1202
1203#[derive(Debug, Clone, Serialize, Deserialize)]
1205pub struct BatchPriceResponse {
1206 pub prices: Vec<TokenPrice>,
1207}
1208
1209#[derive(Debug, Deserialize)]
1211pub struct ApiKeysResponse {
1212 #[serde(rename = "apiKeys")]
1213 pub api_keys: Vec<String>,
1214}
1215
1216#[derive(Debug, Deserialize)]
1217pub struct MidpointResponse {
1218 #[serde(with = "rust_decimal::serde::str")]
1219 pub mid: Decimal,
1220}
1221
1222#[derive(Debug, Deserialize)]
1223pub struct PriceResponse {
1224 #[serde(with = "rust_decimal::serde::str")]
1225 pub price: Decimal,
1226}
1227
1228#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1237pub enum PricesHistoryInterval {
1238 OneMinute,
1239 OneHour,
1240 SixHours,
1241 OneDay,
1242 OneWeek,
1243}
1244
1245impl PricesHistoryInterval {
1246 pub const fn as_str(self) -> &'static str {
1247 match self {
1248 Self::OneMinute => "1m",
1249 Self::OneHour => "1h",
1250 Self::SixHours => "6h",
1251 Self::OneDay => "1d",
1252 Self::OneWeek => "1w",
1253 }
1254 }
1255}
1256
1257#[derive(Debug, Clone, Serialize, Deserialize)]
1262pub struct PricesHistoryResponse {
1263 pub history: Vec<serde_json::Value>,
1264}
1265
1266#[derive(Debug, Deserialize)]
1267pub struct SpreadResponse {
1268 #[serde(with = "rust_decimal::serde::str")]
1269 pub spread: Decimal,
1270}
1271
1272#[derive(Debug, Deserialize)]
1273pub struct TickSizeResponse {
1274 #[serde(with = "rust_decimal::serde::str")]
1275 pub minimum_tick_size: Decimal,
1276}
1277
1278#[derive(Debug, Deserialize)]
1279pub struct NegRiskResponse {
1280 pub neg_risk: bool,
1281}
1282
1283#[derive(Debug, Serialize, Deserialize)]
1284pub struct BookParams {
1285 pub token_id: String,
1286 pub side: Side,
1287}
1288
1289#[derive(Debug, Deserialize)]
1290pub struct OrderBookSummary {
1291 pub market: String,
1292 pub asset_id: String,
1293 #[serde(default)]
1294 pub hash: Option<String>,
1295 #[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
1296 pub timestamp: u64,
1297 #[serde(
1298 default,
1299 deserialize_with = "crate::decode::deserializers::vec_from_null"
1300 )]
1301 pub bids: Vec<OrderSummary>,
1302 #[serde(
1303 default,
1304 deserialize_with = "crate::decode::deserializers::vec_from_null"
1305 )]
1306 pub asks: Vec<OrderSummary>,
1307 pub min_order_size: Decimal,
1308 pub neg_risk: bool,
1309 pub tick_size: Decimal,
1310 #[serde(
1311 default,
1312 deserialize_with = "crate::decode::deserializers::optional_decimal_from_string_default_on_error"
1313 )]
1314 pub last_trade_price: Option<Decimal>,
1315}
1316
1317#[derive(Debug, Clone, Serialize, Deserialize)]
1318pub struct OrderSummary {
1319 #[serde(with = "rust_decimal::serde::str")]
1320 pub price: Decimal,
1321 #[serde(with = "rust_decimal::serde::str")]
1322 pub size: Decimal,
1323}
1324
1325#[derive(Debug, Serialize, Deserialize)]
1326pub struct MarketsResponse {
1327 pub limit: usize,
1328 pub count: usize,
1329 pub next_cursor: Option<String>,
1330 pub data: Vec<Market>,
1331}
1332
1333#[derive(Debug, Serialize, Deserialize)]
1334pub struct SimplifiedMarketsResponse {
1335 pub limit: usize,
1336 pub count: usize,
1337 pub next_cursor: Option<String>,
1338 pub data: Vec<SimplifiedMarket>,
1339}
1340
1341#[derive(Debug, Serialize, Deserialize)]
1343pub struct SimplifiedMarket {
1344 pub condition_id: String,
1345 pub tokens: [Token; 2],
1346 pub rewards: Rewards,
1347 pub min_incentive_size: Option<String>,
1348 pub max_incentive_spread: Option<String>,
1349 pub active: bool,
1350 pub closed: bool,
1351}
1352
1353#[derive(Debug, Clone, Serialize, Deserialize)]
1355pub struct Rewards {
1356 pub rates: Option<serde_json::Value>,
1357 pub min_size: Decimal,
1359 pub max_spread: Decimal,
1360 #[serde(default)]
1361 pub event_start_date: Option<String>,
1362 #[serde(default)]
1363 pub event_end_date: Option<String>,
1364 #[serde(skip_serializing_if = "Option::is_none", default)]
1365 pub in_game_multiplier: Option<Decimal>,
1366 #[serde(skip_serializing_if = "Option::is_none", default)]
1367 pub reward_epoch: Option<Decimal>,
1368}
1369
1370pub type ClientResult<T> = anyhow::Result<T>;
1372
1373pub type Result<T> = std::result::Result<T, crate::errors::PolyfillError>;
1375
1376pub type ApiCreds = ApiCredentials;
1378pub type CreateOrderOptions = OrderOptions;
1379pub type OrderArgs = OrderRequest;