
A high-performance Substreams package for extracting and processing Polymarket prediction market data on Polygon, with built-in support for PostgreSQL, ClickHouse, and SQL sinks.
db_out module produces DatabaseChanges for direct use with substreams-sink-sqlethcommon:index_events filters| Contract | Address | Events |
|---|---|---|
| CTF Exchange | 0x4bfb41d5b3570defd03c39a9a4d8de6bd8b8982e |
OrderFilled, OrdersMatched, OrderCancelled, FeeCharged, TokenRegistered, TradingPaused/Unpaused, Admin/Operator changes, Factory updates |
| Conditional Tokens | 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045 |
ConditionPreparation, ConditionResolution, PositionSplit/Merge/Redeem |
| USDC (Collateral) | 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 |
Transfer, Approval |
┌─────────────────────────┐
│ sf.ethereum.type.v2.Block │
└────────────┬────────────┘
│
┌──────────────────┼──────────────────┐
▼ ▼ ▼
map_ctf_exchange_events map_ctf_events map_usdc_events
│
┌────────┼────────┐
▼ ▼ ▼
store_ store_ db_out ──▶ DatabaseChanges
total_ total_ │
order_ volume ┌────┴────┐
count ▼ ▼
PostgreSQL ClickHouse
| Module | Input | Output | Description |
|---|---|---|---|
map_ctf_exchange_events |
Block | CtfExchangeEvents |
Extracts all 13 CTF Exchange event types |
map_ctf_events |
Block | CtfEvents |
CTF condition/position events (placeholder) |
map_usdc_events |
Block | UsdcEvents |
USDC transfer/approval events (placeholder) |
map_trading_data |
Block | TradingData |
Enriched trading information |
db_out |
map_ctf_exchange_events + store deltas |
DatabaseChanges |
SQL/ClickHouse sink output |
| Store | Policy | Type | Description |
|---|---|---|---|
store_total_order_count |
add | bigint | Cumulative order fill count per market |
store_total_volume |
add | bigint | Cumulative trading volume per market |
git clone https://github.com/PaulieB14/Polymarket-Substreams.git
cd Polymarket-Substreams
substreams build
# Stream CTF Exchange events
substreams gui substreams.yaml map_ctf_exchange_events -e polygon.substreams.pinax.network:443
# Stream database changes (for sink testing)
substreams gui substreams.yaml db_out -e polygon.substreams.pinax.network:443
# 1. Setup the database schema
substreams-sink-sql setup "psql://user:password@localhost:5432/polymarket" ./substreams.yaml
# 2. Run the sink
substreams-sink-sql run "psql://user:password@localhost:5432/polymarket" ./substreams.yaml
# 1. Setup using ClickHouse schema
substreams-sink-sql setup "clickhouse://user:password@localhost:9000/polymarket" ./substreams.yaml --schema ./schema.clickhouse.sql
# 2. Run the sink
substreams-sink-sql run "clickhouse://user:password@localhost:9000/polymarket" ./substreams.yaml --engine clickhouse
Note: Pass the DSN on the command line, not in the manifest. The
schema.sql(PostgreSQL) andschema.clickhouse.sql(ClickHouse) files define the table structures.
| Table | Source Event | Key Fields |
|---|---|---|
order_fills |
OrderFilled | maker, taker, maker_asset_id, amounts, fee |
orders_matched |
OrdersMatched | taker_order_hash, asset IDs, amounts |
order_cancellations |
OrderCancelled | order_hash |
fee_charges |
FeeCharged | receiver, token_id, amount |
token_registrations |
TokenRegistered | token0, token1, condition_id |
trading_status_changes |
TradingPaused/Unpaused | pauser, status |
admin_changes |
NewAdmin/RemovedAdmin | admin, target_address, action |
operator_changes |
NewOperator/RemovedOperator | admin, target_address, action |
factory_updates |
ProxyFactory/SafeFactory Updated | factory_type, old/new factory |
| Table | Source Store | Description |
|---|---|---|
order_count_updates |
store_total_order_count |
Running fill count per market |
volume_updates |
store_total_volume |
Running volume per market |
mv_hourly_volume: Hourly trading volume, trade count, and fees per marketmv_trader_stats: Per-trader stats (trade count, total volume, fees paid)SELECT maker_asset_id, COUNT(*) AS fills, SUM(CAST(maker_amount_filled AS NUMERIC)) AS volume
FROM order_fills
GROUP BY maker_asset_id
ORDER BY fills DESC
LIMIT 20;
SELECT taker, COUNT(*) AS trades, SUM(CAST(fee AS NUMERIC)) AS total_fees
FROM order_fills
GROUP BY taker
ORDER BY trades DESC
LIMIT 20;
SELECT hour, trade_count, total_maker_volume
FROM mv_hourly_volume
WHERE maker_asset_id = '<MARKET_ID>'
ORDER BY hour DESC
LIMIT 24;
# Install Rust and wasm target
rustup target add wasm32-unknown-unknown
# Build
cargo build --target wasm32-unknown-unknown --release
# Or use the Substreams CLI
substreams build
├── abi/ # Contract ABI JSON
├── proto/
│ └── contract.proto # Protobuf definitions
├── src/
│ ├── abi/ # Generated ABI bindings
│ ├── pb/ # Generated protobuf code
│ └── lib.rs # Module handlers (maps, stores, db_out)
├── schema.sql # PostgreSQL DDL
├── schema.clickhouse.sql # ClickHouse DDL with materialized views
├── substreams.yaml # Module manifest with sink config
├── Cargo.toml # Rust dependencies
└── build.rs # ABI code generation
abi/proto/contract.protosrc/lib.rs and substreams.yamlschema.sql and schema.clickhouse.sqldb_out function# Package the substreams
substreams pack
# Publish to the registry
substreams publish
Contributions are welcome! See CONTRIBUTING.md for guidelines.
MIT - see LICENSE.
substreams gui polymarket@v0.2.0 map_ctf_exchange_eventssubstreams gui polymarket@v0.2.0 map_ctf_eventssubstreams gui polymarket@v0.2.0 map_usdc_eventssubstreams gui polymarket@v0.2.0 map_trading_datasubstreams gui polymarket@v0.2.0 db_outall_events gives you all the events in a block (from successful transactions), with basic block hash/number/timestamp and transaction hash
substreams gui polymarket@v0.2.0 ethcommon:all_eventssubstreams gui polymarket@v0.2.0 store_total_order_countsubstreams gui polymarket@v0.2.0 store_total_volumeindex_events sets the following keys on the block:
substreams gui polymarket@v0.2.0 ethcommon:index_events