Skip to content

Spot-Price Oracle from AMM Reserves

SAFE-0101 Oracle / Price Checked automatically by the scanner
1

What goes wrong

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.

2

The vulnerable pattern

proof of concept — how it is exploited
// 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
}
3

How to fix it

the pattern that is safe
// 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);
Cheese Bank / Warp Finance oracle manipulations. Use Chainlink or a TWAP.
4

Where this has happened

Largest recorded losses in the same failure class — related, not the same bug:

Check your own contract for this

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.

Run the scanner See how it is attacked Read the docs