Polymarket 的 CLOB(中心化限价订单簿)采用双层认证机制:L1(私钥认证) 和 L2(API 凭证认证)。
公共端点和公共方法无需认证,但涉及用户订单创建、取消、持仓查询等私有操作时,必须使用认证。
本指南详细说明如何使用官方 SDK(TypeScript/Python)或直接 REST API 完成认证。强烈推荐使用官方客户端库处理签名和认证逻辑。认证层级概述L1 认证(私钥签名)
- 使用用户钱包私钥对 EIP-712 结构化消息签名,证明私钥所有权。
- 非托管:私钥始终由用户控制,交易完全非托管。
- 作用:创建或派生 L2 API 凭证(apiKey、secret、passphrase),以及本地签名订单。
L2 认证(API 凭证 + HMAC)
- 使用 L1 生成的 API 凭证(apiKey、secret、passphrase)对请求进行 HMAC-SHA256 签名。
- 作用:访问私有端点,如下单、撤单、查询余额/持仓等。
L1 认证详解(私钥签名)使用 CLOB Client(推荐)TypeScript 示例(ethers v5):
typescript
import { ClobClient } from "@polymarket/clob-client";
import { Wallet } from "ethers";
// v5.8.0
const HOST = "https://clob.polymarket.com";
const CHAIN_ID = 137; // Polygon 主网
const signer = new Wallet(process.env.PRIVATE_KEY!);
const client = new ClobClient(HOST, CHAIN_ID, signer); // signer 启用 L1 方法
// 获取现有凭证,或新建(createOrDeriveApiKey)
const apiCreds = await client.createOrDeriveApiKey();
/*
apiCreds = {
"apiKey": "550e8400-e29b-41d4-a716-446655440000",
"secret": "base64EncodedSecretString",
"passphrase": "randomPassphraseString"
}
*/
Python 示例(py-clob-client):
python
from py_clob_client.client import ClobClient
import os
host = "https://clob.polymarket.com"
chain_id = 137 # Polygon 主网
private_key = os.getenv("PRIVATE_KEY")
client = ClobClient(
host=host,
chain_id=chain_id,
key=private_key # 启用 L1 方法
)
# 获取或创建凭证
api_creds = await client.create_or_derive_api_key()
# 输出同上
安全警告:
绝不将私钥硬编码或提交到版本控制!始终使用环境变量或安全密钥管理系统。直接 REST API(不推荐,手动签名)请求头需包含:
| Header | 是否必填 | 说明 |
|---|---|---|
| POLY_ADDRESS | 是 | Polygon 签名地址 |
| POLY_SIGNATURE | 是 | EIP-712 签名 |
| POLY_TIMESTAMP | 是 | 当前 UNIX 时间戳 |
| POLY_NONCE | 是 | Nonce(默认 0) |
EIP-712 签名结构(TypeScript 示例):
typescript
const domain = {
name: "ClobAuthDomain",
version: "1",
chainId: chainId, // 137
};
const types = {
ClobAuth: [
{ name: "address", type: "address" },
{ name: "timestamp", type: "string" },
{ name: "nonce", type: "uint256" },
{ name: "message", type: "string" },
],
};
const value = {
address: signingAddress,
timestamp: ts,
nonce: nonce,
message: "This message attests that I control the given wallet",
};
const sig = await signer._signTypedData(domain, types, value);
相关端点:
- 创建凭证:POST {clob-endpoint}/auth/api-key
- 派生凭证:GET {clob-endpoint}/auth/derive-api-key
响应:
json
{
"apiKey": "550e8400-e29b-41d4-a716-446655440000",
"secret": "base64EncodedSecretString",
"passphrase": "randomPassphraseString"
}
L2 认证详解(API 凭证 + HMAC)使用 CLOB Client(推荐)TypeScript 示例:
typescript
const client = new ClobClient(
HOST,
CHAIN_ID,
signer,
apiCreds, // 来自 L1 的凭证
1, // signatureType(见下表)
FUNDER // 资金地址(见下表)
);
// 示例:创建并提交订单(订单仍需私钥签名)
const order = await client.createAndPostOrder(
{
tokenID: "123456",
price: 0.65,
size: 100,
side: "BUY"
},
{
tickSize: "0.01",
negRisk: false
}
);
Python 示例类似,使用 creds=api_creds、signature_type=1、funder=...。注意:即使使用 L2 头,下单 payload 仍需用户私钥签名。直接 REST API(手动 HMAC)请求头需包含:
| Header | 是否必填 | 说明 |
|---|---|---|
| POLY_ADDRESS | 是 | Polygon 签名地址 |
| POLY_SIGNATURE | 是 | HMAC-SHA256 签名(使用 secret) |
| POLY_TIMESTAMP | 是 | 当前 UNIX 时间戳 |
| POLY_API_KEY | 是 | apiKey |
| POLY_PASSPHRASE | 是 | passphrase |
HMAC-SHA256 实现参考官方客户端源码:
- TypeScript: https://github.com/Polymarket/clob-client/blob/main/src/signing/hmac.ts
- Python: https://github.com/Polymarket/py-clob-client/blob/main/py_clob_client/signing/hmac.py
签名类型(Signature Type)与资金地址(Funder)初始化 L2 客户端时,必须指定:
| 签名类型 | 值 | 说明 |
|---|---|---|
| EOA | 0 | 标准以太坊钱包(如 MetaMask)。资金地址 = EOA 地址,需要持有 POL 支付 gas。 |
| POLY_PROXY | 1 | Polymarket.com 通过 Magic Link(邮箱/Google)登录的用户自定义代理钱包。需用户先从官网导出私钥并导入你的应用。 |
| GNOSIS_SAFE | 2 | Gnosis Safe 多签代理钱包(最常见)。适用于新用户或不匹配前两种的返回用户。 |
资金地址(Funder):
- 在 Polymarket.com 上显示的地址即代理钱包(通常 Gnosis Safe),用作 funder。
- 代理钱包在用户首次登录 Polymarket.com 时自动部署。
- funder 地址必须与 L1 签名地址匹配,否则报错“Invalid Funder Address”。
常见问题排查(Troubleshooting)
- INVALID_SIGNATURE:私钥错误或格式不对。
解决:确认私钥为有效 hex 字符串(以“0x”开头),地址匹配,权限正确。 - NONCE_ALREADY_USED:同一 nonce 已用于创建凭证。
解决:用 deriveApiKey(originalNonce) 派生现有凭证,或用新 nonce 创建。 - Invalid Funder Address:资金地址错误或未部署。
解决:检查 https://polymarket.com/settings 中的地址;若无,需先登录官网触发部署。 - 丢失凭证但有 nonce: typescript
const recovered = await client.deriveApiKey(originalNonce); - 凭证和 nonce 都丢失:无法恢复,只能新建: typescript
const newCreds = await client.createApiKey(); // 记得保存 nonce!
安全提醒:私钥、API 凭证均为敏感信息,丢失不可逆。始终安全存储。
