Address Details
contract

0xFF5F884291EB111D1B7fb25E6099a736D4fdA52c

Contract Name
BreakerBox
Creator
0x56fd3f–9b8d81 at 0xed8922–2272d8
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,715
Last Balance Update
21371662
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
EVM Version
istanbul




Verified at
2023-03-10T06:55:50.979353Z

lib/mento-core/contracts/BreakerBox.sol

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

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

import { SafeMath } from "openzeppelin-solidity/contracts/math/SafeMath.sol";
import { Ownable } from "openzeppelin-solidity/contracts/ownership/Ownable.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.
 */
contract BreakerBox is IBreakerBox, Initializable, Ownable {
  using AddressLinkedList for LinkedList.List;
  using SafeMath for uint256;

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

  address[] public rateFeedIDs;
  // Maps rate feed ID to its current trading mode info.
  mapping(address => TradingModeInfo) public rateFeedTradingModes;
  // Maps a trading mode to the associated breaker.
  mapping(uint64 => address) public tradingModeBreaker;
  // Maps a breaker to the associated trading mode.
  mapping(address => uint64) public breakerTradingMode;
  // Ordered list of breakers to be checked.
  LinkedList.List private breakers;
  // Maps a breaker with rate feed id and bool to check if it's enabled.
  mapping(address => mapping(address => bool)) public breakerEnabled;

  // 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(
      tradingModeBreaker[tradingMode] == address(0),
      "There is already a breaker added with the same trading mode"
    );
    require(tradingMode != 0, "The default trading mode can not have a breaker");
    _;
  }

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

  /**
   * @notice Sets initialized == true on implementation contracts.
   * @param test Set to true to skip implementation initialization.
   */
  constructor(bool test) public Initializable(test) {}

  /**
   * @param _rateFeedIDs rateFeedIDs to be added.
   * @param _sortedOracles The address of the Celo sorted oracles contract.
   */
  function initialize(address[] calldata _rateFeedIDs, ISortedOracles _sortedOracles) external initializer {
    _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 tradingMode-Breaker 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, uint64 tradingMode) public onlyOwner onlyValidBreaker(breaker, tradingMode) {
    tradingModeBreaker[tradingMode] = breaker;
    breakerTradingMode[breaker] = tradingMode;
    breakers.push(breaker);
    emit BreakerAdded(breaker);
  }

  /**
   * @notice Adds a breaker to the list of breakers at a specified position.
   * @param breaker The address of the breaker to be added.
   * @param tradingMode The trading mode of the breaker to be added.
   * @param prevBreaker The address of the breaker that should come before the new breaker.
   * @param nextBreaker The address of the breaker that should come after the new breaker.
   */
  function insertBreaker(
    address breaker,
    uint64 tradingMode,
    address prevBreaker,
    address nextBreaker
  ) external onlyOwner onlyValidBreaker(breaker, tradingMode) {
    tradingModeBreaker[tradingMode] = breaker;
    breakerTradingMode[breaker] = tradingMode;
    breakers.insert(breaker, prevBreaker, nextBreaker);
    emit BreakerAdded(breaker);
  }

  /**
   * @notice Removes the specified breaker from the list of breakers.
   * @param breaker The address of the breaker to be removed.
   * @dev Will set any rateFeedID using this breakers trading mode to the default trading mode
   *      because if its tripped and if we remove it rateFeed will be stuck in the trading mode.
   */
  function removeBreaker(address breaker) external onlyOwner {
    require(isBreaker(breaker), "This breaker has not been added");

    uint64 tradingMode = breakerTradingMode[breaker];

    // Set any refenceRateIDs using this breakers trading mode to the default mode.
    // Disable a breaker on this address
    address[] memory activeRateFeeds = rateFeedIDs;
    TradingModeInfo memory tradingModeInfo;

    for (uint256 i = 0; i < activeRateFeeds.length; i++) {
      tradingModeInfo = rateFeedTradingModes[activeRateFeeds[i]];
      if (tradingModeInfo.tradingMode == tradingMode) {
        setRateFeedTradingMode(activeRateFeeds[i], 0);
      }
      if (breakerEnabled[breaker][activeRateFeeds[i]]) {
        breakerEnabled[breaker][activeRateFeeds[i]] = false;
      }
    }
    delete tradingModeBreaker[tradingMode];
    delete breakerTradingMode[breaker];
    breakers.remove(breaker);

    emit BreakerRemoved(breaker);
  }

  /**
   * @notice Enables or disables a breaker for the specified rate feed.
   * @param breakerAddress The address of the breaker.
   * @param rateFeedId The id of the rate feed.
   * @param isEnabled Boolean indicating whether the breaker should be
   *                  enabled or disabled for the given rateFeed.
   * @dev If the breaker is being disabled and the rateFeed is using the same trading mode
   *      as the breaker, the rateFeed will be set to the default trading mode.
   */
  function toggleBreaker(
    address breakerAddress,
    address rateFeedId,
    bool isEnabled
  ) public onlyOwner {
    TradingModeInfo memory info = rateFeedTradingModes[rateFeedId];
    require(info.lastUpdatedTime != 0, "This rate feed has not been added to the BreakerBox");
    require(isBreaker(breakerAddress), "This breaker has not been added to the BreakerBox");

    // Check if we are disabling the breaker for this rateFeedID.
    // If so, set the rateFeed to the default trading mode,
    // before disabling the breaker.
    if (!isEnabled && tradingModeBreaker[info.tradingMode] == breakerAddress) {
      setRateFeedTradingMode(rateFeedId, 0);
    }

    breakerEnabled[breakerAddress][rateFeedId] = isEnabled;
    emit BreakerStatusUpdated(breakerAddress, rateFeedId, isEnabled);
  }

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

  /**
   * @notice Adds a rateFeedID to the mapping of monitored rateFeedIDs.
   * @param rateFeedID The address of the rateFeedID to be added.
   */
  function addRateFeed(address rateFeedID) public onlyOwner {
    TradingModeInfo memory info = rateFeedTradingModes[rateFeedID];
    require(info.lastUpdatedTime == 0, "Rate feed ID has already been added");

    require(sortedOracles.getOracles(rateFeedID).length > 0, "Rate feed ID does not exist as it has 0 oracles");

    info.tradingMode = 0; // Default trading mode (Bi-directional).
    info.lastUpdatedTime = uint64(block.timestamp);
    info.lastUpdatedBlock = uint128(block.number);
    rateFeedTradingModes[rateFeedID] = info;
    rateFeedIDs.push(rateFeedID);

    emit RateFeedAdded(rateFeedID);
  }

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

  /**
   * @notice Removes a rateFeedID from the mapping of monitored rateFeedIDs.
   * @param rateFeedID The address of the rateFeedID 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 rateFeedTradingModes[rateFeedID];

    address[] memory _breakers = breakers.getKeys();

    // remove configured rate feed for the breaker
    for (uint256 i = 0; i < _breakers.length; i++) {
      if (breakerEnabled[_breakers[i]][rateFeedID]) {
        breakerEnabled[_breakers[i]][rateFeedID] = false;
      }
    }
    emit RateFeedRemoved(rateFeedID);
  }

  /**
   * @notice Sets the trading mode for the specified rateFeedID.
   * @param rateFeedID The address of the rateFeedID.
   * @param tradingMode The trading mode that should be set.
   */
  function setRateFeedTradingMode(address rateFeedID, uint64 tradingMode) public onlyOwner {
    require(
      tradingMode == 0 || tradingModeBreaker[tradingMode] != address(0),
      "Trading mode must be default or have a breaker set"
    );

    TradingModeInfo memory info = rateFeedTradingModes[rateFeedID];
    require(info.lastUpdatedTime > 0, "Rate feed ID has not been added");

    info.tradingMode = tradingMode;
    info.lastUpdatedTime = uint64(block.timestamp);
    info.lastUpdatedBlock = uint128(block.number);
    rateFeedTradingModes[rateFeedID] = info;

    emit TradingModeUpdated(rateFeedID, tradingMode);
  }

  /* ==================== 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.getKeys();
  }

  /**
   * @notice Checks whether a breaker with the specifed address has been added.
   */
  function isBreaker(address breaker) public view returns (bool) {
    return breakers.contains(breaker);
  }

  /**
   * @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 rateFeedID to retrieve the trading mode for.
   */
  function getRateFeedTradingMode(address rateFeedID) external view returns (uint256 tradingMode) {
    TradingModeInfo memory info = rateFeedTradingModes[rateFeedID];
    return info.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 rateFeedID.
   */
  function isBreakerEnabled(address breaker, address rateFeedID) external view returns (bool) {
    return breakerEnabled[breaker][rateFeedID];
  }

  /* ==================== 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 registryId of the rateFeedID to run checks for.
   */
  function checkAndSetBreakers(address rateFeedID) external {
    TradingModeInfo memory info = rateFeedTradingModes[rateFeedID];

    // This rateFeedID has not been added. So do nothing.
    if (info.lastUpdatedTime == 0) {
      return;
    }

    // Check if a breaker has non default trading mode and reset if we should.
    if (info.tradingMode != 0) {
      IBreaker breaker = IBreaker(tradingModeBreaker[info.tradingMode]);

      uint256 cooldown = breaker.getCooldown(rateFeedID);

      // If the cooldown == 0, then a manual reset is required.
      if (((cooldown > 0) && (cooldown.add(info.lastUpdatedTime)) <= block.timestamp)) {
        if (breaker.shouldReset(rateFeedID)) {
          info.tradingMode = 0;
          info.lastUpdatedTime = uint64(block.timestamp);
          info.lastUpdatedBlock = uint128(block.number);
          rateFeedTradingModes[rateFeedID] = info;
          emit ResetSuccessful(rateFeedID, address(breaker));
        } else {
          emit ResetAttemptCriteriaFail(rateFeedID, address(breaker));
          return;
        }
      } else {
        emit ResetAttemptNotCool(rateFeedID, address(breaker));
        return;
      }
    }

    address[] memory _breakers = breakers.getKeys();

    // Check all breakers.
    for (uint256 i = 0; i < _breakers.length; i++) {
      if (breakerEnabled[_breakers[i]][rateFeedID]) {
        IBreaker breaker = IBreaker(_breakers[i]);
        bool tripBreaker = breaker.shouldTrigger(rateFeedID);
        if (tripBreaker) {
          info.tradingMode = breakerTradingMode[address(breaker)];
          info.lastUpdatedTime = uint64(block.timestamp);
          info.lastUpdatedBlock = uint128(block.number);
          rateFeedTradingModes[rateFeedID] = info;
          emit BreakerTripped(address(breaker), rateFeedID);
        }
      }
    }
  }
}
        

/lib/mento-core/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/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/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/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/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/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/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 track additional info about
   *      the current trading mode a specific rate feed ID is in.
   *      LastUpdatedTime helps to check cooldown.
   *      LastUpdatedBlock helps to determine if check should be executed.
   */
  struct TradingModeInfo {
    uint64 tradingMode;
    uint64 lastUpdatedTime;
    uint128 lastUpdatedBlock;
  }

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

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

  /**
   * @notice Emitted when a breaker is tripped by a rate feed.
   * @param breaker The address of the breaker that was tripped.
   * @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 that was added.
   */
  event RateFeedAdded(address indexed rateFeedID);

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

  /**
   * @notice Emitted when the trading mode for a rate feed is updated
   * @param rateFeedID The address of the rataFeedID.
   * @param tradingMode The new trading mode of the rate feed.
   */
  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 ordered 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 registryId of the rateFeedID to run checks for.
   */
  function checkAndSetBreakers(address rateFeedID) external;

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

/lib/mento-core/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
    );
}
          

/lib/mento-core/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/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/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;
    }
}
          

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","payable":false,"inputs":[{"type":"bool","name":"test","internalType":"bool"}]},{"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":"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","payable":false,"outputs":[],"name":"addBreaker","inputs":[{"type":"address","name":"breaker","internalType":"address"},{"type":"uint64","name":"tradingMode","internalType":"uint64"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addRateFeed","inputs":[{"type":"address","name":"rateFeedID","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addRateFeeds","inputs":[{"type":"address[]","name":"newRateFeedIDs","internalType":"address[]"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"breakerEnabled","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"breakerTradingMode","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"checkAndSetBreakers","inputs":[{"type":"address","name":"rateFeedID","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getBreakers","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"tradingMode","internalType":"uint256"}],"name":"getRateFeedTradingMode","inputs":[{"type":"address","name":"rateFeedID","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address[]","name":"","internalType":"address[]"}],"name":"getRateFeeds","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"address[]","name":"_rateFeedIDs","internalType":"address[]"},{"type":"address","name":"_sortedOracles","internalType":"contract ISortedOracles"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"initialized","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"insertBreaker","inputs":[{"type":"address","name":"breaker","internalType":"address"},{"type":"uint64","name":"tradingMode","internalType":"uint64"},{"type":"address","name":"prevBreaker","internalType":"address"},{"type":"address","name":"nextBreaker","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isBreaker","inputs":[{"type":"address","name":"breaker","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isBreakerEnabled","inputs":[{"type":"address","name":"breaker","internalType":"address"},{"type":"address","name":"rateFeedID","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isOwner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"rateFeedIDs","inputs":[{"type":"uint256","name":"","internalType":"uint256"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint64","name":"tradingMode","internalType":"uint64"},{"type":"uint64","name":"lastUpdatedTime","internalType":"uint64"},{"type":"uint128","name":"lastUpdatedBlock","internalType":"uint128"}],"name":"rateFeedTradingModes","inputs":[{"type":"address","name":"","internalType":"address"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeBreaker","inputs":[{"type":"address","name":"breaker","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeRateFeed","inputs":[{"type":"address","name":"rateFeedID","internalType":"address"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setRateFeedTradingMode","inputs":[{"type":"address","name":"rateFeedID","internalType":"address"},{"type":"uint64","name":"tradingMode","internalType":"uint64"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setSortedOracles","inputs":[{"type":"address","name":"_sortedOracles","internalType":"contract ISortedOracles"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"contract ISortedOracles"}],"name":"sortedOracles","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"toggleBreaker","inputs":[{"type":"address","name":"breakerAddress","internalType":"address"},{"type":"address","name":"rateFeedId","internalType":"address"},{"type":"bool","name":"isEnabled","internalType":"bool"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"","internalType":"address"}],"name":"tradingModeBreaker","inputs":[{"type":"uint64","name":"","internalType":"uint64"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}],"constant":false}]
              

Contract Creation Code

0x60806040523480156200001157600080fd5b506040516200307938038062003079833981810160405260208110156200003757600080fd5b505180806200004e576000805460ff191660011790555b506000620000646001600160e01b03620000bd16565b60008054610100600160a81b0319166101006001600160a01b038416908102919091178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35050620000c1565b3390565b612fa880620000d16000396000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c80634afb215e116100f9578063ab02e6c011610097578063e0d8bc1811610071578063e0d8bc1814610609578063f2fde38b1461066c578063fab07b6314610692578063ff7bffa1146106d8576101b9565b8063ab02e6c014610585578063c0b05da0146105ab578063c4bb759b146105e3576101b9565b8063715018a6116100d3578063715018a6146104ca578063793cef51146104d25780638da5cb5b146105755780638f32d59b1461057d576101b9565b80634afb215e14610457578063607e45691461047d57806367c0c689146104a3576101b9565b806321a2d9d011610166578063360e10ae11610140578063360e10ae1461033f5780633b2d10e8146103655780633ed739c31461039b578063462d0b2e146103de576101b9565b806321a2d9d0146102b15780632e730a8e14610309578063320836a814610311576101b9565b8063132e8aa711610197578063132e8aa714610254578063158ef93e146102785780631d82c3a314610294576101b9565b806307437f6c146101be57806309833c3e146101f65780630c6071461461021c575b600080fd5b6101f4600480360360408110156101d457600080fd5b5080356001600160a01b0316906020013567ffffffffffffffff16610706565b005b6101f46004803603602081101561020c57600080fd5b50356001600160a01b031661097c565b6101f46004803603606081101561023257600080fd5b506001600160a01b038135811691602081013590911690604001351515610d57565b61025c610f8b565b604080516001600160a01b039092168252519081900360200190f35b610280610f9a565b604080519115158252519081900360200190f35b61025c600480360360208110156102aa57600080fd5b5035610fa3565b6102b9610fca565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156102f55781810151838201526020016102dd565b505050509050019250505060405180910390f35b6102b961110a565b6102806004803603604081101561032757600080fd5b506001600160a01b038135811691602001351661116c565b6101f46004803603602081101561035557600080fd5b50356001600160a01b031661118c565b6101f46004803603604081101561037b57600080fd5b5080356001600160a01b0316906020013567ffffffffffffffff1661161a565b6103c1600480360360208110156103b157600080fd5b50356001600160a01b03166118a6565b6040805167ffffffffffffffff9092168252519081900360200190f35b6101f4600480360360408110156103f457600080fd5b81019060208101813564010000000081111561040f57600080fd5b82018360208201111561042157600080fd5b8035906020019184602083028401116401000000008311171561044357600080fd5b9193509150356001600160a01b03166118c2565b6101f46004803603602081101561046d57600080fd5b50356001600160a01b0316611998565b6102806004803603602081101561049357600080fd5b50356001600160a01b0316611a98565b61025c600480360360208110156104b957600080fd5b503567ffffffffffffffff16611b48565b6101f4611b63565b6101f4600480360360208110156104e857600080fd5b81019060208101813564010000000081111561050357600080fd5b82018360208201111561051557600080fd5b8035906020019184602083028401116401000000008311171561053757600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611c22945050505050565b61025c611caf565b610280611cc3565b6101f46004803603602081101561059b57600080fd5b50356001600160a01b0316611cec565b6105d1600480360360208110156105c157600080fd5b50356001600160a01b03166123b6565b60408051918252519081900360200190f35b6101f4600480360360208110156105f957600080fd5b50356001600160a01b031661243b565b61062f6004803603602081101561061f57600080fd5b50356001600160a01b0316612829565b6040805167ffffffffffffffff94851681529290931660208301526fffffffffffffffffffffffffffffffff168183015290519081900360600190f35b6101f46004803603602081101561068257600080fd5b50356001600160a01b031661287e565b6101f4600480360360808110156106a857600080fd5b506001600160a01b03813581169167ffffffffffffffff60208201351691604082013581169160600135166128e0565b610280600480360360408110156106ee57600080fd5b506001600160a01b0381358116916020013516612b69565b61070e611cc3565b61075f576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b818161076a82611a98565b156107a65760405162461bcd60e51b8152600401808060200182810382526023815260200180612ede6023913960400191505060405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316156108055760405162461bcd60e51b815260040180806020018281038252603b815260200180612e72603b913960400191505060405180910390fd5b67ffffffffffffffff811661084b5760405162461bcd60e51b815260040180806020018281038252602f815260200180612db8602f913960400191505060405180910390fd5b67ffffffffffffffff8316600081815260036020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a16908117909155808452600492839052818420805467ffffffffffffffff191690951790945580517f26afac4900000000000000000000000000000000000000000000000000000000815260059281019290925260248201939093529151736200f54d73491d56b8d7a975c9ee18efb4d518df926326afac49926044808301939192829003018186803b15801561092a57600080fd5b505af415801561093e573d6000803e3d6000fd5b50506040516001600160a01b03871692507fb41d9a8e03d4798a0a905017e377ecae53ebc5ca694c8fccaeabb5a08c0d333f9150600090a250505050565b610984611cc3565b6109d5576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6109dd612d97565b506001600160a01b0381166000908152600260209081526040918290208251606081018452905467ffffffffffffffff80821683526801000000000000000082041692820183905270010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169281019290925215610a8e5760405162461bcd60e51b8152600401808060200182810382526023815260200180612f016023913960400191505060405180910390fd5b600a54604080517f8e7492810000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015291516000939290921691638e749281916024808201928692909190829003018186803b158015610af757600080fd5b505afa158015610b0b573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526020811015610b5257600080fd5b8101908080516040519392919084640100000000821115610b7257600080fd5b908301906020820185811115610b8757600080fd5b8251866020820283011164010000000082111715610ba457600080fd5b82525081516020918201928201910280838360005b83811015610bd1578181015183820152602001610bb9565b505050509050016040525050505111610c1b5760405162461bcd60e51b815260040180806020018281038252602f815260200180612f45602f913960400191505060405180910390fd5b60008082524267ffffffffffffffff90811660208085019182526fffffffffffffffffffffffffffffffff43811660408088019182526001600160a01b0389168088526002909452808720885181549651935185167001000000000000000000000000000000000293881668010000000000000000027fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff9190981667ffffffffffffffff19909716969096179590951695909517909116179091556001805480820182559084527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180547fffffffffffffffffffffffff00000000000000000000000000000000000000001682179055905190917fa1bccd87833fab06528ad8412cd349ff6ec2f1b851f48592a05ff995e4e7347d91a25050565b610d5f611cc3565b610db0576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b610db8612d97565b506001600160a01b0382166000908152600260209081526040918290208251606081018452905467ffffffffffffffff80821683526801000000000000000082041692820183905270010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1692810192909252610e685760405162461bcd60e51b8152600401808060200182810382526033815260200180612e3f6033913960400191505060405180910390fd5b610e7184611a98565b610eac5760405162461bcd60e51b8152600401808060200182810382526031815260200180612ead6031913960400191505060405180910390fd5b81158015610edf5750805167ffffffffffffffff166000908152600360205260409020546001600160a01b038581169116145b15610eef57610eef83600061161a565b6001600160a01b0380851660008181526009602090815260408083209488168084529482529182902080548715157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911681179091558251938452908301939093528181019290925290517f292d7648986a4abc017bc2a39852a675c1e325e24afd18fad659810792d5e4059181900360600190a150505050565b600a546001600160a01b031681565b60005460ff1681565b60018181548110610fb057fe5b6000918252602090912001546001600160a01b0316905081565b60606005736200f54d73491d56b8d7a975c9ee18efb4d518df63fe3c7a8e90916040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b15801561101e57600080fd5b505af4158015611032573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561107957600080fd5b810190808051604051939291908464010000000082111561109957600080fd5b9083019060208201858111156110ae57600080fd5b82518660208202830111640100000000821117156110cb57600080fd5b82525081516020918201928201910280838360005b838110156110f85781810151838201526020016110e0565b50505050905001604052505050905090565b6060600180548060200260200160405190810160405280929190818152602001828054801561116257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611144575b5050505050905090565b600960209081526000928352604080842090915290825290205460ff1681565b611194611cc3565b6111e5576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6000805b60015481101561123557826001600160a01b03166001828154811061120a57fe5b6000918252602090912001546001600160a01b0316141561122d57809150611235565b6001016111e9565b50816001600160a01b03166001828154811061124d57fe5b6000918252602090912001546001600160a01b0316146112b4576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b600180546000916112cb919063ffffffff612b9716565b905080821461133657600181815481106112e157fe5b600091825260209091200154600180546001600160a01b03909216918490811061130757fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600180548061134157fe5b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559092019092556001600160a01b038516825260029052604080822082905580517ffe3c7a8e000000000000000000000000000000000000000000000000000000008152600560048201529051606092736200f54d73491d56b8d7a975c9ee18efb4d518df9263fe3c7a8e9260248083019392829003018186803b15801561141d57600080fd5b505af4158015611431573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561147857600080fd5b810190808051604051939291908464010000000082111561149857600080fd5b9083019060208201858111156114ad57600080fd5b82518660208202830111640100000000821117156114ca57600080fd5b82525081516020918201928201910280838360005b838110156114f75781810151838201526020016114df565b50505050905001604052505050905060008090505b81518110156115df576009600083838151811061152557fe5b6020908102919091018101516001600160a01b0390811683528282019390935260409182016000908120938916815292905290205460ff16156115d75760006009600084848151811061157457fe5b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000876001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055505b60010161150c565b506040516001600160a01b038516907f2646cbfbc7a17246cd5998517025a987bbdc416a91f2482601aeb30045d3881990600090a250505050565b611622611cc3565b611673576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b67ffffffffffffffff811615806116ab575067ffffffffffffffff81166000908152600360205260409020546001600160a01b031615155b6116e65760405162461bcd60e51b8152600401808060200182810382526032815260200180612de76032913960400191505060405180910390fd5b6116ee612d97565b506001600160a01b0382166000908152600260209081526040918290208251606081018452905467ffffffffffffffff80821683526801000000000000000082041692820183905270010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16928101929092526117b4576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b67ffffffffffffffff80831680835242821660208085019182526fffffffffffffffffffffffffffffffff43811660408088019182526001600160a01b038a166000818152600286528290208951815497519451861670010000000000000000000000000000000002948a1668010000000000000000027fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff91909a1667ffffffffffffffff1990981697909717969096169790971790921617909255815192835290517fb64ea6f0b71eb82019a4e1cb18612c962bf400a2333377020f4a9ab71eeeeb529281900390910190a2505050565b60046020526000908152604090205467ffffffffffffffff1681565b60005460ff161561191a576040805162461bcd60e51b815260206004820152601c60248201527f636f6e747261637420616c726561647920696e697469616c697a656400000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561194e33612be0565b61195781611998565b611993838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611c2292505050565b505050565b6119a0611cc3565b6119f1576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116611a365760405162461bcd60e51b8152600401808060200182810382526021815260200180612f246021913960400191505060405180910390fd5b600a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f590fd633a008765ce9e65e8081adfba311e99e11b958a5ecb5000ea3355f735390600090a250565b604080517f542424fb000000000000000000000000000000000000000000000000000000008152600560048201526001600160a01b03831660248201529051600091736200f54d73491d56b8d7a975c9ee18efb4d518df9163542424fb91604480820192602092909190829003018186803b158015611b1657600080fd5b505af4158015611b2a573d6000803e3d6000fd5b505050506040513d6020811015611b4057600080fd5b505192915050565b6003602052600090815260409020546001600160a01b031681565b611b6b611cc3565b611bbc576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516101009091046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffff0000000000000000000000000000000000000000ff169055565b611c2a611cc3565b611c7b576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b60005b8151811015611cab57611ca3828281518110611c9657fe5b602002602001015161097c565b600101611c7e565b5050565b60005461010090046001600160a01b031690565b6000805461010090046001600160a01b0316611cdd612ca2565b6001600160a01b031614905090565b611cf4612d97565b506001600160a01b0381166000908152600260209081526040918290208251606081018452905467ffffffffffffffff80821683526801000000000000000082041692820183905270010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1692810192909252611d7357506123b3565b805167ffffffffffffffff161561207357805167ffffffffffffffff1660009081526003602090815260408083205481517f39b84ecf0000000000000000000000000000000000000000000000000000000081526001600160a01b038781166004830152925192909116939284926339b84ecf926024808201939291829003018186803b158015611e0357600080fd5b505afa158015611e17573d6000803e3d6000fd5b505050506040513d6020811015611e2d57600080fd5b505190508015801590611e60575042611e5d846020015167ffffffffffffffff1683612ca690919063ffffffff16565b11155b1561202857816001600160a01b03166368b89d58856040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050602060405180830381600087803b158015611ebd57600080fd5b505af1158015611ed1573d6000803e3d6000fd5b505050506040513d6020811015611ee757600080fd5b505115611fdb5760008084524267ffffffffffffffff90811660208087019182526fffffffffffffffffffffffffffffffff4381166040808a019182526001600160a01b03808c1680895260029095528188208b5181549751945186167001000000000000000000000000000000000294891668010000000000000000027fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff9190991667ffffffffffffffff199098169790971796909616969096179092161790925590519185169290917fd45bd915ab99a070b980cdf13e671da6b79cc32e66eff6dc12c83a92071e6ab39190a3612023565b816001600160a01b0316846001600160a01b03167f90ca142474a3987fe4ec5cb24a254e13086fb998251070b5c9fc8ab70d78b8af60405160405180910390a35050506123b3565b612070565b816001600160a01b0316846001600160a01b03167f636207d0069f1a3500c8d1676c804bc9d9a9d27e9add85139022a1757edf552260405160405180910390a35050506123b3565b50505b60606005736200f54d73491d56b8d7a975c9ee18efb4d518df63fe3c7a8e90916040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b1580156120c757600080fd5b505af41580156120db573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561212257600080fd5b810190808051604051939291908464010000000082111561214257600080fd5b90830190602082018581111561215757600080fd5b825186602082028301116401000000008211171561217457600080fd5b82525081516020918201928201910280838360005b838110156121a1578181015183820152602001612189565b50505050905001604052505050905060008090505b81518110156123af57600960008383815181106121cf57fe5b6020908102919091018101516001600160a01b0390811683528282019390935260409182016000908120938816815292905290205460ff16156123a757600082828151811061221a57fe5b602002602001015190506000816001600160a01b031663fd165f53876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050602060405180830381600087803b15801561227e57600080fd5b505af1158015612292573d6000803e3d6000fd5b505050506040513d60208110156122a857600080fd5b5051905080156123a4576001600160a01b0382811660008181526004602090815260408083205467ffffffffffffffff9081168b524281168b8401908152436fffffffffffffffffffffffffffffffff9081168d8501908152978e1680875260029095528386208d5181549351995167ffffffffffffffff19909416908516177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000999094169890980292909217821670010000000000000000000000000000000091909216021790945592517fe59f00019fc03badf2caa7d5de220ccfa5a411564a41f3b15906c02fd20150d59190a35b50505b6001016121b6565b5050505b50565b60006123c0612d97565b50506001600160a01b03166000908152600260209081526040918290208251606081018452905467ffffffffffffffff8082168084526801000000000000000083049091169383019390935270010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1692019190915290565b612443611cc3565b612494576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b61249d81611a98565b6124ee576040805162461bcd60e51b815260206004820152601f60248201527f5468697320627265616b657220686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b6001600160a01b038116600090815260046020908152604091829020546001805484518185028101850190955280855267ffffffffffffffff9092169360609390929083018282801561256a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161254c575b50505050509050612579612d97565b60005b8251811015612704576002600084838151811061259557fe5b6020908102919091018101516001600160a01b031682528181019290925260409081016000208151606081018352905467ffffffffffffffff8082168084526801000000000000000083048216958401959095527001000000000000000000000000000000009091046fffffffffffffffffffffffffffffffff169282019290925293508516141561263f5761263f83828151811061263057fe5b6020026020010151600061161a565b6001600160a01b0385166000908152600960205260408120845190919085908490811061266857fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16156126fc576001600160a01b0385166000908152600960205260408120845182908690859081106126bc57fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055505b60010161257c565b5067ffffffffffffffff8316600090815260036020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556001600160a01b038716808452600492839052818420805467ffffffffffffffff1916905581517fe2c0c56a000000000000000000000000000000000000000000000000000000008152600593810193909352602483015251736200f54d73491d56b8d7a975c9ee18efb4d518df9263e2c0c56a9260448082019391829003018186803b1580156127d757600080fd5b505af41580156127eb573d6000803e3d6000fd5b50506040516001600160a01b03871692507f25d0fcab10ffc3ea7a197ec99e51df0362a1485e3a020caa618dbf72f92bb9f39150600090a250505050565b60026020526000908152604090205467ffffffffffffffff808216916801000000000000000081049091169070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1683565b612886611cc3565b6128d7576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6123b381612be0565b6128e8611cc3565b612939576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b838361294482611a98565b156129805760405162461bcd60e51b8152600401808060200182810382526023815260200180612ede6023913960400191505060405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316156129df5760405162461bcd60e51b815260040180806020018281038252603b815260200180612e72603b913960400191505060405180910390fd5b67ffffffffffffffff8116612a255760405162461bcd60e51b815260040180806020018281038252602f815260200180612db8602f913960400191505060405180910390fd5b67ffffffffffffffff8516600081815260036020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038c8116918217909255808552600493849052828520805467ffffffffffffffff191690961790955581517f07debf7c0000000000000000000000000000000000000000000000000000000081526005938101939093526024830194909452878416604483015292861660648201529151736200f54d73491d56b8d7a975c9ee18efb4d518df926307debf7c926084808301939192829003018186803b158015612b1557600080fd5b505af4158015612b29573d6000803e3d6000fd5b50506040516001600160a01b03891692507fb41d9a8e03d4798a0a905017e377ecae53ebc5ca694c8fccaeabb5a08c0d333f9150600090a2505050505050565b6001600160a01b03918216600090815260096020908152604080832093909416825291909152205460ff1690565b6000612bd983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612d00565b9392505050565b6001600160a01b038116612c255760405162461bcd60e51b8152600401808060200182810382526026815260200180612e196026913960400191505060405180910390fd5b600080546040516001600160a01b038085169361010090930416917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b3390565b600082820183811015612bd9576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008184841115612d8f5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612d54578181015183820152602001612d3c565b50505050905090810190601f168015612d815780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60408051606081018252600080825260208201819052918101919091529056fe5468652064656661756c742074726164696e67206d6f64652063616e206e6f742068617665206120627265616b657254726164696e67206d6f6465206d7573742062652064656661756c74206f722068617665206120627265616b6572207365744f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373546869732072617465206665656420686173206e6f74206265656e20616464656420746f2074686520427265616b6572426f78546865726520697320616c7265616479206120627265616b65722061646465642077697468207468652073616d652074726164696e67206d6f64655468697320627265616b657220686173206e6f74206265656e20616464656420746f2074686520427265616b6572426f785468697320627265616b65722068617320616c7265616479206265656e2061646465645261746520666565642049442068617320616c7265616479206265656e206164646564536f727465644f7261636c65732061646472657373206d7573742062652073657452617465206665656420494420646f6573206e6f74206578697374206173206974206861732030206f7261636c6573a265627a7a723158201f19e4ba64c3acb116b113470f105c5af2bc8ef653c39ffe9240af5bf24349af64736f6c634300051100320000000000000000000000000000000000000000000000000000000000000000

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101b95760003560e01c80634afb215e116100f9578063ab02e6c011610097578063e0d8bc1811610071578063e0d8bc1814610609578063f2fde38b1461066c578063fab07b6314610692578063ff7bffa1146106d8576101b9565b8063ab02e6c014610585578063c0b05da0146105ab578063c4bb759b146105e3576101b9565b8063715018a6116100d3578063715018a6146104ca578063793cef51146104d25780638da5cb5b146105755780638f32d59b1461057d576101b9565b80634afb215e14610457578063607e45691461047d57806367c0c689146104a3576101b9565b806321a2d9d011610166578063360e10ae11610140578063360e10ae1461033f5780633b2d10e8146103655780633ed739c31461039b578063462d0b2e146103de576101b9565b806321a2d9d0146102b15780632e730a8e14610309578063320836a814610311576101b9565b8063132e8aa711610197578063132e8aa714610254578063158ef93e146102785780631d82c3a314610294576101b9565b806307437f6c146101be57806309833c3e146101f65780630c6071461461021c575b600080fd5b6101f4600480360360408110156101d457600080fd5b5080356001600160a01b0316906020013567ffffffffffffffff16610706565b005b6101f46004803603602081101561020c57600080fd5b50356001600160a01b031661097c565b6101f46004803603606081101561023257600080fd5b506001600160a01b038135811691602081013590911690604001351515610d57565b61025c610f8b565b604080516001600160a01b039092168252519081900360200190f35b610280610f9a565b604080519115158252519081900360200190f35b61025c600480360360208110156102aa57600080fd5b5035610fa3565b6102b9610fca565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156102f55781810151838201526020016102dd565b505050509050019250505060405180910390f35b6102b961110a565b6102806004803603604081101561032757600080fd5b506001600160a01b038135811691602001351661116c565b6101f46004803603602081101561035557600080fd5b50356001600160a01b031661118c565b6101f46004803603604081101561037b57600080fd5b5080356001600160a01b0316906020013567ffffffffffffffff1661161a565b6103c1600480360360208110156103b157600080fd5b50356001600160a01b03166118a6565b6040805167ffffffffffffffff9092168252519081900360200190f35b6101f4600480360360408110156103f457600080fd5b81019060208101813564010000000081111561040f57600080fd5b82018360208201111561042157600080fd5b8035906020019184602083028401116401000000008311171561044357600080fd5b9193509150356001600160a01b03166118c2565b6101f46004803603602081101561046d57600080fd5b50356001600160a01b0316611998565b6102806004803603602081101561049357600080fd5b50356001600160a01b0316611a98565b61025c600480360360208110156104b957600080fd5b503567ffffffffffffffff16611b48565b6101f4611b63565b6101f4600480360360208110156104e857600080fd5b81019060208101813564010000000081111561050357600080fd5b82018360208201111561051557600080fd5b8035906020019184602083028401116401000000008311171561053757600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611c22945050505050565b61025c611caf565b610280611cc3565b6101f46004803603602081101561059b57600080fd5b50356001600160a01b0316611cec565b6105d1600480360360208110156105c157600080fd5b50356001600160a01b03166123b6565b60408051918252519081900360200190f35b6101f4600480360360208110156105f957600080fd5b50356001600160a01b031661243b565b61062f6004803603602081101561061f57600080fd5b50356001600160a01b0316612829565b6040805167ffffffffffffffff94851681529290931660208301526fffffffffffffffffffffffffffffffff168183015290519081900360600190f35b6101f46004803603602081101561068257600080fd5b50356001600160a01b031661287e565b6101f4600480360360808110156106a857600080fd5b506001600160a01b03813581169167ffffffffffffffff60208201351691604082013581169160600135166128e0565b610280600480360360408110156106ee57600080fd5b506001600160a01b0381358116916020013516612b69565b61070e611cc3565b61075f576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b818161076a82611a98565b156107a65760405162461bcd60e51b8152600401808060200182810382526023815260200180612ede6023913960400191505060405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316156108055760405162461bcd60e51b815260040180806020018281038252603b815260200180612e72603b913960400191505060405180910390fd5b67ffffffffffffffff811661084b5760405162461bcd60e51b815260040180806020018281038252602f815260200180612db8602f913960400191505060405180910390fd5b67ffffffffffffffff8316600081815260036020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038a16908117909155808452600492839052818420805467ffffffffffffffff191690951790945580517f26afac4900000000000000000000000000000000000000000000000000000000815260059281019290925260248201939093529151736200f54d73491d56b8d7a975c9ee18efb4d518df926326afac49926044808301939192829003018186803b15801561092a57600080fd5b505af415801561093e573d6000803e3d6000fd5b50506040516001600160a01b03871692507fb41d9a8e03d4798a0a905017e377ecae53ebc5ca694c8fccaeabb5a08c0d333f9150600090a250505050565b610984611cc3565b6109d5576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6109dd612d97565b506001600160a01b0381166000908152600260209081526040918290208251606081018452905467ffffffffffffffff80821683526801000000000000000082041692820183905270010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff169281019290925215610a8e5760405162461bcd60e51b8152600401808060200182810382526023815260200180612f016023913960400191505060405180910390fd5b600a54604080517f8e7492810000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015291516000939290921691638e749281916024808201928692909190829003018186803b158015610af757600080fd5b505afa158015610b0b573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526020811015610b5257600080fd5b8101908080516040519392919084640100000000821115610b7257600080fd5b908301906020820185811115610b8757600080fd5b8251866020820283011164010000000082111715610ba457600080fd5b82525081516020918201928201910280838360005b83811015610bd1578181015183820152602001610bb9565b505050509050016040525050505111610c1b5760405162461bcd60e51b815260040180806020018281038252602f815260200180612f45602f913960400191505060405180910390fd5b60008082524267ffffffffffffffff90811660208085019182526fffffffffffffffffffffffffffffffff43811660408088019182526001600160a01b0389168088526002909452808720885181549651935185167001000000000000000000000000000000000293881668010000000000000000027fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff9190981667ffffffffffffffff19909716969096179590951695909517909116179091556001805480820182559084527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf60180547fffffffffffffffffffffffff00000000000000000000000000000000000000001682179055905190917fa1bccd87833fab06528ad8412cd349ff6ec2f1b851f48592a05ff995e4e7347d91a25050565b610d5f611cc3565b610db0576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b610db8612d97565b506001600160a01b0382166000908152600260209081526040918290208251606081018452905467ffffffffffffffff80821683526801000000000000000082041692820183905270010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1692810192909252610e685760405162461bcd60e51b8152600401808060200182810382526033815260200180612e3f6033913960400191505060405180910390fd5b610e7184611a98565b610eac5760405162461bcd60e51b8152600401808060200182810382526031815260200180612ead6031913960400191505060405180910390fd5b81158015610edf5750805167ffffffffffffffff166000908152600360205260409020546001600160a01b038581169116145b15610eef57610eef83600061161a565b6001600160a01b0380851660008181526009602090815260408083209488168084529482529182902080548715157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090911681179091558251938452908301939093528181019290925290517f292d7648986a4abc017bc2a39852a675c1e325e24afd18fad659810792d5e4059181900360600190a150505050565b600a546001600160a01b031681565b60005460ff1681565b60018181548110610fb057fe5b6000918252602090912001546001600160a01b0316905081565b60606005736200f54d73491d56b8d7a975c9ee18efb4d518df63fe3c7a8e90916040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b15801561101e57600080fd5b505af4158015611032573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561107957600080fd5b810190808051604051939291908464010000000082111561109957600080fd5b9083019060208201858111156110ae57600080fd5b82518660208202830111640100000000821117156110cb57600080fd5b82525081516020918201928201910280838360005b838110156110f85781810151838201526020016110e0565b50505050905001604052505050905090565b6060600180548060200260200160405190810160405280929190818152602001828054801561116257602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611144575b5050505050905090565b600960209081526000928352604080842090915290825290205460ff1681565b611194611cc3565b6111e5576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6000805b60015481101561123557826001600160a01b03166001828154811061120a57fe5b6000918252602090912001546001600160a01b0316141561122d57809150611235565b6001016111e9565b50816001600160a01b03166001828154811061124d57fe5b6000918252602090912001546001600160a01b0316146112b4576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b600180546000916112cb919063ffffffff612b9716565b905080821461133657600181815481106112e157fe5b600091825260209091200154600180546001600160a01b03909216918490811061130757fe5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600180548061134157fe5b6000828152602080822083017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690559092019092556001600160a01b038516825260029052604080822082905580517ffe3c7a8e000000000000000000000000000000000000000000000000000000008152600560048201529051606092736200f54d73491d56b8d7a975c9ee18efb4d518df9263fe3c7a8e9260248083019392829003018186803b15801561141d57600080fd5b505af4158015611431573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561147857600080fd5b810190808051604051939291908464010000000082111561149857600080fd5b9083019060208201858111156114ad57600080fd5b82518660208202830111640100000000821117156114ca57600080fd5b82525081516020918201928201910280838360005b838110156114f75781810151838201526020016114df565b50505050905001604052505050905060008090505b81518110156115df576009600083838151811061152557fe5b6020908102919091018101516001600160a01b0390811683528282019390935260409182016000908120938916815292905290205460ff16156115d75760006009600084848151811061157457fe5b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000876001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055505b60010161150c565b506040516001600160a01b038516907f2646cbfbc7a17246cd5998517025a987bbdc416a91f2482601aeb30045d3881990600090a250505050565b611622611cc3565b611673576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b67ffffffffffffffff811615806116ab575067ffffffffffffffff81166000908152600360205260409020546001600160a01b031615155b6116e65760405162461bcd60e51b8152600401808060200182810382526032815260200180612de76032913960400191505060405180910390fd5b6116ee612d97565b506001600160a01b0382166000908152600260209081526040918290208251606081018452905467ffffffffffffffff80821683526801000000000000000082041692820183905270010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16928101929092526117b4576040805162461bcd60e51b815260206004820152601f60248201527f52617465206665656420494420686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b67ffffffffffffffff80831680835242821660208085019182526fffffffffffffffffffffffffffffffff43811660408088019182526001600160a01b038a166000818152600286528290208951815497519451861670010000000000000000000000000000000002948a1668010000000000000000027fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff91909a1667ffffffffffffffff1990981697909717969096169790971790921617909255815192835290517fb64ea6f0b71eb82019a4e1cb18612c962bf400a2333377020f4a9ab71eeeeb529281900390910190a2505050565b60046020526000908152604090205467ffffffffffffffff1681565b60005460ff161561191a576040805162461bcd60e51b815260206004820152601c60248201527f636f6e747261637420616c726561647920696e697469616c697a656400000000604482015290519081900360640190fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561194e33612be0565b61195781611998565b611993838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250611c2292505050565b505050565b6119a0611cc3565b6119f1576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6001600160a01b038116611a365760405162461bcd60e51b8152600401808060200182810382526021815260200180612f246021913960400191505060405180910390fd5b600a80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f590fd633a008765ce9e65e8081adfba311e99e11b958a5ecb5000ea3355f735390600090a250565b604080517f542424fb000000000000000000000000000000000000000000000000000000008152600560048201526001600160a01b03831660248201529051600091736200f54d73491d56b8d7a975c9ee18efb4d518df9163542424fb91604480820192602092909190829003018186803b158015611b1657600080fd5b505af4158015611b2a573d6000803e3d6000fd5b505050506040513d6020811015611b4057600080fd5b505192915050565b6003602052600090815260409020546001600160a01b031681565b611b6b611cc3565b611bbc576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b600080546040516101009091046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffff0000000000000000000000000000000000000000ff169055565b611c2a611cc3565b611c7b576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b60005b8151811015611cab57611ca3828281518110611c9657fe5b602002602001015161097c565b600101611c7e565b5050565b60005461010090046001600160a01b031690565b6000805461010090046001600160a01b0316611cdd612ca2565b6001600160a01b031614905090565b611cf4612d97565b506001600160a01b0381166000908152600260209081526040918290208251606081018452905467ffffffffffffffff80821683526801000000000000000082041692820183905270010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1692810192909252611d7357506123b3565b805167ffffffffffffffff161561207357805167ffffffffffffffff1660009081526003602090815260408083205481517f39b84ecf0000000000000000000000000000000000000000000000000000000081526001600160a01b038781166004830152925192909116939284926339b84ecf926024808201939291829003018186803b158015611e0357600080fd5b505afa158015611e17573d6000803e3d6000fd5b505050506040513d6020811015611e2d57600080fd5b505190508015801590611e60575042611e5d846020015167ffffffffffffffff1683612ca690919063ffffffff16565b11155b1561202857816001600160a01b03166368b89d58856040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050602060405180830381600087803b158015611ebd57600080fd5b505af1158015611ed1573d6000803e3d6000fd5b505050506040513d6020811015611ee757600080fd5b505115611fdb5760008084524267ffffffffffffffff90811660208087019182526fffffffffffffffffffffffffffffffff4381166040808a019182526001600160a01b03808c1680895260029095528188208b5181549751945186167001000000000000000000000000000000000294891668010000000000000000027fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff9190991667ffffffffffffffff199098169790971796909616969096179092161790925590519185169290917fd45bd915ab99a070b980cdf13e671da6b79cc32e66eff6dc12c83a92071e6ab39190a3612023565b816001600160a01b0316846001600160a01b03167f90ca142474a3987fe4ec5cb24a254e13086fb998251070b5c9fc8ab70d78b8af60405160405180910390a35050506123b3565b612070565b816001600160a01b0316846001600160a01b03167f636207d0069f1a3500c8d1676c804bc9d9a9d27e9add85139022a1757edf552260405160405180910390a35050506123b3565b50505b60606005736200f54d73491d56b8d7a975c9ee18efb4d518df63fe3c7a8e90916040518263ffffffff1660e01b81526004018082815260200191505060006040518083038186803b1580156120c757600080fd5b505af41580156120db573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052602081101561212257600080fd5b810190808051604051939291908464010000000082111561214257600080fd5b90830190602082018581111561215757600080fd5b825186602082028301116401000000008211171561217457600080fd5b82525081516020918201928201910280838360005b838110156121a1578181015183820152602001612189565b50505050905001604052505050905060008090505b81518110156123af57600960008383815181106121cf57fe5b6020908102919091018101516001600160a01b0390811683528282019390935260409182016000908120938816815292905290205460ff16156123a757600082828151811061221a57fe5b602002602001015190506000816001600160a01b031663fd165f53876040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b03168152602001915050602060405180830381600087803b15801561227e57600080fd5b505af1158015612292573d6000803e3d6000fd5b505050506040513d60208110156122a857600080fd5b5051905080156123a4576001600160a01b0382811660008181526004602090815260408083205467ffffffffffffffff9081168b524281168b8401908152436fffffffffffffffffffffffffffffffff9081168d8501908152978e1680875260029095528386208d5181549351995167ffffffffffffffff19909416908516177fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff1668010000000000000000999094169890980292909217821670010000000000000000000000000000000091909216021790945592517fe59f00019fc03badf2caa7d5de220ccfa5a411564a41f3b15906c02fd20150d59190a35b50505b6001016121b6565b5050505b50565b60006123c0612d97565b50506001600160a01b03166000908152600260209081526040918290208251606081018452905467ffffffffffffffff8082168084526801000000000000000083049091169383019390935270010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1692019190915290565b612443611cc3565b612494576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b61249d81611a98565b6124ee576040805162461bcd60e51b815260206004820152601f60248201527f5468697320627265616b657220686173206e6f74206265656e20616464656400604482015290519081900360640190fd5b6001600160a01b038116600090815260046020908152604091829020546001805484518185028101850190955280855267ffffffffffffffff9092169360609390929083018282801561256a57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161254c575b50505050509050612579612d97565b60005b8251811015612704576002600084838151811061259557fe5b6020908102919091018101516001600160a01b031682528181019290925260409081016000208151606081018352905467ffffffffffffffff8082168084526801000000000000000083048216958401959095527001000000000000000000000000000000009091046fffffffffffffffffffffffffffffffff169282019290925293508516141561263f5761263f83828151811061263057fe5b6020026020010151600061161a565b6001600160a01b0385166000908152600960205260408120845190919085908490811061266857fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff16156126fc576001600160a01b0385166000908152600960205260408120845182908690859081106126bc57fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055505b60010161257c565b5067ffffffffffffffff8316600090815260036020908152604080832080547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556001600160a01b038716808452600492839052818420805467ffffffffffffffff1916905581517fe2c0c56a000000000000000000000000000000000000000000000000000000008152600593810193909352602483015251736200f54d73491d56b8d7a975c9ee18efb4d518df9263e2c0c56a9260448082019391829003018186803b1580156127d757600080fd5b505af41580156127eb573d6000803e3d6000fd5b50506040516001600160a01b03871692507f25d0fcab10ffc3ea7a197ec99e51df0362a1485e3a020caa618dbf72f92bb9f39150600090a250505050565b60026020526000908152604090205467ffffffffffffffff808216916801000000000000000081049091169070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1683565b612886611cc3565b6128d7576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b6123b381612be0565b6128e8611cc3565b612939576040805162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015290519081900360640190fd5b838361294482611a98565b156129805760405162461bcd60e51b8152600401808060200182810382526023815260200180612ede6023913960400191505060405180910390fd5b67ffffffffffffffff81166000908152600360205260409020546001600160a01b0316156129df5760405162461bcd60e51b815260040180806020018281038252603b815260200180612e72603b913960400191505060405180910390fd5b67ffffffffffffffff8116612a255760405162461bcd60e51b815260040180806020018281038252602f815260200180612db8602f913960400191505060405180910390fd5b67ffffffffffffffff8516600081815260036020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038c8116918217909255808552600493849052828520805467ffffffffffffffff191690961790955581517f07debf7c0000000000000000000000000000000000000000000000000000000081526005938101939093526024830194909452878416604483015292861660648201529151736200f54d73491d56b8d7a975c9ee18efb4d518df926307debf7c926084808301939192829003018186803b158015612b1557600080fd5b505af4158015612b29573d6000803e3d6000fd5b50506040516001600160a01b03891692507fb41d9a8e03d4798a0a905017e377ecae53ebc5ca694c8fccaeabb5a08c0d333f9150600090a2505050505050565b6001600160a01b03918216600090815260096020908152604080832093909416825291909152205460ff1690565b6000612bd983836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250612d00565b9392505050565b6001600160a01b038116612c255760405162461bcd60e51b8152600401808060200182810382526026815260200180612e196026913960400191505060405180910390fd5b600080546040516001600160a01b038085169361010090930416917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b3390565b600082820183811015612bd9576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b60008184841115612d8f5760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612d54578181015183820152602001612d3c565b50505050905090810190601f168015612d815780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b60408051606081018252600080825260208201819052918101919091529056fe5468652064656661756c742074726164696e67206d6f64652063616e206e6f742068617665206120627265616b657254726164696e67206d6f6465206d7573742062652064656661756c74206f722068617665206120627265616b6572207365744f776e61626c653a206e6577206f776e657220697320746865207a65726f2061646472657373546869732072617465206665656420686173206e6f74206265656e20616464656420746f2074686520427265616b6572426f78546865726520697320616c7265616479206120627265616b65722061646465642077697468207468652073616d652074726164696e67206d6f64655468697320627265616b657220686173206e6f74206265656e20616464656420746f2074686520427265616b6572426f785468697320627265616b65722068617320616c7265616479206265656e2061646465645261746520666565642049442068617320616c7265616479206265656e206164646564536f727465644f7261636c65732061646472657373206d7573742062652073657452617465206665656420494420646f6573206e6f74206578697374206173206974206861732030206f7261636c6573a265627a7a723158201f19e4ba64c3acb116b113470f105c5af2bc8ef653c39ffe9240af5bf24349af64736f6c63430005110032

External libraries

AddressLinkedList : 0x6200f54d73491d56b8d7a975c9ee18efb4d518df  
AddressSortedLinkedListWithMedian : 0xed477a99035d0c1e11369f1d7a4e587893cc002b