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(¶ms, 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};