PolyClaw cannot simply “buy YES tokens” on Polymarket the way you’d buy a share on a stock exchange. Polymarket is built on the Gnosis Conditional Token Framework (CTF), which means every outcome token is always minted in a pair. To hold a directional position you must first split collateral into both sides, then dispose of the side you don’t want. This page walks through exactly how that works under the hood.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/deniszidbaev-cmyk/polyclaw-cmyk/llms.txt
Use this file to discover all available pages before exploring further.
The Conditional Token Framework (CTF)
The CTF is a Gnosis standard for representing conditional outcomes as ERC-1155 tokens on-chain. Every Polymarket question maps to a condition that has exactly two outcome slots: YES (partition = 1) and NO (partition = 2).
When you deposit pUSD into the CTF contract it always mints equal amounts of both tokens. There is no way to mint only YES — the contract enforces the pairing. Each token is worth 1 depending on the final outcome:
- The winning token redeems 1:1 for $1 of pUSD.
- The losing token redeems for $0.
Step-by-step trade execution
Fetch market info
PolyClaw calls the Polymarket Gamma API (
GammaClient.get_market()) to retrieve the market’s condition_id, YES token ID, NO token ID, and current mid-market prices for both sides. These are required for the split call and the subsequent CLOB sell.Check pUSD balance
The wallet must hold enough pUSD — not USDC.e. PolyClaw reads the pUSD balance via If you have USDC.e but no pUSD, wrap it 1:1 using the Collateral Onramp’s
WalletManager.get_balances() and aborts early if the balance is insufficient.wrap() function. The polymarket.com UI does this automatically; CLI users must call it manually.Split position
PolyClaw calls Once this transaction is confirmed, your wallet holds
CTF.splitPosition on-chain to mint outcome tokens:amount YES tokens and amount NO tokens. The split is irreversible — you must then sell the unwanted side to realise your directional position.Sell unwanted side on the CLOB
ClobClientWrapper.sell_fok() creates a FOK (Fill or Kill) sell order at 10% below the current market price and posts it to https://clob.polymarket.com:Understanding the economics
Consider buying a YES position on a market where YES trades at $0.65:| Step | Action | Cash flow |
|---|---|---|
| Split | Deposit $100 pUSD into CTF | −$100.00 |
| Tokens received | 100 YES tokens + 100 NO tokens | — |
| CLOB sell | Sell 100 NO tokens at 0.315 each | +$31.50 |
| Net cost | 31.50 | $68.50 |
| Effective entry | $68.50 / 100 YES tokens | $0.685 per YES |
CLOB order types
| Type | Behaviour | When used |
|---|---|---|
| FOK (Fill or Kill) | Must fill completely at the limit price or cancel instantly. No partial fills. | Default for selling the unwanted side after a split. |
| GTC (Good Till Cancelled) | Sits in the order book until matched or manually cancelled. | Available via ClobClientWrapper.buy_gtc() for limit buys. |
post_order is a 0x hex string like:
What happens if the CLOB sell fails
The split is an on-chain transaction that confirms before the CLOB sell is even attempted. If the CLOB sell fails for any reason, the split has already succeeded — you hold both YES and NO tokens in your wallet. Common failure causes and their remedies:- Cloudflare IP block — Polymarket’s CLOB API blocks many datacenter IPs. Set
HTTPS_PROXYto a rotating residential proxy andCLOB_MAX_RETRIES=10. The client will retry with a new IP on each attempt. - Insufficient liquidity — No resting buy orders exist at the sell price. Sell manually on polymarket.com → Portfolio.
- Intentional skip — Pass
--skip-sellto keep both sides deliberately (useful for LP or manual strategies).
Redeeming on resolution
When a market resolves, the winning tokens can be exchanged 1:1 for pUSD by callingCTF.redeemPositions.
polymarket.com auto-redeems only positions placed through its own UI. Positions entered via PolyClaw must be redeemed manually using
polyclaw redeem. The command calls CTF.redeemPositions(pUSD, 0x00...00, conditionId, indexSets) where indexSets = [1] for YES and [2] for NO.