polymarket
Trade on Polymarket prediction markets (CLOB V2) from a Privy EOA wallet. Search markets, place/cancel orders, manage positions. No private key handling. Use when the user wants to bet on event outcomes (e.g. "buy YES at 0.65 on the ceasefire market", "what are my open positions", "close my Trump bet").
What this skill does
# Polymarket Trading (CLOB V2)
Script-first. Every workflow is one bash call + at most one `wallet_sign_typed_data` (which can't be scripted because it's a wallet RPC). Verified live: see Changelog v5.1.0.
---
## TL;DR — Trade in 3 steps
```bash
# 1. One-time setup (idempotent — safe to re-run)
python3 scripts/setup.py --all 10 # wrap 10 USDC.e -> pUSD + all approvals
# 2. Find a market
python3 scripts/search.py "trump" --limit 3 # returns token_ids
# 3. Place order
python3 scripts/prepare_order.py <token_id> BUY <price> <size>
# → sign /tmp/poly_order.json via wallet_sign_typed_data
python3 scripts/post_order.py <signature>
```
All scripts live in `skills/polymarket/scripts/` and assume working dir is the skill folder.
---
## Account prerequisites (one-time, on-chain)
CLOB V2 settles in **pUSD** (an ERC-20 USDC wrapper), NOT raw USDC.e. Before the first order, the EOA must:
1. Hold USDC.e on Polygon (any amount ≥ what you want to trade).
2. Wrap USDC.e → pUSD via `CollateralOnramp.wrap()`.
3. `approve(pUSD, spender, MAX)` for the 3 V2 exchange spenders.
4. `setApprovalForAll(CTF, spender, true)` for the same 3 spenders (needed for SELL/redemption).
`scripts/setup.py` does all of this and is **idempotent**: it reads on-chain state and skips anything already done. Gas is sponsored by the Privy/Alchemy paymaster — user pays 0 MATIC.
```bash
python3 scripts/setup.py # dry-run: show current state + next step
python3 scripts/setup.py --all 10 # wrap 10 USDC.e + approve everything
python3 scripts/setup.py --wrap 50 # wrap more later
python3 scripts/setup.py --approve # re-issue approvals only
```
---
## Scripts
| Script | Purpose | Tool calls |
|---|---|---|
| `setup.py` | One-time wrap + approvals (idempotent) | 0–8 wallet_transfer |
| `search.py` | Find events/markets, returns token_ids + live prices | 0 |
| `status.py` | Balance + positions + open orders + recent trades | 0 |
| `prepare_order.py` | Fetch orderbook + build EIP-712 payload | 0 |
| `post_order.py` | Submit signed order, verify fill | 0 |
| `cancel.py` | Cancel one order (`--id`) or all (`--all`) | 0 |
| `close_positions.py` | Build SELL orders for all positions | 0 |
| `auth.py` | Check / derive CLOB API key from wallet | 0–1 sign |
### Search
```bash
python3 scripts/search.py "ceasefire" --limit 3
```
- Use **short keywords** (`trump`, `btc`, `ceasefire`), not full literal questions — long queries often return empty.
- Output JSON includes `outcomes[i].token_id` (YES = index 0, NO = index 1) and current price.
### Place an order — full flow
```bash
# 1. Prepare: fetches market info + orderbook, writes /tmp/poly_order.json
python3 scripts/prepare_order.py 7892825...50228 BUY 0.65 10
# 2. Sign (Python in agent runtime, ONE tool call)
# from core.skill_tools import wallet
# p = json.load(open('/tmp/poly_order.json'))
# sig = wallet.wallet_sign_typed_data(
# domain=p['domain'], types=p['types'],
# primaryType=p['primaryType'], message=p['message']
# )['signature']
# 3. Post: submits and prints order ID + fill status + tx hash
python3 scripts/post_order.py 0xSIGNATURE
```
### Close one or all positions
```bash
python3 scripts/close_positions.py # all positions
python3 scripts/close_positions.py --token_id X # one position
# → writes one /tmp/poly_close_N.json per position; sign each + post
```
---
## YES / NO & orderbook
Every binary market has two complementary tokens: `YES + NO ≈ $1.00`.
| Bet | Action | Use | Buy price |
|---|---|---|---|
| Event happens | BUY YES | `outcomes[0].token_id` | YES price |
| Event won't happen | BUY NO | `outcomes[1].token_id` | NO price |
Always check the book for the token **you intend to buy**:
- BUY → entry ≈ `best_ask`
- SELL → exit ≈ `best_bid`
- If you see 0.01 / 0.99, you're looking at the wrong token's book.
---
## Order rules (CLOB V2)
- **Minimum order value:** $1 (i.e. `price × size ≥ 1.0`)
- **Minimum size:** 5 shares
- **Tick:** normalized automatically by `prepare_order.py` (usually $0.01)
- **`signatureType`:** always `0` (EOA) for Privy wallets
V2 wire format is strict — `post_order.py` already handles this, but if you ever build a payload by hand:
- `salt` must be **int** (not string)
- Do **NOT** send `taker` / `nonce` / `feeRateBps` (V1 fields, removed in V2)
- `metadata` and `builder` are `bytes32` zeros (`0x` + 64 zeros)
---
## Auth refresh
CLOB credentials (`POLY_API_KEY` / `POLY_SECRET` / `POLY_PASSPHRASE`) are derived from a wallet signature once and persist. If `status.py` returns 401:
```bash
python3 scripts/auth.py --check # quick sanity check
python3 scripts/auth.py --prepare 0xWALLET # build signing payload
# → wallet_sign_typed_data(...)
python3 scripts/auth.py --save 0xSIG 0xWALLET TIMESTAMP
```
Invariants: `TIMESTAMP` and `0xWALLET` in `--save` must match the most recent `--prepare`. If 401 persists, rerun the full prepare→sign→save flow with a fresh timestamp.
---
## Geo / VPN
CLOB API is geo-blocked from US IPs. `scripts/common.py` transparently routes through `sc-vpn.internal:8080` and caches the fastest region. No agent action needed. Override with `POLY_VPN_REGION=ar` or disable with `POLY_DISABLE_VPN=true`.
---
## Errors → fixes
| Error | Cause | Fix |
|---|---|---|
| `Invalid order payload` | Wrong V2 wire format (string salt / extra V1 fields) | Use `post_order.py` (it sends the right shape) |
| `invalid amount for a marketable BUY order ($X), min size: $1` | Order value < $1 | Increase price × size to ≥ $1 |
| `not enough balance` / 0 buying power | pUSD not wrapped yet, OR `signature_type` mismatch in cache | `setup.py --all 10`, then `status.py` |
| `L2_BALANCE_TOO_LOW` | No pUSD in EOA | Wrap more: `setup.py --wrap N` |
| `order_version_mismatch` | Old V1 signing schema | Re-run `prepare_order.py` (uses V2 domain `version=2`) |
| 401 / Invalid API key | Stale CLOB credentials | `auth.py` refresh flow |
| 403 geo-block | VPN unhealthy | Retry; if persists, set `POLY_VPN_REGION` to another region |
| Orderbook shows 0.01 / 0.99 | Looking at the wrong outcome's book | Use the token_id you actually plan to buy |
### Known transient errors
- **Privy / Alchemy paymaster HTTP 500** may happen during rapid back-to-back on-chain calls.
- This is typically transient infra jitter, not a permanent wallet/skill issue.
- Practical fix: wait ~10 seconds and retry the same step.
---
## Architecture summary
- **Wallet:** Privy EOA, `signatureType=0`. Agent signs EIP-712 via `wallet_sign_typed_data`; no private key in agent context.
- **Gas:** sponsored (Alchemy paymaster) — every on-chain call routes through `wallet_transfer`.
- **Collateral:** pUSD (`0xC011a7E1...DFB`), 6 decimals, 1:1 wrap of USDC.e.
- **Exchanges:** CTF Exchange V2 (binary), Neg-Risk Adapter, Neg-Risk Exchange V2 — all 3 must be approved for SELL/settlement.
- **CLOB:** `https://clob.polymarket.com` (V2 backend, live since Apr 28 2026). L1 = wallet sig, L2 = HMAC with derived API key.
---
## Changelog
- **v6.0.1** — Bugfixes: (1) `scripts/common.py::save_env_var()` now guards missing trailing newline in `.env` to prevent key concatenation; (2) `scripts/close_positions.py` migrated from V1 wire fields to CLOB V2 schema (`timestamp/metadata/builder`, domain `version=2`) aligned with `prepare_order.py`. Added "Known transient errors" note for occasional Privy/Alchemy paymaster HTTP 500 under rapid consecutive calls (retry after ~10s).
- **v6.0.0** — Major: full SKILL rewrite for clarity ("3 steps to trade"), new idempotent `setup.py` for one-time wrap + approvals, end-to-end live-verified on CLOB V2 (BUY `0x43f20c67...20b653` → SELL `0x19f475e4...fedde1`, 5 NO @ 0.989 → @ 0.988, ~$0.005 slippage). Supersedes the V1-era flow entirely.
- **v5.1.0** — ARelated in Web3
xaut-trade
IncludedBuy or sell XAUT (Tether Gold) on Ethereum. Supports market orders (Uniswap V3) and limit orders (UniswapX). Wallet modes: Foundry keystore or WDK. Delegates non-XAUT intents to registered skills (e.g. Polymarket prediction markets, Hyperliquid trading). Triggers: buy XAUT, XAUT trade, swap USDT for XAUT, sell XAUT, swap XAUT for USDT, limit order, limit buy XAUT, limit sell XAUT, check limit order, cancel limit order, XAUT when, create wallet, setup wallet, polymarket, prediction market, bet on, odds on, hyperliquid, perp, perpetual, long, short, open long, open short, close position, leverage.
qfc-openclaw-skill
IncludedQFC blockchain interaction — wallet, faucet, chain queries, staking, epoch & finality, AI inference
gate-dex-trade
IncludedExecutes on-chain token swaps via Gate DEX. Use when user wants to swap, buy, sell, exchange, or convert tokens, or bridge cross-chain. Covers full swap flow: price quotes, transaction build, signing, and submission. Do NOT use for read-only data lookups or wallet account management.
hunch
IncludedDiscover, bet on, track, and settle Hunch prediction markets in natural language. Trigger when a user wants to bet, take a position, or get odds on a crypto outcome — token market-cap milestones and flips, launchpad races (Bankr vs pump.fun volume / #1-days / launches over a cap), token head-to-head outperformance, mcap strike-ladders, and up/down price rounds. Also trigger on "what can I bet on about $TOKEN", "odds on …", "take YES/NO on …", "show my Hunch bets", "did my market resolve". Settles in USDC on Base via x402 (≤ $10 / bet); every bet returns an on-chain proof.
opensea
IncludedQuery NFT data, trade on the Seaport marketplace, and swap ERC20 tokens across Ethereum, Base, Arbitrum, Optimism, Polygon, and more.
analyzing-market-sentiment
IncludedThis skill provides comprehensive cryptocurrency market sentiment analysis by combining multiple data sources Analyze cryptocurrency market sentiment using Fear & Greed Index, news analysis, and market momentum. Use when gauging overall market mood, checking if markets are fearful or greedy, or analyzing sentiment for specific coins. Trigger with phrases like "analyze crypto sentiment", "check market mood", "is the market fearful", "sentiment for Bitcoin", or "Fear and Greed index".