# V3Oracle susceptible to price manipulation

V3Oracle.getValue() derives position token amounts from manipulable Uniswap slot0 spot price, letting a flash-loan price distortion inflate/deflate collateral value while TWAP check passes.

- Payout: Contest reward
- Severity: medium
- Program: Revert Lend
- Credited: b0g0
- Disclosed: 2024-05-22
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2024-03-revert-lend-findings/issues/175
- Library page: https://bugbountylibrary.com/r/c4%3A2024-03-revert-lend%3AM-19
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:business-logic vuln:flash-loan vuln:oracle-manipulation

**Target:** V3Oracle.getValue() / Uniswap V3 position valuation
**Root cause:** getPositionBreakdown() computes amount0/amount1 via LiquidityAmounts.getAmountsForLiquidity using slot0 sqrtPriceX96 (spot price) rather than the oracle price, so position value depends on a manipulable input even though the price itself is TWAP/Chainlink-validated.
**Steps:**
1. Configure V3Oracle with a TWAP duration (e.g. 1 hour); TWAP reports 4000 USDC/WETH.
2. Attacker takes a flash loan and swaps heavily in the Uniswap V3 pool to distort slot0 spot price within one block.
3. In the same transaction call borrow/repay on V3Vault, which invokes V3Oracle.getValue().
4. getPositionBreakdown() -> _initializeState() reads slot0 sqrtPriceX96; _getAmounts() computes inflated/deflated amount0/amount1 for the position.
5. value = price0X96*(amount0+fees0)/Q96 + price1X96*(amount1+fees1)/Q96 uses the manipulated amounts.
6. _checkPoolPrice() compares spot to Chainlink-derived price; TWAP barely moves so the check passes.
7. Attacker borrows/repays at favorable terms, then unwinds the swap.
**How found:** Code reading: noticed getValue() multiplies oracle-validated prices by amounts derived from slot0 spot price; reasoned that price-manipulation protection covers only the price factor, not the amount factor, and that TWAP-based _checkPoolPrice tolerates large single-block spot deviations.
**Exploitation:** Single-transaction flash-loan swap distorts the pool spot price; the same tx calls V3Vault borrow/repay which prices the position using manipulated amount0/amount1 while oracle price checks pass, yielding favorable borrow/repay terms. Impact concentrated on tight-range positions; wide-range positions only slightly manipulable.
**Insight:** When an oracle validates a price but the position's token amounts are still derived from slot0, the value is manipulable through the amount factor; check every input to a valuation formula, not just the price, and note tight-range positions amplify amount distortion.
