{"file_path":"lib/mento-core-2.6.5/contracts/swap/BiPoolManager.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.5.13;\npragma experimental ABIEncoderV2;\n\nimport { Ownable } from \"openzeppelin-solidity/contracts/ownership/Ownable.sol\";\nimport { SafeMath } from \"openzeppelin-solidity/contracts/math/SafeMath.sol\";\n\nimport { IERC20 } from \"../interfaces/IERC20.sol\";\nimport { IExchangeProvider } from \"../interfaces/IExchangeProvider.sol\";\nimport { IBiPoolManager } from \"../interfaces/IBiPoolManager.sol\";\nimport { IReserve } from \"../interfaces/IReserve.sol\";\nimport { ISortedOracles } from \"../interfaces/ISortedOracles.sol\";\nimport { IBreakerBox } from \"../interfaces/IBreakerBox.sol\";\n\nimport { Initializable } from \"celo/contracts/common/Initializable.sol\";\nimport { FixidityLib } from \"celo/contracts/common/FixidityLib.sol\";\n\n/**\n * @title BiPoolExchangeManager\n * @notice An exchange manager that manages asset exchanges consisting of two assets\n */\ncontract BiPoolManager is IExchangeProvider, IBiPoolManager, Initializable, Ownable {\n  using FixidityLib for FixidityLib.Fraction;\n  using SafeMath for uint256;\n\n  /* ==================== State Variables ==================== */\n\n  // Address of the broker contract.\n  address public broker;\n\n  // Maps an exchange id to the corresponding PoolExchange struct.\n  // exchangeId is in the format \"asset0Symbol:asset1Symbol:pricingModuleName\"\n  mapping(bytes32 => PoolExchange) public exchanges;\n  bytes32[] public exchangeIds;\n\n  uint256 private constant TRADING_MODE_BIDIRECTIONAL = 0;\n\n  // Address of the Mento Reserve contract\n  IReserve public reserve;\n\n  // Address of the Mento BreakerBox contract\n  IBreakerBox public breakerBox;\n\n  // Address of the Mento SortedOracles contract\n  ISortedOracles public sortedOracles;\n\n  // Token precision multiplier used to normalize values to the\n  // same precision when calculating vAMM bucket sizes.\n  mapping(address => uint256) public tokenPrecisionMultipliers;\n\n  bytes32 public constant CONSTANT_SUM = keccak256(abi.encodePacked(\"ConstantSum\"));\n  bytes32 public constant CONSTANT_PRODUCT = keccak256(abi.encodePacked(\"ConstantProduct\"));\n\n  // Maps a pricing module identifier to the address of the pricing module contract.\n  mapping(bytes32 => address) public pricingModules;\n\n  /* ==================== Constructor ==================== */\n\n  /**\n   * @notice Sets initialized == true on implementation contracts.\n   * @param test Set to true to skip implementation initialization.\n   */\n  // solhint-disable-next-line no-empty-blocks\n  constructor(bool test) public Initializable(test) {}\n\n  /**\n   * @notice Allows the contract to be upgradable via the proxy.\n   * @param _broker The address of the broker contract.\n   * @param _reserve The address of the reserve contract.\n   * @param _sortedOracles The address of the sorted oracles contract.\n   * @param _breakerBox The address of the breaker box contract.\n   */\n  function initialize(\n    address _broker,\n    IReserve _reserve,\n    ISortedOracles _sortedOracles,\n    IBreakerBox _breakerBox\n  ) external initializer {\n    _transferOwnership(msg.sender);\n    setBroker(_broker);\n    setReserve(_reserve);\n    setSortedOracles(_sortedOracles);\n    setBreakerBox(_breakerBox);\n  }\n\n  /* ==================== Modifiers ==================== */\n\n  modifier onlyBroker() {\n    require(msg.sender == broker, \"Caller is not the Broker\");\n    _;\n  }\n\n  modifier verifyExchangeTokens(address tokenIn, address tokenOut, PoolExchange memory exchange) {\n    require(\n      (tokenIn == exchange.asset0 && tokenOut == exchange.asset1) ||\n        (tokenIn == exchange.asset1 && tokenOut == exchange.asset0),\n      \"tokenIn and tokenOut must match exchange\"\n    );\n    _;\n  }\n\n  /* ==================== View Functions ==================== */\n\n  /**\n   * @notice Get a PoolExchange from storage.\n   * @param exchangeId the exchange id\n   */\n  function getPoolExchange(bytes32 exchangeId) public view returns (PoolExchange memory exchange) {\n    exchange = exchanges[exchangeId];\n    require(exchange.asset0 != address(0), \"An exchange with the specified id does not exist\");\n  }\n\n  /**\n   * @notice Get all exchange IDs.\n   * @return exchangeIds List of the exchangeIds.\n   */\n  function getExchangeIds() external view returns (bytes32[] memory) {\n    return exchangeIds;\n  }\n\n  /**\n   * @notice Get all exchanges (used by interfaces)\n   * @dev We don't expect the number of exchanges to grow to\n   * astronomical values so this is safe gas-wise as is.\n   */\n  function getExchanges() public view returns (Exchange[] memory _exchanges) {\n    uint256 numExchanges = exchangeIds.length;\n    _exchanges = new Exchange[](numExchanges);\n    for (uint256 i = 0; i < numExchanges; i++) {\n      _exchanges[i].exchangeId = exchangeIds[i];\n      _exchanges[i].assets = new address[](2);\n      _exchanges[i].assets[0] = exchanges[exchangeIds[i]].asset0;\n      _exchanges[i].assets[1] = exchanges[exchangeIds[i]].asset1;\n    }\n  }\n\n  /**\n   * @notice Calculate amountOut of tokenOut received for a given amountIn of tokenIn\n   * @param exchangeId The id of the exchange i.e PoolExchange to use\n   * @param tokenIn The token to be sold\n   * @param tokenOut The token to be bought\n   * @param amountIn The amount of tokenIn to be sold\n   * @return amountOut The amount of tokenOut to be bought\n   */\n  function getAmountOut(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountIn\n  ) external view returns (uint256 amountOut) {\n    PoolExchange memory exchange = getPoolExchange(exchangeId);\n    uint256 scaledAmountIn = amountIn.mul(tokenPrecisionMultipliers[tokenIn]);\n    (uint256 scaledAmountOut, ) = _getAmountOut(exchange, tokenIn, tokenOut, scaledAmountIn);\n    amountOut = scaledAmountOut.div(tokenPrecisionMultipliers[tokenOut]);\n    return amountOut;\n  }\n\n  /**\n   * @notice Calculate amountIn of tokenIn for a given amountOut of tokenOut\n   * @param exchangeId The id of the exchange i.e PoolExchange to use\n   * @param tokenIn The token to be sold\n   * @param tokenOut The token to be bought\n   * @param amountOut The amount of tokenOut to be bought\n   * @return amountIn The amount of tokenIn to be sold\n   */\n  function getAmountIn(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountOut\n  ) external view returns (uint256 amountIn) {\n    PoolExchange memory exchange = getPoolExchange(exchangeId);\n    uint256 scaledAmountOut = amountOut.mul(tokenPrecisionMultipliers[tokenOut]);\n    (uint256 scaledAmountIn, ) = _getAmountIn(exchange, tokenIn, tokenOut, scaledAmountOut);\n    amountIn = scaledAmountIn.div(tokenPrecisionMultipliers[tokenIn]);\n    return amountIn;\n  }\n\n  /* ==================== Mutative Functions ==================== */\n\n  /**\n   * @notice Sets the address of the broker contract.\n   * @param _broker The new address of the broker contract.\n   */\n  function setBroker(address _broker) public onlyOwner {\n    require(_broker != address(0), \"Broker address must be set\");\n    broker = _broker;\n    emit BrokerUpdated(_broker);\n  }\n\n  /**\n   * @notice Sets the address of the reserve contract.\n   * @param _reserve The new address of the reserve contract.\n   */\n  function setReserve(IReserve _reserve) public onlyOwner {\n    require(address(_reserve) != address(0), \"Reserve address must be set\");\n    reserve = _reserve;\n    emit ReserveUpdated(address(_reserve));\n  }\n\n  /**\n   * @notice Sets the address of the BreakerBox.\n   * @param _breakerBox The new BreakerBox address.\n   */\n  function setBreakerBox(IBreakerBox _breakerBox) public onlyOwner {\n    require(address(_breakerBox) != address(0), \"BreakerBox address must be set\");\n    breakerBox = _breakerBox;\n    emit BreakerBoxUpdated(address(_breakerBox));\n  }\n\n  /**\n   * @notice Sets the address of the sortedOracles contract.\n   * @param _sortedOracles The new address of the sorted oracles contract.\n   */\n  function setSortedOracles(ISortedOracles _sortedOracles) public onlyOwner {\n    require(address(_sortedOracles) != address(0), \"SortedOracles address must be set\");\n    sortedOracles = _sortedOracles;\n    emit SortedOraclesUpdated(address(_sortedOracles));\n  }\n\n  /**\n   * @notice Updates the pricing modules for a list of identifiers\n   * @dev This function can only be called by the owner of the contract.\n   *      The number of identifiers and modules provided must be the same.\n   * @param identifiers An array of identifiers for which the pricing modules are to be set.\n   * @param modules An array of module addresses corresponding to each identifier.\n   */\n  function setPricingModules(bytes32[] calldata identifiers, address[] calldata modules) external onlyOwner {\n    require(identifiers.length == modules.length, \"identifiers and modules must be the same length\");\n    for (uint256 i = 0; i < identifiers.length; i++) {\n      pricingModules[identifiers[i]] = modules[i];\n    }\n    emit PricingModulesUpdated(identifiers, modules);\n  }\n\n  function setSpread(bytes32 exchangeId, uint256 spread) external onlyOwner {\n    require(exchanges[exchangeId].asset0 != address(0), \"invalid exchangeId\");\n\n    FixidityLib.Fraction memory newSpread = FixidityLib.wrap(spread);\n    require(newSpread.lte(FixidityLib.fixed1()), \"spread must be <= 1\");\n\n    exchanges[exchangeId].config.spread = newSpread;\n    emit SpreadUpdated(exchangeId, spread);\n  }\n\n  /**\n   * @notice Creates a new exchange using the given parameters.\n   * @param _exchange the PoolExchange to create.\n   * @return exchangeId The id of the newly created exchange.\n   */\n  function createExchange(PoolExchange calldata _exchange) external onlyOwner returns (bytes32 exchangeId) {\n    PoolExchange memory exchange = _exchange;\n    require(address(exchange.pricingModule) != address(0), \"pricingModule must be set\");\n    require(exchange.asset0 != address(0), \"asset0 must be set\");\n    require(exchange.asset1 != address(0), \"asset1 must be set\");\n    require(exchange.asset0 != exchange.asset1, \"exchange assets can't be identical\");\n    require(\n      pricingModules[pricingModuleIdentifier(exchange)] == address(exchange.pricingModule),\n      \"invalid pricingModule\"\n    );\n\n    // slither-disable-next-line encode-packed-collision\n    exchangeId = keccak256(\n      abi.encodePacked(\n        IERC20(exchange.asset0).symbol(),\n        IERC20(exchange.asset1).symbol(),\n        exchange.pricingModule.name()\n      )\n    );\n    require(exchanges[exchangeId].asset0 == address(0), \"An exchange with the specified assets and exchange exists\");\n\n    validate(exchange);\n    (uint256 bucket0, uint256 bucket1) = getUpdatedBuckets(exchange);\n\n    exchange.bucket0 = bucket0;\n    exchange.bucket1 = bucket1;\n\n    uint256 asset0Decimals = IERC20(exchange.asset0).decimals();\n    uint256 asset1Decimals = IERC20(exchange.asset1).decimals();\n\n    require(asset0Decimals <= 18, \"asset0 decimals must be <= 18\");\n    require(asset1Decimals <= 18, \"asset1 decimals must be <= 18\");\n\n    tokenPrecisionMultipliers[exchange.asset0] = 10 ** (18 - uint256(asset0Decimals));\n    tokenPrecisionMultipliers[exchange.asset1] = 10 ** (18 - uint256(asset1Decimals));\n\n    exchanges[exchangeId] = exchange;\n    // slither-disable-next-line controlled-array-length\n    exchangeIds.push(exchangeId);\n\n    emit ExchangeCreated(exchangeId, exchange.asset0, exchange.asset1, address(exchange.pricingModule));\n  }\n\n  /**\n   * @notice Destroys a exchange with the given parameters if it exists and frees up\n   *         the collateral and stable allocation it was using.\n   * @param exchangeId the id of the exchange to destroy\n   * @param exchangeIdIndex The index of the exchangeId in the ids array\n   * @return destroyed A boolean indicating whether or not the exchange was successfully destroyed.\n   */\n  function destroyExchange(bytes32 exchangeId, uint256 exchangeIdIndex) external onlyOwner returns (bool destroyed) {\n    require(exchangeIdIndex < exchangeIds.length, \"exchangeIdIndex not in range\");\n    require(exchangeIds[exchangeIdIndex] == exchangeId, \"exchangeId at index doesn't match\");\n    PoolExchange memory exchange = exchanges[exchangeId];\n\n    delete exchanges[exchangeId];\n    exchangeIds[exchangeIdIndex] = exchangeIds[exchangeIds.length.sub(1)];\n    exchangeIds.pop();\n    destroyed = true;\n\n    emit ExchangeDestroyed(exchangeId, exchange.asset0, exchange.asset1, address(exchange.pricingModule));\n  }\n\n  /**\n   * @notice Execute a token swap with fixed amountIn\n   * @param exchangeId The id of exchange, i.e. PoolExchange to use\n   * @param tokenIn The token to be sold\n   * @param tokenOut The token to be bought\n   * @param amountIn The amount of tokenIn to be sold\n   * @return amountOut The amount of tokenOut to be bought\n   */\n  function swapIn(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountIn\n  ) external onlyBroker returns (uint256 amountOut) {\n    PoolExchange memory exchange = getPoolExchange(exchangeId);\n    require(\n      breakerBox.getRateFeedTradingMode(exchange.config.referenceRateFeedID) == TRADING_MODE_BIDIRECTIONAL,\n      \"Trading is suspended for this reference rate\"\n    );\n\n    uint256 scaledAmountIn = amountIn.mul(tokenPrecisionMultipliers[tokenIn]);\n    (uint256 scaledAmountOut, bool bucketsUpdated) = _getAmountOut(exchange, tokenIn, tokenOut, scaledAmountIn);\n    executeSwap(exchangeId, exchange, tokenIn, scaledAmountIn, scaledAmountOut, bucketsUpdated);\n\n    amountOut = scaledAmountOut.div(tokenPrecisionMultipliers[tokenOut]);\n    return amountOut;\n  }\n\n  /**\n   * @notice Execute a token swap with fixed amountOut\n   * @param exchangeId The id of exchange, i.e. PoolExchange to use\n   * @param tokenIn The token to be sold\n   * @param tokenOut The token to be bought\n   * @param amountOut The amount of tokenOut to be bought\n   * @return amountIn The amount of tokenIn to be sold\n   */\n  function swapOut(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountOut\n  ) external onlyBroker returns (uint256 amountIn) {\n    PoolExchange memory exchange = getPoolExchange(exchangeId);\n    require(\n      breakerBox.getRateFeedTradingMode(exchange.config.referenceRateFeedID) == TRADING_MODE_BIDIRECTIONAL,\n      \"Trading is suspended for this reference rate\"\n    );\n\n    uint256 scaledAmountOut = amountOut.mul(tokenPrecisionMultipliers[tokenOut]);\n    (uint256 scaledAmountIn, bool bucketsUpdated) = _getAmountIn(exchange, tokenIn, tokenOut, scaledAmountOut);\n    executeSwap(exchangeId, exchange, tokenIn, scaledAmountIn, scaledAmountOut, bucketsUpdated);\n\n    amountIn = scaledAmountIn.div(tokenPrecisionMultipliers[tokenIn]);\n    return amountIn;\n  }\n\n  /* ==================== Private Functions ==================== */\n\n  /**\n   * @notice Execute a swap against the in memory exchange and write\n   *         the new bucket sizes to storage.\n   * @dev In constant sum exchanges, the virtual bucket ratio serve as the reference price\n   *      and should remain constant between bucket updates.\n   *      Thats why the amounts of a swap are only applied for constant product exchanges.\n   * @param exchangeId The id of the exchange\n   * @param exchange The exchange to operate on\n   * @param tokenIn The token to be sold\n   * @param scaledAmountIn The amount of tokenIn to be sold scaled to 18 decimals\n   * @param scaledAmountOut The amount of tokenOut to be bought scaled to 18 decimals\n   * @param bucketsUpdated whether the buckets updated during the swap\n   */\n  function executeSwap(\n    bytes32 exchangeId,\n    PoolExchange memory exchange,\n    address tokenIn,\n    uint256 scaledAmountIn,\n    uint256 scaledAmountOut,\n    bool bucketsUpdated\n  ) internal {\n    if (bucketsUpdated) {\n      // solhint-disable-next-line not-rely-on-time\n      exchanges[exchangeId].lastBucketUpdate = now;\n      emit BucketsUpdated(exchangeId, exchange.bucket0, exchange.bucket1);\n    }\n\n    if (isConstantProduct(exchange)) {\n      if (tokenIn == exchange.asset0) {\n        exchange.bucket0 = exchange.bucket0.add(scaledAmountIn);\n        exchange.bucket1 = exchange.bucket1.sub(scaledAmountOut);\n      } else {\n        exchange.bucket0 = exchange.bucket0.sub(scaledAmountOut);\n        exchange.bucket1 = exchange.bucket1.add(scaledAmountIn);\n      }\n    }\n\n    exchanges[exchangeId].bucket0 = exchange.bucket0;\n    exchanges[exchangeId].bucket1 = exchange.bucket1;\n  }\n\n  /**\n   * @notice Calculate amountOut of tokenOut received for a given amountIn of tokenIn\n   * @param exchange The exchange to operate on\n   * @param tokenIn The token to be sold\n   * @param tokenOut The token to be bought\n   * @param scaledAmountIn The amount of tokenIn to be sold scaled to 18 decimals\n   * @return scaledAmountOut The amount of tokenOut to be bought scaled to 18 decimals\n   * @return bucketsUpdated Wether the buckets were updated during the quote\n   */\n  function _getAmountOut(\n    PoolExchange memory exchange,\n    address tokenIn,\n    address tokenOut,\n    uint256 scaledAmountIn\n  )\n    internal\n    view\n    verifyExchangeTokens(tokenIn, tokenOut, exchange)\n    returns (uint256 scaledAmountOut, bool bucketsUpdated)\n  {\n    (exchange, bucketsUpdated) = updateBucketsIfNecessary(exchange);\n\n    if (tokenIn == exchange.asset0) {\n      scaledAmountOut = exchange.pricingModule.getAmountOut(\n        exchange.bucket0,\n        exchange.bucket1,\n        exchange.config.spread.unwrap(),\n        scaledAmountIn\n      );\n    } else {\n      scaledAmountOut = exchange.pricingModule.getAmountOut(\n        exchange.bucket1,\n        exchange.bucket0,\n        exchange.config.spread.unwrap(),\n        scaledAmountIn\n      );\n    }\n  }\n\n  /**\n   * @notice Calculate amountIn of tokenIn for a given amountOut of tokenOut\n   * @param exchange The exchange to operate on\n   * @param tokenIn The token to be sold\n   * @param tokenOut The token to be bought\n   * @param scaledAmountOut The amount of tokenOut to be bought scaled to 18 decimals\n   * @return scaledAmountIn The amount of tokenIn to be sold scaled to 18 decimals\n   * @return bucketsUpdated Whether the buckets were updated during the quote\n   */\n  function _getAmountIn(\n    PoolExchange memory exchange,\n    address tokenIn,\n    address tokenOut,\n    uint256 scaledAmountOut\n  )\n    internal\n    view\n    verifyExchangeTokens(tokenIn, tokenOut, exchange)\n    returns (uint256 scaledAmountIn, bool bucketsUpdated)\n  {\n    (exchange, bucketsUpdated) = updateBucketsIfNecessary(exchange);\n\n    if (tokenIn == exchange.asset0) {\n      scaledAmountIn = exchange.pricingModule.getAmountIn(\n        exchange.bucket0,\n        exchange.bucket1,\n        exchange.config.spread.unwrap(),\n        scaledAmountOut\n      );\n    } else {\n      scaledAmountIn = exchange.pricingModule.getAmountIn(\n        exchange.bucket1,\n        exchange.bucket0,\n        exchange.config.spread.unwrap(),\n        scaledAmountOut\n      );\n    }\n  }\n\n  /**\n   * @notice If conditions are met, update the exchange bucket sizes.\n   * @dev This doesn't checkpoint the exchange, just updates the in-memory one\n   * so it should be used in a context that then checkpoints the exchange.\n   * @param exchange The exchange being updated.\n   * @return exchangeAfter The updated exchange.\n   */\n  function updateBucketsIfNecessary(\n    PoolExchange memory exchange\n  ) internal view returns (PoolExchange memory, bool updated) {\n    if (shouldUpdateBuckets(exchange)) {\n      (exchange.bucket0, exchange.bucket1) = getUpdatedBuckets(exchange);\n      updated = true;\n    }\n    return (exchange, updated);\n  }\n\n  /**\n   * @notice Determine if a exchange's buckets should be updated\n   * based on staleness of buckets and oracle rates.\n   * @param exchange The PoolExchange.\n   * @return shouldUpdate\n   */\n  function shouldUpdateBuckets(PoolExchange memory exchange) internal view returns (bool) {\n    bool hasValidMedian = oracleHasValidMedian(exchange);\n    if (isConstantSum(exchange)) {\n      require(hasValidMedian, \"no valid median\");\n    }\n    // solhint-disable-next-line not-rely-on-time\n    bool timePassed = now >= exchange.lastBucketUpdate.add(exchange.config.referenceRateResetFrequency);\n    return timePassed && hasValidMedian;\n  }\n\n  /**\n   * @notice Determine if the median is valid based on the current oracle rates.\n   * @param exchange The PoolExchange.\n   * @return HasValidMedian.\n   */\n  function oracleHasValidMedian(PoolExchange memory exchange) internal view returns (bool) {\n    // solhint-disable-next-line not-rely-on-time\n    // slither-disable-next-line unused-return\n    (bool isReportExpired, ) = sortedOracles.isOldestReportExpired(exchange.config.referenceRateFeedID);\n    bool enoughReports = (sortedOracles.numRates(exchange.config.referenceRateFeedID) >=\n      exchange.config.minimumReports);\n    // solhint-disable-next-line not-rely-on-time\n    bool medianReportRecent = sortedOracles.medianTimestamp(exchange.config.referenceRateFeedID) >\n      now.sub(exchange.config.referenceRateResetFrequency);\n    return !isReportExpired && enoughReports && medianReportRecent;\n  }\n\n  /**\n   * @notice Calculate the new bucket sizes for a exchange.\n   * @param exchange The PoolExchange in context.\n   * @return bucket0 The size of bucket0.\n   * @return bucket1 The size of bucket1.\n   */\n  function getUpdatedBuckets(PoolExchange memory exchange) internal view returns (uint256 bucket0, uint256 bucket1) {\n    bucket0 = exchange.config.stablePoolResetSize;\n    uint256 exchangeRateNumerator;\n    uint256 exchangeRateDenominator;\n    (exchangeRateNumerator, exchangeRateDenominator) = getOracleExchangeRate(exchange.config.referenceRateFeedID);\n\n    bucket1 = exchangeRateDenominator.mul(bucket0).div(exchangeRateNumerator);\n  }\n\n  /**\n   * @notice Get the exchange rate as numerator,denominator from sorted oracles\n   * and protect in case of a 0-denominator.\n   * @param target the reportTarget to read from SortedOracles\n   * @return rateNumerator\n   * @return rateDenominator\n   */\n  function getOracleExchangeRate(\n    address target\n  ) internal view returns (uint256 rateNumerator, uint256 rateDenominator) {\n    (rateNumerator, rateDenominator) = sortedOracles.medianRate(target);\n    require(rateDenominator > 0, \"exchange rate denominator must be greater than 0\");\n  }\n\n  /**\n   * @notice Valitates a PoolExchange's parameters and configuration\n   * @dev Reverts if not valid\n   * @param exchange The PoolExchange to validate\n   */\n  function validate(PoolExchange memory exchange) private view {\n    require(reserve.isStableAsset(exchange.asset0), \"asset0 must be a stable registered with the reserve\");\n    require(\n      reserve.isStableAsset(exchange.asset1) || reserve.isCollateralAsset(exchange.asset1),\n      \"asset1 must be a stable or collateral\"\n    );\n    require(FixidityLib.lte(exchange.config.spread, FixidityLib.fixed1()), \"spread must be less than or equal to 1\");\n    require(exchange.config.referenceRateFeedID != address(0), \"referenceRateFeedID must be set\");\n  }\n\n  /**\n   * @notice Get the identifier of the pricing module used by a exchange\n   * @param exchange The exchange to get the pricing module identifier for\n   * @return The encoded and hashed identifier of the pricing module\n   */\n  function pricingModuleIdentifier(PoolExchange memory exchange) internal view returns (bytes32) {\n    return keccak256(abi.encodePacked(exchange.pricingModule.name()));\n  }\n\n  /**\n   * @notice Determine whether an exchange is using a constant sum pricing module\n   * @param exchange The exchange to check\n   * @return bool indicating if the exchange is using a constant sum pricing module\n   */\n  function isConstantSum(PoolExchange memory exchange) internal view returns (bool) {\n    return pricingModuleIdentifier(exchange) == CONSTANT_SUM;\n  }\n\n  /**\n   * @notice Determine whether an exchange is using a constant product pricing module\n   * @param exchange The exchange to check\n   * @return bool indicating if the exchange is using a constant product pricing module\n   */\n  function isConstantProduct(PoolExchange memory exchange) internal view returns (bool) {\n    return pricingModuleIdentifier(exchange) == CONSTANT_PRODUCT;\n  }\n}\n","deployed_bytecode":"0x608060405234801561001057600080fd5b50600436106101e55760003560e01c8063abff01101161010f578063d482dda6116100a2578063f2fde38b11610071578063f2fde38b146103eb578063f414c5e4146103fe578063f670dde114610406578063f8c8765e14610419576101e5565b8063d482dda61461038a578063dc162e36146103b0578063e46eb5b6146103c5578063eaaba701146103d8576101e5565b8063c5df620a116100de578063c5df620a14610354578063cd3293de14610367578063cd8513ba1461036f578063d3385d0514610377576101e5565b8063abff01101461031e578063b089869114610326578063bf0d021314610339578063c0ad52d51461034c576101e5565b806345015421116101875780638da5cb5b116101565780638da5cb5b146102db5780638f32d59b146102f057806393c7e3bc146102f85780639cecc80a1461030b576101e5565b8063450154211461029a57806345b2b467146102ad5780634afb215e146102c0578063715018a6146102d3576101e5565b80631e2e3a6b116101c35780631e2e3a6b14610232578063278488a41461024757806338b1e9f71461026757806342bfc99c14610287576101e5565b8063040bbd35146101ea578063132e8aa7146101ff578063158ef93e1461021d575b600080fd5b6101fd6101f8366004612fae565b61042c565b005b6102076104ed565b6040516102149190613f00565b60405180910390f35b6102256104fc565b6040516102149190613ee4565b61023a610505565b6040516102149190613ed3565b61025a610255366004612f0b565b6106ce565b604051610214919061411f565b61027a610275366004612f0b565b6107b1565b6040516102149190613ef2565b61027a610295366004612f29565b6107cf565b6101fd6102a8366004612e43565b610957565b61027a6102bb366004612dc4565b610a71565b6101fd6102ce366004612fae565b610a83565b6101fd610b2f565b6102e3610bb9565b6040516102149190613e26565b610225610bcd565b61027a610306366004612f29565b610bf6565b6101fd610319366004612fae565b610c81565b6102e3610d2d565b61027a610334366004613001565b610d3c565b6101fd610347366004612dc4565b6113d2565b61027a61147e565b6101fd610362366004612f7e565b6114a6565b61020761159a565b61027a6115a9565b61027a610385366004612f29565b6115b8565b61039d610398366004612f0b565b611733565b6040516102149796959493929190613e34565b6103b86117bf565b6040516102149190613ec2565b6102256103d3366004612f7e565b611817565b6102e36103e6366004612f0b565b611b77565b6101fd6103f9366004612dc4565b611b92565b610207611bc2565b61027a610414366004612f29565b611bd1565b6101fd610427366004612de2565b611c50565b610434610bcd565b6104595760405162461bcd60e51b81526004016104509061404f565b60405180910390fd5b6001600160a01b03811661047f5760405162461bcd60e51b8152600401610450906140df565b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f21921b3b46ef2c939e85d6a14410c6e3b9ce132b66e944357ff4f789f68e00e2906104e2908390613e26565b60405180910390a150565b6006546001600160a01b031681565b60005460ff1681565b6003546040805182815260208084028201019091526060919081801561054557816020015b610532612a99565b81526020019060019003908161052a5790505b50915060005b818110156106c9576003818154811061056057fe5b906000526020600020015483828151811061057757fe5b6020908102919091010151526040805160028082526060820190925290816020016020820280388339019050508382815181106105b057fe5b60200260200101516020018190525060026000600383815481106105d057fe5b9060005260206000200154815260200190815260200160002060000160009054906101000a90046001600160a01b031683828151811061060c57fe5b60200260200101516020015160008151811061062457fe5b60200260200101906001600160a01b031690816001600160a01b031681525050600260006003838154811061065557fe5b9060005260206000200154815260200190815260200160002060010160009054906101000a90046001600160a01b031683828151811061069157fe5b6020026020010151602001516001815181106106a957fe5b6001600160a01b039092166020928302919091019091015260010161054b565b505090565b6106d6612ab1565b50600081815260026020818152604092839020835160e08101855281546001600160a01b03908116825260018301548116828501529382015484168186015260038201546060808301919091526004830154608080840191909152600584015460a080850191909152875160c08181018a5260068701549282019283529181526007860154881696810196909652600885015497860197909752600984015491850191909152600a9092015491830191909152928301528151166107ac5760405162461bcd60e51b8152600401610450906140af565b919050565b600381815481106107be57fe5b600091825260209091200154905081565b6001546000906001600160a01b031633146107fc5760405162461bcd60e51b815260040161045090613fcf565b610804612ab1565b61080d866106ce565b60055460c0820151602001516040517fc0b05da00000000000000000000000000000000000000000000000000000000081529293506000926001600160a01b039092169163c0b05da09161086391600401613e26565b60206040518083038186803b15801561087b57600080fd5b505afa15801561088f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b3919081019061308d565b60ff16146108d35760405162461bcd60e51b815260040161045090613f1f565b6001600160a01b0385166000908152600760205260408120546108fd90859063ffffffff611cd116565b905060008061090e84898986611d14565b9150915061092089858a868686611f1c565b6001600160a01b03871660009081526007602052604090205461094a90839063ffffffff61203d16565b9998505050505050505050565b61095f610bcd565b61097b5760405162461bcd60e51b81526004016104509061404f565b82811461099a5760405162461bcd60e51b81526004016104509061410f565b60005b83811015610a2d578282828181106109b157fe5b90506020020160206109c69190810190612dc4565b600860008787858181106109d657fe5b6020908102929092013583525081019190915260400160002080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039290921691909117905560010161099d565b507f84557d458d60fcb29d9a10a8f28861c76847f7ef6450a9266a228a6f3a590baa84848484604051610a639493929190613e91565b60405180910390a150505050565b60076020526000908152604090205481565b610a8b610bcd565b610aa75760405162461bcd60e51b81526004016104509061404f565b6001600160a01b038116610acd5760405162461bcd60e51b8152600401610450906140bf565b600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f590fd633a008765ce9e65e8081adfba311e99e11b958a5ecb5000ea3355f735390600090a250565b610b37610bcd565b610b535760405162461bcd60e51b81526004016104509061404f565b600080546040516101009091046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffff0000000000000000000000000000000000000000ff169055565b60005461010090046001600160a01b031690565b6000805461010090046001600160a01b0316610be761207f565b6001600160a01b031614905090565b6000610c00612ab1565b610c09866106ce565b6001600160a01b03861660009081526007602052604081205491925090610c3790859063ffffffff611cd116565b90506000610c4783888885611d14565b506001600160a01b038716600090815260076020526040902054909150610c7590829063ffffffff61203d16565b98975050505050505050565b610c89610bcd565b610ca55760405162461bcd60e51b81526004016104509061404f565b6001600160a01b038116610ccb5760405162461bcd60e51b8152600401610450906140cf565b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f0b248ab246a87e452fbedee8dc12dfc53e3f3bfdc6920999062c56dea4ab522a90600090a250565b6001546001600160a01b031681565b6000610d46610bcd565b610d625760405162461bcd60e51b81526004016104509061404f565b610d6a612ab1565b610d7936849003840184613020565b60408101519091506001600160a01b0316610da65760405162461bcd60e51b81526004016104509061400f565b80516001600160a01b0316610dcd5760405162461bcd60e51b815260040161045090613f6f565b60208101516001600160a01b0316610df75760405162461bcd60e51b81526004016104509061407f565b80602001516001600160a01b031681600001516001600160a01b03161415610e315760405162461bcd60e51b81526004016104509061405f565b80604001516001600160a01b031660086000610e4c84612083565b81526020810191909152604001600020546001600160a01b031614610e835760405162461bcd60e51b81526004016104509061403f565b80600001516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610ec057600080fd5b505afa158015610ed4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610efc9190810190612fcc565b81602001516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f759190810190612fcc565b82604001516001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015610fb257600080fd5b505afa158015610fc6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fee9190810190612fcc565b60405160200161100093929190613dec565b60408051601f198184030181529181528151602092830120600081815260029093529120549092506001600160a01b03161561104e5760405162461bcd60e51b815260040161045090613f9f565b6110578161212b565b6000806110638361239b565b915091508183606001818152505080836080018181525050600083600001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156110ba57600080fd5b505afa1580156110ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110f2919081019061308d565b60ff169050600084602001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561113657600080fd5b505afa15801561114a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061116e919081019061308d565b60ff16905060128211156111945760405162461bcd60e51b815260040161045090613faf565b60128111156111b55760405162461bcd60e51b815260040161045090613fef565b81601203600a0a6007600087600001516001600160a01b03166001600160a01b031681526020019081526020016000208190555080601203600a0a6007600087602001516001600160a01b03166001600160a01b0316815260200190815260200160002081905550846002600088815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a0820151816005015560c08201518160060160008201518160000160008201518160000155505060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506040820151816002015560608201518160030155608082015181600401555050905050600386908060018154018082558091505090600182039060005260206000200160009091929091909150555084602001516001600160a01b031685600001516001600160a01b0316877fb374789237d43aed0f75b4c50a45793fd70e354bb96eecd573f35f5d509d78a188604001516040516113c09190613e26565b60405180910390a45050505050919050565b6113da610bcd565b6113f65760405162461bcd60e51b81526004016104509061404f565b6001600160a01b03811661141c5760405162461bcd60e51b8152600401610450906140ff565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f865dab7821134b6eb27cba259b40e33bbc1b898e970a535a18a83147f380a51f90600090a250565b60405160200161148d90613e1b565b6040516020818303038152906040528051906020012081565b6114ae610bcd565b6114ca5760405162461bcd60e51b81526004016104509061404f565b6000828152600260205260409020546001600160a01b03166114fe5760405162461bcd60e51b81526004016104509061402f565b611506612b0e565b61150f826123eb565b905061152961151c612405565b829063ffffffff61242916565b6115455760405162461bcd60e51b81526004016104509061406f565b6000838152600260205260409081902082516006909101555183907fd543777ec8c7717f747583b4011aee3b898ca0b5bc6c32144b7d4887eb62c74e9061158d908590613ef2565b60405180910390a2505050565b6004546001600160a01b031681565b60405160200161148d90613e10565b6001546000906001600160a01b031633146115e55760405162461bcd60e51b815260040161045090613fcf565b6115ed612ab1565b6115f6866106ce565b60055460c0820151602001516040517fc0b05da00000000000000000000000000000000000000000000000000000000081529293506000926001600160a01b039092169163c0b05da09161164c91600401613e26565b60206040518083038186803b15801561166457600080fd5b505afa158015611678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061169c919081019061308d565b60ff16146116bc5760405162461bcd60e51b815260040161045090613f1f565b6001600160a01b0384166000908152600760205260408120546116e690859063ffffffff611cd116565b90506000806116f784898986612431565b9150915061170989858a858786611f1c565b6001600160a01b03881660009081526007602052604090205461094a90839063ffffffff61203d16565b6002602081815260009283526040928390208054600182015493820154600383015460048401546005850154885160c081018a52600687015460a08201908152815260078701546001600160a01b0390811698820198909852600887015499810199909952600986015460608a0152600a90950154608089015292851696958516959190941693929087565b6060600380548060200260200160405190810160405280929190818152602001828054801561180d57602002820191906000526020600020905b8154815260200190600101908083116117f9575b5050505050905090565b6000611821610bcd565b61183d5760405162461bcd60e51b81526004016104509061404f565b600354821061185e5760405162461bcd60e51b815260040161045090613f7f565b826003838154811061186c57fe5b9060005260206000200154146118945760405162461bcd60e51b81526004016104509061408f565b61189c612ab1565b600260008581526020019081526020016000206040518060e00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016002820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600382015481526020016004820154815260200160058201548152602001600682016040518060a00160405290816000820160405180602001604052908160008201548152505081526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600282015481526020016003820154815260200160048201548152505081525050905060026000858152602001908152602001600020600080820160006101000a8154906001600160a01b0302191690556001820160006101000a8154906001600160a01b0302191690556002820160006101000a8154906001600160a01b03021916905560038201600090556004820160009055600582016000905560068201600080820160008082016000905550506001820160006101000a8154906001600160a01b030219169055600282016000905560038201600090556004820160009055505050506003611ac5600160038054905061254390919063ffffffff16565b81548110611acf57fe5b906000526020600020015460038481548110611ae757fe5b6000918252602090912001556003805480611afe57fe5b600190038181906000526020600020016000905590556001915080602001516001600160a01b031681600001516001600160a01b0316857fadbbec6c203cb0248e89fe6d15ad651061a9d5203a1ab0273256e2b7decffa898460400151604051611b689190613e26565b60405180910390a45092915050565b6008602052600090815260409020546001600160a01b031681565b611b9a610bcd565b611bb65760405162461bcd60e51b81526004016104509061404f565b611bbf81612585565b50565b6005546001600160a01b031681565b6000611bdb612ab1565b611be4866106ce565b6001600160a01b03851660009081526007602052604081205491925090611c1290859063ffffffff611cd116565b90506000611c2283888885612431565b506001600160a01b038816600090815260076020526040902054909150610c7590829063ffffffff61203d16565b60005460ff1615611c735760405162461bcd60e51b815260040161045090613f3f565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611ca733612585565b611cb0846113d2565b611cb983610c81565b611cc282610a83565b611ccb8161042c565b50505050565b600082611ce057506000611d0e565b82820282848281611ced57fe5b0414611d0b5760405162461bcd60e51b81526004016104509061401f565b90505b92915050565b60008084848780600001516001600160a01b0316836001600160a01b0316148015611d54575080602001516001600160a01b0316826001600160a01b0316145b80611d8b575080602001516001600160a01b0316836001600160a01b0316148015611d8b575080516001600160a01b038381169116145b611da75760405162461bcd60e51b8152600401610450906140ef565b611db089612628565b8151919a5094506001600160a01b0389811691161415611e6f5788604001516001600160a01b03166352707d8c8a606001518b60800151611df88d60c0015160000151612660565b8a6040518563ffffffff1660e01b8152600401611e189493929190614149565b60206040518083038186803b158015611e3057600080fd5b505afa158015611e44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e68919081019061303f565b9450611f10565b88604001516001600160a01b03166352707d8c8a608001518b60600151611e9d8d60c0015160000151612660565b8a6040518563ffffffff1660e01b8152600401611ebd9493929190614149565b60206040518083038186803b158015611ed557600080fd5b505afa158015611ee9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611f0d919081019061303f565b94505b50505094509492505050565b8015611f8057426002600088815260200190815260200160002060050181905550857f949f5db193cbfa01f2d443b1c656bfede15497de0d86838cea089bd60c43834286606001518760800151604051611f7792919061412e565b60405180910390a25b611f8985612664565b156120115784516001600160a01b0385811691161415611fdc576060850151611fb8908463ffffffff61269b16565b60608601526080850151611fd2908363ffffffff61254316565b6080860152612011565b6060850151611ff1908363ffffffff61254316565b6060860152608085015161200b908463ffffffff61269b16565b60808601525b505050606082015160009384526002602052604090932060038101939093555060800151600490910155565b6000611d0b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506126c0565b3390565b600081604001516001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b1580156120c257600080fd5b505afa1580156120d6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120fe9190810190612fcc565b60405160200161210e9190613de0565b604051602081830303815290604052805190602001209050919050565b6004805482516040517f4f8e6e230000000000000000000000000000000000000000000000000000000081526001600160a01b0390921692634f8e6e2392612174929101613e26565b60206040518083038186803b15801561218c57600080fd5b505afa1580156121a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506121c49190810190612eb3565b6121e05760405162461bcd60e51b815260040161045090613f2f565b6004805460208301516040517f4f8e6e230000000000000000000000000000000000000000000000000000000081526001600160a01b0390921692634f8e6e239261222c929101613e26565b60206040518083038186803b15801561224457600080fd5b505afa158015612258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061227c9190810190612eb3565b8061231e57506004805460208301516040517fcae182fe0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169263cae182fe926122ce929101613e26565b60206040518083038186803b1580156122e657600080fd5b505afa1580156122fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061231e9190810190612eb3565b61233a5760405162461bcd60e51b815260040161045090613fbf565b60c0810151516123519061234c612405565b612429565b61236d5760405162461bcd60e51b815260040161045090613fff565b60c0810151602001516001600160a01b0316611bbf5760405162461bcd60e51b81526004016104509061409f565b6000808260c001516080015191506000806123bd8560c00151602001516126f9565b90925090506123e2826123d6838763ffffffff611cd116565b9063ffffffff61203d16565b92505050915091565b6123f3612b0e565b50604080516020810190915290815290565b61240d612b0e565b50604080516020810190915269d3c21bcecceda1000000815290565b519051111590565b60008084848780600001516001600160a01b0316836001600160a01b0316148015612471575080602001516001600160a01b0316826001600160a01b0316145b806124a8575080602001516001600160a01b0316836001600160a01b03161480156124a8575080516001600160a01b038381169116145b6124c45760405162461bcd60e51b8152600401610450906140ef565b6124cd89612628565b8151919a5094506001600160a01b03898116911614156125155788604001516001600160a01b031663571fd0128a606001518b60800151611df88d60c0015160000151612660565b88604001516001600160a01b031663571fd0128a608001518b60600151611e9d8d60c0015160000151612660565b6000611d0b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506127b8565b6001600160a01b0381166125ab5760405162461bcd60e51b815260040161045090613f4f565b600080546040516001600160a01b038085169361010090930416917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b612630612ab1565b600061263b836127e4565b15612657576126498361239b565b608085015260608401525060015b8291505b915091565b5190565b600060405160200161267590613e10565b6040516020818303038152906040528051906020012061269483612083565b1492915050565b600082820183811015611d0b5760405162461bcd60e51b815260040161045090613f8f565b600081836126e15760405162461bcd60e51b81526004016104509190613f0e565b5060008385816126ed57fe5b049150505b9392505050565b6006546040517fef90e1b000000000000000000000000000000000000000000000000000000000815260009182916001600160a01b039091169063ef90e1b090612747908690600401613e26565b604080518083038186803b15801561275e57600080fd5b505afa158015612772573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612796919081019061305d565b90925090508061265b5760405162461bcd60e51b815260040161045090613fdf565b600081848411156127dc5760405162461bcd60e51b81526004016104509190613f0e565b505050900390565b6000806127f083612855565b90506127fb83612a88565b1561281d578061281d5760405162461bcd60e51b815260040161045090613f5f565b600061283e8460c00151604001518560a0015161269b90919063ffffffff16565b421015905080801561284d5750815b949350505050565b60065460c0820151602001516040517fffe736bf00000000000000000000000000000000000000000000000000000000815260009283926001600160a01b039091169163ffe736bf916128aa91600401613e26565b604080518083038186803b1580156128c157600080fd5b505afa1580156128d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128f99190810190612ed1565b5060c084015160608101516006546020909201516040517fbbc66a9400000000000000000000000000000000000000000000000000000000815293945060009391926001600160a01b03169163bbc66a949161295791600401613e26565b60206040518083038186803b15801561296f57600080fd5b505afa158015612983573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129a7919081019061303f565b1015905060006129c88560c00151604001514261254390919063ffffffff16565b60065460c0870151602001516040517f071b48fc0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163071b48fc91612a1891600401613e26565b60206040518083038186803b158015612a3057600080fd5b505afa158015612a44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a68919081019061303f565b11905082158015612a765750815b8015612a7f5750805b95945050505050565b600060405160200161267590613e1b565b60408051808201909152600081526060602082015290565b6040518060e0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001612b09612b21565b905290565b6040518060200160405280600081525090565b6040518060a00160405280612b34612b0e565b815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b8035611d0e8161425d565b8051611d0e8161425d565b60008083601f840112612b8757600080fd5b50813567ffffffffffffffff811115612b9f57600080fd5b602083019150836020820283011115612bb757600080fd5b9250929050565b8051611d0e81614271565b8035611d0e8161427a565b8035611d0e81614283565b600082601f830112612bf057600080fd5b8151612c03612bfe826141a5565b61417e565b91508082526020830160208301858383011115612c1f57600080fd5b612c2a838284614227565b50505092915050565b600060208284031215612c4557600080fd5b612c4f602061417e565b90506000612c5d8484612bc9565b82525092915050565b600060a08284031215612c7857600080fd5b612c8260a061417e565b90506000612c908484612c33565b8252506020612ca184848301612b5f565b6020830152506040612cb584828501612bc9565b6040830152506060612cc984828501612bc9565b6060830152506080612cdd84828501612bc9565b60808301525092915050565b60006101608284031215612cfc57600080fd5b50919050565b60006101608284031215612d1557600080fd5b612d1f60e061417e565b90506000612d2d8484612b5f565b8252506020612d3e84848301612b5f565b6020830152506040612d5284828501612bd4565b6040830152506060612d6684828501612bc9565b6060830152506080612d7a84828501612bc9565b60808301525060a0612d8e84828501612bc9565b60a08301525060c0612da284828501612c66565b60c08301525092915050565b8051611d0e8161427a565b8051611d0e8161428c565b600060208284031215612dd657600080fd5b600061284d8484612b5f565b60008060008060808587031215612df857600080fd5b6000612e048787612b5f565b9450506020612e1587828801612bd4565b9350506040612e2687828801612bd4565b9250506060612e3787828801612bd4565b91505092959194509250565b60008060008060408587031215612e5957600080fd5b843567ffffffffffffffff811115612e7057600080fd5b612e7c87828801612b75565b9450945050602085013567ffffffffffffffff811115612e9b57600080fd5b612ea787828801612b75565b95989497509550505050565b600060208284031215612ec557600080fd5b600061284d8484612bbe565b60008060408385031215612ee457600080fd5b6000612ef08585612bbe565b9250506020612f0185828601612b6a565b9150509250929050565b600060208284031215612f1d57600080fd5b600061284d8484612bc9565b60008060008060808587031215612f3f57600080fd5b6000612f4b8787612bc9565b9450506020612f5c87828801612b5f565b9350506040612f6d87828801612b5f565b9250506060612e3787828801612bc9565b60008060408385031215612f9157600080fd5b6000612f9d8585612bc9565b9250506020612f0185828601612bc9565b600060208284031215612fc057600080fd5b600061284d8484612bd4565b600060208284031215612fde57600080fd5b815167ffffffffffffffff811115612ff557600080fd5b61284d84828501612bdf565b6000610160828403121561301457600080fd5b600061284d8484612ce9565b6000610160828403121561303357600080fd5b600061284d8484612d02565b60006020828403121561305157600080fd5b600061284d8484612dae565b6000806040838503121561307057600080fd5b600061307c8585612dae565b9250506020612f0185828601612dae565b60006020828403121561309f57600080fd5b600061284d8484612db9565b60006130b783836130d7565b505060200190565b60006130b783836132a3565b6000611d0b8383613cc2565b6130e0816141ee565b82525050565b60006130f283856141d6565b93506130fd826141cd565b8060005b858110156131335761311382846141df565b61311d88826130ab565b9750613128836141d0565b925050600101613101565b509495945050505050565b600061314982612660565b61315381856141d6565b935061315e836141d0565b8060005b8381101561313357815161317688826130ab565b9750613181836141d0565b925050600101613162565b600061319883856141d6565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156131c757600080fd5b6020830292506131d883858461421b565b50500190565b60006131e982612660565b6131f381856141d6565b93506131fe836141d0565b8060005b8381101561313357815161321688826130bf565b9750613221836141d0565b925050600101613202565b600061323782612660565b61324181856141d6565b935083602082028501613253856141d0565b8060005b8581101561328d578484038952815161327085826130cb565b945061327b836141d0565b60209a909a0199925050600101613257565b5091979650505050505050565b6130e0816141f9565b6130e0816141cd565b6130e0816141fe565b60006132c082612660565b6132ca81856141d6565b93506132da818560208601614227565b6132e381614253565b9093019392505050565b60006132f882612660565b61330281856107ac565b9350613312818560208601614227565b9290920192915050565b6000613329602c836141d6565b7f54726164696e672069732073757370656e64656420666f72207468697320726581527f666572656e636520726174650000000000000000000000000000000000000000602082015260400192915050565b60006133886033836141d6565b7f617373657430206d757374206265206120737461626c6520726567697374657281527f6564207769746820746865207265736572766500000000000000000000000000602082015260400192915050565b60006133e7601c836141d6565b7f636f6e747261637420616c726561647920696e697469616c697a656400000000815260200192915050565b60006134206026836141d6565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181527f6464726573730000000000000000000000000000000000000000000000000000602082015260400192915050565b600061347f600f836141d6565b7f6e6f2076616c6964206d656469616e0000000000000000000000000000000000815260200192915050565b60006134b86012836141d6565b7f617373657430206d757374206265207365740000000000000000000000000000815260200192915050565b60006134f1601c836141d6565b7f65786368616e67654964496e646578206e6f7420696e2072616e676500000000815260200192915050565b600061352a601b836141d6565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613563600f836107ac565b7f436f6e7374616e7450726f6475637400000000000000000000000000000000008152600f0192915050565b600061359c6039836141d6565b7f416e2065786368616e676520776974682074686520737065636966696564206181527f737365747320616e642065786368616e67652065786973747300000000000000602082015260400192915050565b60006135fb601d836141d6565b7f61737365743020646563696d616c73206d757374206265203c3d203138000000815260200192915050565b60006136346025836141d6565b7f617373657431206d757374206265206120737461626c65206f7220636f6c6c6181527f746572616c000000000000000000000000000000000000000000000000000000602082015260400192915050565b60006136936018836141d6565b7f43616c6c6572206973206e6f74207468652042726f6b65720000000000000000815260200192915050565b60006136cc6030836141d6565b7f65786368616e676520726174652064656e6f6d696e61746f72206d757374206281527f652067726561746572207468616e203000000000000000000000000000000000602082015260400192915050565b600061372b601d836141d6565b7f61737365743120646563696d616c73206d757374206265203c3d203138000000815260200192915050565b60006137646026836141d6565b7f737072656164206d757374206265206c657373207468616e206f72206571756181527f6c20746f20310000000000000000000000000000000000000000000000000000602082015260400192915050565b60006137c36019836141d6565b7f70726963696e674d6f64756c65206d7573742062652073657400000000000000815260200192915050565b60006137fc6021836141d6565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f81527f7700000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b600061385b6012836141d6565b7f696e76616c69642065786368616e676549640000000000000000000000000000815260200192915050565b60006138946015836141d6565b7f696e76616c69642070726963696e674d6f64756c650000000000000000000000815260200192915050565b60006138cd6020836141d6565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572815260200192915050565b60006139066022836141d6565b7f65786368616e6765206173736574732063616e2774206265206964656e74696381527f616c000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b60006139656013836141d6565b7f737072656164206d757374206265203c3d203100000000000000000000000000815260200192915050565b600061399e6012836141d6565b7f617373657431206d757374206265207365740000000000000000000000000000815260200192915050565b60006139d7600b836107ac565b7f436f6e7374616e7453756d0000000000000000000000000000000000000000008152600b0192915050565b6000613a106021836141d6565b7f65786368616e6765496420617420696e64657820646f65736e2774206d61746381527f6800000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b6000613a6f601f836141d6565b7f7265666572656e636552617465466565644944206d7573742062652073657400815260200192915050565b6000613aa86030836141d6565b7f416e2065786368616e676520776974682074686520737065636966696564206981527f6420646f6573206e6f7420657869737400000000000000000000000000000000602082015260400192915050565b6000613b076021836141d6565b7f536f727465644f7261636c65732061646472657373206d75737420626520736581527f7400000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b6000613b66601b836141d6565b7f526573657276652061646472657373206d757374206265207365740000000000815260200192915050565b6000613b9f601e836141d6565b7f427265616b6572426f782061646472657373206d757374206265207365740000815260200192915050565b6000613bd86028836141d6565b7f746f6b656e496e20616e6420746f6b656e4f7574206d757374206d617463682081527f65786368616e6765000000000000000000000000000000000000000000000000602082015260400192915050565b6000613c37601a836141d6565b7f42726f6b65722061646472657373206d75737420626520736574000000000000815260200192915050565b6000613c70602f836141d6565b7f6964656e7469666965727320616e64206d6f64756c6573206d7573742062652081527f7468652073616d65206c656e6774680000000000000000000000000000000000602082015260400192915050565b80516000906040840190613cd685826132a3565b5060208301518482036020860152612a7f828261313e565b80516020830190611ccb84826132a3565b805160a0830190613d108482613cee565b506020820151613d2360208501826130d7565b506040820151613d3660408501826132a3565b506060820151613d4960608501826132a3565b506080820151611ccb60808501826132a3565b8051610160830190613d6e84826130d7565b506020820151613d8160208501826130d7565b506040820151613d9460408501826132ac565b506060820151613da760608501826132a3565b506080820151613dba60808501826132a3565b5060a0820151613dcd60a08501826132a3565b5060c0820151611ccb60c0850182613cff565b60006126f282846132ed565b6000613df882866132ed565b9150613e0482856132ed565b9150612a7f82846132ed565b6000611d0e82613556565b6000611d0e826139ca565b60208101611d0e82846130d7565b6101608101613e43828a6130d7565b613e5060208301896130d7565b613e5d60408301886132ac565b613e6a60608301876132a3565b613e7760808301866132a3565b613e8460a08301856132a3565b610c7560c0830184613cff565b60408082528101613ea381868861318c565b90508181036020830152613eb88184866130e6565b9695505050505050565b60208082528101611d0b81846131de565b60208082528101611d0b818461322c565b60208101611d0e828461329a565b60208101611d0e82846132a3565b60208101611d0e82846132ac565b60208082528101611d0b81846132b5565b60208082528101611d0e8161331c565b60208082528101611d0e8161337b565b60208082528101611d0e816133da565b60208082528101611d0e81613413565b60208082528101611d0e81613472565b60208082528101611d0e816134ab565b60208082528101611d0e816134e4565b60208082528101611d0e8161351d565b60208082528101611d0e8161358f565b60208082528101611d0e816135ee565b60208082528101611d0e81613627565b60208082528101611d0e81613686565b60208082528101611d0e816136bf565b60208082528101611d0e8161371e565b60208082528101611d0e81613757565b60208082528101611d0e816137b6565b60208082528101611d0e816137ef565b60208082528101611d0e8161384e565b60208082528101611d0e81613887565b60208082528101611d0e816138c0565b60208082528101611d0e816138f9565b60208082528101611d0e81613958565b60208082528101611d0e81613991565b60208082528101611d0e81613a03565b60208082528101611d0e81613a62565b60208082528101611d0e81613a9b565b60208082528101611d0e81613afa565b60208082528101611d0e81613b59565b60208082528101611d0e81613b92565b60208082528101611d0e81613bcb565b60208082528101611d0e81613c2a565b60208082528101611d0e81613c63565b6101608101611d0e8284613d5c565b6040810161413c82856132a3565b6126f260208301846132a3565b6080810161415782876132a3565b61416460208301866132a3565b61417160408301856132a3565b612a7f60608301846132a3565b60405181810167ffffffffffffffff8111828210171561419d57600080fd5b604052919050565b600067ffffffffffffffff8211156141bc57600080fd5b506020601f91909101601f19160190565b90565b60200190565b90815260200190565b6000611d0b6020840184612b5f565b6000611d0e82614209565b151590565b6000611d0e826141ee565b6001600160a01b031690565b60ff1690565b82818337506000910152565b60005b8381101561424257818101518382015260200161422a565b83811115611ccb5750506000910152565b601f01601f191690565b614266816141ee565b8114611bbf57600080fd5b614266816141f9565b614266816141cd565b614266816141fe565b6142668161421556fea365627a7a72315820b07a353e3c84a93c77c4a62a250446907eb0175afe6e597bb0b231527b1eec6d6c6578706572696d656e74616cf564736f6c63430005110040","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"istanbul","libraries":{"":{"AddressLinkedList":"0x6200f54d73491d56b8d7a975c9ee18efb4d518df","AddressSortedLinkedListWithMedian":"0xed477a99035d0c1e11369f1d7a4e587893cc002b"}},"optimizer":{"enabled":true,"runs":10000},"outputSelection":{"*":{"":["*"],"*":["*"]}},"remappings":["@celo/=lib/mento-core-2.6.0/node_modules/@celo/contracts/","@chainlink/contracts/=lib/mento-core-2.6.5/lib/foundry-chainlink-toolkit/lib/chainlink-brownie-contracts/contracts/src/","@openzeppelin/=lib/mento-core-2.6.5/lib/foundry-chainlink-toolkit/lib/openzeppelin-contracts/","@prb/test/=lib/mento-core-2.6.5/lib/prb-math/lib/prb-test/src/","celo-foundry/=lib/celo-foundry/src/","celo/=node_modules/@celo/","chainlink-brownie-contracts/=lib/mento-core-2.6.5/lib/foundry-chainlink-toolkit/lib/chainlink-brownie-contracts/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/","contracts/=contracts/","ds-test/=lib/celo-foundry/lib/forge-std/lib/ds-test/src/","forge-std-next/=lib/forge-std-next/src/","forge-std/=lib/celo-foundry/lib/forge-std/src/","foundry-chainlink-toolkit/=lib/mento-core-2.6.5/lib/foundry-chainlink-toolkit/","mento-core-2.0.0/=lib/mento-core-2.0.0/contracts/","mento-core-2.1.0/=lib/mento-core-2.1.0/contracts/","mento-core-2.2.0/=lib/mento-core-2.2.0/contracts/","mento-core-2.3.1/=lib/mento-core-2.3.1/contracts/","mento-core-2.5.0/=lib/mento-core-2.5.0/contracts/","mento-core-2.6.0-oz/=lib/mento-core-2.6.0/lib/openzeppelin-contracts-next/","mento-core-2.6.0/=lib/mento-core-2.6.0/contracts/","mento-core-2.6.2/=lib/mento-core-2.6.2/contracts/","mento-core-2.6.3/=lib/mento-core-2.6.3/contracts/","mento-core-2.6.4/=lib/mento-core-2.6.4/contracts/","mento-core-2.6.5/=lib/mento-core-2.6.5/contracts/","mento-std/=lib/mento-core-2.6.5/lib/mento-std/src/","merkle-distributor/=lib/merkle-distributor/contracts/","openzeppelin-contracts-next/=lib/mento-core-2.6.5/lib/openzeppelin-contracts-next/","openzeppelin-contracts-upgradeable/=lib/mento-core-2.6.5/lib/openzeppelin-contracts-upgradeable/","openzeppelin-contracts/=lib/mento-core-2.6.5/lib/openzeppelin-contracts-next/","openzeppelin-solidity/=lib/mento-core-2.0.0/lib/openzeppelin-contracts/","prb-math/=lib/mento-core-2.6.5/lib/prb-math/src/","prb-test/=lib/mento-core-2.6.5/lib/prb-math/lib/prb-test/src/","prb/math/=lib/mento-core-2.6.5/lib/prb-math/src/","safe-contracts/=lib/mento-core-2.6.5/lib/safe-contracts/","src/=lib/mento-core-2.6.5/lib/prb-math/src/","test/=lib/mento-core-2.6.5/test/"]},"optimization_runs":10000,"sourcify_repo_url":null,"decoded_constructor_args":[["false",{"internalType":"bool","name":"test","type":"bool"}]],"compiler_version":"v0.5.17+commit.d19bba13","is_verified_via_verifier_alliance":false,"verified_at":"2026-01-28T19:18:50.477230Z","implementations":[],"proxy_type":null,"external_libraries":[{"name":"AddressLinkedList","address_hash":"0x6200F54D73491d56b8d7A975C9ee18EFb4D518Df"},{"name":"AddressSortedLinkedListWithMedian","address_hash":"0xED477A99035d0c1e11369F1D7A4e587893cc002B"}],"creation_bytecode":"0x60806040523480156200001157600080fd5b50604051620043ff380380620043ff8339810160408190526200003491620000cf565b808062000049576000805460ff191660011790555b5060006200005f6001600160e01b03620000b816565b60008054610100600160a81b0319166101006001600160a01b038416908102919091178255604051929350917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3505062000117565b3390565b8051620000c981620000fd565b92915050565b600060208284031215620000e257600080fd5b6000620000f08484620000bc565b949350505050565b151590565b6200010881620000f8565b81146200011457600080fd5b50565b6142d880620001276000396000f3fe608060405234801561001057600080fd5b50600436106101e55760003560e01c8063abff01101161010f578063d482dda6116100a2578063f2fde38b11610071578063f2fde38b146103eb578063f414c5e4146103fe578063f670dde114610406578063f8c8765e14610419576101e5565b8063d482dda61461038a578063dc162e36146103b0578063e46eb5b6146103c5578063eaaba701146103d8576101e5565b8063c5df620a116100de578063c5df620a14610354578063cd3293de14610367578063cd8513ba1461036f578063d3385d0514610377576101e5565b8063abff01101461031e578063b089869114610326578063bf0d021314610339578063c0ad52d51461034c576101e5565b806345015421116101875780638da5cb5b116101565780638da5cb5b146102db5780638f32d59b146102f057806393c7e3bc146102f85780639cecc80a1461030b576101e5565b8063450154211461029a57806345b2b467146102ad5780634afb215e146102c0578063715018a6146102d3576101e5565b80631e2e3a6b116101c35780631e2e3a6b14610232578063278488a41461024757806338b1e9f71461026757806342bfc99c14610287576101e5565b8063040bbd35146101ea578063132e8aa7146101ff578063158ef93e1461021d575b600080fd5b6101fd6101f8366004612fae565b61042c565b005b6102076104ed565b6040516102149190613f00565b60405180910390f35b6102256104fc565b6040516102149190613ee4565b61023a610505565b6040516102149190613ed3565b61025a610255366004612f0b565b6106ce565b604051610214919061411f565b61027a610275366004612f0b565b6107b1565b6040516102149190613ef2565b61027a610295366004612f29565b6107cf565b6101fd6102a8366004612e43565b610957565b61027a6102bb366004612dc4565b610a71565b6101fd6102ce366004612fae565b610a83565b6101fd610b2f565b6102e3610bb9565b6040516102149190613e26565b610225610bcd565b61027a610306366004612f29565b610bf6565b6101fd610319366004612fae565b610c81565b6102e3610d2d565b61027a610334366004613001565b610d3c565b6101fd610347366004612dc4565b6113d2565b61027a61147e565b6101fd610362366004612f7e565b6114a6565b61020761159a565b61027a6115a9565b61027a610385366004612f29565b6115b8565b61039d610398366004612f0b565b611733565b6040516102149796959493929190613e34565b6103b86117bf565b6040516102149190613ec2565b6102256103d3366004612f7e565b611817565b6102e36103e6366004612f0b565b611b77565b6101fd6103f9366004612dc4565b611b92565b610207611bc2565b61027a610414366004612f29565b611bd1565b6101fd610427366004612de2565b611c50565b610434610bcd565b6104595760405162461bcd60e51b81526004016104509061404f565b60405180910390fd5b6001600160a01b03811661047f5760405162461bcd60e51b8152600401610450906140df565b600580547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383161790556040517f21921b3b46ef2c939e85d6a14410c6e3b9ce132b66e944357ff4f789f68e00e2906104e2908390613e26565b60405180910390a150565b6006546001600160a01b031681565b60005460ff1681565b6003546040805182815260208084028201019091526060919081801561054557816020015b610532612a99565b81526020019060019003908161052a5790505b50915060005b818110156106c9576003818154811061056057fe5b906000526020600020015483828151811061057757fe5b6020908102919091010151526040805160028082526060820190925290816020016020820280388339019050508382815181106105b057fe5b60200260200101516020018190525060026000600383815481106105d057fe5b9060005260206000200154815260200190815260200160002060000160009054906101000a90046001600160a01b031683828151811061060c57fe5b60200260200101516020015160008151811061062457fe5b60200260200101906001600160a01b031690816001600160a01b031681525050600260006003838154811061065557fe5b9060005260206000200154815260200190815260200160002060010160009054906101000a90046001600160a01b031683828151811061069157fe5b6020026020010151602001516001815181106106a957fe5b6001600160a01b039092166020928302919091019091015260010161054b565b505090565b6106d6612ab1565b50600081815260026020818152604092839020835160e08101855281546001600160a01b03908116825260018301548116828501529382015484168186015260038201546060808301919091526004830154608080840191909152600584015460a080850191909152875160c08181018a5260068701549282019283529181526007860154881696810196909652600885015497860197909752600984015491850191909152600a9092015491830191909152928301528151166107ac5760405162461bcd60e51b8152600401610450906140af565b919050565b600381815481106107be57fe5b600091825260209091200154905081565b6001546000906001600160a01b031633146107fc5760405162461bcd60e51b815260040161045090613fcf565b610804612ab1565b61080d866106ce565b60055460c0820151602001516040517fc0b05da00000000000000000000000000000000000000000000000000000000081529293506000926001600160a01b039092169163c0b05da09161086391600401613e26565b60206040518083038186803b15801561087b57600080fd5b505afa15801561088f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108b3919081019061308d565b60ff16146108d35760405162461bcd60e51b815260040161045090613f1f565b6001600160a01b0385166000908152600760205260408120546108fd90859063ffffffff611cd116565b905060008061090e84898986611d14565b9150915061092089858a868686611f1c565b6001600160a01b03871660009081526007602052604090205461094a90839063ffffffff61203d16565b9998505050505050505050565b61095f610bcd565b61097b5760405162461bcd60e51b81526004016104509061404f565b82811461099a5760405162461bcd60e51b81526004016104509061410f565b60005b83811015610a2d578282828181106109b157fe5b90506020020160206109c69190810190612dc4565b600860008787858181106109d657fe5b6020908102929092013583525081019190915260400160002080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b039290921691909117905560010161099d565b507f84557d458d60fcb29d9a10a8f28861c76847f7ef6450a9266a228a6f3a590baa84848484604051610a639493929190613e91565b60405180910390a150505050565b60076020526000908152604090205481565b610a8b610bcd565b610aa75760405162461bcd60e51b81526004016104509061404f565b6001600160a01b038116610acd5760405162461bcd60e51b8152600401610450906140bf565b600680547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f590fd633a008765ce9e65e8081adfba311e99e11b958a5ecb5000ea3355f735390600090a250565b610b37610bcd565b610b535760405162461bcd60e51b81526004016104509061404f565b600080546040516101009091046001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080547fffffffffffffffffffffff0000000000000000000000000000000000000000ff169055565b60005461010090046001600160a01b031690565b6000805461010090046001600160a01b0316610be761207f565b6001600160a01b031614905090565b6000610c00612ab1565b610c09866106ce565b6001600160a01b03861660009081526007602052604081205491925090610c3790859063ffffffff611cd116565b90506000610c4783888885611d14565b506001600160a01b038716600090815260076020526040902054909150610c7590829063ffffffff61203d16565b98975050505050505050565b610c89610bcd565b610ca55760405162461bcd60e51b81526004016104509061404f565b6001600160a01b038116610ccb5760405162461bcd60e51b8152600401610450906140cf565b600480547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f0b248ab246a87e452fbedee8dc12dfc53e3f3bfdc6920999062c56dea4ab522a90600090a250565b6001546001600160a01b031681565b6000610d46610bcd565b610d625760405162461bcd60e51b81526004016104509061404f565b610d6a612ab1565b610d7936849003840184613020565b60408101519091506001600160a01b0316610da65760405162461bcd60e51b81526004016104509061400f565b80516001600160a01b0316610dcd5760405162461bcd60e51b815260040161045090613f6f565b60208101516001600160a01b0316610df75760405162461bcd60e51b81526004016104509061407f565b80602001516001600160a01b031681600001516001600160a01b03161415610e315760405162461bcd60e51b81526004016104509061405f565b80604001516001600160a01b031660086000610e4c84612083565b81526020810191909152604001600020546001600160a01b031614610e835760405162461bcd60e51b81526004016104509061403f565b80600001516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610ec057600080fd5b505afa158015610ed4573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610efc9190810190612fcc565b81602001516001600160a01b03166395d89b416040518163ffffffff1660e01b815260040160006040518083038186803b158015610f3957600080fd5b505afa158015610f4d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f759190810190612fcc565b82604001516001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b158015610fb257600080fd5b505afa158015610fc6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fee9190810190612fcc565b60405160200161100093929190613dec565b60408051601f198184030181529181528151602092830120600081815260029093529120549092506001600160a01b03161561104e5760405162461bcd60e51b815260040161045090613f9f565b6110578161212b565b6000806110638361239b565b915091508183606001818152505080836080018181525050600083600001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b1580156110ba57600080fd5b505afa1580156110ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506110f2919081019061308d565b60ff169050600084602001516001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561113657600080fd5b505afa15801561114a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061116e919081019061308d565b60ff16905060128211156111945760405162461bcd60e51b815260040161045090613faf565b60128111156111b55760405162461bcd60e51b815260040161045090613fef565b81601203600a0a6007600087600001516001600160a01b03166001600160a01b031681526020019081526020016000208190555080601203600a0a6007600087602001516001600160a01b03166001600160a01b0316815260200190815260200160002081905550846002600088815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160020160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550606082015181600301556080820151816004015560a0820151816005015560c08201518160060160008201518160000160008201518160000155505060208201518160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506040820151816002015560608201518160030155608082015181600401555050905050600386908060018154018082558091505090600182039060005260206000200160009091929091909150555084602001516001600160a01b031685600001516001600160a01b0316877fb374789237d43aed0f75b4c50a45793fd70e354bb96eecd573f35f5d509d78a188604001516040516113c09190613e26565b60405180910390a45050505050919050565b6113da610bcd565b6113f65760405162461bcd60e51b81526004016104509061404f565b6001600160a01b03811661141c5760405162461bcd60e51b8152600401610450906140ff565b600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f865dab7821134b6eb27cba259b40e33bbc1b898e970a535a18a83147f380a51f90600090a250565b60405160200161148d90613e1b565b6040516020818303038152906040528051906020012081565b6114ae610bcd565b6114ca5760405162461bcd60e51b81526004016104509061404f565b6000828152600260205260409020546001600160a01b03166114fe5760405162461bcd60e51b81526004016104509061402f565b611506612b0e565b61150f826123eb565b905061152961151c612405565b829063ffffffff61242916565b6115455760405162461bcd60e51b81526004016104509061406f565b6000838152600260205260409081902082516006909101555183907fd543777ec8c7717f747583b4011aee3b898ca0b5bc6c32144b7d4887eb62c74e9061158d908590613ef2565b60405180910390a2505050565b6004546001600160a01b031681565b60405160200161148d90613e10565b6001546000906001600160a01b031633146115e55760405162461bcd60e51b815260040161045090613fcf565b6115ed612ab1565b6115f6866106ce565b60055460c0820151602001516040517fc0b05da00000000000000000000000000000000000000000000000000000000081529293506000926001600160a01b039092169163c0b05da09161164c91600401613e26565b60206040518083038186803b15801561166457600080fd5b505afa158015611678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061169c919081019061308d565b60ff16146116bc5760405162461bcd60e51b815260040161045090613f1f565b6001600160a01b0384166000908152600760205260408120546116e690859063ffffffff611cd116565b90506000806116f784898986612431565b9150915061170989858a858786611f1c565b6001600160a01b03881660009081526007602052604090205461094a90839063ffffffff61203d16565b6002602081815260009283526040928390208054600182015493820154600383015460048401546005850154885160c081018a52600687015460a08201908152815260078701546001600160a01b0390811698820198909852600887015499810199909952600986015460608a0152600a90950154608089015292851696958516959190941693929087565b6060600380548060200260200160405190810160405280929190818152602001828054801561180d57602002820191906000526020600020905b8154815260200190600101908083116117f9575b5050505050905090565b6000611821610bcd565b61183d5760405162461bcd60e51b81526004016104509061404f565b600354821061185e5760405162461bcd60e51b815260040161045090613f7f565b826003838154811061186c57fe5b9060005260206000200154146118945760405162461bcd60e51b81526004016104509061408f565b61189c612ab1565b600260008581526020019081526020016000206040518060e00160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b031681526020016002820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600382015481526020016004820154815260200160058201548152602001600682016040518060a00160405290816000820160405180602001604052908160008201548152505081526020016001820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600282015481526020016003820154815260200160048201548152505081525050905060026000858152602001908152602001600020600080820160006101000a8154906001600160a01b0302191690556001820160006101000a8154906001600160a01b0302191690556002820160006101000a8154906001600160a01b03021916905560038201600090556004820160009055600582016000905560068201600080820160008082016000905550506001820160006101000a8154906001600160a01b030219169055600282016000905560038201600090556004820160009055505050506003611ac5600160038054905061254390919063ffffffff16565b81548110611acf57fe5b906000526020600020015460038481548110611ae757fe5b6000918252602090912001556003805480611afe57fe5b600190038181906000526020600020016000905590556001915080602001516001600160a01b031681600001516001600160a01b0316857fadbbec6c203cb0248e89fe6d15ad651061a9d5203a1ab0273256e2b7decffa898460400151604051611b689190613e26565b60405180910390a45092915050565b6008602052600090815260409020546001600160a01b031681565b611b9a610bcd565b611bb65760405162461bcd60e51b81526004016104509061404f565b611bbf81612585565b50565b6005546001600160a01b031681565b6000611bdb612ab1565b611be4866106ce565b6001600160a01b03851660009081526007602052604081205491925090611c1290859063ffffffff611cd116565b90506000611c2283888885612431565b506001600160a01b038816600090815260076020526040902054909150610c7590829063ffffffff61203d16565b60005460ff1615611c735760405162461bcd60e51b815260040161045090613f3f565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055611ca733612585565b611cb0846113d2565b611cb983610c81565b611cc282610a83565b611ccb8161042c565b50505050565b600082611ce057506000611d0e565b82820282848281611ced57fe5b0414611d0b5760405162461bcd60e51b81526004016104509061401f565b90505b92915050565b60008084848780600001516001600160a01b0316836001600160a01b0316148015611d54575080602001516001600160a01b0316826001600160a01b0316145b80611d8b575080602001516001600160a01b0316836001600160a01b0316148015611d8b575080516001600160a01b038381169116145b611da75760405162461bcd60e51b8152600401610450906140ef565b611db089612628565b8151919a5094506001600160a01b0389811691161415611e6f5788604001516001600160a01b03166352707d8c8a606001518b60800151611df88d60c0015160000151612660565b8a6040518563ffffffff1660e01b8152600401611e189493929190614149565b60206040518083038186803b158015611e3057600080fd5b505afa158015611e44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611e68919081019061303f565b9450611f10565b88604001516001600160a01b03166352707d8c8a608001518b60600151611e9d8d60c0015160000151612660565b8a6040518563ffffffff1660e01b8152600401611ebd9493929190614149565b60206040518083038186803b158015611ed557600080fd5b505afa158015611ee9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250611f0d919081019061303f565b94505b50505094509492505050565b8015611f8057426002600088815260200190815260200160002060050181905550857f949f5db193cbfa01f2d443b1c656bfede15497de0d86838cea089bd60c43834286606001518760800151604051611f7792919061412e565b60405180910390a25b611f8985612664565b156120115784516001600160a01b0385811691161415611fdc576060850151611fb8908463ffffffff61269b16565b60608601526080850151611fd2908363ffffffff61254316565b6080860152612011565b6060850151611ff1908363ffffffff61254316565b6060860152608085015161200b908463ffffffff61269b16565b60808601525b505050606082015160009384526002602052604090932060038101939093555060800151600490910155565b6000611d0b83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506126c0565b3390565b600081604001516001600160a01b03166306fdde036040518163ffffffff1660e01b815260040160006040518083038186803b1580156120c257600080fd5b505afa1580156120d6573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526120fe9190810190612fcc565b60405160200161210e9190613de0565b604051602081830303815290604052805190602001209050919050565b6004805482516040517f4f8e6e230000000000000000000000000000000000000000000000000000000081526001600160a01b0390921692634f8e6e2392612174929101613e26565b60206040518083038186803b15801561218c57600080fd5b505afa1580156121a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506121c49190810190612eb3565b6121e05760405162461bcd60e51b815260040161045090613f2f565b6004805460208301516040517f4f8e6e230000000000000000000000000000000000000000000000000000000081526001600160a01b0390921692634f8e6e239261222c929101613e26565b60206040518083038186803b15801561224457600080fd5b505afa158015612258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061227c9190810190612eb3565b8061231e57506004805460208301516040517fcae182fe0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169263cae182fe926122ce929101613e26565b60206040518083038186803b1580156122e657600080fd5b505afa1580156122fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061231e9190810190612eb3565b61233a5760405162461bcd60e51b815260040161045090613fbf565b60c0810151516123519061234c612405565b612429565b61236d5760405162461bcd60e51b815260040161045090613fff565b60c0810151602001516001600160a01b0316611bbf5760405162461bcd60e51b81526004016104509061409f565b6000808260c001516080015191506000806123bd8560c00151602001516126f9565b90925090506123e2826123d6838763ffffffff611cd116565b9063ffffffff61203d16565b92505050915091565b6123f3612b0e565b50604080516020810190915290815290565b61240d612b0e565b50604080516020810190915269d3c21bcecceda1000000815290565b519051111590565b60008084848780600001516001600160a01b0316836001600160a01b0316148015612471575080602001516001600160a01b0316826001600160a01b0316145b806124a8575080602001516001600160a01b0316836001600160a01b03161480156124a8575080516001600160a01b038381169116145b6124c45760405162461bcd60e51b8152600401610450906140ef565b6124cd89612628565b8151919a5094506001600160a01b03898116911614156125155788604001516001600160a01b031663571fd0128a606001518b60800151611df88d60c0015160000151612660565b88604001516001600160a01b031663571fd0128a608001518b60600151611e9d8d60c0015160000151612660565b6000611d0b83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506127b8565b6001600160a01b0381166125ab5760405162461bcd60e51b815260040161045090613f4f565b600080546040516001600160a01b038085169361010090930416917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b03909216610100027fffffffffffffffffffffff0000000000000000000000000000000000000000ff909216919091179055565b612630612ab1565b600061263b836127e4565b15612657576126498361239b565b608085015260608401525060015b8291505b915091565b5190565b600060405160200161267590613e10565b6040516020818303038152906040528051906020012061269483612083565b1492915050565b600082820183811015611d0b5760405162461bcd60e51b815260040161045090613f8f565b600081836126e15760405162461bcd60e51b81526004016104509190613f0e565b5060008385816126ed57fe5b049150505b9392505050565b6006546040517fef90e1b000000000000000000000000000000000000000000000000000000000815260009182916001600160a01b039091169063ef90e1b090612747908690600401613e26565b604080518083038186803b15801561275e57600080fd5b505afa158015612772573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612796919081019061305d565b90925090508061265b5760405162461bcd60e51b815260040161045090613fdf565b600081848411156127dc5760405162461bcd60e51b81526004016104509190613f0e565b505050900390565b6000806127f083612855565b90506127fb83612a88565b1561281d578061281d5760405162461bcd60e51b815260040161045090613f5f565b600061283e8460c00151604001518560a0015161269b90919063ffffffff16565b421015905080801561284d5750815b949350505050565b60065460c0820151602001516040517fffe736bf00000000000000000000000000000000000000000000000000000000815260009283926001600160a01b039091169163ffe736bf916128aa91600401613e26565b604080518083038186803b1580156128c157600080fd5b505afa1580156128d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506128f99190810190612ed1565b5060c084015160608101516006546020909201516040517fbbc66a9400000000000000000000000000000000000000000000000000000000815293945060009391926001600160a01b03169163bbc66a949161295791600401613e26565b60206040518083038186803b15801561296f57600080fd5b505afa158015612983573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506129a7919081019061303f565b1015905060006129c88560c00151604001514261254390919063ffffffff16565b60065460c0870151602001516040517f071b48fc0000000000000000000000000000000000000000000000000000000081526001600160a01b039092169163071b48fc91612a1891600401613e26565b60206040518083038186803b158015612a3057600080fd5b505afa158015612a44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a68919081019061303f565b11905082158015612a765750815b8015612a7f5750805b95945050505050565b600060405160200161267590613e1b565b60408051808201909152600081526060602082015290565b6040518060e0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160008152602001612b09612b21565b905290565b6040518060200160405280600081525090565b6040518060a00160405280612b34612b0e565b815260200160006001600160a01b031681526020016000815260200160008152602001600081525090565b8035611d0e8161425d565b8051611d0e8161425d565b60008083601f840112612b8757600080fd5b50813567ffffffffffffffff811115612b9f57600080fd5b602083019150836020820283011115612bb757600080fd5b9250929050565b8051611d0e81614271565b8035611d0e8161427a565b8035611d0e81614283565b600082601f830112612bf057600080fd5b8151612c03612bfe826141a5565b61417e565b91508082526020830160208301858383011115612c1f57600080fd5b612c2a838284614227565b50505092915050565b600060208284031215612c4557600080fd5b612c4f602061417e565b90506000612c5d8484612bc9565b82525092915050565b600060a08284031215612c7857600080fd5b612c8260a061417e565b90506000612c908484612c33565b8252506020612ca184848301612b5f565b6020830152506040612cb584828501612bc9565b6040830152506060612cc984828501612bc9565b6060830152506080612cdd84828501612bc9565b60808301525092915050565b60006101608284031215612cfc57600080fd5b50919050565b60006101608284031215612d1557600080fd5b612d1f60e061417e565b90506000612d2d8484612b5f565b8252506020612d3e84848301612b5f565b6020830152506040612d5284828501612bd4565b6040830152506060612d6684828501612bc9565b6060830152506080612d7a84828501612bc9565b60808301525060a0612d8e84828501612bc9565b60a08301525060c0612da284828501612c66565b60c08301525092915050565b8051611d0e8161427a565b8051611d0e8161428c565b600060208284031215612dd657600080fd5b600061284d8484612b5f565b60008060008060808587031215612df857600080fd5b6000612e048787612b5f565b9450506020612e1587828801612bd4565b9350506040612e2687828801612bd4565b9250506060612e3787828801612bd4565b91505092959194509250565b60008060008060408587031215612e5957600080fd5b843567ffffffffffffffff811115612e7057600080fd5b612e7c87828801612b75565b9450945050602085013567ffffffffffffffff811115612e9b57600080fd5b612ea787828801612b75565b95989497509550505050565b600060208284031215612ec557600080fd5b600061284d8484612bbe565b60008060408385031215612ee457600080fd5b6000612ef08585612bbe565b9250506020612f0185828601612b6a565b9150509250929050565b600060208284031215612f1d57600080fd5b600061284d8484612bc9565b60008060008060808587031215612f3f57600080fd5b6000612f4b8787612bc9565b9450506020612f5c87828801612b5f565b9350506040612f6d87828801612b5f565b9250506060612e3787828801612bc9565b60008060408385031215612f9157600080fd5b6000612f9d8585612bc9565b9250506020612f0185828601612bc9565b600060208284031215612fc057600080fd5b600061284d8484612bd4565b600060208284031215612fde57600080fd5b815167ffffffffffffffff811115612ff557600080fd5b61284d84828501612bdf565b6000610160828403121561301457600080fd5b600061284d8484612ce9565b6000610160828403121561303357600080fd5b600061284d8484612d02565b60006020828403121561305157600080fd5b600061284d8484612dae565b6000806040838503121561307057600080fd5b600061307c8585612dae565b9250506020612f0185828601612dae565b60006020828403121561309f57600080fd5b600061284d8484612db9565b60006130b783836130d7565b505060200190565b60006130b783836132a3565b6000611d0b8383613cc2565b6130e0816141ee565b82525050565b60006130f283856141d6565b93506130fd826141cd565b8060005b858110156131335761311382846141df565b61311d88826130ab565b9750613128836141d0565b925050600101613101565b509495945050505050565b600061314982612660565b61315381856141d6565b935061315e836141d0565b8060005b8381101561313357815161317688826130ab565b9750613181836141d0565b925050600101613162565b600061319883856141d6565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156131c757600080fd5b6020830292506131d883858461421b565b50500190565b60006131e982612660565b6131f381856141d6565b93506131fe836141d0565b8060005b8381101561313357815161321688826130bf565b9750613221836141d0565b925050600101613202565b600061323782612660565b61324181856141d6565b935083602082028501613253856141d0565b8060005b8581101561328d578484038952815161327085826130cb565b945061327b836141d0565b60209a909a0199925050600101613257565b5091979650505050505050565b6130e0816141f9565b6130e0816141cd565b6130e0816141fe565b60006132c082612660565b6132ca81856141d6565b93506132da818560208601614227565b6132e381614253565b9093019392505050565b60006132f882612660565b61330281856107ac565b9350613312818560208601614227565b9290920192915050565b6000613329602c836141d6565b7f54726164696e672069732073757370656e64656420666f72207468697320726581527f666572656e636520726174650000000000000000000000000000000000000000602082015260400192915050565b60006133886033836141d6565b7f617373657430206d757374206265206120737461626c6520726567697374657281527f6564207769746820746865207265736572766500000000000000000000000000602082015260400192915050565b60006133e7601c836141d6565b7f636f6e747261637420616c726561647920696e697469616c697a656400000000815260200192915050565b60006134206026836141d6565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206181527f6464726573730000000000000000000000000000000000000000000000000000602082015260400192915050565b600061347f600f836141d6565b7f6e6f2076616c6964206d656469616e0000000000000000000000000000000000815260200192915050565b60006134b86012836141d6565b7f617373657430206d757374206265207365740000000000000000000000000000815260200192915050565b60006134f1601c836141d6565b7f65786368616e67654964496e646578206e6f7420696e2072616e676500000000815260200192915050565b600061352a601b836141d6565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b6000613563600f836107ac565b7f436f6e7374616e7450726f6475637400000000000000000000000000000000008152600f0192915050565b600061359c6039836141d6565b7f416e2065786368616e676520776974682074686520737065636966696564206181527f737365747320616e642065786368616e67652065786973747300000000000000602082015260400192915050565b60006135fb601d836141d6565b7f61737365743020646563696d616c73206d757374206265203c3d203138000000815260200192915050565b60006136346025836141d6565b7f617373657431206d757374206265206120737461626c65206f7220636f6c6c6181527f746572616c000000000000000000000000000000000000000000000000000000602082015260400192915050565b60006136936018836141d6565b7f43616c6c6572206973206e6f74207468652042726f6b65720000000000000000815260200192915050565b60006136cc6030836141d6565b7f65786368616e676520726174652064656e6f6d696e61746f72206d757374206281527f652067726561746572207468616e203000000000000000000000000000000000602082015260400192915050565b600061372b601d836141d6565b7f61737365743120646563696d616c73206d757374206265203c3d203138000000815260200192915050565b60006137646026836141d6565b7f737072656164206d757374206265206c657373207468616e206f72206571756181527f6c20746f20310000000000000000000000000000000000000000000000000000602082015260400192915050565b60006137c36019836141d6565b7f70726963696e674d6f64756c65206d7573742062652073657400000000000000815260200192915050565b60006137fc6021836141d6565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f81527f7700000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b600061385b6012836141d6565b7f696e76616c69642065786368616e676549640000000000000000000000000000815260200192915050565b60006138946015836141d6565b7f696e76616c69642070726963696e674d6f64756c650000000000000000000000815260200192915050565b60006138cd6020836141d6565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572815260200192915050565b60006139066022836141d6565b7f65786368616e6765206173736574732063616e2774206265206964656e74696381527f616c000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b60006139656013836141d6565b7f737072656164206d757374206265203c3d203100000000000000000000000000815260200192915050565b600061399e6012836141d6565b7f617373657431206d757374206265207365740000000000000000000000000000815260200192915050565b60006139d7600b836107ac565b7f436f6e7374616e7453756d0000000000000000000000000000000000000000008152600b0192915050565b6000613a106021836141d6565b7f65786368616e6765496420617420696e64657820646f65736e2774206d61746381527f6800000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b6000613a6f601f836141d6565b7f7265666572656e636552617465466565644944206d7573742062652073657400815260200192915050565b6000613aa86030836141d6565b7f416e2065786368616e676520776974682074686520737065636966696564206981527f6420646f6573206e6f7420657869737400000000000000000000000000000000602082015260400192915050565b6000613b076021836141d6565b7f536f727465644f7261636c65732061646472657373206d75737420626520736581527f7400000000000000000000000000000000000000000000000000000000000000602082015260400192915050565b6000613b66601b836141d6565b7f526573657276652061646472657373206d757374206265207365740000000000815260200192915050565b6000613b9f601e836141d6565b7f427265616b6572426f782061646472657373206d757374206265207365740000815260200192915050565b6000613bd86028836141d6565b7f746f6b656e496e20616e6420746f6b656e4f7574206d757374206d617463682081527f65786368616e6765000000000000000000000000000000000000000000000000602082015260400192915050565b6000613c37601a836141d6565b7f42726f6b65722061646472657373206d75737420626520736574000000000000815260200192915050565b6000613c70602f836141d6565b7f6964656e7469666965727320616e64206d6f64756c6573206d7573742062652081527f7468652073616d65206c656e6774680000000000000000000000000000000000602082015260400192915050565b80516000906040840190613cd685826132a3565b5060208301518482036020860152612a7f828261313e565b80516020830190611ccb84826132a3565b805160a0830190613d108482613cee565b506020820151613d2360208501826130d7565b506040820151613d3660408501826132a3565b506060820151613d4960608501826132a3565b506080820151611ccb60808501826132a3565b8051610160830190613d6e84826130d7565b506020820151613d8160208501826130d7565b506040820151613d9460408501826132ac565b506060820151613da760608501826132a3565b506080820151613dba60808501826132a3565b5060a0820151613dcd60a08501826132a3565b5060c0820151611ccb60c0850182613cff565b60006126f282846132ed565b6000613df882866132ed565b9150613e0482856132ed565b9150612a7f82846132ed565b6000611d0e82613556565b6000611d0e826139ca565b60208101611d0e82846130d7565b6101608101613e43828a6130d7565b613e5060208301896130d7565b613e5d60408301886132ac565b613e6a60608301876132a3565b613e7760808301866132a3565b613e8460a08301856132a3565b610c7560c0830184613cff565b60408082528101613ea381868861318c565b90508181036020830152613eb88184866130e6565b9695505050505050565b60208082528101611d0b81846131de565b60208082528101611d0b818461322c565b60208101611d0e828461329a565b60208101611d0e82846132a3565b60208101611d0e82846132ac565b60208082528101611d0b81846132b5565b60208082528101611d0e8161331c565b60208082528101611d0e8161337b565b60208082528101611d0e816133da565b60208082528101611d0e81613413565b60208082528101611d0e81613472565b60208082528101611d0e816134ab565b60208082528101611d0e816134e4565b60208082528101611d0e8161351d565b60208082528101611d0e8161358f565b60208082528101611d0e816135ee565b60208082528101611d0e81613627565b60208082528101611d0e81613686565b60208082528101611d0e816136bf565b60208082528101611d0e8161371e565b60208082528101611d0e81613757565b60208082528101611d0e816137b6565b60208082528101611d0e816137ef565b60208082528101611d0e8161384e565b60208082528101611d0e81613887565b60208082528101611d0e816138c0565b60208082528101611d0e816138f9565b60208082528101611d0e81613958565b60208082528101611d0e81613991565b60208082528101611d0e81613a03565b60208082528101611d0e81613a62565b60208082528101611d0e81613a9b565b60208082528101611d0e81613afa565b60208082528101611d0e81613b59565b60208082528101611d0e81613b92565b60208082528101611d0e81613bcb565b60208082528101611d0e81613c2a565b60208082528101611d0e81613c63565b6101608101611d0e8284613d5c565b6040810161413c82856132a3565b6126f260208301846132a3565b6080810161415782876132a3565b61416460208301866132a3565b61417160408301856132a3565b612a7f60608301846132a3565b60405181810167ffffffffffffffff8111828210171561419d57600080fd5b604052919050565b600067ffffffffffffffff8211156141bc57600080fd5b506020601f91909101601f19160190565b90565b60200190565b90815260200190565b6000611d0b6020840184612b5f565b6000611d0e82614209565b151590565b6000611d0e826141ee565b6001600160a01b031690565b60ff1690565b82818337506000910152565b60005b8381101561424257818101518382015260200161422a565b83811115611ccb5750506000910152565b601f01601f191690565b614266816141ee565b8114611bbf57600080fd5b614266816141f9565b614266816141cd565b614266816141fe565b6142668161421556fea365627a7a72315820b07a353e3c84a93c77c4a62a250446907eb0175afe6e597bb0b231527b1eec6d6c6578706572696d656e74616cf564736f6c634300051100400000000000000000000000000000000000000000000000000000000000000000","name":"BiPoolManager","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"istanbul","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"lib/mento-core-2.0.0/lib/openzeppelin-contracts/contracts/GSN/Context.sol","source_code":"pragma solidity ^0.5.0;\n\n/*\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\ncontract Context {\n    // Empty internal constructor, to prevent people from mistakenly deploying\n    // an instance of this contract, which should be used via inheritance.\n    constructor () internal { }\n    // solhint-disable-previous-line no-empty-blocks\n\n    function _msgSender() internal view returns (address payable) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view returns (bytes memory) {\n        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n        return msg.data;\n    }\n}\n"},{"file_path":"lib/mento-core-2.0.0/lib/openzeppelin-contracts/contracts/math/SafeMath.sol","source_code":"pragma solidity ^0.5.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n    /**\n     * @dev Returns the addition of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     * - Addition cannot overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        uint256 c = a + b;\n        require(c >= a, \"SafeMath: addition overflow\");\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        return sub(a, b, \"SafeMath: subtraction overflow\");\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     * - Subtraction cannot overflow.\n     *\n     * _Available since v2.4.0._\n     */\n    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        require(b <= a, errorMessage);\n        uint256 c = a - b;\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     * - Multiplication cannot overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n        // benefit is lost if 'b' is also tested.\n        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n        if (a == 0) {\n            return 0;\n        }\n\n        uint256 c = a * b;\n        require(c / a == b, \"SafeMath: multiplication overflow\");\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers. Reverts on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        return div(a, b, \"SafeMath: division by zero\");\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     *\n     * _Available since v2.4.0._\n     */\n    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        // Solidity only automatically asserts when dividing by 0\n        require(b > 0, errorMessage);\n        uint256 c = a / b;\n        // assert(a == b * c + a % b); // There is no case in which this doesn't hold\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * Reverts when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        return mod(a, b, \"SafeMath: modulo by zero\");\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * Reverts with custom message when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     * - The divisor cannot be zero.\n     *\n     * _Available since v2.4.0._\n     */\n    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        require(b != 0, errorMessage);\n        return a % b;\n    }\n}\n"},{"file_path":"lib/mento-core-2.0.0/lib/openzeppelin-contracts/contracts/ownership/Ownable.sol","source_code":"pragma solidity ^0.5.0;\n\nimport \"../GSN/Context.sol\";\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\ncontract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor () internal {\n        address msgSender = _msgSender();\n        _owner = msgSender;\n        emit OwnershipTransferred(address(0), msgSender);\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(isOwner(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Returns true if the caller is the current owner.\n     */\n    function isOwner() public view returns (bool) {\n        return _msgSender() == _owner;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public onlyOwner {\n        emit OwnershipTransferred(_owner, address(0));\n        _owner = address(0);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public onlyOwner {\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     */\n    function _transferOwnership(address newOwner) internal {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        emit OwnershipTransferred(_owner, newOwner);\n        _owner = newOwner;\n    }\n}\n"},{"file_path":"lib/mento-core-2.6.5/contracts/interfaces/IBiPoolManager.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\n// solhint-disable func-name-mixedcase\npragma solidity >0.5.13 <0.9;\npragma experimental ABIEncoderV2;\n\nimport { IPricingModule } from \"./IPricingModule.sol\";\nimport { IReserve } from \"./IReserve.sol\";\nimport { ISortedOracles } from \"./ISortedOracles.sol\";\nimport { IBreakerBox } from \"./IBreakerBox.sol\";\nimport { IExchangeProvider } from \"./IExchangeProvider.sol\";\n\nimport { FixidityLib } from \"celo/contracts/common/FixidityLib.sol\";\n\n/**\n * @title BiPool Manager interface\n * @notice An exchange provider implementation managing the state of all two-asset virtual pools.\n */\ninterface IBiPoolManager {\n  /**\n   * @title PoolExchange\n   * @notice The PoolExchange is a type of asset exchange that\n   * that implements an AMM with two virtual buckets.\n   */\n  struct PoolExchange {\n    address asset0;\n    address asset1;\n    IPricingModule pricingModule;\n    uint256 bucket0;\n    uint256 bucket1;\n    uint256 lastBucketUpdate;\n    PoolConfig config;\n  }\n\n  /**\n   * @notice Variables related to bucket updates and sizing.\n   * @dev Broken down into a separate struct because the compiler\n   * version doesn't support structs with too many members.\n   * Sad reacts only.\n   */\n  struct PoolConfig {\n    FixidityLib.Fraction spread;\n    address referenceRateFeedID; // rateFeedID of the price that this pool follows (i.e. it's reference rate)\n    uint256 referenceRateResetFrequency;\n    uint256 minimumReports;\n    uint256 stablePoolResetSize;\n  }\n\n  /**\n   * @notice Emitted when a new PoolExchange has been created.\n   * @param exchangeId The id of the new PoolExchange\n   * @param asset0 The address of asset0\n   * @param asset1 The address of asset1\n   * @param pricingModule the address of the pricingModule\n   */\n  event ExchangeCreated(\n    bytes32 indexed exchangeId,\n    address indexed asset0,\n    address indexed asset1,\n    address pricingModule\n  );\n\n  /**\n   * @notice Emitted when a PoolExchange has been destroyed.\n   * @param exchangeId The id of the PoolExchange\n   * @param asset0 The address of asset0\n   * @param asset1 The address of asset1\n   * @param pricingModule the address of the pricingModule\n   */\n  event ExchangeDestroyed(\n    bytes32 indexed exchangeId,\n    address indexed asset0,\n    address indexed asset1,\n    address pricingModule\n  );\n\n  /**\n   * @notice Emitted when the broker address is updated.\n   * @param newBroker The address of the new broker.\n   */\n  event BrokerUpdated(address indexed newBroker);\n\n  /**\n   * @notice Emitted when the reserve address is updated.\n   * @param newReserve The address of the new reserve.\n   */\n  event ReserveUpdated(address indexed newReserve);\n\n  /**\n   * @notice Emitted when the breakerBox address is updated.\n   * @param newBreakerBox The address of the new breakerBox.\n   */\n  event BreakerBoxUpdated(address newBreakerBox);\n\n  /**\n   * @notice Emitted when the sortedOracles address is updated.\n   * @param newSortedOracles The address of the new sortedOracles.\n   */\n  event SortedOraclesUpdated(address indexed newSortedOracles);\n\n  /**\n   * @notice Emitted when the buckets for a specified exchange are updated.\n   * @param exchangeId The id of the exchange\n   * @param bucket0 The new bucket0 size\n   * @param bucket1 The new bucket1 size\n   */\n  event BucketsUpdated(bytes32 indexed exchangeId, uint256 bucket0, uint256 bucket1);\n\n  /**\n   * @notice Emitted when the pricing modules have been updated.\n   * @param newIdentifiers The new identifiers.\n   * @param newAddresses The new pricing module addresses.\n   */\n  event PricingModulesUpdated(bytes32[] newIdentifiers, address[] newAddresses);\n\n  /**\n   * @notice Emitted when the spread for a specified exchange is updated.\n   * @param exchangeId The id of the exchange\n   * @param spread The new spread\n   */\n  event SpreadUpdated(bytes32 indexed exchangeId, uint256 spread);\n\n  /**\n   * @notice Retrieves the pool with the specified exchangeId.\n   * @param exchangeId The id of the pool to be retrieved.\n   * @return exchange The PoolExchange with that ID.\n   */\n  function getPoolExchange(bytes32 exchangeId) external view returns (PoolExchange memory exchange);\n\n  /**\n   * @notice Get all exchange IDs.\n   * @return _exchangeIds List of the exchangeIds.\n   */\n  function getExchangeIds() external view returns (bytes32[] memory _exchangeIds);\n\n  /**\n   * @notice Create a PoolExchange with the provided data.\n   * @param exchange The PoolExchange to be created.\n   * @return exchangeId The id of the exchange.\n   */\n  function createExchange(PoolExchange calldata exchange) external returns (bytes32 exchangeId);\n\n  /**\n   * @notice Delete a PoolExchange.\n   * @param exchangeId The PoolExchange to be created.\n   * @param exchangeIdIndex The index of the exchangeId in the exchangeIds array.\n   * @return destroyed - true on successful delition.\n   */\n  function destroyExchange(bytes32 exchangeId, uint256 exchangeIdIndex) external returns (bool destroyed);\n\n  /**\n   * @notice Allows the contract to be upgradable via the proxy.\n   * @param _broker The address of the broker contract.\n   * @param _reserve The address of the reserve contract.\n   * @param _sortedOracles The address of the sorted oracles contract.\n   * @param _breakerBox The address of the breaker box contract.\n   */\n  function initialize(\n    address _broker,\n    IReserve _reserve,\n    ISortedOracles _sortedOracles,\n    IBreakerBox _breakerBox\n  ) external;\n\n  function swapIn(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountIn\n  ) external returns (uint256 amountOut);\n\n  function swapOut(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountOut\n  ) external returns (uint256 amountIn);\n\n  /**\n   * @notice Updates the pricing modules for a list of identifiers\n   * @dev This function can only be called by the owner of the contract.\n   *      The number of identifiers and modules provided must be the same.\n   * @param identifiers An array of identifiers for which the pricing modules are to be set.\n   * @param addresses An array of module addresses corresponding to each identifier.\n   */\n  function setPricingModules(bytes32[] calldata identifiers, address[] calldata addresses) external;\n\n  // @notice Getters:\n  function broker() external view returns (address);\n\n  function exchanges(bytes32) external view returns (PoolExchange memory);\n\n  function exchangeIds(uint256) external view returns (bytes32);\n\n  function reserve() external view returns (IReserve);\n\n  function sortedOracles() external view returns (ISortedOracles);\n\n  function breakerBox() external view returns (IBreakerBox);\n\n  function tokenPrecisionMultipliers(address) external view returns (uint256);\n\n  function CONSTANT_SUM() external view returns (bytes32);\n\n  function CONSTANT_PRODUCT() external view returns (bytes32);\n\n  function pricingModules(bytes32) external view returns (address);\n\n  function getExchanges() external view returns (IExchangeProvider.Exchange[] memory);\n\n  function getAmountOut(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountIn\n  ) external view returns (uint256 amountOut);\n\n  function getAmountIn(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountOut\n  ) external view returns (uint256 amountIn);\n\n  /// @notice Setters:\n  function setBroker(address newBroker) external;\n\n  function setReserve(IReserve newReserve) external;\n\n  function setSortedOracles(ISortedOracles newSortedOracles) external;\n\n  function setBreakerBox(IBreakerBox newBreakerBox) external;\n\n  function setSpread(bytes32 exchangeId, uint256 spread) external;\n\n  /// @notice IOwnable:\n  function transferOwnership(address newOwner) external;\n\n  function renounceOwnership() external;\n\n  function owner() external view returns (address);\n}\n"},{"file_path":"lib/mento-core-2.6.5/contracts/interfaces/IBreakerBox.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity >0.5.13 <0.9;\npragma experimental ABIEncoderV2;\n\nimport { ISortedOracles } from \"./ISortedOracles.sol\";\n\n/**\n * @title Breaker Box Interface\n * @notice Defines the basic interface for the Breaker Box\n */\ninterface IBreakerBox {\n  /**\n   * @dev Used to keep track of the status of a breaker for a specific rate feed.\n   *\n   * - TradingMode: Represents the trading mode the breaker is in for a rate feed.\n   *                This uses a bitmask approach, meaning each bit represents a\n   *                different trading mode. The final trading mode of the rate feed\n   *                is obtained by applying a logical OR operation to the TradingMode\n   *                of all breakers associated with that rate feed. This allows multiple\n   *                breakers to contribute to the final trading mode simultaneously.\n   *                Possible values:\n   *                0: bidirectional trading.\n   *                1: inflow only.\n   *                2: outflow only.\n   *                3: trading halted.\n   *\n   * - LastUpdatedTime: Records the last time the breaker status was updated. This is\n   *                    used to manage cooldown periods before the breaker can be reset.\n   *\n   * - Enabled:     Indicates whether the breaker is enabled for the associated rate feed.\n   */\n  struct BreakerStatus {\n    uint8 tradingMode;\n    uint64 lastUpdatedTime;\n    bool enabled;\n  }\n\n  /**\n   * @notice Emitted when a new breaker is added to the breaker box.\n   * @param breaker The address of the breaker.\n   */\n  event BreakerAdded(address indexed breaker);\n\n  /**\n   * @notice Emitted when a breaker is removed from the breaker box.\n   * @param breaker The address of the breaker.\n   */\n  event BreakerRemoved(address indexed breaker);\n\n  /**\n   * @notice Emitted when a breaker is tripped by a rate feed.\n   * @param breaker The address of the breaker.\n   * @param rateFeedID The address of the rate feed.\n   */\n  event BreakerTripped(address indexed breaker, address indexed rateFeedID);\n\n  /**\n   * @notice Emitted when a new rate feed is added to the breaker box.\n   * @param rateFeedID The address of the rate feed.\n   */\n  event RateFeedAdded(address indexed rateFeedID);\n\n  /**\n   * @notice Emitted when dependencies for a rate feed are set.\n   * @param rateFeedID The address of the rate feed.\n   * @param dependencies The addresses of the dependendent rate feeds.\n   */\n  event RateFeedDependenciesSet(address indexed rateFeedID, address[] indexed dependencies);\n\n  /**\n   * @notice Emitted when a rate feed is removed from the breaker box.\n   * @param rateFeedID The address of the rate feed.\n   */\n  event RateFeedRemoved(address indexed rateFeedID);\n\n  /**\n   * @notice Emitted when the trading mode for a rate feed is updated\n   * @param rateFeedID The address of the rate feed.\n   * @param tradingMode The new trading mode.\n   */\n  event TradingModeUpdated(address indexed rateFeedID, uint256 tradingMode);\n\n  /**\n   * @notice Emitted after a reset attempt is successful.\n   * @param rateFeedID The address of the rate feed.\n   * @param breaker The address of the breaker.\n   */\n  event ResetSuccessful(address indexed rateFeedID, address indexed breaker);\n\n  /**\n   * @notice  Emitted after a reset attempt fails when the\n   *          rate feed fails the breakers reset criteria.\n   * @param rateFeedID The address of the rate feed.\n   * @param breaker The address of the breaker.\n   */\n  event ResetAttemptCriteriaFail(address indexed rateFeedID, address indexed breaker);\n\n  /**\n   * @notice Emitted after a reset attempt fails when cooldown time has not elapsed.\n   * @param rateFeedID The address of the rate feed.\n   * @param breaker The address of the breaker.\n   */\n  event ResetAttemptNotCool(address indexed rateFeedID, address indexed breaker);\n\n  /**\n   * @notice Emitted when the sortedOracles address is updated.\n   * @param newSortedOracles The address of the new sortedOracles.\n   */\n  event SortedOraclesUpdated(address indexed newSortedOracles);\n\n  /**\n   * @notice Emitted when the breaker is enabled or disabled for a rate feed.\n   * @param breaker The address of the breaker.\n   * @param rateFeedID The address of the rate feed.\n   * @param status Indicating the status.\n   */\n  event BreakerStatusUpdated(address breaker, address rateFeedID, bool status);\n\n  /**\n   * @notice Retrives an array of all breaker addresses.\n   */\n  function getBreakers() external view returns (address[] memory);\n\n  /**\n   * @notice Checks if a breaker with the specified address has been added to the breaker box.\n   * @param breaker The address of the breaker to check;\n   * @return A bool indicating whether or not the breaker has been added.\n   */\n  function isBreaker(address breaker) external view returns (bool);\n\n  /**\n   * @notice Checks breakers for the rateFeedID and sets correct trading mode\n   * if any breakers are tripped or need to be reset.\n   * @param rateFeedID The address of the rate feed to run checks for.\n   */\n  function checkAndSetBreakers(address rateFeedID) external;\n\n  /**\n   * @notice Gets the trading mode for the specified rateFeedID.\n   * @param rateFeedID The address of the rate feed to retrieve the trading mode for.\n   */\n  function getRateFeedTradingMode(address rateFeedID) external view returns (uint8 tradingMode);\n\n  /**\n   * @notice Adds a breaker to the end of the list of breakers & the breakerTradingMode mapping.\n   * @param breaker The address of the breaker to be added.\n   * @param tradingMode The trading mode of the breaker to be added.\n   */\n  function addBreaker(address breaker, uint8 tradingMode) external;\n\n  /**\n   * @notice Removes the specified breaker from the list of breakers\n   *         and resets breakerTradingMode mapping + BreakerStatus.\n   * @param breaker The address of the breaker to be removed.\n   */\n  function removeBreaker(address breaker) external;\n\n  /**\n   * @notice Enables or disables a breaker for the specified rate feed.\n   * @param breakerAddress The address of the breaker.\n   * @param rateFeedID The address of the rateFeed to be toggled.\n   * @param enable Boolean indicating whether the breaker should be\n   *               enabled or disabled for the given rateFeed.\n   */\n  function toggleBreaker(address breakerAddress, address rateFeedID, bool enable) external;\n\n  /**\n   * @notice Adds a rateFeedID to the mapping of monitored rateFeedIDs.\n   * @param rateFeedID The address of the rateFeed to be added.\n   */\n  function addRateFeed(address rateFeedID) external;\n\n  /**\n   * @notice Adds the specified rateFeedIDs to the mapping of monitored rateFeedIDs.\n   * @param newRateFeedIDs The array of rateFeed addresses to be added.\n   */\n  function addRateFeeds(address[] calldata newRateFeedIDs) external;\n\n  /**\n   * @notice Sets dependent rate feeds for a given rate feed.\n   * @param rateFeedID The address of the rate feed.\n   * @param dependencies The array of dependent rate feeds.\n   */\n  function setRateFeedDependencies(address rateFeedID, address[] calldata dependencies) external;\n\n  /**\n   * @notice Removes a rateFeed from the mapping of monitored rateFeeds\n   *         and resets all the BreakerStatus entries for that rateFeed.\n   * @param rateFeedID The address of the rateFeed to be removed.\n   */\n  function removeRateFeed(address rateFeedID) external;\n\n  /**\n   * @notice Sets the trading mode for the specified rateFeed.\n   * @param rateFeedID The address of the rateFeed.\n   * @param tradingMode The trading mode that should be set.\n   */\n  function setRateFeedTradingMode(address rateFeedID, uint8 tradingMode) external;\n\n  /**\n   * @notice Returns addresses of rateFeedIDs that have been added.\n   */\n  function getRateFeeds() external view returns (address[] memory);\n\n  /**\n   * @notice Checks if a breaker is enabled for a specific rate feed.\n   * @param breaker The address of the breaker we're checking for.\n   * @param rateFeedID The address of the rateFeed.\n   */\n  function isBreakerEnabled(address breaker, address rateFeedID) external view returns (bool);\n\n  /**\n   * @notice Sets the address of the sortedOracles contract.\n   * @param _sortedOracles The new address of the sorted oracles contract.\n   */\n  function setSortedOracles(ISortedOracles _sortedOracles) external;\n\n  /// @notice Public state variable getters:\n  function breakerTradingMode(address) external view returns (uint8);\n\n  function sortedOracles() external view returns (address);\n\n  function rateFeedStatus(address) external view returns (bool);\n\n  function owner() external view returns (address);\n\n  function rateFeedBreakerStatus(address, address) external view returns (BreakerStatus memory);\n\n  function rateFeedDependencies(address, uint256) external view returns (address);\n\n  function rateFeedTradingMode(address) external view returns (uint8);\n}\n"},{"file_path":"lib/mento-core-2.6.5/contracts/interfaces/IERC20.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity >=0.5.13 <0.9.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP. Does not include\n * the optional functions; to access them see {ERC20Detailed}.\n */\ninterface IERC20 {\n  /**\n   * @dev Returns the name of the token.\n   */\n  function name() external view returns (string memory);\n\n  /**\n   * @dev Returns the symbol of the token.\n   */\n  function symbol() external view returns (string memory);\n\n  /**\n   * @dev Returns the decimals places of the token.\n   */\n  function decimals() external view returns (uint8);\n\n  /**\n   * @dev Returns the amount of tokens in existence.\n   */\n  function totalSupply() external view returns (uint256);\n\n  /**\n   * @dev Returns the amount of tokens owned by `account`.\n   */\n  function balanceOf(address account) external view returns (uint256);\n\n  /**\n   * @dev Moves `amount` tokens from the caller's account to `recipient`.\n   *\n   * Returns a boolean value indicating whether the operation succeeded.\n   *\n   * Emits a {Transfer} event.\n   */\n  function transfer(address recipient, uint256 amount) external returns (bool);\n\n  /**\n   * @dev Returns the remaining number of tokens that `spender` will be\n   * allowed to spend on behalf of `owner` through {transferFrom}. This is\n   * zero by default.\n   *\n   * This value changes when {approve} or {transferFrom} are called.\n   */\n  function allowance(address owner, address spender) external view returns (uint256);\n\n  /**\n   * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n   *\n   * Returns a boolean value indicating whether the operation succeeded.\n   *\n   * IMPORTANT: Beware that changing an allowance with this method brings the risk\n   * that someone may use both the old and the new allowance by unfortunate\n   * transaction ordering. One possible solution to mitigate this race\n   * condition is to first reduce the spender's allowance to 0 and set the\n   * desired value afterwards:\n   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n   *\n   * Emits an {Approval} event.\n   */\n  function approve(address spender, uint256 amount) external returns (bool);\n\n  /**\n   * @dev Moves `amount` tokens from `sender` to `recipient` using the\n   * allowance mechanism. `amount` is then deducted from the caller's\n   * allowance.\n   *\n   * Returns a boolean value indicating whether the operation succeeded.\n   *\n   * Emits a {Transfer} event.\n   */\n  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n  /**\n   * @dev Emitted when `value` tokens are moved from one account (`from`) to\n   * another (`to`).\n   *\n   * Note that `value` may be zero.\n   */\n  event Transfer(address indexed from, address indexed to, uint256 value);\n\n  /**\n   * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n   * a call to {approve}. `value` is the new allowance.\n   */\n  event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},{"file_path":"lib/mento-core-2.6.5/contracts/interfaces/IExchangeProvider.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity >0.5.13 <0.9;\npragma experimental ABIEncoderV2;\n\n/**\n * @title ExchangeProvider interface\n * @notice The IExchangeProvider interface is the interface that the Broker uses\n * to communicate with different exchange manager implementations like the BiPoolManager\n */\ninterface IExchangeProvider {\n  /**\n   * @notice Exchange - a struct that's used only by UIs (frontends/CLIs)\n   * in order to discover what asset swaps are possible within an\n   * exchange provider.\n   * It's up to the specific exchange provider to convert its internal\n   * representation to this universal struct. This conversion should\n   * only happen in view calls used for discovery.\n   * @param exchangeId The ID of the exchange, used to initiate swaps or get quotes.\n   * @param assets An array of addresses of ERC20 tokens that can be swapped.\n   */\n  struct Exchange {\n    bytes32 exchangeId;\n    address[] assets;\n  }\n\n  /**\n   * @notice Get all exchanges supported by the ExchangeProvider.\n   * @return exchanges An array of Exchange structs.\n   */\n  function getExchanges() external view returns (Exchange[] memory exchanges);\n\n  /**\n   * @notice Execute a token swap with fixed amountIn\n   * @param exchangeId The id of the exchange to use\n   * @param tokenIn The token to be sold\n   * @param tokenOut The token to be bought\n   * @param amountIn The amount of tokenIn to be sold\n   * @return amountOut The amount of tokenOut to be bought\n   */\n  function swapIn(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountIn\n  ) external returns (uint256 amountOut);\n\n  /**\n   * @notice Execute a token swap with fixed amountOut\n   * @param exchangeId The id of the exchange to use\n   * @param tokenIn The token to be sold\n   * @param tokenOut The token to be bought\n   * @param amountOut The amount of tokenOut to be bought\n   * @return amountIn The amount of tokenIn to be sold\n   */\n  function swapOut(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountOut\n  ) external returns (uint256 amountIn);\n\n  /**\n   * @notice Calculate amountOut of tokenOut received for a given amountIn of tokenIn\n   * @param exchangeId The id of the exchange to use\n   * @param tokenIn The token to be sold\n   * @param tokenOut The token to be bought\n   * @param amountIn The amount of tokenIn to be sold\n   * @return amountOut The amount of tokenOut to be bought\n   */\n  function getAmountOut(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountIn\n  ) external view returns (uint256 amountOut);\n\n  /**\n   * @notice Calculate amountIn of tokenIn needed for a given amountOut of tokenOut\n   * @param exchangeId The ID of the pool to use\n   * @param tokenIn The token to be sold\n   * @param tokenOut The token to be bought\n   * @param amountOut The amount of tokenOut to be bought\n   * @return amountIn The amount of tokenIn to be sold\n   */\n  function getAmountIn(\n    bytes32 exchangeId,\n    address tokenIn,\n    address tokenOut,\n    uint256 amountOut\n  ) external view returns (uint256 amountIn);\n}\n"},{"file_path":"lib/mento-core-2.6.5/contracts/interfaces/IPricingModule.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity >0.5.13 <0.9;\n\n/**\n * @title Interface for a Mento Pricing Module.\n * @notice A Mento pricing module represents an exchange relation between a pair of ERC20 assets.\n */\ninterface IPricingModule {\n  /**\n   * @notice Returns the output amount and new bucket sizes for a given input amount.\n   * @param tokenInBucketSize Size of the tokenIn bucket.\n   * @param tokenOutBucketSize Size of the tokenOut bucket.\n   * @param spread Spread charged on exchanges.\n   * @param amountIn Amount of tokenIn being paid in.\n   * @return amountOut Amount of tokenOut that will be paid out.\n   */\n  function getAmountOut(\n    uint256 tokenInBucketSize,\n    uint256 tokenOutBucketSize,\n    uint256 spread,\n    uint256 amountIn\n  ) external view returns (uint256 amountOut);\n\n  /**\n   * @notice Returns the input amount necessary for a given output amount.\n   * @param tokenInBucketSize Size of the tokenIn bucket.\n   * @param tokenOutBucketSize Size of the tokenOut bucket.\n   * @param spread Spread charged on exchanges.\n   * @param amountOut Amount of tokenIn being paid out.\n   * @return amountIn Amount of tokenOut that would have to be paid in.\n   */\n  function getAmountIn(\n    uint256 tokenInBucketSize,\n    uint256 tokenOutBucketSize,\n    uint256 spread,\n    uint256 amountOut\n  ) external view returns (uint256 amountIn);\n\n  /**\n   * @notice Retrieve the name of this pricing module.\n   * @return pricingModuleName The name of the pricing module.\n   */\n  function name() external view returns (string memory pricingModuleName);\n}\n"},{"file_path":"lib/mento-core-2.6.5/contracts/interfaces/IReserve.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity >0.5.13 <0.9;\n\ninterface IReserve {\n  function setTobinTaxStalenessThreshold(uint256) external;\n\n  function addToken(address) external returns (bool);\n\n  function removeToken(address, uint256) external returns (bool);\n\n  function transferGold(address payable, uint256) external returns (bool);\n\n  function transferExchangeGold(address payable, uint256) external returns (bool);\n\n  function transferCollateralAsset(address collateralAsset, address payable to, uint256 value) external returns (bool);\n\n  function getReserveGoldBalance() external view returns (uint256);\n\n  function getUnfrozenReserveGoldBalance() external view returns (uint256);\n\n  function getOrComputeTobinTax() external returns (uint256, uint256);\n\n  function getTokens() external view returns (address[] memory);\n\n  function getReserveRatio() external view returns (uint256);\n\n  function addExchangeSpender(address) external;\n\n  function removeExchangeSpender(address, uint256) external;\n\n  function addSpender(address) external;\n\n  function removeSpender(address) external;\n\n  function isStableAsset(address) external view returns (bool);\n\n  function isCollateralAsset(address) external view returns (bool);\n\n  function getDailySpendingRatioForCollateralAsset(address collateralAsset) external view returns (uint256);\n\n  function isExchangeSpender(address exchange) external view returns (bool);\n\n  function addCollateralAsset(address asset) external returns (bool);\n\n  function transferExchangeCollateralAsset(\n    address collateralAsset,\n    address payable to,\n    uint256 value\n  ) external returns (bool);\n\n  function initialize(\n    address registryAddress,\n    uint256 _tobinTaxStalenessThreshold,\n    uint256 _spendingRatioForCelo,\n    uint256 _frozenGold,\n    uint256 _frozenDays,\n    bytes32[] calldata _assetAllocationSymbols,\n    uint256[] calldata _assetAllocationWeights,\n    uint256 _tobinTax,\n    uint256 _tobinTaxReserveRatio,\n    address[] calldata _collateralAssets,\n    uint256[] calldata _collateralAssetDailySpendingRatios\n  ) external;\n\n  /// @notice IOwnable:\n  function transferOwnership(address newOwner) external;\n\n  function renounceOwnership() external;\n\n  function owner() external view returns (address);\n\n  /// @notice Getters:\n  function registry() external view returns (address);\n\n  function tobinTaxStalenessThreshold() external view returns (uint256);\n\n  function tobinTax() external view returns (uint256);\n\n  function tobinTaxReserveRatio() external view returns (uint256);\n\n  function getDailySpendingRatio() external view returns (uint256);\n\n  function checkIsCollateralAsset(address collateralAsset) external view returns (bool);\n\n  function isToken(address) external view returns (bool);\n\n  function getOtherReserveAddresses() external view returns (address[] memory);\n\n  function getAssetAllocationSymbols() external view returns (bytes32[] memory);\n\n  function getAssetAllocationWeights() external view returns (uint256[] memory);\n\n  function collateralAssetSpendingLimit(address) external view returns (uint256);\n\n  function getExchangeSpenders() external view returns (address[] memory);\n\n  function getUnfrozenBalance() external view returns (uint256);\n\n  function isOtherReserveAddress(address otherReserveAddress) external view returns (bool);\n\n  function isSpender(address spender) external view returns (bool);\n\n  /// @notice Setters:\n  function setRegistry(address) external;\n\n  function setTobinTax(uint256) external;\n\n  function setTobinTaxReserveRatio(uint256) external;\n\n  function setDailySpendingRatio(uint256 spendingRatio) external;\n\n  function setDailySpendingRatioForCollateralAssets(\n    address[] calldata _collateralAssets,\n    uint256[] calldata collateralAssetDailySpendingRatios\n  ) external;\n\n  function setFrozenGold(uint256 frozenGold, uint256 frozenDays) external;\n\n  function setAssetAllocations(bytes32[] calldata symbols, uint256[] calldata weights) external;\n\n  function removeCollateralAsset(address collateralAsset, uint256 index) external returns (bool);\n\n  function addOtherReserveAddress(address otherReserveAddress) external returns (bool);\n\n  function removeOtherReserveAddress(address otherReserveAddress, uint256 index) external returns (bool);\n\n  function collateralAssets(uint256 index) external view returns (address);\n\n  function collateralAssetLastSpendingDay(address collateralAsset) external view returns (uint256);\n}\n"},{"file_path":"lib/mento-core-2.6.5/contracts/interfaces/ISortedOracles.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity >0.5.13 <0.9;\n\nimport { IBreakerBox } from \"./IBreakerBox.sol\";\n\ninterface ISortedOracles {\n  enum MedianRelation {\n    Undefined,\n    Lesser,\n    Greater,\n    Equal\n  }\n\n  function addOracle(address, address) external;\n\n  function removeOracle(address, address, uint256) external;\n\n  function report(address, uint256, address, address) external;\n\n  function removeExpiredReports(address, uint256) external;\n\n  function isOldestReportExpired(address token) external view returns (bool, address);\n\n  function numRates(address) external view returns (uint256);\n\n  function medianRate(address) external view returns (uint256, uint256);\n\n  function numTimestamps(address) external view returns (uint256);\n\n  function medianTimestamp(address) external view returns (uint256);\n\n  function getOracles(address) external view returns (address[] memory);\n\n  function getRates(address token) external view returns (address[] memory, uint256[] memory, MedianRelation[] memory);\n\n  function getTimestamps(\n    address token\n  ) external view returns (address[] memory, uint256[] memory, MedianRelation[] memory);\n\n  function initialize(uint256) external;\n\n  function setBreakerBox(IBreakerBox) external;\n\n  function getTokenReportExpirySeconds(address token) external view returns (uint256);\n\n  function oracles(address, uint256) external view returns (address);\n\n  function breakerBox() external view returns (IBreakerBox);\n}\n"},{"file_path":"node_modules/@celo/contracts/common/FixidityLib.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\n/**\n * @title FixidityLib\n * @author Gadi Guy, Alberto Cuesta Canada\n * @notice This library provides fixed point arithmetic with protection against\n * overflow.\n * All operations are done with uint256 and the operands must have been created\n * with any of the newFrom* functions, which shift the comma digits() to the\n * right and check for limits, or with wrap() which expects a number already\n * in the internal representation of a fraction.\n * When using this library be sure to use maxNewFixed() as the upper limit for\n * creation of fixed point numbers.\n * @dev All contained functions are pure and thus marked internal to be inlined\n * on consuming contracts at compile time for gas efficiency.\n */\nlibrary FixidityLib {\n  struct Fraction {\n    uint256 value;\n  }\n\n  /**\n   * @notice Number of positions that the comma is shifted to the right.\n   */\n  function digits() internal pure returns (uint8) {\n    return 24;\n  }\n\n  uint256 private constant FIXED1_UINT = 1000000000000000000000000;\n\n  /**\n   * @notice This is 1 in the fixed point units used in this library.\n   * @dev Test fixed1() equals 10^digits()\n   * Hardcoded to 24 digits.\n   */\n  function fixed1() internal pure returns (Fraction memory) {\n    return Fraction(FIXED1_UINT);\n  }\n\n  /**\n   * @notice Wrap a uint256 that represents a 24-decimal fraction in a Fraction\n   * struct.\n   * @param x Number that already represents a 24-decimal fraction.\n   * @return A Fraction struct with contents x.\n   */\n  function wrap(uint256 x) internal pure returns (Fraction memory) {\n    return Fraction(x);\n  }\n\n  /**\n   * @notice Unwraps the uint256 inside of a Fraction struct.\n   */\n  function unwrap(Fraction memory x) internal pure returns (uint256) {\n    return x.value;\n  }\n\n  /**\n   * @notice The amount of decimals lost on each multiplication operand.\n   * @dev Test mulPrecision() equals sqrt(fixed1)\n   */\n  function mulPrecision() internal pure returns (uint256) {\n    return 1000000000000;\n  }\n\n  /**\n   * @notice Maximum value that can be converted to fixed point. Optimize for deployment.\n   * @dev\n   * Test maxNewFixed() equals maxUint256() / fixed1()\n   */\n  function maxNewFixed() internal pure returns (uint256) {\n    return 115792089237316195423570985008687907853269984665640564;\n  }\n\n  /**\n   * @notice Converts a uint256 to fixed point Fraction\n   * @dev Test newFixed(0) returns 0\n   * Test newFixed(1) returns fixed1()\n   * Test newFixed(maxNewFixed()) returns maxNewFixed() * fixed1()\n   * Test newFixed(maxNewFixed()+1) fails\n   */\n  function newFixed(uint256 x) internal pure returns (Fraction memory) {\n    require(x <= maxNewFixed(), \"can't create fixidity number larger than maxNewFixed()\");\n    return Fraction(x * FIXED1_UINT);\n  }\n\n  /**\n   * @notice Converts a uint256 in the fixed point representation of this\n   * library to a non decimal. All decimal digits will be truncated.\n   */\n  function fromFixed(Fraction memory x) internal pure returns (uint256) {\n    return x.value / FIXED1_UINT;\n  }\n\n  /**\n   * @notice Converts two uint256 representing a fraction to fixed point units,\n   * equivalent to multiplying dividend and divisor by 10^digits().\n   * @param numerator numerator must be <= maxNewFixed()\n   * @param denominator denominator must be <= maxNewFixed() and denominator can't be 0\n   * @dev\n   * Test newFixedFraction(1,0) fails\n   * Test newFixedFraction(0,1) returns 0\n   * Test newFixedFraction(1,1) returns fixed1()\n   * Test newFixedFraction(1,fixed1()) returns 1\n   */\n  function newFixedFraction(uint256 numerator, uint256 denominator)\n    internal\n    pure\n    returns (Fraction memory)\n  {\n    Fraction memory convertedNumerator = newFixed(numerator);\n    Fraction memory convertedDenominator = newFixed(denominator);\n    return divide(convertedNumerator, convertedDenominator);\n  }\n\n  /**\n   * @notice Returns the integer part of a fixed point number.\n   * @dev\n   * Test integer(0) returns 0\n   * Test integer(fixed1()) returns fixed1()\n   * Test integer(newFixed(maxNewFixed())) returns maxNewFixed()*fixed1()\n   */\n  function integer(Fraction memory x) internal pure returns (Fraction memory) {\n    return Fraction((x.value / FIXED1_UINT) * FIXED1_UINT); // Can't overflow\n  }\n\n  /**\n   * @notice Returns the fractional part of a fixed point number.\n   * In the case of a negative number the fractional is also negative.\n   * @dev\n   * Test fractional(0) returns 0\n   * Test fractional(fixed1()) returns 0\n   * Test fractional(fixed1()-1) returns 10^24-1\n   */\n  function fractional(Fraction memory x) internal pure returns (Fraction memory) {\n    return Fraction(x.value - (x.value / FIXED1_UINT) * FIXED1_UINT); // Can't overflow\n  }\n\n  /**\n   * @notice x+y.\n   * @dev The maximum value that can be safely used as an addition operator is defined as\n   * maxFixedAdd = maxUint256()-1 / 2, or\n   * 57896044618658097711785492504343953926634992332820282019728792003956564819967.\n   * Test add(maxFixedAdd,maxFixedAdd) equals maxFixedAdd + maxFixedAdd\n   * Test add(maxFixedAdd+1,maxFixedAdd+1) throws\n   */\n  function add(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {\n    uint256 z = x.value + y.value;\n    require(z >= x.value, \"add overflow detected\");\n    return Fraction(z);\n  }\n\n  /**\n   * @notice x-y.\n   * @dev\n   * Test subtract(6, 10) fails\n   */\n  function subtract(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {\n    require(x.value >= y.value, \"substraction underflow detected\");\n    return Fraction(x.value - y.value);\n  }\n\n  /**\n   * @notice x*y. If any of the operators is higher than the max multiplier value it\n   * might overflow.\n   * @dev The maximum value that can be safely used as a multiplication operator\n   * (maxFixedMul) is calculated as sqrt(maxUint256()*fixed1()),\n   * or 340282366920938463463374607431768211455999999999999\n   * Test multiply(0,0) returns 0\n   * Test multiply(maxFixedMul,0) returns 0\n   * Test multiply(0,maxFixedMul) returns 0\n   * Test multiply(fixed1()/mulPrecision(),fixed1()*mulPrecision()) returns fixed1()\n   * Test multiply(maxFixedMul,maxFixedMul) is around maxUint256()\n   * Test multiply(maxFixedMul+1,maxFixedMul+1) fails\n   */\n  function multiply(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {\n    if (x.value == 0 || y.value == 0) return Fraction(0);\n    if (y.value == FIXED1_UINT) return x;\n    if (x.value == FIXED1_UINT) return y;\n\n    // Separate into integer and fractional parts\n    // x = x1 + x2, y = y1 + y2\n    uint256 x1 = integer(x).value / FIXED1_UINT;\n    uint256 x2 = fractional(x).value;\n    uint256 y1 = integer(y).value / FIXED1_UINT;\n    uint256 y2 = fractional(y).value;\n\n    // (x1 + x2) * (y1 + y2) = (x1 * y1) + (x1 * y2) + (x2 * y1) + (x2 * y2)\n    uint256 x1y1 = x1 * y1;\n    if (x1 != 0) require(x1y1 / x1 == y1, \"overflow x1y1 detected\");\n\n    // x1y1 needs to be multiplied back by fixed1\n    // solium-disable-next-line mixedcase\n    uint256 fixed_x1y1 = x1y1 * FIXED1_UINT;\n    if (x1y1 != 0) require(fixed_x1y1 / x1y1 == FIXED1_UINT, \"overflow x1y1 * fixed1 detected\");\n    x1y1 = fixed_x1y1;\n\n    uint256 x2y1 = x2 * y1;\n    if (x2 != 0) require(x2y1 / x2 == y1, \"overflow x2y1 detected\");\n\n    uint256 x1y2 = x1 * y2;\n    if (x1 != 0) require(x1y2 / x1 == y2, \"overflow x1y2 detected\");\n\n    x2 = x2 / mulPrecision();\n    y2 = y2 / mulPrecision();\n    uint256 x2y2 = x2 * y2;\n    if (x2 != 0) require(x2y2 / x2 == y2, \"overflow x2y2 detected\");\n\n    // result = fixed1() * x1 * y1 + x1 * y2 + x2 * y1 + x2 * y2 / fixed1();\n    Fraction memory result = Fraction(x1y1);\n    result = add(result, Fraction(x2y1)); // Add checks for overflow\n    result = add(result, Fraction(x1y2)); // Add checks for overflow\n    result = add(result, Fraction(x2y2)); // Add checks for overflow\n    return result;\n  }\n\n  /**\n   * @notice 1/x\n   * @dev\n   * Test reciprocal(0) fails\n   * Test reciprocal(fixed1()) returns fixed1()\n   * Test reciprocal(fixed1()*fixed1()) returns 1 // Testing how the fractional is truncated\n   * Test reciprocal(1+fixed1()*fixed1()) returns 0 // Testing how the fractional is truncated\n   * Test reciprocal(newFixedFraction(1, 1e24)) returns newFixed(1e24)\n   */\n  function reciprocal(Fraction memory x) internal pure returns (Fraction memory) {\n    require(x.value != 0, \"can't call reciprocal(0)\");\n    return Fraction((FIXED1_UINT * FIXED1_UINT) / x.value); // Can't overflow\n  }\n\n  /**\n   * @notice x/y. If the dividend is higher than the max dividend value, it\n   * might overflow. You can use multiply(x,reciprocal(y)) instead.\n   * @dev The maximum value that can be safely used as a dividend (maxNewFixed) is defined as\n   * divide(maxNewFixed,newFixedFraction(1,fixed1())) is around maxUint256().\n   * This yields the value 115792089237316195423570985008687907853269984665640564.\n   * Test maxNewFixed equals maxUint256()/fixed1()\n   * Test divide(maxNewFixed,1) equals maxNewFixed*(fixed1)\n   * Test divide(maxNewFixed+1,multiply(mulPrecision(),mulPrecision())) throws\n   * Test divide(fixed1(),0) fails\n   * Test divide(maxNewFixed,1) = maxNewFixed*(10^digits())\n   * Test divide(maxNewFixed+1,1) throws\n   */\n  function divide(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {\n    require(y.value != 0, \"can't divide by 0\");\n    uint256 X = x.value * FIXED1_UINT;\n    require(X / FIXED1_UINT == x.value, \"overflow at divide\");\n    return Fraction(X / y.value);\n  }\n\n  /**\n   * @notice x > y\n   */\n  function gt(Fraction memory x, Fraction memory y) internal pure returns (bool) {\n    return x.value > y.value;\n  }\n\n  /**\n   * @notice x >= y\n   */\n  function gte(Fraction memory x, Fraction memory y) internal pure returns (bool) {\n    return x.value >= y.value;\n  }\n\n  /**\n   * @notice x < y\n   */\n  function lt(Fraction memory x, Fraction memory y) internal pure returns (bool) {\n    return x.value < y.value;\n  }\n\n  /**\n   * @notice x <= y\n   */\n  function lte(Fraction memory x, Fraction memory y) internal pure returns (bool) {\n    return x.value <= y.value;\n  }\n\n  /**\n   * @notice x == y\n   */\n  function equals(Fraction memory x, Fraction memory y) internal pure returns (bool) {\n    return x.value == y.value;\n  }\n\n  /**\n   * @notice x <= 1\n   */\n  function isProperFraction(Fraction memory x) internal pure returns (bool) {\n    return lte(x, fixed1());\n  }\n}\n"},{"file_path":"node_modules/@celo/contracts/common/Initializable.sol","source_code":"// SPDX-License-Identifier: LGPL-3.0-only\npragma solidity >=0.5.13 <0.9.0;\n\ncontract Initializable {\n  bool public initialized;\n\n  constructor(bool testingDeployment) public {\n    if (!testingDeployment) {\n      initialized = true;\n    }\n  }\n\n  modifier initializer() {\n    require(!initialized, \"contract already initialized\");\n    initialized = true;\n    _;\n  }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"bool","name":"test","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newBreakerBox","type":"address"}],"name":"BreakerBoxUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newBroker","type":"address"}],"name":"BrokerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"bucket0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bucket1","type":"uint256"}],"name":"BucketsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"asset0","type":"address"},{"indexed":true,"internalType":"address","name":"asset1","type":"address"},{"indexed":false,"internalType":"address","name":"pricingModule","type":"address"}],"name":"ExchangeCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"asset0","type":"address"},{"indexed":true,"internalType":"address","name":"asset1","type":"address"},{"indexed":false,"internalType":"address","name":"pricingModule","type":"address"}],"name":"ExchangeDestroyed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32[]","name":"newIdentifiers","type":"bytes32[]"},{"indexed":false,"internalType":"address[]","name":"newAddresses","type":"address[]"}],"name":"PricingModulesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newReserve","type":"address"}],"name":"ReserveUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newSortedOracles","type":"address"}],"name":"SortedOraclesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"spread","type":"uint256"}],"name":"SpreadUpdated","type":"event"},{"constant":true,"inputs":[],"name":"CONSTANT_PRODUCT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"CONSTANT_SUM","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"breakerBox","outputs":[{"internalType":"contract IBreakerBox","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"broker","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"components":[{"internalType":"address","name":"asset0","type":"address"},{"internalType":"address","name":"asset1","type":"address"},{"internalType":"contract IPricingModule","name":"pricingModule","type":"address"},{"internalType":"uint256","name":"bucket0","type":"uint256"},{"internalType":"uint256","name":"bucket1","type":"uint256"},{"internalType":"uint256","name":"lastBucketUpdate","type":"uint256"},{"components":[{"components":[{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct FixidityLib.Fraction","name":"spread","type":"tuple"},{"internalType":"address","name":"referenceRateFeedID","type":"address"},{"internalType":"uint256","name":"referenceRateResetFrequency","type":"uint256"},{"internalType":"uint256","name":"minimumReports","type":"uint256"},{"internalType":"uint256","name":"stablePoolResetSize","type":"uint256"}],"internalType":"struct IBiPoolManager.PoolConfig","name":"config","type":"tuple"}],"internalType":"struct IBiPoolManager.PoolExchange","name":"_exchange","type":"tuple"}],"name":"createExchange","outputs":[{"internalType":"bytes32","name":"exchangeId","type":"bytes32"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"uint256","name":"exchangeIdIndex","type":"uint256"}],"name":"destroyExchange","outputs":[{"internalType":"bool","name":"destroyed","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"exchangeIds","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"exchanges","outputs":[{"internalType":"address","name":"asset0","type":"address"},{"internalType":"address","name":"asset1","type":"address"},{"internalType":"contract IPricingModule","name":"pricingModule","type":"address"},{"internalType":"uint256","name":"bucket0","type":"uint256"},{"internalType":"uint256","name":"bucket1","type":"uint256"},{"internalType":"uint256","name":"lastBucketUpdate","type":"uint256"},{"components":[{"components":[{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct FixidityLib.Fraction","name":"spread","type":"tuple"},{"internalType":"address","name":"referenceRateFeedID","type":"address"},{"internalType":"uint256","name":"referenceRateResetFrequency","type":"uint256"},{"internalType":"uint256","name":"minimumReports","type":"uint256"},{"internalType":"uint256","name":"stablePoolResetSize","type":"uint256"}],"internalType":"struct IBiPoolManager.PoolConfig","name":"config","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getExchangeIds","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getExchanges","outputs":[{"components":[{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address[]","name":"assets","type":"address[]"}],"internalType":"struct IExchangeProvider.Exchange[]","name":"_exchanges","type":"tuple[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"exchangeId","type":"bytes32"}],"name":"getPoolExchange","outputs":[{"components":[{"internalType":"address","name":"asset0","type":"address"},{"internalType":"address","name":"asset1","type":"address"},{"internalType":"contract IPricingModule","name":"pricingModule","type":"address"},{"internalType":"uint256","name":"bucket0","type":"uint256"},{"internalType":"uint256","name":"bucket1","type":"uint256"},{"internalType":"uint256","name":"lastBucketUpdate","type":"uint256"},{"components":[{"components":[{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct FixidityLib.Fraction","name":"spread","type":"tuple"},{"internalType":"address","name":"referenceRateFeedID","type":"address"},{"internalType":"uint256","name":"referenceRateResetFrequency","type":"uint256"},{"internalType":"uint256","name":"minimumReports","type":"uint256"},{"internalType":"uint256","name":"stablePoolResetSize","type":"uint256"}],"internalType":"struct IBiPoolManager.PoolConfig","name":"config","type":"tuple"}],"internalType":"struct IBiPoolManager.PoolExchange","name":"exchange","type":"tuple"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_broker","type":"address"},{"internalType":"contract IReserve","name":"_reserve","type":"address"},{"internalType":"contract ISortedOracles","name":"_sortedOracles","type":"address"},{"internalType":"contract IBreakerBox","name":"_breakerBox","type":"address"}],"name":"initialize","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"initialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"pricingModules","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"reserve","outputs":[{"internalType":"contract IReserve","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IBreakerBox","name":"_breakerBox","type":"address"}],"name":"setBreakerBox","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_broker","type":"address"}],"name":"setBroker","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32[]","name":"identifiers","type":"bytes32[]"},{"internalType":"address[]","name":"modules","type":"address[]"}],"name":"setPricingModules","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IReserve","name":"_reserve","type":"address"}],"name":"setReserve","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract ISortedOracles","name":"_sortedOracles","type":"address"}],"name":"setSortedOracles","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"uint256","name":"spread","type":"uint256"}],"name":"setSpread","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"sortedOracles","outputs":[{"internalType":"contract ISortedOracles","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountIn","type":"uint256"}],"name":"swapIn","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"}],"name":"swapOut","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenPrecisionMultipliers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":"0x0000000000000000000000000000000000000000000000000000000000000000"}