clob-client-rust
===============
Rust client for Polymarket CLOB (ported from the official TypeScript `clob-client`).
This crate focuses on:
- Order building + EIP-712 signing parity
- Typed endpoint calls
- TS v5.1.0 parity additions: Readonly API Key + RFQ client + HTTP PUT + optional geo token
Important behavior note:
- Tick size is **not** auto-resolved from the backend. If you need a market-specific tick, fetch it externally and pass it in. Otherwise the SDK uses the fallback tick `"0.01"`.
## Install
```toml
[dependencies]
clob-client-rust = "0.1"
```
## Auth models (TS parity)
### 1) L2 auth (signer + API key creds)
Used for trading flows (create/post/cancel) and authenticated reads.
```rust
use clob_client_rust::client::ClobClient;
use clob_client_rust::signer_adapter::EthersSigner;
use clob_client_rust::types::ApiKeyCreds;
use std::sync::Arc;
let signer = Arc::new(EthersSigner::new_from_private_key(&pk)?);
let creds = ApiKeyCreds { key, secret, passphrase };
let mut client = ClobClient::new(&host, chain_id, Some(signer), Some(creds), true);
```
### 2) Readonly API key headers (TS parity)
Important TS parity note:
- TypeScript `client.getOpenOrders()` still uses **L2 auth** (HMAC headers).
- The readonly key is used only in the standalone TS example `getOpenOrdersWithReadonlyKey.ts`, by manually calling `GET /data/orders` with extra headers.
Rust parity example (same as TS example, via `http_helpers`):
```rust
use clob_client_rust::endpoints::GET_OPEN_ORDERS;
use clob_client_rust::http_helpers::{RequestOptions, get};
use clob_client_rust::types::SignedOrder;
use std::collections::HashMap;
let endpoint = format!("{}{}", host.trim_end_matches('/'), GET_OPEN_ORDERS);
let mut headers = HashMap::new();
headers.insert("POLY_READONLY_API_KEY".to_string(), readonly_key);
headers.insert("POLY_ADDRESS".to_string(), address.clone());
let mut params = HashMap::new();
params.insert("maker_address".to_string(), address);
let opts = RequestOptions { headers: Some(headers), data: None, params: Some(params) };
let val = get(&endpoint, Some(opts)).await?;
let arr = if val.is_array() { val } else { val["data"].clone() };
let orders: Vec<SignedOrder> = serde_json::from_value(arr)?;
```
## Geo block token
TypeScript injects `geo_block_token` into every request automatically. In Rust it is **optional**:
```rust
let client = client.with_geo_block_token(token);
```
When set, the SDK injects `geo_block_token` into query parameters for supported calls.
## RFQ client (TS v5.1.0)
RFQ is exposed as a sub-client similar to TS: `client.rfq()`.
```rust
use clob_client_rust::types::GetRfqQuotesParams;
let quotes = client
.rfq()
.get_rfq_quotes(Some(GetRfqQuotesParams { limit: Some(10), ..Default::default() }))
.await?;
```
Accept/approve will:
1) fetch the quote
2) build a signed order via `client.create_order(...)`
3) post the action payload to the RFQ endpoint
Tick size behavior stays explicit (fallback is `"0.01"`).
## Readonly API key management
The SDK exposes the endpoints added in TS v5.1.0:
- `create_readonly_api_key`
- `get_readonly_api_keys`
- `delete_readonly_api_key`
- `validate_readonly_api_key`
TS parity:
- `create/get/delete` require L2 auth.
- `validate_readonly_api_key` is a public GET (query params), no L2 needed.
See the examples in `examples/`.
## HTTP helpers (GET/POST/PUT/DELETE)
`http_helpers` provides typed request wrappers including `put_typed/put`.
## Examples
Build/sign only (no network):
```bash
cargo run --example sign_order
```
Readonly open orders (TS parity headers):
```bash
cargo run --example get_open_orders_with_readonly_key
```
RFQ quotes:
```bash
cargo run --example rfq_get_quotes
```