ETH Price: $2,667.93 (+0.08%)

Contract

0xb05F478d93C7063194f37535aD148242B8d1F1B8
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Setup Asset178688162023-08-08 7:49:23553 days ago1691480963IN
0xb05F478d...2B8d1F1B8
0 ETH0.002522615.58096783
Setup Asset178349382023-08-03 14:02:59558 days ago1691071379IN
0xb05F478d...2B8d1F1B8
0 ETH0.0084722352.20076344
Setup Asset178345012023-08-03 12:34:23558 days ago1691066063IN
0xb05F478d...2B8d1F1B8
0 ETH0.0041107920.59578993
Setup Asset178340662023-08-03 11:07:11558 days ago1691060831IN
0xb05F478d...2B8d1F1B8
0 ETH0.0023015714.22157562
Set Heartbeat178336552023-08-03 9:44:11558 days ago1691055851IN
0xb05F478d...2B8d1F1B8
0 ETH0.0005379614.71589182
Set Heartbeat178336542023-08-03 9:43:59558 days ago1691055839IN
0xb05F478d...2B8d1F1B8
0 ETH0.0005527115.11916349
Set Heartbeat178336532023-08-03 9:43:47558 days ago1691055827IN
0xb05F478d...2B8d1F1B8
0 ETH0.0005677915.5318846
Set Heartbeat178336522023-08-03 9:43:35558 days ago1691055815IN
0xb05F478d...2B8d1F1B8
0 ETH0.0005720815.64909667
Set Heartbeat178336502023-08-03 9:43:11558 days ago1691055791IN
0xb05F478d...2B8d1F1B8
0 ETH0.0004907513.42439225
Set Heartbeat178336492023-08-03 9:42:47558 days ago1691055767IN
0xb05F478d...2B8d1F1B8
0 ETH0.000496813.5942092
Setup Asset178230922023-08-01 22:18:47559 days ago1690928327IN
0xb05F478d...2B8d1F1B8
0 ETH0.0044100518.4289005
Setup Asset178219662023-08-01 18:33:11559 days ago1690914791IN
0xb05F478d...2B8d1F1B8
0 ETH0.0069405932.09153533
Setup Asset178197822023-08-01 11:14:11560 days ago1690888451IN
0xb05F478d...2B8d1F1B8
0 ETH0.0029839517.66460461
Setup Asset178189852023-08-01 8:33:59560 days ago1690878839IN
0xb05F478d...2B8d1F1B8
0 ETH0.000549616.4596805
Setup Asset178189852023-08-01 8:33:59560 days ago1690878839IN
0xb05F478d...2B8d1F1B8
0 ETH0.0035959416.4596805
Setup Asset178189542023-08-01 8:27:47560 days ago1690878467IN
0xb05F478d...2B8d1F1B8
0 ETH0.0031747516.03120112
Setup Asset178145982023-07-31 17:51:35560 days ago1690825895IN
0xb05F478d...2B8d1F1B8
0 ETH0.0053669227.21258376
Setup Asset178133782023-07-31 13:45:59561 days ago1690811159IN
0xb05F478d...2B8d1F1B8
0 ETH0.0040490426.44186509

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xe37B8c83...61D47e423
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
ChainlinkV3PriceProvider

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 8 : ChainlinkV3PriceProvider.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.13;

import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

import "../PriceProvider.sol";
import "../IERC20LikeV2.sol";

contract ChainlinkV3PriceProvider is PriceProvider {
    using SafeMath for uint256;

    struct AssetData {
        // Time threshold to invalidate stale prices
        uint256 heartbeat;
        // If true, we bypass the aggregator and consult the fallback provider directly
        bool forceFallback;
        // If true, the aggregator returns price in USD, so we need to convert to QUOTE
        bool convertToQuote;
        // Chainlink aggregator proxy
        AggregatorV3Interface aggregator;
        // Provider used if the aggregator's price is invalid or if it became disabled
        IPriceProvider fallbackProvider;
    }

    /// @dev Aggregator that converts from USD to quote token
    AggregatorV3Interface internal immutable _QUOTE_AGGREGATOR; // solhint-disable-line var-name-mixedcase

    /// @dev Decimals used by the _QUOTE_AGGREGATOR
    uint8 internal immutable _QUOTE_AGGREGATOR_DECIMALS; // solhint-disable-line var-name-mixedcase

    /// @dev Used to optimize calculations in emergency disable function
    // solhint-disable-next-line var-name-mixedcase
    uint256 internal immutable _MAX_PRICE_DIFF = type(uint256).max / (100 * EMERGENCY_PRECISION);
    
    // @dev Precision to use for the EMERGENCY_THRESHOLD
    uint256 public constant EMERGENCY_PRECISION = 1e6;

    /// @dev Disable the aggregator if the difference with the fallback is higher than this percentage (10%)
    uint256 public constant EMERGENCY_THRESHOLD = 10 * EMERGENCY_PRECISION; // solhint-disable-line var-name-mixedcase

    /// @dev this is basically `PriceProvider.quoteToken.decimals()`
    uint8 internal immutable _QUOTE_TOKEN_DECIMALS; // solhint-disable-line var-name-mixedcase

    /// @dev Address allowed to call the emergencyDisable function, can be set by the owner
    address public emergencyManager;

    /// @dev Threshold used to determine if the price returned by the _QUOTE_AGGREGATOR is valid
    uint256 public quoteAggregatorHeartbeat;

    /// @dev Data used for each asset
    mapping(address => AssetData) public assetData;

    event NewAggregator(address indexed asset, AggregatorV3Interface indexed aggregator, bool convertToQuote);
    event NewFallbackPriceProvider(address indexed asset, IPriceProvider indexed fallbackProvider);
    event NewHeartbeat(address indexed asset, uint256 heartbeat);
    event NewQuoteAggregatorHeartbeat(uint256 heartbeat);
    event NewEmergencyManager(address indexed emergencyManager);
    event AggregatorDisabled(address indexed asset, AggregatorV3Interface indexed aggregator);

    error AggregatorDidNotChange();
    error AggregatorPriceNotAvailable();
    error AssetNotSupported();
    error EmergencyManagerDidNotChange();
    error EmergencyThresholdNotReached();
    error FallbackProviderAlreadySet();
    error FallbackProviderDidNotChange();
    error FallbackProviderNotSet();
    error HeartbeatDidNotChange();
    error InvalidAggregator();
    error InvalidAggregatorDecimals();
    error InvalidFallbackPriceProvider();
    error InvalidHeartbeat();
    error OnlyEmergencyManager();
    error QuoteAggregatorHeartbeatDidNotChange();

    modifier onlyAssetSupported(address _asset) {
        if (!assetSupported(_asset)) {
            revert AssetNotSupported();
        }

        _;
    }

    constructor(
        IPriceProvidersRepository _priceProvidersRepository,
        address _emergencyManager,
        AggregatorV3Interface _quoteAggregator,
        uint256 _quoteAggregatorHeartbeat
    ) PriceProvider(_priceProvidersRepository) {
        _setEmergencyManager(_emergencyManager);
        _QUOTE_TOKEN_DECIMALS = IERC20LikeV2(quoteToken).decimals();
        _QUOTE_AGGREGATOR = _quoteAggregator;
        _QUOTE_AGGREGATOR_DECIMALS = _quoteAggregator.decimals();
        quoteAggregatorHeartbeat = _quoteAggregatorHeartbeat;
    }

    /// @inheritdoc IPriceProvider
    function assetSupported(address _asset) public view virtual override returns (bool) {
        AssetData storage data = assetData[_asset];

        // Asset is supported if:
        //     - the asset is the quote token
        //       OR
        //     - the aggregator address is defined AND
        //         - the aggregator is not disabled
        //           OR
        //         - the fallback is defined

        if (_asset == quoteToken) {
            return true;
        }

        if (address(data.aggregator) != address(0)) {
            return !data.forceFallback || address(data.fallbackProvider) != address(0);
        }

        return false;
    }

    /// @dev Returns price directly from aggregator using all internal settings except of fallback provider
    /// @param _asset Asset for which we want to get the price
    function getAggregatorPrice(address _asset) public view virtual returns (bool success, uint256 price) {
        (success, price) = _getAggregatorPrice(_asset);
    }
    
    /// @inheritdoc IPriceProvider
    function getPrice(address _asset) public view virtual override returns (uint256) {
        address quote = quoteToken;

        if (_asset == quote) {
            return 10 ** _QUOTE_TOKEN_DECIMALS;
        }

        (bool success, uint256 price) = _getAggregatorPrice(_asset);

        return success ? price : _getFallbackPrice(_asset);
    }

    /// @dev Sets the aggregator, fallbackProvider and heartbeat for an asset. Can only be called by the manager.
    /// @param _asset Asset to setup
    /// @param _aggregator Chainlink aggregator proxy
    /// @param _fallbackProvider Provider to use if the price is invalid or if the aggregator was disabled
    /// @param _heartbeat Threshold in seconds to invalidate a stale price
    function setupAsset(
        address _asset,
        AggregatorV3Interface _aggregator,
        IPriceProvider _fallbackProvider,
        uint256 _heartbeat,
        bool _convertToQuote
    ) external virtual onlyManager {
        // This has to be done first so that `_setAggregator` works
        _setHeartbeat(_asset, _heartbeat);

        if (!_setAggregator(_asset, _aggregator, _convertToQuote)) revert AggregatorDidNotChange();

        // We don't care if this doesn't change
        _setFallbackPriceProvider(_asset, _fallbackProvider);
    }

    /// @dev Sets the aggregator for an asset. Can only be called by the manager.
    /// @param _asset Asset for which to set the aggregator
    /// @param _aggregator Aggregator to set
    function setAggregator(address _asset, AggregatorV3Interface _aggregator, bool _convertToQuote)
        external
        virtual
        onlyManager
        onlyAssetSupported(_asset)
    {
        if (!_setAggregator(_asset, _aggregator, _convertToQuote)) revert AggregatorDidNotChange();
    }

    /// @dev Sets the fallback provider for an asset. Can only be called by the manager.
    /// @param _asset Asset for which to set the fallback provider
    /// @param _fallbackProvider Provider to set
    function setFallbackPriceProvider(address _asset, IPriceProvider _fallbackProvider)
        external
        virtual
        onlyManager
        onlyAssetSupported(_asset)
    {
        if (!_setFallbackPriceProvider(_asset, _fallbackProvider)) {
            revert FallbackProviderDidNotChange();
        }
    }

    /// @dev Sets the heartbeat threshold for an asset. Can only be called by the manager.
    /// @param _asset Asset for which to set the heartbeat threshold
    /// @param _heartbeat Threshold to set
    function setHeartbeat(address _asset, uint256 _heartbeat)
        external
        virtual
        onlyManager
        onlyAssetSupported(_asset)
    {
        if (!_setHeartbeat(_asset, _heartbeat)) revert HeartbeatDidNotChange();
    }

    /// @dev Sets the quote aggregator heartbeat threshold. Can only be called by the manager.
    /// @param _heartbeat Threshold to set
    function setQuoteAggregatorHeartbeat(uint256 _heartbeat)
        external
        virtual
        onlyManager
    {
        if (!_setQuoteAggregatorHeartbeat(_heartbeat)) revert QuoteAggregatorHeartbeatDidNotChange();
    }

    /// @dev Sets the emergencyManager. Can only be called by the manager.
    /// @param _emergencyManager Emergency manager to set
    function setEmergencyManager(address _emergencyManager) external virtual onlyManager {
        if (!_setEmergencyManager(_emergencyManager)) revert EmergencyManagerDidNotChange();
    }

    /// @dev Disables the aggregator for an asset if there is a big discrepancy between the aggregator and the
    /// fallback provider. The only way to reenable the asset is by calling setupAsset or setAggregator again.
    /// Can only be called by the emergencyManager.
    /// @param _asset Asset for which to disable the aggregator
    function emergencyDisable(address _asset) external virtual {
        if (msg.sender != emergencyManager) {
            revert OnlyEmergencyManager();
        }

        (bool success, uint256 price) = _getAggregatorPrice(_asset);

        if (!success) {
            revert AggregatorPriceNotAvailable();
        }

        uint256 fallbackPrice = _getFallbackPrice(_asset);

        uint256 diff;

        unchecked {
            // It is ok to uncheck because of the initial fallbackPrice >= price check
            diff = fallbackPrice >= price ? fallbackPrice - price : price - fallbackPrice;
        }

        if (diff > _MAX_PRICE_DIFF || (diff * 100 * EMERGENCY_PRECISION) / price < EMERGENCY_THRESHOLD) {
            revert EmergencyThresholdNotReached();
        }

        // Disable main aggregator, fallback stays enabled
        assetData[_asset].forceFallback = true;

        emit AggregatorDisabled(_asset, assetData[_asset].aggregator);
    }

    function getFallbackProvider(address _asset) external view virtual returns (IPriceProvider) {
        return assetData[_asset].fallbackProvider;
    }

    function _getAggregatorPrice(address _asset) internal view virtual returns (bool success, uint256 price) {
        AssetData storage data = assetData[_asset];

        uint256 heartbeat = data.heartbeat;
        bool forceFallback = data.forceFallback;
        AggregatorV3Interface aggregator = data.aggregator;

        if (address(aggregator) == address(0)) revert AssetNotSupported();

        (
            /*uint80 roundID*/,
            int256 aggregatorPrice,
            /*uint256 startedAt*/,
            uint256 timestamp,
            /*uint80 answeredInRound*/
        ) = aggregator.latestRoundData();

        // If a valid price is returned and it was updated recently
        if (!forceFallback && _isValidPrice(aggregatorPrice, timestamp, heartbeat)) {
            uint256 result;

            if (data.convertToQuote) {
                // _toQuote performs decimal normalization internally
                result = _toQuote(uint256(aggregatorPrice));
            } else {
                uint8 aggregatorDecimals = aggregator.decimals();
                result = _normalizeWithDecimals(uint256(aggregatorPrice), aggregatorDecimals);
            }

            return (true, result);
        }

        return (false, 0);
    }

    function _getFallbackPrice(address _asset) internal view virtual returns (uint256) {
        IPriceProvider fallbackProvider = assetData[_asset].fallbackProvider;

        if (address(fallbackProvider) == address(0)) revert FallbackProviderNotSet();

        return fallbackProvider.getPrice(_asset);
    }

    function _setEmergencyManager(address _emergencyManager) internal virtual returns (bool changed) {
        if (_emergencyManager == emergencyManager) {
            return false;
        }

        emergencyManager = _emergencyManager;

        emit NewEmergencyManager(_emergencyManager);

        return true;
    }

    function _setAggregator(
        address _asset,
        AggregatorV3Interface _aggregator,
        bool _convertToQuote
    ) internal virtual returns (bool changed) {
        if (address(_aggregator) == address(0)) revert InvalidAggregator();

        AssetData storage data = assetData[_asset];

        if (data.aggregator == _aggregator && data.forceFallback == false) {
            return false;
        }

        // There doesn't seem to be a way to verify if this is a "valid" aggregator (other than getting the price)
        data.forceFallback = false;
        data.aggregator = _aggregator;

        (bool success,) = _getAggregatorPrice(_asset);

        if (!success) revert AggregatorPriceNotAvailable();

        if (_convertToQuote && _aggregator.decimals() != _QUOTE_AGGREGATOR_DECIMALS) {
            revert InvalidAggregatorDecimals();
        }

        // We want to always update this
        assetData[_asset].convertToQuote = _convertToQuote;

        emit NewAggregator(_asset, _aggregator, _convertToQuote);

        return true;
    }

    function _setFallbackPriceProvider(address _asset, IPriceProvider _fallbackProvider)
        internal
        virtual
        returns (bool changed)
    {
        if (_fallbackProvider == assetData[_asset].fallbackProvider) {
            return false;
        }

        assetData[_asset].fallbackProvider = _fallbackProvider;

        if (address(_fallbackProvider) != address(0)) {
            if (
                !priceProvidersRepository.isPriceProvider(_fallbackProvider) ||
                !_fallbackProvider.assetSupported(_asset) ||
                _fallbackProvider.quoteToken() != quoteToken
            ) {
                revert InvalidFallbackPriceProvider();
            }

            // Make sure it doesn't revert
            _getFallbackPrice(_asset);
        }

        emit NewFallbackPriceProvider(_asset, _fallbackProvider);

        return true;
    }

    function _setHeartbeat(address _asset, uint256 _heartbeat) internal virtual returns (bool changed) {
        // Arbitrary limit, Chainlink's threshold is always less than a day
        if (_heartbeat > 2 days) revert InvalidHeartbeat();

        if (_heartbeat == assetData[_asset].heartbeat) {
            return false;
        }

        assetData[_asset].heartbeat = _heartbeat;

        emit NewHeartbeat(_asset, _heartbeat);

        return true;
    }

    function _setQuoteAggregatorHeartbeat(uint256 _heartbeat) internal virtual returns (bool changed) {
        // Arbitrary limit, Chainlink's threshold is always less than a day
        if (_heartbeat > 2 days) revert InvalidHeartbeat();

        if (_heartbeat == quoteAggregatorHeartbeat) {
            return false;
        }

        quoteAggregatorHeartbeat = _heartbeat;

        emit NewQuoteAggregatorHeartbeat(_heartbeat);

        return true;
    }

    /// @dev Adjusts the given price to use the same decimals as the quote token.
    /// @param _price Price to adjust decimals
    /// @param _decimals Decimals considered in `_price`
    function _normalizeWithDecimals(uint256 _price, uint8 _decimals) internal view virtual returns (uint256) {
        // We want to return the price of 1 asset token, but with the decimals of the quote token
        if (_QUOTE_TOKEN_DECIMALS == _decimals) {
            return _price;
        } else if (_QUOTE_TOKEN_DECIMALS < _decimals) {
            return _price / 10 ** (_decimals - _QUOTE_TOKEN_DECIMALS);
        } else {
            return _price * 10 ** (_QUOTE_TOKEN_DECIMALS - _decimals);
        }
    }

    /// @dev Converts a price returned by an aggregator to quote units
    function _toQuote(uint256 _price) internal view virtual returns (uint256) {
       (
            /*uint80 roundID*/,
            int256 aggregatorPrice,
            /*uint256 startedAt*/,
            uint256 timestamp,
            /*uint80 answeredInRound*/
        ) = _QUOTE_AGGREGATOR.latestRoundData();

        // If an invalid price is returned
        if (!_isValidPrice(aggregatorPrice, timestamp, quoteAggregatorHeartbeat)) {
            revert AggregatorPriceNotAvailable();
        }

        // _price and aggregatorPrice should both have the same decimals so we normalize here
        return _price * 10 ** _QUOTE_TOKEN_DECIMALS / uint256(aggregatorPrice);
    }

    function _isValidPrice(int256 _price, uint256 _timestamp, uint256 _heartbeat) internal view virtual returns (bool) {
        return _price > 0 && block.timestamp - _timestamp < _heartbeat;
    }
}

File 2 of 8 : SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 3 of 8 : AggregatorV3Interface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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 4 of 8 : PriceProvider.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.6 <0.9.0;

import "../lib/Ping.sol";
import "../interfaces/IPriceProvider.sol";
import "../interfaces/IPriceProvidersRepository.sol";

/// @title PriceProvider
/// @notice Abstract PriceProvider contract, parent of all PriceProviders
/// @dev Price provider is a contract that directly integrates with a price source, ie. a DEX or alternative system
/// like Chainlink to calculate TWAP prices for assets. Each price provider should support a single price source
/// and multiple assets.
abstract contract PriceProvider is IPriceProvider {
    /// @notice PriceProvidersRepository address
    IPriceProvidersRepository public immutable priceProvidersRepository;

    /// @notice Token address which prices are quoted in. Must be the same as PriceProvidersRepository.quoteToken
    address public immutable override quoteToken;

    modifier onlyManager() {
        if (priceProvidersRepository.manager() != msg.sender) revert("OnlyManager");
        _;
    }

    /// @param _priceProvidersRepository address of PriceProvidersRepository
    constructor(IPriceProvidersRepository _priceProvidersRepository) {
        if (
            !Ping.pong(_priceProvidersRepository.priceProvidersRepositoryPing)            
        ) {
            revert("InvalidPriceProviderRepository");
        }

        priceProvidersRepository = _priceProvidersRepository;
        quoteToken = _priceProvidersRepository.quoteToken();
    }

    /// @inheritdoc IPriceProvider
    function priceProviderPing() external pure override returns (bytes4) {
        return this.priceProviderPing.selector;
    }

    function _revertBytes(bytes memory _errMsg, string memory _customErr) internal pure {
        if (_errMsg.length > 0) {
            assembly { // solhint-disable-line no-inline-assembly
                revert(add(32, _errMsg), mload(_errMsg))
            }
        }

        revert(_customErr);
    }
}

File 5 of 8 : IERC20LikeV2.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.6;

/// @dev This is only meant to be used by price providers, which use a different
/// Solidity version than the rest of the codebase. This way de won't need to include
/// an additional version of OpenZeppelin's library.
interface IERC20LikeV2 {
    function decimals() external view returns (uint8);
    function balanceOf(address) external view returns(uint256);
}

File 6 of 8 : Ping.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.6 <0.9.0;


library Ping {
    function pong(function() external pure returns(bytes4) pingFunction) internal pure returns (bool) {
        return pingFunction.address != address(0) && pingFunction.selector == pingFunction();
    }
}

File 7 of 8 : IPriceProvider.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.6 <0.9.0;

/// @title Common interface for Silo Price Providers
interface IPriceProvider {
    /// @notice Returns "Time-Weighted Average Price" for an asset. Calculates TWAP price for quote/asset.
    /// It unifies all tokens decimal to 18, examples:
    /// - if asses == quote it returns 1e18
    /// - if asset is USDC and quote is ETH and ETH costs ~$3300 then it returns ~0.0003e18 WETH per 1 USDC
    /// @param _asset address of an asset for which to read price
    /// @return price of asses with 18 decimals, throws when pool is not ready yet to provide price
    function getPrice(address _asset) external view returns (uint256 price);

    /// @dev Informs if PriceProvider is setup for asset. It does not means PriceProvider can provide price right away.
    /// Some providers implementations need time to "build" buffer for TWAP price,
    /// so price may not be available yet but this method will return true.
    /// @param _asset asset in question
    /// @return TRUE if asset has been setup, otherwise false
    function assetSupported(address _asset) external view returns (bool);

    /// @notice Gets token address in which prices are quoted
    /// @return quoteToken address
    function quoteToken() external view returns (address);

    /// @notice Helper method that allows easily detects, if contract is PriceProvider
    /// @dev this can save us from simple human errors, in case we use invalid address
    /// but this should NOT be treated as security check
    /// @return always true
    function priceProviderPing() external pure returns (bytes4);
}

File 8 of 8 : IPriceProvidersRepository.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.7.6 <0.9.0;

import "./IPriceProvider.sol";

interface IPriceProvidersRepository {
    /// @notice Emitted when price provider is added
    /// @param newPriceProvider new price provider address
    event NewPriceProvider(IPriceProvider indexed newPriceProvider);

    /// @notice Emitted when price provider is removed
    /// @param priceProvider removed price provider address
    event PriceProviderRemoved(IPriceProvider indexed priceProvider);

    /// @notice Emitted when asset is assigned to price provider
    /// @param asset assigned asset   address
    /// @param priceProvider price provider address
    event PriceProviderForAsset(address indexed asset, IPriceProvider indexed priceProvider);

    /// @notice Register new price provider
    /// @param _priceProvider address of price provider
    function addPriceProvider(IPriceProvider _priceProvider) external;

    /// @notice Unregister price provider
    /// @param _priceProvider address of price provider to be removed
    function removePriceProvider(IPriceProvider _priceProvider) external;

    /// @notice Sets price provider for asset
    /// @dev Request for asset price is forwarded to the price provider assigned to that asset
    /// @param _asset address of an asset for which price provider will be used
    /// @param _priceProvider address of price provider
    function setPriceProviderForAsset(address _asset, IPriceProvider _priceProvider) external;

    /// @notice Returns "Time-Weighted Average Price" for an asset
    /// @param _asset address of an asset for which to read price
    /// @return price TWAP price of a token with 18 decimals
    function getPrice(address _asset) external view returns (uint256 price);

    /// @notice Gets price provider assigned to an asset
    /// @param _asset address of an asset for which to get price provider
    /// @return priceProvider address of price provider
    function priceProviders(address _asset) external view returns (IPriceProvider priceProvider);

    /// @notice Gets token address in which prices are quoted
    /// @return quoteToken address
    function quoteToken() external view returns (address);

    /// @notice Gets manager role address
    /// @return manager role address
    function manager() external view returns (address);

    /// @notice Checks if providers are available for an asset
    /// @param _asset asset address to check
    /// @return returns TRUE if price feed is ready, otherwise false
    function providersReadyForAsset(address _asset) external view returns (bool);

    /// @notice Returns true if address is a registered price provider
    /// @param _provider address of price provider to be removed
    /// @return true if address is a registered price provider, otherwise false
    function isPriceProvider(IPriceProvider _provider) external view returns (bool);

    /// @notice Gets number of price providers registered
    /// @return number of price providers registered
    function providersCount() external view returns (uint256);

    /// @notice Gets an array of price providers
    /// @return array of price providers
    function providerList() external view returns (address[] memory);

    /// @notice Sanity check function
    /// @return returns always TRUE
    function priceProvidersRepositoryPing() external pure returns (bytes4);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IPriceProvidersRepository","name":"_priceProvidersRepository","type":"address"},{"internalType":"address","name":"_emergencyManager","type":"address"},{"internalType":"contract AggregatorV3Interface","name":"_quoteAggregator","type":"address"},{"internalType":"uint256","name":"_quoteAggregatorHeartbeat","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AggregatorDidNotChange","type":"error"},{"inputs":[],"name":"AggregatorPriceNotAvailable","type":"error"},{"inputs":[],"name":"AssetNotSupported","type":"error"},{"inputs":[],"name":"EmergencyManagerDidNotChange","type":"error"},{"inputs":[],"name":"EmergencyThresholdNotReached","type":"error"},{"inputs":[],"name":"FallbackProviderAlreadySet","type":"error"},{"inputs":[],"name":"FallbackProviderDidNotChange","type":"error"},{"inputs":[],"name":"FallbackProviderNotSet","type":"error"},{"inputs":[],"name":"HeartbeatDidNotChange","type":"error"},{"inputs":[],"name":"InvalidAggregator","type":"error"},{"inputs":[],"name":"InvalidAggregatorDecimals","type":"error"},{"inputs":[],"name":"InvalidFallbackPriceProvider","type":"error"},{"inputs":[],"name":"InvalidHeartbeat","type":"error"},{"inputs":[],"name":"OnlyEmergencyManager","type":"error"},{"inputs":[],"name":"QuoteAggregatorHeartbeatDidNotChange","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"contract AggregatorV3Interface","name":"aggregator","type":"address"}],"name":"AggregatorDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"contract AggregatorV3Interface","name":"aggregator","type":"address"},{"indexed":false,"internalType":"bool","name":"convertToQuote","type":"bool"}],"name":"NewAggregator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"emergencyManager","type":"address"}],"name":"NewEmergencyManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"contract IPriceProvider","name":"fallbackProvider","type":"address"}],"name":"NewFallbackPriceProvider","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"heartbeat","type":"uint256"}],"name":"NewHeartbeat","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"heartbeat","type":"uint256"}],"name":"NewQuoteAggregatorHeartbeat","type":"event"},{"inputs":[],"name":"EMERGENCY_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMERGENCY_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetData","outputs":[{"internalType":"uint256","name":"heartbeat","type":"uint256"},{"internalType":"bool","name":"forceFallback","type":"bool"},{"internalType":"bool","name":"convertToQuote","type":"bool"},{"internalType":"contract AggregatorV3Interface","name":"aggregator","type":"address"},{"internalType":"contract IPriceProvider","name":"fallbackProvider","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"assetSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"emergencyDisable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getAggregatorPrice","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getFallbackProvider","outputs":[{"internalType":"contract IPriceProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceProviderPing","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"priceProvidersRepository","outputs":[{"internalType":"contract IPriceProvidersRepository","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteAggregatorHeartbeat","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"contract AggregatorV3Interface","name":"_aggregator","type":"address"},{"internalType":"bool","name":"_convertToQuote","type":"bool"}],"name":"setAggregator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_emergencyManager","type":"address"}],"name":"setEmergencyManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"contract IPriceProvider","name":"_fallbackProvider","type":"address"}],"name":"setFallbackPriceProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_heartbeat","type":"uint256"}],"name":"setHeartbeat","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_heartbeat","type":"uint256"}],"name":"setQuoteAggregatorHeartbeat","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"contract AggregatorV3Interface","name":"_aggregator","type":"address"},{"internalType":"contract IPriceProvider","name":"_fallbackProvider","type":"address"},{"internalType":"uint256","name":"_heartbeat","type":"uint256"},{"internalType":"bool","name":"_convertToQuote","type":"bool"}],"name":"setupAsset","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101215760003560e01c80635ddf2be3116100ad578063b31fb25611610071578063b31fb256146102fe578063d0532d9114610321578063d2c18f5914610334578063da31cf3c14610347578063db09c3fd1461035057600080fd5b80635ddf2be31461028b57806375435703146102b25780637f2141c8146102c55780638f001f59146102d85780639a2ca257146102eb57600080fd5b80632553b17f116100f45780632553b17f146101b45780632f1605fc146101c957806341976e09146101dc57806341fee44a146101ef57806357e0c50f1461027657600080fd5b8063087d31b7146101265780630f2a1632146101415780631d498ad31461014b578063217a4b7014610175575b600080fd5b61012e610380565b6040519081526020015b60405180910390f35b61012e620f424081565b61015e6101593660046116b9565b610391565b604080519215158352602083019190915201610138565b61019c7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6040516001600160a01b039091168152602001610138565b6101c76101c23660046116d6565b6103a7565b005b6101c76101d736600461170f565b6104b5565b61012e6101ea3660046116b9565b6105b5565b61023f6101fd3660046116b9565b600260208190526000918252604090912080546001820154919092015460ff808316926101008104909116916001600160a01b03620100009092048216911685565b604080519586529315156020860152911515928401929092526001600160a01b03918216606084015216608082015260a001610138565b6040516357e0c50f60e01b8152602001610138565b61019c7f000000000000000000000000a40111994f44c8add82ef495269e19109c9a982a81565b6101c76102c03660046116b9565b61064b565b6101c76102d3366004611749565b6107a8565b6101c76102e6366004611794565b6108af565b6101c76102f93660046117ad565b61098a565b61031161030c3660046116b9565b610a81565b6040519015158152602001610138565b6101c761032f3660046116b9565b610b17565b60005461019c906001600160a01b031681565b61012e60015481565b61019c61035e3660046116b9565b6001600160a01b03908116600090815260026020819052604090912001541690565b61038e620f4240600a61182b565b81565b60008061039d83610c77565b9094909350915050565b336001600160a01b03167f000000000000000000000000a40111994f44c8add82ef495269e19109c9a982a6001600160a01b031663481c6a756040518163ffffffff1660e01b8152600401602060405180830381865afa15801561040f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610433919061184a565b6001600160a01b0316146104625760405162461bcd60e51b815260040161045990611867565b60405180910390fd5b8161046c81610a81565b6104895760405163981a2a2b60e01b815260040160405180910390fd5b6104938383610e06565b6104b057604051630d51b37960e21b815260040160405180910390fd5b505050565b336001600160a01b03167f000000000000000000000000a40111994f44c8add82ef495269e19109c9a982a6001600160a01b031663481c6a756040518163ffffffff1660e01b8152600401602060405180830381865afa15801561051d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610541919061184a565b6001600160a01b0316146105675760405162461bcd60e51b815260040161045990611867565b8161057181610a81565b61058e5760405163981a2a2b60e01b815260040160405180910390fd5b610598838361107b565b6104b05760405163d0abfce560e01b815260040160405180910390fd5b60007f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b038082169084160361061d576106167f0000000000000000000000000000000000000000000000000000000000000012600a611970565b9392505050565b60008061062985610c77565b91509150816106405761063b85611126565b610642565b805b95945050505050565b6000546001600160a01b0316331461067657604051633111da4560e21b815260040160405180910390fd5b60008061068283610c77565b91509150816106a457604051638a93c04960e01b815260040160405180910390fd5b60006106af84611126565b90506000828210156106c3578183036106c7565b8282035b90507f0000002af31dc4611873bf3f70834acdae9f0f4f534f5d60585a5f1c1a3ced1b8111806107265750610700620f4240600a61182b565b83620f424061071084606461182b565b61071a919061182b565b610724919061197f565b105b15610744576040516332d3273560e21b815260040160405180910390fd5b6001600160a01b038086166000818152600260205260408082206001908101805460ff191690911790819055905162010000909104909316927f19986ca6379d8de58c363928f6de20927669b98ab030c431c2f2fee2625961d59190a35050505050565b336001600160a01b03167f000000000000000000000000a40111994f44c8add82ef495269e19109c9a982a6001600160a01b031663481c6a756040518163ffffffff1660e01b8152600401602060405180830381865afa158015610810573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610834919061184a565b6001600160a01b03161461085a5760405162461bcd60e51b815260040161045990611867565b8261086481610a81565b6108815760405163981a2a2b60e01b815260040160405180910390fd5b61088c8484846111ce565b6108a957604051630fe8d77760e11b815260040160405180910390fd5b50505050565b336001600160a01b03167f000000000000000000000000a40111994f44c8add82ef495269e19109c9a982a6001600160a01b031663481c6a756040518163ffffffff1660e01b8152600401602060405180830381865afa158015610917573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093b919061184a565b6001600160a01b0316146109615760405162461bcd60e51b815260040161045990611867565b61096a816113bf565b6109875760405163f620192160e01b815260040160405180910390fd5b50565b336001600160a01b03167f000000000000000000000000a40111994f44c8add82ef495269e19109c9a982a6001600160a01b031663481c6a756040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a16919061184a565b6001600160a01b031614610a3c5760405162461bcd60e51b815260040161045990611867565b610a46858361107b565b50610a528585836111ce565b610a6f57604051630fe8d77760e11b815260040160405180910390fd5b610a798584610e06565b505050505050565b6001600160a01b038082166000818152600260205260408120909290917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29091169003610ad15750600192915050565b60018101546201000090046001600160a01b031615610b0e57600181015460ff1615806106165750600201546001600160a01b0316151592915050565b50600092915050565b336001600160a01b03167f000000000000000000000000a40111994f44c8add82ef495269e19109c9a982a6001600160a01b031663481c6a756040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba3919061184a565b6001600160a01b031614610bc95760405162461bcd60e51b815260040161045990611867565b610bd281611436565b610987576040516393c3b9ab60e01b815260040160405180910390fd5b60006001600160a01b03831615801590610c6e575082826040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c5991906119a1565b60e083901b6001600160e01b03199081169116145b90505b92915050565b6001600160a01b038082166000908152600260205260408120805460018201549293849360ff811691620100009091041680610cc65760405163981a2a2b60e01b815260040160405180910390fd5b600080826001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610d07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2b91906119ea565b5093505092505083158015610d465750610d468282876114a2565b15610df5576001860154600090610100900460ff1615610d7057610d69836114c3565b9050610de4565b6000846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015610db0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dd49190611a3a565b9050610de084826115bb565b9150505b60019a909950975050505050505050565b506000988998509650505050505050565b6001600160a01b03808316600090815260026020819052604082200154909190811690831603610e3857506000610c71565b6001600160a01b0383811660009081526002602081905260409091200180546001600160a01b031916918416918217905515611032576040516312fd145b60e31b81526001600160a01b0383811660048301527f000000000000000000000000a40111994f44c8add82ef495269e19109c9a982a16906397e8a2d890602401602060405180830381865afa158015610ed4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef89190611a5d565b1580610f6b575060405163598fd92b60e11b81526001600160a01b03848116600483015283169063b31fb25690602401602060405180830381865afa158015610f45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f699190611a5d565b155b8061100957507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316826001600160a01b031663217a4b706040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ffd919061184a565b6001600160a01b031614155b156110275760405163f7ebc71360e01b815260040160405180910390fd5b61103083611126565b505b816001600160a01b0316836001600160a01b03167f26f22f8c474f2065d47d555b7f96badf39d94093d6db814098680b098d96a27860405160405180910390a350600192915050565b60006202a3008211156110a157604051638f1825c960e01b815260040160405180910390fd5b6001600160a01b03831660009081526002602052604090205482036110c857506000610c71565b6001600160a01b03831660008181526002602052604090819020849055517f7892d1ac746d3db86c35b555e3c7ddbe78b1a209068eadaf1ad5bfe08a8653a9906111159085815260200190565b60405180910390a250600192915050565b6001600160a01b038082166000908152600260208190526040822001549091168061116457604051631c48ef1360e21b815260040160405180910390fd5b6040516341976e0960e01b81526001600160a01b0384811660048301528216906341976e0990602401602060405180830381865afa1580156111aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106169190611a7a565b60006001600160a01b0383166111f75760405163029a68ed60e41b815260040160405180910390fd5b6001600160a01b0384811660009081526002602052604090206001810154909185811662010000909204161480156112345750600181015460ff16155b15611243576000915050610616565b60018101805461ff01600160b01b031916620100006001600160a01b03871602179055600061127186610c77565b5090508061129257604051638a93c04960e01b815260040160405180910390fd5b83801561132657507f000000000000000000000000000000000000000000000000000000000000000860ff16856001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113209190611a3a565b60ff1614155b1561134457604051636322b92560e11b815260040160405180910390fd5b6001600160a01b038087166000818152600260205260409081902060010180548815156101000261ff001990911617905551918716917ffc4600a47c5e7ea766bb29e689a692a267b8549a1f07afa418b47bdd479e1817906113ab90881515815260200190565b60405180910390a350600195945050505050565b60006202a3008211156113e557604051638f1825c960e01b815260040160405180910390fd5b60015482036113f657506000919050565b60018290556040518281527fcc859b6b85e71cdf22c35275e400cbd6817f8bdfd829e0d386dbf3edc292ffcc9060200160405180910390a1506001919050565b600080546001600160a01b039081169083160361145557506000919050565b600080546001600160a01b0319166001600160a01b038416908117825560405190917fc9f3c0828967b8c34f2d6bbf6797c2965918320a1b0cd659293a94bff918fecd91a2506001919050565b600080841380156114bb5750816114b98442611a93565b105b949350505050565b60008060007f0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b84196001600160a01b031663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611526573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061154a91906119ea565b5093505092505061155e82826001546114a2565b61157b57604051638a93c04960e01b815260040160405180910390fd5b816115a77f0000000000000000000000000000000000000000000000000000000000000012600a611970565b6115b1908661182b565b6114bb919061197f565b60008160ff167f000000000000000000000000000000000000000000000000000000000000001260ff16036115f1575081610c71565b8160ff167f000000000000000000000000000000000000000000000000000000000000001260ff161015611665576116497f000000000000000000000000000000000000000000000000000000000000001283611aaa565b61165490600a611970565b61165e908461197f565b9050610c71565b61168f827f0000000000000000000000000000000000000000000000000000000000000012611aaa565b61169a90600a611970565b61165e908461182b565b6001600160a01b038116811461098757600080fd5b6000602082840312156116cb57600080fd5b8135610616816116a4565b600080604083850312156116e957600080fd5b82356116f4816116a4565b91506020830135611704816116a4565b809150509250929050565b6000806040838503121561172257600080fd5b823561172d816116a4565b946020939093013593505050565b801515811461098757600080fd5b60008060006060848603121561175e57600080fd5b8335611769816116a4565b92506020840135611779816116a4565b915060408401356117898161173b565b809150509250925092565b6000602082840312156117a657600080fd5b5035919050565b600080600080600060a086880312156117c557600080fd5b85356117d0816116a4565b945060208601356117e0816116a4565b935060408601356117f0816116a4565b92506060860135915060808601356118078161173b565b809150509295509295909350565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561184557611845611815565b500290565b60006020828403121561185c57600080fd5b8151610616816116a4565b6020808252600b908201526a27b7363ca6b0b730b3b2b960a91b604082015260600190565b600181815b808511156118c75781600019048211156118ad576118ad611815565b808516156118ba57918102915b93841c9390800290611891565b509250929050565b6000826118de57506001610c71565b816118eb57506000610c71565b8160018114611901576002811461190b57611927565b6001915050610c71565b60ff84111561191c5761191c611815565b50506001821b610c71565b5060208310610133831016604e8410600b841016171561194a575081810a610c71565b611954838361188c565b806000190482111561196857611968611815565b029392505050565b6000610c6e60ff8416836118cf565b60008261199c57634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156119b357600080fd5b81516001600160e01b03198116811461061657600080fd5b805169ffffffffffffffffffff811681146119e557600080fd5b919050565b600080600080600060a08688031215611a0257600080fd5b611a0b866119cb565b9450602086015193506040860151925060608601519150611a2e608087016119cb565b90509295509295909350565b600060208284031215611a4c57600080fd5b815160ff8116811461061657600080fd5b600060208284031215611a6f57600080fd5b81516106168161173b565b600060208284031215611a8c57600080fd5b5051919050565b600082821015611aa557611aa5611815565b500390565b600060ff821660ff841680821015611ac457611ac4611815565b9003939250505056fea2646970667358221220f1811bd1a10b772e2b6de72d32bafddadcbd7b8c591b434c2c71e28b2b64739464736f6c634300080d0033

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.