Forkchoice Ethereum Mainnet

Address Contract Verified

Address 0x15f7744C393CD07bEac9322cE531bd0cB363536b
Balance 0 ETH
Nonce 1
Code Size 3905 bytes
Indexed Transactions 0 (1 on-chain, 1.1% indexed)
External Etherscan · Sourcify

Contract Bytecode

3905 bytes
0x608060405234801561000f575f80fd5b506004361061012f575f3560e01c8063a0dcdc68116100ad578063d29dba911161007d578063ebbc496511610063578063ebbc49651461030e578063ebdac45814610316578063feaf968c1461033d575f80fd5b8063d29dba91146102db578063e30c3978146102ee575f80fd5b8063a0dcdc6814610279578063acdb31f61461028c578063c42069ec1461029f578063d116c081146102b4575f80fd5b8063620518d8116101025780638a0531a6116100e85780638a0531a6146101cf5780638da5cb5b1461020d578063a06a720714610252575f80fd5b8063620518d8146101b15780637284e416146101ba575f80fd5b80630d73ed7b146101335780631af214a81461015b578063313ce5671461019457806350d25bcd1461019b575b5f80fd5b610146610141366004610aa1565b61037c565b60405190151581526020015b60405180910390f35b6101827f000000000000000000000000000000000000000000000000000000000000000881565b60405160ff9091168152602001610152565b6012610182565b6101a36104ee565b604051908152602001610152565b6101a360035481565b6101c2610503565b6040516101529190610acf565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161515610146565b60015461022d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610152565b6101827f000000000000000000000000000000000000000000000000000000000000000081565b6101a3610287366004610b38565b61058e565b61014661029a366004610b60565b6105f5565b6102b26102ad366004610b80565b610642565b005b61022d7f000000000000000000000000471a6299c027bd81ed4d66069dc510bd0569f4f881565b6102b26102e9366004610ba2565b61070f565b60025461022d9073ffffffffffffffffffffffffffffffffffffffff1681565b6102b2610795565b61022d7f000000000000000000000000000000000000000000000000000000000000000081565b610345610862565b6040805169ffffffffffffffffffff968716815260208101959095528401929092526060830152909116608082015260a001610152565b5f808273ffffffffffffffffffffffffffffffffffffffff1663245a7bfc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103c7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103eb9190610bb9565b90505f8173ffffffffffffffffffffffffffffffffffffffff166370da2f676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610437573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061045b9190610bd4565b90505f8273ffffffffffffffffffffffffffffffffffffffff166322adbc786040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104a7573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104cb9190610bd4565b9050858260170b1315806104e25750858160170b12155b93505050505b92915050565b5f806104f8610862565b509195945050505050565b5f805461050f90610bf4565b80601f016020809104026020016040519081016040528092919081815260200182805461053b90610bf4565b80156105865780601f1061055d57610100808354040283529160200191610586565b820191905f5260205f20905b81548152906001019060200180831161056957829003601f168201915b505050505081565b5f60128260ff1611156105c2576105a6601283610c72565b6105b190600a610da9565b6105bb9084610db7565b90506104e8565b60128260ff1610156105ee576105d9826012610c72565b6105e490600a610da9565b6105bb9084610e43565b5090919050565b5f8042600354846106069190610e8e565b109050808061063a575061063a847f000000000000000000000000471a6299c027bd81ed4d66069dc510bd0569f4f861037c565b949350505050565b60015473ffffffffffffffffffffffffffffffffffffffff1633146106c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4f6e6c79206f776e65720000000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60015473ffffffffffffffffffffffffffffffffffffffff163314610790576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f4f6e6c79206f776e65720000000000000000000000000000000000000000000060448201526064016106bf565b600355565b60025473ffffffffffffffffffffffffffffffffffffffff163314610816576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4f6e6c792070656e64696e67206f776e6572000000000000000000000000000060448201526064016106bf565b60028054600180547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b5f805f805f7f000000000000000000000000471a6299c027bd81ed4d66069dc510bd0569f4f873ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156108d0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108f49190610ebf565b93985091965094509250905061090a84836105f5565b15610a495773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001615610a15577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa1580156109b4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109d89190610ebf565b939850919650945092509050610a0e847f000000000000000000000000000000000000000000000000000000000000000061058e565b9350610a76565b610a3f847f000000000000000000000000000000000000000000000000000000000000000861058e565b93505f9150610a76565b610a73847f000000000000000000000000000000000000000000000000000000000000000861058e565b93505b9091929394565b73ffffffffffffffffffffffffffffffffffffffff81168114610a9e575f80fd5b50565b5f8060408385031215610ab2575f80fd5b823591506020830135610ac481610a7d565b809150509250929050565b5f6020808352835180828501525f5b81811015610afa57858101830151858201604001528201610ade565b505f6040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b5f8060408385031215610b49575f80fd5b82359150602083013560ff81168114610ac4575f80fd5b5f8060408385031215610b71575f80fd5b50508035926020909101359150565b5f60208284031215610b90575f80fd5b8135610b9b81610a7d565b9392505050565b5f60208284031215610bb2575f80fd5b5035919050565b5f60208284031215610bc9575f80fd5b8151610b9b81610a7d565b5f60208284031215610be4575f80fd5b81518060170b8114610b9b575f80fd5b600181811c90821680610c0857607f821691505b602082108103610c3f577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b50919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b60ff82811682821603908111156104e8576104e8610c45565b600181815b80851115610ce457817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610cca57610cca610c45565b80851615610cd757918102915b93841c9390800290610c90565b509250929050565b5f82610cfa575060016104e8565b81610d0657505f6104e8565b8160018114610d1c5760028114610d2657610d42565b60019150506104e8565b60ff841115610d3757610d37610c45565b50506001821b6104e8565b5060208310610133831016604e8410600b8410161715610d65575081810a6104e8565b610d6f8383610c8b565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115610da157610da1610c45565b029392505050565b5f610b9b60ff841683610cec565b5f82610dea577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f800000000000000000000000000000000000000000000000000000000000000083141615610e3e57610e3e610c45565b500590565b8082025f82127f800000000000000000000000000000000000000000000000000000000000000084141615610e7a57610e7a610c45565b81810583148215176104e8576104e8610c45565b808201808211156104e8576104e8610c45565b805169ffffffffffffffffffff81168114610eba575f80fd5b919050565b5f805f805f60a08688031215610ed3575f80fd5b610edc86610ea1565b9450602086015193506040860151925060608601519150610eff60808701610ea1565b9050929550929590935056fea26469706673582212203cca3589daf875bbedf4f9e6eb300755a90bc45cecaaff967f518f42b4f4525e64736f6c63430008140033

Verified Source Code Full Match

Compiler: v0.8.20+commit.a1b79de6 EVM: shanghai Optimization: Yes (10000 runs)
ChainlinkBasePriceFeed.sol 162 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "src/interfaces/IChainlinkFeed.sol";

interface IAggregator {
    function maxAnswer() external view returns (int192);

    function minAnswer() external view returns (int192);
}

// Standard feed component for FiRM price feeds
/// @dev Always return the feed price in 18 decimals
contract ChainlinkBasePriceFeed {
    IChainlinkFeed public immutable assetToUsd;
    IChainlinkFeed public immutable assetToUsdFallback;
    uint8 public immutable assetToUsdDecimals;
    uint8 public immutable assetToUsdFallbackDecimals;
    string public description;

    address public owner;
    address public pendingOwner;

    uint256 public assetToUsdHeartbeat;

    modifier onlyOwner() {
        require(msg.sender == owner, "Only owner");
        _;
    }

    modifier onlyPendingOwner() {
        require(msg.sender == pendingOwner, "Only pending owner");
        _;
    }

    constructor(
        address _owner,
        address _assetToUsd,
        address _assetToUsdFallback,
        uint256 _assetToUsdHeartbeat
    ) {
        owner = _owner;
        assetToUsd = IChainlinkFeed(_assetToUsd);
        assetToUsdFallback = IChainlinkFeed(_assetToUsdFallback);
        assetToUsdHeartbeat = _assetToUsdHeartbeat;
        assetToUsdDecimals = IChainlinkFeed(_assetToUsd).decimals();
        uint8 fallbackDecimals = 0;
        if (address(assetToUsdFallback) != address(0)) {
            fallbackDecimals = assetToUsdFallback.decimals();
        }
        assetToUsdFallbackDecimals = fallbackDecimals;
        description = assetToUsd.description();
    }

    /**
     * @notice Retrieves the latest round data for the asset token price feed
     * @return roundId The round ID of the Chainlink price feed for the feed with the lowest updatedAt feed
     * @return usdPrice The latest asset price in USD with 18 decimals
     * @return startedAt The timestamp when the latest round of Chainlink price feed started of the lowest last updatedAt feed
     * @return updatedAt The lowest timestamp when either of the latest round of Chainlink price feed was updated
     * @return answeredInRound The round ID in which the answer was computed of the lowest updatedAt feed
     */
    function latestRoundData()
        public
        view
        returns (
            uint80 roundId,
            int256 usdPrice,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        )
    {
        (roundId, usdPrice, startedAt, updatedAt, answeredInRound) = assetToUsd
            .latestRoundData();

        if (isPriceStale(usdPrice, updatedAt)) {
            if (hasFallback()) {
                (
                    roundId,
                    usdPrice,
                    startedAt,
                    updatedAt,
                    answeredInRound
                ) = assetToUsdFallback.latestRoundData();
                usdPrice = normalizePrice(usdPrice, assetToUsdFallbackDecimals);
            } else {
                usdPrice = normalizePrice(usdPrice, assetToUsdDecimals);
                updatedAt = 0;
            }
        } else {
            usdPrice = normalizePrice(usdPrice, assetToUsdDecimals);
        }
    }

    /**
     * @notice Returns the latest price only
     * @dev Unlike chainlink oracles, the latestAnswer will always be the same as in the latestRoundData
     * @return int256 Returns the last finalized price of the chainlink oracle
     */
    function latestAnswer() external view returns (int256) {
        (, int256 latestPrice, , , ) = latestRoundData();
        return latestPrice;
    }

    /**
     * @notice Checks if a given price is out of the boundaries defined in the Chainlink aggregator.
     * @param price The price to be checked.
     * @param feed The Chainlink feed to retrieve the boundary information from.
     * @return bool Returns `true` if the price is out of bounds, otherwise `false`.
     */
    function isPriceOutOfBounds(
        int price,
        IChainlinkFeed feed
    ) public view returns (bool) {
        IAggregator aggregator = IAggregator(feed.aggregator());
        int192 max = aggregator.maxAnswer();
        int192 min = aggregator.minAnswer();
        return (max <= price || min >= price);
    }

    function isPriceStale(
        int256 price,
        uint256 updatedAt
    ) public view returns (bool) {
        bool stalePrice = updatedAt + assetToUsdHeartbeat < block.timestamp;
        return stalePrice || isPriceOutOfBounds(price, assetToUsd);
    }

    function hasFallback() public view returns (bool) {
        return address(assetToUsdFallback) != address(0);
    }

    function setHeartbeat(uint256 newHeartbeat) public onlyOwner {
        assetToUsdHeartbeat = newHeartbeat;
    }

    function setPendingOwner(address newPendingOwner) public onlyOwner {
        pendingOwner = newPendingOwner;
    }

    function acceptOwner() public onlyPendingOwner {
        owner = pendingOwner;
        pendingOwner = address(0);
    }

    function decimals() public pure returns (uint8) {
        return 18;
    }

    function normalizePrice(
        int256 price,
        uint8 feedDecimals
    ) public pure returns (int256) {
        if (feedDecimals > 18) {
            return price / int(10 ** (feedDecimals - 18));
        } else if (feedDecimals < 18) {
            return price * int(10 ** (18 - feedDecimals));
        }
        return price;
    }
}
IChainlinkFeed.sol 30 lines
pragma solidity ^0.8.13;

interface IChainlinkFeed {
    function aggregator() external view returns (address aggregator);

    function decimals() external view returns (uint8 decimals);

    function latestRoundData()
        external
        view
        returns (
            uint80 roundId,
            int256 crvUsdPrice,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );

    function latestAnswer() external view returns (int256 price);

    function description() external view returns (string memory description);
}

interface IChainlinkBasePriceFeed is IChainlinkFeed {
    function assetToUsd() external view returns (IChainlinkFeed);

    function assetToUsdFallback() external view returns (IChainlinkFeed);

    function assetToUsdHeartbeat() external view returns (uint256 heartbeat);
}

Read Contract

assetToUsd 0xd116c081 → address
assetToUsdDecimals 0x1af214a8 → uint8
assetToUsdFallback 0xebdac458 → address
assetToUsdFallbackDecimals 0xa06a7207 → uint8
assetToUsdHeartbeat 0x620518d8 → uint256
decimals 0x313ce567 → uint8
description 0x7284e416 → string
hasFallback 0x8a0531a6 → bool
isPriceOutOfBounds 0x0d73ed7b → bool
isPriceStale 0xacdb31f6 → bool
latestAnswer 0x50d25bcd → int256
latestRoundData 0xfeaf968c → uint80, int256, uint256, uint256, uint80
normalizePrice 0xa0dcdc68 → int256
owner 0x8da5cb5b → address
pendingOwner 0xe30c3978 → address

Write Contract 3 functions

These functions modify contract state and require a wallet transaction to execute.

acceptOwner 0xebbc4965
No parameters
setHeartbeat 0xd29dba91
uint256 newHeartbeat
setPendingOwner 0xc42069ec
address newPendingOwner

Recent Transactions

This address has 1 on-chain transactions, but only 1.1% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →