Neither average is better, because they answer different questions. A time-weighted average price (TWAP) asks where the price sat over a stretch of time. A volume-weighted average price (VWAP) asks where trading happened. A liquidity-weighted price asks where size could trade right now. Each has a weak point as a reference: a TWAP lags real moves, a VWAP follows volume that can be manufactured and a liquidity weighting depends on how liquidity is counted.
Both averages also serve as benchmarks for trade execution. This article is about the other job: producing the one number that a lender, a risk system or a contract reads as the price of an asset.
TWAP: where the price sat
A TWAP weights each price by how long it stood. Uniswap v2 makes this cheap to compute. The pool keeps a running sum that adds the current price for every second that passes. To average over any window, a caller reads the sum at the start and again at the end, subtracts and divides by the seconds in between:
TWAP = (a_end - a_start) / (t_end - t_start)
Here a is the running sum. The contract does not keep a history of it, so the caller has to read and store the starting value itself.
The sum is updated with the price standing at the start of a block, which is the price after the last trade of the previous block. That detail is the defence. In the v2 whitepaper, Uniswap’s authors call the v1 spot price unsafe as an oracle because it is easy to manipulate, possibly inside a single transaction or by a miner who controls transaction order. A price recorded between blocks forces an attacker to leave a distorted price standing at the end of a block, with no guarantee of trading it back in the next.
A hypothetical example shows the effect. Take 100 blocks at a price of 2,000, with one block pushed to 3,000. A contract that reads the spot price sees 3,000. A contract that reads the TWAP over the 100 blocks sees 2,010.
The window is a trade-off
The same property that makes a push expensive makes the average slow. Uniswap’s v2 whitepaper says a longer window costs an attacker more but gives a less up-to-date price. Uniswap’s docs add that the cost of manipulating a simple TWAP rises roughly in line with the liquidity of the pool and with the length of the window. They also say that block-level measurement alone is not enough when a lot of value settles on the price: an attack can still pay.
In a real move the TWAP spends the whole window catching up. A system that liquidates on a TWAP accepts a late price in exchange for one that is harder to move. Weighting recent prices more, as an exponential moving average does, shortens the lag but makes the oracle cheaper to manipulate, according to the Uniswap guide on building an oracle.
Uniswap v3: ticks and a geometric mean
Uniswap v3 changed what the pool sums. It accumulates the tick, which is the log of the price, multiplied by seconds. The price at tick i is 1.0001^i, so an average tick converts back to a price:
TWAP = 1.0001 ^ mean_tick
mean_tick = (a_end - a_start) / (t_end - t_start)
An arithmetic mean of ticks is a geometric mean of prices. A mean tick of 100,000, the figure used in the Uniswap docs, gives a price of about 22,015.5 units of the second token per unit of the other.
The reason for the switch is a quirk of averages. Say the USD price of ETH is 100 in one block and 300 in the next. The average USD per ETH is 200, but the average ETH per USD is 1/150, not 1/200. An arithmetic TWAP therefore depends on which way round the pair is quoted, which is why v2 tracks two accumulators. The v3 whitepaper says the geometric mean avoids the need for separate accumulators.
V3 also keeps a list of past checkpoints in a circular buffer, written at most once per block. A pool starts with room for one. Anyone willing to pay the gas can raise the count by calling increaseObservationCardinalityNext, so how far back a v3 TWAP can reach is a setting of each pool, not a constant. Reading goes through observe. A request older than the stored history reverts. Uniswap v4 has no built-in oracle.
VWAP: where trading happened
A VWAP weights each trade by its size:
VWAP = sum(price * volume) / sum(volume)
The sums run over the trades in the window. Exchange documents write it the same way: the NYSE volume summary specification divides the total of price times volume per trade by total volume. The Cboe Futures Exchange rule filing for a settlement VWAP does so for contracts traded in a 30-second interval. That filing also shows that the window and the trades that qualify are rule choices, not part of the formula.
The inputs differ from a TWAP. A TWAP needs the price at each block and the seconds between blocks. A VWAP needs the reported size of every trade, so it is as good as the volume it is fed.
Volume can be manufactured
Here is a hypothetical example. Three honest trades of 100 units each at 2,000, 2,002 and 1,998 give a VWAP of 2,000. Add 900 units of self-trading at 2,100 and the VWAP becomes 2,075. Three quarters of the volume is invented and the average has moved by 75.
Wash trading is a documented problem, not a thought experiment. The US Commodity Futures Trading Commission defines it as entering transactions to give the appearance that purchases and sales have been made, without incurring market risk or changing the trader’s position. Three sources show its scale and scope:
- A study of 29 centralized exchanges using 2019 data, published in Management Science in 2023, found that wash trading averaged more than 70% of reported volume across the unregulated exchanges it examined. The regulated exchanges in the sample showed the transaction patterns expected of real markets. The authors also found that fabricated volume temporarily distorted prices.
- A 2021 study of two order-book decentralized exchanges, IDEX and EtherDelta, found that more than 30% of the tokens traded on them had been subject to wash trading. It covered order-book venues, not automated market maker pools.
- On 9 October 2024 the US Securities and Exchange Commission announced fraud charges against three companies purporting to be market makers and nine individuals. As alleged, they self-traded on trading platforms and used bots that at times generated billions of dollars of artificial volume each day.
None of this says volume is always fake. It says a VWAP assumes volume reflects real risk-taking. That assumption has to be checked venue by venue.
Liquidity weighting: where size could trade now
We found no standard definition of a liquidity-weighted price to cite, so here it is a plain description of an approach. Take a price from each venue and weight it by the liquidity available near that price. A venue that could absorb a large trade near the quoted price counts for more than one that could not.
It is a different kind of average. A TWAP looks back over time and a VWAP looks back over trades. A liquidity weighting looks at the state of the pools at a moment and asks what the market could do, not what it did. The question matters because a price says nothing about size: how far a trade moves a pool is covered in price impact and slippage.
The nearest relative in Uniswap’s own design is the v3 liquidity accumulator, which records in-range liquidity over time for one pool. The v3 whitepaper says it can help a contract decide which of the pools for a pair will have the most reliable TWAP. It is a per-pool measure, not a price across venues. The docs advise using it with care.
The approach has two weak points. It needs a rule for what counts as near the price. And a reading of liquidity at one moment is a snapshot like the spot price, so on its own it carries the same single-moment exposure that time averaging was designed to reduce.
Matching the average to the job
| Average | Question | Weak point |
|---|---|---|
| TWAP | Where did the price sit? | Lags real moves |
| VWAP | Where did trading happen? | Volume can be invented |
| Liquidity weighting | Where could size trade now? | Needs a rule and a moment |
A risk team can reasonably want more than one of these, since the weak points differ. A time average is slow to move when the market moves, which matters for liquidations. A volume average is as honest as the venues behind it. A liquidity weighting needs protection against a single-moment push, which time can add.
Published rates that weight by liquidity, such as the Ethereum price feed and the Solana price feed, address the third question. How ML Data weights is described on the methodology page. The background on how an on-chain price is measured is in DEX-native price feeds explained. The article on price oracle manipulation follows each weak point above into the attacks that have used it.
Sources
- Uniswap Docs: Uniswap v2 Oracles
- Uniswap Docs: Building an Oracle
- Uniswap v2 Core whitepaper, section 2.2 Price oracle
- Uniswap Docs: Price Oracles (v3)
- Uniswap v3 Core whitepaper, section 5 Oracle upgrades
- NYSE Volume Summary Client Specification, v1.0a, 22 May 2017
- Cboe Futures Exchange rule certification CFE-2021-001, Daily Settlement VWAP
- CFTC Glossary: Wash Trading
- Cong, Li, Tang and Yang: Crypto Wash Trading, Management Science 69(11), 2023
- Victor and Weintraud: Detecting and Quantifying Wash Trading on Decentralized Cryptocurrency Exchanges, 2021
- SEC press release 2024-166: SEC Charges Three So-Called Market Makers and Nine Individuals in Crackdown on Manipulation of Crypto Assets Offered and Sold as Securities