oracle-manipulationlisted
Install: claude install-skill iktok90-design/ai-smart-contract-auditor
# Oracle manipulation detection
## When this applies
Any code that consumes a price feed or derives a price from on-chain state:
- Chainlink: `latestAnswer`, `latestRoundData`, `getRoundData`
- Uniswap V2: `getReserves`, `getAmountsOut`, `price0Average`
- Uniswap V3/V4: `slot0`, `observe`, `consult`
- Curve: `get_virtual_price`, `get_dy`
- Balancer: `getRate`
- Custom oracle modules, on-chain TWAPs
- LP token pricing, collateral valuation, liquidation thresholds, mint/burn rates
## Detection patterns
### Spot price from AMM (CRITICAL — funds at risk)
```solidity
(uint112 r0, uint112 r1,) = pair.getReserves();
uint256 price = r1 * 1e18 / r0; // ← flash-loan manipulable in one block
```
### Stale Chainlink data (HIGH)
```solidity
(, int256 answer,,,) = feed.latestRoundData(); // ← ignores updatedAt and answeredInRound
```
Required checks:
- `updatedAt != 0`
- `block.timestamp - updatedAt <= heartbeat` (with chain-specific tolerance)
- `answeredInRound >= roundId`
- `answer > 0`
- Heartbeat sanity: ETH/USD is 1h on mainnet but 24h on some L2s — verify
### `latestAnswer` (deprecated, no freshness) (HIGH)
```solidity
int256 p = feed.latestAnswer(); // ← deprecated, prefer latestRoundData
```
### Single-source dependence (HIGH)
Only one oracle, no fallback, no cross-check against a second source.
### Uniswap V3 `slot0` without TWAP (CRITICAL)
```solidity
(uint160 sqrtPriceX96,,,,,,) = pool.slot0(); // ← spot, manipulable
```
Use `observe()` for TWAP with suffic