r/thegraph • u/PaulieB79 • 15h ago
Querying Polymarket V2 (post-April-28 CLOB) on-chain data with The Graph: 4 open-source subgraphs, real queries, and what's still missing
When Polymarket switched to CLOB V2 on 2026-04-28, it brought new CTF Exchange contracts, pUSD collateral, and builder-code attribution. That change broke a lot of the analytics people had built on V1 events. I rebuilt my subgraphs for V2 and published them on The Graph's decentralized network. Below is everything I know about them: what each one covers, what's actually synced right now, real queries with real output, and the gaps.
Source (PRs welcome; TODO: confirm license): https://github.com/PaulieB14/polymarket-v2-subgraphs
The subgraphs
Status was checked 2026-10-16 at about 7:02 PM ET. The Polygon chain head was block 95,657,583.
| Subgraph | Deployment | Covers | Era | Status |
|---|---|---|---|---|
| polymarket-v2-main | QmTKrqyYg23BjhihmsrRjbV9cVS2piNmnHsr7cjYaTgdWu (subgraph FjHkLw5U5Tsr9THKX3HCSxEXjM92GCaPtsxwjge7PaVS) |
Conditions, resolutions/payouts, splits/merges/redemptions, per-user positions and profit, builder stats, global counters | CTF from V1 genesis (block 28M) + V2 exchange events | ✅ Synced (block 95,657,575, ~8 blocks behind), no indexing errors |
| polymarket-v2-orderbook | QmNtJGxpAjFgoHhMwdijyvbLrpPPiHHX2qct56nTpk42Bs (subgraph B9mm21DKCex8ka4g8cteQU4NQqtviwmcTjQAYLbzQ1eR) |
Every V2 fill, per-token market volume, per-trader volume, builder attribution | V2 only (from block 84,902,353) | ✅ Synced (95,657,573), no errors |
| polymarket-v2-pnl | QmT21E4p8r6FCzW2EPK4NVj1dbcggdvKxZr8uuMcB4P5Cu (subgraph 6iGihLdrPygidk3h61e4Bnbr2yREof5STEguPuenhSfT) |
Per-user positions with average cost basis, realized P&L | V2 only | ✅ Synced (95,657,579), no errors. ⚠️ Heavy sorts can time out (see limitations) |
| Polymarket Open Interest V2 | QmbT2MmS2VGbGihiTUmWk6GMc2QYqoT9ZhiupUicYMWt6H (subgraph EvkLMq7ocbxLWCn1wXJoj25wUKwEbKR8Zx2huFzC3n5f) |
Per-market and global OI, hourly snapshots | V1 genesis → now | ❌ Not queryable right now: no indexer allocation on the network |
Legacy V1 subgraphs are still up for history before the migration: Polymarket main QmdyCguL…QX8a, Orderbook QmVGA9vv…pUup, and P&L QmZAYiMe…wQU. TODO: confirm sync status before linking these.
Example queries (real output, trimmed)
1. Platform totals plus the top V2 markets by volume (orderbook)
{
globalStats(id: "global") { tradesQuantity scaledCollateralVolume scaledCollateralFees tradersCount marketsCount buildersCount }
markets(first: 3, orderBy: scaledCollateralVolume, orderDirection: desc) { id tradesQuantity scaledCollateralVolume lastPrice }
}
"globalStats": { "tradesQuantity": "868875100", "scaledCollateralVolume": "34324527882.98",
"scaledCollateralFees": "201150627.72", "tradersCount": "1275086",
"marketsCount": "3650588", "buildersCount": "3862" },
"markets": [
{ "id": "319268930482876715…480574", "tradesQuantity": "86064", "scaledCollateralVolume": "256203489.84", "lastPrice": "0.999" },
{ "id": "590469406952990582…791078", "tradesQuantity": "148323", "scaledCollateralVolume": "117238750.64", "lastPrice": "0.999" }
]
Note: markets are keyed by outcome tokenId, not by question. You need Polymarket's Gamma API, or MarketData.condition in the main subgraph, to turn a tokenId into a human-readable question. "Volume" here is the summed collateral across fill events. TODO: check whether that double-counts relative to Polymarket's headline volume before quoting the $34B figure.
2. Builder attribution (new in V2)
{ builders(first: 3, orderBy: scaledVolume, orderDirection: desc) { id orderCount scaledVolume } }
[ { "id": "0xceebf77a…ce0c1", "orderCount": "2991872", "scaledVolume": "785020729.79" },
{ "id": "0x25a86cf1…0afda4", "orderCount": "344926", "scaledVolume": "573084309.72" },
{ "id": "0x6b0e773f…c67984", "orderCount": "2665966", "scaledVolume": "288251744.66" } ]
This shows which front ends and bots route V2 flow. The builder codes are bytes32, and mapping them to names is off-chain (TODO: is there a public registry?).
3. Live trade tape
{ orderFilledEvents(first: 3, orderBy: timestamp, orderDirection: desc) { timestamp side price size exchange market { id } } }
[ { "timestamp": "1792191723", "side": 0, "price": "0.38999999", "size": "51.282052", "exchange": "CTF" },
{ "timestamp": "1792191723", "side": 0, "price": "0.61000000", "size": "48.972052", "exchange": "CTF" },
{ "timestamp": "1792191723", "side": 1, "price": "0.39", "size": "2.31", "exchange": "CTF" } ]
side 0 = BUY and 1 = SELL. exchange is either CTF or NEG_RISK.
4. A trader's positions and realized P&L (pnl)
{ accounts(first: 2, where: { tradesQuantity_gt: "100" }) {
id tradesQuantity scaledCollateralVolume realizedPnl
positions(first: 2) { tokenId amount avgPrice realizedPnl } } }
{ "id": "0x0000000000110124f0712c657fc401c0d6b80f9c", "tradesQuantity": "4065",
"scaledCollateralVolume": "184975.61", "realizedPnl": "5672.33",
"positions": [ { "tokenId": "100276467…914745", "amount": "633333332", "avgPrice": "0.15", "realizedPnl": "0" } ] }
In practice, filter with accounts(where: { id: "0x…" }) for one wallet. amount uses 6 decimals.
5. Resolutions and market catalog (main)
{ globals(first: 1) { numConditions numOpenConditions numClosedConditions numTraders }
conditions(first: 2, orderBy: resolutionTimestamp, orderDirection: desc, where: { resolutionTimestamp_not: null }) { id resolutionTimestamp payouts } }
"globals": [ { "numConditions": 4412308, "numOpenConditions": 379818, "numClosedConditions": 4032490, "numTraders": "898695" } ],
"conditions": [ { "id": "0xfc23aaa7…ba02c1", "resolutionTimestamp": "1792191722", "payouts": ["0","1"] } ]
What you can build
- Leaderboards by trader volume or realized P&L (V2 era)
- Live trade feeds and "hot market" detection by recent fill counts
- Builder and front-end market share since the V2 cutover
- Resolution watchers, for example to alert when a condition resolves and show payouts
- Bots that check a wallet's cost basis before trading
Limitations (please read before building on this)
- Open Interest V2 currently syncing
- P&L is V2-only. Cost basis starts at the V2 deploy block, so positions opened under V1 will show incomplete cost basis. Combine with the V1 P&L subgraph if you need full history. Realized P&L only; unrealized P&L needs live prices from the CLOB API.
- Heavy queries can time out.
accounts(orderBy: realizedPnl, orderDirection: desc)across all accounts timed out on both indexers when I tested it. Filter first, for example byidortradesQuantity_gt. - Adapter masking: V2 splits, merges, and redeems go through
CtfCollateralAdapterandNegRiskCtfCollateralAdapter, sostakeholderon Split/Merge can be the adapter rather than the user's wallet. Fill-based data (orderbook, pnl) isn't affected. - No question text on-chain. Everything is keyed by conditionId or tokenId, so join with the Gamma API for titles and slugs.
- Some
MarketData.conditionvalues are null, specifically NegRisk positions minted through the NegRisk Adapter. - On-chain fills only: no resting orders, no order-book depth, and no off-chain cancellations.
- Usage is still low. The gateway's 30-day query counter showed 0 for these deployments. That may be a reporting lag (TODO: verify), but expect few indexers per deployment, so latency varies.
How to query
- Get a free API key at https://thegraph.com/studio/ (API Keys). TODO: confirm the current free-tier allowance before stating a number.
- POST GraphQL to
https://gateway.thegraph.com/api/<API_KEY>/subgraphs/id/<SUBGRAPH_ID>, or use/deployments/id/<Qm…>to pin a specific version. - Check freshness with
{ _meta { block { number } hasIndexingErrors } }.
curl -s -X POST "https://gateway.thegraph.com/api/$KEY/subgraphs/id/B9mm21DKCex8ka4g8cteQU4NQqtviwmcTjQAYLbzQ1eR" \
-H 'content-type: application/json' \
-d '{"query":"{ globalStats(id:\"global\"){ tradesQuantity tradersCount } }"}'
There's also an MCP server that wraps these subgraphs together with Polymarket's Gamma and CLOB APIs: https://github.com/PaulieB14/graph-polymarket-mcp
Questions, bug reports, and schema requests are welcome in the comments or as GitHub issues.
If you'd rather not write GraphQL, Graph Advocate (graphadvocate.com) answers these kinds of questions for about $0.01 per call via x402.

