The contract derives a price from an AMM's live reserves (getReserves / balanceOf of the pair) instead of a manipulation-resistant TWAP or a Chainlink feed. A single flash-loan swap moves the spot price within one transaction, so any value read this way can be inflated or crushed at will.
// Attacker manipulates the spot price inside one tx function attack() external { uint256 loan = pool.flashLoan(50_000e18); // 1. borrow router.swap(loan, address(token)); // 2. skew reserves -> price spikes victim.borrowAgainst(collateral); // 3. over-borrow at fake price router.swap(...); // 4. swap back pool.repay(loan); // 5. repay, keep profit }
// Use a TWAP or a decentralized feed, never live reserves
(, int256 answer,,uint256 updatedAt,) = chainlinkFeed.latestRoundData();
require(answer > 0 && block.timestamp - updatedAt < 3600, "stale price");
uint256 price = uint256(answer);
Largest recorded losses in the same failure class — related, not the same bug:
The SaferICO scanner runs 201 detectors over your Solidity source, SAFE-0101 among them. Paste an address or the source itself — a small per-scan fee, shown before you sign, or unlimited on any plan.