An on-chain price is a ratio that anyone can recompute. In a constant product pool the price of token A in terms of token B is the pool’s balance of B divided by its balance of A. Both balances sit in a public contract that can be read at any block. A DEX-native price feed applies that idea across many pools: it computes the price from the pools themselves (what they hold, what they executed and how much depth sits near the price) and pins the result to one block. Every input stays public, so the number can be checked rather than taken on trust.
Pool-state pricing is a method that other providers apply too, each in its own way. This article explains the method itself: where the numbers come from, why a set of pools measures a market better than one pool and what a reader can verify.
Where an on-chain price is born
A traditional exchange matches buyers and sellers. An automated market maker replaces that matching with a pool holding reserves of two tokens. A trader swaps against the pool, the reserves change and the relative price moves with them. Uniswap, a widely used design, keeps the product of the two reserves from falling after a trade, written x * y = k.
Two consequences matter for anyone reading prices from pools.
- The price is a function of state. For a constant product pool the marginal price, before fees, is one reserve divided by the other. Nothing needs to be reported to anyone: the contract already holds the inputs.
- Size moves the price. A trade that is large relative to the reserves shifts the ratio further than a modest one. Price impact is the pool’s own measure of how much a given trade would move the market.
Why would a pool’s ratio track the wider market at all? Arbitrage. When the pool price drifts from the market by more than the trading fee, a trader profits by swapping until the gap closes. The Uniswap v2 whitepaper makes this argument directly: the pool tends to follow the relative market price because someone is paid to make it so.
Pools are not all built alike. That shapes how a price is read.
| Pool design | State that matters | Price read from |
|---|---|---|
| Constant product | Two reserves | Ratio of the reserves |
| Concentrated liquidity | Liquidity and a square-root price | The square-root price |
| Stable-asset curve | Balances and an amplification setting | The invariant at current balances |
| Weighted pool | Balances and weights | Balance ratio adjusted by weights |
In concentrated liquidity pools, providers place capital inside a chosen price range. Only liquidity whose range contains the current price is active. A reader of such a pool queries the pool for its liquidity and its square-root price rather than for two simple reserves. Stable-asset pools use a curve that blends constant sum with constant product, so that swaps between assets meant to be worth the same move the price far less than a constant product pool would. Weighted pools extend the constant product idea to uneven weights and to more than two tokens.
The practical lesson is that “pool state” means different things in different pools. A price read has to know each pool’s math before it can turn state into a number.
Pinned to a block
Pool state changes whenever a swap lands. A question such as “what is the price” has no stable answer until it names a moment. On a blockchain the natural moment is a block. Ethereum’s JSON-RPC interface lets state queries carry a block parameter that sets the height at which the chain is read. A call made with eth_call runs a contract function against that state without creating a transaction.
The block can be named by number or, since EIP-1898, by hash. A hash identifies exactly one block even if a competing branch of the chain existed at the same height, so a reader keeps a coherent picture of state. On Ethereum mainnet a new block arrives about every twelve seconds. Reading old blocks needs a node that keeps historical state, which not every endpoint serves.
We checked the effect on 23 October 2026 against a public Ethereum endpoint. Two identical reserve reads at one pinned block returned identical values. The price of a concentrated liquidity pool changed in most of ten consecutive block steps. The repeatable read is what makes a reading checkable. The change across blocks is why the block has to be stated.
Why one pool is not enough
The spot price of a pool is what that pool would quote right now. Because trades change it directly, it can be moved on purpose. The v2 whitepaper sketches the pattern for the v1 spot price: an attacker buys from a pair to inflate the price, triggers a contract that settles at the inflated price, then sells back to restore it, possibly within one atomic transaction. The v2 documentation adds that reading a pair’s reserves and relying on the result without an outside price is not safe. It also notes that oracle implementations have been the main attack route in numerous hacks.
Time averaging is one response. A time-weighted average price accumulates the price second by second. The trade-off is lag, since an average follows a real move late. It answers a different question from a measurement of the market now. The guide to TWAP, VWAP and liquidity-weighted prices compares the options.
The other response is breadth. A market for an asset is rarely a single pool. Several pools on several chains can quote the same pair, with different amounts of capital behind each. A composition reads all of them and weights each by the liquidity it holds, so a pool with little liquidity carries little weight. Anomalous prints and stale pools are excluded before publication. The design intent is that a spike confined to one pool does not reach the published rate. The methodology page describes the approach in full. Case studies of attacks and the defences that held up are in the article on price oracle manipulation.
Each pool in a composition is a public contract. The feed serves the pools and weights behind every reading, so a reader who doubts a number can go to the pools and look.
Computed from pools, or reported by a venue
An exchange publishes prices built from its own order book: buyers and sellers post orders at price levels. The book is filled as demand shifts. A ticker or last-trade price is the exchange’s record of its own matching. To check it, a reader relies on the venue’s records. That arrangement works well for assets that trade mostly on exchanges.
A DEX-native price starts somewhere else. A trader faces the pool instead of another trader’s order, the pool’s state lives on a public chain and the protocols involved are permissionless, so anyone can read that state. The price is recomputed from the chain rather than relayed from a venue or from an aggregator that collects venue reports.
For many on-chain assets, that difference decides which method is appropriate. Many liquid staking tokens, yield-bearing stablecoins and wrapped bitcoin variants trade mainly in on-chain pools. Some are not listed on any exchange, so no exchange price exists to read. For a token like these, the on-chain market is the primary record of what the token trades for, not a fallback.
The two methods fail in different places, which is why the comparison of CEX and DEX pricing treats them as a pair. For liquid staking tokens, a related distinction applies: the market rate is what the token trades for, while the protocol’s own exchange rate can be read from its contract. How liquid staking tokens are priced separates the two.
Who reads a price like this
Three kinds of readers can use pool-state prices. Each asks a slightly different question.
- Protocols that value collateral need a price that a single block or a single pool cannot move.
- Risk and treasury teams mark holdings and watch for stress. They can use the price together with its conditions to see whether a token is drifting from its anchor.
- Oracle networks and other applications can read from a measurement layer and deliver the result onward. That is where ML Data sits: the measurement layer that applications and oracle networks read from, with the delivery left to them.
On the vocabulary, a price oracle in the general sense is any tool for viewing price information about an asset. Delivering a value to a smart contract is one job. Computing that value from the market is another. A feed is the output of the second job.
A price also says nothing about how much can trade at it. Two pools can quote the same rate while one of them would move sharply on a large order. That is why the feed returns the market depth within one percent alongside the rate, the amount that can trade before the price moves one percent in either direction.
Reading a feed page
For every pair the feed returns the price together with the conditions it was made in, from the same block:
- the market rate for the pair
- depth within one percent, up and down
- liquidity and volume over 24 hours and 7 days
- a venue breakdown listing each pool with its chain, exchange, liquidity and weight in the rate
- a block reference, the block each snapshot is pinned to, so the rate is checkable
The ETH/USD feed page shows the public part of this: the rate, its block time, depth within one percent and the composition by chain. The walkthrough of a feed page covers each element and how readings are labelled. The data feeds overview describes the same fields at product level. The coverage page lists the pairs available.
For a team that wants to verify a reading, the path is short. Take the block reference, read the pools from the venue breakdown at that block, apply each pool’s own math and compare the weighted result with the published rate. The API page covers programmatic access.
Sources
- How Uniswap Works
- Uniswap v2 Pricing
- Uniswap v2 Oracles
- Concentrated Liquidity
- Fetching Pool Data with the v3 SDK
- Uniswap v2 Core whitepaper
- Uniswap v3 Core whitepaper
- StableSwap: efficient mechanism for Stablecoin liquidity
- Balancer Weighted Pools
- Ethereum JSON-RPC API
- Oracles
- EIP-1898: Add blockHash to defaultBlock methods