TWAP (Time-Weighted Average Price)
A price calculation method that averages asset prices over a time period to resist short-term manipulation.
Time-Weighted Average Price (TWAP) is a pricing mechanism that calculates the average price of an asset over a specified time period, providing manipulation-resistant price data for DeFi protocols. Unlike spot prices that reflect instantaneous market conditions, TWAP smooths out short-term volatility and makes flash loan attacks economically impractical. TWAP oracles are commonly built on top of DEX liquidity pools, most notably Uniswap, and serve as on-chain price references for lending protocols, derivatives, and other DeFi applications.
Why TWAP Matters
Spot prices can be manipulated within a single transaction:
1Block N:21. Attacker takes flash loan (1M USDC)32. Swaps USDC → ETH on Uniswap (moves price up 20%)43. Uses inflated ETH price in vulnerable protocol54. Profits from price difference65. Swaps back, repays flash loan
TWAP defeats this by averaging prices over time—manipulating a 30-minute TWAP requires holding the manipulated price for 30 minutes, which is economically prohibitive.
How TWAP Works
TWAP accumulates price observations over time:
1TWAP = (Price₁ × Time₁ + Price₂ × Time₂ + ... + Priceₙ × Timeₙ) / Total Time
In Uniswap V2/V3, the contract tracks cumulative price-time values:
1// Uniswap V2 accumulator (simplified)2price0CumulativeLast += price0 * timeElapsed;3price1CumulativeLast += price1 * timeElapsed;45// To get TWAP between two observations:6twap = (priceCumulativeEnd - priceCumulativeStart) / (timeEnd - timeStart);
Uniswap V3 TWAP
Uniswap V3 stores observations in a circular buffer:
1import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";2import "@uniswap/v3-periphery/contracts/libraries/OracleLibrary.sol";34function getTWAP(5 address pool,6 uint32 period7) external view returns (uint256 price) {8 (int24 arithmeticMeanTick,) = OracleLibrary.consult(pool, period);910 price = OracleLibrary.getQuoteAtTick(11 arithmeticMeanTick,12 1e18, // Base amount13 token0, // Base token14 token1 // Quote token15 );16}
TWAP Period Selection
| Period | Manipulation Resistance | Responsiveness |
|---|---|---|
| 1 minute | Low | High |
| 10 minutes | Medium | Medium |
| 30 minutes | High | Low |
| 1 hour+ | Very High | Very Low |
Trade-off: Longer periods are more secure but respond slower to legitimate price movements.
TWAP vs Chainlink
| Aspect | TWAP | Chainlink |
|---|---|---|
| Data source | On-chain DEX | Off-chain APIs |
| Decentralization | Fully on-chain | Network of nodes |
| Manipulation cost | Time-based | Economic (stake) |
| Freshness | Configurable | Heartbeat-based |
| Coverage | DEX-listed pairs only | Curated feeds |
| Gas cost | Lower | Higher |
Many protocols use both: Chainlink as primary, TWAP as fallback or sanity check.
Security Considerations
Low Liquidity Pools
TWAP from low-liquidity pools is easier to manipulate:
1// Check pool has sufficient liquidity2require(pool.liquidity() > MIN_LIQUIDITY, "Insufficient liquidity");
Stale Observations
Pools with low trading activity may have outdated observations:
1// Verify observation is recent2(,, uint16 observationIndex, uint16 observationCardinality,,,) = pool.slot0();3(uint32 observationTimestamp,,,) = pool.observations(observationIndex);4require(block.timestamp - observationTimestamp < MAX_STALENESS, "Stale TWAP");
Price Deviation Attacks
Gradual price manipulation over the TWAP window:
1// Compare TWAP to spot price2uint256 spotPrice = getSpotPrice();3uint256 twapPrice = getTWAP(30 minutes);4uint256 deviation = calculateDeviation(spotPrice, twapPrice);5require(deviation < MAX_DEVIATION, "Price deviation too high");
Implementation Patterns
Dual Oracle System
1function getPrice() external view returns (uint256) {2 uint256 chainlinkPrice = getChainlinkPrice();3 uint256 twapPrice = getTWAP();45 // Require prices within 5% of each other6 uint256 deviation = diff(chainlinkPrice, twapPrice) * 10000 / chainlinkPrice;7 require(deviation < 500, "Oracle deviation");89 // Return average or prefer one source10 return (chainlinkPrice + twapPrice) / 2;11}
Circuit Breaker
1uint256 public lastPrice;23function getSecurePrice() external returns (uint256 price) {4 price = getTWAP();56 if (lastPrice > 0) {7 uint256 change = diff(price, lastPrice) * 10000 / lastPrice;8 require(change < MAX_PRICE_CHANGE, "Circuit breaker triggered");9 }1011 lastPrice = price;12}
Audit Checklist
When auditing TWAP implementations:
- Sufficient observation period for the use case
- Pool liquidity requirements enforced
- Staleness checks on observations
- Deviation checks against other price sources
- Proper decimal handling
- Edge cases (pool just created, no observations)
TWAP oracles provide a trust-minimized, manipulation-resistant price source for DeFi protocols, but require careful implementation to avoid edge cases and ensure sufficient security for the specific use case.
Related Terms
Oracle
A service that provides external data (prices, events, random numbers) to smart contracts that cannot access off-chain information directly.
Price Manipulation
Attacks that artificially move asset prices to exploit protocols relying on those prices for critical operations.
Flash Loan
Uncollateralized loan borrowed and repaid within a single transaction, often used for arbitrage or attacks.
Automated Market Maker (AMM)
A decentralized exchange protocol that uses mathematical formulas to price assets instead of order books.
Need expert guidance on TWAP (Time-Weighted Average Price)?
Our team at Zealynx has deep expertise in blockchain security and DeFi protocols. Whether you need an audit or consultation, we're here to help.
Get a Quote
