Skip to main content

polyoxide_clob/
lib.rs

1//! # polyoxide-clob
2//!
3//! Rust client library for Polymarket CLOB (Centralized Limit Order Book) API.
4//!
5//! ## Features
6//!
7//! - Order creation, signing, and posting with EIP-712
8//! - Market data and order book retrieval
9//! - Account balance and trade history
10//! - HMAC-based L2 authentication
11//! - Type-safe API with idiomatic Rust patterns
12//!
13//! ## Example
14//!
15//! ```no_run
16//! use polyoxide_clob::{Account, Chain, ClobBuilder, CreateOrderParams, OrderKind, OrderSide};
17//!
18//! #[tokio::main]
19//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
20//!     // Load account from environment variables
21//!     let account = Account::from_env()?;
22//!
23//!     // Create CLOB client
24//!     let clob = ClobBuilder::new()
25//!         .with_account(account)
26//!         .chain(Chain::PolygonMainnet)
27//!         .build()?;
28//!
29//!     // Place an order
30//!     let params = CreateOrderParams {
31//!         token_id: "token_id".to_string(),
32//!         price: 0.52,
33//!         size: 100.0,
34//!         side: OrderSide::Buy,
35//!         order_type: OrderKind::Gtc,
36//!         post_only: false,
37//!         expiration: None,
38//!         funder: None,
39//!         signature_type: None,
40//!     };
41//!
42//!     let response = clob.place_order(&params, None).await?;
43//!     println!("Order ID: {:?}", response.order_id);
44//!
45//!     Ok(())
46//! }
47//! ```
48//!
49//! ## Order outcomes and retries
50//!
51//! Polymarket returns HTTP 400 both for genuine faults (malformed payload, banned
52//! address, tick-size violation) and for the *defined* kill outcomes of marketable
53//! orders — a FAK that matched nothing, a FOK that could not fill in full. Those two
54//! are not failures, so they get their own variants rather than collapsing into a
55//! generic validation error:
56//!
57//! - [`ClobError::FakUnmatched`] — nothing on the book matched a Fill-And-Kill order
58//! - [`ClobError::FokUnfilled`] — a Fill-Or-Kill order could not be filled entirely
59//!
60//! Both are deterministic: resubmitting the identical order cannot change the answer.
61//! [`ClobError::is_retriable`] reports that, and is the intended input to a caller's
62//! retry policy — so retriability never has to be re-derived from status codes or
63//! from the venue's prose, which changes without notice.
64//!
65//! ```
66//! use polyoxide_clob::ClobError;
67//!
68//! fn handle(err: ClobError) {
69//!     match err {
70//!         // Normal outcomes of a marketable order — report, don't retry, don't alert.
71//!         ClobError::FakUnmatched { .. } | ClobError::FokUnfilled { .. } => {}
72//!         // Rate limits, timeouts, connection failures, 425, and 5xx.
73//!         e if e.is_retriable() => {}
74//!         // Deterministic faults: auth, validation, signing.
75//!         _ => {}
76//!     }
77//! }
78//! ```
79//!
80//! This crate's own retry loop only ever retries `429`, so a killed order has never
81//! been resent by the SDK itself.
82
83/// Doctest-only anchor that compiles every fenced `rust` example in the crate
84/// README, so broken examples fail CI. Exists only under `cfg(doctest)`, so it
85/// never appears in `cargo doc` output or normal builds.
86#[cfg(doctest)]
87#[doc = include_str!("../README.md")]
88struct ReadmeDoctests;
89
90pub mod account;
91pub mod api;
92pub mod client;
93pub mod core;
94pub mod error;
95pub mod request;
96pub mod types;
97pub mod utils;
98
99#[cfg(feature = "ws")]
100pub mod ws;
101
102pub use core::chain::{Chain, Contracts};
103
104pub use account::{Account, AccountConfig, Credentials, Signer, Wallet};
105
106#[cfg(feature = "keychain")]
107pub use account::{save_private_key_to_keychain, KEYCHAIN_SERVICE};
108pub use api::{
109    account::{
110        BalanceAllowanceResponse, BuilderTrade, ListBuilderTrades, ListBuilderTradesResponse,
111        ListClobTrades, ListTradesResponse, MakerOrder, Trade,
112    },
113    auth::{
114        ApiKeyInfo, ApiKeyResponse, BuilderApiKeyResponse, ClosedOnlyResponse,
115        ReadonlyApiKeyResponse, ValidateKeyResponse,
116    },
117    health::{Health, ServerTimeResponse},
118    markets::{
119        BatchPricesHistoryRequest, BatchPricesHistoryResponse, BookParams, CalculatePriceResponse,
120        ClobMarketDetails, ClobRewards, ClobToken, FeeDetails, LastTradePriceResponse,
121        ListClobMarkets, ListMarketsResponse, LiveActivityMarket, Market, MarketByTokenResponse,
122        MarketPrice, MarketToken, MidpointResponse, OrderBook, OrderLevel, PriceHistoryPoint,
123        PriceResponse, PricesHistoryQuery, PricesHistoryResponse, SpreadResponse,
124    },
125    notifications::Notification,
126    orders::{
127        BatchCancelResponse, ListOrders, ListOrdersResponse, OpenOrder, OrderResponse,
128        OrderScoringResponse,
129    },
130    rewards::{
131        ListMultiRewardMarkets, ListRewardMarkets, ListUserRewardMarkets, MultiMarketOrderBy,
132        Paginated, PublicRewards, RebatedFees, RewardEarnings, RewardMarket, RewardMarketEarning,
133        RewardMarketRequest, RewardPercentages, RewardTotalEarnings, SortPosition,
134        UserEarningsRequest, UserPercentagesRequest, UserRewardMarketOrderBy,
135        UserTotalEarningsRequest,
136    },
137};
138pub use client::{Clob, ClobBuilder, CreateOrderParams, SignedOrderPayload};
139pub use error::ClobError;
140pub use types::{
141    Order, OrderKind, OrderSide, ParseTickSizeError, PartialCreateOrderOptions, SignatureType,
142    SignedOrder, TickSize,
143};