Use Case

An oracle is a mechanism used to fetch data from an external source and use it to make decisions within a protocol. Make sure that an oracle is working as expected. Manipulation of oracles is a very common attack vector. An oracle can be manipulated to return a price that is not representative of the true price of an asset. Oracles are used in many DeFi protocols, including lending protocols, derivatives protocols, and more.

Explanation

This assertion makes sure that the oracle has been updated within the last 10 minutes and that the price doesn’t deviate more than 10% from the pre-state price. There are two triggers, one for the liveness of the oracle and one for the price.

Code Example

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

import {Assertion} from "../../lib/credible-std/src/Assertion.sol";

interface IOracle {
    function lastUpdated() external view returns (uint256);
    function price() external view returns (uint256);
}

// Checks that the oracle is live
contract OracleLivenessAssertion is Assertion {
    IOracle public oracle = IOracle(address(0xbeef));

    function fnSelectors() external pure override returns (bytes4[] memory assertions) {
        assertions = new bytes4[](2);
        assertions[0] = this.assertionOracleLiveness.selector;
        assertions[1] = this.assertionOraclePrice.selector;
    }

    // Make sure that the oracle has been updated within the last 10 minutes
    function assertionOracleLiveness() external {
        ph.forkPostState();
        require(block.timestamp - oracle.lastUpdated() <= 10 minutes, "Oracle not updated within the last 10 minutes");
    }

    // Make sure that price doesn't deviate more than 10%
    function assertionOraclePrice() external {
        ph.forkPreState();
        uint256 prePrice = oracle.price();
        ph.forkPostState();
        uint256 postPrice = oracle.price();
        // Calculate the absolute price difference as a percentage
        // If post price is higher than pre price, subtract pre from post
        // Otherwise subtract post from pre to get positive difference
        // Multiply by 100 to convert to percentage points for 10% check
        uint256 priceDeviation =
            (((postPrice > prePrice) ? postPrice - prePrice : prePrice - postPrice) * 100) / prePrice;
        require(priceDeviation <= 10, "Price deviation is too large");
    }
}