Address Details
contract

0xC76BDf0AFb654888728003683cf748A8B1b4f5fD

Contract Name
BreakerBox
Creator
0x56fd3f–9b8d81 at 0xffef6a–c1dc55
Balance
0 CELO ( )
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
1 Transactions
Transfers
0 Transfers
Gas Used
28,716
Last Balance Update
26219508
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
BreakerBox




Optimization enabled
true
Compiler version
v0.5.17+commit.d19bba13




Optimization runs
10000
Verified at
2023-08-29T10:29:39.192407Z

lib/mento-core-2.2.0/contracts/oracles/BreakerBox.sol

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.13;

import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol";
import { Ownable } from "openzeppelin-solidity/contracts/ownership/Ownable.sol";

import { IBreakerBox } from "../interfaces/IBreakerBox.sol";
import { IBreaker } from "../interfaces/IBreaker.sol";
import { ISortedOracles } from "../interfaces/ISortedOracles.sol";

import { AddressLinkedList, LinkedList } from "../common/linkedlists/AddressLinkedList.sol";
import { Initializable } from "../common/Initializable.sol";

/**
 * @title   BreakerBox
 * @notice  The BreakerBox checks the criteria defined in separate breaker contracts
 *          to determine whether or not buying or selling should be allowed for a
 *          specified rateFeedIDs. The contract stores references to all breakers
 *          that hold criteria to be checked, rateFeedIDs that
 *          can make use of the BreakerBox & their current trading modes.
 */
contract BreakerBox is IBreakerBox, Ownable {
  using SafeMath for uint256;

  /* ==================== State Variables ==================== */

  address[] public rateFeedIDs;

  // Maps a rate feed to a boolean indicating whether it has been added to the BreakerBox.
  mapping(address => bool) public rateFeedStatus;

  // Maps a rate feed to its breakers and their breaker status. (rateFeedID => (breaker => BreakerStatus)
  mapping(address => mapping(address => BreakerStatus)) public rateFeedBreakerStatus;

  // Maps a rate feed to the associated trading mode.
  mapping(address => uint8) public rateFeedTradingMode;

  // Maps a rate feed to its dependent rate feeds.
  mapping(address => address[]) public rateFeedDependencies;

  // Maps a breaker to the associated trading mode it should activate when triggered.
  mapping(address => uint8) public breakerTradingMode;

  // List of breakers to be checked.
  address[] public breakers;

  // Address of the Mento SortedOracles contract
  ISortedOracles public sortedOracles;

  modifier onlyValidBreaker(address breaker, uint64 tradingMode) {
    require(!isBreaker(breaker), "This breaker has already been added");
    require(tradingMode != 0, "The default trading mode can not have a breaker");
    _;
  }

  /* ==================== Constructor ==================== */

  /**
   * @param _rateFeedIDs rateFeedIDs to be added.
   * @param _sortedOracles The address of the Celo sorted oracles contract.
   */
  constructor(address[] memory _rateFeedIDs, ISortedOracles _sortedOracles) public {
    _transferOwnership(msg.sender);
    setSortedOracles(_sortedOracles);
    addRateFeeds(_rateFeedIDs);
  }

  /* ==================== Mutative Functions ==================== */

  /**
   * @notice Sets the address of the sortedOracles contract.
   * @param _sortedOracles The new address of the sorted oracles contract.
   */
  function setSortedOracles(ISortedOracles _sortedOracles) public onlyOwner {
    require(address(_sortedOracles) != address(0), "SortedOracles address must be set");
    sortedOracles = _sortedOracles;
    emit SortedOraclesUpdated(address(_sortedOracles));
  }

  /* ==================== Restricted Functions ==================== */

  /* ---------- Breakers ---------- */

  /**
   * @notice Adds a breaker to the end of the list of breakers & the breakerTradingMode mapping.
   * @param breaker The address of the breaker to be added.
   * @param tradingMode The trading mode of the breaker to be added.
   */
  function addBreaker(address breaker, uint8 tradingMode) public onlyOwner onlyValidBreaker(breaker, tradingMode) {
    breakerTradingMode[breaker] = tradingMode;
    breakers.push(breaker);
    emit BreakerAdded(breaker);
  }

  /**
   * @notice Removes the specified breaker from the list of breakers
   *         and resets breakerTradingMode mapping + BreakerStatus.
   * @param breaker The address of the breaker to be removed.
   */
  function removeBreaker(address breaker) external onlyOwner {
    uint256 breakerIndex = 0;
    for (uint256 i = 0; i < breakers.length; i++) {
      if (breakers[i] == breaker) {
        breakerIndex = i;
        break;
      }
    }
    require(breakers[breakerIndex] == breaker, "Breaker has not been added");

    for (uint256 i = 0; i < rateFeedIDs.length; i++) {
      if (rateFeedBreakerStatus[rateFeedIDs[i]][breaker].enabled) {
        toggleBreaker(breaker, rateFeedIDs[i], false);
      }
    }

    delete breakerTradingMode[breaker];

    uint256 lastIndex = breakers.length.sub(1);
    if (breakerIndex != lastIndex) {
      breakers[breakerIndex] = breakers[lastIndex];
    }
    breakers.pop();

    emit BreakerRemoved(breaker);
  }

  /**
   * @notice Enables or disables a breaker for the specified rate feed.
   * @param breakerAddress The address of the breaker.
   * @param rateFeedID The address of the rateFeed to be toggled.
   * @param enable Boolean indicating whether the breaker should be
   *               enabled or disabled for the given rateFeed.
   */
  function toggleBreaker(
    address breakerAddress,
    address rateFeedID,
    bool enable
  ) public onlyOwner {
    require(rateFeedStatus[rateFeedID], "Rate feed ID has not been added");
    require(isBreaker(breakerAddress), "This breaker has not been added to the BreakerBox");
    require(rateFeedBreakerStatus[rateFeedID][breakerAddress].enabled != enable, "Breaker is already in this state");
    if (enable) {
      rateFeedBreakerStatus[rateFeedID][breakerAddress].enabled = enable;
      _checkAndSetBreakers(rateFeedID);
    } else {
      delete rateFeedBreakerStatus[rateFeedID][breakerAddress];
      uint8 tradingMode = calculateTradingMode(rateFeedID);
      setRateFeedTradingMode(rateFeedID, tradingMode);
    }
    emit BreakerStatusUpdated(breakerAddress, rateFeedID, enable);
  }

  /**
   * @dev Calculates the trading mode for a given rate feed by applying
   *      a logical OR on the trading modes of all enabled breakers.
   * @param rateFeedId The address of the rate feed.
   */
  function calculateTradingMode(address rateFeedId) internal view returns (uint8) {
    uint8 tradingMode = 0;
    for (uint256 i = 0; i < breakers.length; i++) {
      if (rateFeedBreakerStatus[rateFeedId][breakers[i]].enabled) {
        tradingMode = tradingMode | rateFeedBreakerStatus[rateFeedId][breakers[i]].tradingMode;
      }
    }
    return tradingMode;
  }

  /* ---------- rateFeedIDs ---------- */

  /**
   * @notice Adds a rateFeedID to the mapping of monitored rateFeedIDs.
   * @param rateFeedID The address of the rateFeed to be added.
   */
  function addRateFeed(address rateFeedID) public onlyOwner {
    require(!rateFeedStatus[rateFeedID], "Rate feed ID has already been added");
    require(sortedOracles.getOracles(rateFeedID).length > 0, "Rate feed ID does not exist as it has 0 oracles");
    rateFeedIDs.push(rateFeedID);
    rateFeedStatus[rateFeedID] = true;
    emit RateFeedAdded(rateFeedID);
  }

  /**
   * @notice Adds the specified rateFeedIDs to the mapping of monitored rateFeedIDs.
   * @param newRateFeedIDs The array of rateFeed addresses to be added.
   */
  function addRateFeeds(address[] memory newRateFeedIDs) public onlyOwner {
    for (uint256 i = 0; i < newRateFeedIDs.length; i++) {
      addRateFeed(newRateFeedIDs[i]);
    }
  }

  /**
   * @notice Sets dependent rate feeds for a given rate feed.
   * @param rateFeedID The address of the rate feed.
   * @param dependencies The array of dependent rate feeds.
   */
  function setRateFeedDependencies(address rateFeedID, address[] calldata dependencies) external onlyOwner {
    require(rateFeedStatus[rateFeedID], "Rate feed ID has not been added");
    rateFeedDependencies[rateFeedID] = dependencies;
    emit RateFeedDependenciesSet(rateFeedID, dependencies);
  }

  /**
   * @notice Removes a rateFeed from the mapping of monitored rateFeeds
   *         and resets all the BreakerStatus entries for that rateFeed.
   * @param rateFeedID The address of the rateFeed to be removed.
   */
  function removeRateFeed(address rateFeedID) external onlyOwner {
    uint256 rateFeedIndex = 0;
    for (uint256 i = 0; i < rateFeedIDs.length; i++) {
      if (rateFeedIDs[i] == rateFeedID) {
        rateFeedIndex = i;
        break;
      }
    }
    require(rateFeedIDs[rateFeedIndex] == rateFeedID, "Rate feed ID has not been added");

    uint256 lastIndex = rateFeedIDs.length.sub(1);
    if (rateFeedIndex != lastIndex) {
      rateFeedIDs[rateFeedIndex] = rateFeedIDs[lastIndex];
    }
    rateFeedIDs.pop();

    delete rateFeedDependencies[rateFeedID];
    delete rateFeedTradingMode[rateFeedID];
    deleteBreakerStatus(rateFeedID);
    rateFeedStatus[rateFeedID] = false;

    emit RateFeedRemoved(rateFeedID);
  }

  /**
   * @notice Sets the trading mode for the specified rateFeed.
   * @param rateFeedID The address of the rateFeed.
   * @param tradingMode The trading mode that should be set.
   */
  function setRateFeedTradingMode(address rateFeedID, uint8 tradingMode) public onlyOwner {
    require(rateFeedStatus[rateFeedID], "Rate feed ID has not been added");

    rateFeedTradingMode[rateFeedID] = tradingMode;
    emit TradingModeUpdated(rateFeedID, tradingMode);
  }

  /**
   * @notice Resets all the BreakerStatus entries for the specified rateFeed.
   * @param rateFeedID The address of the rateFeed.
   */
  function deleteBreakerStatus(address rateFeedID) internal {
    for (uint256 i = 0; i < breakers.length; i++) {
      if (rateFeedBreakerStatus[rateFeedID][breakers[i]].enabled) {
        delete rateFeedBreakerStatus[rateFeedID][breakers[i]];
      }
    }
  }

  /* ==================== View Functions ==================== */

  /**
   * @notice Returns an array of breaker addresses from start to end.
   * @return An ordered list of breakers.
   */
  function getBreakers() external view returns (address[] memory) {
    return breakers;
  }

  /**
   * @notice Checks whether a breaker with the specifed address has been added.
   */
  function isBreaker(address breaker) public view returns (bool) {
    for (uint256 i = 0; i < breakers.length; i++) {
      if (breakers[i] == breaker) {
        return true;
      }
    }
    return false;
  }

  /**
   * @notice Returns addresses of rateFeedIDs that have been added.
   */
  function getRateFeeds() external view returns (address[] memory) {
    return rateFeedIDs;
  }

  /**
   * @notice Returns the trading mode for the specified rateFeedID.
   * @param rateFeedID The address of the rateFeed to retrieve the trading mode for.
   */
  function getRateFeedTradingMode(address rateFeedID) external view returns (uint8) {
    require(rateFeedStatus[rateFeedID], "Rate feed ID has not been added");
    uint8 tradingMode = rateFeedTradingMode[rateFeedID];
    for (uint256 i = 0; i < rateFeedDependencies[rateFeedID].length; i++) {
      tradingMode = tradingMode | rateFeedTradingMode[rateFeedDependencies[rateFeedID][i]];
    }
    return tradingMode;
  }

  /**
   * @notice Checks if a breaker is enabled for a specific rate feed.
   * @param breaker The address of the breaker we're checking for.
   * @param rateFeedID The address of the rateFeed.
   */
  function isBreakerEnabled(address breaker, address rateFeedID) external view returns (bool) {
    return rateFeedBreakerStatus[rateFeedID][breaker].enabled;
  }

  /* ==================== Check Breakers ==================== */

  /**
   * @notice Checks breakers for the rateFeedID with the specified id 
             and sets correct trading mode if any breakers are tripped
             or need to be reset.
   * @param rateFeedID The address of the rateFeed to run checks for.
   */
  function checkAndSetBreakers(address rateFeedID) external {
    require(msg.sender == address(sortedOracles), "Caller must be the SortedOracles contract");

    _checkAndSetBreakers(rateFeedID);
  }

  /**
   * @notice Checks breakers for the rateFeedID with the specified id 
             and sets correct trading mode if any breakers are tripped
             or need to be reset. 
   * @param rateFeedID The address of the rateFeed to run checks for.
   */
  function _checkAndSetBreakers(address rateFeedID) internal {
    uint8 _tradingMode = 0;
    for (uint256 i = 0; i < breakers.length; i++) {
      if (rateFeedBreakerStatus[rateFeedID][breakers[i]].enabled) {
        uint8 _breakerTradingMode = updateBreaker(rateFeedID, breakers[i]);
        _tradingMode = _tradingMode | _breakerTradingMode;
      }
    }
    rateFeedTradingMode[rateFeedID] = _tradingMode;
  }

  /**
   * @notice Gets the updated breaker trading mode for a specific rateFeed.
   * @param rateFeedID The address of the rateFeed.
   * @param breaker The address of the breaker to update.
   */
  function updateBreaker(address rateFeedID, address breaker) internal returns (uint8) {
    if (rateFeedBreakerStatus[rateFeedID][breaker].tradingMode != 0) {
      return tryResetBreaker(rateFeedID, breaker);
    }
    return checkBreaker(rateFeedID, breaker);
  }

  /**
   * @notice Tries to reset a breaker if the cooldown has passed.
   * @param rateFeedID The address of the rateFeed to run checks for.
   * @param _breaker The address of the breaker to reset.
   */
  function tryResetBreaker(address rateFeedID, address _breaker) internal returns (uint8) {
    BreakerStatus memory _breakerStatus = rateFeedBreakerStatus[rateFeedID][_breaker];
    IBreaker breaker = IBreaker(_breaker);
    uint256 cooldown = breaker.getCooldown(rateFeedID);

    // If the cooldown == 0, then a manual reset is required.
    if ((cooldown > 0) && (block.timestamp >= cooldown.add(_breakerStatus.lastUpdatedTime))) {
      if (breaker.shouldReset(rateFeedID)) {
        rateFeedBreakerStatus[rateFeedID][_breaker].tradingMode = 0;
        rateFeedBreakerStatus[rateFeedID][_breaker].lastUpdatedTime = uint64(block.timestamp);
        emit ResetSuccessful(rateFeedID, _breaker);
      } else {
        emit ResetAttemptCriteriaFail(rateFeedID, _breaker);
      }
    } else {
      emit ResetAttemptNotCool(rateFeedID, _breaker);
    }
    return rateFeedBreakerStatus[rateFeedID][_breaker].tradingMode;
  }

  /**
   * @notice Checks if a breaker tripped.
   * @param rateFeedID The address of the rateFeed to run checks for.
   * @param _breaker The address of the breaker to check.
   */
  function checkBreaker(address rateFeedID, address _breaker) internal returns (uint8) {
    uint8 tradingMode = 0;
    IBreaker breaker = IBreaker(_breaker);
    if (breaker.shouldTrigger(rateFeedID)) {
      tradingMode = breakerTradingMode[_breaker];
      rateFeedBreakerStatus[rateFeedID][_breaker].tradingMode = tradingMode;
      rateFeedBreakerStatus[rateFeedID][_breaker].lastUpdatedTime = uint64(block.timestamp);
      emit BreakerTripped(_breaker, rateFeedID);
    }
    return tradingMode;
  }
}
        

/lib/mento-core-2.0.0/lib/openzeppelin-contracts/contracts/GSN/Context.sol

pragma solidity ^0.5.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
contract Context {
    // Empty internal constructor, to prevent people from mistakenly deploying
    // an instance of this contract, which should be used via inheritance.
    constructor () internal { }
    // solhint-disable-previous-line no-empty-blocks

    function _msgSender() internal view returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}
          

/lib/mento-core-2.0.0/lib/openzeppelin-contracts/contracts/math/SafeMath.sol

pragma solidity ^0.5.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @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) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @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 sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     *
     * _Available since v2.4.0._
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @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) {
        // 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 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts 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.
     *
     * _Available since v2.4.0._
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts 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 mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message 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.
     *
     * _Available since v2.4.0._
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}
          

/lib/mento-core-2.0.0/lib/openzeppelin-contracts/contracts/ownership/Ownable.sol

pragma solidity ^0.5.0;

import "../GSN/Context.sol";
/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor () internal {
        address msgSender = _msgSender();
        _owner = msgSender;
        emit OwnershipTransferred(address(0), msgSender);
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(isOwner(), "Ownable: caller is not the owner");
        _;
    }

    /**
     * @dev Returns true if the caller is the current owner.
     */
    function isOwner() public view returns (bool) {
        return _msgSender() == _owner;
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}
          

/lib/mento-core-2.2.0/contracts/common/Initializable.sol

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.13;

contract Initializable {
  bool public initialized;

  constructor(bool testingDeployment) public {
    if (!testingDeployment) {
      initialized = true;
    }
  }

  modifier initializer() {
    require(!initialized, "contract already initialized");
    initialized = true;
    _;
  }
}
          

/lib/mento-core-2.2.0/contracts/common/linkedlists/AddressLinkedList.sol

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.13;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";

import "./LinkedList.sol";

/**
 * @title Maintains a doubly linked list keyed by address.
 * @dev Following the `next` pointers will lead you to the head, rather than the tail.
 */
library AddressLinkedList {
  using LinkedList for LinkedList.List;
  using SafeMath for uint256;

  function toBytes(address a) public pure returns (bytes32) {
    return bytes32(uint256(a) << 96);
  }

  function toAddress(bytes32 b) public pure returns (address) {
    return address(uint256(b) >> 96);
  }

  /**
   * @notice Inserts an element into a doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to insert.
   * @param previousKey The key of the element that comes before the element to insert.
   * @param nextKey The key of the element that comes after the element to insert.
   */
  function insert(
    LinkedList.List storage list,
    address key,
    address previousKey,
    address nextKey
  ) public {
    list.insert(toBytes(key), toBytes(previousKey), toBytes(nextKey));
  }

  /**
   * @notice Inserts an element at the end of the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to insert.
   */
  function push(LinkedList.List storage list, address key) public {
    list.insert(toBytes(key), bytes32(0), list.tail);
  }

  /**
   * @notice Removes an element from the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to remove.
   */
  function remove(LinkedList.List storage list, address key) public {
    list.remove(toBytes(key));
  }

  /**
   * @notice Updates an element in the list.
   * @param list A storage pointer to the underlying list.
   * @param key The element key.
   * @param previousKey The key of the element that comes before the updated element.
   * @param nextKey The key of the element that comes after the updated element.
   */
  function update(
    LinkedList.List storage list,
    address key,
    address previousKey,
    address nextKey
  ) public {
    list.update(toBytes(key), toBytes(previousKey), toBytes(nextKey));
  }

  /**
   * @notice Returns whether or not a particular key is present in the sorted list.
   * @param list A storage pointer to the underlying list.
   * @param key The element key.
   * @return Whether or not the key is in the sorted list.
   */
  function contains(LinkedList.List storage list, address key) public view returns (bool) {
    return list.elements[toBytes(key)].exists;
  }

  /**
   * @notice Returns the N greatest elements of the list.
   * @param list A storage pointer to the underlying list.
   * @param n The number of elements to return.
   * @return The keys of the greatest elements.
   * @dev Reverts if n is greater than the number of elements in the list.
   */
  function headN(LinkedList.List storage list, uint256 n) public view returns (address[] memory) {
    bytes32[] memory byteKeys = list.headN(n);
    address[] memory keys = new address[](n);
    for (uint256 i = 0; i < n; i = i.add(1)) {
      keys[i] = toAddress(byteKeys[i]);
    }
    return keys;
  }

  /**
   * @notice Gets all element keys from the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @return All element keys from head to tail.
   */
  function getKeys(LinkedList.List storage list) public view returns (address[] memory) {
    return headN(list, list.numElements);
  }
}
          

/lib/mento-core-2.2.0/contracts/common/linkedlists/LinkedList.sol

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.13;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";

/**
 * @title Maintains a doubly linked list keyed by bytes32.
 * @dev Following the `next` pointers will lead you to the head, rather than the tail.
 */
library LinkedList {
  using SafeMath for uint256;

  struct Element {
    bytes32 previousKey;
    bytes32 nextKey;
    bool exists;
  }

  struct List {
    bytes32 head;
    bytes32 tail;
    uint256 numElements;
    mapping(bytes32 => Element) elements;
  }

  /**
   * @notice Inserts an element into a doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to insert.
   * @param previousKey The key of the element that comes before the element to insert.
   * @param nextKey The key of the element that comes after the element to insert.
   */
  function insert(
    List storage list,
    bytes32 key,
    bytes32 previousKey,
    bytes32 nextKey
  ) internal {
    require(key != bytes32(0), "Key must be defined");
    require(!contains(list, key), "Can't insert an existing element");
    require(previousKey != key && nextKey != key, "Key cannot be the same as previousKey or nextKey");

    Element storage element = list.elements[key];
    element.exists = true;

    if (list.numElements == 0) {
      list.tail = key;
      list.head = key;
    } else {
      require(previousKey != bytes32(0) || nextKey != bytes32(0), "Either previousKey or nextKey must be defined");

      element.previousKey = previousKey;
      element.nextKey = nextKey;

      if (previousKey != bytes32(0)) {
        require(contains(list, previousKey), "If previousKey is defined, it must exist in the list");
        Element storage previousElement = list.elements[previousKey];
        require(previousElement.nextKey == nextKey, "previousKey must be adjacent to nextKey");
        previousElement.nextKey = key;
      } else {
        list.tail = key;
      }

      if (nextKey != bytes32(0)) {
        require(contains(list, nextKey), "If nextKey is defined, it must exist in the list");
        Element storage nextElement = list.elements[nextKey];
        require(nextElement.previousKey == previousKey, "previousKey must be adjacent to nextKey");
        nextElement.previousKey = key;
      } else {
        list.head = key;
      }
    }

    list.numElements = list.numElements.add(1);
  }

  /**
   * @notice Inserts an element at the tail of the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to insert.
   */
  function push(List storage list, bytes32 key) internal {
    insert(list, key, bytes32(0), list.tail);
  }

  /**
   * @notice Removes an element from the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to remove.
   */
  function remove(List storage list, bytes32 key) internal {
    Element storage element = list.elements[key];
    require(key != bytes32(0) && contains(list, key), "key not in list");
    if (element.previousKey != bytes32(0)) {
      Element storage previousElement = list.elements[element.previousKey];
      previousElement.nextKey = element.nextKey;
    } else {
      list.tail = element.nextKey;
    }

    if (element.nextKey != bytes32(0)) {
      Element storage nextElement = list.elements[element.nextKey];
      nextElement.previousKey = element.previousKey;
    } else {
      list.head = element.previousKey;
    }

    delete list.elements[key];
    list.numElements = list.numElements.sub(1);
  }

  /**
   * @notice Updates an element in the list.
   * @param list A storage pointer to the underlying list.
   * @param key The element key.
   * @param previousKey The key of the element that comes before the updated element.
   * @param nextKey The key of the element that comes after the updated element.
   */
  function update(
    List storage list,
    bytes32 key,
    bytes32 previousKey,
    bytes32 nextKey
  ) internal {
    require(key != bytes32(0) && key != previousKey && key != nextKey && contains(list, key), "key on in list");
    remove(list, key);
    insert(list, key, previousKey, nextKey);
  }

  /**
   * @notice Returns whether or not a particular key is present in the sorted list.
   * @param list A storage pointer to the underlying list.
   * @param key The element key.
   * @return Whether or not the key is in the sorted list.
   */
  function contains(List storage list, bytes32 key) internal view returns (bool) {
    return list.elements[key].exists;
  }

  /**
   * @notice Returns the keys of the N elements at the head of the list.
   * @param list A storage pointer to the underlying list.
   * @param n The number of elements to return.
   * @return The keys of the N elements at the head of the list.
   * @dev Reverts if n is greater than the number of elements in the list.
   */
  function headN(List storage list, uint256 n) internal view returns (bytes32[] memory) {
    require(n <= list.numElements, "not enough elements");
    bytes32[] memory keys = new bytes32[](n);
    bytes32 key = list.head;
    for (uint256 i = 0; i < n; i = i.add(1)) {
      keys[i] = key;
      key = list.elements[key].previousKey;
    }
    return keys;
  }

  /**
   * @notice Gets all element keys from the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @return All element keys from head to tail.
   */
  function getKeys(List storage list) internal view returns (bytes32[] memory) {
    return headN(list, list.numElements);
  }
}
          

/lib/mento-core-2.2.0/contracts/common/linkedlists/SortedLinkedList.sol

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.13;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./LinkedList.sol";

/**
 * @title Maintains a sorted list of unsigned ints keyed by bytes32.
 */
library SortedLinkedList {
  using SafeMath for uint256;
  using LinkedList for LinkedList.List;

  struct List {
    LinkedList.List list;
    mapping(bytes32 => uint256) values;
  }

  /**
   * @notice Inserts an element into a doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to insert.
   * @param value The element value.
   * @param lesserKey The key of the element less than the element to insert.
   * @param greaterKey The key of the element greater than the element to insert.
   */
  function insert(
    List storage list,
    bytes32 key,
    uint256 value,
    bytes32 lesserKey,
    bytes32 greaterKey
  ) internal {
    require(key != bytes32(0) && key != lesserKey && key != greaterKey && !contains(list, key), "invalid key");
    require(
      (lesserKey != bytes32(0) || greaterKey != bytes32(0)) || list.list.numElements == 0,
      "greater and lesser key zero"
    );
    require(contains(list, lesserKey) || lesserKey == bytes32(0), "invalid lesser key");
    require(contains(list, greaterKey) || greaterKey == bytes32(0), "invalid greater key");
    (lesserKey, greaterKey) = getLesserAndGreater(list, value, lesserKey, greaterKey);
    list.list.insert(key, lesserKey, greaterKey);
    list.values[key] = value;
  }

  /**
   * @notice Removes an element from the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to remove.
   */
  function remove(List storage list, bytes32 key) internal {
    list.list.remove(key);
    list.values[key] = 0;
  }

  /**
   * @notice Updates an element in the list.
   * @param list A storage pointer to the underlying list.
   * @param key The element key.
   * @param value The element value.
   * @param lesserKey The key of the element will be just left of `key` after the update.
   * @param greaterKey The key of the element will be just right of `key` after the update.
   * @dev Note that only one of "lesserKey" or "greaterKey" needs to be correct to reduce friction.
   */
  function update(
    List storage list,
    bytes32 key,
    uint256 value,
    bytes32 lesserKey,
    bytes32 greaterKey
  ) internal {
    remove(list, key);
    insert(list, key, value, lesserKey, greaterKey);
  }

  /**
   * @notice Inserts an element at the tail of the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to insert.
   */
  function push(List storage list, bytes32 key) internal {
    insert(list, key, 0, bytes32(0), list.list.tail);
  }

  /**
   * @notice Removes N elements from the head of the list and returns their keys.
   * @param list A storage pointer to the underlying list.
   * @param n The number of elements to pop.
   * @return The keys of the popped elements.
   */
  function popN(List storage list, uint256 n) internal returns (bytes32[] memory) {
    require(n <= list.list.numElements, "not enough elements");
    bytes32[] memory keys = new bytes32[](n);
    for (uint256 i = 0; i < n; i = i.add(1)) {
      bytes32 key = list.list.head;
      keys[i] = key;
      remove(list, key);
    }
    return keys;
  }

  /**
   * @notice Returns whether or not a particular key is present in the sorted list.
   * @param list A storage pointer to the underlying list.
   * @param key The element key.
   * @return Whether or not the key is in the sorted list.
   */
  function contains(List storage list, bytes32 key) internal view returns (bool) {
    return list.list.contains(key);
  }

  /**
   * @notice Returns the value for a particular key in the sorted list.
   * @param list A storage pointer to the underlying list.
   * @param key The element key.
   * @return The element value.
   */
  function getValue(List storage list, bytes32 key) internal view returns (uint256) {
    return list.values[key];
  }

  /**
   * @notice Gets all elements from the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @return Array of all keys in the list.
   * @return Values corresponding to keys, which will be ordered largest to smallest.
   */
  function getElements(List storage list) internal view returns (bytes32[] memory, uint256[] memory) {
    bytes32[] memory keys = getKeys(list);
    uint256[] memory values = new uint256[](keys.length);
    for (uint256 i = 0; i < keys.length; i = i.add(1)) {
      values[i] = list.values[keys[i]];
    }
    return (keys, values);
  }

  /**
   * @notice Gets all element keys from the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @return All element keys from head to tail.
   */
  function getKeys(List storage list) internal view returns (bytes32[] memory) {
    return list.list.getKeys();
  }

  /**
   * @notice Returns first N greatest elements of the list.
   * @param list A storage pointer to the underlying list.
   * @param n The number of elements to return.
   * @return The keys of the first n elements.
   * @dev Reverts if n is greater than the number of elements in the list.
   */
  function headN(List storage list, uint256 n) internal view returns (bytes32[] memory) {
    return list.list.headN(n);
  }

  /**
   * @notice Returns the keys of the elements greaterKey than and less than the provided value.
   * @param list A storage pointer to the underlying list.
   * @param value The element value.
   * @param lesserKey The key of the element which could be just left of the new value.
   * @param greaterKey The key of the element which could be just right of the new value.
   * @return The correct lesserKey keys.
   * @return The correct greaterKey keys.
   */
  function getLesserAndGreater(
    List storage list,
    uint256 value,
    bytes32 lesserKey,
    bytes32 greaterKey
  ) private view returns (bytes32, bytes32) {
    // Check for one of the following conditions and fail if none are met:
    //   1. The value is less than the current lowest value
    //   2. The value is greater than the current greatest value
    //   3. The value is just greater than the value for `lesserKey`
    //   4. The value is just less than the value for `greaterKey`
    if (lesserKey == bytes32(0) && isValueBetween(list, value, lesserKey, list.list.tail)) {
      return (lesserKey, list.list.tail);
    } else if (greaterKey == bytes32(0) && isValueBetween(list, value, list.list.head, greaterKey)) {
      return (list.list.head, greaterKey);
    } else if (
      lesserKey != bytes32(0) && isValueBetween(list, value, lesserKey, list.list.elements[lesserKey].nextKey)
    ) {
      return (lesserKey, list.list.elements[lesserKey].nextKey);
    } else if (
      greaterKey != bytes32(0) && isValueBetween(list, value, list.list.elements[greaterKey].previousKey, greaterKey)
    ) {
      return (list.list.elements[greaterKey].previousKey, greaterKey);
    } else {
      require(false, "get lesser and greater failure");
    }
  }

  /**
   * @notice Returns whether or not a given element is between two other elements.
   * @param list A storage pointer to the underlying list.
   * @param value The element value.
   * @param lesserKey The key of the element whose value should be lesserKey.
   * @param greaterKey The key of the element whose value should be greaterKey.
   * @return True if the given element is between the two other elements.
   */
  function isValueBetween(
    List storage list,
    uint256 value,
    bytes32 lesserKey,
    bytes32 greaterKey
  ) private view returns (bool) {
    bool isLesser = lesserKey == bytes32(0) || list.values[lesserKey] <= value;
    bool isGreater = greaterKey == bytes32(0) || list.values[greaterKey] >= value;
    return isLesser && isGreater;
  }
}
          

/lib/mento-core-2.2.0/contracts/common/linkedlists/SortedLinkedListWithMedian.sol

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.13;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./LinkedList.sol";
import "./SortedLinkedList.sol";

/**
 * @title Maintains a sorted list of unsigned ints keyed by bytes32.
 */
library SortedLinkedListWithMedian {
  using SafeMath for uint256;
  using SortedLinkedList for SortedLinkedList.List;

  enum MedianAction {
    None,
    Lesser,
    Greater
  }

  enum MedianRelation {
    Undefined,
    Lesser,
    Greater,
    Equal
  }

  struct List {
    SortedLinkedList.List list;
    bytes32 median;
    mapping(bytes32 => MedianRelation) relation;
  }

  /**
   * @notice Inserts an element into a doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to insert.
   * @param value The element value.
   * @param lesserKey The key of the element less than the element to insert.
   * @param greaterKey The key of the element greater than the element to insert.
   */
  function insert(
    List storage list,
    bytes32 key,
    uint256 value,
    bytes32 lesserKey,
    bytes32 greaterKey
  ) internal {
    list.list.insert(key, value, lesserKey, greaterKey);
    LinkedList.Element storage element = list.list.list.elements[key];

    MedianAction action = MedianAction.None;
    if (list.list.list.numElements == 1) {
      list.median = key;
      list.relation[key] = MedianRelation.Equal;
    } else if (list.list.list.numElements % 2 == 1) {
      // When we have an odd number of elements, and the element that we inserted is less than
      // the previous median, we need to slide the median down one element, since we had previously
      // selected the greater of the two middle elements.
      if (element.previousKey == bytes32(0) || list.relation[element.previousKey] == MedianRelation.Lesser) {
        action = MedianAction.Lesser;
        list.relation[key] = MedianRelation.Lesser;
      } else {
        list.relation[key] = MedianRelation.Greater;
      }
    } else {
      // When we have an even number of elements, and the element that we inserted is greater than
      // the previous median, we need to slide the median up one element, since we always select
      // the greater of the two middle elements.
      if (element.nextKey == bytes32(0) || list.relation[element.nextKey] == MedianRelation.Greater) {
        action = MedianAction.Greater;
        list.relation[key] = MedianRelation.Greater;
      } else {
        list.relation[key] = MedianRelation.Lesser;
      }
    }
    updateMedian(list, action);
  }

  /**
   * @notice Removes an element from the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to remove.
   */
  function remove(List storage list, bytes32 key) internal {
    MedianAction action = MedianAction.None;
    if (list.list.list.numElements == 0) {
      list.median = bytes32(0);
    } else if (list.list.list.numElements % 2 == 0) {
      // When we have an even number of elements, we always choose the higher of the two medians.
      // Thus, if the element we're removing is greaterKey than or equal to the median we need to
      // slide the median left by one.
      if (list.relation[key] == MedianRelation.Greater || list.relation[key] == MedianRelation.Equal) {
        action = MedianAction.Lesser;
      }
    } else {
      // When we don't have an even number of elements, we just choose the median value.
      // Thus, if the element we're removing is less than or equal to the median, we need to slide
      // median right by one.
      if (list.relation[key] == MedianRelation.Lesser || list.relation[key] == MedianRelation.Equal) {
        action = MedianAction.Greater;
      }
    }
    updateMedian(list, action);

    list.list.remove(key);
  }

  /**
   * @notice Updates an element in the list.
   * @param list A storage pointer to the underlying list.
   * @param key The element key.
   * @param value The element value.
   * @param lesserKey The key of the element will be just left of `key` after the update.
   * @param greaterKey The key of the element will be just right of `key` after the update.
   * @dev Note that only one of "lesserKey" or "greaterKey" needs to be correct to reduce friction.
   */
  function update(
    List storage list,
    bytes32 key,
    uint256 value,
    bytes32 lesserKey,
    bytes32 greaterKey
  ) internal {
    remove(list, key);
    insert(list, key, value, lesserKey, greaterKey);
  }

  /**
   * @notice Inserts an element at the tail of the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @param key The key of the element to insert.
   */
  function push(List storage list, bytes32 key) internal {
    insert(list, key, 0, bytes32(0), list.list.list.tail);
  }

  /**
   * @notice Removes N elements from the head of the list and returns their keys.
   * @param list A storage pointer to the underlying list.
   * @param n The number of elements to pop.
   * @return The keys of the popped elements.
   */
  function popN(List storage list, uint256 n) internal returns (bytes32[] memory) {
    require(n <= list.list.list.numElements, "not enough elements");
    bytes32[] memory keys = new bytes32[](n);
    for (uint256 i = 0; i < n; i = i.add(1)) {
      bytes32 key = list.list.list.head;
      keys[i] = key;
      remove(list, key);
    }
    return keys;
  }

  /**
   * @notice Returns whether or not a particular key is present in the sorted list.
   * @param list A storage pointer to the underlying list.
   * @param key The element key.
   * @return Whether or not the key is in the sorted list.
   */
  function contains(List storage list, bytes32 key) internal view returns (bool) {
    return list.list.contains(key);
  }

  /**
   * @notice Returns the value for a particular key in the sorted list.
   * @param list A storage pointer to the underlying list.
   * @param key The element key.
   * @return The element value.
   */
  function getValue(List storage list, bytes32 key) internal view returns (uint256) {
    return list.list.values[key];
  }

  /**
   * @notice Returns the median value of the sorted list.
   * @param list A storage pointer to the underlying list.
   * @return The median value.
   */
  function getMedianValue(List storage list) internal view returns (uint256) {
    return getValue(list, list.median);
  }

  /**
   * @notice Returns the key of the first element in the list.
   * @param list A storage pointer to the underlying list.
   * @return The key of the first element in the list.
   */
  function getHead(List storage list) internal view returns (bytes32) {
    return list.list.list.head;
  }

  /**
   * @notice Returns the key of the median element in the list.
   * @param list A storage pointer to the underlying list.
   * @return The key of the median element in the list.
   */
  function getMedian(List storage list) internal view returns (bytes32) {
    return list.median;
  }

  /**
   * @notice Returns the key of the last element in the list.
   * @param list A storage pointer to the underlying list.
   * @return The key of the last element in the list.
   */
  function getTail(List storage list) internal view returns (bytes32) {
    return list.list.list.tail;
  }

  /**
   * @notice Returns the number of elements in the list.
   * @param list A storage pointer to the underlying list.
   * @return The number of elements in the list.
   */
  function getNumElements(List storage list) internal view returns (uint256) {
    return list.list.list.numElements;
  }

  /**
   * @notice Gets all elements from the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @return Array of all keys in the list.
   * @return Values corresponding to keys, which will be ordered largest to smallest.
   * @return Array of relations to median of corresponding list elements.
   */
  function getElements(List storage list)
    internal
    view
    returns (
      bytes32[] memory,
      uint256[] memory,
      MedianRelation[] memory
    )
  {
    bytes32[] memory keys = getKeys(list);
    uint256[] memory values = new uint256[](keys.length);
    MedianRelation[] memory relations = new MedianRelation[](keys.length);
    for (uint256 i = 0; i < keys.length; i = i.add(1)) {
      values[i] = list.list.values[keys[i]];
      relations[i] = list.relation[keys[i]];
    }
    return (keys, values, relations);
  }

  /**
   * @notice Gets all element keys from the doubly linked list.
   * @param list A storage pointer to the underlying list.
   * @return All element keys from head to tail.
   */
  function getKeys(List storage list) internal view returns (bytes32[] memory) {
    return list.list.getKeys();
  }

  /**
   * @notice Moves the median pointer right or left of its current value.
   * @param list A storage pointer to the underlying list.
   * @param action Which direction to move the median pointer.
   */
  function updateMedian(List storage list, MedianAction action) private {
    LinkedList.Element storage previousMedian = list.list.list.elements[list.median];
    if (action == MedianAction.Lesser) {
      list.relation[list.median] = MedianRelation.Greater;
      list.median = previousMedian.previousKey;
    } else if (action == MedianAction.Greater) {
      list.relation[list.median] = MedianRelation.Lesser;
      list.median = previousMedian.nextKey;
    }
    list.relation[list.median] = MedianRelation.Equal;
  }
}
          

/lib/mento-core-2.2.0/contracts/interfaces/IBreaker.sol

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.13;

/**
 * @title Breaker Interface
 * @notice Defines the basic interface for a Breaker
 */
interface IBreaker {
  /**
   * @notice Emitted when the sortedOracles address is updated.
   * @param newSortedOracles The address of the new sortedOracles.
   */
  event SortedOraclesUpdated(address newSortedOracles);

  /**
   * @notice Retrieve the cooldown time for the breaker.
   * @param rateFeedID The rate feed to get the cooldown for
   * @return cooldown The amount of time that must pass before the breaker can reset.
   * @dev when cooldown is 0 auto reset will not be attempted.
   */
  function getCooldown(address rateFeedID) external view returns (uint256 cooldown);

  /**
   * @notice Check if the criteria have been met, by a specified rateFeedID, to trigger the breaker.
   * @param rateFeedID The address of the rate feed to run the check against.
   * @return triggerBreaker A boolean indicating whether or not the breaker
   *                        should be triggered for the given rate feed.
   */
  function shouldTrigger(address rateFeedID) external returns (bool triggerBreaker);

  /**
   * @notice Check if the criteria to automatically reset the breaker have been met.
   * @param rateFeedID The address of rate feed the criteria should be checked against.
   * @return resetBreaker A boolean indicating whether the breaker
   *                      should be reset for the given rate feed.
   * @dev Allows the definition of additional critera to check before reset.
   *      If no additional criteria is needed set to !shouldTrigger();
   */
  function shouldReset(address rateFeedID) external returns (bool resetBreaker);
}
          

/lib/mento-core-2.2.0/contracts/interfaces/IBreakerBox.sol

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.13;

/**
 * @title Breaker Box Interface
 * @notice Defines the basic interface for the Breaker Box
 */
interface IBreakerBox {
  /**
   * @dev Used to keep track of the status of a breaker for a specific rate feed.
   *
   * - TradingMode: Represents the trading mode the breaker is in for a rate feed.
   *                This uses a bitmask approach, meaning each bit represents a
   *                different trading mode. The final trading mode of the rate feed
   *                is obtained by applying a logical OR operation to the TradingMode
   *                of all breakers associated with that rate feed. This allows multiple
   *                breakers to contribute to the final trading mode simultaneously.
   *                Possible values:
   *                0: bidirectional trading.
   *                1: inflow only.
   *                2: outflow only.
   *                3: trading halted.
   *
   * - LastUpdatedTime: Records the last time the breaker status was updated. This is
   *                    used to manage cooldown periods before the breaker can be reset.
   *
   * - Enabled:     Indicates whether the breaker is enabled for the associated rate feed.
   */
  struct BreakerStatus {
    uint8 tradingMode;
    uint64 lastUpdatedTime;
    bool enabled;
  }

  /**
   * @notice Emitted when a new breaker is added to the breaker box.
   * @param breaker The address of the breaker.
   */
  event BreakerAdded(address indexed breaker);

  /**
   * @notice Emitted when a breaker is removed from the breaker box.
   * @param breaker The address of the breaker.
   */
  event BreakerRemoved(address indexed breaker);

  /**
   * @notice Emitted when a breaker is tripped by a rate feed.
   * @param breaker The address of the breaker.
   * @param rateFeedID The address of the rate feed.
   */
  event BreakerTripped(address indexed breaker, address indexed rateFeedID);

  /**
   * @notice Emitted when a new rate feed is added to the breaker box.
   * @param rateFeedID The address of the rate feed.
   */
  event RateFeedAdded(address indexed rateFeedID);

  /**
   * @notice Emitted when dependencies for a rate feed are set.
   * @param rateFeedID The address of the rate feed.
   * @param dependencies The addresses of the dependendent rate feeds.
   */
  event RateFeedDependenciesSet(address indexed rateFeedID, address[] indexed dependencies);

  /**
   * @notice Emitted when a rate feed is removed from the breaker box.
   * @param rateFeedID The address of the rate feed.
   */
  event RateFeedRemoved(address indexed rateFeedID);

  /**
   * @notice Emitted when the trading mode for a rate feed is updated
   * @param rateFeedID The address of the rate feed.
   * @param tradingMode The new trading mode.
   */
  event TradingModeUpdated(address indexed rateFeedID, uint256 tradingMode);

  /**
   * @notice Emitted after a reset attempt is successful.
   * @param rateFeedID The address of the rate feed.
   * @param breaker The address of the breaker.
   */
  event ResetSuccessful(address indexed rateFeedID, address indexed breaker);

  /**
   * @notice  Emitted after a reset attempt fails when the
   *          rate feed fails the breakers reset criteria.
   * @param rateFeedID The address of the rate feed.
   * @param breaker The address of the breaker.
   */
  event ResetAttemptCriteriaFail(address indexed rateFeedID, address indexed breaker);

  /**
   * @notice Emitted after a reset attempt fails when cooldown time has not elapsed.
   * @param rateFeedID The address of the rate feed.
   * @param breaker The address of the breaker.
   */
  event ResetAttemptNotCool(address indexed rateFeedID, address indexed breaker);

  /**
   * @notice Emitted when the sortedOracles address is updated.
   * @param newSortedOracles The address of the new sortedOracles.
   */
  event SortedOraclesUpdated(address indexed newSortedOracles);

  /**
   * @notice Emitted when the breaker is enabled or disabled for a rate feed.
   * @param breaker The address of the breaker.
   * @param rateFeedID The address of the rate feed.
   * @param status Indicating the status.
   */
  event BreakerStatusUpdated(address breaker, address rateFeedID, bool status);

  /**
   * @notice Retrives an array of all breaker addresses.
   */
  function getBreakers() external view returns (address[] memory);

  /**
   * @notice Checks if a breaker with the specified address has been added to the breaker box.
   * @param breaker The address of the breaker to check;
   * @return A bool indicating whether or not the breaker has been added.
   */
  function isBreaker(address breaker) external view returns (bool);

  /**
   * @notice Checks breakers for the rateFeedID and sets correct trading mode
   * if any breakers are tripped or need to be reset.
   * @param rateFeedID The address of the rate feed to run checks for.
   */
  function checkAndSetBreakers(address rateFeedID) external;

  /**
   * @notice Gets the trading mode for the specified rateFeedID.
   * @param rateFeedID The address of the rate feed to retrieve the trading mode for.
   */
  function getRateFeedTradingMode(address rateFeedID) external view returns (uint8 tradingMode);
}
          

/lib/mento-core-2.2.0/contracts/interfaces/ISortedOracles.sol

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.5.13;

import "../common/linkedlists/SortedLinkedListWithMedian.sol";

interface ISortedOracles {
  function addOracle(address, address) external;

  function removeOracle(
    address,
    address,
    uint256
  ) external;

  function report(
    address,
    uint256,
    address,
    address
  ) external;

  function removeExpiredReports(address, uint256) external;

  function isOldestReportExpired(address token) external view returns (bool, address);

  function numRates(address) external view returns (uint256);

  function medianRate(address) external view returns (uint256, uint256);

  function numTimestamps(address) external view returns (uint256);

  function medianTimestamp(address) external view returns (uint256);

  function getOracles(address) external view returns (address[] memory);

  function getTimestamps(address token)
    external
    view
    returns (
      address[] memory,
      uint256[] memory,
      SortedLinkedListWithMedian.MedianRelation[] memory
    );
}
          

Compiler Settings

{"remappings":[":celo-foundry/=lib/celo-foundry/src/",":contracts/=contracts/",":ds-test/=lib/celo-foundry/lib/forge-std/lib/ds-test/src/",":forge-std-next/=lib/mento-core-2.2.0/lib/forge-std-next/src/",":forge-std/=lib/celo-foundry/lib/forge-std/src/",":mento-core-2.0.0/=lib/mento-core-2.0.0/contracts/",":mento-core-2.1.0/=lib/mento-core-2.1.0/contracts/",":mento-core-2.2.0/=lib/mento-core-2.2.0/contracts/",":mento-core/=lib/mento-core/contracts/",":openzeppelin-contracts-next/=lib/mento-core-2.2.0/lib/openzeppelin-contracts-next/",":openzeppelin-contracts-upgradeable/=lib/mento-core-2.2.0/lib/openzeppelin-contracts-upgradeable/",":openzeppelin-contracts/=lib/mento-core-2.0.0/lib/openzeppelin-contracts/contracts/",":openzeppelin-solidity/=lib/mento-core-2.0.0/lib/openzeppelin-contracts/",":test/=lib/mento-core-2.0.0/test/"],"optimizer":{"runs":10000,"enabled":true},"libraries":{"AddressSortedLinkedListWithMedian":"0x29b1b5e05217c751038861af2c77494eab10a257","AddressLinkedList":"0x2f0f7686fffefc3c266403ad600035581deaedff"},"compilationTarget":{"lib/mento-core-2.2.0/contracts/oracles/BreakerBox.sol":"BreakerBox"}}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address[]","name":"_rateFeedIDs","internalType":"address[]"},{"type":"address","name":"_sortedOracles","internalType":"contract ISortedOracles"}]},{"type":"event","name":"BreakerAdded","inputs":[{"type":"address","name":"breaker","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"BreakerRemoved","inputs":[{"type":"address","name":"breaker","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"BreakerStatusUpdated","inputs":[{"type":"address","name":"breaker","internalType":"address","indexed":false},{"type":"address","name":"rateFeedID","internalType":"address","indexed":false},{"type":"bool","name":"status","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"BreakerTripped","inputs":[{"type":"address","name":"breaker","internalType":"address","indexed":true},{"type":"address","name":"rateFeedID","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RateFeedAdded","inputs":[{"type":"address","name":"rateFeedID","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RateFeedDependenciesSet","inputs":[{"type":"address","name":"rateFeedID","internalType":"address","indexed":true},{"type":"address[]","name":"dependencies","internalType":"address[]","indexed":true}],"anonymous":false},{"type":"event","name":"RateFeedRemoved","inputs":[{"type":"address","name":"rateFeedID","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ResetAttemptCriteriaFail","inputs":[{"type":"address","name":"rateFeedID","internalType":"address","indexed":true},{"type":"address","name":"breaker","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ResetAttemptNotCool","inputs":[{"type":"address","name":"rateFeedID","internalType":"address","indexed":true},{"type":"address","name":"breaker","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"ResetSuccessful","inputs":[{"type":"address","name":"rateFeedID","internalType":"address","indexed":true},{"type":"address","name":"breaker","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SortedOraclesUpdated","inputs":[{"type":"address","name":"newSortedOracles","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"TradingModeUpdated","inputs":[{"type":"address","name":"rateFeedID","internalType":"address","indexed":true},{"type":"uint256","name":"tradingMode","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","name":"addBreaker","inputs":[{"type":"address","name":"breaker","internalType":"address"},{"type":"uint8","name":"tradingMode","internalType":"uint8"}]},{"type":"function","stateMutability":"nonpayable","name":"addRateFeed","inputs":[{"type":"address","name":"rateFeedID","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","name":"addRateFeeds","inputs":[{"type":"address[]","name":"newRateFeedIDs","internalType":"address[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"breakerTradingMode","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"breakers","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","name":"checkAndSetBreakers","inputs":[{"type":"address","name":"rateFeedID","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getBreakers","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"getRateFeedTradingMode","inputs":[{"type":"address","name":"rateFeedID","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getRateFeeds","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isBreaker","inputs":[{"type":"address","name":"breaker","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isBreakerEnabled","inputs":[{"type":"address","name":"breaker","internalType":"address"},{"type":"address","name":"rateFeedID","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isOwner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"tradingMode","internalType":"uint8"},{"type":"uint64","name":"lastUpdatedTime","internalType":"uint64"},{"type":"bool","name":"enabled","internalType":"bool"}],"name":"rateFeedBreakerStatus","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"rateFeedDependencies","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"rateFeedIDs","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"rateFeedStatus","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"rateFeedTradingMode","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","name":"removeBreaker","inputs":[{"type":"address","name":"breaker","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","name":"removeRateFeed","inputs":[{"type":"address","name":"rateFeedID","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","name":"setRateFeedDependencies","inputs":[{"type":"address","name":"rateFeedID","internalType":"address"},{"type":"address[]","name":"dependencies","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","name":"setRateFeedTradingMode","inputs":[{"type":"address","name":"rateFeedID","internalType":"address"},{"type":"uint8","name":"tradingMode","internalType":"uint8"}]},{"type":"function","stateMutability":"nonpayable","name":"setSortedOracles","inputs":[{"type":"address","name":"_sortedOracles","internalType":"contract ISortedOracles"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract ISortedOracles"}],"name":"sortedOracles","inputs":[]},{"type":"function","stateMutability":"nonpayable","name":"toggleBreaker","inputs":[{"type":"address","name":"breakerAddress","internalType":"address"},{"type":"address","name":"rateFeedID","internalType":"address"},{"type":"bool","name":"enable","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]}]
              

Contract Creation Code

0x60806040523480156200001157600080fd5b5060405162002f5438038062002f54833981810160405260408110156200003757600080fd5b81019080805160405193929190846401000000008211156200005857600080fd5b9083019060208201858111156200006e57600080fd5b82518660208202830111640100000000821117156200008c57600080fd5b82525081516020918201928201910280838360005b83811015620000bb578181015183820152602001620000a1565b50505050919091016040525060200151915060009050620000e46001600160e01b036200016116565b600080546001600160a01b0319166001600160a01b03831690811782556040519293509160008051602062002ec1833981519152908290a35062000131336001600160e01b036200016516565b62000145816001600160e01b03620001f616565b62000159826001600160e01b03620002db16565b505062000637565b3390565b6001600160a01b038116620001ac5760405162461bcd60e51b815260040180806020018281038252602681526020018062002e7b6026913960400191505060405180910390fd5b600080546040516001600160a01b038085169392169160008051602062002ec183398151915291a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b620002096001600160e01b036200036e16565b6200024a576040805162461bcd60e51b8152602060048201819052602482015260008051602062002ea1833981519152604482015290519081900360640190fd5b6001600160a01b038116620002915760405162461bcd60e51b815260040180806020018281038252602181526020018062002f046021913960400191505060405180910390fd5b600880546001600160a01b0319166001600160a01b0383169081179091556040517f590fd633a008765ce9e65e8081adfba311e99e11b958a5ecb5000ea3355f735390600090a250565b620002ee6001600160e01b036200036e16565b6200032f576040805162461bcd60e51b8152602060048201819052602482015260008051602062002ea1833981519152604482015290519081900360640190fd5b60005b81518110156200036a57620003618282815181106200034d57fe5b60200260200101516200039d60201b60201c565b60010162000332565b5050565b600080546001600160a01b03166200038e6001600160e01b036200016116565b6001600160a01b031614905090565b620003b06001600160e01b036200036e16565b620003f1576040805162461bcd60e51b8152602060048201819052602482015260008051602062002ea1833981519152604482015290519081900360640190fd5b6001600160a01b03811660009081526002602052604090205460ff16156200044b5760405162461bcd60e51b815260040180806020018281038252602381526020018062002ee16023913960400191505060405180910390fd5b60085460408051638e74928160e01b81526001600160a01b03848116600483015291516000939290921691638e749281916024808201928692909190829003018186803b1580156200049c57600080fd5b505afa158015620004b1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526020811015620004db57600080fd5b8101908080516040519392919084640100000000821115620004fc57600080fd5b9083019060208201858111156200051257600080fd5b82518660208202830111640100000000821117156200053057600080fd5b82525081516020918201928201910280838360005b838110156200055f57818101518382015260200162000545565b505050509050016040525050505111620005ab5760405162461bcd60e51b815260040180806020018281038252602f81526020018062002f25602f913960400191505060405180910390fd5b6001805480820182557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180546001600160a01b0319166001600160a01b038416908117909155600081815260026020526040808220805460ff1916909417909355915190917fa1bccd87833fab06528ad8412cd349ff6ec2f1b851f48592a05ff995e4e7347d91a250565b61283480620006476000396000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c8063607e4569116100f95780638f32d59b11610097578063c0b05da011610071578063c0b05da014610630578063c4bb759b14610656578063f2fde38b1461067c578063ff7bffa1146106a2576101b9565b80638f32d59b146105a7578063ab02e6c0146105af578063b5b01283146105d5576101b9565b806385c89866116100d357806385c89866146104d657806387efb0b5146104f35780638c892d3d146105735780638da5cb5b1461059f576101b9565b8063607e456914610405578063715018a61461042b578063793cef5114610433576101b9565b806327fd631111610166578063360e10ae11610140578063360e10ae146103595780633ed739c31461037f5780634afb215e146103a55780635727caef146103cb576101b9565b806327fd6311146102e65780632e730a8e146103225780632eeae9961461032a576101b9565b8063132e8aa711610197578063132e8aa71461024d5780631d82c3a31461027157806321a2d9d01461028e576101b9565b80630308422e146101be57806309833c3e146101ef5780630c60714614610215575b600080fd5b6101ed600480360360408110156101d457600080fd5b5080356001600160a01b0316906020013560ff166106d0565b005b6101ed6004803603602081101561020557600080fd5b50356001600160a01b03166107f7565b6101ed6004803603606081101561022b57600080fd5b506001600160a01b038135811691602081013590911690604001351515610ad9565b610255610d95565b604080516001600160a01b039092168252519081900360200190f35b6102556004803603602081101561028757600080fd5b5035610da4565b610296610dcb565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156102d25781810151838201526020016102ba565b505050509050019250505060405180910390f35b61030c600480360360208110156102fc57600080fd5b50356001600160a01b0316610e2e565b6040805160ff9092168252519081900360200190f35b610296610e43565b6101ed6004803603604081101561034057600080fd5b5080356001600160a01b0316906020013560ff16610ea3565b6101ed6004803603602081101561036f57600080fd5b50356001600160a01b0316611034565b61030c6004803603602081101561039557600080fd5b50356001600160a01b03166112d6565b6101ed600480360360208110156103bb57600080fd5b50356001600160a01b03166112eb565b6103f1600480360360208110156103e157600080fd5b50356001600160a01b03166113eb565b604080519115158252519081900360200190f35b6103f16004803603602081101561041b57600080fd5b50356001600160a01b0316611400565b6101ed61145d565b6101ed6004803603602081101561044957600080fd5b81019060208101813564010000000081111561046457600080fd5b82018360208201111561047657600080fd5b8035906020019184602083028401116401000000008311171561049857600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611518945050505050565b610255600480360360208110156104ec57600080fd5b50356115a5565b6101ed6004803603604081101561050957600080fd5b6001600160a01b03823516919081019060408101602082013564010000000081111561053457600080fd5b82018360208201111561054657600080fd5b8035906020019184602083028401116401000000008311171561056857600080fd5b5090925090506115b2565b6102556004803603604081101561058957600080fd5b506001600160a01b0381351690602001356116f0565b610255611725565b6103f1611734565b6101ed600480360360208110156105c557600080fd5b50356001600160a01b0316611758565b610603600480360360408110156105eb57600080fd5b506001600160a01b03813581169160200135166117ad565b6040805160ff909416845267ffffffffffffffff9092166020840152151582820152519081900360600190f35b61030c6004803603602081101561064657600080fd5b50356001600160a01b03166117ef565b6101ed6004803603602081101561066c57600080fd5b50356001600160a01b03166118ff565b6101ed6004803603602081101561069257600080fd5b50356001600160a01b0316611bff565b6103f1600480360360408110156106b857600080fd5b506001600160a01b0381358116916020013516611c61565b6106d8611734565b610729576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b03821660009081526002602052604090205460ff16610796576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b6001600160a01b038216600081815260046020908152604091829020805460ff191660ff8616908117909155825190815291517fb64ea6f0b71eb82019a4e1cb18612c962bf400a2333377020f4a9ab71eeeeb529281900390910190a25050565b6107ff611734565b610850576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b03811660009081526002602052604090205460ff16156108a85760405162461bcd60e51b815260040180806020018281038252602381526020018061278d6023913960400191505060405180910390fd5b600854604080517f8e7492810000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015291516000939290921691638e749281916024808201928692909190829003018186803b15801561091157600080fd5b505afa158015610925573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561096c57600080fd5b810190808051604051939291908464010000000082111561098c57600080fd5b9083019060208201858111156109a157600080fd5b82518660208202830111640100000000821117156109be57600080fd5b82525081516020918201928201910280838360005b838110156109eb5781810151838201526020016109d3565b505050509050016040525050505111610a355760405162461bcd60e51b815260040180806020018281038252602f8152602001806127d1602f913960400191505060405180910390fd5b6001805480820182557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038416908117909155600081815260026020526040808220805460ff1916909417909355915190917fa1bccd87833fab06528ad8412cd349ff6ec2f1b851f48592a05ff995e4e7347d91a250565b610ae1611734565b610b32576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b03821660009081526002602052604090205460ff16610b9f576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b610ba883611400565b610be35760405162461bcd60e51b81526004018080602001828103825260318152602001806127396031913960400191505060405180910390fd5b6001600160a01b0380831660009081526003602090815260408083209387168352929052205460ff69010000000000000000009091041615158115151415610c72576040805162461bcd60e51b815260206004820181905260248201527f427265616b657220697320616c726561647920696e2074686973207374617465604482015290519081900360640190fd5b8015610ce1576001600160a01b03828116600090815260036020908152604080832093871683529290522080547fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff16690100000000000000000083151502179055610cdc82611c9e565b610d45565b6001600160a01b038083166000908152600360209081526040808320938716835292905290812080547fffffffffffffffffffffffffffffffffffffffffffff00000000000000000000169055610d3783611d7a565b9050610d4383826106d0565b505b604080516001600160a01b038086168252841660208201528215158183015290517f292d7648986a4abc017bc2a39852a675c1e325e24afd18fad659810792d5e4059181900360600190a1505050565b6008546001600160a01b031681565b60018181548110610db157fe5b6000918252602090912001546001600160a01b0316905081565b60606007805480602002602001604051908101604052809291908181526020018280548015610e2357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610e05575b505050505090505b90565b60046020526000908152604090205460ff1681565b60606001805480602002602001604051908101604052809291908181526020018280548015610e23576020028201919060005260206000209081546001600160a01b03168152600190910190602001808311610e05575050505050905090565b610eab611734565b610efc576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b818160ff16610f0a82611400565b15610f465760405162461bcd60e51b815260040180806020018281038252602381526020018061276a6023913960400191505060405180910390fd5b67ffffffffffffffff8116610f8c5760405162461bcd60e51b815260040180806020018281038252602f8152602001806126bb602f913960400191505060405180910390fd5b6001600160a01b038416600081815260066020526040808220805460ff191660ff8816179055600780546001810182559083527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180547fffffffffffffffffffffffff00000000000000000000000000000000000000001684179055517fb41d9a8e03d4798a0a905017e377ecae53ebc5ca694c8fccaeabb5a08c0d333f9190a250505050565b61103c611734565b61108d576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6000805b6001548110156110dd57826001600160a01b0316600182815481106110b257fe5b6000918252602090912001546001600160a01b031614156110d5578091506110dd565b600101611091565b50816001600160a01b0316600182815481106110f557fe5b6000918252602090912001546001600160a01b03161461115c576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b60018054600091611173919063ffffffff611e4c16565b90508082146111de576001818154811061118957fe5b600091825260209091200154600180546001600160a01b0390921691849081106111af57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60018054806111e957fe5b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559092019092556001600160a01b03851682526005905260408120611262916125ab565b6001600160a01b0383166000908152600460205260409020805460ff1916905561128b83611e95565b6001600160a01b038316600081815260026020526040808220805460ff19169055517f2646cbfbc7a17246cd5998517025a987bbdc416a91f2482601aeb30045d388199190a2505050565b60066020526000908152604090205460ff1681565b6112f3611734565b611344576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b0381166113895760405162461bcd60e51b81526004018080602001828103825260218152602001806127b06021913960400191505060405180910390fd5b600880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f590fd633a008765ce9e65e8081adfba311e99e11b958a5ecb5000ea3355f735390600090a250565b60026020526000908152604090205460ff1681565b6000805b60075481101561145257826001600160a01b03166007828154811061142557fe5b6000918252602090912001546001600160a01b0316141561144a576001915050611458565b600101611404565b50600090505b919050565b611465611734565b6114b6576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b611520611734565b611571576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b60005b81518110156115a15761159982828151811061158c57fe5b60200260200101516107f7565b600101611574565b5050565b60078181548110610db157fe5b6115ba611734565b61160b576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b03831660009081526002602052604090205460ff16611678576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b6001600160a01b038316600090815260056020526040902061169b9083836125c9565b50818160405180838360200280828437604051920182900382209450506001600160a01b03871692507f01ebc358c2c8d23692013d9ef4f803f9e0f60486a319faa591e1f84fd08fcd529150600090a3505050565b6005602052816000526040600020818154811061170957fe5b6000918252602090912001546001600160a01b03169150829050565b6000546001600160a01b031690565b600080546001600160a01b0316611749611f82565b6001600160a01b031614905090565b6008546001600160a01b031633146117a15760405162461bcd60e51b81526004018080602001828103825260298152602001806127106029913960400191505060405180910390fd5b6117aa81611c9e565b50565b600360209081526000928352604080842090915290825290205460ff8082169167ffffffffffffffff6101008204169169010000000000000000009091041683565b6001600160a01b03811660009081526002602052604081205460ff1661185c576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b6001600160a01b03821660009081526004602052604081205460ff16905b6001600160a01b0384166000908152600560205260409020548110156118f8576001600160a01b038416600090815260056020526040812080546004929190849081106118c357fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff16919091179060010161187a565b5092915050565b611907611734565b611958576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6000805b6007548110156119a857826001600160a01b03166007828154811061197d57fe5b6000918252602090912001546001600160a01b031614156119a0578091506119a8565b60010161195c565b50816001600160a01b0316600782815481106119c057fe5b6000918252602090912001546001600160a01b031614611a27576040805162461bcd60e51b815260206004820152601a60248201527f427265616b657220686173206e6f74206265656e206164646564000000000000604482015290519081900360640190fd5b60005b600154811015611ac3576003600060018381548110611a4557fe5b60009182526020808320909101546001600160a01b039081168452838201949094526040928301822093871682529290925290205460ff69010000000000000000009091041615611abb57611abb8360018381548110611aa157fe5b60009182526020822001546001600160a01b031690610ad9565b600101611a2a565b506001600160a01b0382166000908152600660205260408120805460ff19169055600754611af890600163ffffffff611e4c16565b9050808214611b635760078181548110611b0e57fe5b600091825260209091200154600780546001600160a01b039092169184908110611b3457fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6007805480611b6e57fe5b60008281526020812082017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559091019091556040516001600160a01b038516917f25d0fcab10ffc3ea7a197ec99e51df0362a1485e3a020caa618dbf72f92bb9f391a2505050565b611c07611734565b611c58576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6117aa81611f86565b6001600160a01b038181166000908152600360209081526040808320938616835292905220546901000000000000000000900460ff165b92915050565b6000805b600754811015611d4c576001600160a01b03831660009081526003602052604081206007805491929184908110611cd557fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff69010000000000000000009091041615611d44576000611d3d8460078481548110611d2357fe5b6000918252602090912001546001600160a01b031661203e565b9290921791505b600101611ca2565b506001600160a01b03919091166000908152600460205260409020805460ff191660ff909216919091179055565b600080805b6007548110156118f8576001600160a01b03841660009081526003602052604081206007805491929184908110611db257fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff69010000000000000000009091041615611e44576001600160a01b03841660009081526003602052604081206007805491929184908110611e1657fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1691909117905b600101611d7f565b6000611e8e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612089565b9392505050565b60005b6007548110156115a1576001600160a01b03821660009081526003602052604081206007805491929184908110611ecb57fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff69010000000000000000009091041615611f7a576001600160a01b03821660009081526003602052604081206007805491929184908110611f2f57fe5b60009182526020808320909101546001600160a01b03168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffff000000000000000000001690555b600101611e98565b3390565b6001600160a01b038116611fcb5760405162461bcd60e51b81526004018080602001828103825260268152602001806126ea6026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6001600160a01b03808316600090815260036020908152604080832093851683529290529081205460ff161561207f576120788383612120565b9050611c98565b611e8e838361240d565b600081848411156121185760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156120dd5781810151838201526020016120c5565b50505050905090810190601f16801561210a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600061212a612644565b506001600160a01b0380841660008181526003602090815260408083209487168084529482528083208151606081018352905460ff808216835267ffffffffffffffff6101008304168386015269010000000000000000009091041615158183015281517f39b84ecf000000000000000000000000000000000000000000000000000000008152600481019590955290519094879490926339b84ecf92602480840193829003018186803b1580156121e157600080fd5b505afa1580156121f5573d6000803e3d6000fd5b505050506040513d602081101561220b57600080fd5b50519050801580159061223d5750602083015161223990829067ffffffffffffffff1663ffffffff61255116565b4210155b1561239a57816001600160a01b03166368b89d58876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050602060405180830381600087803b15801561229a57600080fd5b505af11580156122ae573d6000803e3d6000fd5b505050506040513d60208110156122c457600080fd5b505115612354576001600160a01b038681166000818152600360209081526040808320948a168084529490915280822080547fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000166101004267ffffffffffffffff1602179055517fd45bd915ab99a070b980cdf13e671da6b79cc32e66eff6dc12c83a92071e6ab39190a3612395565b846001600160a01b0316866001600160a01b03167f90ca142474a3987fe4ec5cb24a254e13086fb998251070b5c9fc8ab70d78b8af60405160405180910390a35b6123db565b846001600160a01b0316866001600160a01b03167f636207d0069f1a3500c8d1676c804bc9d9a9d27e9add85139022a1757edf552260405160405180910390a35b505050506001600160a01b03918216600090815260036020908152604080832093909416825291909152205460ff1690565b604080517ffd165f530000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301529151600092839285929183169163fd165f539160248082019260209290919082900301818887803b15801561247857600080fd5b505af115801561248c573d6000803e3d6000fd5b505050506040513d60208110156124a257600080fd5b505115612549576001600160a01b03848116600081815260066020908152604080832054948a1680845260038352818420858552909252808320805460ff90961660ff1990961686177fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff166101004267ffffffffffffffff160217905551939550927fe59f00019fc03badf2caa7d5de220ccfa5a411564a41f3b15906c02fd20150d59190a35b509392505050565b600082820183811015611e8e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b50805460008255906000526020600020908101906117aa9190612664565b828054828255906000526020600020908101928215612634579160200282015b828111156126345781547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038435161782556020909201916001909101906125e9565b5061264092915061267e565b5090565b604080516060810182526000808252602082018190529181019190915290565b610e2b91905b80821115612640576000815560010161266a565b610e2b91905b808211156126405780547fffffffffffffffffffffffff000000000000000000000000000000000000000016815560010161268456fe5468652064656661756c742074726164696e67206d6f64652063616e206e6f742068617665206120627265616b65724f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737343616c6c6572206d7573742062652074686520536f727465644f7261636c657320636f6e74726163745468697320627265616b657220686173206e6f74206265656e20616464656420746f2074686520427265616b6572426f785468697320627265616b65722068617320616c7265616479206265656e2061646465645261746520666565642049442068617320616c7265616479206265656e206164646564536f727465644f7261636c65732061646472657373206d7573742062652073657452617465206665656420494420646f6573206e6f74206578697374206173206974206861732030206f7261636c6573a265627a7a72315820f807c460ba71f7b8cec5f504b723de0338eb5a85eeadc6f2370bb59c79b9e10f64736f6c634300051100324f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573734f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65728be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05261746520666565642049442068617320616c7265616479206265656e206164646564536f727465644f7261636c65732061646472657373206d7573742062652073657452617465206665656420494420646f6573206e6f74206578697374206173206974206861732030206f7261636c65730000000000000000000000000000000000000000000000000000000000000040000000000000000000000000fdd8bd58115ffbf04e47411c1d228ecc45e930750000000000000000000000000000000000000000000000000000000000000000

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101b95760003560e01c8063607e4569116100f95780638f32d59b11610097578063c0b05da011610071578063c0b05da014610630578063c4bb759b14610656578063f2fde38b1461067c578063ff7bffa1146106a2576101b9565b80638f32d59b146105a7578063ab02e6c0146105af578063b5b01283146105d5576101b9565b806385c89866116100d357806385c89866146104d657806387efb0b5146104f35780638c892d3d146105735780638da5cb5b1461059f576101b9565b8063607e456914610405578063715018a61461042b578063793cef5114610433576101b9565b806327fd631111610166578063360e10ae11610140578063360e10ae146103595780633ed739c31461037f5780634afb215e146103a55780635727caef146103cb576101b9565b806327fd6311146102e65780632e730a8e146103225780632eeae9961461032a576101b9565b8063132e8aa711610197578063132e8aa71461024d5780631d82c3a31461027157806321a2d9d01461028e576101b9565b80630308422e146101be57806309833c3e146101ef5780630c60714614610215575b600080fd5b6101ed600480360360408110156101d457600080fd5b5080356001600160a01b0316906020013560ff166106d0565b005b6101ed6004803603602081101561020557600080fd5b50356001600160a01b03166107f7565b6101ed6004803603606081101561022b57600080fd5b506001600160a01b038135811691602081013590911690604001351515610ad9565b610255610d95565b604080516001600160a01b039092168252519081900360200190f35b6102556004803603602081101561028757600080fd5b5035610da4565b610296610dcb565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156102d25781810151838201526020016102ba565b505050509050019250505060405180910390f35b61030c600480360360208110156102fc57600080fd5b50356001600160a01b0316610e2e565b6040805160ff9092168252519081900360200190f35b610296610e43565b6101ed6004803603604081101561034057600080fd5b5080356001600160a01b0316906020013560ff16610ea3565b6101ed6004803603602081101561036f57600080fd5b50356001600160a01b0316611034565b61030c6004803603602081101561039557600080fd5b50356001600160a01b03166112d6565b6101ed600480360360208110156103bb57600080fd5b50356001600160a01b03166112eb565b6103f1600480360360208110156103e157600080fd5b50356001600160a01b03166113eb565b604080519115158252519081900360200190f35b6103f16004803603602081101561041b57600080fd5b50356001600160a01b0316611400565b6101ed61145d565b6101ed6004803603602081101561044957600080fd5b81019060208101813564010000000081111561046457600080fd5b82018360208201111561047657600080fd5b8035906020019184602083028401116401000000008311171561049857600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611518945050505050565b610255600480360360208110156104ec57600080fd5b50356115a5565b6101ed6004803603604081101561050957600080fd5b6001600160a01b03823516919081019060408101602082013564010000000081111561053457600080fd5b82018360208201111561054657600080fd5b8035906020019184602083028401116401000000008311171561056857600080fd5b5090925090506115b2565b6102556004803603604081101561058957600080fd5b506001600160a01b0381351690602001356116f0565b610255611725565b6103f1611734565b6101ed600480360360208110156105c557600080fd5b50356001600160a01b0316611758565b610603600480360360408110156105eb57600080fd5b506001600160a01b03813581169160200135166117ad565b6040805160ff909416845267ffffffffffffffff9092166020840152151582820152519081900360600190f35b61030c6004803603602081101561064657600080fd5b50356001600160a01b03166117ef565b6101ed6004803603602081101561066c57600080fd5b50356001600160a01b03166118ff565b6101ed6004803603602081101561069257600080fd5b50356001600160a01b0316611bff565b6103f1600480360360408110156106b857600080fd5b506001600160a01b0381358116916020013516611c61565b6106d8611734565b610729576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b03821660009081526002602052604090205460ff16610796576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b6001600160a01b038216600081815260046020908152604091829020805460ff191660ff8616908117909155825190815291517fb64ea6f0b71eb82019a4e1cb18612c962bf400a2333377020f4a9ab71eeeeb529281900390910190a25050565b6107ff611734565b610850576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b03811660009081526002602052604090205460ff16156108a85760405162461bcd60e51b815260040180806020018281038252602381526020018061278d6023913960400191505060405180910390fd5b600854604080517f8e7492810000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015291516000939290921691638e749281916024808201928692909190829003018186803b15801561091157600080fd5b505afa158015610925573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561096c57600080fd5b810190808051604051939291908464010000000082111561098c57600080fd5b9083019060208201858111156109a157600080fd5b82518660208202830111640100000000821117156109be57600080fd5b82525081516020918201928201910280838360005b838110156109eb5781810151838201526020016109d3565b505050509050016040525050505111610a355760405162461bcd60e51b815260040180806020018281038252602f8152602001806127d1602f913960400191505060405180910390fd5b6001805480820182557fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038416908117909155600081815260026020526040808220805460ff1916909417909355915190917fa1bccd87833fab06528ad8412cd349ff6ec2f1b851f48592a05ff995e4e7347d91a250565b610ae1611734565b610b32576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b03821660009081526002602052604090205460ff16610b9f576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b610ba883611400565b610be35760405162461bcd60e51b81526004018080602001828103825260318152602001806127396031913960400191505060405180910390fd5b6001600160a01b0380831660009081526003602090815260408083209387168352929052205460ff69010000000000000000009091041615158115151415610c72576040805162461bcd60e51b815260206004820181905260248201527f427265616b657220697320616c726561647920696e2074686973207374617465604482015290519081900360640190fd5b8015610ce1576001600160a01b03828116600090815260036020908152604080832093871683529290522080547fffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffff16690100000000000000000083151502179055610cdc82611c9e565b610d45565b6001600160a01b038083166000908152600360209081526040808320938716835292905290812080547fffffffffffffffffffffffffffffffffffffffffffff00000000000000000000169055610d3783611d7a565b9050610d4383826106d0565b505b604080516001600160a01b038086168252841660208201528215158183015290517f292d7648986a4abc017bc2a39852a675c1e325e24afd18fad659810792d5e4059181900360600190a1505050565b6008546001600160a01b031681565b60018181548110610db157fe5b6000918252602090912001546001600160a01b0316905081565b60606007805480602002602001604051908101604052809291908181526020018280548015610e2357602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610e05575b505050505090505b90565b60046020526000908152604090205460ff1681565b60606001805480602002602001604051908101604052809291908181526020018280548015610e23576020028201919060005260206000209081546001600160a01b03168152600190910190602001808311610e05575050505050905090565b610eab611734565b610efc576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b818160ff16610f0a82611400565b15610f465760405162461bcd60e51b815260040180806020018281038252602381526020018061276a6023913960400191505060405180910390fd5b67ffffffffffffffff8116610f8c5760405162461bcd60e51b815260040180806020018281038252602f8152602001806126bb602f913960400191505060405180910390fd5b6001600160a01b038416600081815260066020526040808220805460ff191660ff8816179055600780546001810182559083527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6880180547fffffffffffffffffffffffff00000000000000000000000000000000000000001684179055517fb41d9a8e03d4798a0a905017e377ecae53ebc5ca694c8fccaeabb5a08c0d333f9190a250505050565b61103c611734565b61108d576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6000805b6001548110156110dd57826001600160a01b0316600182815481106110b257fe5b6000918252602090912001546001600160a01b031614156110d5578091506110dd565b600101611091565b50816001600160a01b0316600182815481106110f557fe5b6000918252602090912001546001600160a01b03161461115c576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b60018054600091611173919063ffffffff611e4c16565b90508082146111de576001818154811061118957fe5b600091825260209091200154600180546001600160a01b0390921691849081106111af57fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b60018054806111e957fe5b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559092019092556001600160a01b03851682526005905260408120611262916125ab565b6001600160a01b0383166000908152600460205260409020805460ff1916905561128b83611e95565b6001600160a01b038316600081815260026020526040808220805460ff19169055517f2646cbfbc7a17246cd5998517025a987bbdc416a91f2482601aeb30045d388199190a2505050565b60066020526000908152604090205460ff1681565b6112f3611734565b611344576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b0381166113895760405162461bcd60e51b81526004018080602001828103825260218152602001806127b06021913960400191505060405180910390fd5b600880547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f590fd633a008765ce9e65e8081adfba311e99e11b958a5ecb5000ea3355f735390600090a250565b60026020526000908152604090205460ff1681565b6000805b60075481101561145257826001600160a01b03166007828154811061142557fe5b6000918252602090912001546001600160a01b0316141561144a576001915050611458565b600101611404565b50600090505b919050565b611465611734565b6114b6576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055565b611520611734565b611571576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b60005b81518110156115a15761159982828151811061158c57fe5b60200260200101516107f7565b600101611574565b5050565b60078181548110610db157fe5b6115ba611734565b61160b576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b03831660009081526002602052604090205460ff16611678576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b6001600160a01b038316600090815260056020526040902061169b9083836125c9565b50818160405180838360200280828437604051920182900382209450506001600160a01b03871692507f01ebc358c2c8d23692013d9ef4f803f9e0f60486a319faa591e1f84fd08fcd529150600090a3505050565b6005602052816000526040600020818154811061170957fe5b6000918252602090912001546001600160a01b03169150829050565b6000546001600160a01b031690565b600080546001600160a01b0316611749611f82565b6001600160a01b031614905090565b6008546001600160a01b031633146117a15760405162461bcd60e51b81526004018080602001828103825260298152602001806127106029913960400191505060405180910390fd5b6117aa81611c9e565b50565b600360209081526000928352604080842090915290825290205460ff8082169167ffffffffffffffff6101008204169169010000000000000000009091041683565b6001600160a01b03811660009081526002602052604081205460ff1661185c576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b6001600160a01b03821660009081526004602052604081205460ff16905b6001600160a01b0384166000908152600560205260409020548110156118f8576001600160a01b038416600090815260056020526040812080546004929190849081106118c357fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff16919091179060010161187a565b5092915050565b611907611734565b611958576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6000805b6007548110156119a857826001600160a01b03166007828154811061197d57fe5b6000918252602090912001546001600160a01b031614156119a0578091506119a8565b60010161195c565b50816001600160a01b0316600782815481106119c057fe5b6000918252602090912001546001600160a01b031614611a27576040805162461bcd60e51b815260206004820152601a60248201527f427265616b657220686173206e6f74206265656e206164646564000000000000604482015290519081900360640190fd5b60005b600154811015611ac3576003600060018381548110611a4557fe5b60009182526020808320909101546001600160a01b039081168452838201949094526040928301822093871682529290925290205460ff69010000000000000000009091041615611abb57611abb8360018381548110611aa157fe5b60009182526020822001546001600160a01b031690610ad9565b600101611a2a565b506001600160a01b0382166000908152600660205260408120805460ff19169055600754611af890600163ffffffff611e4c16565b9050808214611b635760078181548110611b0e57fe5b600091825260209091200154600780546001600160a01b039092169184908110611b3457fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b6007805480611b6e57fe5b60008281526020812082017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559091019091556040516001600160a01b038516917f25d0fcab10ffc3ea7a197ec99e51df0362a1485e3a020caa618dbf72f92bb9f391a2505050565b611c07611734565b611c58576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6117aa81611f86565b6001600160a01b038181166000908152600360209081526040808320938616835292905220546901000000000000000000900460ff165b92915050565b6000805b600754811015611d4c576001600160a01b03831660009081526003602052604081206007805491929184908110611cd557fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff69010000000000000000009091041615611d44576000611d3d8460078481548110611d2357fe5b6000918252602090912001546001600160a01b031661203e565b9290921791505b600101611ca2565b506001600160a01b03919091166000908152600460205260409020805460ff191660ff909216919091179055565b600080805b6007548110156118f8576001600160a01b03841660009081526003602052604081206007805491929184908110611db257fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff69010000000000000000009091041615611e44576001600160a01b03841660009081526003602052604081206007805491929184908110611e1657fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1691909117905b600101611d7f565b6000611e8e83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612089565b9392505050565b60005b6007548110156115a1576001600160a01b03821660009081526003602052604081206007805491929184908110611ecb57fe5b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff69010000000000000000009091041615611f7a576001600160a01b03821660009081526003602052604081206007805491929184908110611f2f57fe5b60009182526020808320909101546001600160a01b03168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffff000000000000000000001690555b600101611e98565b3390565b6001600160a01b038116611fcb5760405162461bcd60e51b81526004018080602001828103825260268152602001806126ea6026913960400191505060405180910390fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0392909216919091179055565b6001600160a01b03808316600090815260036020908152604080832093851683529290529081205460ff161561207f576120788383612120565b9050611c98565b611e8e838361240d565b600081848411156121185760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b838110156120dd5781810151838201526020016120c5565b50505050905090810190601f16801561210a5780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b600061212a612644565b506001600160a01b0380841660008181526003602090815260408083209487168084529482528083208151606081018352905460ff808216835267ffffffffffffffff6101008304168386015269010000000000000000009091041615158183015281517f39b84ecf000000000000000000000000000000000000000000000000000000008152600481019590955290519094879490926339b84ecf92602480840193829003018186803b1580156121e157600080fd5b505afa1580156121f5573d6000803e3d6000fd5b505050506040513d602081101561220b57600080fd5b50519050801580159061223d5750602083015161223990829067ffffffffffffffff1663ffffffff61255116565b4210155b1561239a57816001600160a01b03166368b89d58876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050602060405180830381600087803b15801561229a57600080fd5b505af11580156122ae573d6000803e3d6000fd5b505050506040513d60208110156122c457600080fd5b505115612354576001600160a01b038681166000818152600360209081526040808320948a168084529490915280822080547fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000166101004267ffffffffffffffff1602179055517fd45bd915ab99a070b980cdf13e671da6b79cc32e66eff6dc12c83a92071e6ab39190a3612395565b846001600160a01b0316866001600160a01b03167f90ca142474a3987fe4ec5cb24a254e13086fb998251070b5c9fc8ab70d78b8af60405160405180910390a35b6123db565b846001600160a01b0316866001600160a01b03167f636207d0069f1a3500c8d1676c804bc9d9a9d27e9add85139022a1757edf552260405160405180910390a35b505050506001600160a01b03918216600090815260036020908152604080832093909416825291909152205460ff1690565b604080517ffd165f530000000000000000000000000000000000000000000000000000000081526001600160a01b0384811660048301529151600092839285929183169163fd165f539160248082019260209290919082900301818887803b15801561247857600080fd5b505af115801561248c573d6000803e3d6000fd5b505050506040513d60208110156124a257600080fd5b505115612549576001600160a01b03848116600081815260066020908152604080832054948a1680845260038352818420858552909252808320805460ff90961660ff1990961686177fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff166101004267ffffffffffffffff160217905551939550927fe59f00019fc03badf2caa7d5de220ccfa5a411564a41f3b15906c02fd20150d59190a35b509392505050565b600082820183811015611e8e576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b50805460008255906000526020600020908101906117aa9190612664565b828054828255906000526020600020908101928215612634579160200282015b828111156126345781547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038435161782556020909201916001909101906125e9565b5061264092915061267e565b5090565b604080516060810182526000808252602082018190529181019190915290565b610e2b91905b80821115612640576000815560010161266a565b610e2b91905b808211156126405780547fffffffffffffffffffffffff000000000000000000000000000000000000000016815560010161268456fe5468652064656661756c742074726164696e67206d6f64652063616e206e6f742068617665206120627265616b65724f776e61626c653a206e6577206f776e657220697320746865207a65726f206164647265737343616c6c6572206d7573742062652074686520536f727465644f7261636c657320636f6e74726163745468697320627265616b657220686173206e6f74206265656e20616464656420746f2074686520427265616b6572426f785468697320627265616b65722068617320616c7265616479206265656e2061646465645261746520666565642049442068617320616c7265616479206265656e206164646564536f727465644f7261636c65732061646472657373206d7573742062652073657452617465206665656420494420646f6573206e6f74206578697374206173206974206861732030206f7261636c6573a265627a7a72315820f807c460ba71f7b8cec5f504b723de0338eb5a85eeadc6f2370bb59c79b9e10f64736f6c63430005110032

External libraries

AddressLinkedList : 0x2f0f7686fffefc3c266403ad600035581deaedff  
AddressSortedLinkedListWithMedian : 0x29b1b5e05217c751038861af2c77494eab10a257