DEV Community

Cover image for Price Oracle Manipulation:
Mhammed Talhaouy
Mhammed Talhaouy

Posted on

Price Oracle Manipulation:

Price oracles are a critical component of DeFi. They provide smart contracts with off-chain data, like asset prices. But if an attacker can manipulate that data, the consequences can be severe. This is called *Price Oracle Manipulation *.

Let’s break it down with a simple example.


Vulnerable Smart Contract Example

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

interface IPriceOracle {
    function getPrice(address token) external view returns (uint256);
}

contract LendingProtocol {
    IPriceOracle public oracle;
    mapping(address => uint256) public collateral;
    mapping(address => uint256) public debt;

    constructor(address _oracle) {
        oracle = IPriceOracle(_oracle);
    }

    function depositCollateral(address token, uint256 amount) external {
        collateral[msg.sender] += amount;
    }

    function borrow(address token, uint256 amount) external {
        uint256 price = oracle.getPrice(token);
        require(amount <= collateral[msg.sender] * price / 2, "Insufficient collateral");
        debt[msg.sender] += amount;
    }
}
Enter fullscreen mode Exit fullscreen mode

What’s happening here?

  • The contract uses an oracle to fetch token prices.
  • Collateral determines how much a user can borrow.
  • If the oracle price is manipulated, the contract can lend more than it should, opening the door for exploits.

Attack Scenario

  1. Attacker manipulates the price feed of token on the oracle (via flash loans or low-liquidity pools).
  2. The contract thinks the collateral is worth more than it actually is.
  3. Attacker borrows excessive funds and drains the protocol.

Safe Implementation Using Chainlink Price Feeds

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract SafeLendingProtocol {
    AggregatorV3Interface public priceFeed;
    mapping(address => uint256) public collateral;
    mapping(address => uint256) public debt;

    constructor(address _priceFeed) {
        priceFeed = AggregatorV3Interface(_priceFeed);
    }

    function getLatestPrice() public view returns (uint256) {
        (,int256 price,,,) = priceFeed.latestRoundData();
        return uint256(price);
    }

    function depositCollateral(address token, uint256 amount) external {
        collateral[msg.sender] += amount;
    }

    function borrow(address token, uint256 amount) external {
        uint256 price = getLatestPrice();
        require(amount <= collateral[msg.sender] * price / 2, "Insufficient collateral");
        debt[msg.sender] += amount;
    }
}
Enter fullscreen mode Exit fullscreen mode

Why this is safer:

  • Uses Chainlink decentralized oracles instead of a single source.
  • The oracle aggregates multiple sources, reducing manipulation risk.
  • Can further add TWAP (Time-Weighted Average Price) to smooth out flash price spikes.

Top comments (0)