polymarket-bindings 0.1.1

API bindings and normalized models for the Polymarket Rust SDK
Documentation
use polymarket_types::{CtfConditionId, DecimalString, TokenId};
use serde::Deserialize;

use crate::de::deserialize_decimalish;

#[derive(Clone, Debug, PartialEq, Deserialize)]
pub struct OrderBookLevel {
    #[serde(deserialize_with = "deserialize_decimalish")]
    pub price: Option<String>,
    #[serde(deserialize_with = "deserialize_decimalish")]
    pub size: Option<String>,
}

#[derive(Clone, Debug, PartialEq)]
pub struct OrderBook {
    pub market: CtfConditionId,
    pub token_id: TokenId,
    pub timestamp: Option<i64>,
    pub bids: Vec<OrderBookLevel>,
    pub asks: Vec<OrderBookLevel>,
    pub min_order_size: DecimalString,
    pub tick_size: DecimalString,
    pub neg_risk: bool,
    pub last_trade_price: Option<DecimalString>,
    pub hash: String,
}

#[derive(Debug, Deserialize)]
struct OrderBookRaw {
    market: String,
    asset_id: String,
    timestamp: Option<String>,
    bids: Vec<OrderBookLevel>,
    asks: Vec<OrderBookLevel>,
    #[serde(rename = "min_order_size", deserialize_with = "deserialize_decimalish")]
    min_order_size: Option<String>,
    #[serde(rename = "tick_size", deserialize_with = "deserialize_decimalish")]
    tick_size: Option<String>,
    neg_risk: bool,
    #[serde(
        rename = "last_trade_price",
        default,
        deserialize_with = "deserialize_decimalish"
    )]
    last_trade_price: Option<String>,
    hash: String,
}

impl OrderBook {
    fn from_raw(raw: OrderBookRaw) -> Result<Self, String> {
        let market = CtfConditionId::parse(raw.market).map_err(|e| e.message)?;
        let token_id = TokenId::parse(raw.asset_id).map_err(|e| e.message)?;
        let timestamp = raw.timestamp.and_then(|t| t.parse().ok());
        let min_order_size = raw
            .min_order_size
            .and_then(|v| DecimalString::parse(v).ok())
            .ok_or_else(|| "missing min_order_size".to_string())?;
        let tick_size = raw
            .tick_size
            .and_then(|v| DecimalString::parse(v).ok())
            .ok_or_else(|| "missing tick_size".to_string())?;
        let last_trade_price = raw
            .last_trade_price
            .and_then(|v| DecimalString::parse(v).ok());

        Ok(Self {
            market,
            token_id,
            timestamp,
            bids: raw.bids,
            asks: raw.asks,
            min_order_size,
            tick_size,
            neg_risk: raw.neg_risk,
            last_trade_price,
            hash: raw.hash,
        })
    }
}

impl<'de> Deserialize<'de> for OrderBook {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let raw = OrderBookRaw::deserialize(deserializer)?;
        Self::from_raw(raw).map_err(serde::de::Error::custom)
    }
}