# Polymarket 集成（v1 读取 + 交易）

本文档描述了 issue #1398 的 Polymarket 集成。

## 范围

这个 `polymarket` 工具现在支持以下市场浏览和交易工作流：

* Gamma API（`https://gamma-api.polymarket.com`)
* CLOB API（`https://clob.polymarket.com`)

支持的读取操作：

* `list_markets`
* `get_market`
* `list_events`
* `get_orderbook`
* `get_price`
* `get_positions`
* `get_balance`
* `get_open_orders`
* `get_usdc_allowance`

支持的写入操作：

* `place_order`
* `cancel_order`

## 架构

实现位于 `src/openhuman/tools/impl/network/polymarket.rs` 以及辅助模块：

* `clob_auth.rs`：L1 凭据派生 + L2 HMAC 头
* `polymarket_orders.rs`：EIP-712 订单类型化数据签名

关键运行时行为：

* 二层 API 凭据会在首次经过身份验证的调用时派生并缓存。
* 派生出的凭据会持久化到 `integrations.polymarket.derived_clob_credentials` （在 secret-store 迁移完成前使用普通配置回退）。
* 下单会先获取 `GET /nonce?user=<eoa>` 然后再签名，以避免重放/nonce 不匹配。
* USDC.e 授权通过 Polygon 的 `eth_call` 读取，针对 ERC-20 的 `allowance(owner, spender)`.

## 身份验证与签名流程

### L1 握手（一次性引导）

* 签名 CLOB `ClobAuth` 带有 Polygon chain id 的 EIP-712 载荷 `137`.
* 调用 `POST /auth/api-key`；如有需要，则回退到 `GET /auth/derive-api-key`.
* 持久化返回的 `{ apiKey, secret, passphrase }` 用于 L2。

### L2 经过身份验证的请求

每个经过身份验证的 CLOB 请求都会签名：

* `timestamp + method + request_path（POST 时还包括 body）`

请求头：

* `POLY_ADDRESS`
* `POLY_SIGNATURE`
* `POLY_TIMESTAMP`
* `POLY_NONCE: 0`
* `POLY_API_KEY`
* `POLY_PASSPHRASE`

### 订单签名

`place_order` 使用以下域对 EIP-712 订单进行签名：

* 名称： `Polymarket CTF Exchange`
* 版本： `1`
* chain id： `137`
* 验证合约： `integrations.polymarket.clob_exchange_contract`

## 权限

写入操作目前受一个明确的临时审批标志保护。

* `place_order` 和 `cancel_order` 需要 `approved=true`.
* 如果省略或为 `false`，工具会返回：
  * `Polymarket 写入需要用户明确批准。在与用户确认后，请使用 arguments.approved = true 重新调用。`

这是临时措施，直到 #1339 中的共享审批闸门集成完成。

## 配置

配置路径： `integrations.polymarket`.

字段：

* `enabled` （默认 `false`)
* `gamma_base_url` （默认 `https://gamma-api.polymarket.com`)
* `clob_base_url` （默认 `https://clob.polymarket.com`)
* `timeout_secs` （默认 `15`)
* `eoa_address` （可选的默认用户地址）
* `polygon_rpc_url` （默认 `https://polygon-rpc.com`)
* `usdc_contract` （默认 `0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174`)
* `clob_exchange_contract` （默认 `0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E`)
* `derived_clob_credentials` （可选的缓存 L2 凭据）

## USDC 授权合约

`get_usdc_allowance` 只报告授权状态；不会修改链上状态。

* 代币：Polygon 上的 USDC.e（`0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174`)
* 花费者：Polymarket 交易所（`0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E`)

如果授权不足，必须单独执行批准（钱包工具 / 明确用户批准流程）。

## 错误和重试行为

* 4xx 错误被视为客户端错误，不会重试。
* 429 和 5xx 错误被视为临时错误，最多重试 3 次。
* 重试之间的退避固定为 500ms。
* 超时会表现为明确的截止时间错误。

## 测试策略

单元测试位于 `src/openhuman/tools/impl/network/polymarket_tests.rs` 以及辅助模块测试。

* 现有的读取路径和重试行为测试仍然被覆盖。
* 新增了对经过身份验证的读取操作、写入审批闸门以及 Polygon 授权读取的覆盖。
* `clob_auth.rs` tests 覆盖 HMAC/头部夹具行为。
* `polymarket_orders.rs` tests 覆盖域和确定性签名夹具行为。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tinyhumans.gitbook.io/openhuman/zh/kai-fa/polymarket.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
