The chain already maintains your exchange's core objects: a factory event registers every pool, and each pool's log stream carries its trades. SQD serves the PairCreated, PoolCreated, and V4 Initialize events that build the pool registry, plus the swap, mint, burn, and sync streams behind charts and price APIs, across 225+ networks. A deployment on another chain is the same handler with the dataset name and factory address swapped.
Every pool in the list, every candle, every open position is read back off the chain. Rebuilt the naive way, that means paginating millions of blocks over eth_getLogs against per-provider caps, standing up a separate indexer for each chain the protocol deploys to, and polling slot0 or getReserves per pool per block for state. All of it is onchain already; the cost is in how you read it.
The root object a DEX renders is the pool registry, and the chain already maintains it: a factory emits exactly one creation event per pool. PairCreated on Uniswap V2 forks, PoolCreated on V3 forks, Initialize on the V4 PoolManager. Filter the factory's address and that event's topic0, and the stream from the factory's deployment block to the chain head is your registry.
The Uniswap V3 factory (0x1f98…f984) emitted its first PoolCreated at block 12,369,739 on 2021-05-04, registering the UNI/WETH 0.3% pool. 10,230,365 blocks later, at block 22,600,104, the same filter returns a new 1% pool:
The new pool is 0x2c28…3fcd, and the same transaction (0x0cf7…f996) carries the pool contract's create trace, which the Portal serves from the same endpoint. This page is the exchange operator's data stack; for the consumer side, liquidations, MEV, and aggregated markets, see DeFi & Trading.
The registry row above comes back from one bounded query. Set fromBlock to 12,369,739 and drop toBlock, and the same filter is the factory's complete history:
One gotcha: the field a registry actually needs, the pool address, is not in the topics. PoolCreated indexes token0, token1, and fee, and leaves tickSpacing and the pool address ABI-encoded in data. A topics-only pipeline decodes everything except the address it came for; word 2 of data is the pool.
Rebuilding this registry over eth_getLogs means paginating those 10.2 million blocks against per-provider window caps, some as small as 50 blocks per call (the verified caps). The Portal takes the whole range in one query shape and streams back only the blocks that match; the Squid and Pipes SDKs decode against the ABI and resume the stream for you.
A deployment elsewhere is the dataset name and the factory address swapped, not a second indexer. On base-mainnet, the identical query shape with Aerodrome's factory (0x420d…40da) and its own PoolCreated topic0 returns pool 0xfe7f…3330 at block 31,000,872, with token0 the canonical Base WETH and the factory's running pool count, 6,627, in the second data word. PancakeSwap runs this pattern in production across BNB Chain, Ethereum, Base, Arbitrum One, and more.
Uniswap V4 has no factory and deploys no pool contracts: every pool lives inside one PoolManager (0x0000…8a90) and is a bytes32 id, not an address. Discovery reads the PoolManager's Initialize events: at block 22,600,073 the first id in our scan window was 0xa036…d815. A registry keyed on addresses needs a second key type for V4, and every pool's events now land in a single contract's log stream. That concentration is what moved UNCX's locker indexing to SQD.
Once the registry knows a pool, the pool's own log stream carries the order flow. One block after the registry row above, at block 22,600,105, the USDC/WETH 0.05% pool (0x88e6…5640) settled a single swap (0x61fe…a07c). Its five data words carry the whole trade and the pool's state after it:
The two prices this row yields must reconcile, and they do: 34,401.181986 USDC over 13.703287655962952718 WETH is a paid average of 2,510.43, while sqrtPriceX96 works out to 2,509.60. The first includes the pool's 0.05 percent fee and averages across the range the trade crossed; the second is the pool's marginal price after the trade. A candle API stores the second; the first is what the trader paid.
The query is the discovery filter with the address and topic0 swapped, the same shape on every pool and every chain:
Two mechanics to respect. topic0 is global: every V3 fork, and any unrelated contract, can emit an event with this exact signature, so a production feed filters by the pool set discovered from the factory, never by topic0 alone. And on V2-style pools one swap lands as three logs in one transaction, Fees, Sync, and Swap (verified on an Aerodrome pool at Base block 31,000,280, 0x4bdf…957e): Sync holds the post-trade reserves, so reserve and TVL series ride the same stream.
The alternative is polling: a chart backend on raw RPC calls slot0 or getReserves per pool per block, multiplied by every deployment. Here the executed price, size, and block timestamp arrive in one row, and candles are an aggregation of the stream. GMX runs its multichain perp DEX data layer on SQD; the traces guide covers the create-trace and internal-call side.
Live queries against real blockchain data. Pick a network, choose a query, hit run.
The public endpoint is free for development. See plans for dedicated portals and higher limits.
Indexes trading and liquidity data across BNB Chain, Ethereum, Base, Arbitrum One, and more, one handler per pattern.
Runs its multichain perp DEX data layer on SQD, the same query shape across every deployment.
Moved its liquidity-locker indexing to SQD when V4 concentrated every pool's events into one contract.
One filter on the factory address and the creation event's topic0 returns every PairCreated or PoolCreated from the deployment block to head. The gotcha is handled downstream: the new pool's address arrives ABI-encoded in the data section, not in a topic.
A pool's log stream carries its order flow: executed price and size in the Swap data words, post-trade reserves in a V2-style Sync. Candles, volume, and TVL series are aggregations of that stream, not per-block slot0 or getReserves polling.
The event ABI is identical wherever the same contracts are deployed, so a multi-chain DEX is one handler with the dataset name and factory address swapped per chain. PancakeSwap runs this pattern across BNB Chain, Ethereum, Base, Arbitrum One, and more.
Uniswap V4 deploys no pool contracts: every pool is a bytes32 id inside one PoolManager, and all its events land in a single log stream. Discovery reads the PoolManager's Initialize events; the Portal serves that stream the same way it serves a factory's.
The events, transactions, and traces are public. The work a provider saves you is in the reading, and it compounds with every pool and every chain.
See this on your own contracts
Tell us the chains and contracts you care about, and we will show you the query that returns them.
Transfers, mint and burn, and peg signals read from DEX trades.
Issuance, transfers, and the issuer control events a token API omits.
Item ownership, game currencies, and marketplace settlement onchain.
Registrations, delegation, and the social graph that stays onchain.
Deployments as CREATE traces, LP creation, and the first trades.
Private Portal. Dedicated. Validated. Managed. Tell us what you're building, we'll show you what it looks like on SQD.