Polymarket/rs-clob-client
GitHub: Polymarket/rs-clob-client
面向Polymarket预测市场的Rust客户端SDK,提供类型安全的订单管理、实时数据流与多API模块集成能力。
Stars: 544 | Forks: 151

# Polymarket Rust 客户端
[](https://crates.io/crates/polymarket-client-sdk)
[](https://github.com/Polymarket/rs-clob-client/actions/workflows/ci.yml)
[](https://codecov.io/gh/Polymarket/rs-clob-client)
一个用于与 Polymarket 服务(主要是中央限价订单簿 (CLOB))进行交互的符合人体工程学的 Rust 客户端。
该 crate 提供了强类型请求构建器、认证端点、`alloy` 支持等功能。
## 目录
- [概述](#overview)
- [快速上手](#getting-started)
- [功能标志](#feature-flags)
- [重导出类型](#re-exported-types)
- [示例](#examples)
- [CLOB 客户端](#clob-client)
- [WebSocket 流](#websocket-streaming)
- [可选 API](#optional-apis)
- [其他 CLOB 功能](#additional-clob-capabilities)
- [设置 Token 授权额度](#token-allowances)
- [最低支持的 Rust 版本 (MSRV)](#minimum-supported-rust-version-msrv)
- [贡献](#contributing)
- [关于 Polymarket](#about-polymarket)
## 概述
- **类型化 CLOB 请求**(订单、交易、市场、余额等)
- **双重认证流程**
- 标准认证流程
- [Builder](https://docs.polymarket.com/developers/builders/builder-intro) 认证流程
- **类型级状态机**
- 防止在认证前使用认证端点
- 在编译时强制执行正确的转换
- 通过 `alloy::signers::Signer` 提供 **Signer 支持**
- 包括远程签名者,例如 AWS KMS
- **零成本抽象** — 热路径中无动态分发
- **订单构建器**,用于轻松构建和签名
- **完整的 `serde` 支持**
- 基于 `reqwest` 的 **Async-first 设计**
## 快速上手
将 crate 添加到您的 `Cargo.toml`:
```
[dependencies]
polymarket-client-sdk = "0.3"
```
或者
```
cargo add polymarket-client-sdk
```
然后运行任何示例
```
cargo run --example unauthenticated
```
## 功能标志
该 crate 是模块化的,具有针对不同 Polymarket API 的可选功能:
| Feature | 描述 |
|--------------|------------------------------------------------------------------------------------------------------------------------------------------------|
| `clob` | 核心 CLOB 客户端,用于下单、市场数据和认证 |
| `tracing` | 通过 [`tracing`](https://docs.rs/tracing) 进行结构化日志记录,用于 HTTP 请求、认证流程和缓存 |
| `ws` | WebSocket 客户端,用于实时订单簿、价格和用户事件流 |
| `rtds` | 实时数据流,用于加密货币价格(Binance、Chainlink)和评论 |
| `data` | Data API 客户端,用于持仓、交易、排行榜和分析 |
| `gamma` | Gamma API 客户端,用于市场/事件发现、搜索和元数据 |
| `bridge` | Bridge API 客户端,用于跨链存款(EVM、Solana、Bitcoin) |
| `rfq` | RFQ API(在 CLOB 内),用于提交和查询报价 |
| `heartbeats` | Clob 功能,自动向 Polymarket 服务器发送心跳消息,如果客户端断开连接,所有未完成订单将被取消 |
| `ctf` | CTF API 客户端,用于在二元和负风险市场上执行拆分/合并/赎回操作
在您的 `Cargo.toml` 中启用功能:
```
[dependencies]
polymarket-client-sdk = { version = "0.3", features = ["ws", "data"] }
```
## 重导出类型
此 SDK 重导出了外部 crate 中常用的类型,因此您无需将它们添加到您的 `Cargo.toml` 中:
### 来自 `types` 模块
```
use polymarket_client_sdk::types::{
Address, ChainId, Signature, address, // from alloy::primitives
DateTime, NaiveDate, Utc, // from chrono
Decimal, dec, // from rust_decimal + rust_decimal_macros
};
```
### 来自 `auth` 模块
```
use polymarket_client_sdk::auth::{
LocalSigner, Signer, // from alloy::signers (LocalSigner + trait)
Uuid, ApiKey, // from uuid (ApiKey = Uuid)
SecretString, ExposeSecret, // from secrecy
builder::Url, // from url (for remote builder config)
};
```
### 来自 `error` 模块
```
use polymarket_client_sdk::error::{
StatusCode, Method, // from reqwest (for error inspection)
};
```
这使您能够使用 SDK,而无需管理这些常见依赖项的版本兼容性。
## 示例
完整示例集请参见 `examples/`。以下是针对常见用例的精选示例。
### CLOB 客户端
#### 未认证客户端(只读)
```
use polymarket_client_sdk::clob::Client;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = Client::default();
let ok = client.ok().await?;
println!("Ok: {ok}");
Ok(())
}
```
#### 已认证客户端
将 `POLYMARKET_PRIVATE_KEY` 设置为包含您私钥的环境变量。
##### [EOA](https://www.binance.com/en/academy/glossary/externally-owned-account-eoa) 钱包
如果使用 MetaMask 或硬件钱包,您必须先设置 Token 授权额度。请参阅下面的 [Token 授权额度](#token-allowances) 部分。
```
use std::str::FromStr as _;
use alloy::signers::Signer as _;
use alloy::signers::local::LocalSigner;
use polymarket_client_sdk::{POLYGON, PRIVATE_KEY_VAR};
use polymarket_client_sdk::clob::{Client, Config};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let private_key = std::env::var(PRIVATE_KEY_VAR).expect("Need a private key");
let signer = LocalSigner::from_str(&private_key)?.with_chain_id(Some(POLYGON));
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
let ok = client.ok().await?;
println!("Ok: {ok}");
let api_keys = client.api_keys().await?;
println!("API keys: {api_keys:?}");
Ok(())
}
```
##### 代理/Safe 钱包
对于代理/Safe 钱包,资金地址是使用 CREATE2 从您的签名者 EOA 地址**自动派生**的:
```
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.signature_type(SignatureType::GnosisSafe) // Funder auto-derived via CREATE2
.authenticate()
.await?;
```
SDK 会计算 Polymarket 为您的 EOA 部署的确定性钱包地址。这与您使用浏览器钱包登录 polymarket.com 时显示的地址相同。
如果您需要覆盖派生地址(例如,对于高级用例),您可以显式提供它:
```
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.funder(address!(""))
.signature_type(SignatureType::GnosisSafe)
.authenticate()
.await?;
```
您也可以手动派生这些地址:
```
use polymarket_client_sdk::{derive_safe_wallet, derive_proxy_wallet, POLYGON};
// For browser wallet users (GnosisSafe)
let safe_address = derive_safe_wallet(signer.address(), POLYGON);
// For Magic/email wallet users (Proxy)
let proxy_address = derive_proxy_wallet(signer.address(), POLYGON);
```
##### 资金地址
**资金地址**是 Polymarket 上实际持有您资金的地址。当使用代理钱包(如 Magic 等电子邮件钱包或浏览器扩展钱包)时,签名密钥与持有资金的地址不同。当您指定 `SignatureType::Proxy` 或 `SignatureType::GnosisSafe` 时,SDK 会使用 CREATE2 自动派生正确的资金地址。
如有需要,您可以使用 `.funder(address)` 覆盖此设置。
##### 签名类型
**signature_type** 参数告诉系统如何验证您的签名:
- `signature_type=0`(默认):标准 EOA(外部拥有账户)签名 - 包括 MetaMask、硬件钱包以及您直接控制私钥的任何钱包
- `signature_type=1`:Email/Magic 钱包签名(委托签名)
- `signature_type=2`:浏览器钱包代理签名(当使用代理合约而非直接钱包连接时)
有关更多信息,请参阅 [SignatureType](src/clob/types/mod.rs#L182)。
##### 下市价单
```
use std::str::FromStr as _;
use alloy::signers::Signer as _;
use alloy::signers::local::LocalSigner;
use polymarket_client_sdk::{POLYGON, PRIVATE_KEY_VAR};
use polymarket_client_sdk::clob::{Client, Config};
use polymarket_client_sdk::clob::types::{Amount, OrderType, Side};
use polymarket_client_sdk::types::Decimal;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let private_key = std::env::var(PRIVATE_KEY_VAR).expect("Need a private key");
let signer = LocalSigner::from_str(&private_key)?.with_chain_id(Some(POLYGON));
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
let order = client
.market_order()
.token_id("")
.amount(Amount::usdc(Decimal::ONE_HUNDRED)?)
.side(Side::Buy)
.order_type(OrderType::FOK)
.build()
.await?;
let signed_order = client.sign(&signer, order).await?;
let response = client.post_order(signed_order).await?;
println!("Order response: {:?}", response);
Ok(())
}
```
##### 下限价单
```
use std::str::FromStr as _;
use alloy::signers::Signer as _;
use alloy::signers::local::LocalSigner;
use polymarket_client_sdk::{POLYGON, PRIVATE_KEY_VAR};
use polymarket_client_sdk::clob::{Client, Config};
use polymarket_client_sdk::clob::types::Side;
use polymarket_client_sdk::types::Decimal;
use rust_decimal_macros::dec;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let private_key = std::env::var(PRIVATE_KEY_VAR).expect("Need a private key");
let signer = LocalSigner::from_str(&private_key)?.with_chain_id(Some(POLYGON));
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.authenticate()
.await?;
let order = client
.limit_order()
.token_id("")
.size(Decimal::ONE_HUNDRED)
.price(dec!(0.1))
.side(Side::Buy)
.build()
.await?;
let signed_order = client.sign(&signer, order).await?;
let response = client.post_order(signed_order).await?;
println!("Order response: {:?}", response);
Ok(())
}
```
#### Builder 认证客户端
适用于机构/第三方应用集成及远程签名:
```
use std::str::FromStr as _;
use alloy::signers::Signer as _;
use alloy::signers::local::LocalSigner;
use polymarket_client_sdk::auth::builder::Config as BuilderConfig;
use polymarket_client_sdk::{POLYGON, PRIVATE_KEY_VAR};
use polymarket_client_sdk::clob::{Client, Config};
use polymarket_client_sdk::clob::types::SignatureType;
use polymarket_client_sdk::clob::types::request::TradesRequest;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let private_key = std::env::var(PRIVATE_KEY_VAR).expect("Need a private key");
let signer = LocalSigner::from_str(&private_key)?.with_chain_id(Some(POLYGON));
let builder_config = BuilderConfig::remote("http://localhost:3000/sign", None)?; // Or your signing server
let client = Client::new("https://clob.polymarket.com", Config::default())?
.authentication_builder(&signer)
.signature_type(SignatureType::Proxy) // Funder auto-derived via CREATE2
.authenticate()
.await?;
let client = client.promote_to_builder(builder_config).await?;
let ok = client.ok().await?;
println!("Ok: {ok}");
let api_keys = client.api_keys().await?;
println!("API keys: {api_keys:?}");
let builder_trades = client.builder_trades(&TradesRequest::default(), None).await?;
println!("Builder trades: {builder_trades:?}");
Ok(())
}
```
### WebSocket 流
实时订单簿和用户事件流。需要 `ws` 功能。
```
polymarket-client-sdk = { version = "0.3", features = ["ws"] }
```
```
use futures::StreamExt as _;
use polymarket_client_sdk::clob::ws::Client;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = Client::default();
// Subscribe to orderbook updates for specific assets
let asset_ids = vec!["".to_owned()];
let stream = client.subscribe_orderbook(asset_ids)?;
let mut stream = Box::pin(stream);
while let Some(book_result) = stream.next().await {
let book = book_result?;
println!("Orderbook update for {}: {} bids, {} asks",
book.asset_id, book.bids.len(), book.asks.len());
}
Ok(())
}
```
可用流:
- `subscribe_orderbook()` - 资产的买卖盘水平
- `subscribe_prices()` - 价格变动事件
- `subscribe_midpoints()` - 计算出的中间价
- `subscribe_orders()` - 用户订单更新(需认证)
- `subscribe_trades()` - 用户交易执行(需认证)
有关更多 WebSocket 示例,包括认证用户流,请参阅 [`examples/clob/ws/`](examples/clob/ws/)。
### 可选 API
#### Data API
交易分析、持仓和排行榜。需要 `data` 功能。
```
use polymarket_client_sdk::data::Client;
use polymarket_client_sdk::data::types::request::PositionsRequest;
use polymarket_client_sdk::types::address;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = Client::default();
let user = address!("0x0000000000000000000000000000000000000000"); // Your address
let request = PositionsRequest::builder().user(user).limit(10)?.build();
let positions = client.positions(&request).await?;
println!("Open positions: {:?}", positions);
Ok(())
}
```
有关交易、排行榜、活动等更多信息,请参阅 [`examples/data.rs`](examples/data.rs)。
#### Gamma API
市场和事件发现。需要 `gamma` 功能。
```
use polymarket_client_sdk::gamma::Client;
use polymarket_client_sdk::gamma::types::request::{EventsRequest, SearchRequest};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = Client::default();
// Find active events
let request = EventsRequest::builder().active(true).limit(5).build();
let events = client.events(&request).await?;
println!("Found {} events", events.len());
// Search for markets
let search = SearchRequest::builder().q("bitcoin").build();
let results = client.search(&search).await?;
println!("Search results: {:?}", results);
Ok(())
}
```
有关标签、系列、评论和体育端点,请参阅 [`examples/gamma.rs`](examples/gamma/client.rs)。
#### Bridge API
来自 EVM 链、Solana 和 Bitcoin 的跨链存款。需要 `bridge` 功能。
```
use polymarket_client_sdk::bridge::Client;
use polymarket_client_sdk::bridge::types::DepositRequest;
use polymarket_client_sdk::types::address;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let client = Client::default();
// Get deposit addresses for your wallet
let request = DepositRequest::builder()
.address(address!("0x0000000000000000000000000000000000000000")) // Your address
.build();
let response = client.deposit(&request).await?;
println!("EVM: {}", response.address.evm);
println!("Solana: {}", response.address.svm);
println!("Bitcoin: {}", response.address.btc);
Ok(())
}
```
有关支持的资产和最低存款额,请参阅 [`examples/bridge.rs`](examples/bridge.rs)。
## 其他 CLOB 功能
除了基本下单外,CLOB 客户端还支持:
- **奖励与收益** - 查询做市商奖励、每日收益和奖励百分比
- **流式分页** - `stream_data()` 用于遍历大型结果集
- **批量操作** - `post_orders()` 和 `cancel_orders()` 用于一次处理多个订单
- **订单评分** - 检查订单是否有资格获得做市商奖励
- **通知** - 管理交易通知
- **余额管理** - 查询和刷新余额/授权额度缓存
- **地理封锁检测** - 检查您所在的区域是否可用交易
有关全面用法,请参阅 [`examples/clob/authenticated.rs`](examples/clob/authenticated.rs)。
## Token 授权额度
### 我需要设置授权额度吗?
MetaMask 和 EOA 用户必须设置 Token 授权额度。
如果您使用的是代理或 [Safe](https://help.safe.global/en/articles/40869-what-is-safe)-type 钱包,则不需要。
### 什么是授权额度?
将授权额度视为权限。在 Polymarket 能够转移您的资金以执行交易之前,您需要授予交易所合约访问您的 USDC 和条件 Token 的权限。
### 快速设置
您需要批准两种类型的 Token:
1. **USDC**(用于存款和交易)
2. **条件代币**(您交易的结果代币)
每种都需要获得批准,交易所合约才能正常工作。
### 设置授权额度
使用 [examples/approvals.rs](examples/approvals.rs) 来批准正确的合约。运行一次以批准 USDC。然后更改 `TOKEN_TO_APPROVE` 并为每个条件代币运行一次。
**专业提示**:您只需要为每个钱包设置一次。之后,您就可以自由交易了。
## 最低支持的 Rust 版本 (MSRV)
**MSRV: Rust [1.88](https://releases.rs/docs/1.88.0/)**
旧版本*可能*可以编译,但不被支持。
本项目旨在保持与至少六个月大的 Rust 版本兼容。
如果外部力量需要,版本更新可能比政策指南规定的更频繁。例如,下游依赖项中的 CVE 需要提升 MSRV 将被视为违反六个月准则的可接受理由。
## 贡献
我们鼓励社区贡献。请查看我们的[贡献指南](.github/CONTRIBUTING.md),了解如何为此 SDK 做贡献的说明。
## 关于 Polymarket
[Polymarket](https://docs.polymarket.com/polymarket-learn/get-started/what-is-polymarket) 是世界上最大的预测市场,允许您通过对各个主题的未来事件下注来保持知情并从您的知识中获利。
研究表明,预测市场通常比权威专家更准确,因为它们将新闻、民意调查和专家意见结合成一个单一数值,代表了市场对事件概率的看法。我们的市场反映了您最关心的事件的准确、无偏见和实时的概率。市场寻求真理。
标签:Alloy, CLOB, DeFi, Polymarket, Reqwest, Rust, Rust库, WebSocket, 中央限价订单簿, 依赖分析, 加密货币, 区块链, 可视化界面, 客户端SDK, 异步编程, 类型安全, 网络流量审计, 自动交易, 通知系统, 通知系统, 量化交易, 预测市场