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;
}
}
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
- Attacker manipulates the price feed of
tokenon the oracle (via flash loans or low-liquidity pools). - The contract thinks the collateral is worth more than it actually is.
- 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;
}
}
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)