ETH Price: $3,114.60 (+0.55%)
Gas: 5 Gwei

Contract

0x6a24ECc18224857BD73A7aa53c2a4Eb43c17D5A8
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value

There are no matching entries

Please try again later

Latest 2 internal transactions

Advanced mode:
Parent Transaction Hash Block From To Value
194371832024-03-15 1:48:4764 days ago1710467327
0x6a24ECc1...43c17D5A8
 Contract Creation0 ETH
194371832024-03-15 1:48:4764 days ago1710467327  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
PriceFeed

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 9 : PriceFeed.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "./Interfaces/IPriceFeed.sol";
import "./Interfaces/IFallbackCaller.sol";
import "./Dependencies/AggregatorV3Interface.sol";
import "./Dependencies/BaseMath.sol";
import "./Dependencies/EbtcMath.sol";
import "./Dependencies/AuthNoOwner.sol";
import "./FixedAdapter.sol";

/*
 * PriceFeed for mainnet deployment, it connects to two Chainlink's live feeds, ETH:BTC and
 * stETH:ETH, which are used to aggregate the price feed of stETH:BTC in conjuction.
 * It also allows for a fallback oracle to intervene in case that the primary Chainlink oracle fails.
 *
 * The PriceFeed uses Chainlink as primary oracle and allows for an optional fallback source. It contains logic for
 * switching oracles based on oracle failures, timeouts, and conditions for returning to the primary
 * Chainlink oracle. In addition, it contains the mechanism to add or remove the fallback oracle through governance.
 */
contract PriceFeed is BaseMath, IPriceFeed, AuthNoOwner {
    string public constant NAME = "PriceFeed";

    // Chainlink oracles in mainnet
    AggregatorV3Interface public immutable ETH_BTC_CL_FEED;
    AggregatorV3Interface public immutable STETH_ETH_CL_FEED;
    // STETH_ETH_FIXED_FEED must have the same decimals as STETH_ETH_CL_FEED
    AggregatorV3Interface public immutable STETH_ETH_FIXED_FEED;

    uint256 public immutable DENOMINATOR;
    uint256 public immutable SCALED_DECIMAL;

    // Fallback feed
    IFallbackCaller public fallbackCaller; // Wrapper contract that calls the fallback system

    // Maximum time period allowed since Chainlink's latest round data timestamp, beyond which Chainlink is considered frozen.
    uint256 public constant TIMEOUT_ETH_BTC_FEED = 4800; // 1 hours & 20min: 60 * 80
    uint256 public constant TIMEOUT_STETH_ETH_FEED = 90000; // 25 hours: 60 * 60 * 25
    uint256 constant INVALID_PRICE = 0;

    /**
     * @notice Maximum number of resulting and feed decimals
     */
    uint8 public constant MAX_DECIMALS = 18;

    // Maximum deviation allowed between two consecutive Chainlink oracle prices. 18-digit precision.
    uint256 public constant MAX_PRICE_DEVIATION_FROM_PREVIOUS_ROUND = 5e17; // 50%

    /*
     * The maximum relative price difference between two oracle responses allowed in order for the PriceFeed
     * to return to using the Chainlink oracle. 18-digit precision.
     */
    uint256 public constant MAX_PRICE_DIFFERENCE_BETWEEN_ORACLES = 5e16; // 5%

    // The last good price seen from an oracle by eBTC
    uint256 public lastGoodPrice;

    // The current status of the PriceFeed, which determines the conditions for the next price fetch attempt
    Status public status;

    // Dynamic feed = Chainlink stETH/ETH feed
    // Static feed = 1:1 FixedAdapter
    // defaults to static feed
    bool public useDynamicFeed;

    // --- Dependency setters ---

    /// @notice Sets the addresses of the contracts and initializes the system
    /// @param _fallbackCallerAddress The address of the Fallback oracle contract
    /// @param _authorityAddress The address of the Authority contract
    /// @param _collEthCLFeed The address of the collateral-ETH ChainLink feed
    /// @param _ethBtcCLFeed The address of the ETH-BTC ChainLink feed
    constructor(
        address _fallbackCallerAddress,
        address _authorityAddress,
        address _collEthCLFeed,
        address _ethBtcCLFeed,
        bool _useDynamicFeed
    ) {
        fallbackCaller = IFallbackCaller(_fallbackCallerAddress);

        _initializeAuthority(_authorityAddress);

        emit FallbackCallerChanged(address(0), _fallbackCallerAddress);

        ETH_BTC_CL_FEED = AggregatorV3Interface(_ethBtcCLFeed);
        STETH_ETH_CL_FEED = AggregatorV3Interface(_collEthCLFeed);
        STETH_ETH_FIXED_FEED = new FixedAdapter();

        uint8 ethBtcDecimals = ETH_BTC_CL_FEED.decimals();
        require(ethBtcDecimals <= MAX_DECIMALS);
        uint8 stEthEthDecimals = STETH_ETH_CL_FEED.decimals();
        require(stEthEthDecimals <= MAX_DECIMALS);
        require(stEthEthDecimals == STETH_ETH_FIXED_FEED.decimals());

        DENOMINATOR =
            10 ** ((stEthEthDecimals > ethBtcDecimals ? stEthEthDecimals : ethBtcDecimals) * 2);
        SCALED_DECIMAL = stEthEthDecimals > ethBtcDecimals
            ? 10 ** (stEthEthDecimals - ethBtcDecimals)
            : 10 ** (ethBtcDecimals - stEthEthDecimals);

        useDynamicFeed = _useDynamicFeed;

        // Get an initial price from Chainlink to serve as first reference for lastGoodPrice
        ChainlinkResponse memory chainlinkResponse = _getCurrentChainlinkResponse();
        ChainlinkResponse memory prevChainlinkResponse = _getPrevChainlinkResponse(
            chainlinkResponse.roundEthBtcId,
            chainlinkResponse.roundStEthEthId
        );

        require(
            !_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse) &&
                !_chainlinkIsFrozen(chainlinkResponse),
            "PriceFeed: Chainlink must be working and current"
        );

        _storeChainlinkPrice(chainlinkResponse.answer);

        // Explicitly set initial system status after `require` checks
        status = Status.chainlinkWorking;

        // emit STETH_ETH_FIXED_FEED address
        emit CollateralFeedSourceUpdated(address(_collateralFeed()));
    }

    // --- Functions ---

    function setCollateralFeedSource(bool _useDynamicFeed) external requiresAuth {
        useDynamicFeed = _useDynamicFeed;
        emit CollateralFeedSourceUpdated(address(_collateralFeed()));
    }

    /// @notice Returns the latest price obtained from the Oracle
    /// @dev Called by eBTC functions that require a current price. Also callable permissionlessly.
    /// @dev Non-view function - it updates and stores the last good price seen by eBTC.
    /// @dev Uses a main oracle (Chainlink) and a fallback oracle in case Chainlink fails. If both fail, it uses the last good price seen by eBTC.
    /// @dev The fallback oracle address can be swapped by the Authority. The fallback oracle must conform to the IFallbackCaller interface.
    /// @return The latest price fetched from the Oracle
    function fetchPrice() external override returns (uint256) {
        // Get current and previous price data from Chainlink, and current price data from Fallback
        ChainlinkResponse memory chainlinkResponse = _getCurrentChainlinkResponse();
        ChainlinkResponse memory prevChainlinkResponse = _getPrevChainlinkResponse(
            chainlinkResponse.roundEthBtcId,
            chainlinkResponse.roundStEthEthId
        );
        FallbackResponse memory fallbackResponse = _getCurrentFallbackResponse();

        // --- CASE 1: System fetched last price from Chainlink  ---
        if (status == Status.chainlinkWorking) {
            // If Chainlink is broken, try Fallback
            if (_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse)) {
                // If Fallback is broken then both oracles are untrusted, so return the last good price
                if (_fallbackIsBroken(fallbackResponse)) {
                    _changeStatus(Status.bothOraclesUntrusted);
                    return INVALID_PRICE;
                }
                /*
                 * If Fallback is only frozen but otherwise returning valid data, return the last good price.
                 * Fallback may need to be tipped to return current data.
                 */
                if (_fallbackIsFrozen(fallbackResponse)) {
                    _changeStatus(Status.usingFallbackChainlinkUntrusted);
                    return INVALID_PRICE;
                }

                // If Chainlink is broken and Fallback is working, switch to Fallback and return current Fallback price
                _changeStatus(Status.usingFallbackChainlinkUntrusted);
                return _storeFallbackPrice(fallbackResponse);
            }

            // If Chainlink is frozen, try Fallback
            if (_chainlinkIsFrozen(chainlinkResponse)) {
                // If Fallback is broken too, remember Fallback broke, and return last good price
                if (_fallbackIsBroken(fallbackResponse)) {
                    _changeStatus(Status.usingChainlinkFallbackUntrusted);
                    return INVALID_PRICE;
                }

                // If Fallback is frozen or working, remember Chainlink froze, and switch to Fallback
                _changeStatus(Status.usingFallbackChainlinkFrozen);

                if (_fallbackIsFrozen(fallbackResponse)) {
                    return INVALID_PRICE;
                }

                // If Fallback is working, use it
                return _storeFallbackPrice(fallbackResponse);
            }

            // If Chainlink price has changed by > 50% between two consecutive rounds, compare it to Fallback's price
            if (_chainlinkPriceChangeAboveMax(chainlinkResponse, prevChainlinkResponse)) {
                // If Fallback is broken, both oracles are untrusted, and return last good price
                // We don't trust CL for now given this large price differential
                if (_fallbackIsBroken(fallbackResponse)) {
                    _changeStatus(Status.bothOraclesUntrusted);
                    return INVALID_PRICE;
                }

                // If Fallback is frozen, switch to Fallback and return last good price
                // We don't trust CL for now given this large price differential
                if (_fallbackIsFrozen(fallbackResponse)) {
                    _changeStatus(Status.usingFallbackChainlinkUntrusted);
                    return INVALID_PRICE;
                }

                /*
                 * If Fallback is live and both oracles have a similar price, conclude that Chainlink's large price deviation between
                 * two consecutive rounds was likely a legitmate market price movement, and so continue using Chainlink
                 */
                if (_bothOraclesSimilarPrice(chainlinkResponse, fallbackResponse)) {
                    return _storeChainlinkPrice(chainlinkResponse.answer);
                }

                // If Fallback is live but the oracles differ too much in price, conclude that Chainlink's initial price deviation was
                // an oracle failure. Switch to Fallback, and use Fallback price
                _changeStatus(Status.usingFallbackChainlinkUntrusted);
                return _storeFallbackPrice(fallbackResponse);
            }

            // If Chainlink is working and Fallback is broken, remember Fallback is broken
            if (_fallbackIsBroken(fallbackResponse)) {
                _changeStatus(Status.usingChainlinkFallbackUntrusted);
            }

            // If Chainlink is working, return Chainlink current price (no status change)
            return _storeChainlinkPrice(chainlinkResponse.answer);
        }

        // --- CASE 2: The system fetched last price from Fallback ---
        if (status == Status.usingFallbackChainlinkUntrusted) {
            if (_fallbackIsBroken(fallbackResponse)) {
                _changeStatus(Status.bothOraclesUntrusted);
                return INVALID_PRICE;
            }

            /*
             * If Fallback is only frozen but otherwise returning valid data, just return the last good price.
             * Fallback may need to be tipped to return current data.
             */
            if (_fallbackIsFrozen(fallbackResponse)) {
                return INVALID_PRICE;
            }

            // If both Fallback and Chainlink are live, unbroken, and reporting similar prices, switch back to Chainlink
            if (
                _bothOraclesLiveAndUnbrokenAndSimilarPrice(
                    chainlinkResponse,
                    prevChainlinkResponse,
                    fallbackResponse
                )
            ) {
                _changeStatus(Status.chainlinkWorking);
                return _storeChainlinkPrice(chainlinkResponse.answer);
            }

            // Otherwise, use Fallback price
            return _storeFallbackPrice(fallbackResponse);
        }

        // --- CASE 3: Both oracles were untrusted at the last price fetch ---
        if (status == Status.bothOraclesUntrusted) {
            /*
             * If there's no fallback, only use Chainlink
             */
            if (address(fallbackCaller) == address(0)) {
                // If CL has resumed working
                if (
                    !_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse) &&
                    !_chainlinkIsFrozen(chainlinkResponse) &&
                    !_chainlinkPriceChangeAboveMax(chainlinkResponse, prevChainlinkResponse)
                ) {
                    _changeStatus(Status.usingChainlinkFallbackUntrusted);
                    return _storeChainlinkPrice(chainlinkResponse.answer);
                } else {
                    return INVALID_PRICE;
                }
            }

            /*
             * If both oracles are now live, unbroken and similar price, we assume that they are reporting
             * accurately, and so we switch back to Chainlink.
             */
            if (
                _bothOraclesLiveAndUnbrokenAndSimilarPrice(
                    chainlinkResponse,
                    prevChainlinkResponse,
                    fallbackResponse
                )
            ) {
                _changeStatus(Status.chainlinkWorking);
                return _storeChainlinkPrice(chainlinkResponse.answer);
            }

            // Otherwise, return the last good price - both oracles are still untrusted (no status change)
            return INVALID_PRICE;
        }

        // --- CASE 4: Using Fallback, and Chainlink is frozen ---
        if (status == Status.usingFallbackChainlinkFrozen) {
            if (_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse)) {
                // If both Oracles are broken, return last good price
                if (_fallbackIsBroken(fallbackResponse)) {
                    _changeStatus(Status.bothOraclesUntrusted);
                    return INVALID_PRICE;
                }

                // If Chainlink is broken, remember it and switch to using Fallback
                _changeStatus(Status.usingFallbackChainlinkUntrusted);

                if (_fallbackIsFrozen(fallbackResponse)) {
                    return INVALID_PRICE;
                }

                // If Fallback is working, return Fallback current price
                return _storeFallbackPrice(fallbackResponse);
            }

            if (_chainlinkIsFrozen(chainlinkResponse)) {
                // if Chainlink is frozen and Fallback is broken, remember Fallback broke, and return last good price
                if (_fallbackIsBroken(fallbackResponse)) {
                    _changeStatus(Status.usingChainlinkFallbackUntrusted);
                    return INVALID_PRICE;
                }

                // If both are frozen, just use lastGoodPrice
                if (_fallbackIsFrozen(fallbackResponse)) {
                    return INVALID_PRICE;
                }

                // if Chainlink is frozen and Fallback is working, keep using Fallback (no status change)
                return _storeFallbackPrice(fallbackResponse);
            }

            if (_chainlinkPriceChangeAboveMax(chainlinkResponse, prevChainlinkResponse)) {
                // if Chainlink price is deviated between rounds and fallback is broken, just use lastGoodPrice
                if (_fallbackIsBroken(fallbackResponse)) {
                    _changeStatus(Status.bothOraclesUntrusted);
                    return INVALID_PRICE;
                }

                // If Chainlink price is deviated between rounds, remember it and keep using fallback
                _changeStatus(Status.usingFallbackChainlinkUntrusted);

                // If fallback is frozen, just use lastGoodPrice
                if (_fallbackIsFrozen(fallbackResponse)) {
                    return INVALID_PRICE;
                }

                // otherwise fallback is working and keep using its latest response
                return _storeFallbackPrice(fallbackResponse);
            }

            // if Chainlink is live and Fallback is broken, remember Fallback broke, and return Chainlink price
            if (_fallbackIsBroken(fallbackResponse)) {
                _changeStatus(Status.usingChainlinkFallbackUntrusted);
                return _storeChainlinkPrice(chainlinkResponse.answer);
            }

            // If Chainlink is live and Fallback is frozen, just use last good price (no status change) since we have no basis for comparison
            if (_fallbackIsFrozen(fallbackResponse)) {
                return INVALID_PRICE;
            }

            // If Chainlink is live and Fallback is working, compare prices. Switch to Chainlink
            // if prices are within 5%, and return Chainlink price.
            if (_bothOraclesSimilarPrice(chainlinkResponse, fallbackResponse)) {
                _changeStatus(Status.chainlinkWorking);
                return _storeChainlinkPrice(chainlinkResponse.answer);
            }

            // Otherwise if Chainlink is live but price not within 5% of Fallback, distrust Chainlink, and return Fallback price
            _changeStatus(Status.usingFallbackChainlinkUntrusted);
            return _storeFallbackPrice(fallbackResponse);
        }

        // --- CASE 5: Using Chainlink, Fallback is untrusted ---
        if (status == Status.usingChainlinkFallbackUntrusted) {
            // If Chainlink breaks, now both oracles are untrusted
            if (_chainlinkIsBroken(chainlinkResponse, prevChainlinkResponse)) {
                _changeStatus(Status.bothOraclesUntrusted);
                return INVALID_PRICE;
            }

            // If Chainlink is frozen, return last good price (no status change)
            if (_chainlinkIsFrozen(chainlinkResponse)) {
                return INVALID_PRICE;
            }

            // If Chainlink is live but deviated >50% from it's previous price and Fallback is still untrusted, switch
            // to bothOraclesUntrusted and return last good price
            if (_chainlinkPriceChangeAboveMax(chainlinkResponse, prevChainlinkResponse)) {
                _changeStatus(Status.bothOraclesUntrusted);
                return INVALID_PRICE;
            }

            // If Chainlink and Fallback are both live, unbroken and similar price, switch back to chainlinkWorking and return Chainlink price
            if (
                _bothOraclesLiveAndUnbrokenAndSimilarPrice(
                    chainlinkResponse,
                    prevChainlinkResponse,
                    fallbackResponse
                )
            ) {
                if (address(fallbackCaller) != address(0)) {
                    _changeStatus(Status.chainlinkWorking);
                }
                return _storeChainlinkPrice(chainlinkResponse.answer);
            }

            // Otherwise if Chainlink is live and deviated <50% from it's previous price and Fallback is still untrusted,
            // return Chainlink price (no status change)
            return _storeChainlinkPrice(chainlinkResponse.answer);
        }

        /// @audit This should never be used, but we added it for the Certora Prover
        return INVALID_PRICE;
    }

    // --- Governance Functions ---
    /// @notice Sets a new fallback oracle
    /// @dev Healthy response of new oracle is checked, with extra event emitted on failure
    /// @param _fallbackCaller The address of the new IFallbackCaller compliant oracle\
    function setFallbackCaller(address _fallbackCaller) external requiresAuth {
        // health check-up before officially set it up
        IFallbackCaller newFallbackCaler = IFallbackCaller(_fallbackCaller);
        FallbackResponse memory fallbackResponse;

        if (_fallbackCaller != address(0)) {
            try newFallbackCaler.getFallbackResponse() returns (
                uint256 answer,
                uint256 timestampRetrieved,
                bool success
            ) {
                fallbackResponse.answer = answer;
                fallbackResponse.timestamp = timestampRetrieved;
                fallbackResponse.success = success;
                if (
                    !_fallbackIsBroken(fallbackResponse) &&
                    !_responseTimeout(fallbackResponse.timestamp, newFallbackCaler.fallbackTimeout())
                ) {
                    address oldFallbackCaller = address(fallbackCaller);
                    fallbackCaller = newFallbackCaler;
                    emit FallbackCallerChanged(oldFallbackCaller, _fallbackCaller);
                }
            } catch {
                emit UnhealthyFallbackCaller(_fallbackCaller, block.timestamp);
            }
        } else {
            address oldFallbackCaller = address(fallbackCaller);
            // NOTE: assume intentionally bricking fallback!!!
            fallbackCaller = newFallbackCaler;
            emit FallbackCallerChanged(oldFallbackCaller, _fallbackCaller);
        }
    }

    // --- Helper functions ---

    /// @notice Checks if Chainlink oracle is broken by checking both the current and previous responses
    /// @dev Chainlink is considered broken if its current or previous round data is in any way bad. We check the previous round for two reasons.
    /// @dev 1. It is necessary data for the price deviation check in case 1
    /// @dev 2. Chainlink is the PriceFeed's preferred primary oracle - having two consecutive valid round responses adds peace of mind when using or returning to Chainlink.
    /// @param _currentResponse The latest response from the Chainlink oracle
    /// @param _prevResponse The previous response from the Chainlink oracle
    /// @return A boolean indicating whether the Chainlink oracle is broken
    function _chainlinkIsBroken(
        ChainlinkResponse memory _currentResponse,
        ChainlinkResponse memory _prevResponse
    ) internal view returns (bool) {
        return _badChainlinkResponse(_currentResponse) || _badChainlinkResponse(_prevResponse);
    }

    /// @notice Checks for a bad response from the Chainlink oracle
    /// @dev A response is considered bad if the success value reports failure, or if the timestamp is invalid (0 or in the future)
    /// @param _response The response from the Chainlink oracle to evaluate
    /// @return A boolean indicating whether the Chainlink oracle response is bad

    function _badChainlinkResponse(ChainlinkResponse memory _response) internal view returns (bool) {
        // Check for response call reverted
        if (!_response.success) {
            return true;
        }

        // Check for an invalid timestamp that is 0, or in the future
        if (
            _response.timestampEthBtc == 0 ||
            _response.timestampEthBtc > block.timestamp ||
            _response.timestampStEthEth == 0 ||
            _response.timestampStEthEth > block.timestamp
        ) {
            return true;
        }

        return false;
    }

    /// @notice Checks if the Chainlink oracle is frozen
    /// @dev The oracle is considered frozen if either of the feed timestamps are older than the threshold specified by the static timeout thresholds
    /// @param _response The response from the Chainlink oracle to evaluate
    /// @return A boolean indicating whether the Chainlink oracle is frozen
    function _chainlinkIsFrozen(ChainlinkResponse memory _response) internal view returns (bool) {
        return
            _responseTimeout(_response.timestampEthBtc, TIMEOUT_ETH_BTC_FEED) ||
            _responseTimeout(_response.timestampStEthEth, TIMEOUT_STETH_ETH_FEED);
    }

    /// @notice Checks if the price change between Chainlink oracle rounds is above the maximum threshold allowed
    /// @param _currentResponse The latest response from the Chainlink oracle
    /// @param _prevResponse The previous response from the Chainlink oracle
    /// @return A boolean indicating whether the price change from Chainlink oracle is above the maximum threshold allowed
    function _chainlinkPriceChangeAboveMax(
        ChainlinkResponse memory _currentResponse,
        ChainlinkResponse memory _prevResponse
    ) internal pure returns (bool) {
        uint256 minPrice = EbtcMath._min(_currentResponse.answer, _prevResponse.answer);
        uint256 maxPrice = EbtcMath._max(_currentResponse.answer, _prevResponse.answer);

        /*
         * Use the larger price as the denominator:
         * - If price decreased, the percentage deviation is in relation to the the previous price.
         * - If price increased, the percentage deviation is in relation to the current price.
         */
        uint256 percentDeviation = maxPrice > 0
            ? ((maxPrice - minPrice) * EbtcMath.DECIMAL_PRECISION) / maxPrice
            : 0;

        // Return true if price has more than doubled, or more than halved.
        return percentDeviation > MAX_PRICE_DEVIATION_FROM_PREVIOUS_ROUND;
    }

    function _fallbackIsBroken(FallbackResponse memory _response) internal view returns (bool) {
        // Check for response call reverted
        if (!_response.success) {
            return true;
        }
        // Check for an invalid timeStamp that is 0, or in the future
        if (_response.timestamp == 0 || _response.timestamp > block.timestamp) {
            return true;
        }
        // Check for zero price (FallbackCaller must ensure that the price is not negative and return 0 if it is)
        if (_response.answer == 0) {
            return true;
        }

        return false;
    }

    /// @notice Checks if the fallback oracle is frozen by comparing the current timestamp with the timeout value.
    /// @param _fallbackResponse Response from the fallback oracle to check
    /// @return A boolean indicating whether the fallback oracle is frozen.
    function _fallbackIsFrozen(
        FallbackResponse memory _fallbackResponse
    ) internal view returns (bool) {
        return
            _fallbackResponse.timestamp > 0 &&
            _responseTimeout(_fallbackResponse.timestamp, fallbackCaller.fallbackTimeout());
    }

    function _responseTimeout(uint256 _timestamp, uint256 _timeout) internal view returns (bool) {
        return block.timestamp - _timestamp > _timeout;
    }

    /// @notice Checks if both the Chainlink and fallback oracles are live, unbroken, and reporting similar prices.
    /// @param _chainlinkResponse The latest response from the Chainlink oracle.
    /// @param _prevChainlinkResponse The previous response from the Chainlink oracle.
    /// @param _fallbackResponse The latest response from the fallback oracle.
    /// @return A boolean indicating whether both oracles are live, unbroken, and reporting similar prices.

    function _bothOraclesLiveAndUnbrokenAndSimilarPrice(
        ChainlinkResponse memory _chainlinkResponse,
        ChainlinkResponse memory _prevChainlinkResponse,
        FallbackResponse memory _fallbackResponse
    ) internal view returns (bool) {
        // Return false if either oracle is broken or frozen
        if (
            (address(fallbackCaller) != address(0) &&
                (_fallbackIsBroken(_fallbackResponse) || _fallbackIsFrozen(_fallbackResponse))) ||
            _chainlinkIsBroken(_chainlinkResponse, _prevChainlinkResponse) ||
            _chainlinkIsFrozen(_chainlinkResponse)
        ) {
            return false;
        }

        return _bothOraclesSimilarPrice(_chainlinkResponse, _fallbackResponse);
    }

    /// @notice Checks if the prices reported by the Chainlink and fallback oracles are similar, within the maximum deviation specified by MAX_PRICE_DIFFERENCE_BETWEEN_ORACLES.
    /// @param _chainlinkResponse The response from the Chainlink oracle.
    /// @param _fallbackResponse The response from the fallback oracle.
    /// @return A boolean indicating whether the prices reported by both oracles are similar.

    function _bothOraclesSimilarPrice(
        ChainlinkResponse memory _chainlinkResponse,
        FallbackResponse memory _fallbackResponse
    ) internal view returns (bool) {
        if (address(fallbackCaller) == address(0)) {
            return true;
        }
        // Get the relative price difference between the oracles. Use the lower price as the denominator, i.e. the reference for the calculation.
        uint256 minPrice = EbtcMath._min(_fallbackResponse.answer, _chainlinkResponse.answer);
        if (minPrice == 0) return false;
        uint256 maxPrice = EbtcMath._max(_fallbackResponse.answer, _chainlinkResponse.answer);
        uint256 percentPriceDifference = ((maxPrice - minPrice) * EbtcMath.DECIMAL_PRECISION) /
            minPrice;

        /*
         * Return true if the relative price difference is <= MAX_PRICE_DIFFERENCE_BETWEEN_ORACLES: if so, we assume both oracles are probably reporting
         * the honest market price, as it is unlikely that both have been broken/hacked and are still in-sync.
         */
        return percentPriceDifference <= MAX_PRICE_DIFFERENCE_BETWEEN_ORACLES;
    }

    /// @notice Changes the status of the oracle state machine
    /// @param _status The new status of the contract.
    function _changeStatus(Status _status) internal {
        status = _status;
        emit PriceFeedStatusChanged(_status);
    }

    /// @notice Stores the latest valid price.
    /// @param _currentPrice The price to be stored.
    function _storePrice(uint256 _currentPrice) internal {
        emit LastGoodPriceUpdated(_currentPrice);
    }

    /// @notice Stores the price reported by the fallback oracle.
    /// @param _fallbackResponse The latest response from the fallback oracle.
    /// @return The price reported by the fallback oracle.
    function _storeFallbackPrice(
        FallbackResponse memory _fallbackResponse
    ) internal returns (uint256) {
        _storePrice(_fallbackResponse.answer);
        return _fallbackResponse.answer;
    }

    /// @notice Stores the price reported by the Chainlink oracle.
    /// @param _answer The latest price reported by the Chainlink oracle.
    /// @return The price reported by the Chainlink oracle.
    function _storeChainlinkPrice(uint256 _answer) internal returns (uint256) {
        _storePrice(_answer);
        return _answer;
    }

    // --- Oracle response wrapper functions ---

    /// @notice Retrieves the latest response from the fallback oracle. If the fallback oracle address is set to the zero address, it returns a failing struct.
    /// @return fallbackResponse The latest response from the fallback oracle.

    function _getCurrentFallbackResponse()
        internal
        view
        returns (FallbackResponse memory fallbackResponse)
    {
        if (address(fallbackCaller) != address(0)) {
            try fallbackCaller.getFallbackResponse() returns (
                uint256 answer,
                uint256 timestampRetrieved,
                bool success
            ) {
                fallbackResponse.answer = answer;
                fallbackResponse.timestamp = timestampRetrieved;
                fallbackResponse.success = success;
            } catch {
                // If call to Fallback reverts, return a zero response with success = false
            }
        } // If unset we return a zero response with success = false

        // Return is implicit
    }

    function _collateralFeed() private view returns (AggregatorV3Interface) {
        return useDynamicFeed ? STETH_ETH_CL_FEED : STETH_ETH_FIXED_FEED;
    }

    /// @notice Fetches Chainlink responses for the current round of data for both ETH-BTC and stETH-ETH price feeds.
    /// @return chainlinkResponse A struct containing data retrieved from the price feeds, including the round IDs, timestamps, aggregated price, and a success flag.
    function _getCurrentChainlinkResponse()
        internal
        view
        returns (ChainlinkResponse memory chainlinkResponse)
    {
        // Try to get latest prices data:
        int256 ethBtcAnswer;
        int256 stEthEthAnswer;
        try ETH_BTC_CL_FEED.latestRoundData() returns (
            uint80 roundId,
            int256 answer,
            uint256,
            /* startedAt */
            uint256 timestamp,
            uint80 /* answeredInRound */
        ) {
            ethBtcAnswer = answer;
            chainlinkResponse.roundEthBtcId = roundId;
            chainlinkResponse.timestampEthBtc = timestamp;
        } catch {
            // If call to Chainlink aggregator reverts, return a zero response with success = false
            return chainlinkResponse;
        }

        try _collateralFeed().latestRoundData() returns (
            uint80 roundId,
            int256 answer,
            uint256,
            /* startedAt */
            uint256 timestamp,
            uint80 /* answeredInRound */
        ) {
            stEthEthAnswer = answer;
            chainlinkResponse.roundStEthEthId = roundId;
            chainlinkResponse.timestampStEthEth = timestamp;
        } catch {
            // If call to Chainlink aggregator reverts, return a zero response with success = false
            return chainlinkResponse;
        }

        if (
            _checkHealthyCLResponse(chainlinkResponse.roundEthBtcId, ethBtcAnswer) &&
            _checkHealthyCLResponse(chainlinkResponse.roundStEthEthId, stEthEthAnswer)
        ) {
            chainlinkResponse.answer = _formatClAggregateAnswer(ethBtcAnswer, stEthEthAnswer);
        } else {
            return chainlinkResponse;
        }

        chainlinkResponse.success = true;
    }

    /// @notice Returns if the CL feed is healthy or not, based on: negative value and null round id. For price aggregation
    /// @param _roundId The aggregator round of the target CL feed
    /// @param _answer CL price price reported for target feeds
    /// @return The boolean state indicating CL response health for aggregation
    function _checkHealthyCLResponse(uint80 _roundId, int256 _answer) internal view returns (bool) {
        if (_answer <= 0) return false;
        if (_roundId == 0) return false;

        return true;
    }

    /// @notice Fetches Chainlink responses for the previous round of data for both ETH-BTC and stETH-ETH price feeds.
    /// @param _currentRoundEthBtcId The current round ID for the ETH-BTC price feed.
    /// @param _currentRoundStEthEthId The current round ID for the stETH-ETH price feed.
    /// @return prevChainlinkResponse A struct containing data retrieved from the price feeds, including the round IDs, timestamps, aggregated price, and a success flag.
    function _getPrevChainlinkResponse(
        uint80 _currentRoundEthBtcId,
        uint80 _currentRoundStEthEthId
    ) internal view returns (ChainlinkResponse memory prevChainlinkResponse) {
        // If first round, early return
        // Handles revert from underflow in _currentRoundEthBtcId - 1
        // and _currentRoundStEthEthId - 1
        // Behavior should be indentical to following block if this revert was caught
        if (_currentRoundEthBtcId == 0 || _currentRoundStEthEthId == 0) {
            return prevChainlinkResponse;
        }

        // Try to get latest prices data from prev round:
        int256 ethBtcAnswer;
        int256 stEthEthAnswer;
        try ETH_BTC_CL_FEED.getRoundData(_currentRoundEthBtcId - 1) returns (
            uint80 roundId,
            int256 answer,
            uint256,
            /* startedAt */
            uint256 timestamp,
            uint80 /* answeredInRound */
        ) {
            ethBtcAnswer = answer;
            prevChainlinkResponse.roundEthBtcId = roundId;
            prevChainlinkResponse.timestampEthBtc = timestamp;
        } catch {
            // If call to Chainlink aggregator reverts, return a zero response with success = false
            return prevChainlinkResponse;
        }

        try _collateralFeed().getRoundData(_currentRoundStEthEthId - 1) returns (
            uint80 roundId,
            int256 answer,
            uint256,
            /* startedAt */
            uint256 timestamp,
            uint80 /* answeredInRound */
        ) {
            stEthEthAnswer = answer;
            prevChainlinkResponse.roundStEthEthId = roundId;
            prevChainlinkResponse.timestampStEthEth = timestamp;
        } catch {
            // If call to Chainlink aggregator reverts, return a zero response with success = false
            return prevChainlinkResponse;
        }

        if (
            _checkHealthyCLResponse(prevChainlinkResponse.roundEthBtcId, ethBtcAnswer) &&
            _checkHealthyCLResponse(prevChainlinkResponse.roundStEthEthId, stEthEthAnswer)
        ) {
            prevChainlinkResponse.answer = _formatClAggregateAnswer(ethBtcAnswer, stEthEthAnswer);
        } else {
            return prevChainlinkResponse;
        }

        prevChainlinkResponse.success = true;
    }

    // @notice Returns the price of stETH:BTC in 18 decimals denomination
    // @param _ethBtcAnswer CL price retrieve from ETH:BTC feed
    // @param _stEthEthAnswer CL price retrieve from stETH:BTC feed
    // @return The aggregated calculated price for stETH:BTC
    function _formatClAggregateAnswer(
        int256 _ethBtcAnswer,
        int256 _stEthEthAnswer
    ) internal view returns (uint256) {
        return
            (SCALED_DECIMAL *
                uint256(_ethBtcAnswer) *
                uint256(_stEthEthAnswer) *
                EbtcMath.DECIMAL_PRECISION) / DENOMINATOR;
    }
}

File 2 of 9 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
// Code from https://github.com/smartcontractkit/chainlink/blob/master/evm-contracts/src/v0.6/interfaces/AggregatorV3Interface.sol

pragma solidity 0.8.17;

interface AggregatorV3Interface {
    function decimals() external view returns (uint8);

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

    function version() external view returns (uint256);

    // getRoundData and latestRoundData should both raise "No data present"
    // if they do not have data to report, instead of returning unset values
    // which could be misinterpreted as actual reported values.
    function getRoundData(
        uint80 _roundId
    )
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        );

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

File 3 of 9 : AuthNoOwner.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.17;

import {Authority} from "./Authority.sol";

/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic.
/// @author Modified by BadgerDAO to remove owner
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
contract AuthNoOwner {
    event AuthorityUpdated(address indexed user, Authority indexed newAuthority);

    Authority private _authority;
    bool private _authorityInitialized;

    modifier requiresAuth() virtual {
        require(isAuthorized(msg.sender, msg.sig), "Auth: UNAUTHORIZED");

        _;
    }

    function authority() public view returns (Authority) {
        return _authority;
    }

    function authorityInitialized() public view returns (bool) {
        return _authorityInitialized;
    }

    function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
        Authority auth = _authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.

        // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be
        // aware that this makes protected functions uncallable even to the owner if the authority is out of order.
        return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig));
    }

    /// @notice Changed constructor to initialize to allow flexiblity of constructor vs initializer use
    /// @notice sets authorityInitiailzed flag to ensure only one use of
    function _initializeAuthority(address newAuthority) internal {
        require(address(_authority) == address(0), "Auth: authority is non-zero");
        require(!_authorityInitialized, "Auth: authority already initialized");

        _authority = Authority(newAuthority);
        _authorityInitialized = true;

        emit AuthorityUpdated(address(this), Authority(newAuthority));
    }
}

File 4 of 9 : Authority.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.17;

/// @notice A generic interface for a contract which provides authorization data to an Auth instance.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
interface Authority {
    function canCall(address user, address target, bytes4 functionSig) external view returns (bool);
}

File 5 of 9 : BaseMath.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

contract BaseMath {
    uint256 public constant DECIMAL_PRECISION = 1e18;
}

File 6 of 9 : EbtcMath.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

library EbtcMath {
    uint256 internal constant DECIMAL_PRECISION = 1e18;
    uint256 public constant MAX_TCR = type(uint256).max;

    /* Precision for Nominal ICR (independent of price). Rationale for the value:
     *
     * - Making it “too high” could lead to overflows.
     * - Making it “too low” could lead to an ICR equal to zero, due to truncation from Solidity floor division.
     *
     * This value of 1e20 is chosen for safety: the NICR will only overflow for numerator > ~1e39 ETH,
     * and will only truncate to 0 if the denominator is at least 1e20 times greater than the numerator.
     *
     */
    uint256 internal constant NICR_PRECISION = 1e20;

    function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return (_a < _b) ? _a : _b;
    }

    function _max(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return (_a >= _b) ? _a : _b;
    }

    /**
     * credit to OpenZeppelin
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, "EbtcMath: downcast to uint128 will overflow");
        return uint128(value);
    }

    /*
     * Multiply two decimal numbers and use normal rounding rules:
     * -round product up if 19'th mantissa digit >= 5
     * -round product down if 19'th mantissa digit < 5
     *
     * Used only inside the exponentiation, _decPow().
     */
    function decMul(uint256 x, uint256 y) internal pure returns (uint256 decProd) {
        uint256 prod_xy = x * y;

        decProd = (prod_xy + (DECIMAL_PRECISION / 2)) / DECIMAL_PRECISION;
    }

    /*
     * _decPow: Exponentiation function for 18-digit decimal base, and integer exponent n.
     *
     * Uses the efficient "exponentiation by squaring" algorithm. O(log(n)) complexity.
     *
     * Called by two functions that represent time in units of minutes:
     * 1) CdpManager._calcDecayedBaseRate
     * 2) CommunityIssuance._getCumulativeIssuanceFraction
     *
     * The exponent is capped to avoid reverting due to overflow. The cap 525600000 equals
     * "minutes in 1000 years": 60 * 24 * 365 * 1000
     *
     * If a period of > 1000 years is ever used as an exponent in either of the above functions, the result will be
     * negligibly different from just passing the cap, since:
     *
     * In function 1), the decayed base rate will be 0 for 1000 years or > 1000 years
     * In function 2), the difference in tokens issued at 1000 years and any time > 1000 years, will be negligible
     */
    function _decPow(uint256 _base, uint256 _minutes) internal pure returns (uint256) {
        if (_minutes > 525600000) {
            _minutes = 525600000;
        } // cap to avoid overflow

        if (_minutes == 0) {
            return DECIMAL_PRECISION;
        }

        uint256 y = DECIMAL_PRECISION;
        uint256 x = _base;
        uint256 n = _minutes;

        // Exponentiation-by-squaring
        while (n > 1) {
            if (n % 2 == 0) {
                x = decMul(x, x);
                n = n / 2;
            } else {
                // if (n % 2 != 0)
                y = decMul(x, y);
                x = decMul(x, x);
                n = (n - 1) / 2;
            }
        }

        return decMul(x, y);
    }

    function _getAbsoluteDifference(uint256 _a, uint256 _b) internal pure returns (uint256) {
        return (_a >= _b) ? (_a - _b) : (_b - _a);
    }

    function _computeNominalCR(uint256 _collShares, uint256 _debt) internal pure returns (uint256) {
        if (_debt > 0) {
            return (_collShares * NICR_PRECISION) / _debt;
        }
        // Return the maximal value for uint256 if the Cdp has a debt of 0. Represents "infinite" CR.
        else {
            // if (_debt == 0)
            return MAX_TCR;
        }
    }

    /// @dev Compute collateralization ratio, given stETH balance, price, and debt balance
    function _computeCR(
        uint256 _stEthBalance,
        uint256 _debt,
        uint256 _price
    ) internal pure returns (uint256) {
        if (_debt > 0) {
            uint256 newCollRatio = (_stEthBalance * _price) / _debt;

            return newCollRatio;
        }
        // Return the maximal value for uint256 if the Cdp has a debt of 0. Represents "infinite" CR.
        else {
            // if (_debt == 0)
            return MAX_TCR;
        }
    }
}

File 7 of 9 : FixedAdapter.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {AggregatorV3Interface} from "./Dependencies/AggregatorV3Interface.sol";

contract FixedAdapter is AggregatorV3Interface {
    uint8 public constant override decimals = 18;
    uint256 public constant override version = 1;

    /// @notice PriceFeed always fetches current and previous rounds. It's ok to
    /// hardcode round IDs as long as they are greater than 0.
    uint80 public constant CURRENT_ROUND = 2;
    uint80 public constant PREVIOUS_ROUND = 1;
    int256 internal constant ADAPTER_PRECISION = int256(10 ** decimals);

    function description() external view returns (string memory) {
        return "stETH/ETH Fixed Adapter";
    }

    // getRoundData and latestRoundData should both raise "No data present"
    // if they do not have data to report, instead of returning unset values
    // which could be misinterpreted as actual reported values.
    function getRoundData(
        uint80 _roundId
    )
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        )
    {
        require(_roundId == CURRENT_ROUND || _roundId == PREVIOUS_ROUND);

        roundId = _roundId;
        updatedAt = _roundId == CURRENT_ROUND ? block.timestamp : block.timestamp - 1;
        answer = ADAPTER_PRECISION;
    }

    function latestRoundData()
        external
        view
        returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
        )
    {
        roundId = CURRENT_ROUND;
        updatedAt = block.timestamp;
        answer = ADAPTER_PRECISION;
    }
}

File 8 of 9 : IFallbackCaller.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IFallbackCaller {
    // --- Events ---
    event FallbackTimeOutChanged(uint256 _oldTimeOut, uint256 _newTimeOut);

    // --- Function External View ---

    // NOTE: The fallback oracle must always return its answer scaled to 18 decimals where applicable
    //       The system will assume an 18 decimal response for efficiency.
    function getFallbackResponse() external view returns (uint256, uint256, bool);

    // NOTE: this returns the timeout window interval for the fallback oracle instead
    // of storing in the `PriceFeed` contract is retrieve for the `FallbackCaller`
    function fallbackTimeout() external view returns (uint256);

    // --- Function External Setter ---

    function setFallbackTimeout(uint256 newFallbackTimeout) external;
}

File 9 of 9 : IPriceFeed.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IPriceFeed {
    // --- Events ---
    event LastGoodPriceUpdated(uint256 _lastGoodPrice);
    event PriceFeedStatusChanged(Status newStatus);
    event FallbackCallerChanged(
        address indexed _oldFallbackCaller,
        address indexed _newFallbackCaller
    );
    event UnhealthyFallbackCaller(address indexed _fallbackCaller, uint256 timestamp);
    event CollateralFeedSourceUpdated(address indexed stEthFeed);

    // --- Structs ---

    struct ChainlinkResponse {
        uint80 roundEthBtcId;
        uint80 roundStEthEthId;
        uint256 answer;
        uint256 timestampEthBtc;
        uint256 timestampStEthEth;
        bool success;
    }

    struct FallbackResponse {
        uint256 answer;
        uint256 timestamp;
        bool success;
    }

    // --- Enum ---

    enum Status {
        chainlinkWorking,
        usingFallbackChainlinkUntrusted,
        bothOraclesUntrusted,
        usingFallbackChainlinkFrozen,
        usingChainlinkFallbackUntrusted
    }

    // --- Function ---
    function fetchPrice() external returns (uint256);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_fallbackCallerAddress","type":"address"},{"internalType":"address","name":"_authorityAddress","type":"address"},{"internalType":"address","name":"_collEthCLFeed","type":"address"},{"internalType":"address","name":"_ethBtcCLFeed","type":"address"},{"internalType":"bool","name":"_useDynamicFeed","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stEthFeed","type":"address"}],"name":"CollateralFeedSourceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oldFallbackCaller","type":"address"},{"indexed":true,"internalType":"address","name":"_newFallbackCaller","type":"address"}],"name":"FallbackCallerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_lastGoodPrice","type":"uint256"}],"name":"LastGoodPriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IPriceFeed.Status","name":"newStatus","type":"uint8"}],"name":"PriceFeedStatusChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_fallbackCaller","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UnhealthyFallbackCaller","type":"event"},{"inputs":[],"name":"DECIMAL_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ETH_BTC_CL_FEED","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PRICE_DEVIATION_FROM_PREVIOUS_ROUND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PRICE_DIFFERENCE_BETWEEN_ORACLES","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SCALED_DECIMAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STETH_ETH_CL_FEED","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STETH_ETH_FIXED_FEED","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMEOUT_ETH_BTC_FEED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMEOUT_STETH_ETH_FEED","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authorityInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fallbackCaller","outputs":[{"internalType":"contract IFallbackCaller","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fetchPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastGoodPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_useDynamicFeed","type":"bool"}],"name":"setCollateralFeedSource","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_fallbackCaller","type":"address"}],"name":"setFallbackCaller","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"status","outputs":[{"internalType":"enum IPriceFeed.Status","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"useDynamicFeed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

6101206040523480156200001257600080fd5b506040516200286c3803806200286c833981016040819052620000359162000aa9565b600180546001600160a01b0319166001600160a01b0387161790556200005b8462000413565b6040516001600160a01b038616906000907f633b20eaebf02bd523c44b01ff791580199b6217bae352f4cbdc95e1226fb550908290a36001600160a01b03808316608052831660a052604051620000b29062000a7e565b604051809103906000f080158015620000cf573d6000803e3d6000fd5b506001600160a01b031660c0816001600160a01b03168152505060006080516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200012c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000152919062000b21565b9050601260ff821611156200016657600080fd5b600060a0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001a9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001cf919062000b21565b9050601260ff82161115620001e357600080fd5b60c0516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000224573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200024a919062000b21565b60ff168160ff16146200025c57600080fd5b8160ff168160ff161162000271578162000273565b805b6200028090600262000b5c565b6200028d90600a62000c7f565b60e05260ff80831690821611620002bd57620002aa818362000c90565b620002b790600a62000c7f565b620002d6565b620002c9828262000c90565b620002d690600a62000c7f565b6101009081526003805461ff0019168515159092029190911790556000620002fd62000527565b905060006200031b82600001518360200151620006bf60201b60201c565b9050620003298282620008cd565b1580156200033f57506200033d82620008f3565b155b620003aa5760405162461bcd60e51b815260206004820152603060248201527f5072696365466565643a20436861696e6c696e6b206d75737420626520776f7260448201526f1ada5b99c8185b990818dd5c9c995b9d60821b60648201526084015b60405180910390fd5b6040820151620003ba9062000928565b506003805460ff19169055620003cf62000939565b6001600160a01b03167f0bf6cc51307ce9e3a6e5ff2f9281a57123273aff808032156de6990798c4eb9460405160405180910390a250505050505050505062000d8f565b6000546001600160a01b0316156200046e5760405162461bcd60e51b815260206004820152601b60248201527f417574683a20617574686f72697479206973206e6f6e2d7a65726f00000000006044820152606401620003a1565b600054600160a01b900460ff1615620004d65760405162461bcd60e51b815260206004820152602360248201527f417574683a20617574686f7269747920616c726561647920696e697469616c696044820152621e995960ea1b6064820152608401620003a1565b600080546001600160a81b0319166001600160a01b038316908117600160a01b178255604051909130917fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b763899801989190a350565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526000806080516001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa925050508015620005bb575060408051601f3d908101601f19168201909252620005b89181019062000cc4565b60015b620005c557505090565b506001600160501b0390931686525060608501919091529150620005e862000939565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa92505050801562000644575060408051601f3d908101601f19168201909252620006419181019062000cc4565b60015b6200064e57505090565b506001600160501b039093166020870152506080850191909152905082516200067890836200095a565b801562000691575060208301516200069190826200095a565b15620006ae57620006a3828262000991565b6040840152620006b3565b505090565b5050600160a082015290565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091526001600160501b03831615806200070f57506001600160501b038216155b620008c7576000806080516001600160a01b0316639a6fc8f560018762000737919062000d19565b6040516001600160e01b031960e084901b1681526001600160501b03909116600482015260240160a060405180830381865afa9250505080156200079a575060408051601f3d908101601f19168201909252620007979181019062000cc4565b60015b620007a7575050620008c7565b506001600160501b0390931686525060608501919091529150620007ca62000939565b6001600160a01b0316639a6fc8f5620007e560018762000d19565b6040516001600160e01b031960e084901b1681526001600160501b03909116600482015260240160a060405180830381865afa92505050801562000848575060408051601f3d908101601f19168201909252620008459181019062000cc4565b60015b62000855575050620008c7565b506001600160501b039093166020870152506080850191909152905082516200087f90836200095a565b801562000898575060208301516200089890826200095a565b15620008b557620008aa828262000991565b6040840152620008bd565b5050620008c7565b5050600160a08201525b92915050565b6000620008da83620009d5565b80620008ec5750620008ec82620009d5565b9392505050565b60006200090d82606001516112c062000a3160201b60201c565b80620008c757506080820151620008c79062015f9062000a31565b6000620009358262000a48565b5090565b600354600090610100900460ff1662000953575060c05190565b5060a05190565b60008082136200096d57506000620008c7565b826001600160501b03166000036200098857506000620008c7565b50600192915050565b600060e051670de0b6b3a7640000838561010051620009b1919062000d3c565b620009bd919062000d3c565b620009c9919062000d3c565b620008ec919062000d56565b60008160a00151620009e957506001919050565b60608201511580620009fe5750428260600151115b8062000a0c57506080820151155b8062000a1b5750428260800151115b1562000a2957506001919050565b506000919050565b60008162000a40844262000d79565b119392505050565b6040518181527f4d29de21de555af78a62fc82dd4bc05e9ae5b0660a37f04729527e0f22780cd39060200160405180910390a150565b6103ee806200247e83390190565b80516001600160a01b038116811462000aa457600080fd5b919050565b600080600080600060a0868803121562000ac257600080fd5b62000acd8662000a8c565b945062000add6020870162000a8c565b935062000aed6040870162000a8c565b925062000afd6060870162000a8c565b91506080860151801515811462000b1357600080fd5b809150509295509295909350565b60006020828403121562000b3457600080fd5b815160ff81168114620008ec57600080fd5b634e487b7160e01b600052601160045260246000fd5b60ff818116838216029081169081811462000b7b5762000b7b62000b46565b5092915050565b600181815b8085111562000bc357816000190482111562000ba75762000ba762000b46565b8085161562000bb557918102915b93841c939080029062000b87565b509250929050565b60008262000bdc57506001620008c7565b8162000beb57506000620008c7565b816001811462000c04576002811462000c0f5762000c2f565b6001915050620008c7565b60ff84111562000c235762000c2362000b46565b50506001821b620008c7565b5060208310610133831016604e8410600b841016171562000c54575081810a620008c7565b62000c60838362000b82565b806000190482111562000c775762000c7762000b46565b029392505050565b6000620008ec60ff84168362000bcb565b60ff8281168282160390811115620008c757620008c762000b46565b80516001600160501b038116811462000aa457600080fd5b600080600080600060a0868803121562000cdd57600080fd5b62000ce88662000cac565b945060208601519350604086015192506060860151915062000d0d6080870162000cac565b90509295509295909350565b6001600160501b0382811682821603908082111562000b7b5762000b7b62000b46565b8082028115828204841417620008c757620008c762000b46565b60008262000d7457634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115620008c757620008c762000b46565b60805160a05160c05160e0516101005161168062000dfe6000396000818161026001526112d20152600081816102b201526112a301526000818161019901526112100152600081816101d801526112350152600081816101ff01528181610a630152610c0401526116806000f3fe608060405234801561001057600080fd5b50600436106101375760003560e01c806356e0c35e116100b857806397bc1e1b1161007c57806397bc1e1b146102d45780639a60bfe3146102e6578063a20baee6146102fb578063a3f4df7e1461030a578063b6f0e8ce1461033f578063bf7e214f1461035257600080fd5b806356e0c35e1461025b57806358a6aa88146102825780637a2fe2a9146102915780638151d751146102a4578063918f8674146102ad57600080fd5b80632388efb0116100ff5780632388efb0146101d35780632c9479f0146101fa57806345079cb414610221578063473baff11461022f5780634ce3e31f1461025157600080fd5b80630417cf8e1461013c5780630490be831461015b5780630fdb11cf14610172578063200d2ed21461017a5780632354d60014610194575b600080fd5b610144601281565b60405160ff90911681526020015b60405180910390f35b61016460025481565b604051908152602001610152565b610164610363565b6003546101879060ff1681565b6040516101529190611419565b6101bb7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610152565b6101bb7f000000000000000000000000000000000000000000000000000000000000000081565b6101bb7f000000000000000000000000000000000000000000000000000000000000000081565b61016466b1a2bc2ec5000081565b60035461024190610100900460ff1681565b6040519015158152602001610152565b61016462015f9081565b6101647f000000000000000000000000000000000000000000000000000000000000000081565b6101646706f05b59d3b2000081565b6001546101bb906001600160a01b031681565b6101646112c081565b6101647f000000000000000000000000000000000000000000000000000000000000000081565b600054600160a01b900460ff16610241565b6102f96102f4366004611452565b610733565b005b610164670de0b6b3a764000081565b61033260405180604001604052806009815260200168141c9a58d95199595960ba1b81525081565b604051610152919061146f565b6102f961034d3660046114bd565b6107e2565b6000546001600160a01b03166101bb565b60008061036e610a56565b9050600061038482600001518360200151610bce565b90506000610390610db1565b9050600060035460ff1660048111156103ab576103ab611403565b036104dc576103ba8383610e6f565b15610414576103c881610e90565b156103e1576103d76002610edd565b6000935050505090565b6103ea81610f3b565b156103f9576103d76001610edd565b6104036001610edd565b61040c81610f9a565b935050505090565b61041d83610fae565b1561045c5761042b81610e90565b1561043a576103d76004610edd565b6104446003610edd565b61044d81610f3b565b15610403576000935050505090565b6104668383610fd7565b156104b75761047481610e90565b15610483576103d76002610edd565b61048c81610f3b565b1561049b576103d76001610edd565b6104a58382611050565b156103f95761040c83604001516110e7565b6104c081610e90565b156104cf576104cf6004610edd565b61040c83604001516110e7565b600160035460ff1660048111156104f5576104f5611403565b036105445761050381610e90565b15610512576103d76002610edd565b61051b81610f3b565b1561052a576000935050505090565b6105358383836110f6565b15610403576104cf6000610edd565b600260035460ff16600481111561055d5761055d611403565b036105cb576001546001600160a01b03166105b15761057c8383610e6f565b15801561058f575061058d83610fae565b155b80156105a257506105a08383610fd7565b155b156103d7576104cf6004610edd565b6105bc8383836110f6565b156103d7576104cf6000610edd565b6003805460ff1660048111156105e3576105e3611403565b036106a0576105f28383610e6f565b156106195761060081610e90565b1561060f576103d76002610edd565b6104446001610edd565b61062283610fae565b1561063f5761063081610e90565b15610444576103d76004610edd565b6106498383610fd7565b156106575761060081610e90565b61066081610e90565b1561066f576104cf6004610edd565b61067881610f3b565b15610687576000935050505090565b6106918382611050565b156103f9576104cf6000610edd565b600460035460ff1660048111156106b9576106b9611403565b036103d7576106c88383610e6f565b156106d7576103d76002610edd565b6106e083610fae565b156106ef576000935050505090565b6106f98383610fd7565b15610708576103d76002610edd565b6107138383836110f6565b156104cf576001546001600160a01b0316156104cf576104cf6000610edd565b610749336000356001600160e01b031916611164565b61078f5760405162461bcd60e51b8152602060048201526012602482015271105d5d1a0e8815539055551213d49256915160721b60448201526064015b60405180910390fd5b6003805461ff001916610100831515021790556107aa6111fb565b6001600160a01b03167f0bf6cc51307ce9e3a6e5ff2f9281a57123273aff808032156de6990798c4eb9460405160405180910390a250565b6107f8336000356001600160e01b031916611164565b6108395760405162461bcd60e51b8152602060048201526012602482015271105d5d1a0e8815539055551213d49256915160721b6044820152606401610786565b604080516060810182526000808252602082018190529181019190915281906001600160a01b03831615610a0057816001600160a01b031663bbcb625f6040518163ffffffff1660e01b8152600401606060405180830381865afa9250505080156108c1575060408051601f3d908101601f191682019092526108be918101906114e6565b60015b61090d57826001600160a01b03167f8c32448b27b941b35da4a33f2afee2fdada7d1149551d0d4c28e7feeff3663064260405161090091815260200190565b60405180910390a2505050565b82845260208401829052801515604085015261092884610e90565b1580156109a1575061099f8460200151866001600160a01b0316634277bc066040518163ffffffff1660e01b8152600401602060405180830381865afa158015610976573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099a919061151f565b611257565b155b156109f857600180546001600160a01b038781166001600160a01b03198316179092556040519082169188169082907f633b20eaebf02bd523c44b01ff791580199b6217bae352f4cbdc95e1226fb55090600090a3505b505050505050565b600180546001600160a01b038481166001600160a01b03198316179092556040519082169185169082907f633b20eaebf02bd523c44b01ff791580199b6217bae352f4cbdc95e1226fb55090600090a350505050565b610a5e6113b9565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa925050508015610adb575060408051601f3d908101601f19168201909252610ad891810190611554565b60015b610ae457505090565b506001600160501b0390931686525060608501919091529150610b056111fb565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa925050508015610b5e575060408051601f3d908101601f19168201909252610b5b91810190611554565b60015b610b6757505090565b506001600160501b03909316602087015250608085019190915290508251610b8f908361126c565b8015610ba45750610ba483602001518261126c565b15610bbd57610bb3828261129f565b6040840152610bc2565b505090565b5050600160a082015290565b610bd66113b9565b6001600160501b0383161580610bf357506001600160501b038216155b610dab576000806001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016639a6fc8f5610c346001886115ba565b6040516001600160e01b031960e084901b1681526001600160501b03909116600482015260240160a060405180830381865afa925050508015610c94575060408051601f3d908101601f19168201909252610c9191810190611554565b60015b610c9f575050610dab565b506001600160501b0390931686525060608501919091529150610cc06111fb565b6001600160a01b0316639a6fc8f5610cd96001876115ba565b6040516001600160e01b031960e084901b1681526001600160501b03909116600482015260240160a060405180830381865afa925050508015610d39575060408051601f3d908101601f19168201909252610d3691810190611554565b60015b610d44575050610dab565b506001600160501b03909316602087015250608085019190915290508251610d6c908361126c565b8015610d815750610d8183602001518261126c565b15610d9a57610d90828261129f565b6040840152610da1565b5050610dab565b5050600160a08201525b92915050565b610dd7604051806060016040528060008152602001600081526020016000151581525090565b6001546001600160a01b031615610e6c57600160009054906101000a90046001600160a01b03166001600160a01b031663bbcb625f6040518163ffffffff1660e01b8152600401606060405180830381865afa925050508015610e57575060408051601f3d908101601f19168201909252610e54918101906114e6565b60015b15610e6c579183526020830152151560408201525b90565b6000610e7a83611314565b80610e895750610e8982611314565b9392505050565b60008160400151610ea357506001919050565b60208201511580610eb75750428260200151115b15610ec457506001919050565b8151600003610ed557506001919050565b506000919050565b6003805482919060ff19166001836004811115610efc57610efc611403565b02179055507f5c57579a8214fe4f710c1c56fa829f045b9fa6d225a744225a30c32188064d4e81604051610f309190611419565b60405180910390a150565b6000808260200151118015610dab57506020808301516001546040805163213bde0360e11b81529051610dab946001600160a01b0390931692634277bc0692600480820193918290030181865afa158015610976573d6000803e3d6000fd5b6000610fa98260000151611363565b505190565b6000610fc082606001516112c0611257565b80610dab5750610dab826080015162015f90611257565b600080610fec84604001518460400151611393565b90506000611002856040015185604001516113a9565b9050600080821161101457600061103c565b81670de0b6b3a764000061102885836115e1565b61103291906115f4565b61103c919061160b565b6706f05b59d3b20000109695505050505050565b6001546000906001600160a01b031661106b57506001610dab565b600061107f83600001518560400151611393565b905080600003611093576000915050610dab565b60006110a7846000015186604001516113a9565b9050600082670de0b6b3a76400006110bf82856115e1565b6110c991906115f4565b6110d3919061160b565b66b1a2bc2ec5000010159695505050505050565b60006110f282611363565b5090565b6001546000906001600160a01b031615801590611126575061111782610e90565b80611126575061112682610f3b565b8061113657506111368484610e6f565b80611145575061114584610fae565b1561115257506000610e89565b61115c8483611050565b949350505050565b600080546001600160a01b0316801580159061115c575060405163b700961360e01b81526001600160a01b0385811660048301523060248301526001600160e01b03198516604483015282169063b700961390606401602060405180830381865afa1580156111d7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115c919061162d565b600354600090610100900460ff1661123257507f000000000000000000000000000000000000000000000000000000000000000090565b507f000000000000000000000000000000000000000000000000000000000000000090565b60008161126484426115e1565b119392505050565b600080821361127d57506000610dab565b826001600160501b031660000361129657506000610dab565b50600192915050565b60007f0000000000000000000000000000000000000000000000000000000000000000670de0b6b3a7640000836112f6867f00000000000000000000000000000000000000000000000000000000000000006115f4565b61130091906115f4565b61130a91906115f4565b610e89919061160b565b60008160a0015161132757506001919050565b6060820151158061133b5750428260600151115b8061134857506080820151155b806113565750428260800151115b15610ed557506001919050565b6040518181527f4d29de21de555af78a62fc82dd4bc05e9ae5b0660a37f04729527e0f22780cd390602001610f30565b60008183106113a25781610e89565b5090919050565b6000818310156113a25781610e89565b6040518060c0016040528060006001600160501b0316815260200160006001600160501b031681526020016000815260200160008152602001600081526020016000151581525090565b634e487b7160e01b600052602160045260246000fd5b602081016005831061143b57634e487b7160e01b600052602160045260246000fd5b91905290565b801515811461144f57600080fd5b50565b60006020828403121561146457600080fd5b8135610e8981611441565b600060208083528351808285015260005b8181101561149c57858101830151858201604001528201611480565b506000604082860101526040601f19601f8301168501019250505092915050565b6000602082840312156114cf57600080fd5b81356001600160a01b0381168114610e8957600080fd5b6000806000606084860312156114fb57600080fd5b8351925060208401519150604084015161151481611441565b809150509250925092565b60006020828403121561153157600080fd5b5051919050565b80516001600160501b038116811461154f57600080fd5b919050565b600080600080600060a0868803121561156c57600080fd5b61157586611538565b945060208601519350604086015192506060860151915061159860808701611538565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b6001600160501b038281168282160390808211156115da576115da6115a4565b5092915050565b81810381811115610dab57610dab6115a4565b8082028115828204841417610dab57610dab6115a4565b60008261162857634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561163f57600080fd5b8151610e898161144156fea2646970667358221220128fcd3f494b5397341e7c92e1bcfcfaac459065cfaae5daa44c5b82a92b6b3b64736f6c63430008110033608060405234801561001057600080fd5b506103ce806100206000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80637284e4161161005b5780637284e416146100d75780639a6fc8f514610116578063d5c8610c1461015d578063feaf968c1461016557600080fd5b8063313ce5671461008257806354fd4d50146100a15780635a901295146100b7575b600080fd5b61008a601281565b60405160ff90911681526020015b60405180910390f35b6100a9600181565b604051908152602001610098565b6100bf600181565b6040516001600160501b039091168152602001610098565b604080518082018252601781527f73744554482f45544820466978656420416461707465720000000000000000006020820152905161009891906101f8565b610129610124366004610246565b61016d565b604080516001600160501b03968716815260208101959095528401929092526060830152909116608082015260a001610098565b6100bf600281565b6101296101dc565b6000808080806001600160501b0386166002148061019457506001600160501b0386166001145b61019d57600080fd5b8594506001600160501b0385166002146101c1576101bc60014261028c565b6101c3565b425b91506101d16012600a610389565b935091939590929450565b600260008042816101ef6012600a610389565b93509091929394565b600060208083528351808285015260005b8181101561022557858101830151858201604001528201610209565b506000604082860101526040601f19601f8301168501019250505092915050565b60006020828403121561025857600080fd5b81356001600160501b038116811461026f57600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561029f5761029f610276565b92915050565b600181815b808511156102e05781600019048211156102c6576102c6610276565b808516156102d357918102915b93841c93908002906102aa565b509250929050565b6000826102f75750600161029f565b816103045750600061029f565b816001811461031a576002811461032457610340565b600191505061029f565b60ff84111561033557610335610276565b50506001821b61029f565b5060208310610133831016604e8410600b8410161715610363575081810a61029f565b61036d83836102a5565b806000190482111561038157610381610276565b029392505050565b600061026f60ff8416836102e856fea2646970667358221220582e2bdc4501c188f91e6fb6d50e70e501cb793402ccf5aa8414f1a92a8cfc3664736f6c6343000811003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a095d44831c26cfb6acb806a6531ae3ca32dbc100000000000000000000000086392dc19c0b719886221c78ab11eb8cf5c52812000000000000000000000000e61ebc2b9fd43bca89e38c707acb280907f447cb0000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101375760003560e01c806356e0c35e116100b857806397bc1e1b1161007c57806397bc1e1b146102d45780639a60bfe3146102e6578063a20baee6146102fb578063a3f4df7e1461030a578063b6f0e8ce1461033f578063bf7e214f1461035257600080fd5b806356e0c35e1461025b57806358a6aa88146102825780637a2fe2a9146102915780638151d751146102a4578063918f8674146102ad57600080fd5b80632388efb0116100ff5780632388efb0146101d35780632c9479f0146101fa57806345079cb414610221578063473baff11461022f5780634ce3e31f1461025157600080fd5b80630417cf8e1461013c5780630490be831461015b5780630fdb11cf14610172578063200d2ed21461017a5780632354d60014610194575b600080fd5b610144601281565b60405160ff90911681526020015b60405180910390f35b61016460025481565b604051908152602001610152565b610164610363565b6003546101879060ff1681565b6040516101529190611419565b6101bb7f000000000000000000000000e71306c6353bd8e282f77dbd3a06a357936b3bec81565b6040516001600160a01b039091168152602001610152565b6101bb7f00000000000000000000000086392dc19c0b719886221c78ab11eb8cf5c5281281565b6101bb7f000000000000000000000000e61ebc2b9fd43bca89e38c707acb280907f447cb81565b61016466b1a2bc2ec5000081565b60035461024190610100900460ff1681565b6040519015158152602001610152565b61016462015f9081565b6101647f000000000000000000000000000000000000000000000000000000000000000181565b6101646706f05b59d3b2000081565b6001546101bb906001600160a01b031681565b6101646112c081565b6101647f0000000000000000000000000000000000c097ce7bc90715b34b9f100000000081565b600054600160a01b900460ff16610241565b6102f96102f4366004611452565b610733565b005b610164670de0b6b3a764000081565b61033260405180604001604052806009815260200168141c9a58d95199595960ba1b81525081565b604051610152919061146f565b6102f961034d3660046114bd565b6107e2565b6000546001600160a01b03166101bb565b60008061036e610a56565b9050600061038482600001518360200151610bce565b90506000610390610db1565b9050600060035460ff1660048111156103ab576103ab611403565b036104dc576103ba8383610e6f565b15610414576103c881610e90565b156103e1576103d76002610edd565b6000935050505090565b6103ea81610f3b565b156103f9576103d76001610edd565b6104036001610edd565b61040c81610f9a565b935050505090565b61041d83610fae565b1561045c5761042b81610e90565b1561043a576103d76004610edd565b6104446003610edd565b61044d81610f3b565b15610403576000935050505090565b6104668383610fd7565b156104b75761047481610e90565b15610483576103d76002610edd565b61048c81610f3b565b1561049b576103d76001610edd565b6104a58382611050565b156103f95761040c83604001516110e7565b6104c081610e90565b156104cf576104cf6004610edd565b61040c83604001516110e7565b600160035460ff1660048111156104f5576104f5611403565b036105445761050381610e90565b15610512576103d76002610edd565b61051b81610f3b565b1561052a576000935050505090565b6105358383836110f6565b15610403576104cf6000610edd565b600260035460ff16600481111561055d5761055d611403565b036105cb576001546001600160a01b03166105b15761057c8383610e6f565b15801561058f575061058d83610fae565b155b80156105a257506105a08383610fd7565b155b156103d7576104cf6004610edd565b6105bc8383836110f6565b156103d7576104cf6000610edd565b6003805460ff1660048111156105e3576105e3611403565b036106a0576105f28383610e6f565b156106195761060081610e90565b1561060f576103d76002610edd565b6104446001610edd565b61062283610fae565b1561063f5761063081610e90565b15610444576103d76004610edd565b6106498383610fd7565b156106575761060081610e90565b61066081610e90565b1561066f576104cf6004610edd565b61067881610f3b565b15610687576000935050505090565b6106918382611050565b156103f9576104cf6000610edd565b600460035460ff1660048111156106b9576106b9611403565b036103d7576106c88383610e6f565b156106d7576103d76002610edd565b6106e083610fae565b156106ef576000935050505090565b6106f98383610fd7565b15610708576103d76002610edd565b6107138383836110f6565b156104cf576001546001600160a01b0316156104cf576104cf6000610edd565b610749336000356001600160e01b031916611164565b61078f5760405162461bcd60e51b8152602060048201526012602482015271105d5d1a0e8815539055551213d49256915160721b60448201526064015b60405180910390fd5b6003805461ff001916610100831515021790556107aa6111fb565b6001600160a01b03167f0bf6cc51307ce9e3a6e5ff2f9281a57123273aff808032156de6990798c4eb9460405160405180910390a250565b6107f8336000356001600160e01b031916611164565b6108395760405162461bcd60e51b8152602060048201526012602482015271105d5d1a0e8815539055551213d49256915160721b6044820152606401610786565b604080516060810182526000808252602082018190529181019190915281906001600160a01b03831615610a0057816001600160a01b031663bbcb625f6040518163ffffffff1660e01b8152600401606060405180830381865afa9250505080156108c1575060408051601f3d908101601f191682019092526108be918101906114e6565b60015b61090d57826001600160a01b03167f8c32448b27b941b35da4a33f2afee2fdada7d1149551d0d4c28e7feeff3663064260405161090091815260200190565b60405180910390a2505050565b82845260208401829052801515604085015261092884610e90565b1580156109a1575061099f8460200151866001600160a01b0316634277bc066040518163ffffffff1660e01b8152600401602060405180830381865afa158015610976573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061099a919061151f565b611257565b155b156109f857600180546001600160a01b038781166001600160a01b03198316179092556040519082169188169082907f633b20eaebf02bd523c44b01ff791580199b6217bae352f4cbdc95e1226fb55090600090a3505b505050505050565b600180546001600160a01b038481166001600160a01b03198316179092556040519082169185169082907f633b20eaebf02bd523c44b01ff791580199b6217bae352f4cbdc95e1226fb55090600090a350505050565b610a5e6113b9565b6000807f000000000000000000000000e61ebc2b9fd43bca89e38c707acb280907f447cb6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa925050508015610adb575060408051601f3d908101601f19168201909252610ad891810190611554565b60015b610ae457505090565b506001600160501b0390931686525060608501919091529150610b056111fb565b6001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa925050508015610b5e575060408051601f3d908101601f19168201909252610b5b91810190611554565b60015b610b6757505090565b506001600160501b03909316602087015250608085019190915290508251610b8f908361126c565b8015610ba45750610ba483602001518261126c565b15610bbd57610bb3828261129f565b6040840152610bc2565b505090565b5050600160a082015290565b610bd66113b9565b6001600160501b0383161580610bf357506001600160501b038216155b610dab576000806001600160a01b037f000000000000000000000000e61ebc2b9fd43bca89e38c707acb280907f447cb16639a6fc8f5610c346001886115ba565b6040516001600160e01b031960e084901b1681526001600160501b03909116600482015260240160a060405180830381865afa925050508015610c94575060408051601f3d908101601f19168201909252610c9191810190611554565b60015b610c9f575050610dab565b506001600160501b0390931686525060608501919091529150610cc06111fb565b6001600160a01b0316639a6fc8f5610cd96001876115ba565b6040516001600160e01b031960e084901b1681526001600160501b03909116600482015260240160a060405180830381865afa925050508015610d39575060408051601f3d908101601f19168201909252610d3691810190611554565b60015b610d44575050610dab565b506001600160501b03909316602087015250608085019190915290508251610d6c908361126c565b8015610d815750610d8183602001518261126c565b15610d9a57610d90828261129f565b6040840152610da1565b5050610dab565b5050600160a08201525b92915050565b610dd7604051806060016040528060008152602001600081526020016000151581525090565b6001546001600160a01b031615610e6c57600160009054906101000a90046001600160a01b03166001600160a01b031663bbcb625f6040518163ffffffff1660e01b8152600401606060405180830381865afa925050508015610e57575060408051601f3d908101601f19168201909252610e54918101906114e6565b60015b15610e6c579183526020830152151560408201525b90565b6000610e7a83611314565b80610e895750610e8982611314565b9392505050565b60008160400151610ea357506001919050565b60208201511580610eb75750428260200151115b15610ec457506001919050565b8151600003610ed557506001919050565b506000919050565b6003805482919060ff19166001836004811115610efc57610efc611403565b02179055507f5c57579a8214fe4f710c1c56fa829f045b9fa6d225a744225a30c32188064d4e81604051610f309190611419565b60405180910390a150565b6000808260200151118015610dab57506020808301516001546040805163213bde0360e11b81529051610dab946001600160a01b0390931692634277bc0692600480820193918290030181865afa158015610976573d6000803e3d6000fd5b6000610fa98260000151611363565b505190565b6000610fc082606001516112c0611257565b80610dab5750610dab826080015162015f90611257565b600080610fec84604001518460400151611393565b90506000611002856040015185604001516113a9565b9050600080821161101457600061103c565b81670de0b6b3a764000061102885836115e1565b61103291906115f4565b61103c919061160b565b6706f05b59d3b20000109695505050505050565b6001546000906001600160a01b031661106b57506001610dab565b600061107f83600001518560400151611393565b905080600003611093576000915050610dab565b60006110a7846000015186604001516113a9565b9050600082670de0b6b3a76400006110bf82856115e1565b6110c991906115f4565b6110d3919061160b565b66b1a2bc2ec5000010159695505050505050565b60006110f282611363565b5090565b6001546000906001600160a01b031615801590611126575061111782610e90565b80611126575061112682610f3b565b8061113657506111368484610e6f565b80611145575061114584610fae565b1561115257506000610e89565b61115c8483611050565b949350505050565b600080546001600160a01b0316801580159061115c575060405163b700961360e01b81526001600160a01b0385811660048301523060248301526001600160e01b03198516604483015282169063b700961390606401602060405180830381865afa1580156111d7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115c919061162d565b600354600090610100900460ff1661123257507f000000000000000000000000e71306c6353bd8e282f77dbd3a06a357936b3bec90565b507f00000000000000000000000086392dc19c0b719886221c78ab11eb8cf5c5281290565b60008161126484426115e1565b119392505050565b600080821361127d57506000610dab565b826001600160501b031660000361129657506000610dab565b50600192915050565b60007f0000000000000000000000000000000000c097ce7bc90715b34b9f1000000000670de0b6b3a7640000836112f6867f00000000000000000000000000000000000000000000000000000000000000016115f4565b61130091906115f4565b61130a91906115f4565b610e89919061160b565b60008160a0015161132757506001919050565b6060820151158061133b5750428260600151115b8061134857506080820151155b806113565750428260800151115b15610ed557506001919050565b6040518181527f4d29de21de555af78a62fc82dd4bc05e9ae5b0660a37f04729527e0f22780cd390602001610f30565b60008183106113a25781610e89565b5090919050565b6000818310156113a25781610e89565b6040518060c0016040528060006001600160501b0316815260200160006001600160501b031681526020016000815260200160008152602001600081526020016000151581525090565b634e487b7160e01b600052602160045260246000fd5b602081016005831061143b57634e487b7160e01b600052602160045260246000fd5b91905290565b801515811461144f57600080fd5b50565b60006020828403121561146457600080fd5b8135610e8981611441565b600060208083528351808285015260005b8181101561149c57858101830151858201604001528201611480565b506000604082860101526040601f19601f8301168501019250505092915050565b6000602082840312156114cf57600080fd5b81356001600160a01b0381168114610e8957600080fd5b6000806000606084860312156114fb57600080fd5b8351925060208401519150604084015161151481611441565b809150509250925092565b60006020828403121561153157600080fd5b5051919050565b80516001600160501b038116811461154f57600080fd5b919050565b600080600080600060a0868803121561156c57600080fd5b61157586611538565b945060208601519350604086015192506060860151915061159860808701611538565b90509295509295909350565b634e487b7160e01b600052601160045260246000fd5b6001600160501b038281168282160390808211156115da576115da6115a4565b5092915050565b81810381811115610dab57610dab6115a4565b8082028115828204841417610dab57610dab6115a4565b60008261162857634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561163f57600080fd5b8151610e898161144156fea2646970667358221220128fcd3f494b5397341e7c92e1bcfcfaac459065cfaae5daa44c5b82a92b6b3b64736f6c63430008110033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a095d44831c26cfb6acb806a6531ae3ca32dbc100000000000000000000000086392dc19c0b719886221c78ab11eb8cf5c52812000000000000000000000000e61ebc2b9fd43bca89e38c707acb280907f447cb0000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _fallbackCallerAddress (address): 0x0000000000000000000000000000000000000000
Arg [1] : _authorityAddress (address): 0x2A095d44831C26cFB6aCb806A6531AE3CA32DBc1
Arg [2] : _collEthCLFeed (address): 0x86392dC19c0b719886221c78AB11eb8Cf5c52812
Arg [3] : _ethBtcCLFeed (address): 0xE61EbC2B9Fd43bCA89E38c707aCb280907f447CB
Arg [4] : _useDynamicFeed (bool): False

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 0000000000000000000000002a095d44831c26cfb6acb806a6531ae3ca32dbc1
Arg [2] : 00000000000000000000000086392dc19c0b719886221c78ab11eb8cf5c52812
Arg [3] : 000000000000000000000000e61ebc2b9fd43bca89e38c707acb280907f447cb
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.