{"file_path":"lib/mento-core/contracts/swap/FPMM.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity 0.8.24;\n\nimport \"../interfaces/IFPMM.sol\";\nimport \"./router/interfaces/IRPool.sol\";\nimport { ERC20Upgradeable } from \"openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol\";\nimport { OwnableUpgradeable } from \"openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol\";\n// solhint-disable-next-line max-line-length\nimport { ReentrancyGuardUpgradeable } from \"openzeppelin-contracts-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol\";\nimport { MathUpgradeable as Math } from \"openzeppelin-contracts-upgradeable/contracts/utils/math/MathUpgradeable.sol\";\n// solhint-disable-next-line max-line-length\nimport { SafeERC20Upgradeable } from \"openzeppelin-contracts-upgradeable/contracts/token/ERC20/utils/SafeERC20Upgradeable.sol\";\n// solhint-disable-next-line max-line-length\nimport { IERC20Upgradeable as IERC20 } from \"openzeppelin-contracts-upgradeable/contracts/token/ERC20/IERC20Upgradeable.sol\";\nimport { IOracleAdapter } from \"../interfaces/IOracleAdapter.sol\";\nimport { IFPMMCallee } from \"../interfaces/IFPMMCallee.sol\";\nimport { ILiquidityStrategy } from \"../interfaces/ILiquidityStrategy.sol\";\nimport { TradingLimitsV2 } from \"../libraries/TradingLimitsV2.sol\";\nimport { ITradingLimitsV2 } from \"../interfaces/ITradingLimitsV2.sol\";\n\n/**\n * @title Fixed Price Market Maker (FPMM)\n * @author Mento Labs\n * @notice This contract implements a fixed price market maker that manages a liquidity pool\n * of two tokens and facilitates swaps between them based on oracle rates and potential fallback\n * to internal pricing.\n * @dev Invariants of the pool:\n * 1. Swap does not decrease the total value of the pool\n * 2. Rebalance reduces the price difference while keeping the same direction\n * 3. Rebalance keeps the price difference at or above the configured threshold\n * 4. Rebalance does not decrease the reserve value more than the rebalance incentive\n */\ncontract FPMM is IRPool, IFPMM, ReentrancyGuardUpgradeable, ERC20Upgradeable, OwnableUpgradeable {\n  using SafeERC20Upgradeable for IERC20;\n  using TradingLimitsV2 for ITradingLimitsV2.State;\n  using TradingLimitsV2 for ITradingLimitsV2.Config;\n  using TradingLimitsV2 for ITradingLimitsV2.TradingLimits;\n\n  /* ============================================================ */\n  /* ======================== Constants ========================= */\n  /* ============================================================ */\n\n  /// @inheritdoc IFPMM\n  uint256 public constant MINIMUM_LIQUIDITY = 10 ** 3;\n\n  /// @inheritdoc IFPMM\n  uint256 public constant BASIS_POINTS_DENOMINATOR = 10_000;\n\n  /// @inheritdoc IFPMM\n  uint256 public constant TRADING_MODE_BIDIRECTIONAL = 0;\n\n  // keccak256(abi.encode(uint256(keccak256(\"mento.storage.FPMM\")) - 1)) & ~bytes32(uint256(0xff))\n  bytes32 private constant _FPMM_STORAGE_LOCATION = 0xe40ad100017325097d9c1a3195cd4d2d97dcb316ccef4f208489777afd465d00;\n\n  /* ============================================================ */\n  /* ======================== Constructor ======================= */\n  /* ============================================================ */\n\n  /**\n   * @notice Contract constructor\n   * @param disable Boolean to disable initializers for implementation contract\n   */\n  constructor(bool disable) {\n    if (disable) {\n      _disableInitializers();\n    }\n  }\n\n  /* ============================================================ */\n  /* ==================== Initialization ======================== */\n  /* ============================================================ */\n\n  modifier onlyFeeSetter() {\n    FPMMStorage storage $ = _getFPMMStorage();\n    if (msg.sender != owner() && msg.sender != $.feeSetter) revert NotFeeSetter();\n    _;\n  }\n\n  /// @inheritdoc IFPMM\n  function initialize(\n    address _token0,\n    address _token1,\n    address _oracleAdapter,\n    address _referenceRateFeedID,\n    bool _invertRateFeed,\n    address _initialOwner,\n    FPMMParams calldata _params\n  ) external initializer {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    $.token0 = _token0;\n    $.token1 = _token1;\n\n    string memory symbol0 = ERC20Upgradeable(_token0).symbol();\n    string memory symbol1 = ERC20Upgradeable(_token1).symbol();\n\n    string memory name_ = string(abi.encodePacked(\"Mento Fixed Price MM - \", symbol0, \"/\", symbol1));\n    string memory symbol_ = string(abi.encodePacked(\"FPMM-\", symbol0, \"/\", symbol1));\n\n    __ERC20_init(name_, symbol_);\n    __Ownable_init();\n\n    uint8 token0Decimals = ERC20Upgradeable(_token0).decimals();\n    uint8 token1Decimals = ERC20Upgradeable(_token1).decimals();\n\n    if (token0Decimals > 18 || token1Decimals > 18) revert InvalidTokenDecimals();\n\n    $.decimals0 = 10 ** token0Decimals;\n    $.decimals1 = 10 ** token1Decimals;\n    $.feeSetter = _params.feeSetter;\n\n    setLPFee(_params.lpFee);\n    setProtocolFeeRecipient(_params.protocolFeeRecipient);\n    setProtocolFee(_params.protocolFee);\n    setRebalanceIncentive(_params.rebalanceIncentive);\n    setRebalanceThresholds(_params.rebalanceThresholdAbove, _params.rebalanceThresholdBelow);\n\n    setOracleAdapter(_oracleAdapter);\n    setReferenceRateFeedID(_referenceRateFeedID);\n    setInvertRateFeed(_invertRateFeed);\n    transferOwnership(_initialOwner);\n  }\n\n  /* ============================================================ */\n  /* ====================== View Functions ====================== */\n  /* ============================================================ */\n\n  /// @inheritdoc IRPool\n  function metadata()\n    external\n    view\n    returns (uint256 dec0, uint256 dec1, uint256 r0, uint256 r1, address t0, address t1)\n  {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    return ($.decimals0, $.decimals1, $.reserve0, $.reserve1, $.token0, $.token1);\n  }\n\n  /// @inheritdoc IRPool\n  function tokens() external view returns (address, address) {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    return ($.token0, $.token1);\n  }\n\n  /// @inheritdoc IRPool\n  function getReserves() public view returns (uint256 _reserve0, uint256 _reserve1, uint256 _blockTimestampLast) {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    _reserve0 = $.reserve0;\n    _reserve1 = $.reserve1;\n    _blockTimestampLast = $.blockTimestampLast;\n  }\n\n  /// @inheritdoc IRPool\n  function token0() external view returns (address) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.token0;\n  }\n\n  /// @inheritdoc IRPool\n  function token1() external view returns (address) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.token1;\n  }\n\n  /// @inheritdoc IRPool\n  function decimals0() external view returns (uint256) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.decimals0;\n  }\n\n  /// @inheritdoc IRPool\n  function decimals1() external view returns (uint256) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.decimals1;\n  }\n\n  /// @inheritdoc IRPool\n  function reserve0() external view returns (uint256) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.reserve0;\n  }\n\n  /// @inheritdoc IRPool\n  function reserve1() external view returns (uint256) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.reserve1;\n  }\n\n  /// @inheritdoc IFPMM\n  function blockTimestampLast() external view returns (uint256) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.blockTimestampLast;\n  }\n\n  /// @inheritdoc IFPMM\n  function oracleAdapter() external view returns (IOracleAdapter) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.oracleAdapter;\n  }\n\n  /// @inheritdoc IFPMM\n  function invertRateFeed() external view returns (bool) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.invertRateFeed;\n  }\n\n  /// @inheritdoc IFPMM\n  function referenceRateFeedID() external view returns (address) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.referenceRateFeedID;\n  }\n\n  /// @inheritdoc IFPMM\n  function lpFee() external view returns (uint256) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.lpFee;\n  }\n\n  /// @inheritdoc IFPMM\n  function protocolFee() external view override(IFPMM, IRPool) returns (uint256) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.protocolFee;\n  }\n\n  /// @inheritdoc IFPMM\n  function protocolFeeRecipient() external view returns (address) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.protocolFeeRecipient;\n  }\n\n  /// @inheritdoc IFPMM\n  function feeSetter() external view returns (address) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.feeSetter;\n  }\n\n  /// @inheritdoc IFPMM\n  function rebalanceIncentive() external view returns (uint256) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.rebalanceIncentive;\n  }\n\n  /// @inheritdoc IFPMM\n  function rebalanceThresholdAbove() external view returns (uint256) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.rebalanceThresholdAbove;\n  }\n\n  /// @inheritdoc IFPMM\n  function rebalanceThresholdBelow() external view returns (uint256) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.rebalanceThresholdBelow;\n  }\n\n  /// @inheritdoc IFPMM\n  function liquidityStrategy(address strategy) external view returns (bool) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    return $.liquidityStrategy[strategy];\n  }\n\n  /// @inheritdoc IFPMM\n  function getRebalancingState()\n    external\n    view\n    returns (\n      uint256 oraclePriceNumerator,\n      uint256 oraclePriceDenominator,\n      uint256 reservePriceNumerator,\n      uint256 reservePriceDenominator,\n      bool reservePriceAboveOraclePrice,\n      uint16 rebalanceThreshold,\n      uint256 priceDifference\n    )\n  {\n    (\n      oraclePriceNumerator,\n      oraclePriceDenominator,\n      reservePriceNumerator,\n      reservePriceDenominator,\n      reservePriceAboveOraclePrice,\n      rebalanceThreshold,\n      priceDifference\n    ) = _getRebalancingState();\n  }\n\n  /// @inheritdoc IRPool\n  function getAmountOut(uint256 amountIn, address tokenIn) public view returns (uint256 amountOut) {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    if (tokenIn != $.token0 && tokenIn != $.token1) revert InvalidToken();\n\n    if (amountIn == 0) return 0;\n\n    (uint256 rateNumerator, uint256 rateDenominator) = _getRateFeed();\n\n    if (tokenIn == $.token0) {\n      return\n        _convertWithRateAndFee(\n          amountIn,\n          $.decimals0,\n          $.decimals1,\n          rateNumerator,\n          rateDenominator,\n          BASIS_POINTS_DENOMINATOR - ($.lpFee + $.protocolFee),\n          BASIS_POINTS_DENOMINATOR\n        );\n    } else {\n      return\n        _convertWithRateAndFee(\n          amountIn,\n          $.decimals1,\n          $.decimals0,\n          rateDenominator,\n          rateNumerator,\n          BASIS_POINTS_DENOMINATOR - ($.lpFee + $.protocolFee),\n          BASIS_POINTS_DENOMINATOR\n        );\n    }\n  }\n\n  /// @inheritdoc IFPMM\n  function getTradingLimits(\n    address token\n  ) external view returns (ITradingLimitsV2.Config memory config, ITradingLimitsV2.State memory state) {\n    FPMMStorage storage $ = _getFPMMStorage();\n    if (token != $.token0 && token != $.token1) revert InvalidToken();\n\n    config = $.tradingLimits[token].config;\n    state = $.tradingLimits[token].state;\n  }\n\n  /* ============================================================ */\n  /* ====================== External Functions ================== */\n  /* ============================================================ */\n\n  /// @inheritdoc IFPMM\n  function mint(address to) external nonReentrant returns (uint256 liquidity) {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    uint256 balance0 = IERC20($.token0).balanceOf(address(this));\n    uint256 balance1 = IERC20($.token1).balanceOf(address(this));\n\n    uint256 amount0 = balance0 - $.reserve0;\n    uint256 amount1 = balance1 - $.reserve1;\n\n    uint256 totalSupply_ = totalSupply();\n    // slither-disable-next-line incorrect-equality\n    if (totalSupply_ == 0) {\n      liquidity = Math.sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY;\n      _mint(address(1), MINIMUM_LIQUIDITY);\n    } else {\n      liquidity = Math.min((amount0 * totalSupply_) / $.reserve0, (amount1 * totalSupply_) / $.reserve1);\n    }\n\n    if (liquidity <= MINIMUM_LIQUIDITY) revert InsufficientLiquidityMinted();\n    _mint(to, liquidity);\n\n    _update();\n\n    emit Mint(msg.sender, amount0, amount1, liquidity, to);\n  }\n\n  // slither-disable-start reentrancy-benign\n  // slither-disable-start reentrancy-no-eth\n  /// @inheritdoc IFPMM\n  function burn(address to) external nonReentrant returns (uint256 amount0, uint256 amount1) {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    uint256 balance0 = IERC20($.token0).balanceOf(address(this));\n    uint256 balance1 = IERC20($.token1).balanceOf(address(this));\n\n    uint256 liquidity = balanceOf(address(this));\n\n    uint256 _totalSupply = totalSupply();\n\n    amount0 = (liquidity * balance0) / _totalSupply;\n    amount1 = (liquidity * balance1) / _totalSupply;\n\n    // slither-disable-next-line incorrect-equality\n    if (amount0 == 0 && amount1 == 0) revert InsufficientLiquidityBurned();\n\n    _burn(address(this), liquidity);\n\n    IERC20($.token0).safeTransfer(to, amount0);\n    IERC20($.token1).safeTransfer(to, amount1);\n\n    _update();\n\n    emit Burn(msg.sender, amount0, amount1, liquidity, to);\n  }\n\n  // slither-disable-end reentrancy-benign\n  // slither-disable-end reentrancy-no-eth\n\n  // slither-disable-start reentrancy-no-eth\n  /// @inheritdoc IRPool\n  function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external nonReentrant {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    if (amount0Out == 0 && amount1Out == 0) revert InsufficientOutputAmount();\n    if (amount0Out >= $.reserve0 || amount1Out >= $.reserve1) revert InsufficientLiquidity();\n    if (to == $.token0 || to == $.token1) revert InvalidToAddress();\n\n    // used to avoid stack too deep error\n    // slither-disable-next-line uninitialized-local\n    SwapData memory swapData;\n\n    swapData.amount0Out = amount0Out;\n    swapData.amount1Out = amount1Out;\n\n    (swapData.rateNumerator, swapData.rateDenominator) = _getRateFeed();\n    swapData.initialReserveValue = _totalValueInToken1Scaled(\n      $.reserve0,\n      $.reserve1,\n      swapData.rateNumerator,\n      swapData.rateDenominator\n    );\n\n    if (amount0Out > 0) IERC20($.token0).safeTransfer(to, amount0Out);\n    if (amount1Out > 0) IERC20($.token1).safeTransfer(to, amount1Out);\n\n    if (data.length > 0) IFPMMCallee(to).hook(msg.sender, amount0Out, amount1Out, data);\n\n    swapData.newReserve0 = IERC20($.token0).balanceOf(address(this));\n    swapData.newReserve1 = IERC20($.token1).balanceOf(address(this));\n\n    swapData.amount0In = swapData.newReserve0 > $.reserve0 - amount0Out\n      ? swapData.newReserve0 - ($.reserve0 - amount0Out)\n      : 0;\n    swapData.amount1In = swapData.newReserve1 > $.reserve1 - amount1Out\n      ? swapData.newReserve1 - ($.reserve1 - amount1Out)\n      : 0;\n    // slither-disable-next-line incorrect-equality\n    if (swapData.amount0In == 0 && swapData.amount1In == 0) revert InsufficientInputAmount();\n\n    _swapCheck(swapData);\n    _transferProtocolFee(swapData.amount0In, swapData.amount1In);\n    _update();\n\n    _applyTradingLimits($.token0, swapData.amount0In, swapData.amount0Out);\n    _applyTradingLimits($.token1, swapData.amount1In, swapData.amount1Out);\n\n    emit Swap(msg.sender, swapData.amount0In, swapData.amount1In, amount0Out, amount1Out, to);\n  }\n\n  // slither-disable-end reentrancy-no-eth\n\n  // slither-disable-start reentrancy-no-eth\n  // solhint-disable code-complexity\n  /// @inheritdoc IFPMM\n  function rebalance(uint256 amount0Out, uint256 amount1Out, bytes calldata data) external nonReentrant {\n    _update();\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    if (!$.liquidityStrategy[msg.sender]) revert NotLiquidityStrategy();\n    if ((amount0Out > 0) == (amount1Out > 0)) revert OneOutputAmountRequired();\n    if (amount0Out >= $.reserve0 || amount1Out >= $.reserve1) revert InsufficientLiquidity();\n\n    // used to avoid stack too deep error\n    // slither-disable-next-line uninitialized-local\n    SwapData memory swapData;\n\n    swapData.amount0Out = amount0Out;\n    swapData.amount1Out = amount1Out;\n    uint256 threshold;\n    (\n      swapData.rateNumerator,\n      swapData.rateDenominator,\n      ,\n      ,\n      swapData.reservePriceAboveOraclePrice,\n      threshold,\n      swapData.initialPriceDifference\n    ) = _getRebalancingState();\n\n    if (swapData.initialPriceDifference < threshold) revert PriceDifferenceTooSmall();\n\n    if (amount0Out > 0) IERC20($.token0).safeTransfer(msg.sender, amount0Out);\n    if (amount1Out > 0) IERC20($.token1).safeTransfer(msg.sender, amount1Out);\n\n    if (data.length > 0) ILiquidityStrategy(msg.sender).onRebalance(msg.sender, amount0Out, amount1Out, data);\n\n    uint256 balance0 = IERC20($.token0).balanceOf(address(this));\n    uint256 balance1 = IERC20($.token1).balanceOf(address(this));\n\n    uint256 amount0In = balance0 > $.reserve0 - amount0Out ? balance0 - ($.reserve0 - amount0Out) : 0;\n    uint256 amount1In = balance1 > $.reserve1 - amount1Out ? balance1 - ($.reserve1 - amount1Out) : 0;\n\n    // slither-disable-next-line incorrect-equality\n    if (!((amount0Out > 0 && amount1In > 0 && amount0In == 0) || (amount1Out > 0 && amount0In > 0 && amount1In == 0)))\n      revert RebalanceDirectionInvalid();\n\n    swapData.amount0In = amount0In;\n    swapData.amount1In = amount1In;\n\n    _update();\n\n    uint256 newPriceDifference = _rebalanceCheck(swapData);\n    emit Rebalanced(msg.sender, swapData.initialPriceDifference, newPriceDifference);\n  }\n\n  // solhint-enable code-complexity\n  // slither-disable-end reentrancy-no-eth\n\n  /* ============================================================ */\n  /* ===================== Admin Functions ====================== */\n  /* ============================================================ */\n\n  /// @inheritdoc IFPMM\n  function setLPFee(uint256 _lpFee) public virtual onlyFeeSetter {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    if (_lpFee + $.protocolFee > 200) revert FeeTooHigh(); // Max 2% combined\n\n    uint256 oldFee = $.lpFee;\n    $.lpFee = _lpFee;\n    emit LPFeeUpdated(oldFee, _lpFee);\n  }\n\n  /// @inheritdoc IFPMM\n  function setProtocolFee(uint256 _protocolFee) public onlyFeeSetter {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    if (_protocolFee > 0 && $.protocolFeeRecipient == address(0)) revert ProtocolFeeRecipientRequired();\n    if (_protocolFee + $.lpFee > 200) revert FeeTooHigh(); // Max 2% combined\n\n    uint256 oldFee = $.protocolFee;\n    $.protocolFee = _protocolFee;\n    emit ProtocolFeeUpdated(oldFee, _protocolFee);\n  }\n\n  /// @inheritdoc IFPMM\n  function setProtocolFeeRecipient(address _protocolFeeRecipient) public onlyOwner {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    if (_protocolFeeRecipient == address(0)) revert ZeroAddress();\n\n    address oldRecipient = $.protocolFeeRecipient;\n    $.protocolFeeRecipient = _protocolFeeRecipient;\n    emit ProtocolFeeRecipientUpdated(oldRecipient, _protocolFeeRecipient);\n  }\n\n  /// @inheritdoc IFPMM\n  function setFeeSetter(address _feeSetter) public onlyOwner {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    address oldFeeSetter = $.feeSetter;\n    $.feeSetter = _feeSetter;\n    emit FeeSetterUpdated(oldFeeSetter, _feeSetter);\n  }\n\n  /// @inheritdoc IFPMM\n  function setRebalanceIncentive(uint256 _rebalanceIncentive) public onlyFeeSetter {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    if (_rebalanceIncentive > 100) revert RebalanceIncentiveTooHigh(); // Max 1%\n    uint256 oldIncentive = $.rebalanceIncentive;\n    $.rebalanceIncentive = _rebalanceIncentive;\n    emit RebalanceIncentiveUpdated(oldIncentive, _rebalanceIncentive);\n  }\n\n  /// @inheritdoc IFPMM\n  function setRebalanceThresholds(uint256 _rebalanceThresholdAbove, uint256 _rebalanceThresholdBelow) public onlyOwner {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    // Rebalance thresholds should enforce 1/3 vs 2/3 token reserve values\n    if (_rebalanceThresholdAbove > 10000) revert RebalanceThresholdTooHigh();\n    if (_rebalanceThresholdBelow > 5000) revert RebalanceThresholdTooHigh();\n    uint256 oldThresholdAbove = $.rebalanceThresholdAbove;\n    uint256 oldThresholdBelow = $.rebalanceThresholdBelow;\n    $.rebalanceThresholdAbove = _rebalanceThresholdAbove;\n    $.rebalanceThresholdBelow = _rebalanceThresholdBelow;\n\n    emit RebalanceThresholdUpdated(\n      oldThresholdAbove,\n      oldThresholdBelow,\n      _rebalanceThresholdAbove,\n      _rebalanceThresholdBelow\n    );\n  }\n\n  /// @inheritdoc IFPMM\n  function setLiquidityStrategy(address strategy, bool state) external onlyOwner {\n    if (strategy == address(0)) revert ZeroAddress();\n\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    $.liquidityStrategy[strategy] = state;\n    emit LiquidityStrategyUpdated(strategy, state);\n  }\n\n  /// @inheritdoc IFPMM\n  function setOracleAdapter(address _oracleAdapter) public onlyOwner {\n    if (_oracleAdapter == address(0)) revert ZeroAddress();\n\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    address oldOracleAdapter = address($.oracleAdapter);\n    $.oracleAdapter = IOracleAdapter(_oracleAdapter);\n    emit OracleAdapterUpdated(oldOracleAdapter, _oracleAdapter);\n  }\n\n  function setInvertRateFeed(bool _invertRateFeed) public onlyOwner {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    bool oldInvertRateFeed = $.invertRateFeed;\n    $.invertRateFeed = _invertRateFeed;\n\n    emit InvertRateFeedUpdated(oldInvertRateFeed, _invertRateFeed);\n  }\n\n  /// @inheritdoc IFPMM\n  function setReferenceRateFeedID(address _referenceRateFeedID) public onlyOwner {\n    if (_referenceRateFeedID == address(0)) revert ZeroAddress();\n\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    address oldRateFeedID = $.referenceRateFeedID;\n    $.referenceRateFeedID = _referenceRateFeedID;\n    emit ReferenceRateFeedIDUpdated(oldRateFeedID, _referenceRateFeedID);\n  }\n\n  /// @inheritdoc IFPMM\n  function configureTradingLimit(address token, uint256 limit0, uint256 limit1) external onlyOwner {\n    FPMMStorage storage $ = _getFPMMStorage();\n    if (token != $.token0 && token != $.token1) revert InvalidToken();\n\n    // slither-disable-next-line uninitialized-local\n    ITradingLimitsV2.Config memory config;\n    config.decimals = ERC20Upgradeable(token).decimals();\n\n    // scale to 15 decimals for TradingLimitsV2 library internal precision\n    limit0 = (limit0 * 1e15) / 10 ** config.decimals;\n    limit1 = (limit1 * 1e15) / 10 ** config.decimals;\n\n    if (limit0 > uint120(type(int120).max) || limit1 > uint120(type(int120).max)) revert LimitDoesNotFitInInt120();\n    config.limit0 = int120(uint120(limit0));\n    config.limit1 = int120(uint120(limit1));\n\n    config.validate();\n\n    $.tradingLimits[token].config = config;\n    $.tradingLimits[token].state = $.tradingLimits[token].state.reset(config);\n\n    emit TradingLimitConfigured(token, config);\n  }\n\n  /* ============================================================ */\n  /* ==================== Internal Functions ==================== */\n  /* ============================================================ */\n\n  /**\n   * @notice Returns the storage pointer for the FPMM contract\n   * @return $ Pointer to the FPMM storage\n   */\n  function _getFPMMStorage() internal pure returns (FPMMStorage storage $) {\n    // solhint-disable-next-line no-inline-assembly\n    assembly {\n      $.slot := _FPMM_STORAGE_LOCATION\n    }\n  }\n\n  /**\n   * @notice Updates reserves and timestamp\n   * @dev Called after every balance-changing function\n   */\n  function _update() private {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    $.reserve0 = IERC20($.token0).balanceOf(address(this));\n    $.reserve1 = IERC20($.token1).balanceOf(address(this));\n    $.blockTimestampLast = block.timestamp;\n\n    emit UpdateReserves($.reserve0, $.reserve1, $.blockTimestampLast);\n  }\n\n  /**\n   * @notice Transfers the protocol fee to the protocol fee recipient\n   * @param amount0In Amount of token0 in from swap\n   * @param amount1In Amount of token1 in from swap\n   */\n  function _transferProtocolFee(uint256 amount0In, uint256 amount1In) private {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    uint256 fee = $.protocolFee;\n    if (fee == 0) return;\n\n    if (amount0In > 0) {\n      uint256 feeAmount = (amount0In * fee) / BASIS_POINTS_DENOMINATOR;\n      IERC20($.token0).safeTransfer($.protocolFeeRecipient, feeAmount);\n    }\n\n    if (amount1In > 0) {\n      uint256 feeAmount = (amount1In * fee) / BASIS_POINTS_DENOMINATOR;\n      IERC20($.token1).safeTransfer($.protocolFeeRecipient, feeAmount);\n    }\n  }\n\n  /**\n   * @notice Calculates total value of a given amount of tokens in terms of token1 scaled to 18 decimals\n   * @param amount0 Amount of token0\n   * @param amount1 Amount of token1\n   * @param rateNumerator Oracle rate numerator\n   * @param rateDenominator Oracle rate denominator\n   * @return Total value in token1\n   */\n  function _totalValueInToken1Scaled(\n    uint256 amount0,\n    uint256 amount1,\n    uint256 rateNumerator,\n    uint256 rateDenominator\n  ) private view returns (uint256) {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    uint256 token0ValueInToken1 = _convertWithRate(amount0, $.decimals0, 1e18, rateNumerator, rateDenominator);\n    // slither-disable-next-line divide-before-multiply\n    amount1 = amount1 * (1e18 / $.decimals1);\n    return token0ValueInToken1 + amount1;\n  }\n\n  function _getRateFeed() internal view virtual returns (uint256 rateNumerator, uint256 rateDenominator) {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    (rateNumerator, rateDenominator) = $.oracleAdapter.getFXRateIfValid($.referenceRateFeedID);\n\n    if ($.invertRateFeed) {\n      (rateNumerator, rateDenominator) = (rateDenominator, rateNumerator);\n    }\n  }\n\n  /**\n   * @notice Calculates the price difference between oracle and reserve prices\n   * @param oraclePriceNumerator Oracle price numerator\n   * @param oraclePriceDenominator Oracle price denominator\n   * @param reservePriceNumerator Reserve price numerator\n   * @param reservePriceDenominator Reserve price denominator\n   * @return priceDifference Price difference in basis points\n   * @return reservePriceAboveOraclePrice Whether reserve price is above oracle price\n   */\n  function _calculatePriceDifference(\n    uint256 oraclePriceNumerator,\n    uint256 oraclePriceDenominator,\n    uint256 reservePriceNumerator,\n    uint256 reservePriceDenominator\n  ) internal pure returns (uint256 priceDifference, bool reservePriceAboveOraclePrice) {\n    uint256 oracleCrossProduct = oraclePriceNumerator * reservePriceDenominator;\n    uint256 reserveCrossProduct = reservePriceNumerator * oraclePriceDenominator;\n    reservePriceAboveOraclePrice = reserveCrossProduct > oracleCrossProduct;\n\n    uint256 absolutePriceDiff = reservePriceAboveOraclePrice\n      ? reserveCrossProduct - oracleCrossProduct\n      : oracleCrossProduct - reserveCrossProduct;\n    priceDifference = (absolutePriceDiff * BASIS_POINTS_DENOMINATOR) / oracleCrossProduct;\n  }\n\n  /**\n   * @notice Rebalance checks: price difference improves, direction is preserved,\n   * price difference does not move past the configured threshold,\n   * and the reserve value is not decreased more than the rebalance incentive\n   * @param swapData Swap data\n   * @return newPriceDifference New price difference\n   */\n  function _rebalanceCheck(SwapData memory swapData) private view returns (uint256 newPriceDifference) {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    // slither-disable-start divide-before-multiply\n    uint256 reservePriceNumerator = $.reserve1 * (1e18 / $.decimals1);\n    uint256 reservePriceDenominator = $.reserve0 * (1e18 / $.decimals0);\n    // slither-disable-end divide-before-multiply\n\n    bool reservePriceAboveOraclePrice;\n    (newPriceDifference, reservePriceAboveOraclePrice) = _calculatePriceDifference(\n      swapData.rateNumerator,\n      swapData.rateDenominator,\n      reservePriceNumerator,\n      reservePriceDenominator\n    );\n\n    // Ensure price difference is smaller than before\n    if (newPriceDifference >= swapData.initialPriceDifference) revert PriceDifferenceNotImproved();\n\n    // slither-disable-next-line incorrect-equality\n    if (reservePriceAboveOraclePrice != swapData.reservePriceAboveOraclePrice)\n      revert PriceDifferenceMovedInWrongDirection();\n\n    if (reservePriceAboveOraclePrice && newPriceDifference < $.rebalanceThresholdAbove) {\n      revert PriceDifferenceMovedTooFarFromThresholds();\n    }\n    if (!reservePriceAboveOraclePrice && newPriceDifference < $.rebalanceThresholdBelow) {\n      revert PriceDifferenceMovedTooFarFromThresholds();\n    }\n\n    if (swapData.amount0In > 0) {\n      uint256 minAmount0In = _convertWithRateAndFee(\n        swapData.amount1Out,\n        $.decimals1,\n        $.decimals0,\n        swapData.rateDenominator,\n        swapData.rateNumerator,\n        BASIS_POINTS_DENOMINATOR - $.rebalanceIncentive,\n        BASIS_POINTS_DENOMINATOR\n      );\n      if (swapData.amount0In < minAmount0In) revert InsufficientAmount0In();\n    } else {\n      uint256 minAmount1In = _convertWithRateAndFee(\n        swapData.amount0Out,\n        $.decimals0,\n        $.decimals1,\n        swapData.rateNumerator,\n        swapData.rateDenominator,\n        BASIS_POINTS_DENOMINATOR - $.rebalanceIncentive,\n        BASIS_POINTS_DENOMINATOR\n      );\n      if (swapData.amount1In < minAmount1In) revert InsufficientAmount1In();\n    }\n  }\n\n  /**\n   * @notice Swap checks to ensure the reserve value is not decreased\n   * @param swapData Swap data\n   */\n  function _swapCheck(SwapData memory swapData) private view {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    uint256 newReserveValue = _totalValueInToken1Scaled(\n      swapData.newReserve0,\n      swapData.newReserve1,\n      swapData.rateNumerator,\n      swapData.rateDenominator\n    );\n\n    uint256 totalFeeBps = $.lpFee + $.protocolFee;\n\n    uint256 fee0 = (swapData.amount0Out * totalFeeBps) / (BASIS_POINTS_DENOMINATOR - totalFeeBps);\n    uint256 fee1 = (swapData.amount1Out * totalFeeBps) / (BASIS_POINTS_DENOMINATOR - totalFeeBps);\n\n    // slither-disable-next-line divide-before-multiply\n    uint256 totalFeeInToken1 = (_convertWithRate(\n      fee0,\n      $.decimals0,\n      $.decimals1,\n      swapData.rateNumerator,\n      swapData.rateDenominator\n    ) + fee1) * (1e18 / $.decimals1);\n\n    uint256 expectedReserveValue = swapData.initialReserveValue + totalFeeInToken1;\n    if (newReserveValue < expectedReserveValue) revert ReserveValueDecreased();\n  }\n\n  function _getRebalancingState()\n    internal\n    view\n    returns (\n      uint256 oraclePriceNumerator,\n      uint256 oraclePriceDenominator,\n      uint256 reservePriceNumerator,\n      uint256 reservePriceDenominator,\n      bool reservePriceAboveOraclePrice,\n      uint16 rebalanceThreshold,\n      uint256 priceDifference\n    )\n  {\n    FPMMStorage storage $ = _getFPMMStorage();\n\n    if ($.referenceRateFeedID == address(0)) revert ReferenceRateNotSet();\n    if ($.reserve0 == 0 || $.reserve1 == 0) revert ReservesEmpty();\n\n    (oraclePriceNumerator, oraclePriceDenominator) = _getRateFeed();\n\n    // slither-disable-start divide-before-multiply\n    reservePriceNumerator = $.reserve1 * (1e18 / $.decimals1);\n    reservePriceDenominator = $.reserve0 * (1e18 / $.decimals0);\n    // slither-disable-end divide-before-multiply\n\n    (priceDifference, reservePriceAboveOraclePrice) = _calculatePriceDifference(\n      oraclePriceNumerator,\n      oraclePriceDenominator,\n      reservePriceNumerator,\n      reservePriceDenominator\n    );\n\n    rebalanceThreshold = reservePriceAboveOraclePrice\n      ? uint16($.rebalanceThresholdAbove)\n      : uint16($.rebalanceThresholdBelow);\n  }\n\n  function _convertWithRate(\n    uint256 amount,\n    uint256 fromDecimals,\n    uint256 toDecimals,\n    uint256 numerator,\n    uint256 denominator\n  ) internal pure returns (uint256) {\n    return (amount * numerator * toDecimals) / (denominator * fromDecimals);\n  }\n\n  function _convertWithRateAndFee(\n    uint256 amount,\n    uint256 fromDecimals,\n    uint256 toDecimals,\n    uint256 numerator,\n    uint256 denominator,\n    uint256 incentiveNum,\n    uint256 incentiveDen\n  ) internal pure returns (uint256) {\n    return (amount * numerator * toDecimals * incentiveNum) / (denominator * fromDecimals * incentiveDen);\n  }\n\n  /**\n   * @notice Apply trading limits for a token\n   * @param token Address of the token\n   * @param amountIn Amount of token flowing into the pool\n   * @param amountOut Amount of token flowing out of the pool\n   */\n  function _applyTradingLimits(address token, uint256 amountIn, uint256 amountOut) internal {\n    FPMMStorage storage $ = _getFPMMStorage();\n    uint256 totalFee = $.lpFee + $.protocolFee;\n    $.tradingLimits[token].state = $.tradingLimits[token].applyTradingLimits(amountIn, amountOut, totalFee);\n  }\n}\n","deployed_bytecode":"0x608060405234801561000f575f80fd5b5060043610610372575f3560e01c80638da5cb5b116101d4578063c6bf342011610109578063dd62ed3e116100a9578063edb6d07511610079578063edb6d0751461076c578063f140a35a1461077f578063f2fde38b14610792578063fb1a6375146107a5575f80fd5b8063dd62ed3e1461072b578063e4da518a1461073e578063e521cb9214610751578063ea9274b814610764575f80fd5b8063cfa498a3116100e4578063cfa498a3146106ff578063d21220a714610708578063d4ac735314610710578063da7ddb8f14610718575f80fd5b8063c6bf3420146106c6578063cce441a3146106d9578063ce746e66146106ec575f80fd5b8063a9059cbb11610174578063ba9a7a561161014f578063ba9a7a561461068f578063c20a9ca514610698578063c5700a02146106ab578063c60801b7146106b3575f80fd5b8063a9059cbb14610661578063b0e21e8a14610674578063b19805af1461067c575f80fd5b806396cd3bce116101af57806396cd3bce1461060b5780639d63848a1461061e578063a28af8a414610646578063a457c2d71461064e575f80fd5b80638da5cb5b146105af57806393965ec9146105c057806395d89b4114610603575f80fd5b806356bd16ab116102aa578063704ce43e1161024a578063787dce3d11610225578063787dce3d146105645780637bdd6b441461057757806387cf3ef41461057f57806389afcb4414610587575f80fd5b8063704ce43e1461052c57806370a0823114610534578063715018a61461055c575f80fd5b80636391f7db116102855780636391f7db146104dd57806363e979c1146104fe57806364df049e146105115780636a62784214610519575f80fd5b806356bd16ab146104c65780635a76f25e146104ce5780635ca0c578146104d6575f80fd5b806323b872dd1161031557806339509351116102f057806339509351146104905780633d9f3163146104a3578063443cb4bc146104ab57806353cb6a5e146104b3575f80fd5b806323b872dd1461042d578063313ce56714610440578063392f37e91461044f575f80fd5b8063095ea7b311610350578063095ea7b3146103cc5780630c99c084146103ef5780630dfe16811461040557806318160ddd14610425575f80fd5b8063022c0d9f1461037657806306fdde031461038b5780630902f1ac146103a9575b5f80fd5b610389610384366004614225565b6107ad565b005b610393610bc4565b6040516103a091906142aa565b60405180910390f35b6103b1610c54565b604080519384526020840192909252908201526060016103a0565b6103df6103da3660046142dc565b610c7c565b60405190151581526020016103a0565b6103f7610c95565b6040519081526020016103a0565b61040d610ca9565b6040516001600160a01b0390911681526020016103a0565b6067546103f7565b6103df61043b366004614304565b610cc3565b604051601281526020016103a0565b610457610ce8565b6040805196875260208701959095529385019290925260608401526001600160a01b0390811660808401521660a082015260c0016103a0565b6103df61049e3660046142dc565b610d33565b61040d610d54565b6103f7610d71565b6103896104c136600461433d565b610d85565b6103f7610e74565b6103f7610e88565b6103f75f81565b6104f06104eb366004614354565b610e9c565b6040516103a092919061436d565b61038961050c36600461433d565b610fd1565b61040d6110a7565b6103f7610527366004614354565b6110c4565b6103f76112f7565b6103f7610542366004614354565b6001600160a01b03165f9081526065602052604090205490565b61038961130b565b61038961057236600461433d565b61131e565b6103f761143b565b61040d61144f565b61059a610595366004614354565b61146c565b604080519283526020830191909152016103a0565b6097546001600160a01b031661040d565b6105c861166e565b6040805197885260208801969096529486019390935260608501919091521515608084015261ffff1660a083015260c082015260e0016103a0565b610393611693565b6103896106193660046143e4565b6116a2565b61062661171d565b604080516001600160a01b039384168152929091166020830152016103a0565b6103f7611745565b6103df61065c3660046142dc565b611759565b6103df61066f3660046142dc565b6117e3565b6103f76117f0565b61038961068a366004614354565b611804565b6103f76103e881565b6103896106a63660046143ff565b61186a565b6103f7611c91565b6103896106c136600461448e565b611ca5565b6103896106d43660046144dd565b612062565b6103896106e73660046144fd565b612120565b6103df6106fa366004614354565b6121c4565b6103f761271081565b61040d6121f2565b6103f761220f565b610389610726366004614532565b612223565b6103f7610739366004614562565b612549565b61038961074c366004614354565b612573565b61038961075f366004614354565b612600565b6103df61268e565b61038961077a366004614354565b6126ac565b6103f761078d366004614593565b612739565b6103896107a0366004614354565b61282b565b61040d6128a4565b6107b56128c1565b5f6107be61291a565b9050851580156107cc575084155b156107ea576040516342301c2360e01b815260040160405180910390fd5b806004015486101580610801575080600501548510155b1561081f5760405163bb55fd2760e01b815260040160405180910390fd5b80546001600160a01b0385811691161480610849575060018101546001600160a01b038581169116145b1561086757604051638aa3a72f60e01b815260040160405180910390fd5b61086f614179565b60c0810187905260e0810186905261088561293e565b60208301819052818352600484015460058501546108a79391929091906129de565b604082015286156108c85781546108c8906001600160a01b03168689612a41565b85156108e75760018201546108e7906001600160a01b03168688612a41565b821561094f57604051639a7bff7960e01b81526001600160a01b03861690639a7bff79906109219033908b908b908a908a906004016145b4565b5f604051808303815f87803b158015610938575f80fd5b505af115801561094a573d5f803e3d5ffd5b505050505b81546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610994573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109b891906145ff565b61010082015260018201546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610a06573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a2a91906145ff565b6101208201526004820154610a4090889061462a565b81610100015111610a51575f610a71565b868260040154610a61919061462a565b816101000151610a71919061462a565b60808201526005820154610a8690879061462a565b81610120015111610a97575f610ab7565b858260050154610aa7919061462a565b816101200151610ab7919061462a565b60a08201526080810151158015610ad0575060a0810151155b15610aee5760405163098fb56160e01b815260040160405180910390fd5b610af781612a98565b610b0981608001518260a00151612bac565b610b11612c4e565b8154608082015160c0830151610b31926001600160a01b03169190612d8d565b600182015460a082015160e0830151610b54926001600160a01b03169190612d8d565b60808082015160a08301516040805192835260208301919091528101899052606081018890526001600160a01b0387169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822910160405180910390a35050610bbd60018055565b5050505050565b606060688054610bd39061463d565b80601f0160208091040260200160405190810160405280929190818152602001828054610bff9061463d565b8015610c4a5780601f10610c2157610100808354040283529160200191610c4a565b820191905f5260205f20905b815481529060010190602001808311610c2d57829003601f168201915b5050505050905090565b5f805f80610c6061291a565b6004810154600582015460069092015490969195509350915050565b5f33610c89818585612efb565b60019150505b92915050565b5f80610c9f61291a565b600f015492915050565b5f80610cb361291a565b546001600160a01b031692915050565b5f33610cd085828561301e565b610cdb858585613090565b60019150505b9392505050565b5f805f805f805f610cf761291a565b60028101546003820154600483015460058401548454600190950154939c929b5090995097506001600160a01b03928316965091169350915050565b5f33610c89818585610d458383612549565b610d4f9190614675565b612efb565b5f80610d5e61291a565b600701546001600160a01b031692915050565b5f80610d7b61291a565b6004015492915050565b5f610d8e61291a565b9050610da26097546001600160a01b031690565b6001600160a01b0316336001600160a01b031614158015610dd05750600c8101546001600160a01b03163314155b15610dee5760405163e4ed485760e01b815260040160405180910390fd5b5f610df761291a565b905060c881600a015484610e0b9190614675565b1115610e2a5760405163cd4e616760e01b815260040160405180910390fd5b6009810180549084905560408051828152602081018690527fb5d5dda8af4f1e40a5cc4aa66c39ca5aac7f90947261313b07527eb3bdd98bc791015b60405180910390a150505050565b5f80610e7e61291a565b600e015492915050565b5f80610e9261291a565b6005015492915050565b60408051606080820183525f8083526020808401829052838501829052845160808101865282815290810182905293840181905290830152905f610ede61291a565b80549091506001600160a01b03858116911614801590610f0e575060018101546001600160a01b03858116911614155b15610f2c5760405163c1ab6dc160e01b815260040160405180910390fd5b6001600160a01b039093165f8181526011909401602081815260408087208151606080820184526001830154600e81810b8452600160781b8204900b8387015260ff600160f01b9091041682850152959098529282528051608081018252925463ffffffff808216855264010000000082041692840192909252600160401b8204600b90810b91840191909152600160a01b909104900b918101919091529293915050565b5f610fda61291a565b9050610fee6097546001600160a01b031690565b6001600160a01b0316336001600160a01b03161415801561101c5750600c8101546001600160a01b03163314155b1561103a5760405163e4ed485760e01b815260040160405180910390fd5b5f61104361291a565b905060648311156110675760405163712202ab60e01b815260040160405180910390fd5b600d810180549084905560408051828152602081018690527fb273226859e3e49fd86c9ac8f721eaa74e677de0877db704918e0f43ec8d23bc9101610e66565b5f806110b161291a565b600b01546001600160a01b031692915050565b5f6110cd6128c1565b5f6110d661291a565b80546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611120573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061114491906145ff565b60018301546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611191573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111b591906145ff565b90505f8360040154836111c8919061462a565b90505f8460050154836111db919061462a565b90505f6111e760675490565b9050805f03611223576103e86112056112008486614688565b613239565b61120f919061462a565b965061121e60016103e861331d565b611261565b600486015461125e906112368386614688565b61124091906146b3565b600588015461124f8486614688565b61125991906146b3565b6133dd565b96505b6103e8871161128357604051633489be7560e21b815260040160405180910390fd5b61128d888861331d565b611295612c4e565b60408051848152602081018490529081018890526001600160a01b0389169033907fa8137fff86647d8a402117b9c5dbda627f721d3773338fb9678c83e54ed390809060600160405180910390a35050505050506112f260018055565b919050565b5f8061130161291a565b6009015492915050565b6113136133f2565b61131c5f61344c565b565b5f61132761291a565b905061133b6097546001600160a01b031690565b6001600160a01b0316336001600160a01b0316141580156113695750600c8101546001600160a01b03163314155b156113875760405163e4ed485760e01b815260040160405180910390fd5b5f61139061291a565b90505f831180156113ac5750600b8101546001600160a01b0316155b156113ca576040516342123e7160e11b815260040160405180910390fd5b60c88160090154846113dc9190614675565b11156113fb5760405163cd4e616760e01b815260040160405180910390fd5b600a810180549084905560408051828152602081018690527fb404cac19fb1cbeff98d325795b08886e3cd8fe8cb1a2f193aac66f13fb239c39101610e66565b5f8061144561291a565b6002015492915050565b5f8061145961291a565b600c01546001600160a01b031692915050565b5f806114766128c1565b5f61147f61291a565b80546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156114c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114ed91906145ff565b60018301546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa15801561153a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061155e91906145ff565b305f90815260656020526040902054606754919250908061157f8584614688565b61158991906146b3565b9650806115968484614688565b6115a091906146b3565b9550861580156115ae575085155b156115cc5760405163749383ad60e01b815260040160405180910390fd5b6115d6308361349d565b84546115ec906001600160a01b03168989612a41565b6001850154611605906001600160a01b03168988612a41565b61160d612c4e565b60408051888152602081018890529081018390526001600160a01b0389169033907fd175a80c109434bb89948928ab2475a6647c94244cb70002197896423c8833639060600160405180910390a3505050505061166960018055565b915091565b5f805f805f805f61167d6135cf565b959d949c50929a50909850965094509092509050565b606060698054610bd39061463d565b6116aa6133f2565b5f6116b361291a565b60078101805460ff60a01b198116600160a01b86151581810292909217909355604080519390920460ff16801515845260208401919091529293507eaf8726a3679feb41b28b0996e403259aceb28ec6f3c6c3dc7a4c4fe6c8fce1910160405180910390a1505050565b5f805f61172861291a565b80546001909101546001600160a01b039182169591169350915050565b5f8061174f61291a565b6003015492915050565b5f33816117668286612549565b9050838110156117cb5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6117d88286868403612efb565b506001949350505050565b5f33610c89818585613090565b5f806117fa61291a565b600a015492915050565b61180c6133f2565b5f61181561291a565b600c810180546001600160a01b038581166001600160a01b031983168117909355604051939450169182907f83b887657b0e2cbbed6d7b9468d78fe27ce257d950e1c7e36572b3a24f82e41c905f90a3505050565b5f54610100900460ff161580801561188857505f54600160ff909116105b806118a15750303b1580156118a157505f5460ff166001145b6119045760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016117c2565b5f805460ff191660011790558015611925575f805461ff0019166101001790555b5f61192e61291a565b80546001600160a01b03199081166001600160a01b038c81169182178455600184018054909316908c1617909155604080516395d89b4160e01b815290519293505f926395d89b419160048082019286929091908290030181865afa158015611999573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526119c091908101906146e6565b90505f896001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa1580156119fe573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611a2591908101906146e6565b90505f8282604051602001611a3b92919061478e565b60405160208183030381529060405290505f8383604051602001611a609291906147f2565b6040516020818303038152906040529050611a7b82826136cd565b611a836136fd565b5f8d6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ac0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ae4919061483e565b90505f8d6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b23573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b47919061483e565b905060128260ff161180611b5e575060128160ff16115b15611b7c5760405163686d360760e01b815260040160405180910390fd5b611b8782600a61493e565b6002880155611b9781600a61493e565b6003880155611bac60808a0160608b01614354565b600c880180546001600160a01b0319166001600160a01b0392909216919091179055611bd88935610d85565b611beb61075f60608b0160408c01614354565b611bf8896020013561131e565b611c058960800135610fd1565b611c178960a001358a60c00135612062565b611c208d6126ac565b611c298c612573565b611c328b6116a2565b611c3b8a61282b565b505050505050508015611c87575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b5f80611c9b61291a565b6006015492915050565b611cad6128c1565b611cb5612c4e565b5f611cbe61291a565b335f90815260108201602052604090205490915060ff16611cf257604051633b040b3f60e21b815260040160405180910390fd5b83151585151503611d1657604051635747f31560e01b815260040160405180910390fd5b806004015485101580611d2d575080600501548410155b15611d4b5760405163bb55fd2760e01b815260040160405180910390fd5b611d53614179565b60c0810186905260e081018590525f611d6a6135cf565b606089018190529115156101408901526020880194909452938652505061ffff169150811115611dad576040516359658c6b60e01b815260040160405180910390fd5b8615611dc9578254611dc9906001600160a01b03163389612a41565b8515611de8576001830154611de8906001600160a01b03163388612a41565b8315611e4757604051634574893160e11b81523390638ae9126290611e199083908b908b908b908b906004016145b4565b5f604051808303815f87803b158015611e30575f80fd5b505af1158015611e42573d5f803e3d5ffd5b505050505b82546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa158015611e8c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eb091906145ff565b60018501546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611efd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2191906145ff565b90505f898660040154611f34919061462a565b8311611f40575f611f5a565b898660040154611f50919061462a565b611f5a908461462a565b90505f898760050154611f6d919061462a565b8311611f79575f611f93565b898760050154611f89919061462a565b611f93908461462a565b90505f8b118015611fa357505f81115b8015611fad575081155b80611fcb57505f8a118015611fc157505f82115b8015611fcb575080155b611fe85760405163737dec7160e11b815260040160405180910390fd5b6080860182905260a08601819052611ffe612c4e565b5f6120088761372b565b6060880151604080519182526020820183905291925033917f3645b7cfbb41ac8e6dcc3c4877ede2c60b467a0374b7a7fc7563f0a09580999e910160405180910390a2505050505050505061205c60018055565b50505050565b61206a6133f2565b5f61207361291a565b9050612710831115612098576040516306e41b9760e51b815260040160405180910390fd5b6113888211156120bb576040516306e41b9760e51b815260040160405180910390fd5b600e81018054600f83018054928690558490556040805182815260208101849052908101869052606081018590529091907f77c5ddba87b3d3f970242eda9bb1263ade9e4aed3eca233d5fa1af00a574b0259060800160405180910390a15050505050565b6121286133f2565b6001600160a01b03821661214f5760405163d92e233d60e01b815260040160405180910390fd5b5f61215861291a565b6001600160a01b0384165f81815260108301602052604090819020805486151560ff1990911617905551919250907f133037347700fe9a7e5fffb139c832853fc52536035550fc6bc3b3f6207fd875906121b790851515815260200190565b60405180910390a2505050565b5f806121ce61291a565b6001600160a01b039093165f90815260109093016020525050604090205460ff1690565b5f806121fc61291a565b600101546001600160a01b031692915050565b5f8061221961291a565b600d015492915050565b61222b6133f2565b5f61223461291a565b80549091506001600160a01b03858116911614801590612264575060018101546001600160a01b03858116911614155b156122825760405163c1ab6dc160e01b815260040160405180910390fd5b604080516060810182525f8082526020820181905291810191909152846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122fe919061483e565b60ff166040820181905261231390600a61493e565b6123248566038d7ea4c68000614688565b61232e91906146b3565b93508060400151600a612341919061493e565b6123528466038d7ea4c68000614688565b61235c91906146b3565b92506001600160771b0384118061237957506001600160771b0383115b15612397576040516342d22d2760e11b815260040160405180910390fd5b600e84810b825283900b60208201526123af81613913565b6001600160a01b0385165f9081526011830160209081526040918290208351600182018054848701518688015160ff16600160f01b0260ff60f01b196effffffffffffffffffffffffffffff928316600160781b026001600160f01b0319909416929095169190911791909117929092169190911790558251608081018452905463ffffffff80821683526401000000008204811693830193909352600160401b8104600b90810b94830194909452600160a01b900490920b606083015261247a9190839061399e16565b6001600160a01b038087165f8181526011860160209081526040918290208551815492870151878501516060909801516bffffffffffffffffffffffff908116600160a01b029816600160401b0290961667ffffffffffffffff63ffffffff9788166401000000000267ffffffffffffffff1990951697909216969096179290921791909116939093179390931790915590517f0a59d45890c37e353ebb4ff4a00b4e5002b27b21e3a308daea7646097c12533f9061253a90849061494c565b60405180910390a25050505050565b6001600160a01b039182165f90815260666020908152604080832093909416825291909152205490565b61257b6133f2565b6001600160a01b0381166125a25760405163d92e233d60e01b815260040160405180910390fd5b5f6125ab61291a565b6008810180546001600160a01b038581166001600160a01b031983168117909355604051939450169182907fc1ba25a60afffd747fd25304e169131b7ae93932f7f3e508a8cec0e18fa12842905f90a3505050565b6126086133f2565b5f61261161291a565b90506001600160a01b03821661263a5760405163d92e233d60e01b815260040160405180910390fd5b600b810180546001600160a01b038481166001600160a01b0319831681179093556040519116919082907fd3890fc76afcfc31cba1dcf2c27b50e2541e4d75039c981855b5b5e03682aea0905f90a3505050565b5f8061269861291a565b60070154600160a01b900460ff1692915050565b6126b46133f2565b6001600160a01b0381166126db5760405163d92e233d60e01b815260040160405180910390fd5b5f6126e461291a565b6007810180546001600160a01b038581166001600160a01b031983168117909355604051939450169182907fe4630e6e66d263636ccf946c97182b0edb7bbea539a79dfa121bab7444e83b79905f90a3505050565b5f8061274361291a565b80549091506001600160a01b03848116911614801590612773575060018101546001600160a01b03848116911614155b156127915760405163c1ab6dc160e01b815260040160405180910390fd5b835f036127a1575f915050610c8f565b5f806127ab61293e565b845491935091506001600160a01b0390811690861603612807576127fd8684600201548560030154858588600a015489600901546127e99190614675565b6127f59061271061462a565b6127106139f7565b9350505050610c8f565b6127fd8684600301548560020154848688600a015489600901546127e99190614675565b6128336133f2565b6001600160a01b0381166128985760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016117c2565b6128a18161344c565b50565b5f806128ae61291a565b600801546001600160a01b031692915050565b6002600154036129135760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016117c2565b6002600155565b7fe40ad100017325097d9c1a3195cd4d2d97dcb316ccef4f208489777afd465d0090565b5f805f61294961291a565b6007810154600882015460405163073ad38560e21b81526001600160a01b0391821660048201529293501690631ceb4e14906024016040805180830381865afa158015612998573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129bc919061497a565b60078301549194509250600160a01b900460ff16156129d9579091905b509091565b5f806129e861291a565b90505f612a04878360020154670de0b6b3a76400008888613a43565b90508160030154670de0b6b3a7640000612a1e91906146b3565b612a289087614688565b9550612a348682614675565b925050505b949350505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612a93908490613a77565b505050565b5f612aa161291a565b90505f612ac1836101000151846101200151855f015186602001516129de565b90505f82600a01548360090154612ad89190614675565b90505f612ae78261271061462a565b828660c00151612af79190614688565b612b0191906146b3565b90505f612b108361271061462a565b838760e00151612b209190614688565b612b2a91906146b3565b90505f8560030154670de0b6b3a7640000612b4591906146b3565b82612b628589600201548a600301548c5f01518d60200151613a43565b612b6c9190614675565b612b769190614688565b90505f818860400151612b899190614675565b905080861015611c87576040516324d0394d60e21b815260040160405180910390fd5b5f612bb561291a565b600a8101549091505f819003612bcb5750505050565b8315612c0c575f612710612bdf8387614688565b612be991906146b3565b600b8401548454919250612c0a916001600160a01b03908116911683612a41565b505b821561205c575f612710612c208386614688565b612c2a91906146b3565b600b8401546001850154919250610bbd916001600160a01b03908116911683612a41565b5f612c5761291a565b80546040516370a0823160e01b81523060048201529192506001600160a01b0316906370a0823190602401602060405180830381865afa158015612c9d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cc191906145ff565b60048281019190915560018201546040516370a0823160e01b815230928101929092526001600160a01b0316906370a0823190602401602060405180830381865afa158015612d12573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d3691906145ff565b6005820181905542600683018190556004830154604080519182526020820193909352918201527ff71a0e183fe1c86e734de92237976be5699cb46fd28373d6ace2f8eafea2857c9060600160405180910390a150565b5f612d9661291a565b90505f81600a01548260090154612dad9190614675565b6001600160a01b0386165f908152601184016020908152604091829020825160c081018452815463ffffffff80821683870190815264010000000083048216606080860191909152600160401b8404600b90810b6080870152600160a01b90940490930b60a0850152835285519182018652600190930154600e81810b8352600160781b8204900b82860152600160f01b900460ff169481019490945291820192909252919250612e659190869086908590613b4816565b6001600160a01b039586165f908152601193909301602090815260409384902082518154928401519584015160609094015163ffffffff91821667ffffffffffffffff199094169390931764010000000091909616029490941767ffffffffffffffff16600160401b6bffffffffffffffffffffffff9384160290971696909617600160a01b9190961602949094179055505050565b6001600160a01b038316612f5d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016117c2565b6001600160a01b038216612fbe5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016117c2565b6001600160a01b038381165f8181526066602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b5f6130298484612549565b90505f19811461205c57818110156130835760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016117c2565b61205c8484848403612efb565b6001600160a01b0383166130f45760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016117c2565b6001600160a01b0382166131565760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016117c2565b6001600160a01b0383165f90815260656020526040902054818110156131cd5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016117c2565b6001600160a01b038085165f8181526065602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061322c9086815260200190565b60405180910390a361205c565b5f815f0361324857505f919050565b5f600161325484613c62565b901c6001901b9050600181848161326d5761326d61469f565b048201901c905060018184816132855761328561469f565b048201901c9050600181848161329d5761329d61469f565b048201901c905060018184816132b5576132b561469f565b048201901c905060018184816132cd576132cd61469f565b048201901c905060018184816132e5576132e561469f565b048201901c905060018184816132fd576132fd61469f565b048201901c9050610ce1818285816133175761331761469f565b046133dd565b6001600160a01b0382166133735760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016117c2565b8060675f8282546133849190614675565b90915550506001600160a01b0382165f818152606560209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35b5050565b5f8183106133eb5781610ce1565b5090919050565b6097546001600160a01b0316331461131c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016117c2565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b0382166134fd5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016117c2565b6001600160a01b0382165f90815260656020526040902054818110156135705760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016117c2565b6001600160a01b0383165f8181526065602090815260408083208686039055606780548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b5f805f805f805f806135df61291a565b60088101549091506001600160a01b031661360d5760405163c311374360e01b815260040160405180910390fd5b6004810154158061362057506005810154155b1561363e57604051632532ba2760e21b815260040160405180910390fd5b61364661293e565b6003830154919950975061366290670de0b6b3a76400006146b3565b81600501546136719190614688565b95508060020154670de0b6b3a764000061368b91906146b3565b816004015461369a9190614688565b94506136a888888888613cf5565b94509150836136bb5780600f01546136c1565b80600e01545b92505090919293949596565b5f54610100900460ff166136f35760405162461bcd60e51b81526004016117c29061499c565b6133d98282613d5c565b5f54610100900460ff166137235760405162461bcd60e51b81526004016117c29061499c565b61131c613d9b565b5f8061373561291a565b90505f8160030154670de0b6b3a764000061375091906146b3565b826005015461375f9190614688565b90505f8260020154670de0b6b3a764000061377a91906146b3565b83600401546137899190614688565b90505f61379f865f015187602001518585613cf5565b6060880151919650915085106137c857604051630473142360e21b815260040160405180910390fd5b8561014001511515811515146137f157604051632511b62160e11b815260040160405180910390fd5b808015613801575083600e015485105b1561381f5760405163ee269e6f60e01b815260040160405180910390fd5b80158015613830575083600f015485105b1561384e5760405163ee269e6f60e01b815260040160405180910390fd5b6080860151156138b3575f6138868760e00151866003015487600201548a602001518b5f01518a600d01546127106127f5919061462a565b905080876080015110156138ad57604051635b0d893360e01b815260040160405180910390fd5b5061390a565b5f6138e18760c00151866002015487600301548a5f01518b602001518a600d01546127106127f5919061462a565b9050808760a001511015613908576040516302fcdf2f60e31b815260040160405180910390fd5b505b50505050919050565b5f815f0151600e0b13801561392e57505f8160200151600e0b135b80156139475750805f0151600e0b8160200151600e0b13155b156139655760405163588f2bd160e11b815260040160405180910390fd5b604081015160ff1615806139805750806040015160ff166012105b156128a157604051630692acc560e51b815260040160405180910390fd5b604080516080810182525f8082526020820181905291810182905260608101919091525f808452602084018190528251600e0b90036139de575f60408401525b8160200151600e0b5f036133eb5750505f606082015290565b5f81613a038886614688565b613a0d9190614688565b8387613a19888c614688565b613a239190614688565b613a2d9190614688565b613a3791906146b3565b98975050505050505050565b5f613a4e8583614688565b84613a598589614688565b613a639190614688565b613a6d91906146b3565b9695505050505050565b5f613acb826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613dca9092919063ffffffff16565b805190915015612a935780806020019051810190613ae991906149e7565b612a935760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016117c2565b604080516080810182525f808252602080830182905292820181905260608201529085015151600e0b158015613b8657506020808601510151600e0b155b15613b9357508351612a39565b5f613ba685876020015160400151613dd8565b90505f613bbb85886020015160400151613dd8565b9050612710613bca8584614688565b613bd491906146b3565b613bde908361462a565b91505f613beb8284614a02565b90506b7fffffffffffffffffffffff811380613c1357506b7fffffffffffffffffffffff1981125b15613c315760405163af2ae3e960e01b815260040160405180910390fd5b613c43885f0151896020015183613e13565b8089526020890151613c559190613ef9565b5050945195945050505050565b5f80608083901c15613c7657608092831c92015b604083901c15613c8857604092831c92015b602083901c15613c9a57602092831c92015b601083901c15613cac57601092831c92015b600883901c15613cbe57600892831c92015b600483901c15613cd057600492831c92015b600283901c15613ce257600292831c92015b600183901c15610c8f5760010192915050565b5f8080613d028488614688565b90505f613d0f8787614688565b905081811192505f83613d2b57613d26828461462a565b613d35565b613d35838361462a565b905082613d4461271083614688565b613d4e91906146b3565b945050505094509492505050565b5f54610100900460ff16613d825760405162461bcd60e51b81526004016117c29061499c565b6068613d8e8382614a6c565b506069612a938282614a6c565b5f54610100900460ff16613dc15760405162461bcd60e51b81526004016117c29061499c565b61131c3361344c565b6060612a3984845f85613fb6565b5f825f03613de757505f610c8f565b5f613df383600a61493e565b613dff600f600a61493e565b613e099086614688565b612a3991906146b3565b604080516080810182525f80825260208201819052918101829052606081019190915281600b0b5f03613e47575082610ce1565b5f835f0151600e0b1315613e98578351613e649061012c90614b2c565b63ffffffff16421115613e81575f604085015263ffffffff421684525b613e8f846040015183614082565b600b0b60408501525b5f8360200151600e0b1315613ef157620151808460200151613eba9190614b2c565b63ffffffff16421115613eda575f606085015263ffffffff421660208501525b613ee8846060015183614082565b600b0b60608501525b509192915050565b5f815f0151600e0b138015613f3757508051613f1490614b49565b600e0b8260400151600b0b1280613f375750805f0151600e0b8260400151600b0b135b15613f5557604051630493e48f60e41b815260040160405180910390fd5b5f8160200151600e0b138015613f9857508060200151613f7490614b49565b600e0b8260600151600b0b1280613f9857508060200151600e0b8260600151600b0b135b156133d9576040516391336c6960e01b815260040160405180910390fd5b6060824710156140175760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016117c2565b5f80866001600160a01b031685876040516140329190614b6d565b5f6040518083038185875af1925050503d805f811461406c576040519150601f19603f3d011682016040523d82523d5f602084013e614071565b606091505b5091509150612a34878383876140dc565b5f8082600b0b84600b0b6140969190614b88565b90506b7fffffffffffffffffffffff198112806140be57506b7fffffffffffffffffffffff81135b15610ce157604051631bd6ac1960e11b815260040160405180910390fd5b6060831561414a5782515f03614143576001600160a01b0385163b6141435760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016117c2565b5081612a39565b612a39838381511561415f5781518083602001fd5b8060405162461bcd60e51b81526004016117c291906142aa565b6040518061016001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f151581525090565b80356001600160a01b03811681146112f2575f80fd5b5f8083601f8401126141f0575f80fd5b50813567ffffffffffffffff811115614207575f80fd5b60208301915083602082850101111561421e575f80fd5b9250929050565b5f805f805f60808688031215614239575f80fd5b8535945060208601359350614250604087016141ca565b9250606086013567ffffffffffffffff81111561426b575f80fd5b614277888289016141e0565b969995985093965092949392505050565b5f5b838110156142a257818101518382015260200161428a565b50505f910152565b602081525f82518060208401526142c8816040850160208701614288565b601f01601f19169190910160400192915050565b5f80604083850312156142ed575f80fd5b6142f6836141ca565b946020939093013593505050565b5f805f60608486031215614316575f80fd5b61431f846141ca565b925061432d602085016141ca565b9150604084013590509250925092565b5f6020828403121561434d575f80fd5b5035919050565b5f60208284031215614364575f80fd5b610ce1826141ca565b60e0810161439b82858051600e0b82526020810151600e0b602083015260ff60408201511660408301525050565b63ffffffff808451166060840152806020850151166080840152506040830151600b0b60a08301526060830151600b0b60c08301529392505050565b80151581146128a1575f80fd5b5f602082840312156143f4575f80fd5b8135610ce1816143d7565b5f805f805f805f8789036101a0811215614417575f80fd5b614420896141ca565b975061442e60208a016141ca565b965061443c60408a016141ca565b955061444a60608a016141ca565b9450608089013561445a816143d7565b935061446860a08a016141ca565b925060e060bf198201121561447b575f80fd5b5060c08801905092959891949750929550565b5f805f80606085870312156144a1575f80fd5b8435935060208501359250604085013567ffffffffffffffff8111156144c5575f80fd5b6144d1878288016141e0565b95989497509550505050565b5f80604083850312156144ee575f80fd5b50508035926020909101359150565b5f806040838503121561450e575f80fd5b614517836141ca565b91506020830135614527816143d7565b809150509250929050565b5f805f60608486031215614544575f80fd5b61454d846141ca565b95602085013595506040909401359392505050565b5f8060408385031215614573575f80fd5b61457c836141ca565b915061458a602084016141ca565b90509250929050565b5f80604083850312156145a4575f80fd5b8235915061458a602084016141ca565b60018060a01b038616815284602082015283604082015260806060820152816080820152818360a08301375f81830160a090810191909152601f909201601f19160101949350505050565b5f6020828403121561460f575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610c8f57610c8f614616565b600181811c9082168061465157607f821691505b60208210810361466f57634e487b7160e01b5f52602260045260245ffd5b50919050565b80820180821115610c8f57610c8f614616565b8082028115828204841417610c8f57610c8f614616565b634e487b7160e01b5f52601260045260245ffd5b5f826146cd57634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52604160045260245ffd5b5f602082840312156146f6575f80fd5b815167ffffffffffffffff8082111561470d575f80fd5b818401915084601f830112614720575f80fd5b815181811115614732576147326146d2565b604051601f8201601f19908116603f0116810190838211818310171561475a5761475a6146d2565b81604052828152876020848701011115614772575f80fd5b614783836020830160208801614288565b979650505050505050565b7f4d656e746f204669786564205072696365204d4d202d2000000000000000000081525f83516147c5816017850160208801614288565b602f60f81b60179184019182015283516147e6816018840160208801614288565b01601801949350505050565b6446504d4d2d60d81b81525f8351614811816005850160208801614288565b602f60f81b6005918401918201528351614832816006840160208801614288565b01600601949350505050565b5f6020828403121561484e575f80fd5b815160ff81168114610ce1575f80fd5b600181815b8085111561489857815f190482111561487e5761487e614616565b8085161561488b57918102915b93841c9390800290614863565b509250929050565b5f826148ae57506001610c8f565b816148ba57505f610c8f565b81600181146148d057600281146148da576148f6565b6001915050610c8f565b60ff8411156148eb576148eb614616565b50506001821b610c8f565b5060208310610133831016604e8410600b8410161715614919575081810a610c8f565b614923838361485e565b805f190482111561493657614936614616565b029392505050565b5f610ce160ff8416836148a0565b60608101610c8f82848051600e0b82526020810151600e0b602083015260ff60408201511660408301525050565b5f806040838503121561498b575f80fd5b505080516020909101519092909150565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f602082840312156149f7575f80fd5b8151610ce1816143d7565b8181035f831280158383131683831282161715614a2157614a21614616565b5092915050565b601f821115612a9357805f5260205f20601f840160051c81016020851015614a4d5750805b601f840160051c820191505b81811015610bbd575f8155600101614a59565b815167ffffffffffffffff811115614a8657614a866146d2565b614a9a81614a94845461463d565b84614a28565b602080601f831160018114614acd575f8415614ab65750858301515b5f19600386901b1c1916600185901b178555614b24565b5f85815260208120601f198616915b82811015614afb57888601518255948401946001909101908401614adc565b5085821015614b1857878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b63ffffffff818116838216019080821115614a2157614a21614616565b5f81600e0b6001600160771b03198103614b6557614b65614616565b5f0392915050565b5f8251614b7e818460208701614288565b9190910192915050565b8082018281125f831280158216821582161715614ba757614ba7614616565b50509291505056fea264697066735822122036a4aef1559e156203e60113279294072258195f4e8597486d96a466b0fb3a0964736f6c63430008180033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"cancun","libraries":{},"metadata":{"bytecodeHash":"ipfs"},"optimizer":{"enabled":true,"runs":200},"remappings":[":@celo/=lib/mento-core/node_modules/@celo/contracts/",":@chainlink/contracts/=lib/mento-core/lib/foundry-chainlink-toolkit/lib/chainlink-brownie-contracts/contracts/src/",":@ds/=lib/mento-router/lib/multicall/lib/ds-test/src/",":@openzeppelin/=lib/mento-core/lib/foundry-chainlink-toolkit/lib/openzeppelin-contracts/",":@prb/test/=lib/mento-core/lib/prb-math/lib/prb-test/src/",":@std/=lib/mento-router/lib/multicall/lib/forge-std/src/",":BokkyPooBahsDateTimeLibrary/=lib/mento-core/lib/BokkyPooBahsDateTimeLibrary/",":Solady/=lib/bold/contracts/lib/Solady/src/",":V2-gov/=lib/bold/contracts/lib/V2-gov/",":bold/=lib/bold/contracts/",":celo/=lib/mento-core/node_modules/@celo/",":chainlink-brownie-contracts/=lib/mento-core/lib/foundry-chainlink-toolkit/lib/chainlink-brownie-contracts/contracts/src/v0.6/vendor/@arbitrum/nitro-contracts/src/",":chimera/=lib/bold/contracts/lib/V2-gov/lib/chimera/src/",":contracts/=lib/mento-core/contracts/",":createx-forge/=lib/treb-sol/lib/createx-forge/",":ds-test/=lib/mento-router/lib/multicall/lib/ds-test/src/",":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",":forge-std/=lib/forge-std/src/",":foundry-chainlink-toolkit/=lib/mento-core/lib/foundry-chainlink-toolkit/",":halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",":mento-core/=lib/mento-core/contracts/",":mento-router/=lib/mento-router/",":mento-std/=lib/mento-std/src/",":multicall/=lib/mento-router/lib/multicall/src/",":openzeppelin-contracts-next/=lib/mento-core/lib/openzeppelin-contracts-next/",":openzeppelin-contracts-upgradeable/=lib/mento-core/lib/openzeppelin-contracts-upgradeable/",":openzeppelin-contracts/=lib/mento-core/lib/openzeppelin-contracts-next/",":openzeppelin-solidity/=lib/mento-core/lib/openzeppelin-contracts/",":openzeppelin/=lib/mento-core/lib/openzeppelin-contracts/",":prb-math/=lib/mento-core/lib/prb-math/src/",":prb-test/=lib/mento-core/lib/prb-math/lib/prb-test/src/",":prb/math/=lib/mento-core/lib/prb-math/src/",":safe-contracts/=lib/mento-core/lib/safe-contracts/",":safe-smart-account/=lib/treb-sol/lib/safe-utils/lib/safe-smart-account/contracts/",":safe-utils/=lib/treb-sol/lib/safe-utils/src/",":solidity-http/=lib/treb-sol/lib/safe-utils/lib/solidity-http/src/",":solidity-stringutils/=lib/treb-sol/lib/safe-utils/lib/solidity-stringutils/",":src/=src/",":test/=lib/mento-core/test/",":treb-sol/=lib/treb-sol/","lib/bold/:openzeppelin-contracts/=lib/bold/contracts/lib/openzeppelin-contracts/","lib/mento-core/lib/bold/:openzeppelin-contracts/=lib/mento-core/lib/bold/contracts/lib/openzeppelin-contracts/"]},"optimization_runs":200,"sourcify_repo_url":"https://repo.sourcify.dev/contracts/partial_match/42220/0x8cB0518a0510Ab62450F79f3cD9EE0cbdDB77F30/","decoded_constructor_args":[["true",{"internalType":"bool","name":"disable","type":"bool"}]],"compiler_version":"0.8.24+commit.e11b9ed9","is_verified_via_verifier_alliance":false,"verified_at":"2026-04-13T18:32:20.504036Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x608060405234801562000010575f80fd5b5060405162004d2538038062004d2583398101604081905262000033916200010a565b80156200004457620000446200004b565b5062000132565b5f54610100900460ff1615620000b75760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff908116101562000108575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b5f602082840312156200011b575f80fd5b815180151581146200012b575f80fd5b9392505050565b614be580620001405f395ff3fe608060405234801561000f575f80fd5b5060043610610372575f3560e01c80638da5cb5b116101d4578063c6bf342011610109578063dd62ed3e116100a9578063edb6d07511610079578063edb6d0751461076c578063f140a35a1461077f578063f2fde38b14610792578063fb1a6375146107a5575f80fd5b8063dd62ed3e1461072b578063e4da518a1461073e578063e521cb9214610751578063ea9274b814610764575f80fd5b8063cfa498a3116100e4578063cfa498a3146106ff578063d21220a714610708578063d4ac735314610710578063da7ddb8f14610718575f80fd5b8063c6bf3420146106c6578063cce441a3146106d9578063ce746e66146106ec575f80fd5b8063a9059cbb11610174578063ba9a7a561161014f578063ba9a7a561461068f578063c20a9ca514610698578063c5700a02146106ab578063c60801b7146106b3575f80fd5b8063a9059cbb14610661578063b0e21e8a14610674578063b19805af1461067c575f80fd5b806396cd3bce116101af57806396cd3bce1461060b5780639d63848a1461061e578063a28af8a414610646578063a457c2d71461064e575f80fd5b80638da5cb5b146105af57806393965ec9146105c057806395d89b4114610603575f80fd5b806356bd16ab116102aa578063704ce43e1161024a578063787dce3d11610225578063787dce3d146105645780637bdd6b441461057757806387cf3ef41461057f57806389afcb4414610587575f80fd5b8063704ce43e1461052c57806370a0823114610534578063715018a61461055c575f80fd5b80636391f7db116102855780636391f7db146104dd57806363e979c1146104fe57806364df049e146105115780636a62784214610519575f80fd5b806356bd16ab146104c65780635a76f25e146104ce5780635ca0c578146104d6575f80fd5b806323b872dd1161031557806339509351116102f057806339509351146104905780633d9f3163146104a3578063443cb4bc146104ab57806353cb6a5e146104b3575f80fd5b806323b872dd1461042d578063313ce56714610440578063392f37e91461044f575f80fd5b8063095ea7b311610350578063095ea7b3146103cc5780630c99c084146103ef5780630dfe16811461040557806318160ddd14610425575f80fd5b8063022c0d9f1461037657806306fdde031461038b5780630902f1ac146103a9575b5f80fd5b610389610384366004614225565b6107ad565b005b610393610bc4565b6040516103a091906142aa565b60405180910390f35b6103b1610c54565b604080519384526020840192909252908201526060016103a0565b6103df6103da3660046142dc565b610c7c565b60405190151581526020016103a0565b6103f7610c95565b6040519081526020016103a0565b61040d610ca9565b6040516001600160a01b0390911681526020016103a0565b6067546103f7565b6103df61043b366004614304565b610cc3565b604051601281526020016103a0565b610457610ce8565b6040805196875260208701959095529385019290925260608401526001600160a01b0390811660808401521660a082015260c0016103a0565b6103df61049e3660046142dc565b610d33565b61040d610d54565b6103f7610d71565b6103896104c136600461433d565b610d85565b6103f7610e74565b6103f7610e88565b6103f75f81565b6104f06104eb366004614354565b610e9c565b6040516103a092919061436d565b61038961050c36600461433d565b610fd1565b61040d6110a7565b6103f7610527366004614354565b6110c4565b6103f76112f7565b6103f7610542366004614354565b6001600160a01b03165f9081526065602052604090205490565b61038961130b565b61038961057236600461433d565b61131e565b6103f761143b565b61040d61144f565b61059a610595366004614354565b61146c565b604080519283526020830191909152016103a0565b6097546001600160a01b031661040d565b6105c861166e565b6040805197885260208801969096529486019390935260608501919091521515608084015261ffff1660a083015260c082015260e0016103a0565b610393611693565b6103896106193660046143e4565b6116a2565b61062661171d565b604080516001600160a01b039384168152929091166020830152016103a0565b6103f7611745565b6103df61065c3660046142dc565b611759565b6103df61066f3660046142dc565b6117e3565b6103f76117f0565b61038961068a366004614354565b611804565b6103f76103e881565b6103896106a63660046143ff565b61186a565b6103f7611c91565b6103896106c136600461448e565b611ca5565b6103896106d43660046144dd565b612062565b6103896106e73660046144fd565b612120565b6103df6106fa366004614354565b6121c4565b6103f761271081565b61040d6121f2565b6103f761220f565b610389610726366004614532565b612223565b6103f7610739366004614562565b612549565b61038961074c366004614354565b612573565b61038961075f366004614354565b612600565b6103df61268e565b61038961077a366004614354565b6126ac565b6103f761078d366004614593565b612739565b6103896107a0366004614354565b61282b565b61040d6128a4565b6107b56128c1565b5f6107be61291a565b9050851580156107cc575084155b156107ea576040516342301c2360e01b815260040160405180910390fd5b806004015486101580610801575080600501548510155b1561081f5760405163bb55fd2760e01b815260040160405180910390fd5b80546001600160a01b0385811691161480610849575060018101546001600160a01b038581169116145b1561086757604051638aa3a72f60e01b815260040160405180910390fd5b61086f614179565b60c0810187905260e0810186905261088561293e565b60208301819052818352600484015460058501546108a79391929091906129de565b604082015286156108c85781546108c8906001600160a01b03168689612a41565b85156108e75760018201546108e7906001600160a01b03168688612a41565b821561094f57604051639a7bff7960e01b81526001600160a01b03861690639a7bff79906109219033908b908b908a908a906004016145b4565b5f604051808303815f87803b158015610938575f80fd5b505af115801561094a573d5f803e3d5ffd5b505050505b81546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610994573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109b891906145ff565b61010082015260018201546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015610a06573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a2a91906145ff565b6101208201526004820154610a4090889061462a565b81610100015111610a51575f610a71565b868260040154610a61919061462a565b816101000151610a71919061462a565b60808201526005820154610a8690879061462a565b81610120015111610a97575f610ab7565b858260050154610aa7919061462a565b816101200151610ab7919061462a565b60a08201526080810151158015610ad0575060a0810151155b15610aee5760405163098fb56160e01b815260040160405180910390fd5b610af781612a98565b610b0981608001518260a00151612bac565b610b11612c4e565b8154608082015160c0830151610b31926001600160a01b03169190612d8d565b600182015460a082015160e0830151610b54926001600160a01b03169190612d8d565b60808082015160a08301516040805192835260208301919091528101899052606081018890526001600160a01b0387169133917fd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822910160405180910390a35050610bbd60018055565b5050505050565b606060688054610bd39061463d565b80601f0160208091040260200160405190810160405280929190818152602001828054610bff9061463d565b8015610c4a5780601f10610c2157610100808354040283529160200191610c4a565b820191905f5260205f20905b815481529060010190602001808311610c2d57829003601f168201915b5050505050905090565b5f805f80610c6061291a565b6004810154600582015460069092015490969195509350915050565b5f33610c89818585612efb565b60019150505b92915050565b5f80610c9f61291a565b600f015492915050565b5f80610cb361291a565b546001600160a01b031692915050565b5f33610cd085828561301e565b610cdb858585613090565b60019150505b9392505050565b5f805f805f805f610cf761291a565b60028101546003820154600483015460058401548454600190950154939c929b5090995097506001600160a01b03928316965091169350915050565b5f33610c89818585610d458383612549565b610d4f9190614675565b612efb565b5f80610d5e61291a565b600701546001600160a01b031692915050565b5f80610d7b61291a565b6004015492915050565b5f610d8e61291a565b9050610da26097546001600160a01b031690565b6001600160a01b0316336001600160a01b031614158015610dd05750600c8101546001600160a01b03163314155b15610dee5760405163e4ed485760e01b815260040160405180910390fd5b5f610df761291a565b905060c881600a015484610e0b9190614675565b1115610e2a5760405163cd4e616760e01b815260040160405180910390fd5b6009810180549084905560408051828152602081018690527fb5d5dda8af4f1e40a5cc4aa66c39ca5aac7f90947261313b07527eb3bdd98bc791015b60405180910390a150505050565b5f80610e7e61291a565b600e015492915050565b5f80610e9261291a565b6005015492915050565b60408051606080820183525f8083526020808401829052838501829052845160808101865282815290810182905293840181905290830152905f610ede61291a565b80549091506001600160a01b03858116911614801590610f0e575060018101546001600160a01b03858116911614155b15610f2c5760405163c1ab6dc160e01b815260040160405180910390fd5b6001600160a01b039093165f8181526011909401602081815260408087208151606080820184526001830154600e81810b8452600160781b8204900b8387015260ff600160f01b9091041682850152959098529282528051608081018252925463ffffffff808216855264010000000082041692840192909252600160401b8204600b90810b91840191909152600160a01b909104900b918101919091529293915050565b5f610fda61291a565b9050610fee6097546001600160a01b031690565b6001600160a01b0316336001600160a01b03161415801561101c5750600c8101546001600160a01b03163314155b1561103a5760405163e4ed485760e01b815260040160405180910390fd5b5f61104361291a565b905060648311156110675760405163712202ab60e01b815260040160405180910390fd5b600d810180549084905560408051828152602081018690527fb273226859e3e49fd86c9ac8f721eaa74e677de0877db704918e0f43ec8d23bc9101610e66565b5f806110b161291a565b600b01546001600160a01b031692915050565b5f6110cd6128c1565b5f6110d661291a565b80546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611120573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061114491906145ff565b60018301546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611191573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111b591906145ff565b90505f8360040154836111c8919061462a565b90505f8460050154836111db919061462a565b90505f6111e760675490565b9050805f03611223576103e86112056112008486614688565b613239565b61120f919061462a565b965061121e60016103e861331d565b611261565b600486015461125e906112368386614688565b61124091906146b3565b600588015461124f8486614688565b61125991906146b3565b6133dd565b96505b6103e8871161128357604051633489be7560e21b815260040160405180910390fd5b61128d888861331d565b611295612c4e565b60408051848152602081018490529081018890526001600160a01b0389169033907fa8137fff86647d8a402117b9c5dbda627f721d3773338fb9678c83e54ed390809060600160405180910390a35050505050506112f260018055565b919050565b5f8061130161291a565b6009015492915050565b6113136133f2565b61131c5f61344c565b565b5f61132761291a565b905061133b6097546001600160a01b031690565b6001600160a01b0316336001600160a01b0316141580156113695750600c8101546001600160a01b03163314155b156113875760405163e4ed485760e01b815260040160405180910390fd5b5f61139061291a565b90505f831180156113ac5750600b8101546001600160a01b0316155b156113ca576040516342123e7160e11b815260040160405180910390fd5b60c88160090154846113dc9190614675565b11156113fb5760405163cd4e616760e01b815260040160405180910390fd5b600a810180549084905560408051828152602081018690527fb404cac19fb1cbeff98d325795b08886e3cd8fe8cb1a2f193aac66f13fb239c39101610e66565b5f8061144561291a565b6002015492915050565b5f8061145961291a565b600c01546001600160a01b031692915050565b5f806114766128c1565b5f61147f61291a565b80546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156114c9573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114ed91906145ff565b60018301546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa15801561153a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061155e91906145ff565b305f90815260656020526040902054606754919250908061157f8584614688565b61158991906146b3565b9650806115968484614688565b6115a091906146b3565b9550861580156115ae575085155b156115cc5760405163749383ad60e01b815260040160405180910390fd5b6115d6308361349d565b84546115ec906001600160a01b03168989612a41565b6001850154611605906001600160a01b03168988612a41565b61160d612c4e565b60408051888152602081018890529081018390526001600160a01b0389169033907fd175a80c109434bb89948928ab2475a6647c94244cb70002197896423c8833639060600160405180910390a3505050505061166960018055565b915091565b5f805f805f805f61167d6135cf565b959d949c50929a50909850965094509092509050565b606060698054610bd39061463d565b6116aa6133f2565b5f6116b361291a565b60078101805460ff60a01b198116600160a01b86151581810292909217909355604080519390920460ff16801515845260208401919091529293507eaf8726a3679feb41b28b0996e403259aceb28ec6f3c6c3dc7a4c4fe6c8fce1910160405180910390a1505050565b5f805f61172861291a565b80546001909101546001600160a01b039182169591169350915050565b5f8061174f61291a565b6003015492915050565b5f33816117668286612549565b9050838110156117cb5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084015b60405180910390fd5b6117d88286868403612efb565b506001949350505050565b5f33610c89818585613090565b5f806117fa61291a565b600a015492915050565b61180c6133f2565b5f61181561291a565b600c810180546001600160a01b038581166001600160a01b031983168117909355604051939450169182907f83b887657b0e2cbbed6d7b9468d78fe27ce257d950e1c7e36572b3a24f82e41c905f90a3505050565b5f54610100900460ff161580801561188857505f54600160ff909116105b806118a15750303b1580156118a157505f5460ff166001145b6119045760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016117c2565b5f805460ff191660011790558015611925575f805461ff0019166101001790555b5f61192e61291a565b80546001600160a01b03199081166001600160a01b038c81169182178455600184018054909316908c1617909155604080516395d89b4160e01b815290519293505f926395d89b419160048082019286929091908290030181865afa158015611999573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526119c091908101906146e6565b90505f896001600160a01b03166395d89b416040518163ffffffff1660e01b81526004015f60405180830381865afa1580156119fe573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611a2591908101906146e6565b90505f8282604051602001611a3b92919061478e565b60405160208183030381529060405290505f8383604051602001611a609291906147f2565b6040516020818303038152906040529050611a7b82826136cd565b611a836136fd565b5f8d6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ac0573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ae4919061483e565b90505f8d6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b23573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b47919061483e565b905060128260ff161180611b5e575060128160ff16115b15611b7c5760405163686d360760e01b815260040160405180910390fd5b611b8782600a61493e565b6002880155611b9781600a61493e565b6003880155611bac60808a0160608b01614354565b600c880180546001600160a01b0319166001600160a01b0392909216919091179055611bd88935610d85565b611beb61075f60608b0160408c01614354565b611bf8896020013561131e565b611c058960800135610fd1565b611c178960a001358a60c00135612062565b611c208d6126ac565b611c298c612573565b611c328b6116a2565b611c3b8a61282b565b505050505050508015611c87575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050505050505050565b5f80611c9b61291a565b6006015492915050565b611cad6128c1565b611cb5612c4e565b5f611cbe61291a565b335f90815260108201602052604090205490915060ff16611cf257604051633b040b3f60e21b815260040160405180910390fd5b83151585151503611d1657604051635747f31560e01b815260040160405180910390fd5b806004015485101580611d2d575080600501548410155b15611d4b5760405163bb55fd2760e01b815260040160405180910390fd5b611d53614179565b60c0810186905260e081018590525f611d6a6135cf565b606089018190529115156101408901526020880194909452938652505061ffff169150811115611dad576040516359658c6b60e01b815260040160405180910390fd5b8615611dc9578254611dc9906001600160a01b03163389612a41565b8515611de8576001830154611de8906001600160a01b03163388612a41565b8315611e4757604051634574893160e11b81523390638ae9126290611e199083908b908b908b908b906004016145b4565b5f604051808303815f87803b158015611e30575f80fd5b505af1158015611e42573d5f803e3d5ffd5b505050505b82546040516370a0823160e01b81523060048201525f916001600160a01b0316906370a0823190602401602060405180830381865afa158015611e8c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611eb091906145ff565b60018501546040516370a0823160e01b81523060048201529192505f916001600160a01b03909116906370a0823190602401602060405180830381865afa158015611efd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f2191906145ff565b90505f898660040154611f34919061462a565b8311611f40575f611f5a565b898660040154611f50919061462a565b611f5a908461462a565b90505f898760050154611f6d919061462a565b8311611f79575f611f93565b898760050154611f89919061462a565b611f93908461462a565b90505f8b118015611fa357505f81115b8015611fad575081155b80611fcb57505f8a118015611fc157505f82115b8015611fcb575080155b611fe85760405163737dec7160e11b815260040160405180910390fd5b6080860182905260a08601819052611ffe612c4e565b5f6120088761372b565b6060880151604080519182526020820183905291925033917f3645b7cfbb41ac8e6dcc3c4877ede2c60b467a0374b7a7fc7563f0a09580999e910160405180910390a2505050505050505061205c60018055565b50505050565b61206a6133f2565b5f61207361291a565b9050612710831115612098576040516306e41b9760e51b815260040160405180910390fd5b6113888211156120bb576040516306e41b9760e51b815260040160405180910390fd5b600e81018054600f83018054928690558490556040805182815260208101849052908101869052606081018590529091907f77c5ddba87b3d3f970242eda9bb1263ade9e4aed3eca233d5fa1af00a574b0259060800160405180910390a15050505050565b6121286133f2565b6001600160a01b03821661214f5760405163d92e233d60e01b815260040160405180910390fd5b5f61215861291a565b6001600160a01b0384165f81815260108301602052604090819020805486151560ff1990911617905551919250907f133037347700fe9a7e5fffb139c832853fc52536035550fc6bc3b3f6207fd875906121b790851515815260200190565b60405180910390a2505050565b5f806121ce61291a565b6001600160a01b039093165f90815260109093016020525050604090205460ff1690565b5f806121fc61291a565b600101546001600160a01b031692915050565b5f8061221961291a565b600d015492915050565b61222b6133f2565b5f61223461291a565b80549091506001600160a01b03858116911614801590612264575060018101546001600160a01b03858116911614155b156122825760405163c1ab6dc160e01b815260040160405180910390fd5b604080516060810182525f8082526020820181905291810191909152846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156122da573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906122fe919061483e565b60ff166040820181905261231390600a61493e565b6123248566038d7ea4c68000614688565b61232e91906146b3565b93508060400151600a612341919061493e565b6123528466038d7ea4c68000614688565b61235c91906146b3565b92506001600160771b0384118061237957506001600160771b0383115b15612397576040516342d22d2760e11b815260040160405180910390fd5b600e84810b825283900b60208201526123af81613913565b6001600160a01b0385165f9081526011830160209081526040918290208351600182018054848701518688015160ff16600160f01b0260ff60f01b196effffffffffffffffffffffffffffff928316600160781b026001600160f01b0319909416929095169190911791909117929092169190911790558251608081018452905463ffffffff80821683526401000000008204811693830193909352600160401b8104600b90810b94830194909452600160a01b900490920b606083015261247a9190839061399e16565b6001600160a01b038087165f8181526011860160209081526040918290208551815492870151878501516060909801516bffffffffffffffffffffffff908116600160a01b029816600160401b0290961667ffffffffffffffff63ffffffff9788166401000000000267ffffffffffffffff1990951697909216969096179290921791909116939093179390931790915590517f0a59d45890c37e353ebb4ff4a00b4e5002b27b21e3a308daea7646097c12533f9061253a90849061494c565b60405180910390a25050505050565b6001600160a01b039182165f90815260666020908152604080832093909416825291909152205490565b61257b6133f2565b6001600160a01b0381166125a25760405163d92e233d60e01b815260040160405180910390fd5b5f6125ab61291a565b6008810180546001600160a01b038581166001600160a01b031983168117909355604051939450169182907fc1ba25a60afffd747fd25304e169131b7ae93932f7f3e508a8cec0e18fa12842905f90a3505050565b6126086133f2565b5f61261161291a565b90506001600160a01b03821661263a5760405163d92e233d60e01b815260040160405180910390fd5b600b810180546001600160a01b038481166001600160a01b0319831681179093556040519116919082907fd3890fc76afcfc31cba1dcf2c27b50e2541e4d75039c981855b5b5e03682aea0905f90a3505050565b5f8061269861291a565b60070154600160a01b900460ff1692915050565b6126b46133f2565b6001600160a01b0381166126db5760405163d92e233d60e01b815260040160405180910390fd5b5f6126e461291a565b6007810180546001600160a01b038581166001600160a01b031983168117909355604051939450169182907fe4630e6e66d263636ccf946c97182b0edb7bbea539a79dfa121bab7444e83b79905f90a3505050565b5f8061274361291a565b80549091506001600160a01b03848116911614801590612773575060018101546001600160a01b03848116911614155b156127915760405163c1ab6dc160e01b815260040160405180910390fd5b835f036127a1575f915050610c8f565b5f806127ab61293e565b845491935091506001600160a01b0390811690861603612807576127fd8684600201548560030154858588600a015489600901546127e99190614675565b6127f59061271061462a565b6127106139f7565b9350505050610c8f565b6127fd8684600301548560020154848688600a015489600901546127e99190614675565b6128336133f2565b6001600160a01b0381166128985760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016117c2565b6128a18161344c565b50565b5f806128ae61291a565b600801546001600160a01b031692915050565b6002600154036129135760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016117c2565b6002600155565b7fe40ad100017325097d9c1a3195cd4d2d97dcb316ccef4f208489777afd465d0090565b5f805f61294961291a565b6007810154600882015460405163073ad38560e21b81526001600160a01b0391821660048201529293501690631ceb4e14906024016040805180830381865afa158015612998573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129bc919061497a565b60078301549194509250600160a01b900460ff16156129d9579091905b509091565b5f806129e861291a565b90505f612a04878360020154670de0b6b3a76400008888613a43565b90508160030154670de0b6b3a7640000612a1e91906146b3565b612a289087614688565b9550612a348682614675565b925050505b949350505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612a93908490613a77565b505050565b5f612aa161291a565b90505f612ac1836101000151846101200151855f015186602001516129de565b90505f82600a01548360090154612ad89190614675565b90505f612ae78261271061462a565b828660c00151612af79190614688565b612b0191906146b3565b90505f612b108361271061462a565b838760e00151612b209190614688565b612b2a91906146b3565b90505f8560030154670de0b6b3a7640000612b4591906146b3565b82612b628589600201548a600301548c5f01518d60200151613a43565b612b6c9190614675565b612b769190614688565b90505f818860400151612b899190614675565b905080861015611c87576040516324d0394d60e21b815260040160405180910390fd5b5f612bb561291a565b600a8101549091505f819003612bcb5750505050565b8315612c0c575f612710612bdf8387614688565b612be991906146b3565b600b8401548454919250612c0a916001600160a01b03908116911683612a41565b505b821561205c575f612710612c208386614688565b612c2a91906146b3565b600b8401546001850154919250610bbd916001600160a01b03908116911683612a41565b5f612c5761291a565b80546040516370a0823160e01b81523060048201529192506001600160a01b0316906370a0823190602401602060405180830381865afa158015612c9d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612cc191906145ff565b60048281019190915560018201546040516370a0823160e01b815230928101929092526001600160a01b0316906370a0823190602401602060405180830381865afa158015612d12573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d3691906145ff565b6005820181905542600683018190556004830154604080519182526020820193909352918201527ff71a0e183fe1c86e734de92237976be5699cb46fd28373d6ace2f8eafea2857c9060600160405180910390a150565b5f612d9661291a565b90505f81600a01548260090154612dad9190614675565b6001600160a01b0386165f908152601184016020908152604091829020825160c081018452815463ffffffff80821683870190815264010000000083048216606080860191909152600160401b8404600b90810b6080870152600160a01b90940490930b60a0850152835285519182018652600190930154600e81810b8352600160781b8204900b82860152600160f01b900460ff169481019490945291820192909252919250612e659190869086908590613b4816565b6001600160a01b039586165f908152601193909301602090815260409384902082518154928401519584015160609094015163ffffffff91821667ffffffffffffffff199094169390931764010000000091909616029490941767ffffffffffffffff16600160401b6bffffffffffffffffffffffff9384160290971696909617600160a01b9190961602949094179055505050565b6001600160a01b038316612f5d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016117c2565b6001600160a01b038216612fbe5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016117c2565b6001600160a01b038381165f8181526066602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b5f6130298484612549565b90505f19811461205c57818110156130835760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016117c2565b61205c8484848403612efb565b6001600160a01b0383166130f45760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016117c2565b6001600160a01b0382166131565760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016117c2565b6001600160a01b0383165f90815260656020526040902054818110156131cd5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016117c2565b6001600160a01b038085165f8181526065602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061322c9086815260200190565b60405180910390a361205c565b5f815f0361324857505f919050565b5f600161325484613c62565b901c6001901b9050600181848161326d5761326d61469f565b048201901c905060018184816132855761328561469f565b048201901c9050600181848161329d5761329d61469f565b048201901c905060018184816132b5576132b561469f565b048201901c905060018184816132cd576132cd61469f565b048201901c905060018184816132e5576132e561469f565b048201901c905060018184816132fd576132fd61469f565b048201901c9050610ce1818285816133175761331761469f565b046133dd565b6001600160a01b0382166133735760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016117c2565b8060675f8282546133849190614675565b90915550506001600160a01b0382165f818152606560209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35b5050565b5f8183106133eb5781610ce1565b5090919050565b6097546001600160a01b0316331461131c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016117c2565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b0382166134fd5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016117c2565b6001600160a01b0382165f90815260656020526040902054818110156135705760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016117c2565b6001600160a01b0383165f8181526065602090815260408083208686039055606780548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b5f805f805f805f806135df61291a565b60088101549091506001600160a01b031661360d5760405163c311374360e01b815260040160405180910390fd5b6004810154158061362057506005810154155b1561363e57604051632532ba2760e21b815260040160405180910390fd5b61364661293e565b6003830154919950975061366290670de0b6b3a76400006146b3565b81600501546136719190614688565b95508060020154670de0b6b3a764000061368b91906146b3565b816004015461369a9190614688565b94506136a888888888613cf5565b94509150836136bb5780600f01546136c1565b80600e01545b92505090919293949596565b5f54610100900460ff166136f35760405162461bcd60e51b81526004016117c29061499c565b6133d98282613d5c565b5f54610100900460ff166137235760405162461bcd60e51b81526004016117c29061499c565b61131c613d9b565b5f8061373561291a565b90505f8160030154670de0b6b3a764000061375091906146b3565b826005015461375f9190614688565b90505f8260020154670de0b6b3a764000061377a91906146b3565b83600401546137899190614688565b90505f61379f865f015187602001518585613cf5565b6060880151919650915085106137c857604051630473142360e21b815260040160405180910390fd5b8561014001511515811515146137f157604051632511b62160e11b815260040160405180910390fd5b808015613801575083600e015485105b1561381f5760405163ee269e6f60e01b815260040160405180910390fd5b80158015613830575083600f015485105b1561384e5760405163ee269e6f60e01b815260040160405180910390fd5b6080860151156138b3575f6138868760e00151866003015487600201548a602001518b5f01518a600d01546127106127f5919061462a565b905080876080015110156138ad57604051635b0d893360e01b815260040160405180910390fd5b5061390a565b5f6138e18760c00151866002015487600301548a5f01518b602001518a600d01546127106127f5919061462a565b9050808760a001511015613908576040516302fcdf2f60e31b815260040160405180910390fd5b505b50505050919050565b5f815f0151600e0b13801561392e57505f8160200151600e0b135b80156139475750805f0151600e0b8160200151600e0b13155b156139655760405163588f2bd160e11b815260040160405180910390fd5b604081015160ff1615806139805750806040015160ff166012105b156128a157604051630692acc560e51b815260040160405180910390fd5b604080516080810182525f8082526020820181905291810182905260608101919091525f808452602084018190528251600e0b90036139de575f60408401525b8160200151600e0b5f036133eb5750505f606082015290565b5f81613a038886614688565b613a0d9190614688565b8387613a19888c614688565b613a239190614688565b613a2d9190614688565b613a3791906146b3565b98975050505050505050565b5f613a4e8583614688565b84613a598589614688565b613a639190614688565b613a6d91906146b3565b9695505050505050565b5f613acb826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613dca9092919063ffffffff16565b805190915015612a935780806020019051810190613ae991906149e7565b612a935760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016117c2565b604080516080810182525f808252602080830182905292820181905260608201529085015151600e0b158015613b8657506020808601510151600e0b155b15613b9357508351612a39565b5f613ba685876020015160400151613dd8565b90505f613bbb85886020015160400151613dd8565b9050612710613bca8584614688565b613bd491906146b3565b613bde908361462a565b91505f613beb8284614a02565b90506b7fffffffffffffffffffffff811380613c1357506b7fffffffffffffffffffffff1981125b15613c315760405163af2ae3e960e01b815260040160405180910390fd5b613c43885f0151896020015183613e13565b8089526020890151613c559190613ef9565b5050945195945050505050565b5f80608083901c15613c7657608092831c92015b604083901c15613c8857604092831c92015b602083901c15613c9a57602092831c92015b601083901c15613cac57601092831c92015b600883901c15613cbe57600892831c92015b600483901c15613cd057600492831c92015b600283901c15613ce257600292831c92015b600183901c15610c8f5760010192915050565b5f8080613d028488614688565b90505f613d0f8787614688565b905081811192505f83613d2b57613d26828461462a565b613d35565b613d35838361462a565b905082613d4461271083614688565b613d4e91906146b3565b945050505094509492505050565b5f54610100900460ff16613d825760405162461bcd60e51b81526004016117c29061499c565b6068613d8e8382614a6c565b506069612a938282614a6c565b5f54610100900460ff16613dc15760405162461bcd60e51b81526004016117c29061499c565b61131c3361344c565b6060612a3984845f85613fb6565b5f825f03613de757505f610c8f565b5f613df383600a61493e565b613dff600f600a61493e565b613e099086614688565b612a3991906146b3565b604080516080810182525f80825260208201819052918101829052606081019190915281600b0b5f03613e47575082610ce1565b5f835f0151600e0b1315613e98578351613e649061012c90614b2c565b63ffffffff16421115613e81575f604085015263ffffffff421684525b613e8f846040015183614082565b600b0b60408501525b5f8360200151600e0b1315613ef157620151808460200151613eba9190614b2c565b63ffffffff16421115613eda575f606085015263ffffffff421660208501525b613ee8846060015183614082565b600b0b60608501525b509192915050565b5f815f0151600e0b138015613f3757508051613f1490614b49565b600e0b8260400151600b0b1280613f375750805f0151600e0b8260400151600b0b135b15613f5557604051630493e48f60e41b815260040160405180910390fd5b5f8160200151600e0b138015613f9857508060200151613f7490614b49565b600e0b8260600151600b0b1280613f9857508060200151600e0b8260600151600b0b135b156133d9576040516391336c6960e01b815260040160405180910390fd5b6060824710156140175760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016117c2565b5f80866001600160a01b031685876040516140329190614b6d565b5f6040518083038185875af1925050503d805f811461406c576040519150601f19603f3d011682016040523d82523d5f602084013e614071565b606091505b5091509150612a34878383876140dc565b5f8082600b0b84600b0b6140969190614b88565b90506b7fffffffffffffffffffffff198112806140be57506b7fffffffffffffffffffffff81135b15610ce157604051631bd6ac1960e11b815260040160405180910390fd5b6060831561414a5782515f03614143576001600160a01b0385163b6141435760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016117c2565b5081612a39565b612a39838381511561415f5781518083602001fd5b8060405162461bcd60e51b81526004016117c291906142aa565b6040518061016001604052805f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f81526020015f151581525090565b80356001600160a01b03811681146112f2575f80fd5b5f8083601f8401126141f0575f80fd5b50813567ffffffffffffffff811115614207575f80fd5b60208301915083602082850101111561421e575f80fd5b9250929050565b5f805f805f60808688031215614239575f80fd5b8535945060208601359350614250604087016141ca565b9250606086013567ffffffffffffffff81111561426b575f80fd5b614277888289016141e0565b969995985093965092949392505050565b5f5b838110156142a257818101518382015260200161428a565b50505f910152565b602081525f82518060208401526142c8816040850160208701614288565b601f01601f19169190910160400192915050565b5f80604083850312156142ed575f80fd5b6142f6836141ca565b946020939093013593505050565b5f805f60608486031215614316575f80fd5b61431f846141ca565b925061432d602085016141ca565b9150604084013590509250925092565b5f6020828403121561434d575f80fd5b5035919050565b5f60208284031215614364575f80fd5b610ce1826141ca565b60e0810161439b82858051600e0b82526020810151600e0b602083015260ff60408201511660408301525050565b63ffffffff808451166060840152806020850151166080840152506040830151600b0b60a08301526060830151600b0b60c08301529392505050565b80151581146128a1575f80fd5b5f602082840312156143f4575f80fd5b8135610ce1816143d7565b5f805f805f805f8789036101a0811215614417575f80fd5b614420896141ca565b975061442e60208a016141ca565b965061443c60408a016141ca565b955061444a60608a016141ca565b9450608089013561445a816143d7565b935061446860a08a016141ca565b925060e060bf198201121561447b575f80fd5b5060c08801905092959891949750929550565b5f805f80606085870312156144a1575f80fd5b8435935060208501359250604085013567ffffffffffffffff8111156144c5575f80fd5b6144d1878288016141e0565b95989497509550505050565b5f80604083850312156144ee575f80fd5b50508035926020909101359150565b5f806040838503121561450e575f80fd5b614517836141ca565b91506020830135614527816143d7565b809150509250929050565b5f805f60608486031215614544575f80fd5b61454d846141ca565b95602085013595506040909401359392505050565b5f8060408385031215614573575f80fd5b61457c836141ca565b915061458a602084016141ca565b90509250929050565b5f80604083850312156145a4575f80fd5b8235915061458a602084016141ca565b60018060a01b038616815284602082015283604082015260806060820152816080820152818360a08301375f81830160a090810191909152601f909201601f19160101949350505050565b5f6020828403121561460f575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b81810381811115610c8f57610c8f614616565b600181811c9082168061465157607f821691505b60208210810361466f57634e487b7160e01b5f52602260045260245ffd5b50919050565b80820180821115610c8f57610c8f614616565b8082028115828204841417610c8f57610c8f614616565b634e487b7160e01b5f52601260045260245ffd5b5f826146cd57634e487b7160e01b5f52601260045260245ffd5b500490565b634e487b7160e01b5f52604160045260245ffd5b5f602082840312156146f6575f80fd5b815167ffffffffffffffff8082111561470d575f80fd5b818401915084601f830112614720575f80fd5b815181811115614732576147326146d2565b604051601f8201601f19908116603f0116810190838211818310171561475a5761475a6146d2565b81604052828152876020848701011115614772575f80fd5b614783836020830160208801614288565b979650505050505050565b7f4d656e746f204669786564205072696365204d4d202d2000000000000000000081525f83516147c5816017850160208801614288565b602f60f81b60179184019182015283516147e6816018840160208801614288565b01601801949350505050565b6446504d4d2d60d81b81525f8351614811816005850160208801614288565b602f60f81b6005918401918201528351614832816006840160208801614288565b01600601949350505050565b5f6020828403121561484e575f80fd5b815160ff81168114610ce1575f80fd5b600181815b8085111561489857815f190482111561487e5761487e614616565b8085161561488b57918102915b93841c9390800290614863565b509250929050565b5f826148ae57506001610c8f565b816148ba57505f610c8f565b81600181146148d057600281146148da576148f6565b6001915050610c8f565b60ff8411156148eb576148eb614616565b50506001821b610c8f565b5060208310610133831016604e8410600b8410161715614919575081810a610c8f565b614923838361485e565b805f190482111561493657614936614616565b029392505050565b5f610ce160ff8416836148a0565b60608101610c8f82848051600e0b82526020810151600e0b602083015260ff60408201511660408301525050565b5f806040838503121561498b575f80fd5b505080516020909101519092909150565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b5f602082840312156149f7575f80fd5b8151610ce1816143d7565b8181035f831280158383131683831282161715614a2157614a21614616565b5092915050565b601f821115612a9357805f5260205f20601f840160051c81016020851015614a4d5750805b601f840160051c820191505b81811015610bbd575f8155600101614a59565b815167ffffffffffffffff811115614a8657614a866146d2565b614a9a81614a94845461463d565b84614a28565b602080601f831160018114614acd575f8415614ab65750858301515b5f19600386901b1c1916600185901b178555614b24565b5f85815260208120601f198616915b82811015614afb57888601518255948401946001909101908401614adc565b5085821015614b1857878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b63ffffffff818116838216019080821115614a2157614a21614616565b5f81600e0b6001600160771b03198103614b6557614b65614616565b5f0392915050565b5f8251614b7e818460208701614288565b9190910192915050565b8082018281125f831280158216821582161715614ba757614ba7614616565b50509291505056fea264697066735822122036a4aef1559e156203e60113279294072258195f4e8597486d96a466b0fb3a0964736f6c634300081800330000000000000000000000000000000000000000000000000000000000000001","name":"FPMM","is_blueprint":false,"license_type":"none","is_fully_verified":false,"is_verified_via_eth_bytecode_db":true,"language":"solidity","evm_version":"cancun","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":true,"additional_sources":[{"file_path":"lib/mento-core/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/contracts/interfaces/IFPMM.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n// solhint-disable func-name-mixedcase\n\nimport { IOracleAdapter } from \"./IOracleAdapter.sol\";\n\nimport { IRPool } from \"../swap/router/interfaces/IRPool.sol\";\nimport { ITradingLimitsV2 } from \"./ITradingLimitsV2.sol\";\n\ninterface IFPMM is IRPool {\n  /* ============================================================ */\n  /* ======================== Structs ============================ */\n  /* ============================================================ */\n\n  /// @notice Struct to store FPMM contract state\n  /// @custom:storage-location erc7201:mento.storage.FPMM\n  struct FPMMStorage {\n    // token0 is the stable token\n    address token0;\n    // token1 is the collateral token\n    address token1;\n    // decimals of token0 kepts as 10^decimals\n    uint256 decimals0;\n    // decimals of token1 kepts as 10^decimals\n    uint256 decimals1;\n    // reserve amount of token0\n    uint256 reserve0;\n    // reserve amount of token1\n    uint256 reserve1;\n    // timestamp of the last reserve update\n    uint256 blockTimestampLast;\n    // contract for querying oracle price feeds and trading modes\n    IOracleAdapter oracleAdapter;\n    // true if the rate feed should be inverted to quote asset0/asset1\n    bool invertRateFeed;\n    // identifier for the reference rate feed\n    // required for querying the oracle adapter\n    address referenceRateFeedID;\n    // fee taken from the swap for liquidity providers\n    uint256 lpFee;\n    // fee taken from the swap for the protocol\n    uint256 protocolFee;\n    // recipient of the protocol fee\n    address protocolFeeRecipient;\n    // address allowed to set fees (in addition to owner)\n    address feeSetter;\n    // incentive percentage for rebalancing the pool\n    uint256 rebalanceIncentive;\n    // threshold for rebalancing the pool when reserve price > oracle price\n    uint256 rebalanceThresholdAbove;\n    // threshold for rebalancing the pool when reserve price < oracle price\n    uint256 rebalanceThresholdBelow;\n    // true if the address is a trusted liquidity strategy\n    mapping(address => bool) liquidityStrategy;\n    // Trading limits per token\n    mapping(address => ITradingLimitsV2.TradingLimits) tradingLimits;\n  }\n\n  /// @notice Struct containing the initialization parameters for the FPMM contract\n  struct FPMMParams {\n    // fee taken from the swap for liquidity providers\n    uint256 lpFee;\n    // fee taken from the swap for the protocol\n    uint256 protocolFee;\n    // recipient of the protocol fee\n    address protocolFeeRecipient;\n    // address allowed to set fees (optional)\n    address feeSetter;\n    // incentive percentage for rebalancing the pool\n    uint256 rebalanceIncentive;\n    // threshold for rebalancing the pool when reserve price > oracle price\n    uint256 rebalanceThresholdAbove;\n    // threshold for rebalancing the pool when reserve price < oracle price\n    uint256 rebalanceThresholdBelow;\n  }\n\n  /// @notice Struct to store swap data\n  struct SwapData {\n    uint256 rateNumerator;\n    uint256 rateDenominator;\n    uint256 initialReserveValue;\n    uint256 initialPriceDifference;\n    uint256 amount0In;\n    uint256 amount1In;\n    uint256 amount0Out;\n    uint256 amount1Out;\n    uint256 newReserve0;\n    uint256 newReserve1;\n    bool reservePriceAboveOraclePrice;\n  }\n\n  /* ============================================================ */\n  /* ======================== Errors ============================ */\n  /* ============================================================ */\n\n  // @notice Throw when trying to get a price for a rate feed that is not set\n  error ReferenceRateNotSet();\n  // @notice Throw when the reserves are empty\n  error ReservesEmpty();\n  // @notice Throw when requesting an amount out for a token that is not the pool's tokens\n  error InvalidToken();\n  // @notice Throw when trying to set a zero address as a contract address\n  error ZeroAddress();\n  // @notice Throw when trying to set a protocol fee without a protocol fee recipient\n  error ProtocolFeeRecipientRequired();\n  // @notice Throw when a non-fee setter tries to update fees\n  error NotFeeSetter();\n  // @notice Throw when trying to set a fee that is too high\n  error FeeTooHigh();\n  // @notice Throw when trying to mint less than the minimum liquidity\n  error InsufficientLiquidityMinted();\n  // @notice Throw when trying to burn only one of the pool's tokens\n  error InsufficientLiquidityBurned();\n  // @notice Throw when trying to swap with no output amount\n  error InsufficientOutputAmount();\n  // @notice Throw when trying to swap more than the available liquidity\n  error InsufficientLiquidity();\n  // @notice Throw when trying to swap to one of the pool's tokens as the to address\n  error InvalidToAddress();\n  // @notice Throw when trying to swap without an input amount\n  error InsufficientInputAmount();\n  // @notice Throw when a non-liquidity strategy tries to call rebalance\n  error NotLiquidityStrategy();\n  // @notice Throw when trying to rebalance with no output amount\n  error OneOutputAmountRequired();\n  // @notice Throw when trying to rebalance when the price difference is too small\n  error PriceDifferenceTooSmall();\n  // @notice Throw when the price difference doesn't improve after rebalance\n  error PriceDifferenceNotImproved();\n  // @notice Throw when a rebalance operation moves the price difference in the wrong direction\n  error PriceDifferenceMovedInWrongDirection();\n  // @notice Throw when trying to rebalance and price is moved to far from thesholds\n  error PriceDifferenceMovedTooFarFromThresholds();\n  // @notice Throw when trying to rebalance with an insufficient amount of token0 input\n  error InsufficientAmount0In();\n  // @notice Throw when trying to rebalance with an insufficient amount of token1 input\n  error InsufficientAmount1In();\n  // @notice Throw when the reserve value decreases after a swap\n  error ReserveValueDecreased();\n  // @notice Throw when trying to set a rebalance incentive that is too high\n  error RebalanceIncentiveTooHigh();\n  // @notice Throw when trying to set a rebalance threshold that is too high\n  error RebalanceThresholdTooHigh();\n  // @notice Throw when trying to rebalance with an invalid direction\n  error RebalanceDirectionInvalid();\n  // @notice Throw when trying to configure trading limits with a limit that doesn't fit in int120\n  error LimitDoesNotFitInInt120();\n  // @notice Throw when token decimals are invalid\n  error InvalidTokenDecimals();\n\n  /* ============================================================ */\n  /* ======================== Events ============================ */\n  /* ============================================================ */\n\n  /**\n   * @notice Emitted when liquidity is added to the pool\n   * @param sender Address that initiated the mint\n   * @param amount0 Amount of token0 added\n   * @param amount1 Amount of token1 added\n   * @param liquidity Amount of LP tokens minted\n   * @param to Address that receives LP tokens\n   */\n  event Mint(address indexed sender, uint256 amount0, uint256 amount1, uint256 liquidity, address indexed to);\n\n  /**\n   * @notice Emitted when liquidity is removed from the pool\n   * @param sender Address that initiated the burn\n   * @param amount0 Amount of token0 removed\n   * @param amount1 Amount of token1 removed\n   * @param liquidity Amount of LP tokens burned\n   * @param to Address receiving the tokens\n   */\n  event Burn(address indexed sender, uint256 amount0, uint256 amount1, uint256 liquidity, address indexed to);\n\n  /**\n   * @notice Emitted when the LP fee is updated\n   * @param oldFee Previous fee in basis points\n   * @param newFee New fee in basis points\n   */\n  event LPFeeUpdated(uint256 oldFee, uint256 newFee);\n\n  /**\n   * @notice Emitted when the protocol fee is updated\n   * @param oldFee Previous fee in basis points\n   * @param newFee New fee in basis points\n   */\n  event ProtocolFeeUpdated(uint256 oldFee, uint256 newFee);\n\n  /**\n   * @notice Emitted when the protocol fee recipient is updated\n   * @param oldRecipient Previous recipient of the protocol fee\n   * @param newRecipient New recipient of the protocol fee\n   */\n  event ProtocolFeeRecipientUpdated(address indexed oldRecipient, address indexed newRecipient);\n\n  /**\n   * @notice Emitted when the fee setter is updated\n   * @param oldFeeSetter Previous fee setter\n   * @param newFeeSetter New fee setter\n   */\n  event FeeSetterUpdated(address indexed oldFeeSetter, address indexed newFeeSetter);\n\n  /**\n   * @notice Emitted when the rebalance incentive is updated\n   * @param oldIncentive Previous incentive in basis points\n   * @param newIncentive New incentive in basis points\n   */\n  event RebalanceIncentiveUpdated(uint256 oldIncentive, uint256 newIncentive);\n\n  /**\n   * @notice Emitted when the rebalance threshold is updated\n   * @param oldThresholdAbove Previous threshold above in basis points\n   * @param oldThresholdBelow Previous threshold below in basis points\n   * @param newThresholdAbove New threshold above in basis points\n   * @param newThresholdBelow New threshold below in basis points\n   */\n  event RebalanceThresholdUpdated(\n    uint256 oldThresholdAbove,\n    uint256 oldThresholdBelow,\n    uint256 newThresholdAbove,\n    uint256 newThresholdBelow\n  );\n\n  /**\n   * @notice Emitted when a liquidity strategy status is updated\n   * @param strategy Address of the strategy\n   * @param status New status (true = enabled, false = disabled)\n   */\n  event LiquidityStrategyUpdated(address indexed strategy, bool status);\n\n  /**\n   * @notice Emitted when the reference rate feed ID is updated\n   * @param oldRateFeedID Previous rate feed ID\n   * @param newRateFeedID New rate feed ID\n   */\n  event ReferenceRateFeedIDUpdated(address indexed oldRateFeedID, address indexed newRateFeedID);\n\n  /**\n   * @notice Emitted when the OracleAdapter contract is updated\n   * @param oldOracleAdapter Previous OracleAdapter address\n   * @param newOracleAdapter New OracleAdapter address\n   */\n  event OracleAdapterUpdated(address indexed oldOracleAdapter, address indexed newOracleAdapter);\n\n  /**\n   * @notice Emitted when the invert rate feed flag is updated\n   * @param oldInvertRateFeed Previous invert rate feed flag\n   * @param newInvertRateFeed New invert rate feed flag\n   */\n  event InvertRateFeedUpdated(bool oldInvertRateFeed, bool newInvertRateFeed);\n\n  /**\n   * @notice Emitted when a successful rebalance operation occurs\n   * @param sender Address that initiated the rebalance\n   * @param priceDifferenceBefore Price difference before rebalance in basis points\n   * @param priceDifferenceAfter Price difference after rebalance in basis points\n   */\n  event Rebalanced(address indexed sender, uint256 priceDifferenceBefore, uint256 priceDifferenceAfter);\n\n  /**\n   * @notice Emitted when reserves are synchronized\n   * @param reserve0 Updated amount of token0 in reserve\n   * @param reserve1 Updated amount of token1 in reserve\n   * @param blockTimestamp Current block timestamp\n   */\n  event UpdateReserves(uint256 reserve0, uint256 reserve1, uint256 blockTimestamp);\n\n  /**\n   * @notice Emitted when trading limits are configured\n   * @param token Address of the token\n   * @param config Trading limits configuration\n   */\n  event TradingLimitConfigured(address indexed token, ITradingLimitsV2.Config config);\n\n  /* ============================================================ */\n  /* ====================== View Functions ====================== */\n  /* ============================================================ */\n\n  /**\n   * @notice Returns the minimum liquidity that will be locked forever when creating a pool\n   * @return Minimum liquidity amount\n   */\n  function MINIMUM_LIQUIDITY() external view returns (uint256);\n\n  /**\n   * @notice Returns the denominator for basis point calculations (10000 = 100%)\n   * @return Denominator for basis points\n   */\n  function BASIS_POINTS_DENOMINATOR() external view returns (uint256);\n\n  /**\n   * @notice Returns the mode value for bidirectional trading from circuit breaker\n   * @return Mode value for bidirectional trading\n   */\n  function TRADING_MODE_BIDIRECTIONAL() external view returns (uint256);\n\n  /**\n   * @notice Returns the timestamp of the last reserve update\n   * @return Timestamp of the last reserve update\n   */\n  function blockTimestampLast() external view returns (uint256);\n\n  /**\n   * @notice Returns the OracleAdapter contract\n   * @return Address of the OracleAdapter contract\n   */\n  function oracleAdapter() external view returns (IOracleAdapter);\n\n  /**\n   * @notice Returns the invert rate feed flag\n   * @return Invert rate feed flag\n   */\n  function invertRateFeed() external view returns (bool);\n\n  /**\n   * @notice Returns the reference rate feed ID to query for oracle price\n   * @return Address of the reference rate feed ID\n   */\n  function referenceRateFeedID() external view returns (address);\n\n  /**\n   * @notice Returns the LP fee in basis points (1 basis point = .01%)\n   * @return LP fee in basis points\n   */\n  function lpFee() external view returns (uint256);\n\n  /**\n   * @notice Returns the protocol fee in basis points (1 basis point = .01%)\n   * @return Protocol fee in basis points\n   */\n  function protocolFee() external view returns (uint256);\n\n  /**\n   * @notice Returns the recipient of the protocol fee\n   * @return Recipient of the protocol fee\n   */\n  function protocolFeeRecipient() external view returns (address);\n\n  /**\n   * @notice Returns the fee setter address\n   * @return Fee setter address\n   */\n  function feeSetter() external view returns (address);\n\n  /**\n   * @notice Returns the slippage allowed for rebalance operations in basis points\n   * @return Rebalance incentive in basis points\n   */\n  function rebalanceIncentive() external view returns (uint256);\n\n  /**\n   * @notice Returns the threshold for triggering rebalance when reserve price > oracle price in basis points\n   * @return Rebalance threshold above in basis points\n   */\n  function rebalanceThresholdAbove() external view returns (uint256);\n\n  /**\n   * @notice Returns the threshold for triggering rebalance when reserve price < oracle price in basis points\n   * @return Rebalance threshold below in basis points\n   */\n  function rebalanceThresholdBelow() external view returns (uint256);\n\n  /**\n   * @notice Checks if an address is a trusted liquidity strategy\n   * @param strategy Address to check\n   * @return Whether the address is a trusted liquidity strategy\n   */\n  function liquidityStrategy(address strategy) external view returns (bool);\n\n  /**\n   * @notice Gets the rebalancing state of the pool\n   * @return oraclePriceNumerator The numerator of the oracle price.\n   * @return oraclePriceDenominator The denominator of the oracle price.\n   * @return reservePriceNumerator The numerator of the pool reserve price.\n   * @return reservePriceDenominator The denominator of the pool reserve price.\n   * @return reservePriceAboveOraclePrice Whether the pool reserve price is above the oracle price.\n   * @return rebalanceThreshold The rebalance threshold in basis points.\n   * @return priceDifference The price difference between the oracle and pool reserve prices in basis points.\n   */\n  function getRebalancingState()\n    external\n    view\n    returns (\n      uint256 oraclePriceNumerator,\n      uint256 oraclePriceDenominator,\n      uint256 reservePriceNumerator,\n      uint256 reservePriceDenominator,\n      bool reservePriceAboveOraclePrice,\n      uint16 rebalanceThreshold,\n      uint256 priceDifference\n    );\n\n  /**\n   * @notice Gets trading limits config and state for a token\n   * @param token Address of the token\n   * @return config Trading limits config for the token\n   * @return state Trading limits state for the token\n   */\n  function getTradingLimits(\n    address token\n  ) external view returns (ITradingLimitsV2.Config memory config, ITradingLimitsV2.State memory state);\n\n  /* ============================================================ */\n  /* ==================== Mutative Functions ==================== */\n  /* ============================================================ */\n\n  /**\n   * @notice Initializes the FPMM contract\n   * @param _token0 Address of the first token\n   * @param _token1 Address of the second token\n   * @param _oracleAdapter Address of the OracleAdapter contract\n   * @param _referenceRateFeedID Address of the reference rate feed ID\n   * @param _invertRateFeed Whether to invert the rate feed\n   * @param _initialOwner Address of the owner\n   * @param _params Parameters for the FPMM contract\n   */\n  function initialize(\n    address _token0,\n    address _token1,\n    address _oracleAdapter,\n    address _referenceRateFeedID,\n    bool _invertRateFeed,\n    address _initialOwner,\n    FPMMParams calldata _params\n  ) external;\n\n  /**\n   * @notice Mints LP tokens by providing liquidity to the pool\n   * @param to Address to receive LP tokens\n   * @return liquidity Amount of LP tokens minted\n   */\n  function mint(address to) external returns (uint256 liquidity);\n\n  /**\n   * @notice Burns LP tokens to withdraw liquidity from the pool\n   * @param to Address to receive the withdrawn tokens\n   * @return amount0 Amount of token0 withdrawn\n   * @return amount1 Amount of token1 withdrawn\n   */\n  function burn(address to) external returns (uint256 amount0, uint256 amount1);\n\n  /**\n   * @notice Rebalances the pool to align with oracle price\n   * @dev Only callable by approved liquidity strategies\n   * @param amount0Out Amount of token0 to output\n   * @param amount1Out Amount of token1 to output\n   * @param data Optional callback data\n   */\n  function rebalance(uint256 amount0Out, uint256 amount1Out, bytes calldata data) external;\n\n  /**\n   * @notice Sets LP fee\n   * @param _lpFee New fee in basis points\n   */\n  function setLPFee(uint256 _lpFee) external;\n\n  /**\n   * @notice Sets protocol fee\n   * @param _protocolFee New fee in basis points\n   */\n  function setProtocolFee(uint256 _protocolFee) external;\n\n  /**\n   * @notice Sets protocol fee recipient\n   * @param _protocolFeeRecipient The recipient of the protocol fee\n   */\n  function setProtocolFeeRecipient(address _protocolFeeRecipient) external;\n\n  /**\n   * @notice Sets the fee setter address\n   * @param _feeSetter The fee setter (optional)\n   */\n  function setFeeSetter(address _feeSetter) external;\n\n  /**\n   * @notice Sets rebalance incentive\n   * @param _rebalanceIncentive New incentive in basis points\n   */\n  function setRebalanceIncentive(uint256 _rebalanceIncentive) external;\n\n  /**\n   * @notice Sets rebalance threshold\n   * @param _rebalanceThresholdAbove New threshold above in basis points\n   * @param _rebalanceThresholdBelow New threshold below in basis points\n   */\n  function setRebalanceThresholds(uint256 _rebalanceThresholdAbove, uint256 _rebalanceThresholdBelow) external;\n\n  /**\n   * @notice Sets liquidity strategy status\n   * @param strategy Address of the strategy\n   * @param state New status (true = enabled, false = disabled)\n   */\n  function setLiquidityStrategy(address strategy, bool state) external;\n\n  /**\n   * @notice Sets the OracleAdapter contract\n   * @param _oracleAdapter Address of the OracleAdapter contract\n   */\n  function setOracleAdapter(address _oracleAdapter) external;\n\n  /**\n   * @notice Sets the invert rate feed flag\n   * @param _invertRateFeed Whether to invert the rate feed\n   */\n  function setInvertRateFeed(bool _invertRateFeed) external;\n\n  /**\n   * @notice Sets the reference rate feed ID\n   * @param _referenceRateFeedID Address of the reference rate feed\n   */\n  function setReferenceRateFeedID(address _referenceRateFeedID) external;\n\n  /**\n   * @notice Configure trading limits for a token\n   * @param token The token to configure limits for\n   * @param limit0 The limit0 for the token in token decimals\n   * @param limit1 The limit1 for the token in token decimals\n   */\n  function configureTradingLimit(address token, uint256 limit0, uint256 limit1) external;\n}\n"},{"file_path":"lib/mento-core/contracts/interfaces/IFPMMCallee.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\n/**\n * @title Fixed Price Market Maker Callee Interface\n * @author Mento Labs\n * @notice Interface for contracts that can be called during FPMM swaps\n * @dev This interface allows for callback functionality when interacting with FPMM.\n * It enables flash swaps and other advanced trading strategies where a contract\n * can be notified after receiving tokens but before the swap completes.\n */\ninterface IFPMMCallee {\n  /**\n   * @notice Callback function for FPMM swap operations\n   * @dev Called after tokens have been transferred from FPMM but before swap validation checks\n   * @param sender The original address that initiated the swap\n   * @param amount0 The amount of token0 received by the callee\n   * @param amount1 The amount of token1 received by the callee\n   * @param data Additional data forwarded from the swap call\n   */\n  function hook(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external;\n}\n"},{"file_path":"lib/mento-core/contracts/interfaces/ILiquidityStrategy.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\nimport { LiquidityStrategyTypes as LQ } from \"../libraries/LiquidityStrategyTypes.sol\";\n\ninterface ILiquidityStrategy {\n  /* ============================================================ */\n  /* ===================== Structs & Enums ====================== */\n  /* ============================================================ */\n\n  /**\n   * @notice Struct holding the configuration of a pool\n   * @param pool The address of the pool\n   * @param debtToken The address of the debt token\n   * @param cooldown The cooldown period between rebalances in seconds\n   * @param protocolFeeRecipient The recipient of the protocol fee\n   * @param liquiditySourceIncentiveExpansion The incentive for the liquidity source in for expansion\n   * @param protocolIncentiveExpansion The incentive for the protocol in for expansion\n   * @param liquiditySourceIncentiveContraction The incentive for the liquidity source in for contraction\n   * @param protocolIncentiveContraction The incentive for the protocol in for contraction\n   */\n  struct AddPoolParams {\n    address pool;\n    address debtToken;\n    uint32 cooldown;\n    address protocolFeeRecipient;\n    uint64 liquiditySourceIncentiveExpansion;\n    uint64 protocolIncentiveExpansion;\n    uint64 liquiditySourceIncentiveContraction;\n    uint64 protocolIncentiveContraction;\n  }\n\n  /**\n   * @notice Struct holding the complete configuration of an FPMM pool,\n   *         in the context of liquidity management.\n   * @param isToken0Debt Whether token0 is the debt token (true) or token1 is the debt token (false)\n   * @param lastRebalance The timestamp of the last rebalance for this pool\n   * @param rebalanceCooldown The cooldown period that must pass before the next rebalance\n   * @param protocolFeeRecipient The recipient of the protocol fee\n   * @param liquiditySourceIncentiveExpansion The incentive for the liquidity source in for expansion\n   * @param protocolIncentiveExpansion The incentive for the protocol in for expansion\n   * @param liquiditySourceIncentiveContraction The incentive for the liquidity source in for contraction\n   * @param protocolIncentiveContraction The incentive for the protocol in for contraction\n   */\n  struct PoolConfig {\n    bool isToken0Debt;\n    uint32 lastRebalance;\n    uint32 rebalanceCooldown;\n    address protocolFeeRecipient;\n    uint64 liquiditySourceIncentiveExpansion;\n    uint64 protocolIncentiveExpansion;\n    uint64 liquiditySourceIncentiveContraction;\n    uint64 protocolIncentiveContraction;\n  }\n\n  /* ============================================================ */\n  /* ======================== Errors ============================ */\n  /* ============================================================ */\n\n  /// @notice Thrown when the incentive is invalid or exceeds limits\n  error LS_BAD_INCENTIVE();\n  /// @notice Thrown when the callback sender is not the strategy itself\n  error LS_INVALID_SENDER();\n  /// @notice Thrown when the initial owner is address(0)\n  error LS_INVALID_OWNER();\n  /// @notice Thrown when attempting to rebalance before cooldown has elapsed\n  error LS_COOLDOWN_ACTIVE();\n  /// @notice Thrown when strategy execution fails\n  error LS_STRATEGY_EXECUTION_FAILED();\n  /// @notice Thrown when pool address is zero\n  error LS_POOL_MUST_BE_SET();\n  /// @notice Thrown when attempting to add a pool that already exists\n  error LS_POOL_ALREADY_EXISTS();\n  /// @notice Thrown when pool is not found in the registry\n  error LS_POOL_NOT_FOUND();\n  /// @notice Thrown when rebalance thresholds are invalid\n  error LS_INVALID_THRESHOLD();\n  /// @notice Thrown when token decimals are zero\n  error LS_ZERO_DECIMAL();\n  /// @notice Thrown when token decimals exceed 1e18\n  error LS_INVALID_DECIMAL();\n  /// @notice Thrown when oracle prices are invalid\n  error LS_INVALID_PRICES();\n  /// @notice Thrown when the pool cannot be rebalanced\n  error LS_POOL_NOT_REBALANCEABLE();\n  /// @notice Thrown when the hook callback isn't called during a rebalance from the FPMM\n  error LS_HOOK_NOT_CALLED();\n  /// @notice Thrown when the same pool is rebalanced twice in a single transaction\n  error LS_CAN_ONLY_REBALANCE_ONCE(address pool);\n  /// @notice Thrown when trying to add a pool with a debt token that's not a part of the pool\n  error LS_DEBT_TOKEN_NOT_IN_POOL();\n  /// @notice Thrown when trying to add a pool with a protocol fee recipient that is zero address\n  error LS_PROTOCOL_FEE_RECIPIENT_REQUIRED();\n  /// @notice Thrown when the incentive is too high for expansion or contraction\n  error LS_INCENTIVE_TOO_HIGH();\n\n  /* ============================================================ */\n  /* ======================== Events ============================ */\n  /* ============================================================ */\n\n  /**\n   * @notice Emitted when a new pool is added to the strategy\n   * @param pool The address of the pool\n   * @param params The parameters for adding a pool\n   */\n  event PoolAdded(address indexed pool, AddPoolParams params);\n\n  /**\n   * @notice Emitted when a pool is removed from the strategy\n   * @param pool The address of the pool\n   */\n  event PoolRemoved(address indexed pool);\n\n  /**\n   * @notice Emitted when a pool's rebalance cooldown is updated\n   * @param pool The address of the pool\n   * @param cooldown The new cooldown period\n   */\n  event RebalanceCooldownSet(address indexed pool, uint32 cooldown);\n\n  /**\n   * @notice Emitted when liquidity is moved during rebalance\n   * @param pool The address of the pool\n   * @param direction The direction of the rebalance (Expand or Contract)\n   * @param tokenGivenToPool The token address moved into the pool\n   * @param amountGivenToPool The amount of tokens moved into the pool\n   * @param tokenTakenFromPool The token address taken from the pool\n   * @param amountTakenFromPool The amount of tokens taken from the pool\n   */\n  event LiquidityMoved(\n    address indexed pool,\n    LQ.Direction indexed direction,\n    address tokenGivenToPool,\n    uint256 amountGivenToPool,\n    address tokenTakenFromPool,\n    uint256 amountTakenFromPool\n  );\n\n  /* ============================================================ */\n  /* ==================== Mutative Functions ==================== */\n  /* ============================================================ */\n\n  /**\n   * @notice Sets the rebalance cooldown for a given liquidity pool.\n   * @param pool The address of the pool to update.\n   * @param cooldown The new cooldown period for the pool.\n   */\n  function setRebalanceCooldown(address pool, uint32 cooldown) external;\n\n  /**\n   * @notice Executes a rebalance for the specified pool using its configured policy pipeline.\n   * @dev Callable by anyone but subject to cooldown restrictions.\n   * @param pool The address of the pool to rebalance.\n   */\n  function rebalance(address pool) external;\n\n  /**\n   * @notice Hook called by FPMM during rebalance to handle token transfers\n   * @dev Must be called by a registered pool with the correct sender\n   * @param sender The address that initiated the rebalance (must be this contract)\n   * @param amount0Out The amount of token0 to be sent from the pool\n   * @param amount1Out The amount of token1 to be sent from the pool\n   * @param data Encoded callback data containing rebalance parameters\n   */\n  function onRebalance(address sender, uint256 amount0Out, uint256 amount1Out, bytes calldata data) external;\n\n  /* ============================================================ */\n  /* ======================== View Functions ==================== */\n  /* ============================================================ */\n\n  /**\n   * @notice Checks if a pool is registered with the controller.\n   * @param pool The address of the pool to check.\n   * @return True if the pool is registered, false otherwise.\n   */\n  function isPoolRegistered(address pool) external view returns (bool);\n\n  /**\n   * @notice Returns all registered pool addresses.\n   * @return An array of all registered pool addresses.\n   */\n  function getPools() external view returns (address[] memory);\n\n  /**\n   * @notice Determines the rebalance action for a given pool based on current state\n   * @dev View-only version of rebalance logic for external inspection\n   * @param pool The address of the pool to analyze\n   * @return ctx The liquidity context containing pool state and configuration\n   * @return action The determined rebalance action with amounts and direction\n   */\n  function determineAction(address pool) external view returns (LQ.Context memory ctx, LQ.Action memory action);\n}\n"},{"file_path":"lib/mento-core/contracts/interfaces/IMarketHoursBreaker.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\ninterface IMarketHoursBreaker {\n  /**\n   * @notice Check if the timestamp is inside FX market hours\n   * @param timestamp The timestamp to check\n   * @return True if the timestamp is inside FX market hours, false otherwise\n   */\n  function isFXMarketOpen(uint256 timestamp) external pure returns (bool);\n\n  /**\n   * @notice  Enforces that the market is open during valid trading hours.\n   *          This function reverts if called outside of FX market hours or on holidays.\n   * @param   rateFeedID The rate feed to be checked. Unused in this implementation as market hours\n   *          in this breaker are not rate feed dependent.\n   * @return  triggerBreaker Always returns false if execution completes (FX market is open),\n   *          And reverts if the FX market is closed.\n   * @dev     This function implements the IBreaker interface but uses a revert-on-condition\n   *          pattern rather than returning true/false. The boolean return is required by the\n   *          interface but will only be reached when the condition passes (FX market open).\n   */\n  function shouldTrigger(address rateFeedID) external view returns (bool triggerBreaker);\n}\n"},{"file_path":"lib/mento-core/contracts/interfaces/IOracleAdapter.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\nimport { IBreakerBox } from \"./IBreakerBox.sol\";\nimport { ISortedOracles } from \"./ISortedOracles.sol\";\nimport { IMarketHoursBreaker } from \"./IMarketHoursBreaker.sol\";\nimport { AggregatorV3Interface } from \"foundry-chainlink-toolkit/src/interfaces/feeds/AggregatorV3Interface.sol\";\n\ninterface IOracleAdapter {\n  /* ============================================================ */\n  /* ======================== Structs =========================== */\n  /* ============================================================ */\n\n  /// @notice Struct to store OracleAdapter contract state\n  /// @custom:storage-location erc7201:mento.storage.OracleAdapter\n  struct OracleAdapterStorage {\n    // Contract for querying oracle price feeds\n    ISortedOracles sortedOracles;\n    // Contract for checking trading modes\n    IBreakerBox breakerBox;\n    // Contract for checking market hours\n    IMarketHoursBreaker marketHoursBreaker;\n    // Contract for checking L2 sequencer status\n    AggregatorV3Interface l2SequencerUptimeFeed;\n  }\n\n  /// @notice Struct to store info about a rate\n  struct RateInfo {\n    uint256 numerator;\n    uint256 denominator;\n    uint8 tradingMode;\n    bool isRecent;\n    bool isFXMarketOpen;\n  }\n\n  /* ============================================================ */\n  /* ======================== Errors ============================ */\n  /* ============================================================ */\n\n  // @notice Thrown when the FX market is closed\n  error FXMarketClosed();\n  // @notice Thrown when trading is suspended because of a breaker\n  error TradingSuspended();\n  // @notice Thrown when the rate in sorted oracles is 0\n  error InvalidRate();\n  // @notice Thrown when no recent rate is available\n  error NoRecentRate();\n  // @notice Thrown when trying to set a zero address as a contract address\n  error ZeroAddress();\n\n  /* ============================================================ */\n  /* ======================== Events ============================ */\n  /* ============================================================ */\n\n  /**\n   * @notice Emitted when the SortedOracles contract is updated\n   * @param oldSortedOracles Previous SortedOracles address\n   * @param newSortedOracles New SortedOracles address\n   */\n  event SortedOraclesUpdated(address indexed oldSortedOracles, address indexed newSortedOracles);\n\n  /**\n   * @notice Emitted when the BreakerBox contract is updated\n   * @param oldBreakerBox Previous BreakerBox address\n   * @param newBreakerBox New BreakerBox address\n   */\n  event BreakerBoxUpdated(address indexed oldBreakerBox, address indexed newBreakerBox);\n\n  /**\n   * @notice Emitted when the MarketHoursBreaker contract is updated\n   * @param oldMarketHoursBreaker Previous MarketHoursBreaker address\n   * @param newMarketHoursBreaker New MarketHoursBreaker address\n   */\n  event MarketHoursBreakerUpdated(address indexed oldMarketHoursBreaker, address indexed newMarketHoursBreaker);\n\n  /**\n   * @notice Emitted when the L2 sequencer uptime feed contract is updated\n   * @param oldL2SequencerUptimeFeed Previous L2SequencerUptimeFeed address\n   * @param newL2SequencerUptimeFeed New L2SequencerUptimeFeed address\n   */\n  event L2SequencerUptimeFeedUpdated(\n    address indexed oldL2SequencerUptimeFeed,\n    address indexed newL2SequencerUptimeFeed\n  );\n\n  /* ============================================================ */\n  /* ====================== View Functions ====================== */\n  /* ============================================================ */\n\n  /**\n   * @notice Returns the contract for oracle price feeds\n   * @return Address of the SortedOracles contract\n   */\n  function sortedOracles() external view returns (ISortedOracles);\n\n  /**\n   * @notice Returns the contract for checking trading modes\n   * @return Address of the BreakerBox contract\n   */\n  function breakerBox() external view returns (IBreakerBox);\n\n  /**\n   * @notice Returns the contract for checking market hours\n   * @return Address of the MarketHoursBreaker contract\n   */\n  function marketHoursBreaker() external view returns (IMarketHoursBreaker);\n\n  /**\n   * @notice Returns the contract for checking the L2 sequencer status\n   * @return Address of the L2SequencerUptimeFeed contract\n   */\n  function l2SequencerUptimeFeed() external view returns (AggregatorV3Interface);\n\n  /**\n   * @notice Returns true if the market is open based on FX market hours\n   * @return true if the market is open, false otherwise\n   */\n  function isFXMarketOpen() external view returns (bool);\n\n  /**\n   * @notice Returns true if the rate for a given rate feed ID is recent\n   * @param rateFeedID The address of the rate feed\n   * @return true if the rate is recent, false otherwise\n   */\n  function hasRecentRate(address rateFeedID) external view returns (bool);\n\n  /**\n   * @notice Returns the exchange rate for a given rate feed ID\n   * with 18 decimals of precision, along with other info\n   * @param rateFeedID The address of the rate feed\n   * @return rateInfo The rate info\n   */\n  function getRate(address rateFeedID) external view returns (RateInfo memory);\n\n  /**\n   * @notice Returns the exchange rate for a given rate feed ID\n   * with 18 decimals of precision if considered valid, based on\n   * trading mode, and recent rate, otherwise reverts\n   * @param rateFeedID The address of the rate feed\n   * @return numerator The numerator of the rate\n   * @return denominator The denominator of the rate\n   */\n  function getRateIfValid(address rateFeedID) external view returns (uint256 numerator, uint256 denominator);\n\n  /**\n   * @notice Returns the exchange rate for a given rate feed ID\n   * with 18 decimals of precision if considered valid, based on\n   * FX market hours, trading mode, and recent rate, otherwise reverts\n   * @param rateFeedID The address of the rate feed\n   * @return numerator The numerator of the rate\n   * @return denominator The denominator of the rate\n   */\n  function getFXRateIfValid(address rateFeedID) external view returns (uint256 numerator, uint256 denominator);\n\n  /**\n   * @notice Returns the trading mode for a given rate feed ID\n   * @param rateFeedID The address of the rate feed\n   * @return The trading mode\n   */\n  function getTradingMode(address rateFeedID) external view returns (uint8);\n\n  /**\n   * @notice Ensures that the rate feed is valid by checking trading mode and rate freshness\n   * @dev Reverts if trading is suspended or rate is not recent\n   * @param rateFeedID The address of the rate feed\n   */\n  function ensureRateValid(address rateFeedID) external view;\n\n  /**\n   * @notice Returns true if the L2 sequencer has been up and operational for at least the specified duration.\n   * @param since The minimum number of seconds the L2 sequencer must have been up (e.g., 1 hours = 3600).\n   * @return up True if the sequencer has been up for at least `since` seconds, false otherwise\n   */\n  function isL2SequencerUp(uint256 since) external view returns (bool up);\n\n  /* ============================================================ */\n  /* ==================== Mutative Functions ==================== */\n  /* ============================================================ */\n\n  /**\n   * @notice Initializes the OracleAdapter contract\n   * @param _sortedOracles The address of the sorted oracles contract\n   * @param _breakerBox The address of the breaker box contract\n   * @param _marketHoursBreaker The address of the market hours breaker contract\n   * @param _initialOwner The address to transfer ownership to\n   * @param _l2SequencerUptimeFeed The address of the L2 sequencer uptime feed contract\n   */\n  function initialize(\n    address _sortedOracles,\n    address _breakerBox,\n    address _marketHoursBreaker,\n    address _l2SequencerUptimeFeed,\n    address _initialOwner\n  ) external;\n\n  /**\n   * @notice Sets the address of the sorted oracles contract\n   * @param _sortedOracles The address of the sorted oracles contract\n   */\n  function setSortedOracles(address _sortedOracles) external;\n\n  /**\n   * @notice Sets the address of the breaker box contract\n   * @param _breakerBox The address of the breaker box contract\n   */\n  function setBreakerBox(address _breakerBox) external;\n\n  /**\n   * @notice Sets the address of the market hours breaker contract\n   * @param _marketHoursBreaker The address of the market hours breaker contract\n   */\n  function setMarketHoursBreaker(address _marketHoursBreaker) external;\n\n  /**\n   * @notice Sets the address of the L2 sequencer uptime feed contract\n   * @param _l2SequencerUptimeFeed The address of the L2 sequencer uptime feed contract\n   */\n  function setL2SequencerUptimeFeed(address _l2SequencerUptimeFeed) external;\n}\n"},{"file_path":"lib/mento-core/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 isOracle(address, address) external view returns (bool);\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 reportExpirySeconds() external view returns (uint256);\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":"lib/mento-core/contracts/interfaces/ITradingLimitsV2.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\ninterface ITradingLimitsV2 {\n  /* ============================================================ */\n  /* ======================== Errors ============================ */\n  /* ============================================================ */\n\n  // @notice Throw when limit1 is not greater than limit0 when both are active\n  error Limit1MustBeGreaterThanLimit0();\n  // @notice Throw when L0 trading limit is exceeded\n  error L0LimitExceeded();\n  // @notice Throw when L1 trading limit is exceeded\n  error L1LimitExceeded();\n  // @notice Throw when a value exceeds int96 bounds during scaling\n  error ValueExceedsInt96Bounds();\n  // @notice Throw when int96 addition causes overflow\n  error Int96AdditionOverflow();\n  // @notice Throw when decimals are out of range [1, 18]\n  error InvalidDecimals();\n\n  /* ============================================================ */\n  /* ======================== Structs ============================ */\n  /* ============================================================ */\n\n  /**\n   * @dev The State struct contains the current state of a trading limit config.\n   * @param lastUpdated0 The timestamp of the last reset of netflow0.\n   * @param lastUpdated1 The timestamp of the last reset of netflow1.\n   * @param netflow0 The current netflow of the asset for limit0 (L0), stored with 15 decimals of precision.\n   * @param netflow1 The current netflow of the asset for limit1 (L1), stored with 15 decimals of precision.\n   */\n  struct State {\n    uint32 lastUpdated0;\n    uint32 lastUpdated1;\n    int96 netflow0;\n    int96 netflow1;\n  }\n\n  /**\n   * @dev The Config struct contains the configuration of trading limits.\n   * @param limit0 The limit0 for the asset, stored with 15 decimals of precision.\n   * @param limit1 The limit1 for the asset, stored with 15 decimals of precision.\n   * @param decimals The number of decimals of the token the limits are configured for.\n   */\n  struct Config {\n    int120 limit0;\n    int120 limit1;\n    uint8 decimals;\n  }\n\n  struct TradingLimits {\n    State state;\n    Config config;\n  }\n}\n"},{"file_path":"lib/mento-core/contracts/libraries/LiquidityStrategyTypes.sol","source_code":"// SPDX-License-Identifier: GPL-3.0-or-later\npragma solidity ^0.8.0;\n\nimport { IFPMM } from \"../interfaces/IFPMM.sol\";\nimport { ILiquidityStrategy } from \"../interfaces/ILiquidityStrategy.sol\";\n\nimport { Math } from \"openzeppelin-contracts/contracts/utils/math/Math.sol\";\n\n/**\n * @title LiquidityStrategyTypes ()\n * @author Mento Labs\n * @notice Shared types and helpers for the Liquidity Controller, Policies & Strategies.\n */\nlibrary LiquidityStrategyTypes {\n  using Math for uint256;\n  /* ============================================================ */\n  /* ====================== Constants =========================== */\n  /* ============================================================ */\n\n  uint256 public constant FEE_DENOMINATOR = 1e18;\n  uint256 public constant BPS_DENOMINATOR = 10_000;\n\n  /* ============================================================ */\n  /* ======================= Enums ============================== */\n  /* ============================================================ */\n\n  /**\n   * @notice Indicates how the pool should be rebalanced relative to the oracle price.\n   * @dev\n   * - Expand:   Pool price > oracle price (PP > P).\n   *             Rebalance by moving debt tokens into the pool and taking collateral out.\n   * - Contract: Pool price < oracle price (PP < P).\n   *             Rebalance by moving collateral into the pool and taking debt tokens out.\n   */\n  enum Direction {\n    Expand,\n    Contract\n  }\n\n  /* ============================================================ */\n  /* ======================= Structs ============================ */\n  /* ============================================================ */\n\n  /// @notice Struct to store the reserves of the FPMM pool\n  struct Reserves {\n    uint256 reserveNum;\n    uint256 reserveDen;\n  }\n\n  /// @notice Price snapshot and deviation info\n  struct Prices {\n    uint256 oracleNum;\n    uint256 oracleDen;\n    bool poolPriceAbove;\n    uint16 rebalanceThreshold;\n  }\n\n  struct RebalanceIncentives {\n    uint64 liquiditySourceIncentiveExpansion;\n    uint64 protocolIncentiveExpansion;\n    uint64 liquiditySourceIncentiveContraction;\n    uint64 protocolIncentiveContraction;\n  }\n\n  /// @notice Read-only context with shared data\n  struct Context {\n    address pool;\n    Reserves reserves;\n    Prices prices;\n    address token0;\n    address token1;\n    uint64 token0Dec;\n    uint64 token1Dec;\n    bool isToken0Debt;\n    RebalanceIncentives incentives;\n  }\n\n  /// @notice A single rebalance step produced by a policy\n  struct Action {\n    Direction dir;\n    uint256 amount0Out; // amount of token0 to move out of pool\n    uint256 amount1Out; // amount of token1 to move out of pool\n    uint256 amountOwedToPool; // amount to move to pool (post-incentive)\n  }\n\n  /// @notice Callback data passed to hook during rebalance\n  struct CallbackData {\n    uint256 amountOwedToPool;\n    Direction dir;\n    bool isToken0Debt;\n    address debtToken;\n    address collToken;\n  }\n\n  /* ============================================================ */\n  /* ================== Context Functions ======================= */\n  /* ============================================================ */\n\n  /**\n   * @notice Creates a new rebalance context for a pool\n   * @param pool The address of the FPMM pool\n   * @param config The configuration for the pool\n   * @return ctx The rebalance context\n   */\n  function newRebalanceContext(\n    address pool,\n    ILiquidityStrategy.PoolConfig memory config\n  ) internal view returns (Context memory ctx) {\n    IFPMM fpmm = IFPMM(pool);\n    ctx.pool = pool;\n    // Get and set token data\n    {\n      (uint256 dec0, uint256 dec1, , , address t0, address t1) = fpmm.metadata();\n      if (!(dec0 > 0 && dec1 > 0)) revert ILiquidityStrategy.LS_ZERO_DECIMAL();\n      if (!(dec0 <= 1e18 && dec1 <= 1e18)) revert ILiquidityStrategy.LS_INVALID_DECIMAL();\n\n      ctx.token0 = t0;\n      ctx.token1 = t1;\n      ctx.token0Dec = uint64(dec0);\n      ctx.token1Dec = uint64(dec1);\n      ctx.isToken0Debt = config.isToken0Debt;\n\n      // Set incentive from FPMM\n      ctx.incentives = RebalanceIncentives({\n        liquiditySourceIncentiveExpansion: config.liquiditySourceIncentiveExpansion,\n        protocolIncentiveExpansion: config.protocolIncentiveExpansion,\n        liquiditySourceIncentiveContraction: config.liquiditySourceIncentiveContraction,\n        protocolIncentiveContraction: config.protocolIncentiveContraction\n      });\n    }\n\n    // Get and set price data\n    {\n      (\n        uint256 oraclePriceNumerator,\n        uint256 oraclePriceDenominator,\n        uint256 reserveNum,\n        uint256 reserveDen,\n        bool reservePriceAboveOraclePrice,\n        uint16 rebalanceThreshold,\n        uint256 priceDifference\n      ) = fpmm.getRebalancingState();\n\n      if (priceDifference <= rebalanceThreshold) revert ILiquidityStrategy.LS_POOL_NOT_REBALANCEABLE();\n\n      ctx.reserves = Reserves({ reserveNum: reserveNum, reserveDen: reserveDen });\n      ctx.prices = Prices({\n        oracleNum: oraclePriceNumerator,\n        oracleDen: oraclePriceDenominator,\n        poolPriceAbove: reservePriceAboveOraclePrice,\n        rebalanceThreshold: rebalanceThreshold\n      });\n    }\n  }\n\n  /**\n   * @notice Returns the debt token address from context\n   * @param ctx The liquidity context\n   * @return The address of the debt token (stable asset)\n   */\n  function debtToken(Context memory ctx) internal pure returns (address) {\n    return ctx.isToken0Debt ? ctx.token0 : ctx.token1;\n  }\n\n  /**\n   * @notice Returns the collateral token address from context\n   * @param ctx The liquidity context\n   * @return The address of the collateral token\n   */\n  function collateralToken(Context memory ctx) internal pure returns (address) {\n    return ctx.isToken0Debt ? ctx.token1 : ctx.token0;\n  }\n\n  /**\n   * @notice Returns both token addresses in debt/collateral order\n   * @param ctx The liquidity context\n   * @return First the debt token address, then the collateral token address\n   */\n  function tokens(Context memory ctx) internal pure returns (address, address) {\n    return ctx.isToken0Debt ? (ctx.token0, ctx.token1) : (ctx.token1, ctx.token0);\n  }\n\n  /**\n   * @notice Returns token decimals in debt/collateral order\n   * @param ctx The liquidity context\n   * @return debtDecimals The decimal factor (10**decimals) of the debt token\n   * @return collDecimals The decimal factor (10**decimals) of the collateral token\n   */\n  function decimals(Context memory ctx) internal pure returns (uint64 debtDecimals, uint64 collDecimals) {\n    return ctx.isToken0Debt ? (ctx.token0Dec, ctx.token1Dec) : (ctx.token1Dec, ctx.token0Dec);\n  }\n\n  /**\n   * @notice Returns the oracle price for converting debt to collateral\n   * @dev Price convention: Po = ON/OD such that:\n   *      - token1 = token0 * ON/OD\n   *      - token0 = token1 * OD/ON\n   *      For debt→collateral conversion:\n   *      - If token0 is debt: collateral = debt * ON/OD\n   *      - If token1 is debt: collateral = debt * OD/ON\n   * @param ctx The liquidity context\n   * @return numerator The price numerator\n   * @return denominator The price denominator\n   */\n  function debtToCollateralPrice(Context memory ctx) internal pure returns (uint256, uint256) {\n    return\n      ctx.isToken0Debt ? (ctx.prices.oracleNum, ctx.prices.oracleDen) : (ctx.prices.oracleDen, ctx.prices.oracleNum);\n  }\n\n  /**\n   * @notice Returns the oracle price for converting collateral to debt\n   * @dev Price convention: Po = ON/OD such that:\n   *      - token1 = token0 * ON/OD\n   *      - token0 = token1 * OD/ON\n   *      For collateral→debt conversion:\n   *      - If token0 is debt: debt = collateral * OD/ON\n   *      - If token1 is debt: debt = collateral * ON/OD\n   * @param ctx The liquidity context\n   * @return numerator The price numerator\n   * @return denominator The price denominator\n   */\n  function collateralToDebtPrice(Context memory ctx) internal pure returns (uint256, uint256) {\n    return\n      ctx.isToken0Debt ? (ctx.prices.oracleDen, ctx.prices.oracleNum) : (ctx.prices.oracleNum, ctx.prices.oracleDen);\n  }\n\n  /**\n   * @notice Converts a collateral amount to equivalent debt token amount\n   * @dev Uses oracle price and handles decimal scaling\n   * @param ctx The liquidity context\n   * @param collateralBalance The amount of collateral to convert\n   * @return The equivalent amount in debt token units\n   */\n  function convertToDebtToken(Context memory ctx, uint256 collateralBalance) internal pure returns (uint256) {\n    (uint256 priceNumerator, uint256 priceDenominator) = collateralToDebtPrice(ctx);\n    (uint256 debtDecimals, uint256 collDecimals) = decimals(ctx);\n    return convertWithRateScaling(collateralBalance, collDecimals, debtDecimals, priceNumerator, priceDenominator);\n  }\n\n  /**\n   * @notice Converts collateral to debt with custom fee parameters\n   * @dev Allows specifying custom fee numerator/denominator for flexibility\n   * @param ctx The liquidity context\n   * @param collateralBalance The amount of collateral to convert\n   * @param feeNumerator The fee multiplier numerator\n   * @param feeDenominator The fee multiplier denominator\n   * @return The equivalent amount in debt token units with fee applied\n   */\n  function convertToDebtWithFee(\n    Context memory ctx,\n    uint256 collateralBalance,\n    uint256 feeNumerator,\n    uint256 feeDenominator\n  ) internal pure returns (uint256) {\n    (uint256 priceNumerator, uint256 priceDenominator) = collateralToDebtPrice(ctx);\n    (uint256 debtDecimals, uint256 collDecimals) = decimals(ctx);\n    return\n      convertWithRateScalingAndFee(\n        collateralBalance,\n        collDecimals,\n        debtDecimals,\n        priceNumerator,\n        priceDenominator,\n        feeNumerator,\n        feeDenominator\n      );\n  }\n\n  /**\n   * @notice Converts debt to collateral with custom fee parameters\n   * @dev Allows specifying custom fee numerator/denominator for flexibility\n   * @param ctx The liquidity context\n   * @param debtBalance The amount of debt tokens to convert\n   * @param feeNumerator The fee multiplier numerator\n   * @param feeDenominator The fee multiplier denominator\n   * @return The equivalent amount in collateral units with fee applied\n   */\n  function convertToCollateralWithFee(\n    Context memory ctx,\n    uint256 debtBalance,\n    uint256 feeNumerator,\n    uint256 feeDenominator\n  ) internal pure returns (uint256) {\n    (uint256 priceNumerator, uint256 priceDenominator) = debtToCollateralPrice(ctx);\n    (uint256 debtDecimals, uint256 collDecimals) = decimals(ctx);\n    return\n      convertWithRateScalingAndFee(\n        debtBalance,\n        debtDecimals,\n        collDecimals,\n        priceNumerator,\n        priceDenominator,\n        feeNumerator,\n        feeDenominator\n      );\n  }\n\n  /* ============================================================ */\n  /* =================== Action Functions ======================= */\n  /* ============================================================ */\n\n  /**\n   * @notice Creates an expansion action (add debt to pool, receive collateral)\n   * @dev Sets amount0Out/amount1Out based on token order\n   * @param ctx The liquidity context\n   * @param debtToExpand The amount of debt tokens to add to the pool\n   * @param collateralToPay The amount of collateral tokens to receive from the pool\n   * @return action The constructed expansion action\n   */\n  function newExpansion(\n    Context memory ctx,\n    uint256 debtToExpand,\n    uint256 collateralToPay\n  ) internal pure returns (Action memory action) {\n    action.dir = Direction.Expand;\n    if (ctx.isToken0Debt) {\n      action.amount0Out = 0;\n      action.amount1Out = collateralToPay;\n    } else {\n      action.amount0Out = collateralToPay;\n      action.amount1Out = 0;\n    }\n    action.amountOwedToPool = debtToExpand;\n  }\n\n  /**\n   * @notice Creates a contraction action (add collateral to pool, receive debt)\n   * @dev Sets amount0Out/amount1Out based on token order\n   * @param ctx The liquidity context\n   * @param debtToContract The amount of debt tokens to receive from the pool\n   * @param collateralToReceive The amount of collateral tokens to add to the pool\n   * @return action The constructed contraction action\n   */\n  function newContraction(\n    Context memory ctx,\n    uint256 debtToContract,\n    uint256 collateralToReceive\n  ) internal pure returns (Action memory action) {\n    action.dir = Direction.Contract;\n    if (ctx.isToken0Debt) {\n      action.amount0Out = debtToContract;\n      action.amount1Out = 0;\n    } else {\n      action.amount0Out = 0;\n      action.amount1Out = debtToContract;\n    }\n    action.amountOwedToPool = collateralToReceive;\n  }\n\n  /* ============================================================ */\n  /* =================== Helper Functions ======================= */\n  /* ============================================================ */\n\n  /**\n   * @notice Normalize a token amount to 18 decimals given its raw decimal factor.\n   * @param amount raw token units\n   * @param tokenDecimalsFactor 10**decimals (e.g., 1e6 for USDC, 1e18 for Mento tokens)\n   * @dev There is no guard on tokenDecimalsFactor as it's expected that this function is used on context\n   *      data that has been validated by the LiquidityController. If necessary, guard at the caller site.\n   */\n  function to1e18(uint256 amount, uint256 tokenDecimalsFactor) internal pure returns (uint256) {\n    return amount * (1e18 / tokenDecimalsFactor);\n  }\n\n  /**\n   * @notice Convert a 18d-normalized amount back to raw token units.\n   * @param amount18 18d-normalized token units\n   * @param tokenDecimalsFactor 10**decimals (e.g., 1e6 for USDC, 1e18 for Mento tokens)\n   * @dev There is no guard on tokenDecimalsFactor as it's expected that this function is used on context\n   *      data that has been validated by the LiquidityController. If necessary, guard at the caller site.\n   */\n  function from1e18(uint256 amount18, uint256 tokenDecimalsFactor) internal pure returns (uint256) {\n    return amount18 / (1e18 / tokenDecimalsFactor);\n  }\n\n  /**\n   * @notice Scales an amount from one decimal factor to another\n   * @param amount The amount to scale\n   * @param fromDec The source decimal factor (10**decimals)\n   * @param toDec The target decimal factor (10**decimals)\n   * @return The scaled amount\n   */\n  function scaleFromTo(uint256 amount, uint256 fromDec, uint256 toDec) internal pure returns (uint256) {\n    return (amount * toDec) / fromDec;\n  }\n\n  /**\n   * @notice Scales an amount from one decimal factor to another\n   * @param amountNum The amount numerator to scale\n   * @param amountDen The amount denominator to scale\n   * @param fromDec The source decimal factor (10**decimals)\n   * @param toDec The target decimal factor (10**decimals)\n   * @return The scaled amount\n   */\n  function scaleFromTo(\n    uint256 amountNum,\n    uint256 amountDen,\n    uint256 fromDec,\n    uint256 toDec\n  ) internal pure returns (uint256) {\n    return (amountNum * toDec) / (fromDec * amountDen);\n  }\n\n  /**\n   * @notice Converts an amount with both rate and decimal scaling\n   * @dev Formula: (amount * oracleNum * toDec) / (fromDec * oracleDen)\n   * @param amount The amount to convert\n   * @param fromDec The source decimal factor\n   * @param toDec The target decimal factor\n   * @param oracleNum The oracle price numerator\n   * @param oracleDen The oracle price denominator\n   * @return The converted amount\n   */\n  function convertWithRateScaling(\n    uint256 amount,\n    uint256 fromDec,\n    uint256 toDec,\n    uint256 oracleNum,\n    uint256 oracleDen\n  ) internal pure returns (uint256) {\n    return (amount * oracleNum * toDec) / (fromDec * oracleDen);\n  }\n\n  /**\n   * @notice Converts an amount with rate, decimal scaling, and fee/incentive\n   * @dev Formula: (amount * oracleNum * toDec * incentiveNum) / (fromDec * oracleDen * incentiveDen)\n   * @param amount The amount to convert\n   * @param fromDec The source decimal factor\n   * @param toDec The target decimal factor\n   * @param oracleNum The oracle price numerator\n   * @param oracleDen The oracle price denominator\n   * @param incentiveNum The fee/incentive multiplier numerator\n   * @param incentiveDen The fee/incentive multiplier denominator\n   * @return The converted amount with fee applied\n   */\n  function convertWithRateScalingAndFee(\n    uint256 amount,\n    uint256 fromDec,\n    uint256 toDec,\n    uint256 oracleNum,\n    uint256 oracleDen,\n    uint256 incentiveNum,\n    uint256 incentiveDen\n  ) internal pure returns (uint256) {\n    return (amount * oracleNum).mulDiv(toDec * incentiveNum, fromDec * incentiveDen) / oracleDen;\n  }\n\n  /**\n   * @notice Calculates the combined fee multiplier for a given protocol and liquidity source fee\n   * @dev The combined fee multiplier is the remaining fraction after both fees: (1 - protocolFee) * (1 - liquiditySourceFee)\n   *      This is necessary because the protocolFee is a percentage of the total amount of debt being moved out of the pool\n   *      while the liquiditySourceFee is a percentage of the amount being swapped against the liquidity source.\n   *      The liquiditySourceFee is applied to the amount after the deduction of the protocol fee.\n   * @param protocolFee The protocol fee\n   * @param liquiditySourceFee The liquidity source fee\n   * @return combinedFeeMultiplier The remaining fraction after both fees are applied\n   */\n  function combineFees(\n    uint64 protocolFee,\n    uint64 liquiditySourceFee\n  ) internal pure returns (uint256 combinedFeeMultiplier) {\n    combinedFeeMultiplier =\n      ((FEE_DENOMINATOR - protocolFee) * (FEE_DENOMINATOR - liquiditySourceFee)) /\n      FEE_DENOMINATOR;\n  }\n}\n"},{"file_path":"lib/mento-core/contracts/libraries/TradingLimitsV2.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\npragma experimental ABIEncoderV2;\n\nimport { ITradingLimitsV2 } from \"contracts/interfaces/ITradingLimitsV2.sol\";\n\n/**\n * @title TradingLimitsV2\n * @author Mento Team\n * @notice This library provides data structs and utility functions for\n * defining and verifying trading limits on the netflow of an asset.\n * There are two limits that can be enabled:\n * - L0: Short-term limit with fixed 5-minute time window\n *       -limit0 <= netflow0 <= limit0\n * - L1: Medium-term limit with fixed 1-day time window\n *       -limit1 <= netflow1 <= limit1\n *\n * @dev All contained functions are pure or view and marked internal to\n * be inlined on consuming contracts at compile time for gas efficiency.\n * Both State and Config structs are designed to be packed in one\n * storage slot each.\n *\n * Key differences from V1:\n * 1. Netflows are stored with 15 decimals of precision internally\n * 2. Small amounts are no longer rounded up to 1 full token. For tokens with more than 15 decimals,\n *    amounts smaller than 10^(decimals-15) truncate to zero and are untracked\n * 3. Larger data types: int96 for netflows, int120 for limits\n * 4. Removed global limit functionality\n * 5. Fixed timeframes: 5 minutes for L0, 1 day for L1\n */\nlibrary TradingLimitsV2 {\n  uint8 private constant INTERNAL_DECIMALS = 15;\n  uint32 private constant TIMESTEP0 = 5 minutes; // 300 seconds\n  uint32 private constant TIMESTEP1 = 1 days; // 86400 seconds\n  int96 private constant MAX_INT96 = type(int96).max;\n  int96 private constant MIN_INT96 = type(int96).min;\n  uint256 private constant BASIS_POINTS_DENOMINATOR = 10000;\n\n  /**\n   * @notice Validate a trading limit configuration.\n   * @dev Reverts if the configuration is malformed.\n   * @param self the Config struct to check.\n   */\n  function validate(ITradingLimitsV2.Config memory self) internal pure {\n    if (self.limit0 > 0 && self.limit1 > 0 && self.limit1 <= self.limit0) {\n      revert ITradingLimitsV2.Limit1MustBeGreaterThanLimit0();\n    }\n    if (0 == self.decimals || 18 < self.decimals) {\n      revert ITradingLimitsV2.InvalidDecimals();\n    }\n  }\n\n  /**\n   * @notice Verify a trading limit State with a provided Config.\n   * @dev Reverts if the limits are exceeded.\n   * The netflows and limits are stored with 15 decimals of precision.\n   * @param self the trading limit State to check.\n   * @param config the trading limit Config to check against.\n   */\n  function verify(ITradingLimitsV2.State memory self, ITradingLimitsV2.Config memory config) internal pure {\n    if (config.limit0 > 0 && (self.netflow0 < -config.limit0 || self.netflow0 > config.limit0)) {\n      revert ITradingLimitsV2.L0LimitExceeded();\n    }\n    if (config.limit1 > 0 && (self.netflow1 < -config.limit1 || self.netflow1 > config.limit1)) {\n      revert ITradingLimitsV2.L1LimitExceeded();\n    }\n  }\n\n  /**\n   * @notice Reset an existing state with a new config.\n   * It keeps netflows of enabled limits and resets when disabled.\n   * It resets all timestamp checkpoints to reset time-window limits\n   * on next swap.\n   * @param self the trading limit state to reset.\n   * @param config the updated config to reset against.\n   * @return the reset state.\n   */\n  function reset(\n    ITradingLimitsV2.State memory self,\n    ITradingLimitsV2.Config memory config\n  ) internal pure returns (ITradingLimitsV2.State memory) {\n    // Ensure the next swap will reset the trading limits windows.\n    self.lastUpdated0 = 0;\n    self.lastUpdated1 = 0;\n    if (config.limit0 == 0) {\n      self.netflow0 = 0;\n    }\n    if (config.limit1 == 0) {\n      self.netflow1 = 0;\n    }\n    return self;\n  }\n\n  /**\n   * @notice Apply trading limits by updating state and verifying against config.\n   * @dev This is the main entry point for applying trading limits. It loads state and config\n   * in memory, updates the state, verifies limits, and returns the updated TradingLimits struct.\n   * The caller should write the returned struct back to storage.\n   * This function also deducts the fee from the amount in to only track net trading flow for limits.\n   * @param self the trading limits (state + config) to apply.\n   * @param amountIn amount of token flowing in.\n   * @param amountOut amount of token flowing out.\n   * @return the updated trading limits.\n   */\n  function applyTradingLimits(\n    ITradingLimitsV2.TradingLimits memory self,\n    uint256 amountIn,\n    uint256 amountOut,\n    uint256 feeBps\n  ) internal view returns (ITradingLimitsV2.State memory) {\n    if (self.config.limit0 == 0 && self.config.limit1 == 0) {\n      return self.state;\n    }\n    uint256 scaledAmountIn = scaleValue(amountIn, self.config.decimals);\n    uint256 scaledAmountOut = scaleValue(amountOut, self.config.decimals);\n\n    // deducting the fee from the amount in to only track net trading flow for limits.\n    scaledAmountIn = scaledAmountIn - ((scaledAmountIn * feeBps) / (BASIS_POINTS_DENOMINATOR));\n    int256 deltaFlow = int256(scaledAmountIn) - int256(scaledAmountOut);\n\n    if (deltaFlow > MAX_INT96 || deltaFlow < MIN_INT96) revert ITradingLimitsV2.ValueExceedsInt96Bounds();\n    self.state = update(self.state, self.config, int96(deltaFlow));\n    verify(self.state, self.config);\n    return self.state;\n  }\n\n  /**\n   * @notice Updates a trading limit State in the context of a Config with the deltaFlow provided.\n   * @param self the trading limit State to update.\n   * @param config the trading limit Config for the provided State.\n   * @param deltaFlow the delta flow to add to the netflow.\n   * @return State the updated state.\n   */\n  function update(\n    ITradingLimitsV2.State memory self,\n    ITradingLimitsV2.Config memory config,\n    int96 deltaFlow\n  ) internal view returns (ITradingLimitsV2.State memory) {\n    if (deltaFlow == 0) {\n      return self;\n    }\n\n    if (config.limit0 > 0) {\n      if (block.timestamp > self.lastUpdated0 + TIMESTEP0) {\n        self.netflow0 = 0;\n        self.lastUpdated0 = uint32(block.timestamp);\n      }\n      self.netflow0 = safeAdd(self.netflow0, deltaFlow);\n    }\n\n    if (config.limit1 > 0) {\n      if (block.timestamp > self.lastUpdated1 + TIMESTEP1) {\n        self.netflow1 = 0;\n        self.lastUpdated1 = uint32(block.timestamp);\n      }\n      self.netflow1 = safeAdd(self.netflow1, deltaFlow);\n    }\n\n    return self;\n  }\n\n  /**\n   * @notice Scale a value from token decimals to internal precision (15 decimals).\n   * @dev Handles both scaling up (for tokens with < 15 decimals) and scaling down (> 15 decimals).\n   * @param value the value in token decimals.\n   * @param decimals the token's decimal places.\n   * @return the scaled value in 15 decimal precision.\n   */\n  function scaleValue(uint256 value, uint8 decimals) internal pure returns (uint256) {\n    if (value == 0) return 0;\n\n    uint256 scaledValue = (value * 10 ** INTERNAL_DECIMALS) / 10 ** decimals;\n\n    return scaledValue;\n  }\n\n  /**\n   * @notice Safe add two int96 values.\n   * @dev Reverts if addition causes over/underflow.\n   * @param a first value to add.\n   * @param b second value to add.\n   * @return result of addition.\n   */\n  function safeAdd(int96 a, int96 b) internal pure returns (int96) {\n    int256 c = int256(a) + int256(b);\n    if (c < MIN_INT96 || c > MAX_INT96) revert ITradingLimitsV2.Int96AdditionOverflow();\n    return int96(c);\n  }\n}\n"},{"file_path":"lib/mento-core/contracts/swap/router/interfaces/IRPool.sol","source_code":"// SPDX-License-Identifier: BUSL-1.1\npragma solidity ^0.8.0;\n\n/**\n * @title IRPool\n * @notice Minimal interface for a Pool that the router can use\n * to swap\n */\ninterface IRPool {\n  /* ========== Events ========== */\n\n  /**\n   * @notice Emitted when tokens are swapped\n   * @param sender Address that initiated the swap\n   * @param amount0In Amount of token0 sent to the pool\n   * @param amount1In Amount of token1 sent to the pool\n   * @param amount0Out Amount of token0 sent to the receiver\n   * @param amount1Out Amount of token1 sent to the receiver\n   * @param to Address receiving the output tokens\n   */\n  event Swap(\n    address indexed sender,\n    uint256 amount0In,\n    uint256 amount1In,\n    uint256 amount0Out,\n    uint256 amount1Out,\n    address indexed to\n  );\n\n  /* ========== View Functions ========== */\n\n  /**\n   * @notice Calculates output amount for a given input\n   * @param amountIn Input amount\n   * @param tokenIn Address of input token\n   * @return amountOut Output amount after fees\n   */\n  function getAmountOut(uint256 amountIn, address tokenIn) external view returns (uint256 amountOut);\n\n  /**\n   * @notice Swaps tokens\n   * @param amount0Out Amount of token0 to output\n   * @param amount1Out Amount of token1 to output\n   * @param to Address receiving output tokens\n   * @param data Optional callback data\n   */\n  function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;\n\n  /// @notice Returns current reserves and timestamp\n  /// @return _reserve0 Current reserve of token0\n  /// @return _reserve1 Current reserve of token1\n  /// @return _blockTimestampLast Timestamp of last reserve update\n  function getReserves() external view returns (uint256 _reserve0, uint256 _reserve1, uint256 _blockTimestampLast);\n\n  /**\n   * @notice Returns pool metadata\n   * @return dec0 Scaling factor for token0\n   * @return dec1 Scaling factor for token1\n   * @return r0 Reserve amount of token0\n   * @return r1 Reserve amount of token1\n   * @return t0 Address of token0\n   * @return t1 Address of token1\n   */\n  function metadata()\n    external\n    view\n    returns (uint256 dec0, uint256 dec1, uint256 r0, uint256 r1, address t0, address t1);\n\n  /**\n   * @notice Returns addresses of both tokens in the pair\n   * @return Address of token0 and token1\n   */\n  function tokens() external view returns (address, address);\n\n  /**\n   * @notice Returns the address of the first token in the pair\n   * @return Address of token0\n   */\n  function token0() external view returns (address);\n\n  /**\n   * @notice Returns the address of the second token in the pair\n   * @return Address of token1\n   */\n  function token1() external view returns (address);\n\n  /**\n   * @notice Returns the scaling factor for token0 based on its decimals\n   * @return Scaling factor for token0\n   */\n  function decimals0() external view returns (uint256);\n\n  /**\n   * @notice Returns the scaling factor for token1 based on its decimals\n   * @return Scaling factor for token1\n   */\n  function decimals1() external view returns (uint256);\n\n  /**\n   * @notice Returns the reserve amount of token0\n   * @return Reserve amount of token0\n   */\n  function reserve0() external view returns (uint256);\n\n  /**\n   * @notice Returns the reserve amount of token1\n   * @return Reserve amount of token1\n   */\n  function reserve1() external view returns (uint256);\n\n  /**\n   * @notice Returns the protocol fee in basis points (1 basis point = .01%)\n   * @return Protocol fee in basis points\n   */\n  function protocolFee() external view returns (uint256);\n}\n"},{"file_path":"lib/mento-core/lib/foundry-chainlink-toolkit/src/interfaces/feeds/AggregatorV3Interface.sol","source_code":"// SPDX-License-Identifier: MIT\npragma solidity >=0.6.2 <0.9.0;\n\ninterface AggregatorV3Interface {\n  function decimals() external view returns (uint8);\n  function description() external view returns (string memory);\n  function version() external view returns (uint256);\n  function getRoundData(uint80 _roundId) external view returns (\n    uint80 roundId,\n    int256 answer,\n    uint256 startedAt,\n    uint256 updatedAt,\n    uint80 answeredInRound\n  );\n  function latestRoundData() external view returns (\n    uint80 roundId,\n    int256 answer,\n    uint256 startedAt,\n    uint256 updatedAt,\n    uint80 answeredInRound\n  );\n}\n"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-next/contracts/utils/math/Math.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1);\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator,\n        Rounding rounding\n    ) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10**64) {\n                value /= 10**64;\n                result += 64;\n            }\n            if (value >= 10**32) {\n                value /= 10**32;\n                result += 32;\n            }\n            if (value >= 10**16) {\n                value /= 10**16;\n                result += 16;\n            }\n            if (value >= 10**8) {\n                value /= 10**8;\n                result += 8;\n            }\n            if (value >= 10**4) {\n                value /= 10**4;\n                result += 4;\n            }\n            if (value >= 10**2) {\n                value /= 10**2;\n                result += 2;\n            }\n            if (value >= 10**1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n        }\n    }\n}\n"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\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 * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\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 */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\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    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the 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 virtual onlyOwner {\n        _transferOwnership(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 virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/Initializable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts.\n     *\n     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n     * constructor.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = !_initializing;\n        require(\n            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n            \"Initializable: contract is already initialized\"\n        );\n        _initialized = 1;\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n     * are added through upgrades and that require initialization.\n     *\n     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n     * cannot be nested. If one is invoked in the context of another, execution will revert.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     *\n     * WARNING: setting the version to 255 will prevent any future reinitialization.\n     *\n     * Emits an {Initialized} event.\n     */\n    modifier reinitializer(uint8 version) {\n        require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n        _initialized = version;\n        _initializing = true;\n        _;\n        _initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        require(_initializing, \"Initializable: contract is not initializing\");\n        _;\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     *\n     * Emits an {Initialized} event the first time it is successfully executed.\n     */\n    function _disableInitializers() internal virtual {\n        require(!_initializing, \"Initializable: contract is initializing\");\n        if (_initialized < type(uint8).max) {\n            _initialized = type(uint8).max;\n            emit Initialized(type(uint8).max);\n        }\n    }\n\n    /**\n     * @dev Returns the highest version that has been initialized. See {reinitializer}.\n     */\n    function _getInitializedVersion() internal view returns (uint8) {\n        return _initialized;\n    }\n\n    /**\n     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n     */\n    function _isInitializing() internal view returns (bool) {\n        return _initializing;\n    }\n}\n"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-upgradeable/contracts/security/ReentrancyGuardUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    function __ReentrancyGuard_init() internal onlyInitializing {\n        __ReentrancyGuard_init_unchained();\n    }\n\n    function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be _NOT_ENTERED\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/ERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC20Upgradeable.sol\";\nimport \"./extensions/IERC20MetadataUpgradeable.sol\";\nimport \"../../utils/ContextUpgradeable.sol\";\nimport \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {\n    mapping(address => uint256) private _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 private _totalSupply;\n\n    string private _name;\n    string private _symbol;\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * The default value of {decimals} is 18. To select a different value for\n     * {decimals} you should overload it.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {\n        __ERC20_init_unchained(name_, symbol_);\n    }\n\n    function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n        _name = name_;\n        _symbol = symbol_;\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual override returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual override returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the value {ERC20} uses, unless this function is\n     * overridden;\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual override returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual override returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address to, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _transfer(owner, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender) public view virtual override returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on\n     * `transferFrom`. This is semantically equivalent to an infinite approval.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount) public virtual override returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * NOTE: Does not update the allowance if the current allowance\n     * is the maximum `uint256`.\n     *\n     * Requirements:\n     *\n     * - `from` and `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``from``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) public virtual override returns (bool) {\n        address spender = _msgSender();\n        _spendAllowance(from, spender, amount);\n        _transfer(from, to, amount);\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        _approve(owner, spender, allowance(owner, spender) + addedValue);\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n        address owner = _msgSender();\n        uint256 currentAllowance = allowance(owner, spender);\n        require(currentAllowance >= subtractedValue, \"ERC20: decreased allowance below zero\");\n        unchecked {\n            _approve(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `from` to `to`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `from` cannot be the zero address.\n     * - `to` cannot be the zero address.\n     * - `from` must have a balance of at least `amount`.\n     */\n    function _transfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {\n        require(from != address(0), \"ERC20: transfer from the zero address\");\n        require(to != address(0), \"ERC20: transfer to the zero address\");\n\n        _beforeTokenTransfer(from, to, amount);\n\n        uint256 fromBalance = _balances[from];\n        require(fromBalance >= amount, \"ERC20: transfer amount exceeds balance\");\n        unchecked {\n            _balances[from] = fromBalance - amount;\n            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by\n            // decrementing then incrementing.\n            _balances[to] += amount;\n        }\n\n        emit Transfer(from, to, amount);\n\n        _afterTokenTransfer(from, to, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        _beforeTokenTransfer(address(0), account, amount);\n\n        _totalSupply += amount;\n        unchecked {\n            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.\n            _balances[account] += amount;\n        }\n        emit Transfer(address(0), account, amount);\n\n        _afterTokenTransfer(address(0), account, amount);\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 amount) internal virtual {\n        require(account != address(0), \"ERC20: burn from the zero address\");\n\n        _beforeTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n            // Overflow not possible: amount <= accountBalance <= totalSupply.\n            _totalSupply -= amount;\n        }\n\n        emit Transfer(account, address(0), amount);\n\n        _afterTokenTransfer(account, address(0), amount);\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        require(owner != address(0), \"ERC20: approve from the zero address\");\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.\n     *\n     * Does not update the allowance amount in case of infinite allowance.\n     * Revert if not enough allowance is available.\n     *\n     * Might emit an {Approval} event.\n     */\n    function _spendAllowance(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        uint256 currentAllowance = allowance(owner, spender);\n        if (currentAllowance != type(uint256).max) {\n            require(currentAllowance >= amount, \"ERC20: insufficient allowance\");\n            unchecked {\n                _approve(owner, spender, currentAllowance - amount);\n            }\n        }\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[45] private __gap;\n}\n"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/IERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\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    /**\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 `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, 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 `from` to `to` 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(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/IERC20MetadataUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20MetadataUpgradeable is IERC20Upgradeable {\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"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20PermitUpgradeable {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/utils/SafeERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20Upgradeable.sol\";\nimport \"../extensions/draft-IERC20PermitUpgradeable.sol\";\nimport \"../../../utils/AddressUpgradeable.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20Upgradeable {\n    using AddressUpgradeable for address;\n\n    function safeTransfer(\n        IERC20Upgradeable token,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20Upgradeable token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(\n        IERC20Upgradeable token,\n        address spender,\n        uint256 value\n    ) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    function safeIncreaseAllowance(\n        IERC20Upgradeable token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(\n        IERC20Upgradeable token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\n\n    function safePermit(\n        IERC20PermitUpgradeable token,\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        uint256 nonceBefore = token.nonces(owner);\n        token.permit(owner, spender, value, deadline, v, r, s);\n        uint256 nonceAfter = token.nonces(owner);\n        require(nonceAfter == nonceBefore + 1, \"SafeERC20: permit did not succeed\");\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        if (returndata.length > 0) {\n            // Return data is optional\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-upgradeable/contracts/utils/AddressUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n     *\n     * _Available since v4.8._\n     */\n    function verifyCallResultFromTarget(\n        address target,\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        if (success) {\n            if (returndata.length == 0) {\n                // only check isContract if the call was successful and the return data is empty\n                // otherwise we already know that it was a contract\n                require(isContract(target), \"Address: call to non-contract\");\n            }\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    /**\n     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason or using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            _revert(returndata, errorMessage);\n        }\n    }\n\n    function _revert(bytes memory returndata, string memory errorMessage) private pure {\n        // Look for revert reason and bubble it up if present\n        if (returndata.length > 0) {\n            // The easiest way to bubble the revert reason is using memory via assembly\n            /// @solidity memory-safe-assembly\n            assembly {\n                let returndata_size := mload(returndata)\n                revert(add(32, returndata), returndata_size)\n            }\n        } else {\n            revert(errorMessage);\n        }\n    }\n}\n"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-upgradeable/contracts/utils/ContextUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\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 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 */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[50] private __gap;\n}\n"},{"file_path":"lib/mento-core/lib/openzeppelin-contracts-upgradeable/contracts/utils/math/MathUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary MathUpgradeable {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1);\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator,\n        Rounding rounding\n    ) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10**64) {\n                value /= 10**64;\n                result += 64;\n            }\n            if (value >= 10**32) {\n                value /= 10**32;\n                result += 32;\n            }\n            if (value >= 10**16) {\n                value /= 10**16;\n                result += 16;\n            }\n            if (value >= 10**8) {\n                value /= 10**8;\n                result += 8;\n            }\n            if (value >= 10**4) {\n                value /= 10**4;\n                result += 4;\n            }\n            if (value >= 10**2) {\n                value /= 10**2;\n                result += 2;\n            }\n            if (value >= 10**1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n        }\n    }\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"bool","name":"disable","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FeeTooHigh","type":"error"},{"inputs":[],"name":"InsufficientAmount0In","type":"error"},{"inputs":[],"name":"InsufficientAmount1In","type":"error"},{"inputs":[],"name":"InsufficientInputAmount","type":"error"},{"inputs":[],"name":"InsufficientLiquidity","type":"error"},{"inputs":[],"name":"InsufficientLiquidityBurned","type":"error"},{"inputs":[],"name":"InsufficientLiquidityMinted","type":"error"},{"inputs":[],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"Int96AdditionOverflow","type":"error"},{"inputs":[],"name":"InvalidDecimals","type":"error"},{"inputs":[],"name":"InvalidToAddress","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"InvalidTokenDecimals","type":"error"},{"inputs":[],"name":"L0LimitExceeded","type":"error"},{"inputs":[],"name":"L1LimitExceeded","type":"error"},{"inputs":[],"name":"Limit1MustBeGreaterThanLimit0","type":"error"},{"inputs":[],"name":"LimitDoesNotFitInInt120","type":"error"},{"inputs":[],"name":"NotFeeSetter","type":"error"},{"inputs":[],"name":"NotLiquidityStrategy","type":"error"},{"inputs":[],"name":"OneOutputAmountRequired","type":"error"},{"inputs":[],"name":"PriceDifferenceMovedInWrongDirection","type":"error"},{"inputs":[],"name":"PriceDifferenceMovedTooFarFromThresholds","type":"error"},{"inputs":[],"name":"PriceDifferenceNotImproved","type":"error"},{"inputs":[],"name":"PriceDifferenceTooSmall","type":"error"},{"inputs":[],"name":"ProtocolFeeRecipientRequired","type":"error"},{"inputs":[],"name":"RebalanceDirectionInvalid","type":"error"},{"inputs":[],"name":"RebalanceIncentiveTooHigh","type":"error"},{"inputs":[],"name":"RebalanceThresholdTooHigh","type":"error"},{"inputs":[],"name":"ReferenceRateNotSet","type":"error"},{"inputs":[],"name":"ReserveValueDecreased","type":"error"},{"inputs":[],"name":"ReservesEmpty","type":"error"},{"inputs":[],"name":"ValueExceedsInt96Bounds","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldFeeSetter","type":"address"},{"indexed":true,"internalType":"address","name":"newFeeSetter","type":"address"}],"name":"FeeSetterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"oldInvertRateFeed","type":"bool"},{"indexed":false,"internalType":"bool","name":"newInvertRateFeed","type":"bool"}],"name":"InvertRateFeedUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"LPFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"LiquidityStrategyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"liquidity","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOracleAdapter","type":"address"},{"indexed":true,"internalType":"address","name":"newOracleAdapter","type":"address"}],"name":"OracleAdapterUpdated","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":true,"internalType":"address","name":"oldRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newRecipient","type":"address"}],"name":"ProtocolFeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"ProtocolFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldIncentive","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newIncentive","type":"uint256"}],"name":"RebalanceIncentiveUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldThresholdAbove","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldThresholdBelow","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newThresholdAbove","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newThresholdBelow","type":"uint256"}],"name":"RebalanceThresholdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"priceDifferenceBefore","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priceDifferenceAfter","type":"uint256"}],"name":"Rebalanced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldRateFeedID","type":"address"},{"indexed":true,"internalType":"address","name":"newRateFeedID","type":"address"}],"name":"ReferenceRateFeedIDUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount0In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1In","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount0Out","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount1Out","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Swap","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"int120","name":"limit0","type":"int120"},{"internalType":"int120","name":"limit1","type":"int120"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"indexed":false,"internalType":"struct ITradingLimitsV2.Config","name":"config","type":"tuple"}],"name":"TradingLimitConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reserve0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reserve1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"blockTimestamp","type":"uint256"}],"name":"UpdateReserves","type":"event"},{"inputs":[],"name":"BASIS_POINTS_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRADING_MODE_BIDIRECTIONAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"blockTimestampLast","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"burn","outputs":[{"internalType":"uint256","name":"amount0","type":"uint256"},{"internalType":"uint256","name":"amount1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"limit0","type":"uint256"},{"internalType":"uint256","name":"limit1","type":"uint256"}],"name":"configureTradingLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeSetter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address","name":"tokenIn","type":"address"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRebalancingState","outputs":[{"internalType":"uint256","name":"oraclePriceNumerator","type":"uint256"},{"internalType":"uint256","name":"oraclePriceDenominator","type":"uint256"},{"internalType":"uint256","name":"reservePriceNumerator","type":"uint256"},{"internalType":"uint256","name":"reservePriceDenominator","type":"uint256"},{"internalType":"bool","name":"reservePriceAboveOraclePrice","type":"bool"},{"internalType":"uint16","name":"rebalanceThreshold","type":"uint16"},{"internalType":"uint256","name":"priceDifference","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint256","name":"_reserve0","type":"uint256"},{"internalType":"uint256","name":"_reserve1","type":"uint256"},{"internalType":"uint256","name":"_blockTimestampLast","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTradingLimits","outputs":[{"components":[{"internalType":"int120","name":"limit0","type":"int120"},{"internalType":"int120","name":"limit1","type":"int120"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"internalType":"struct ITradingLimitsV2.Config","name":"config","type":"tuple"},{"components":[{"internalType":"uint32","name":"lastUpdated0","type":"uint32"},{"internalType":"uint32","name":"lastUpdated1","type":"uint32"},{"internalType":"int96","name":"netflow0","type":"int96"},{"internalType":"int96","name":"netflow1","type":"int96"}],"internalType":"struct ITradingLimitsV2.State","name":"state","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"},{"internalType":"address","name":"_oracleAdapter","type":"address"},{"internalType":"address","name":"_referenceRateFeedID","type":"address"},{"internalType":"bool","name":"_invertRateFeed","type":"bool"},{"internalType":"address","name":"_initialOwner","type":"address"},{"components":[{"internalType":"uint256","name":"lpFee","type":"uint256"},{"internalType":"uint256","name":"protocolFee","type":"uint256"},{"internalType":"address","name":"protocolFeeRecipient","type":"address"},{"internalType":"address","name":"feeSetter","type":"address"},{"internalType":"uint256","name":"rebalanceIncentive","type":"uint256"},{"internalType":"uint256","name":"rebalanceThresholdAbove","type":"uint256"},{"internalType":"uint256","name":"rebalanceThresholdBelow","type":"uint256"}],"internalType":"struct IFPMM.FPMMParams","name":"_params","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"invertRateFeed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"}],"name":"liquidityStrategy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadata","outputs":[{"internalType":"uint256","name":"dec0","type":"uint256"},{"internalType":"uint256","name":"dec1","type":"uint256"},{"internalType":"uint256","name":"r0","type":"uint256"},{"internalType":"uint256","name":"r1","type":"uint256"},{"internalType":"address","name":"t0","type":"address"},{"internalType":"address","name":"t1","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleAdapter","outputs":[{"internalType":"contract IOracleAdapter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0Out","type":"uint256"},{"internalType":"uint256","name":"amount1Out","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rebalanceIncentive","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalanceThresholdAbove","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalanceThresholdBelow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referenceRateFeedID","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserve0","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserve1","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_feeSetter","type":"address"}],"name":"setFeeSetter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_invertRateFeed","type":"bool"}],"name":"setInvertRateFeed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lpFee","type":"uint256"}],"name":"setLPFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"},{"internalType":"bool","name":"state","type":"bool"}],"name":"setLiquidityStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_oracleAdapter","type":"address"}],"name":"setOracleAdapter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_protocolFee","type":"uint256"}],"name":"setProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_protocolFeeRecipient","type":"address"}],"name":"setProtocolFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rebalanceIncentive","type":"uint256"}],"name":"setRebalanceIncentive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rebalanceThresholdAbove","type":"uint256"},{"internalType":"uint256","name":"_rebalanceThresholdBelow","type":"uint256"}],"name":"setRebalanceThresholds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_referenceRateFeedID","type":"address"}],"name":"setReferenceRateFeedID","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount0Out","type":"uint256"},{"internalType":"uint256","name":"amount1Out","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokens","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":true,"constructor_args":"0x0000000000000000000000000000000000000000000000000000000000000001"}