# Broken TWAP validation allows spot-price manipulation and renders slippage checks ineffective

Olas UniswapPriceOracle.validatePrice() algebraically collapses its 'TWAP' to the current spot price, nullifying slippage checks and enabling same-block flash-loan manipulation of buybacks and V2 liquidity exits.

- Payout: Contest reward
- Severity: high
- Program: Olas
- Credited: BenRai
- Disclosed: 2026-05-18
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2026-01-olas#h-01
- Library page: https://bugbountylibrary.com/r/c4%3A2026-01-olas%3AH-01
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:flash-loan vuln:oracle-manipulation

**Target:** UniswapPriceOracle.validatePrice() in autonolas-tokenomics
**Root cause:** The 'TWAP' is built as cumulativePriceLast + tradePrice*elapsedTime then subtracted from itself and divided by elapsedTime, which algebraically equals tradePrice. No persisted cumulative snapshots are used, so the average always equals current spot.
**Steps:**
1. Read validatePrice() at UniswapPriceOracle.sol L55-L91.
2. Note cumulativePrice = cumulativePriceLast + (tradePrice * elapsedTime).
3. Note timeWeightedAverage = (cumulativePrice - cumulativePriceLast) / elapsedTime.
4. Simplify: equals tradePrice regardless of history/liquidity.
5. Deviation is always ~0, so `require(validatePrice(maxSlippage))` always passes.
6. Flash-loan, swap to move V2 pool spot, trigger buyBack()/convertToV3() in same block, unwind.
**How found:** Code-reading of the TWAP construction: noticing the artificial cumulative price is built from tradePrice itself and then subtracted from itself, revealing the algebraic collapse to spot.
**Exploitation:** Attacker observes a buyBack() or convertToV3() tx, flash-loans to move the Uniswap V2 pool price, lets the victim tx execute in the same block (validatePrice passes since TWAP==manipulated spot), then reverses the swap and pockets arbitrage; protocol receives worse OLAS/quote amounts.
**Insight:** When auditing oracle 'TWAP' code, substitute the formula algebraically: if the cumulative price is constructed from the same spot value being validated, the average trivially equals spot. Real Uniswap V2 TWAPs require persisted cumulative snapshots across blocks, not blockTimestampLast from getReserves().
