💰 Polymarket 交易系统:API 下单 & 钱包架构
文档生成: 2026-04-30 08:41 CST
覆盖: 钱包地址、认证方式、下单流程、CLOB API
一、钱包架构
地址总览
| 名称 | 地址 | 用途 |
|---|---|---|
| EOA (你的) | 0xAf63F116D074Ba2793CBAa83F3380F7e10dfc51d | 签名私钥持有者 |
| Safe (多签) | 0xe39C4853A6e14045F192B65EfbACECf845d74C0B | 资金托管(持仓 + CLOB 余额) |
| Builder Code | 0x60a95778daaf76dfcb9fa65fb41ef2b229f92f52fc35c9b4af7ed917795429ad | 做市商激励码 |
关系图
┌──────────────┐
│ EOA │ 持有私钥,发起签名
│ 0xAf63... │
└──────┬───────┘
│ 签署所有交易
▼
┌──────────────┐
│ Safe 多签 │ 托管 USDC + CLOB 余额
│ 0xe39C... │ 实际下单 maker 地址
└──────┬───────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
Polygon NegRisk CTF Exchange
主网 Adapter 0x4D97D...
(137) 0xC5d56... (条件代币)
关键合约地址(Polygon 主网 Chain ID: 137)
| 合约 | 地址 | 说明 |
|---|---|---|
| CTF Exchange | 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 | 条件代币交易所 |
| NegRisk CTF Exchange | 0xC5d563A36AE78145C45a50134d48A1215220f80a | 负风险适配器 |
| USDC (PoS) | 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 | Polygon USDC |
| CTF Exchange V2 | 0xE111180000d2663C0091e4f400237545B87B996B | V2 合约(EIP-712 签名用) |
| NegRisk V2 | 0xe2222d279d744050d28e00520010520000310F59 | V2 负风险 |
二、认证方式
2.1 L2 HMAC 认证(主要方式)
用于所有 CLOB 下单/撤单操作。
| 环境变量 | 值前缀 | 说明 |
|---|---|---|
POLYMARKET_L2_API_KEY | 70be0740... | API Key |
POLYMARKET_L2_SECRET | b1R_aMey... | Base64 URL-safe 密钥 |
POLYMARKET_L2_PASSPHRASE | 37a1116a... | 口令 |
POLYMARKET_WALLET_ADDRESS | 0xAf63... | EOA 地址(checksum) |
签名算法:
# 1. 获取服务器时间
server_ts = GET /time → int
# 2. 构造消息
message = str(ts) + "POST" + "/order" + body_json
# 3. HMAC-SHA256
secret_bytes = base64_decode(urlsafe→standard, add padding)
signature = base64url_encode(hmac_sha256(secret_bytes, message))
# 4. 请求头
headers = {
'POLY_ADDRESS': checksummed_wallet_address,
'POLY_SIGNATURE': signature,
'POLY_TIMESTAMP': str(server_ts),
'POLY_API_KEY': api_key,
'POLY_PASSPHRASE': passphrase,
}
⚠️ 时钟偏移: 必须使用服务器时间(GET /time),本地时间偏差会触发 invalid signature。
2.2 L1 EIP-712 钱包签名(备用方式)
直接签名下单,不需要 API Key。用于 POST /order + POST /auth/api-key(派生 L2 凭证)。
EIP-712 Typed Data 结构(V2):
{
"domain": {
"name": "Polymarket CTF Exchange",
"version": "2",
"chainId": 137,
"verifyingContract": "<neg_risk 或 ctf exchange>"
},
"types": {
"Order": [
{"name": "salt", "type": "uint256"},
{"name": "maker", "type": "address"},
{"name": "signer", "type": "address"},
{"name": "tokenId", "type": "uint256"},
{"name": "makerAmount", "type": "uint256"},
{"name": "takerAmount", "type": "uint256"},
{"name": "side", "type": "uint8"},
{"name": "signatureType", "type": "uint8"},
{"name": "timestamp", "type": "uint256"},
{"name": "metadata", "type": "bytes32"},
{"name": "builder", "type": "bytes32"}
]
}
}
⚠️ 关键: timestamp 使用 毫秒 (Date.now()),不是秒。这是 npm @polymarket/clob-client-v2 的行为。
2.3 L2 凭证派生
# 从私钥自动派生 L2 API Key(无需网站手动创建)
from src.mm.clob_client import CLOBClient
client = CLOBClient.from_private_key(private_key)
# → 自动调用 POST /auth/api-key → 获取 key/secret/passphrase
三、签名类型 (signatureType)
下单时 signatureType 决定链上验证逻辑:
| 值 | 名称 | maker | signer | 适用场景 |
|---|---|---|---|---|
| 0 | EOA | EOA 地址 | EOA 地址 | 钱包直接持币 |
| 1 | POLY_PROXY | Proxy 地址 | EOA 地址 | ❌ CLOB 不支持 |
| 2 | POLY_GNOSIS_SAFE | Safe 地址 | EOA 地址 | 当前模式 |
当前使用: sig_type=2 (Safe 模式)
maker = Safe 地址 (0xe39C...) — 托管资金signer = EOA 地址 (0xAf63...) — 签署交易四、下单流程
4.1 完整路径
Web UI (/mm/weather)
│
▼
POST /api/mm/weather/place-order ← Flask 路由
│
├─ 1. 验证参数 (price/size/side)
├─ 2. CLOB tick 取整
│ ├─ price < 0.10 → tick=0.001 (0.1¢)
│ └─ price ≥ 0.10 → tick=0.01 (1¢)
├─ 3. 冷却检查 (同 token+side 30s 冷却)
├─ 4. 重复挂单检查 (同 token+side → 撤旧下新)
├─ 5. 自成交检查 (BUY 价 < SELL 价)
├─ 6. 测试上限 $10 (price × size ≤ $10)
│
▼
src/mm/clob_client.py :: create_order()
│
├─ 1. 确定 maker/signer/sig_type
│ └─ Safe mode: maker=0xe39C, signer=0xAf63, sig_type=2
├─ 2. 检测 neg_risk → 选 verifyingContract
├─ 3. _sign_order_v2() EIP-712 签名 (11字段)
├─ 4. _l2_sign() HMAC 认证头
│
▼
POST https://clob.polymarket.com/order
│
└─ ✅ HTTP 200 → order_id
❌ HTTP 4xx → 错误详情
4.2 价格精度
| 价格区间 | tick | 示例 |
|---|---|---|
| < $0.10 | 0.001 (0.1¢) | 0.025 → 保留 3 位 |
| ≥ $0.10 | 0.01 (1¢) | 0.885 → 0.88 或 0.89 |
4.3 数量精度
makerAmount 精度: 4 位小数takerAmount (size) 精度: 2 位小数4.4 USDC 精度
BASE = 10 6 # USDC 6 decimals
# BUY
makerAmount = price BASE size * BASE // BASE # USDC
takerAmount = size * BASE # shares
# SELL
makerAmount = size * BASE # shares
takerAmount = price BASE size * BASE // BASE # USDC
五、撤单
全部撤单
DELETE https://clob.polymarket.com/cancel-all
Headers: L2 HMAC 认证
单笔撤单
DELETE https://clob.polymarket.com/order
Body: {"orderID": "0x..."}
Headers: L2 HMAC 认证
查询挂单
GET https://clob.polymarket.com/orders
Params: ?token_id=<tokenId> (可选)
Headers: L2 HMAC 认证
六、Web UI 交易端点
所有端点位于 /api/mm/weather/,由 src/web/app.py 提供。
| 端点 | 方法 | 功能 |
|---|---|---|
/api/mm/weather/status | GET | MM 状态(持仓/挂单/自动开关) |
/api/mm/weather/place-order | POST | 挂限价单 |
/api/mm/weather/quick-order | POST | 盘口最优价快速下单 5 份 |
/api/mm/weather/cancel-all | POST | 撤销全部挂单 |
/api/mm/weather/cancel-order | POST | 撤销指定挂单 |
/api/mm/weather/open-orders | GET | 查询当前挂单 |
/api/mm/weather/toggle-auto | POST | 开关自动交易 |
/api/mm/weather/auto-status | GET | 自动交易状态 |
/api/mm/weather/cooldowns | GET | 活跃冷却列表 |
/api/mm/weather/run-scan | POST | 手动触发做市扫描 |
place-order 请求体
{
"token_id": "1234567890123456789...",
"price": 0.885,
"size": 10,
"side": "BUY",
"temp": 25,
"comp_type": "exact"
}
quick-order 请求体
{
"token_id": "1234567890...",
"side": "BUY",
"size": 5
}
安全机制
| 检查 | 说明 |
|---|---|
| 冷却 (30s) | 同 token+side 30 秒内不可重复下单 |
| 重复保护 | 同 token+side 有挂单时先撤旧再下新 |
| 自成交防护 | BUY 价不能 ≥ SELL 价(HTTP 409) |
| 测试上限 | 单笔 price × size ≤ $10 |
| Tick 取整 | 自动 ceil/floor 到最近有效 tick |
七、链上操作
补充资金
# 1. 从 Safe 转 USDC 到 Polygon
# 使用 Safe UI 或 Relayer SDK
# 2. 在链上 Approve
USDC → NegRisk Adapter (0xC5d56...)
USDC → CTF Exchange (0x4D97...)
QuickSwap 换 MATIC
# Safe 上的 USDC → MATIC(用于 Gas)
# 通过 QuickSwap Router
审批状态
Safe 需要对以下合约授权 USDC:
0xC5d563A36AE78145C45a50134d48A1215220f80a (NegRisk Adapter)0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 (CTF Exchange)八、自动交易系统
时间窗口
data/mm/auto_trading.json
{
"enabled": false,
"updated_at": "2026-04-30T08:00:00+08:00"
}
手动控制
/mm/weather 页面)POST /api/mm/weather/toggle-auto风控参数
| 参数 | 值 | 说明 |
|---|---|---|
BASE_ORDER_SIZE | $5 | 基础订单金额 |
MAX_ORDER_SIZE | $10 | 当前测试阶段上限 |
MIN_NOTIONAL | $1 | 最小对价 |
| 单合约最大敞口 | $50 | Paper 初始值 |
| 每日最大亏损 | $20 | 硬止损 |
九、网络代理
Polymarket API 被 DNS 阻断,所有请求通过 SOCKS5 代理:
self.session.proxies.update({
'http': 'socks5h://127.0.0.1:7897',
'https': 'socks5h://127.0.0.1:7897',
})
十、CLOB 客户端缓存
_clob_client_cache = None # 单例
def _get_cached_clob_client(private_key):
global _clob_client_cache
if _clob_client_cache is None:
_clob_client_cache = CLOBClient.from_private_key(private_key)
return _clob_client_cache
首次派生 ~4s(EIP-712 签名 → L2 凭证),后续调用即时。
十一、RPC URL
Polygon RPC: https://polygon.drpc.org
仅用于 from_private_key 派生地址(eth_account.Account.from_key),不用于链上查询。
十二、配置文件速查
.env 中所有交易相关配置:
# ── 钱包 ──
POLYMARKET_WALLET_ADDRESS=0xAf63F116D074Ba2793CBAa83F3380F7e10dfc51d
POLYMARKET_PRIVATE_KEY=0xc90e73103ca02bc9a01c7a70f2f5d9a6d840328d087edb9ca0173f34c14d1578
POLYMARKET_SAFE_ADDRESS=0xe39C4853A6e14045F192B65EfbACECf845d74C0B
# ── L2 API 凭证 ──
POLYMARKET_L2_API_KEY=70be0740-a474-d820-1d9c-85522e4dd1ef
POLYMARKET_L2_SECRET=b1R_aMeyFo72ao0vMydNrZUDdXt7BFuv89ZFGaZu6ho=
POLYMARKET_L2_PASSPHRASE=37a1116a9b45ba9668d2ad686d31fafcba4337965c0fec31c8dd81f388c68ae4
# ── Builder ──
POLYMARKET_BUILDER_API_KEY=019dbed3-08c6-7221-8f7a-80ce28a70f2a
POLYMARKET_BUILDER_SECRET=lA9VMqMLkTBVSNI5cUEZzImGLD6Om4grtrpox0BT8KY=
POLYMARKET_BUILDER_PASSPHRASE=b9c5e159ab2296fedd2384b5062ac95874c230f3e66618e88494295264f2855a
POLYMARKET_BUILDER_CODE=0x60a95778daaf76dfcb9fa65fb41ef2b229f92f52fc35c9b4af7ed917795429ad
# ── 链 ──
POLYGON_RPC_URL=https://polygon.drpc.org
CTF_EXCHANGE=0x4D97DCd97eC945f40cF65F87097ACe5EA0476045
NEG_RISK_CTF_EXCHANGE=0xC5d563A36AE78145C45a50134d48A1215220f80a
USDC_ADDRESS=0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174