{"file_path":"contracts/f(x)/v1/Treasury.sol","creation_status":"success","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.6;\npragma abicoder v2;\n\nimport { OwnableUpgradeable } from \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport { SafeMathUpgradeable } from \"@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol\";\nimport { SignedSafeMathUpgradeable } from \"@openzeppelin/contracts-upgradeable/math/SignedSafeMathUpgradeable.sol\";\nimport { IERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol\";\nimport { SafeERC20Upgradeable } from \"@openzeppelin/contracts-upgradeable/token/ERC20/SafeERC20Upgradeable.sol\";\n\nimport { ExponentialMovingAverageV7 } from \"../../common/math/ExponentialMovingAverageV7.sol\";\n\nimport { IRWAVaultPriceOracle } from \"../../price-oracle/interfaces/IRWAVaultPriceOracle.sol\";\n\nimport { IAssetStrategy } from \"../../interfaces/f(x)/IAssetStrategy.sol\";\nimport { IFxFractionalToken } from \"../../interfaces/f(x)/IFxFractionalToken.sol\";\nimport { IFxLeveragedToken } from \"../../interfaces/f(x)/IFxLeveragedToken.sol\";\nimport { IFxRateProvider } from \"../../interfaces/f(x)/IFxRateProvider.sol\";\nimport { IFxTreasury } from \"../../interfaces/f(x)/IFxTreasury.sol\";\n\nimport { FxLowVolatilityMath } from \"../math/FxLowVolatilityMath.sol\";\n\n// solhint-disable no-empty-blocks\n// solhint-disable not-rely-on-time\n\ncontract Treasury is OwnableUpgradeable, IFxTreasury {\n  using SafeERC20Upgradeable for IERC20Upgradeable;\n  using SafeMathUpgradeable for uint256;\n  using SignedSafeMathUpgradeable for int256;\n  using FxLowVolatilityMath for FxLowVolatilityMath.SwapState;\n  using ExponentialMovingAverageV7 for ExponentialMovingAverageV7.EMAStorage;\n\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the whitelist status for settle is updated.\n  /// @param account The address of account to change.\n  /// @param status The new whitelist status.\n  event UpdateSettleWhitelist(address account, bool status);\n\n  /// @notice Emitted when the rate provider contract is updated.\n  /// @param rateProvider The address of new rate provider.\n  event UpdateRateProvider(address rateProvider);\n\n  /// @notice Emitted when the strategy contract is updated.\n  /// @param strategy The address of new strategy.\n  event UpdateStrategy(address strategy);\n\n  /// @notice Emitted when the beta for fToken is updated.\n  /// @param beta The new value of beta.\n  event UpdateBeta(uint256 beta);\n\n  /// @notice Emitted when the base token cap is updated.\n  /// @param baseTokenCap The new base token cap.\n  event UpdateBaseTokenCap(uint256 baseTokenCap);\n\n    /// @notice Emitted when the price oracle contract is updated.\n  /// @param priceOracle The address of new price oracle.\n  event UpdatePriceOracle(address priceOracle, uint256 priceOracleDecimals);\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The precision used to compute nav.\n  uint256 internal constant PRECISION = 1e18;\n\n  /// @dev The precision used to compute nav.\n  int256 private constant PRECISION_I256 = 1e18;\n\n  /// @dev The initial mint ratio for fToken.\n  uint256 private immutable initialMintRatio;\n\n  /*********\n   * Enums *\n   *********/\n\n\n  /*************\n   * Variables *\n   *************/\n\n  /// @notice The address of market contract.\n  address public market;\n\n  /// @inheritdoc IFxTreasury\n  address public override baseToken;\n\n  /// @inheritdoc IFxTreasury\n  address public override fToken;\n\n  /// @inheritdoc IFxTreasury\n  address public override xToken;\n\n  /// @notice The address of RWA Vault price feed.\n  address public priceOracle;\n\n  /// @notice the decimals of the price oracle\n  uint256 public priceOracleDecimals;\n\n  /// @notice The volitality multiple of fToken compare to base token.\n  uint256 public beta;\n\n  /// @inheritdoc IFxTreasury\n  uint256 public override lastPermissionedPrice;\n\n  /// @notice The maximum amount of base token can be deposited.\n  uint256 public baseTokenCap;\n\n  /// @inheritdoc IFxTreasury\n  uint256 public override totalBaseToken;\n\n  /// @inheritdoc IFxTreasury\n  address public override strategy;\n\n  /// @inheritdoc IFxTreasury\n  uint256 public override strategyUnderlying;\n\n  /// @notice Whether the sender is allowed to do settlement.\n  mapping(address => bool) public settleWhitelist;\n\n  /// @notice The address of rate provider contract.\n  address public rateProvider;\n\n  /// @notice The ema storage of the leverage ratio.\n  ExponentialMovingAverageV7.EMAStorage public emaLeverageRatio;\n\n  /// @dev Slots for future use.\n  uint256[37] private _gap;\n\n  /************\n   * Modifier *\n   ************/\n\n  modifier onlyMarket() {\n    require(msg.sender == market, \"Only market\");\n    _;\n  }\n\n  modifier onlyStrategy() {\n    require(msg.sender == strategy, \"Only strategy\");\n    _;\n  }\n\n  /***************\n   * Constructor *\n   ***************/\n\n  constructor(uint256 _initialMintRatio) {\n    require(0 < _initialMintRatio && _initialMintRatio < PRECISION, \"invalid initial mint ratio\");\n    initialMintRatio = _initialMintRatio;\n  }\n\n  function initialize(\n    address _market,\n    address _baseToken,\n    address _fToken,\n    address _xToken,\n    address _priceOracle,\n    uint256 _priceOracleDecimals,\n    uint256 _beta,\n    uint256 _baseTokenCap,\n    address _rateProvider\n  ) external initializer {\n    OwnableUpgradeable.__Ownable_init();\n\n    market = _market;\n    baseToken = _baseToken;\n    fToken = _fToken;\n    xToken = _xToken;\n    priceOracle = _priceOracle;\n    priceOracleDecimals = _priceOracleDecimals;\n    beta = _beta;\n    baseTokenCap = _baseTokenCap;\n\n    if (_rateProvider != address(0)) {\n      rateProvider = _rateProvider;\n    }\n  }\n\n  function initializeV2(uint24 sampleInterval) external {\n    ExponentialMovingAverageV7.EMAStorage memory cachedEmaLeverageRatio = emaLeverageRatio;\n    require(cachedEmaLeverageRatio.lastTime == 0, \"v2 initialized\");\n\n    cachedEmaLeverageRatio.lastTime = uint40(block.timestamp);\n    cachedEmaLeverageRatio.sampleInterval = sampleInterval;\n    cachedEmaLeverageRatio.lastValue = uint96(PRECISION);\n    cachedEmaLeverageRatio.lastEmaValue = uint96(PRECISION);\n\n    emaLeverageRatio = cachedEmaLeverageRatio;\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @inheritdoc IFxTreasury\n  function collateralRatio() external view override returns (uint256) {\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    if (_state.baseSupply == 0) return PRECISION;\n    \n    int256 multiple = _computeMultiple(_state.baseNav);\n    uint256 candidateFNav = IFxFractionalToken(fToken).getCandidateNav(multiple);\n    if (_state.fSupply == 0 || candidateFNav == 0) return PRECISION * PRECISION;\n\n    return _state.baseSupply.mul(_state.baseNav).mul(PRECISION).div(_state.fSupply.mul(candidateFNav));\n  }\n\n  /// @inheritdoc IFxTreasury\n  function getCurrentNav()\n    external\n    view\n    override\n    returns (\n      uint256 _baseNav,\n      uint256 _fNav,\n      uint256 _xNav\n    )\n  {\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n\n    _baseNav = _state.baseNav;\n    _fNav = _state.fNav;\n    _xNav = _state.xNav;\n  }\n\n  /// @inheritdoc IFxTreasury\n  /// @dev If the current collateral ratio <= new collateral ratio, we should return 0.\n  function maxMintableFToken(uint256 _newCollateralRatio)\n    external\n    view\n    override\n    returns (uint256 _maxBaseIn, uint256 _maxFTokenMintable)\n  {\n    require(_newCollateralRatio > PRECISION, \"collateral ratio too small\");\n\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    (_maxBaseIn, _maxFTokenMintable) = _state.maxMintableFToken(_newCollateralRatio);\n  }\n\n  /// @inheritdoc IFxTreasury\n  function maxMintableFTokenWithoutBaseToken(uint256 _newCollateralRatio)\n    external\n    view\n    override\n    returns (uint256 _maxFTokenMintable)\n  {\n    require(_newCollateralRatio > PRECISION, \"collateral ratio too small\");\n\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    _maxFTokenMintable = _state.maxMintableFTokenWithoutBaseToken(_newCollateralRatio);\n  }\n\n  /// @inheritdoc IFxTreasury\n  /// @dev If the current collateral ratio >= new collateral ratio, we should return 0.\n  function mintFTokenWithoutBaseToken(uint256 _newCollateralRatio, address _recipient)\n    external\n    override\n    onlyMarket\n    returns (uint256 _fTokenOut)\n  {\n    require(_newCollateralRatio > PRECISION, \"collateral ratio too small\");\n\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    require(_state.xNav > 0, \"system under collateral\");\n    _updateEMALeverageRatio(_state);\n\n    _fTokenOut = _state.maxMintableFTokenWithoutBaseToken(_newCollateralRatio);\n    if (_fTokenOut > 0) {\n      IFxFractionalToken(fToken).mint(_recipient, _fTokenOut);\n    }\n  }\n\n  /// @inheritdoc IFxTreasury\n  /// @dev If the current collateral ratio >= new collateral ratio, we should return 0.\n  function maxMintableXToken(uint256 _newCollateralRatio)\n    external\n    view\n    override\n    returns (uint256 _maxBaseIn, uint256 _maxXTokenMintable)\n  {\n    require(_newCollateralRatio > PRECISION, \"collateral ratio too small\");\n\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    (_maxBaseIn, _maxXTokenMintable) = _state.maxMintableXToken(_newCollateralRatio);\n  }\n\n  /// @inheritdoc IFxTreasury\n  /// @dev If the current collateral ratio >= new collateral ratio, we should return 0.\n  function maxMintableXTokenWithIncentive(uint256 _newCollateralRatio, uint256 _incentiveRatio)\n    external\n    view\n    override\n    returns (uint256 _maxBaseIn, uint256 _maxXTokenMintable)\n  {\n    require(_newCollateralRatio > PRECISION, \"collateral ratio too small\");\n\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    (_maxBaseIn, _maxXTokenMintable) = _state.maxMintableXTokenWithIncentive(_newCollateralRatio, _incentiveRatio);\n  }\n\n  /// @inheritdoc IFxTreasury\n  /// @dev If the current collateral ratio >= new collateral ratio, we should return 0.\n  function maxRedeemableFToken(uint256 _newCollateralRatio)\n    external\n    view\n    override\n    returns (uint256 _maxBaseOut, uint256 _maxFTokenRedeemable)\n  {\n    require(_newCollateralRatio > PRECISION, \"collateral ratio too small\");\n\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    (_maxBaseOut, _maxFTokenRedeemable) = _state.maxRedeemableFToken(_newCollateralRatio);\n  }\n\n  /// @inheritdoc IFxTreasury\n  /// @dev If the current collateral ratio <= new collateral ratio, we should return 0.\n  function maxRedeemableXToken(uint256 _newCollateralRatio)\n    external\n    view\n    override\n    returns (uint256 _maxBaseOut, uint256 _maxXTokenRedeemable)\n  {\n    require(_newCollateralRatio > PRECISION, \"collateral ratio too small\");\n\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    (_maxBaseOut, _maxXTokenRedeemable) = _state.maxRedeemableXToken(_newCollateralRatio);\n  }\n\n  /// @inheritdoc IFxTreasury\n  /// @dev If the current collateral ratio >= new collateral ratio, we should return 0.\n  function maxLiquidatable(uint256 _newCollateralRatio, uint256 _incentiveRatio)\n    external\n    view\n    override\n    returns (uint256 _maxBaseOut, uint256 _maxFTokenLiquidatable)\n  {\n    require(_newCollateralRatio > PRECISION, \"collateral ratio too small\");\n\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    (_maxBaseOut, _maxFTokenLiquidatable) = _state.maxLiquidatable(_newCollateralRatio, _incentiveRatio);\n  }\n\n  /// @inheritdoc IFxTreasury\n  /// @dev If the current collateral ratio <= new collateral ratio, we should return 0.\n  function maxBaseForCollateralRatio(uint256 _newCollateralRatio) external view override returns (uint256 _maxBaseIn) {\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    uint256 candidateNav = IFxFractionalToken(fToken).getCandidateNav(_computeMultiple(_state.baseNav));\n    _maxBaseIn = _state.maxBaseDonationForCollateralRatio(candidateNav, _newCollateralRatio);\n  }\n\n  /// @inheritdoc IFxTreasury\n  function currentBaseTokenPrice() external view override returns (uint256) {\n    return _fetchRWAOraclePrice();\n  }\n\n  /// @inheritdoc IFxTreasury\n  function convertToWrapped(uint256 _amount) public view override returns (uint256) {\n    address _rateProvider = rateProvider;\n    if (_rateProvider != address(0)) {\n      _amount = _amount.mul(PRECISION).div(IFxRateProvider(_rateProvider).getRate());\n    }\n    return _amount;\n  }\n\n  /// @inheritdoc IFxTreasury\n  function convertToUnwrapped(uint256 _amount) external view override returns (uint256) {\n    address _rateProvider = rateProvider;\n    if (_rateProvider != address(0)) {\n      _amount = _amount.mul(IFxRateProvider(_rateProvider).getRate()).div(PRECISION);\n    }\n    return _amount;\n  }\n\n  /// @inheritdoc IFxTreasury\n  function leverageRatio() external view override returns (uint256) {\n    return emaLeverageRatio.emaValue();\n  }\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @inheritdoc IFxTreasury\n  function mint(\n    uint256 _baseIn,\n    address _recipient,\n    MintOption _option\n  ) external override onlyMarket returns (uint256 _fTokenOut, uint256 _xTokenOut) {\n    FxLowVolatilityMath.SwapState memory _state;\n\n    if (_option == MintOption.FToken) {\n      _state = _loadSwapState();\n      _updateEMALeverageRatio(_state);\n    } else if (_option == MintOption.XToken) {\n      _state = _loadSwapState();\n      _updateEMALeverageRatio(_state);\n    } else {\n      _state = _loadSwapState();\n    }\n    require(_state.xNav > 0, \"system under collateral\");\n\n    if (_option == MintOption.FToken) {\n      _fTokenOut = _state.mintFToken(_baseIn);\n    } else if (_option == MintOption.XToken) {\n      _xTokenOut = _state.mintXToken(_baseIn);\n    } else {\n      if (_state.baseSupply == 0) {\n        uint256 _totalVal = _baseIn.mul(_state.baseNav);\n        _fTokenOut = _totalVal.mul(initialMintRatio).div(PRECISION).div(PRECISION);\n        _xTokenOut = _totalVal.div(PRECISION).sub(_fTokenOut);\n      } else {\n        (_fTokenOut, _xTokenOut) = _state.mint(_baseIn);\n      }\n    }\n\n    // TODO: Need to make this flexible for future use.\n    require(_state.baseSupply + _baseIn <= baseTokenCap, \"Exceed total cap\");\n    totalBaseToken = _state.baseSupply + _baseIn;\n\n    if (_fTokenOut > 0) {\n      IFxFractionalToken(fToken).mint(_recipient, _fTokenOut);\n    }\n    if (_xTokenOut > 0) {\n      IFxLeveragedToken(xToken).mint(_recipient, _xTokenOut);\n    }\n  }\n\n  /// @inheritdoc IFxTreasury\n  function redeem(\n    uint256 _fTokenIn,\n    uint256 _xTokenIn,\n    address _owner\n  ) external override onlyMarket returns (uint256 _baseOut) {\n    FxLowVolatilityMath.SwapState memory _state;\n\n    if (_fTokenIn > 0) {\n      _state = _loadSwapState();\n    } else {\n      _state = _loadSwapState();\n    }\n    _updateEMALeverageRatio(_state);\n\n    if (_state.xNav == 0) {\n      require(_xTokenIn == 0, \"system under collateral\");\n      // only redeem fToken proportionally when under collateral.\n      _baseOut = (_fTokenIn.mul(_state.baseSupply)).div(_state.fSupply);\n    } else {\n      _baseOut = _state.redeem(_fTokenIn, _xTokenIn);\n    }\n\n    if (_fTokenIn > 0) {\n      IFxFractionalToken(fToken).burn(_owner, _fTokenIn);\n    }\n\n    if (_xTokenIn > 0) {\n      IFxLeveragedToken(xToken).burn(_owner, _xTokenIn);\n    }\n\n    totalBaseToken = _state.baseSupply.sub(_baseOut);\n\n    _transferBaseToken(_baseOut, msg.sender);\n  }\n\n  /// @inheritdoc IFxTreasury\n  function addBaseToken(\n    uint256 _baseIn,\n    uint256 _incentiveRatio,\n    address _recipient\n  ) external override onlyMarket returns (uint256 _xTokenOut) {\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    require(_state.xNav > 0, \"system under collateral\");\n    _updateEMALeverageRatio(_state);\n\n    uint256 _fDeltaNav;\n    (_xTokenOut, _fDeltaNav) = _state.mintXToken(_baseIn, _incentiveRatio);\n\n    require(_state.baseSupply + _baseIn <= baseTokenCap, \"Exceed total cap\");\n    totalBaseToken = _state.baseSupply + _baseIn;\n\n    IFxFractionalToken(fToken).setNav(\n      _state.fNav.sub(_fDeltaNav).mul(PRECISION).div(uint256(PRECISION_I256.add(_state.fMultiple)))\n    );\n\n    if (_xTokenOut > 0) {\n      IFxLeveragedToken(xToken).mint(_recipient, _xTokenOut);\n    }\n  }\n\n  /// @inheritdoc IFxTreasury\n  /// @param _baseIn The amount of base token to donate.\n  function donateBaseToken(uint256 _baseIn) external override onlyMarket {\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    _updateEMALeverageRatio(_state);\n\n    // In case of under-collateral, we don't need to check the cap.\n    require(_state.baseSupply + _baseIn <= baseTokenCap || _state.xNav == 0, \"Exceed total cap\");\n    totalBaseToken = _state.baseSupply + _baseIn;\n  }\n\n  /// @inheritdoc IFxTreasury\n  function liquidate(\n    uint256 _fTokenIn,\n    uint256 _incentiveRatio,\n    address _owner\n  ) external override onlyMarket returns (uint256 _baseOut) {\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    require(_state.xNav > 0, \"system under collateral\");\n    _updateEMALeverageRatio(_state);\n\n    uint256 _fDeltaNav;\n    (_baseOut, _fDeltaNav) = _state.liquidateWithIncentive(_fTokenIn, _incentiveRatio);\n\n    totalBaseToken = _state.baseSupply.sub(_baseOut);\n\n    address _fToken = fToken;\n    IFxFractionalToken(_fToken).burn(_owner, _fTokenIn);\n    IFxFractionalToken(_fToken).setNav(\n      _state.fNav.sub(_fDeltaNav).mul(PRECISION).div(uint256(PRECISION_I256.add(_state.fMultiple)))\n    );\n\n    if (_baseOut > 0) {\n      _transferBaseToken(_baseOut, msg.sender);\n    }\n  }\n\n  /// @inheritdoc IFxTreasury\n  function protocolSettle() external override {\n    require(settleWhitelist[msg.sender], \"only settle whitelist\");\n    if (totalBaseToken == 0) return;\n\n    uint256 _newPrice = _fetchRWAOraclePrice();\n    int256 _fMultiple = _computeMultiple(_newPrice);\n    uint256 _fNav = IFxFractionalToken(fToken).updateNav(_fMultiple);\n\n    emit ProtocolSettle(_newPrice, _fNav);\n\n    lastPermissionedPrice = _newPrice;\n\n    // update leverage ratio at the end\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    _updateEMALeverageRatio(_state);\n  }\n\n  /// @inheritdoc IFxTreasury\n  function transferToStrategy(uint256 _amount) external override onlyStrategy {\n    IERC20Upgradeable(baseToken).safeTransfer(strategy, _amount);\n    strategyUnderlying += _amount;\n  }\n\n  /// @inheritdoc IFxTreasury\n  /// @dev For future use.\n  function notifyStrategyProfit(uint256 _amount) external override onlyStrategy {}\n\n  /*******************************\n   * Public Restricted Functions *\n   *******************************/\n\n  function initializePrice() external onlyOwner {\n    require(lastPermissionedPrice == 0, \"only initialize price once\");\n    uint256 _price = _fetchRWAOraclePrice();\n\n    lastPermissionedPrice = _price;\n\n    IFxFractionalToken(fToken).setNav(PRECISION);\n\n    emit ProtocolSettle(_price, PRECISION);\n  }\n\n  /// @notice Change address of strategy contract.\n  /// @param _strategy The new address of strategy contract.\n  function updateStrategy(address _strategy) external onlyOwner {\n    strategy = _strategy;\n\n    emit UpdateStrategy(_strategy);\n  }\n\n  /// @notice Change the value of fToken beta.\n  /// @param _beta The new value of beta.\n  function updateBeta(uint256 _beta) external onlyOwner {\n    beta = _beta;\n\n    emit UpdateBeta(_beta);\n  }\n\n  /// @notice Change address of price oracle contract.\n  /// @param _priceOracle The new address of price oracle contract.\n  /// @param _priceOracleDecimals The decimals of the price oracle.\n  function updatePriceOracle(address _priceOracle, uint256 _priceOracleDecimals) external onlyOwner {\n    priceOracle = _priceOracle;\n    priceOracleDecimals = _priceOracleDecimals;\n\n    emit UpdatePriceOracle(_priceOracle, _priceOracleDecimals);\n  }\n\n  /// @notice Change address of rate provider contract.\n  /// @param _rateProvider The new address of rate provider contract.\n  function updateRateProvider(address _rateProvider) external onlyOwner {\n    rateProvider = _rateProvider;\n\n    emit UpdateRateProvider(_rateProvider);\n  }\n\n  /// @notice Update the whitelist status for settle account.\n  /// @param _account The address of account to update.\n  /// @param _status The status of the account to update.\n  function updateSettleWhitelist(address _account, bool _status) external onlyOwner {\n    settleWhitelist[_account] = _status;\n\n    emit UpdateSettleWhitelist(_account, _status);\n  }\n\n  /// @notice Update the base token cap.\n  /// @param _baseTokenCap The new base token cap.\n  function updateBaseTokenCap(uint256 _baseTokenCap) external onlyOwner {\n    baseTokenCap = _baseTokenCap;\n\n    emit UpdateBaseTokenCap(_baseTokenCap);\n  }\n\n  /// @notice Update the EMA sample interval.\n  /// @param _sampleInterval The new EMA sample interval.\n  function updateEMASampleInterval(uint24 _sampleInterval) external onlyOwner {\n    require(_sampleInterval >= 1 minutes, \"EMA sample interval too small\");\n\n    FxLowVolatilityMath.SwapState memory _state = _loadSwapState();\n    _updateEMALeverageRatio(_state);\n\n    emaLeverageRatio.sampleInterval = _sampleInterval;\n  }\n\n  /**********************\n   * Internal Functions *\n   **********************/\n\n  /// @dev Internal function to transfer base token to receiver.\n  /// @param _amount The amount of base token to transfer.\n  /// @param _recipient The address of receiver.\n  function _transferBaseToken(uint256 _amount, address _recipient) internal returns (uint256) {\n    _amount = convertToWrapped(_amount);\n\n    address _baseToken = baseToken;\n    uint256 _balance = IERC20Upgradeable(_baseToken).balanceOf(address(this));\n    if (_balance < _amount) {\n      uint256 _diff = _amount - _balance;\n      IAssetStrategy(strategy).withdrawToTreasury(_diff);\n      strategyUnderlying = strategyUnderlying.sub(_diff);\n\n      // consider possible slippage here.\n      _balance = IERC20Upgradeable(_baseToken).balanceOf(address(this));\n      if (_amount > _balance) {\n        _amount = _balance;\n      }\n    }\n\n    IERC20Upgradeable(_baseToken).safeTransfer(_recipient, _amount);\n\n    return _amount;\n  }\n\n  /// @dev Internal function to load swap variable to memory\n  function _loadSwapState() internal view returns (FxLowVolatilityMath.SwapState memory _state) {\n    _state.baseSupply = totalBaseToken;\n    _state.baseNav = _fetchRWAOraclePrice();\n\n    if (_state.baseSupply == 0) {\n      _state.fNav = PRECISION;\n      // Case: all base and fToken redeemed, keep invariant functional since xToken supply > 0\n      if (IERC20Upgradeable(xToken).totalSupply() > 0) {\n        _state.xNav = 0;\n      } else {\n        _state.xNav = PRECISION;\n      }\n    } else {\n      _state.fMultiple = _computeMultiple(_state.baseNav);\n      address _fToken = fToken;\n      _state.fSupply = IERC20Upgradeable(_fToken).totalSupply();\n      _state.fNav = IFxFractionalToken(_fToken).getNav(_state.fMultiple);\n\n      _state.xSupply = IERC20Upgradeable(xToken).totalSupply();\n      if (_state.xSupply == 0) {\n        // no xToken, treat the nav of xToken as 1.0\n        _state.xNav = PRECISION;\n      } else {\n        uint256 _fVal = _state.fSupply.mul(_state.fNav);\n        uint256 _baseVal = _state.baseSupply.mul(_state.baseNav);\n        if (_baseVal >= _fVal) {\n          _state.xNav = (_baseVal - _fVal).div(_state.xSupply);\n        } else {\n          // under collateral\n          _state.xNav = 0;\n        }\n      }\n    }\n  }\n\n  /// @dev Internal function to update ema leverage ratio.\n  function _updateEMALeverageRatio(FxLowVolatilityMath.SwapState memory _state) internal {\n    ExponentialMovingAverageV7.EMAStorage memory cachedEmaLeverageRatio = emaLeverageRatio;\n    int256 _lastPermissionedPrice = int256(lastPermissionedPrice);\n    int256 _earningRatio = int256(_state.baseNav).sub(_lastPermissionedPrice).mul(PRECISION_I256).div(\n      _lastPermissionedPrice\n    );\n    uint256 _ratio = _state.leverageRatio(beta, _earningRatio);\n\n    // The value is capped with 100*10^18, it is safe to cast.\n    cachedEmaLeverageRatio.saveValue(uint96(_ratio));\n\n    emaLeverageRatio = cachedEmaLeverageRatio;\n  }\n\n  /// @dev Internal function to compute latest nav multiple based on current price.\n  ///\n  /// Below are some important formula to do the update.\n  ///                newPrice\n  /// ratio = --------------------- - 1\n  ///         lastPermissionedPrice\n  ///\n  /// lastIntermediateFTokenNav = (1 + beta * ratio) * lastFTokenNav\n  ///\n  /// @param _newPrice The current price of base token.\n  /// @return _fMultiple The multiple for fToken.\n  function _computeMultiple(uint256 _newPrice) internal view returns (int256 _fMultiple) {\n    int256 _lastPermissionedPrice = int256(lastPermissionedPrice);\n\n    int256 _ratio = int256(_newPrice).sub(_lastPermissionedPrice).mul(PRECISION_I256).div(_lastPermissionedPrice);\n\n    _fMultiple = _ratio.mul(int256(beta)).div(PRECISION_I256);\n  }\n\n  /// @dev Internal function to fetch current price from RWA Oracle.\n  /// @return _price The twap price of the base token.\n  function _fetchRWAOraclePrice() internal view returns (uint256 _price) {\n    (bool isValid, uint256 sharePrice) = IRWAVaultPriceOracle(priceOracle).getSharePrice();\n    require(isValid, \"invalid price\");\n\n    _price = sharePrice;\n    if (priceOracleDecimals < 18) {\n      _price = _price * (10 ** (18 - priceOracleDecimals));\n    } else if (priceOracleDecimals > 18) {\n      _price = _price / (10 ** (priceOracleDecimals - 18));\n    }\n  }\n}\n","deployed_bytecode":"0x608060405234801561001057600080fd5b50600436106102f15760003560e01c80638da5cb5b1161019d578063c55dae63116100e9578063e9dae0da116100a2578063f2fde38b1161007c578063f2fde38b146105f6578063f354a33914610609578063fd98ff821461061c578063ffcf925e14610624576102f1565b8063e9dae0da146105bd578063e9ea2b25146105d0578063ed0aa428146105e3576102f1565b8063c55dae6314610561578063c6613ae114610569578063c780b4431461057c578063c8ebef2d14610584578063d2056f3e14610597578063daccaf63146105aa576102f1565b8063a8c62e7611610156578063ada5f48411610130578063ada5f4841461052b578063b1b8cd3314610533578063b4eae1cb14610546578063c061ddc71461054e576102f1565b8063a8c62e76146104fd578063ab0bd2e414610505578063ac7dabbc14610518576102f1565b80638da5cb5b146104c2578063947bc1cd146104ca578063949db658146104dd5780639ce4520d146104e55780639faa3c91146104ed578063a8694e57146104f5576102f1565b8063496c62e71161025c578063715018a61161021557806380b54add116101ef57806380b54add1461048c57806380f55605146104945780638740025c1461049c578063876d20de146104af576102f1565b8063715018a61461045a578063770100b914610462578063798fdd2c14610475576102f1565b8063496c62e7146103e657806349d5c1c3146103f9578063553ccf481461040157806357558b4d146104145780635c4bceb01461042757806366498a1014610447576102f1565b80632630c12f116102ae5780632630c12f14610385578063287583f11461038d57806329174f5c146103a05780633afc7282146103b357806344d90cf9146103cb57806348c2d01d146103d3576102f1565b806301c5a46c146102f657806302a5a77314610320578063049104e514610335578063082ad6ac14610355578063088b699e1461035d57806309c431b714610372575b600080fd5b610309610304366004614134565b61062c565b604051610317929190614449565b60405180910390f35b61033361032e366004614134565b610680565b005b6103486103433660046141e9565b6106ad565b6040516103179190614270565b61034861085c565b6103656108bd565b604051610317919061421d565b610348610380366004614134565b6108cc565b610365610975565b61034861039b366004614134565b610984565b6103336103ae366004614134565b610a1f565b6103bb610a71565b604051610317949392919061446d565b610348610aa7565b6103096103e13660046141c8565b610aad565b6103336103f4366004613fd9565b610afa565b610348610bb2565b61033361040f366004614085565b610bb8565b6103486104223660046141e9565b610c7c565b61043a610435366004613fd9565b610e40565b6040516103179190614265565b610309610455366004614134565b610e55565b610333610e95565b6103096104703660046141c8565b610f41565b61047d610f82565b60405161031793929190614457565b610333610fac565b6103656110e2565b6103336104aa366004613ff3565b6110f1565b6103336104bd366004614134565b611229565b6103656112c0565b6103336104d83660046140bb565b6112cf565b610365611383565b610348611392565b610348611398565b61036561139e565b6103656113ad565b610348610513366004614134565b6113bc565b610333610526366004614134565b611471565b610348611508565b610333610541366004614111565b61150e565b6103486115d2565b61030961055c366004614186565b6116f8565b61036561198a565b610348610577366004614164565b611999565b610348611aa4565b610348610592366004614134565b611aaa565b6103096105a5366004614134565b611af0565b6103336105b8366004613fd9565b611b30565b6103336105cb366004614111565b611bdd565b6103096105de366004614134565b611cd7565b6103336105f1366004614134565b611d17565b610333610604366004613fd9565b611d8f565b6103486106173660046141e9565b611e92565b610333612040565b610348612175565b600080670de0b6b3a7640000831161065f5760405162461bcd60e51b8152600401610656906142e7565b60405180910390fd5b600061066961217f565b9050610675818561246f565b909590945092505050565b606f546001600160a01b031633146106aa5760405162461bcd60e51b8152600401610656906143a6565b50565b6065546000906001600160a01b031633146106da5760405162461bcd60e51b815260040161065690614424565b6106e2613f85565b84156106f7576106f061217f565b9050610702565b6106ff61217f565b90505b61070b81612529565b60c08101516107565783156107325760405162461bcd60e51b81526004016106569061436f565b6060810151815161074f919061074990889061266b565b906126cd565b9150610764565b610761818686612734565b91505b84156107cf57606754604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac9061079c908690899060040161424c565b600060405180830381600087803b1580156107b657600080fd5b505af11580156107ca573d6000803e3d6000fd5b505050505b831561083a57606854604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610807908690889060040161424c565b600060405180830381600087803b15801561082157600080fd5b505af1158015610835573d6000803e3d6000fd5b505050505b805161084690836127f5565b606e556108538233612852565b50509392505050565b6040805160808101825260735464ffffffffff8116825262ffffff600160281b82041660208301526001600160601b03600160401b8204811693830193909352600160a01b900490911660608201526000906108b790612a0b565b90505b90565b6068546001600160a01b031681565b6072546000906001600160a01b0316801561096b57610968670de0b6b3a7640000610749836001600160a01b031663679aefce6040518163ffffffff1660e01b815260040160206040518083038186803b15801561092957600080fd5b505afa15801561093d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610961919061414c565b869061266b565b92505b829150505b919050565b6069546001600160a01b031681565b6072546000906001600160a01b0316801561096b57610968816001600160a01b031663679aefce6040518163ffffffff1660e01b815260040160206040518083038186803b1580156109d557600080fd5b505afa1580156109e9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0d919061414c565b61074985670de0b6b3a764000061266b565b606f546001600160a01b03163314610a495760405162461bcd60e51b8152600401610656906143a6565b606f54606654610a66916001600160a01b03918216911683612ae1565b607080549091019055565b60735464ffffffffff81169062ffffff600160281b820416906001600160601b03600160401b8204811691600160a01b90041684565b606e5481565b600080670de0b6b3a76400008411610ad75760405162461bcd60e51b8152600401610656906142e7565b6000610ae161217f565b9050610aee818686612b38565b90969095509350505050565b610b02612c14565b6001600160a01b0316610b136112c0565b6001600160a01b031614610b5c576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b607280546001600160a01b0319166001600160a01b0383161790556040517fe10dfe31cbee4a78d87de12b91be301c8344366882ee5ec6ae987397e2d69f5f90610ba790839061421d565b60405180910390a150565b606c5481565b610bc0612c14565b6001600160a01b0316610bd16112c0565b6001600160a01b031614610c1a576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b6001600160a01b03821660009081526071602052604090819020805460ff1916831515179055517fb74d2e227191f46da87374acb1e5f6191da6798b3ef2680468bf0056b004110690610c709084908490614231565b60405180910390a15050565b6065546000906001600160a01b03163314610ca95760405162461bcd60e51b815260040161065690614424565b6000610cb361217f565b905060008160c0015111610cd95760405162461bcd60e51b81526004016106569061436f565b610ce281612529565b6000610cef828787612c18565b606d5484519295509092509087011115610d1b5760405162461bcd60e51b815260040161065690614345565b81518601606e5560675460408301516001600160a01b039091169063251d8ffb90610d7c90610d5390670de0b6b3a764000090612ca3565b610749670de0b6b3a7640000610d768789608001516127f590919063ffffffff16565b9061266b565b6040518263ffffffff1660e01b8152600401610d989190614270565b600060405180830381600087803b158015610db257600080fd5b505af1158015610dc6573d6000803e3d6000fd5b505050506000831115610853576068546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610e05908790879060040161424c565b600060405180830381600087803b158015610e1f57600080fd5b505af1158015610e33573d6000803e3d6000fd5b5050505050509392505050565b60716020526000908152604090205460ff1681565b600080670de0b6b3a76400008311610e7f5760405162461bcd60e51b8152600401610656906142e7565b6000610e8961217f565b90506106758185612d08565b610e9d612c14565b6001600160a01b0316610eae6112c0565b6001600160a01b031614610ef7576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380546001600160a01b0319169055565b600080670de0b6b3a76400008411610f6b5760405162461bcd60e51b8152600401610656906142e7565b6000610f7561217f565b9050610aee818686612db5565b600080600080610f9061217f565b6020810151608082015160c09092015190969195509350915050565b3360009081526071602052604090205460ff16610fdb5760405162461bcd60e51b8152600401610656906143cd565b606e54610fe7576110e0565b6000610ff1612e7b565b90506000610ffe82612f6b565b6067546040516304d3456360e21b81529192506000916001600160a01b039091169063134d158c90611034908590600401614270565b602060405180830381600087803b15801561104e57600080fd5b505af1158015611062573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611086919061414c565b90507f53b3cb2bbe2075ccf7ce39aa91abab01aac8b08fe9098bbea7f98ea80dae5b8183826040516110b9929190614449565b60405180910390a1606c83905560006110d061217f565b90506110db81612529565b505050505b565b6065546001600160a01b031681565b600054610100900460ff168061110a575061110a612faf565b80611118575060005460ff16155b6111535760405162461bcd60e51b815260040180806020018281038252602e8152602001806144f8602e913960400191505060405180910390fd5b600054610100900460ff1615801561117e576000805460ff1961ff0019909116610100171660011790555b611186612fc0565b606580546001600160a01b03199081166001600160a01b038d8116919091179092556066805482168c84161790556067805482168b84161790556068805482168a841617905560698054909116888316179055606a869055606b859055606d84905582161561120b57607280546001600160a01b0319166001600160a01b0384161790555b801561121d576000805461ff00191690555b50505050505050505050565b611231612c14565b6001600160a01b03166112426112c0565b6001600160a01b03161461128b576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b606d8190556040517f6feb1f001efc32a2021d7f13d152eec43f9e73784f2344dc67cad93c808550db90610ba7908390614270565b6033546001600160a01b031690565b6112d7612c14565b6001600160a01b03166112e86112c0565b6001600160a01b031614611331576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b606980546001600160a01b0319166001600160a01b038416179055606a8190556040517f826cba3adadd8c4068f2d800dddb0e8cc50ed413f90aced811e2e3ba08b2728c90610c70908490849061424c565b6072546001600160a01b031681565b60705481565b606b5481565b6067546001600160a01b031681565b606f546001600160a01b031681565b6000806113c761217f565b60675460208201519192506000916001600160a01b039091169063d751cf9d906113f090612f6b565b6040518263ffffffff1660e01b815260040161140c9190614270565b60206040518083038186803b15801561142457600080fd5b505afa158015611438573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145c919061414c565b9050611469828286613071565b949350505050565b611479612c14565b6001600160a01b031661148a6112c0565b6001600160a01b0316146114d3576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b606b8190556040517fb012dff4b8767663dda829cad57391a882ca901ea4cc4e56e7b23adb442ee95f90610ba7908390614270565b606a5481565b611516612c14565b6001600160a01b03166115276112c0565b6001600160a01b031614611570576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b603c8162ffffff1610156115965760405162461bcd60e51b8152600401610656906142b0565b60006115a061217f565b90506115ab81612529565b506073805462ffffff909216600160281b0267ffffff000000000019909216919091179055565b6000806115dd61217f565b80519091506115f757670de0b6b3a76400009150506108ba565b60006116068260200151612f6b565b60675460405163d751cf9d60e01b81529192506000916001600160a01b039091169063d751cf9d9061163c908590600401614270565b60206040518083038186803b15801561165457600080fd5b505afa158015611668573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168c919061414c565b905082606001516000148061169f575080155b156116bf57506ec097ce7bc90715b34b9f100000000092506108ba915050565b60608301516116f0906116d2908361266b565b6020850151855161074991670de0b6b3a764000091610d769161266b565b935050505090565b60655460009081906001600160a01b031633146117275760405162461bcd60e51b815260040161065690614424565b61172f613f85565b600184600281111561173d57fe5b141561175b5761174b61217f565b905061175681612529565b611782565b600284600281111561176957fe5b14156117775761174b61217f565b61177f61217f565b90505b60008160c00151116117a65760405162461bcd60e51b81526004016106569061436f565b60018460028111156117b457fe5b14156117cb576117c481876130f5565b925061187f565b60028460028111156117d957fe5b14156117f0576117e98187613116565b915061187f565b805161186f57600061180f82602001518861266b90919063ffffffff16565b9050611849670de0b6b3a76400006107498181857f0000000000000000000000000000000000000000000000000c7d713b49da000061266b565b93506118678461186183670de0b6b3a76400006126cd565b906127f5565b92505061187f565b611879818761316a565b90935091505b606d548151870111156118a45760405162461bcd60e51b815260040161065690614345565b80518601606e558215611916576067546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906118e3908890879060040161424c565b600060405180830381600087803b1580156118fd57600080fd5b505af1158015611911573d6000803e3d6000fd5b505050505b8115611981576068546040516340c10f1960e01b81526001600160a01b03909116906340c10f199061194e908890869060040161424c565b600060405180830381600087803b15801561196857600080fd5b505af115801561197c573d6000803e3d6000fd5b505050505b50935093915050565b6066546001600160a01b031681565b6065546000906001600160a01b031633146119c65760405162461bcd60e51b815260040161065690614424565b670de0b6b3a764000083116119ed5760405162461bcd60e51b8152600401610656906142e7565b60006119f761217f565b905060008160c0015111611a1d5760405162461bcd60e51b81526004016106569061436f565b611a2681612529565b611a3081856131ad565b91508115611a9d576067546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611a6a908690869060040161424c565b600060405180830381600087803b158015611a8457600080fd5b505af1158015611a98573d6000803e3d6000fd5b505050505b5092915050565b606d5481565b6000670de0b6b3a76400008211611ad35760405162461bcd60e51b8152600401610656906142e7565b6000611add61217f565b9050611ae981846131ad565b9392505050565b600080670de0b6b3a76400008311611b1a5760405162461bcd60e51b8152600401610656906142e7565b6000611b2461217f565b90506106758185613251565b611b38612c14565b6001600160a01b0316611b496112c0565b6001600160a01b031614611b92576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b606f80546001600160a01b0319166001600160a01b0383161790556040517f351ac3b801ef52eee542597618621efdaafc5a2e9469f78505486074ea9b927190610ba790839061421d565b6040805160808101825260735464ffffffffff811680835262ffffff600160281b83041660208401526001600160601b03600160401b8304811694840194909452600160a01b90910490921660608201529015611c4c5760405162461bcd60e51b8152600401610656906143fc565b4264ffffffffff1680825262ffffff9290921660208201819052670de0b6b3a7640000604083018190526060909201919091526073805464ffffffffff191690921767ffffff00000000001916600160281b909102176bffffffffffffffffffffffff60401b19166503782dace9d960521b176001600160a01b03166503782dace9d960b21b179055565b600080670de0b6b3a76400008311611d015760405162461bcd60e51b8152600401610656906142e7565b6000611d0b61217f565b905061067581856132ed565b6065546001600160a01b03163314611d415760405162461bcd60e51b815260040161065690614424565b6000611d4b61217f565b9050611d5681612529565b606d5481518301111580611d6c575060c0810151155b611d885760405162461bcd60e51b815260040161065690614345565b5101606e55565b611d97612c14565b6001600160a01b0316611da86112c0565b6001600160a01b031614611df1576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b6001600160a01b038116611e365760405162461bcd60e51b81526004018080602001828103825260268152602001806144b16026913960400191505060405180910390fd5b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380546001600160a01b0319166001600160a01b0392909216919091179055565b6065546000906001600160a01b03163314611ebf5760405162461bcd60e51b815260040161065690614424565b6000611ec961217f565b905060008160c0015111611eef5760405162461bcd60e51b81526004016106569061436f565b611ef881612529565b6000611f05828787613389565b83519194509150611f1690846127f5565b606e55606754604051632770a7eb60e21b81526001600160a01b03909116908190639dc29fac90611f4d9088908b9060040161424c565b600060405180830381600087803b158015611f6757600080fd5b505af1158015611f7b573d6000803e3d6000fd5b50505050806001600160a01b031663251d8ffb611fd3611fb08660400151670de0b6b3a7640000612ca390919063ffffffff16565b610749670de0b6b3a7640000610d76888a608001516127f590919063ffffffff16565b6040518263ffffffff1660e01b8152600401611fef9190614270565b600060405180830381600087803b15801561200957600080fd5b505af115801561201d573d6000803e3d6000fd5b505050506000841115612036576120348433612852565b505b5050509392505050565b612048612c14565b6001600160a01b03166120596112c0565b6001600160a01b0316146120a2576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b606c54156120c25760405162461bcd60e51b815260040161065690614279565b60006120cc612e7b565b606c81905560675460405163251d8ffb60e01b81529192506001600160a01b03169063251d8ffb9061210a90670de0b6b3a764000090600401614270565b600060405180830381600087803b15801561212457600080fd5b505af1158015612138573d6000803e3d6000fd5b505050507f53b3cb2bbe2075ccf7ce39aa91abab01aac8b08fe9098bbea7f98ea80dae5b8181670de0b6b3a7640000604051610ba7929190614449565b60006108b7612e7b565b612187613f85565b606e548152612194612e7b565b6020820152805161225057670de0b6b3a76400006080820152606854604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b1580156121f257600080fd5b505afa158015612206573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061222a919061414c565b111561223c57600060c082015261224b565b670de0b6b3a764000060c08201525b6108ba565b61225d8160200151612f6b565b60408083019190915260675481516318160ddd60e01b815291516001600160a01b039091169182916318160ddd91600480820192602092909190829003018186803b1580156122ab57600080fd5b505afa1580156122bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e3919061414c565b6060830152604080830151905163479944cd60e11b81526001600160a01b03831691638f32899a916123189190600401614270565b60206040518083038186803b15801561233057600080fd5b505afa158015612344573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612368919061414c565b6080830152606854604080516318160ddd60e01b815290516001600160a01b03909216916318160ddd91600480820192602092909190829003018186803b1580156123b257600080fd5b505afa1580156123c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ea919061414c565b60a0830181905261240857670de0b6b3a764000060c083015261246b565b60006124258360800151846060015161266b90919063ffffffff16565b6020840151845191925060009161243b9161266b565b90508181106124605760a084015161245690838303906126cd565b60c0850152612468565b600060c08501525b50505b5090565b600080600061249b670de0b6b3a7640000610d768760200151886000015161266b90919063ffffffff16565b905060006124be8660800151610d7688606001518861266b90919063ffffffff16565b905081811115612520578181036124dd86670de0b6b3a76400006127f5565b95506125006124f988608001518861266b90919063ffffffff16565b82906126cd565b935061251c6124f988602001518861266b90919063ffffffff16565b9450505b50509250929050565b6040805160808101825260735464ffffffffff8116825262ffffff600160281b8204166020808401919091526001600160601b03600160401b8304811694840194909452600160a01b9091049092166060820152606c54918301519091906000906125b49083906125ae90670de0b6b3a7640000906125a8908461340c565b90613471565b9061351a565b905060006125cf606b5483876135d29092919063ffffffff16565b90506125db84826136cf565b50508151607380546020850151604086015160609096015164ffffffffff1990921664ffffffffff9094169390931767ffffff00000000001916600160281b62ffffff90941693909302929092176bffffffffffffffffffffffff60401b1916600160401b6001600160601b0395861602176001600160a01b0316600160a01b9490921693909302179091555050565b60008261267a575060006126c7565b8282028284828161268757fe5b04146126c45760405162461bcd60e51b81526004018080602001828103825260218152602001806145476021913960400191505060405180910390fd5b90505b92915050565b6000808211612723576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161272c57fe5b049392505050565b6000806127656127558660800151876060015161266b90919063ffffffff16565b602087015187516118619161266b565b90508460a001516000141561279a57612793856020015161074987608001518761266b90919063ffffffff16565b91506127ed565b60808501516127aa90859061266b565b91506127d16127ca8660a00151610749848761266b90919063ffffffff16565b83906136fa565b91506127ea8560200151836126cd90919063ffffffff16565b91505b509392505050565b60008282111561284c576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600061285d83610984565b6066546040516370a0823160e01b81529194506001600160a01b03169060009082906370a082319061289390309060040161421d565b60206040518083038186803b1580156128ab57600080fd5b505afa1580156128bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e3919061414c565b9050848110156129ee57606f5460405163abae70c560e01b8152828703916001600160a01b03169063abae70c59061291f908490600401614270565b600060405180830381600087803b15801561293957600080fd5b505af115801561294d573d6000803e3d6000fd5b505060705461295f92509050826127f5565b6070556040516370a0823160e01b81526001600160a01b038416906370a082319061298e90309060040161421d565b60206040518083038186803b1580156129a657600080fd5b505afa1580156129ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129de919061414c565b9150818611156129ec578195505b505b612a026001600160a01b0383168587612ae1565b50929392505050565b600042826000015164ffffffffff161015612acd578151602083015164ffffffffff90911642039060009062ffffff16670de0b6b3a7640000830281612a4d57fe5b049050680238fd42c5cf040000811115612a775750505060408101516001600160601b0316610970565b6000612a8582600003613754565b9050670de0b6b3a76400008186606001516001600160601b03160282670de0b6b3a76400000387604001516001600160601b0316020181612ac257fe5b049350505050610970565b5060608101516001600160601b0316610970565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612b33908490613b6c565b505050565b6000806000612b64670de0b6b3a7640000610d768860000151896020015161266b90919063ffffffff16565b90506000612b878760800151610d7689606001518961266b90919063ffffffff16565b905081811115612c0a57818103612bbd6124f9670de0b6b3a7640000888a0260208c015191670de0b6b3a764000091040161266b565b9450612c06612be1670de0b6b3a76400008a60c0015161266b90919063ffffffff16565b61074988670de0b6b3a764000001610d768c602001518a61266b90919063ffffffff16565b9350505b5050935093915050565b3390565b6000806000612c3486602001518661266b90919063ffffffff16565b9050612c4e670de0b6b3a76400006107498387830161266b565b9250612c678660c00151846126cd90919063ffffffff16565b9250612c7f670de0b6b3a7640000610749838761266b565b9150612c988660600151836126cd90919063ffffffff16565b915050935093915050565b6000828201818312801590612cb85750838112155b80612ccd5750600083128015612ccd57508381125b6126c45760405162461bcd60e51b81526004018080602001828103825260218152602001806144d76021913960400191505060405180910390fd5b6000806000612d34670de0b6b3a7640000610d768760200151886000015161266b90919063ffffffff16565b90506000612d578660800151610d7688606001518861266b90919063ffffffff16565b90508082111561252057612d7385670de0b6b3a76400006127f5565b602087015190955081830390612d8d906124f9908861266b565b9450612da96124f987896080015161266b90919063ffffffff16565b93505050509250929050565b6000806000612dd98660800151610d7688606001518861266b90919063ffffffff16565b90506000612e04670de0b6b3a7640000610d7689602001518a6000015161266b90919063ffffffff16565b905080821115612c0a57808203612e2387670de0b6b3a76400006127f5565b9650612e3f6124f9888a6020015161266b90919063ffffffff16565b9450612c06612e65896080015188670de0b6b3a76400000161266b90919063ffffffff16565b610749670de0b6b3a7640000610d76858c6126cd565b6000806000606960009054906101000a90046001600160a01b03166001600160a01b0316635b1dac606040518163ffffffff1660e01b8152600401604080518083038186803b158015612ecd57600080fd5b505afa158015612ee1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0591906140e4565b9150915081612f265760405162461bcd60e51b81526004016106569061431e565b8092506012606a541015612f4657606a54601203600a0a83029250612f66565b6012606a541115612f66576012606a5403600a0a8381612f6257fe5b0492505b505090565b606c5460009081612f8c826125ae670de0b6b3a76400006125a8888461340c565b9050611469670de0b6b3a76400006125ae606b548461347190919063ffffffff16565b6000612fba30613c1d565b15905090565b600054610100900460ff1680612fd95750612fd9612faf565b80612fe7575060005460ff16155b6130225760405162461bcd60e51b815260040180806020018281038252602e8152602001806144f8602e913960400191505060405180910390fd5b600054610100900460ff1615801561304d576000805460ff1961ff0019909116610100171660011790555b613055613c23565b61305d613cc3565b80156106aa576000805461ff001916905550565b60008061308f84610d7687606001518661266b90919063ffffffff16565b905060006130b2670de0b6b3a7640000876020015161266b90919063ffffffff16565b90506130c781610749600161186186846136fa565b86519093508310156130de57600092505050611ae9565b85516130eb9084906127f5565b9695505050505050565b6000611ae9836080015161074985602001518561266b90919063ffffffff16565b60006131378360a00151610d7685602001518561266b90919063ffffffff16565b9050611ae96124f961315a8560800151866060015161266b90919063ffffffff16565b602086015186516118619161266b565b60008061318c846000015161074985876060015161266b90919063ffffffff16565b845160a08601519193506131a491610749908661266b565b90509250929050565b6000806131d7670de0b6b3a7640000610d768660200151876000015161266b90919063ffffffff16565b905060006131fa8560800151610d7687606001518761266b90919063ffffffff16565b905080821161320e576000925050506126c7565b61322f61322886608001518661266b90919063ffffffff16565b83906126cd565b92506132488560600151846127f590919063ffffffff16565b95945050505050565b600080600061327d670de0b6b3a7640000610d768760200151886000015161266b90919063ffffffff16565b905060006132a08660800151610d7688606001518861266b90919063ffffffff16565b9050808211156125205760c0860151818303906132c9906124f990670de0b6b3a764000061266b565b935061251c6124f9670de0b6b3a7640000896020015161266b90919063ffffffff16565b6000806000613319670de0b6b3a7640000610d768760000151886020015161266b90919063ffffffff16565b9050600061333c8660800151610d7688606001518861266b90919063ffffffff16565b90508181111561252057602086015182820390613365906124f990670de0b6b3a764000061266b565b9450612da96124f9670de0b6b3a76400008960c0015161266b90919063ffffffff16565b60008060006133a586608001518661266b90919063ffffffff16565b90506133bf670de0b6b3a76400006107498387830161266b565b92506133d88660200151846126cd90919063ffffffff16565b92506133f0670de0b6b3a7640000610749838761266b565b9150612c986132288688606001516127f590919063ffffffff16565b60008183038183128015906134215750838113155b80613436575060008312801561343657508381135b6126c45760405162461bcd60e51b81526004018080602001828103825260248152602001806145af6024913960400191505060405180910390fd5b600082613480575060006126c7565b826000191480156134945750600160ff1b82145b156134d05760405162461bcd60e51b81526004018080602001828103825260278152602001806145886027913960400191505060405180910390fd5b828202828482816134dd57fe5b05146126c45760405162461bcd60e51b81526004018080602001828103825260278152602001806145886027913960400191505060405180910390fd5b60008161356e576040805162461bcd60e51b815260206004820181905260248201527f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f604482015290519081900360640190fd5b816000191480156135825750600160ff1b83145b156135be5760405162461bcd60e51b81526004018080602001828103825260218152602001806145266021913960400191505060405180910390fd5b60008284816135c957fe5b05949350505050565b602083015183516000916135e6919061266b565b6135fa575068056bc75e2d63100000611ae9565b60208401518451600091613638916136119161266b565b610749670de0b6b3a7640000610d7689608001518a6060015161266b90919063ffffffff16565b9050670de0b6b3a7640000811061365b5768056bc75e2d63100000915050611ae9565b60006136886ec097ce7bc90715b34b9f1000000000610749670de0b6b3a76400008701610d76868a61266b565b90506136a8670de0b6b3a76400008381039061074990610d7681866127f5565b925068056bc75e2d63100000831115610853575068056bc75e2d6310000095945050505050565b6136d882612a0b565b6001600160601b03908116606084015216604082015264ffffffffff42169052565b6000828201838110156126c4576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000680238fd42c5cf03ffff198212158015613779575068070c1cc73b00c800008213155b6137bd576040805162461bcd60e51b815260206004820152601060248201526f1253959053125117d1561413d391539560821b604482015290519081900360640190fd5b60008212156137f1576137d282600003613754565b6ec097ce7bc90715b34b9f1000000000816137e957fe5b059050610970565b60006806f05b59d3b2000000831261383157506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec630262827000000000613867565b6803782dace9d9000000831261386357506803782dace9d8ffffff19909101906b1425982cf597cd205cef7380613867565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac6200000084126138b75768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d63100000084126138f3576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b18800000841261392d57682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c4000008412613967576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac620000084126139a057680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d6310000084126139d95768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412613a12576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c400008412613a4b5768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b6000613bc1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613dbc9092919063ffffffff16565b805190915015612b3357808060200190516020811015613be057600080fd5b5051612b335760405162461bcd60e51b815260040180806020018281038252602a8152602001806145d3602a913960400191505060405180910390fd5b3b151590565b600054610100900460ff1680613c3c5750613c3c612faf565b80613c4a575060005460ff16155b613c855760405162461bcd60e51b815260040180806020018281038252602e8152602001806144f8602e913960400191505060405180910390fd5b600054610100900460ff1615801561305d576000805460ff1961ff00199091166101001716600117905580156106aa576000805461ff001916905550565b600054610100900460ff1680613cdc5750613cdc612faf565b80613cea575060005460ff16155b613d255760405162461bcd60e51b815260040180806020018281038252602e8152602001806144f8602e913960400191505060405180910390fd5b600054610100900460ff16158015613d50576000805460ff1961ff0019909116610100171660011790555b6000613d5a612c14565b603380546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35080156106aa576000805461ff001916905550565b6060611469848460008585613dd085613c1d565b613e21576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310613e5f5780518252601f199092019160209182019101613e40565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613ec1576040519150601f19603f3d011682016040523d82523d6000602084013e613ec6565b606091505b5091509150613ed6828286613ee1565b979650505050505050565b60608315613ef0575081611ae9565b825115613f005782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613f4a578181015183820152602001613f32565b50505050905090810190601f168015613f775780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b80356001600160a01b038116811461097057600080fd5b600060208284031215613fea578081fd5b611ae982613fc2565b60008060008060008060008060006101208a8c031215614011578485fd5b61401a8a613fc2565b985061402860208b01613fc2565b975061403660408b01613fc2565b965061404460608b01613fc2565b955061405260808b01613fc2565b945060a08a0135935060c08a0135925060e08a013591506140766101008b01613fc2565b90509295985092959850929598565b60008060408385031215614097578182fd5b6140a083613fc2565b915060208301356140b0816144a2565b809150509250929050565b600080604083850312156140cd578182fd5b6140d683613fc2565b946020939093013593505050565b600080604083850312156140f6578182fd5b8251614101816144a2565b6020939093015192949293505050565b600060208284031215614122578081fd5b813562ffffff811681146126c4578182fd5b600060208284031215614145578081fd5b5035919050565b60006020828403121561415d578081fd5b5051919050565b60008060408385031215614176578182fd5b823591506131a460208401613fc2565b60008060006060848603121561419a578283fd5b833592506141aa60208501613fc2565b91506040840135600381106141bd578182fd5b809150509250925092565b600080604083850312156141da578182fd5b50508035926020909101359150565b6000806000606084860312156141fd578283fd5b833592506020840135915061421460408501613fc2565b90509250925092565b6001600160a01b0391909116815260200190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b6020808252601a908201527f6f6e6c7920696e697469616c697a65207072696365206f6e6365000000000000604082015260600190565b6020808252601d908201527f454d412073616d706c6520696e74657276616c20746f6f20736d616c6c000000604082015260600190565b6020808252601a908201527f636f6c6c61746572616c20726174696f20746f6f20736d616c6c000000000000604082015260600190565b6020808252600d908201526c696e76616c696420707269636560981b604082015260600190565b60208082526010908201526f045786365656420746f74616c206361760841b604082015260600190565b60208082526017908201527f73797374656d20756e64657220636f6c6c61746572616c000000000000000000604082015260600190565b6020808252600d908201526c4f6e6c7920737472617465677960981b604082015260600190565b6020808252601590820152741bdb9b1e481cd95d1d1b19481dda1a5d195b1a5cdd605a1b604082015260600190565b6020808252600e908201526d1d8c881a5b9a5d1a585b1a5e995960921b604082015260600190565b6020808252600b908201526a13db9b1e481b585c9ad95d60aa1b604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b64ffffffffff94909416845262ffffff9290921660208401526001600160601b03908116604084015216606082015260800190565b80151581146106aa57600080fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573735369676e6564536166654d6174683a206164646974696f6e206f766572666c6f77496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a65645369676e6564536166654d6174683a206469766973696f6e206f766572666c6f77536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725369676e6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a26469706673582212202f9a63ba380aa39620e5c9e1eae84995a463aa851c2a452315487c271124eb7364736f6c63430007060033","optimization_enabled":true,"verified_twin_address_hash":null,"is_verified":true,"compiler_settings":{"evmVersion":"istanbul","libraries":{},"optimizer":{"enabled":true,"runs":200},"outputSelection":{"*":{"":["*"],"*":["*"]}}},"optimization_runs":200,"sourcify_repo_url":null,"decoded_constructor_args":[["900000000000000000",{"internalType":"uint256","name":"_initialMintRatio","type":"uint256"}]],"compiler_version":"v0.7.6+commit.7338295f","is_verified_via_verifier_alliance":false,"verified_at":"2026-04-08T11:42:33.664495Z","implementations":[],"proxy_type":null,"external_libraries":[],"creation_bytecode":"0x60a06040523480156200001157600080fd5b506040516200471a3803806200471a83398101604081905262000034916200007d565b8060001080156200004c5750670de0b6b3a764000081105b620000745760405162461bcd60e51b81526004016200006b9062000096565b60405180910390fd5b608052620000cd565b6000602082840312156200008f578081fd5b5051919050565b6020808252601a908201527f696e76616c696420696e697469616c206d696e7420726174696f000000000000604082015260600190565b608051614632620000e86000398061182552506146326000f3fe608060405234801561001057600080fd5b50600436106102f15760003560e01c80638da5cb5b1161019d578063c55dae63116100e9578063e9dae0da116100a2578063f2fde38b1161007c578063f2fde38b146105f6578063f354a33914610609578063fd98ff821461061c578063ffcf925e14610624576102f1565b8063e9dae0da146105bd578063e9ea2b25146105d0578063ed0aa428146105e3576102f1565b8063c55dae6314610561578063c6613ae114610569578063c780b4431461057c578063c8ebef2d14610584578063d2056f3e14610597578063daccaf63146105aa576102f1565b8063a8c62e7611610156578063ada5f48411610130578063ada5f4841461052b578063b1b8cd3314610533578063b4eae1cb14610546578063c061ddc71461054e576102f1565b8063a8c62e76146104fd578063ab0bd2e414610505578063ac7dabbc14610518576102f1565b80638da5cb5b146104c2578063947bc1cd146104ca578063949db658146104dd5780639ce4520d146104e55780639faa3c91146104ed578063a8694e57146104f5576102f1565b8063496c62e71161025c578063715018a61161021557806380b54add116101ef57806380b54add1461048c57806380f55605146104945780638740025c1461049c578063876d20de146104af576102f1565b8063715018a61461045a578063770100b914610462578063798fdd2c14610475576102f1565b8063496c62e7146103e657806349d5c1c3146103f9578063553ccf481461040157806357558b4d146104145780635c4bceb01461042757806366498a1014610447576102f1565b80632630c12f116102ae5780632630c12f14610385578063287583f11461038d57806329174f5c146103a05780633afc7282146103b357806344d90cf9146103cb57806348c2d01d146103d3576102f1565b806301c5a46c146102f657806302a5a77314610320578063049104e514610335578063082ad6ac14610355578063088b699e1461035d57806309c431b714610372575b600080fd5b610309610304366004614134565b61062c565b604051610317929190614449565b60405180910390f35b61033361032e366004614134565b610680565b005b6103486103433660046141e9565b6106ad565b6040516103179190614270565b61034861085c565b6103656108bd565b604051610317919061421d565b610348610380366004614134565b6108cc565b610365610975565b61034861039b366004614134565b610984565b6103336103ae366004614134565b610a1f565b6103bb610a71565b604051610317949392919061446d565b610348610aa7565b6103096103e13660046141c8565b610aad565b6103336103f4366004613fd9565b610afa565b610348610bb2565b61033361040f366004614085565b610bb8565b6103486104223660046141e9565b610c7c565b61043a610435366004613fd9565b610e40565b6040516103179190614265565b610309610455366004614134565b610e55565b610333610e95565b6103096104703660046141c8565b610f41565b61047d610f82565b60405161031793929190614457565b610333610fac565b6103656110e2565b6103336104aa366004613ff3565b6110f1565b6103336104bd366004614134565b611229565b6103656112c0565b6103336104d83660046140bb565b6112cf565b610365611383565b610348611392565b610348611398565b61036561139e565b6103656113ad565b610348610513366004614134565b6113bc565b610333610526366004614134565b611471565b610348611508565b610333610541366004614111565b61150e565b6103486115d2565b61030961055c366004614186565b6116f8565b61036561198a565b610348610577366004614164565b611999565b610348611aa4565b610348610592366004614134565b611aaa565b6103096105a5366004614134565b611af0565b6103336105b8366004613fd9565b611b30565b6103336105cb366004614111565b611bdd565b6103096105de366004614134565b611cd7565b6103336105f1366004614134565b611d17565b610333610604366004613fd9565b611d8f565b6103486106173660046141e9565b611e92565b610333612040565b610348612175565b600080670de0b6b3a7640000831161065f5760405162461bcd60e51b8152600401610656906142e7565b60405180910390fd5b600061066961217f565b9050610675818561246f565b909590945092505050565b606f546001600160a01b031633146106aa5760405162461bcd60e51b8152600401610656906143a6565b50565b6065546000906001600160a01b031633146106da5760405162461bcd60e51b815260040161065690614424565b6106e2613f85565b84156106f7576106f061217f565b9050610702565b6106ff61217f565b90505b61070b81612529565b60c08101516107565783156107325760405162461bcd60e51b81526004016106569061436f565b6060810151815161074f919061074990889061266b565b906126cd565b9150610764565b610761818686612734565b91505b84156107cf57606754604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac9061079c908690899060040161424c565b600060405180830381600087803b1580156107b657600080fd5b505af11580156107ca573d6000803e3d6000fd5b505050505b831561083a57606854604051632770a7eb60e21b81526001600160a01b0390911690639dc29fac90610807908690889060040161424c565b600060405180830381600087803b15801561082157600080fd5b505af1158015610835573d6000803e3d6000fd5b505050505b805161084690836127f5565b606e556108538233612852565b50509392505050565b6040805160808101825260735464ffffffffff8116825262ffffff600160281b82041660208301526001600160601b03600160401b8204811693830193909352600160a01b900490911660608201526000906108b790612a0b565b90505b90565b6068546001600160a01b031681565b6072546000906001600160a01b0316801561096b57610968670de0b6b3a7640000610749836001600160a01b031663679aefce6040518163ffffffff1660e01b815260040160206040518083038186803b15801561092957600080fd5b505afa15801561093d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610961919061414c565b869061266b565b92505b829150505b919050565b6069546001600160a01b031681565b6072546000906001600160a01b0316801561096b57610968816001600160a01b031663679aefce6040518163ffffffff1660e01b815260040160206040518083038186803b1580156109d557600080fd5b505afa1580156109e9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a0d919061414c565b61074985670de0b6b3a764000061266b565b606f546001600160a01b03163314610a495760405162461bcd60e51b8152600401610656906143a6565b606f54606654610a66916001600160a01b03918216911683612ae1565b607080549091019055565b60735464ffffffffff81169062ffffff600160281b820416906001600160601b03600160401b8204811691600160a01b90041684565b606e5481565b600080670de0b6b3a76400008411610ad75760405162461bcd60e51b8152600401610656906142e7565b6000610ae161217f565b9050610aee818686612b38565b90969095509350505050565b610b02612c14565b6001600160a01b0316610b136112c0565b6001600160a01b031614610b5c576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b607280546001600160a01b0319166001600160a01b0383161790556040517fe10dfe31cbee4a78d87de12b91be301c8344366882ee5ec6ae987397e2d69f5f90610ba790839061421d565b60405180910390a150565b606c5481565b610bc0612c14565b6001600160a01b0316610bd16112c0565b6001600160a01b031614610c1a576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b6001600160a01b03821660009081526071602052604090819020805460ff1916831515179055517fb74d2e227191f46da87374acb1e5f6191da6798b3ef2680468bf0056b004110690610c709084908490614231565b60405180910390a15050565b6065546000906001600160a01b03163314610ca95760405162461bcd60e51b815260040161065690614424565b6000610cb361217f565b905060008160c0015111610cd95760405162461bcd60e51b81526004016106569061436f565b610ce281612529565b6000610cef828787612c18565b606d5484519295509092509087011115610d1b5760405162461bcd60e51b815260040161065690614345565b81518601606e5560675460408301516001600160a01b039091169063251d8ffb90610d7c90610d5390670de0b6b3a764000090612ca3565b610749670de0b6b3a7640000610d768789608001516127f590919063ffffffff16565b9061266b565b6040518263ffffffff1660e01b8152600401610d989190614270565b600060405180830381600087803b158015610db257600080fd5b505af1158015610dc6573d6000803e3d6000fd5b505050506000831115610853576068546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990610e05908790879060040161424c565b600060405180830381600087803b158015610e1f57600080fd5b505af1158015610e33573d6000803e3d6000fd5b5050505050509392505050565b60716020526000908152604090205460ff1681565b600080670de0b6b3a76400008311610e7f5760405162461bcd60e51b8152600401610656906142e7565b6000610e8961217f565b90506106758185612d08565b610e9d612c14565b6001600160a01b0316610eae6112c0565b6001600160a01b031614610ef7576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b6033546040516000916001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3603380546001600160a01b0319169055565b600080670de0b6b3a76400008411610f6b5760405162461bcd60e51b8152600401610656906142e7565b6000610f7561217f565b9050610aee818686612db5565b600080600080610f9061217f565b6020810151608082015160c09092015190969195509350915050565b3360009081526071602052604090205460ff16610fdb5760405162461bcd60e51b8152600401610656906143cd565b606e54610fe7576110e0565b6000610ff1612e7b565b90506000610ffe82612f6b565b6067546040516304d3456360e21b81529192506000916001600160a01b039091169063134d158c90611034908590600401614270565b602060405180830381600087803b15801561104e57600080fd5b505af1158015611062573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611086919061414c565b90507f53b3cb2bbe2075ccf7ce39aa91abab01aac8b08fe9098bbea7f98ea80dae5b8183826040516110b9929190614449565b60405180910390a1606c83905560006110d061217f565b90506110db81612529565b505050505b565b6065546001600160a01b031681565b600054610100900460ff168061110a575061110a612faf565b80611118575060005460ff16155b6111535760405162461bcd60e51b815260040180806020018281038252602e8152602001806144f8602e913960400191505060405180910390fd5b600054610100900460ff1615801561117e576000805460ff1961ff0019909116610100171660011790555b611186612fc0565b606580546001600160a01b03199081166001600160a01b038d8116919091179092556066805482168c84161790556067805482168b84161790556068805482168a841617905560698054909116888316179055606a869055606b859055606d84905582161561120b57607280546001600160a01b0319166001600160a01b0384161790555b801561121d576000805461ff00191690555b50505050505050505050565b611231612c14565b6001600160a01b03166112426112c0565b6001600160a01b03161461128b576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b606d8190556040517f6feb1f001efc32a2021d7f13d152eec43f9e73784f2344dc67cad93c808550db90610ba7908390614270565b6033546001600160a01b031690565b6112d7612c14565b6001600160a01b03166112e86112c0565b6001600160a01b031614611331576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b606980546001600160a01b0319166001600160a01b038416179055606a8190556040517f826cba3adadd8c4068f2d800dddb0e8cc50ed413f90aced811e2e3ba08b2728c90610c70908490849061424c565b6072546001600160a01b031681565b60705481565b606b5481565b6067546001600160a01b031681565b606f546001600160a01b031681565b6000806113c761217f565b60675460208201519192506000916001600160a01b039091169063d751cf9d906113f090612f6b565b6040518263ffffffff1660e01b815260040161140c9190614270565b60206040518083038186803b15801561142457600080fd5b505afa158015611438573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061145c919061414c565b9050611469828286613071565b949350505050565b611479612c14565b6001600160a01b031661148a6112c0565b6001600160a01b0316146114d3576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b606b8190556040517fb012dff4b8767663dda829cad57391a882ca901ea4cc4e56e7b23adb442ee95f90610ba7908390614270565b606a5481565b611516612c14565b6001600160a01b03166115276112c0565b6001600160a01b031614611570576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b603c8162ffffff1610156115965760405162461bcd60e51b8152600401610656906142b0565b60006115a061217f565b90506115ab81612529565b506073805462ffffff909216600160281b0267ffffff000000000019909216919091179055565b6000806115dd61217f565b80519091506115f757670de0b6b3a76400009150506108ba565b60006116068260200151612f6b565b60675460405163d751cf9d60e01b81529192506000916001600160a01b039091169063d751cf9d9061163c908590600401614270565b60206040518083038186803b15801561165457600080fd5b505afa158015611668573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061168c919061414c565b905082606001516000148061169f575080155b156116bf57506ec097ce7bc90715b34b9f100000000092506108ba915050565b60608301516116f0906116d2908361266b565b6020850151855161074991670de0b6b3a764000091610d769161266b565b935050505090565b60655460009081906001600160a01b031633146117275760405162461bcd60e51b815260040161065690614424565b61172f613f85565b600184600281111561173d57fe5b141561175b5761174b61217f565b905061175681612529565b611782565b600284600281111561176957fe5b14156117775761174b61217f565b61177f61217f565b90505b60008160c00151116117a65760405162461bcd60e51b81526004016106569061436f565b60018460028111156117b457fe5b14156117cb576117c481876130f5565b925061187f565b60028460028111156117d957fe5b14156117f0576117e98187613116565b915061187f565b805161186f57600061180f82602001518861266b90919063ffffffff16565b9050611849670de0b6b3a76400006107498181857f000000000000000000000000000000000000000000000000000000000000000061266b565b93506118678461186183670de0b6b3a76400006126cd565b906127f5565b92505061187f565b611879818761316a565b90935091505b606d548151870111156118a45760405162461bcd60e51b815260040161065690614345565b80518601606e558215611916576067546040516340c10f1960e01b81526001600160a01b03909116906340c10f19906118e3908890879060040161424c565b600060405180830381600087803b1580156118fd57600080fd5b505af1158015611911573d6000803e3d6000fd5b505050505b8115611981576068546040516340c10f1960e01b81526001600160a01b03909116906340c10f199061194e908890869060040161424c565b600060405180830381600087803b15801561196857600080fd5b505af115801561197c573d6000803e3d6000fd5b505050505b50935093915050565b6066546001600160a01b031681565b6065546000906001600160a01b031633146119c65760405162461bcd60e51b815260040161065690614424565b670de0b6b3a764000083116119ed5760405162461bcd60e51b8152600401610656906142e7565b60006119f761217f565b905060008160c0015111611a1d5760405162461bcd60e51b81526004016106569061436f565b611a2681612529565b611a3081856131ad565b91508115611a9d576067546040516340c10f1960e01b81526001600160a01b03909116906340c10f1990611a6a908690869060040161424c565b600060405180830381600087803b158015611a8457600080fd5b505af1158015611a98573d6000803e3d6000fd5b505050505b5092915050565b606d5481565b6000670de0b6b3a76400008211611ad35760405162461bcd60e51b8152600401610656906142e7565b6000611add61217f565b9050611ae981846131ad565b9392505050565b600080670de0b6b3a76400008311611b1a5760405162461bcd60e51b8152600401610656906142e7565b6000611b2461217f565b90506106758185613251565b611b38612c14565b6001600160a01b0316611b496112c0565b6001600160a01b031614611b92576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b606f80546001600160a01b0319166001600160a01b0383161790556040517f351ac3b801ef52eee542597618621efdaafc5a2e9469f78505486074ea9b927190610ba790839061421d565b6040805160808101825260735464ffffffffff811680835262ffffff600160281b83041660208401526001600160601b03600160401b8304811694840194909452600160a01b90910490921660608201529015611c4c5760405162461bcd60e51b8152600401610656906143fc565b4264ffffffffff1680825262ffffff9290921660208201819052670de0b6b3a7640000604083018190526060909201919091526073805464ffffffffff191690921767ffffff00000000001916600160281b909102176bffffffffffffffffffffffff60401b19166503782dace9d960521b176001600160a01b03166503782dace9d960b21b179055565b600080670de0b6b3a76400008311611d015760405162461bcd60e51b8152600401610656906142e7565b6000611d0b61217f565b905061067581856132ed565b6065546001600160a01b03163314611d415760405162461bcd60e51b815260040161065690614424565b6000611d4b61217f565b9050611d5681612529565b606d5481518301111580611d6c575060c0810151155b611d885760405162461bcd60e51b815260040161065690614345565b5101606e55565b611d97612c14565b6001600160a01b0316611da86112c0565b6001600160a01b031614611df1576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b6001600160a01b038116611e365760405162461bcd60e51b81526004018080602001828103825260268152602001806144b16026913960400191505060405180910390fd5b6033546040516001600160a01b038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3603380546001600160a01b0319166001600160a01b0392909216919091179055565b6065546000906001600160a01b03163314611ebf5760405162461bcd60e51b815260040161065690614424565b6000611ec961217f565b905060008160c0015111611eef5760405162461bcd60e51b81526004016106569061436f565b611ef881612529565b6000611f05828787613389565b83519194509150611f1690846127f5565b606e55606754604051632770a7eb60e21b81526001600160a01b03909116908190639dc29fac90611f4d9088908b9060040161424c565b600060405180830381600087803b158015611f6757600080fd5b505af1158015611f7b573d6000803e3d6000fd5b50505050806001600160a01b031663251d8ffb611fd3611fb08660400151670de0b6b3a7640000612ca390919063ffffffff16565b610749670de0b6b3a7640000610d76888a608001516127f590919063ffffffff16565b6040518263ffffffff1660e01b8152600401611fef9190614270565b600060405180830381600087803b15801561200957600080fd5b505af115801561201d573d6000803e3d6000fd5b505050506000841115612036576120348433612852565b505b5050509392505050565b612048612c14565b6001600160a01b03166120596112c0565b6001600160a01b0316146120a2576040805162461bcd60e51b81526020600482018190526024820152600080516020614568833981519152604482015290519081900360640190fd5b606c54156120c25760405162461bcd60e51b815260040161065690614279565b60006120cc612e7b565b606c81905560675460405163251d8ffb60e01b81529192506001600160a01b03169063251d8ffb9061210a90670de0b6b3a764000090600401614270565b600060405180830381600087803b15801561212457600080fd5b505af1158015612138573d6000803e3d6000fd5b505050507f53b3cb2bbe2075ccf7ce39aa91abab01aac8b08fe9098bbea7f98ea80dae5b8181670de0b6b3a7640000604051610ba7929190614449565b60006108b7612e7b565b612187613f85565b606e548152612194612e7b565b6020820152805161225057670de0b6b3a76400006080820152606854604080516318160ddd60e01b815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b1580156121f257600080fd5b505afa158015612206573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061222a919061414c565b111561223c57600060c082015261224b565b670de0b6b3a764000060c08201525b6108ba565b61225d8160200151612f6b565b60408083019190915260675481516318160ddd60e01b815291516001600160a01b039091169182916318160ddd91600480820192602092909190829003018186803b1580156122ab57600080fd5b505afa1580156122bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122e3919061414c565b6060830152604080830151905163479944cd60e11b81526001600160a01b03831691638f32899a916123189190600401614270565b60206040518083038186803b15801561233057600080fd5b505afa158015612344573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612368919061414c565b6080830152606854604080516318160ddd60e01b815290516001600160a01b03909216916318160ddd91600480820192602092909190829003018186803b1580156123b257600080fd5b505afa1580156123c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ea919061414c565b60a0830181905261240857670de0b6b3a764000060c083015261246b565b60006124258360800151846060015161266b90919063ffffffff16565b6020840151845191925060009161243b9161266b565b90508181106124605760a084015161245690838303906126cd565b60c0850152612468565b600060c08501525b50505b5090565b600080600061249b670de0b6b3a7640000610d768760200151886000015161266b90919063ffffffff16565b905060006124be8660800151610d7688606001518861266b90919063ffffffff16565b905081811115612520578181036124dd86670de0b6b3a76400006127f5565b95506125006124f988608001518861266b90919063ffffffff16565b82906126cd565b935061251c6124f988602001518861266b90919063ffffffff16565b9450505b50509250929050565b6040805160808101825260735464ffffffffff8116825262ffffff600160281b8204166020808401919091526001600160601b03600160401b8304811694840194909452600160a01b9091049092166060820152606c54918301519091906000906125b49083906125ae90670de0b6b3a7640000906125a8908461340c565b90613471565b9061351a565b905060006125cf606b5483876135d29092919063ffffffff16565b90506125db84826136cf565b50508151607380546020850151604086015160609096015164ffffffffff1990921664ffffffffff9094169390931767ffffff00000000001916600160281b62ffffff90941693909302929092176bffffffffffffffffffffffff60401b1916600160401b6001600160601b0395861602176001600160a01b0316600160a01b9490921693909302179091555050565b60008261267a575060006126c7565b8282028284828161268757fe5b04146126c45760405162461bcd60e51b81526004018080602001828103825260218152602001806145476021913960400191505060405180910390fd5b90505b92915050565b6000808211612723576040805162461bcd60e51b815260206004820152601a60248201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604482015290519081900360640190fd5b81838161272c57fe5b049392505050565b6000806127656127558660800151876060015161266b90919063ffffffff16565b602087015187516118619161266b565b90508460a001516000141561279a57612793856020015161074987608001518761266b90919063ffffffff16565b91506127ed565b60808501516127aa90859061266b565b91506127d16127ca8660a00151610749848761266b90919063ffffffff16565b83906136fa565b91506127ea8560200151836126cd90919063ffffffff16565b91505b509392505050565b60008282111561284c576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b50900390565b600061285d83610984565b6066546040516370a0823160e01b81529194506001600160a01b03169060009082906370a082319061289390309060040161421d565b60206040518083038186803b1580156128ab57600080fd5b505afa1580156128bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128e3919061414c565b9050848110156129ee57606f5460405163abae70c560e01b8152828703916001600160a01b03169063abae70c59061291f908490600401614270565b600060405180830381600087803b15801561293957600080fd5b505af115801561294d573d6000803e3d6000fd5b505060705461295f92509050826127f5565b6070556040516370a0823160e01b81526001600160a01b038416906370a082319061298e90309060040161421d565b60206040518083038186803b1580156129a657600080fd5b505afa1580156129ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129de919061414c565b9150818611156129ec578195505b505b612a026001600160a01b0383168587612ae1565b50929392505050565b600042826000015164ffffffffff161015612acd578151602083015164ffffffffff90911642039060009062ffffff16670de0b6b3a7640000830281612a4d57fe5b049050680238fd42c5cf040000811115612a775750505060408101516001600160601b0316610970565b6000612a8582600003613754565b9050670de0b6b3a76400008186606001516001600160601b03160282670de0b6b3a76400000387604001516001600160601b0316020181612ac257fe5b049350505050610970565b5060608101516001600160601b0316610970565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052612b33908490613b6c565b505050565b6000806000612b64670de0b6b3a7640000610d768860000151896020015161266b90919063ffffffff16565b90506000612b878760800151610d7689606001518961266b90919063ffffffff16565b905081811115612c0a57818103612bbd6124f9670de0b6b3a7640000888a0260208c015191670de0b6b3a764000091040161266b565b9450612c06612be1670de0b6b3a76400008a60c0015161266b90919063ffffffff16565b61074988670de0b6b3a764000001610d768c602001518a61266b90919063ffffffff16565b9350505b5050935093915050565b3390565b6000806000612c3486602001518661266b90919063ffffffff16565b9050612c4e670de0b6b3a76400006107498387830161266b565b9250612c678660c00151846126cd90919063ffffffff16565b9250612c7f670de0b6b3a7640000610749838761266b565b9150612c988660600151836126cd90919063ffffffff16565b915050935093915050565b6000828201818312801590612cb85750838112155b80612ccd5750600083128015612ccd57508381125b6126c45760405162461bcd60e51b81526004018080602001828103825260218152602001806144d76021913960400191505060405180910390fd5b6000806000612d34670de0b6b3a7640000610d768760200151886000015161266b90919063ffffffff16565b90506000612d578660800151610d7688606001518861266b90919063ffffffff16565b90508082111561252057612d7385670de0b6b3a76400006127f5565b602087015190955081830390612d8d906124f9908861266b565b9450612da96124f987896080015161266b90919063ffffffff16565b93505050509250929050565b6000806000612dd98660800151610d7688606001518861266b90919063ffffffff16565b90506000612e04670de0b6b3a7640000610d7689602001518a6000015161266b90919063ffffffff16565b905080821115612c0a57808203612e2387670de0b6b3a76400006127f5565b9650612e3f6124f9888a6020015161266b90919063ffffffff16565b9450612c06612e65896080015188670de0b6b3a76400000161266b90919063ffffffff16565b610749670de0b6b3a7640000610d76858c6126cd565b6000806000606960009054906101000a90046001600160a01b03166001600160a01b0316635b1dac606040518163ffffffff1660e01b8152600401604080518083038186803b158015612ecd57600080fd5b505afa158015612ee1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f0591906140e4565b9150915081612f265760405162461bcd60e51b81526004016106569061431e565b8092506012606a541015612f4657606a54601203600a0a83029250612f66565b6012606a541115612f66576012606a5403600a0a8381612f6257fe5b0492505b505090565b606c5460009081612f8c826125ae670de0b6b3a76400006125a8888461340c565b9050611469670de0b6b3a76400006125ae606b548461347190919063ffffffff16565b6000612fba30613c1d565b15905090565b600054610100900460ff1680612fd95750612fd9612faf565b80612fe7575060005460ff16155b6130225760405162461bcd60e51b815260040180806020018281038252602e8152602001806144f8602e913960400191505060405180910390fd5b600054610100900460ff1615801561304d576000805460ff1961ff0019909116610100171660011790555b613055613c23565b61305d613cc3565b80156106aa576000805461ff001916905550565b60008061308f84610d7687606001518661266b90919063ffffffff16565b905060006130b2670de0b6b3a7640000876020015161266b90919063ffffffff16565b90506130c781610749600161186186846136fa565b86519093508310156130de57600092505050611ae9565b85516130eb9084906127f5565b9695505050505050565b6000611ae9836080015161074985602001518561266b90919063ffffffff16565b60006131378360a00151610d7685602001518561266b90919063ffffffff16565b9050611ae96124f961315a8560800151866060015161266b90919063ffffffff16565b602086015186516118619161266b565b60008061318c846000015161074985876060015161266b90919063ffffffff16565b845160a08601519193506131a491610749908661266b565b90509250929050565b6000806131d7670de0b6b3a7640000610d768660200151876000015161266b90919063ffffffff16565b905060006131fa8560800151610d7687606001518761266b90919063ffffffff16565b905080821161320e576000925050506126c7565b61322f61322886608001518661266b90919063ffffffff16565b83906126cd565b92506132488560600151846127f590919063ffffffff16565b95945050505050565b600080600061327d670de0b6b3a7640000610d768760200151886000015161266b90919063ffffffff16565b905060006132a08660800151610d7688606001518861266b90919063ffffffff16565b9050808211156125205760c0860151818303906132c9906124f990670de0b6b3a764000061266b565b935061251c6124f9670de0b6b3a7640000896020015161266b90919063ffffffff16565b6000806000613319670de0b6b3a7640000610d768760000151886020015161266b90919063ffffffff16565b9050600061333c8660800151610d7688606001518861266b90919063ffffffff16565b90508181111561252057602086015182820390613365906124f990670de0b6b3a764000061266b565b9450612da96124f9670de0b6b3a76400008960c0015161266b90919063ffffffff16565b60008060006133a586608001518661266b90919063ffffffff16565b90506133bf670de0b6b3a76400006107498387830161266b565b92506133d88660200151846126cd90919063ffffffff16565b92506133f0670de0b6b3a7640000610749838761266b565b9150612c986132288688606001516127f590919063ffffffff16565b60008183038183128015906134215750838113155b80613436575060008312801561343657508381135b6126c45760405162461bcd60e51b81526004018080602001828103825260248152602001806145af6024913960400191505060405180910390fd5b600082613480575060006126c7565b826000191480156134945750600160ff1b82145b156134d05760405162461bcd60e51b81526004018080602001828103825260278152602001806145886027913960400191505060405180910390fd5b828202828482816134dd57fe5b05146126c45760405162461bcd60e51b81526004018080602001828103825260278152602001806145886027913960400191505060405180910390fd5b60008161356e576040805162461bcd60e51b815260206004820181905260248201527f5369676e6564536166654d6174683a206469766973696f6e206279207a65726f604482015290519081900360640190fd5b816000191480156135825750600160ff1b83145b156135be5760405162461bcd60e51b81526004018080602001828103825260218152602001806145266021913960400191505060405180910390fd5b60008284816135c957fe5b05949350505050565b602083015183516000916135e6919061266b565b6135fa575068056bc75e2d63100000611ae9565b60208401518451600091613638916136119161266b565b610749670de0b6b3a7640000610d7689608001518a6060015161266b90919063ffffffff16565b9050670de0b6b3a7640000811061365b5768056bc75e2d63100000915050611ae9565b60006136886ec097ce7bc90715b34b9f1000000000610749670de0b6b3a76400008701610d76868a61266b565b90506136a8670de0b6b3a76400008381039061074990610d7681866127f5565b925068056bc75e2d63100000831115610853575068056bc75e2d6310000095945050505050565b6136d882612a0b565b6001600160601b03908116606084015216604082015264ffffffffff42169052565b6000828201838110156126c4576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000680238fd42c5cf03ffff198212158015613779575068070c1cc73b00c800008213155b6137bd576040805162461bcd60e51b815260206004820152601060248201526f1253959053125117d1561413d391539560821b604482015290519081900360640190fd5b60008212156137f1576137d282600003613754565b6ec097ce7bc90715b34b9f1000000000816137e957fe5b059050610970565b60006806f05b59d3b2000000831261383157506806f05b59d3b1ffffff1990910190770195e54c5dd42177f53a27172fa9ec630262827000000000613867565b6803782dace9d9000000831261386357506803782dace9d8ffffff19909101906b1425982cf597cd205cef7380613867565b5060015b6064929092029168056bc75e2d6310000068ad78ebc5ac6200000084126138b75768ad78ebc5ac61ffffff199093019268056bc75e2d631000006e01855144814a7ff805980ff008400082020590505b6856bc75e2d63100000084126138f3576856bc75e2d630ffffff199093019268056bc75e2d631000006b02df0ab5a80a22c61ab5a70082020590505b682b5e3af16b18800000841261392d57682b5e3af16b187fffff199093019268056bc75e2d63100000693f1fce3da636ea5cf85082020590505b6815af1d78b58c4000008412613967576815af1d78b58c3fffff199093019268056bc75e2d63100000690127fa27722cc06cc5e282020590505b680ad78ebc5ac620000084126139a057680ad78ebc5ac61fffff199093019268056bc75e2d6310000068280e60114edb805d0382020590505b68056bc75e2d6310000084126139d95768056bc75e2d630fffff199093019268056bc75e2d63100000680ebc5fb4174612111082020590505b6802b5e3af16b18800008412613a12576802b5e3af16b187ffff199093019268056bc75e2d631000006808f00f760a4b2db55d82020590505b68015af1d78b58c400008412613a4b5768015af1d78b58c3ffff199093019268056bc75e2d631000006806f5f177578893793782020590505b68056bc75e2d631000008481019085906002908280020505918201919050600368056bc75e2d631000008783020505918201919050600468056bc75e2d631000008783020505918201919050600568056bc75e2d631000008783020505918201919050600668056bc75e2d631000008783020505918201919050600768056bc75e2d631000008783020505918201919050600868056bc75e2d631000008783020505918201919050600968056bc75e2d631000008783020505918201919050600a68056bc75e2d631000008783020505918201919050600b68056bc75e2d631000008783020505918201919050600c68056bc75e2d631000008783020505918201919050606468056bc75e2d63100000848402058502059695505050505050565b6000613bc1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613dbc9092919063ffffffff16565b805190915015612b3357808060200190516020811015613be057600080fd5b5051612b335760405162461bcd60e51b815260040180806020018281038252602a8152602001806145d3602a913960400191505060405180910390fd5b3b151590565b600054610100900460ff1680613c3c5750613c3c612faf565b80613c4a575060005460ff16155b613c855760405162461bcd60e51b815260040180806020018281038252602e8152602001806144f8602e913960400191505060405180910390fd5b600054610100900460ff1615801561305d576000805460ff1961ff00199091166101001716600117905580156106aa576000805461ff001916905550565b600054610100900460ff1680613cdc5750613cdc612faf565b80613cea575060005460ff16155b613d255760405162461bcd60e51b815260040180806020018281038252602e8152602001806144f8602e913960400191505060405180910390fd5b600054610100900460ff16158015613d50576000805460ff1961ff0019909116610100171660011790555b6000613d5a612c14565b603380546001600160a01b0319166001600160a01b038316908117909155604051919250906000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35080156106aa576000805461ff001916905550565b6060611469848460008585613dd085613c1d565b613e21576040805162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015290519081900360640190fd5b600080866001600160a01b031685876040518082805190602001908083835b60208310613e5f5780518252601f199092019160209182019101613e40565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d8060008114613ec1576040519150601f19603f3d011682016040523d82523d6000602084013e613ec6565b606091505b5091509150613ed6828286613ee1565b979650505050505050565b60608315613ef0575081611ae9565b825115613f005782518084602001fd5b8160405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015613f4a578181015183820152602001613f32565b50505050905090810190601f168015613f775780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b80356001600160a01b038116811461097057600080fd5b600060208284031215613fea578081fd5b611ae982613fc2565b60008060008060008060008060006101208a8c031215614011578485fd5b61401a8a613fc2565b985061402860208b01613fc2565b975061403660408b01613fc2565b965061404460608b01613fc2565b955061405260808b01613fc2565b945060a08a0135935060c08a0135925060e08a013591506140766101008b01613fc2565b90509295985092959850929598565b60008060408385031215614097578182fd5b6140a083613fc2565b915060208301356140b0816144a2565b809150509250929050565b600080604083850312156140cd578182fd5b6140d683613fc2565b946020939093013593505050565b600080604083850312156140f6578182fd5b8251614101816144a2565b6020939093015192949293505050565b600060208284031215614122578081fd5b813562ffffff811681146126c4578182fd5b600060208284031215614145578081fd5b5035919050565b60006020828403121561415d578081fd5b5051919050565b60008060408385031215614176578182fd5b823591506131a460208401613fc2565b60008060006060848603121561419a578283fd5b833592506141aa60208501613fc2565b91506040840135600381106141bd578182fd5b809150509250925092565b600080604083850312156141da578182fd5b50508035926020909101359150565b6000806000606084860312156141fd578283fd5b833592506020840135915061421460408501613fc2565b90509250925092565b6001600160a01b0391909116815260200190565b6001600160a01b039290921682521515602082015260400190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b6020808252601a908201527f6f6e6c7920696e697469616c697a65207072696365206f6e6365000000000000604082015260600190565b6020808252601d908201527f454d412073616d706c6520696e74657276616c20746f6f20736d616c6c000000604082015260600190565b6020808252601a908201527f636f6c6c61746572616c20726174696f20746f6f20736d616c6c000000000000604082015260600190565b6020808252600d908201526c696e76616c696420707269636560981b604082015260600190565b60208082526010908201526f045786365656420746f74616c206361760841b604082015260600190565b60208082526017908201527f73797374656d20756e64657220636f6c6c61746572616c000000000000000000604082015260600190565b6020808252600d908201526c4f6e6c7920737472617465677960981b604082015260600190565b6020808252601590820152741bdb9b1e481cd95d1d1b19481dda1a5d195b1a5cdd605a1b604082015260600190565b6020808252600e908201526d1d8c881a5b9a5d1a585b1a5e995960921b604082015260600190565b6020808252600b908201526a13db9b1e481b585c9ad95d60aa1b604082015260600190565b918252602082015260400190565b9283526020830191909152604082015260600190565b64ffffffffff94909416845262ffffff9290921660208401526001600160601b03908116604084015216606082015260800190565b80151581146106aa57600080fdfe4f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573735369676e6564536166654d6174683a206164646974696f6e206f766572666c6f77496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a65645369676e6564536166654d6174683a206469766973696f6e206f766572666c6f77536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f774f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65725369676e6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f775369676e6564536166654d6174683a207375627472616374696f6e206f766572666c6f775361666545524332303a204552433230206f7065726174696f6e20646964206e6f742073756363656564a26469706673582212202f9a63ba380aa39620e5c9e1eae84995a463aa851c2a452315487c271124eb7364736f6c634300070600330000000000000000000000000000000000000000000000000c7d713b49da0000","name":"Treasury","is_blueprint":false,"license_type":"none","is_fully_verified":true,"is_verified_via_eth_bytecode_db":false,"language":"solidity","evm_version":"istanbul","can_be_visualized_via_sol2uml":true,"is_verified_via_sourcify":false,"additional_sources":[{"file_path":"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/Initializable.sol\";\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * 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 initializer {\n        __Context_init_unchained();\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal initializer {\n        address msgSender = _msgSender();\n        _owner = msgSender;\n        emit OwnershipTransferred(address(0), msgSender);\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\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        emit OwnershipTransferred(_owner, address(0));\n        _owner = address(0);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        emit OwnershipTransferred(_owner, newOwner);\n        _owner = newOwner;\n    }\n    uint256[49] private __gap;\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMathUpgradeable {\n    /**\n     * @dev Returns the addition of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        uint256 c = a + b;\n        if (c < a) return (false, 0);\n        return (true, c);\n    }\n\n    /**\n     * @dev Returns the substraction of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        if (b > a) return (false, 0);\n        return (true, a - b);\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n        // benefit is lost if 'b' is also tested.\n        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n        if (a == 0) return (true, 0);\n        uint256 c = a * b;\n        if (c / a != b) return (false, 0);\n        return (true, c);\n    }\n\n    /**\n     * @dev Returns the division of two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        if (b == 0) return (false, 0);\n        return (true, a / b);\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.\n     *\n     * _Available since v3.4._\n     */\n    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {\n        if (b == 0) return (false, 0);\n        return (true, a % b);\n    }\n\n    /**\n     * @dev Returns the addition of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     *\n     * - Addition cannot overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        uint256 c = a + b;\n        require(c >= a, \"SafeMath: addition overflow\");\n        return c;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting on\n     * overflow (when the result is negative).\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b <= a, \"SafeMath: subtraction overflow\");\n        return a - b;\n    }\n\n    /**\n     * @dev Returns the multiplication of two unsigned integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     *\n     * - Multiplication cannot overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        if (a == 0) return 0;\n        uint256 c = a * b;\n        require(c / a == b, \"SafeMath: multiplication overflow\");\n        return c;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b > 0, \"SafeMath: division by zero\");\n        return a / b;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting when dividing by zero.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b > 0, \"SafeMath: modulo by zero\");\n        return a % b;\n    }\n\n    /**\n     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n     * overflow (when the result is negative).\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {trySub}.\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        require(b <= a, errorMessage);\n        return a - b;\n    }\n\n    /**\n     * @dev Returns the integer division of two unsigned integers, reverting with custom message on\n     * division by zero. The result is rounded towards zero.\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {tryDiv}.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        require(b > 0, errorMessage);\n        return a / b;\n    }\n\n    /**\n     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),\n     * reverting with custom message when dividing by zero.\n     *\n     * CAUTION: This function is deprecated because it requires allocating memory for the error\n     * message unnecessarily. For custom revert reasons use {tryMod}.\n     *\n     * Counterpart to Solidity's `%` operator. This function uses a `revert`\n     * opcode (which leaves remaining gas untouched) while Solidity uses an\n     * invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {\n        require(b > 0, errorMessage);\n        return a % b;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/math/SignedSafeMathUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @title SignedSafeMath\n * @dev Signed math operations with safety checks that revert on error.\n */\nlibrary SignedSafeMathUpgradeable {\n    int256 constant private _INT256_MIN = -2**255;\n\n    /**\n     * @dev Returns the multiplication of two signed integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `*` operator.\n     *\n     * Requirements:\n     *\n     * - Multiplication cannot overflow.\n     */\n    function mul(int256 a, int256 b) internal pure returns (int256) {\n        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the\n        // benefit is lost if 'b' is also tested.\n        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522\n        if (a == 0) {\n            return 0;\n        }\n\n        require(!(a == -1 && b == _INT256_MIN), \"SignedSafeMath: multiplication overflow\");\n\n        int256 c = a * b;\n        require(c / a == b, \"SignedSafeMath: multiplication overflow\");\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the integer division of two signed integers. Reverts on\n     * division by zero. The result is rounded towards zero.\n     *\n     * Counterpart to Solidity's `/` operator. Note: this function uses a\n     * `revert` opcode (which leaves remaining gas untouched) while Solidity\n     * uses an invalid opcode to revert (consuming all remaining gas).\n     *\n     * Requirements:\n     *\n     * - The divisor cannot be zero.\n     */\n    function div(int256 a, int256 b) internal pure returns (int256) {\n        require(b != 0, \"SignedSafeMath: division by zero\");\n        require(!(b == -1 && a == _INT256_MIN), \"SignedSafeMath: division overflow\");\n\n        int256 c = a / b;\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the subtraction of two signed integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `-` operator.\n     *\n     * Requirements:\n     *\n     * - Subtraction cannot overflow.\n     */\n    function sub(int256 a, int256 b) internal pure returns (int256) {\n        int256 c = a - b;\n        require((b >= 0 && c <= a) || (b < 0 && c > a), \"SignedSafeMath: subtraction overflow\");\n\n        return c;\n    }\n\n    /**\n     * @dev Returns the addition of two signed integers, reverting on\n     * overflow.\n     *\n     * Counterpart to Solidity's `+` operator.\n     *\n     * Requirements:\n     *\n     * - Addition cannot overflow.\n     */\n    function add(int256 a, int256 b) internal pure returns (int256) {\n        int256 c = a + b;\n        require((b >= 0 && c >= a) || (b < 0 && c < a), \"SignedSafeMath: addition overflow\");\n\n        return c;\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/proxy/Initializable.sol","source_code":"// SPDX-License-Identifier: MIT\n\n// solhint-disable-next-line compiler-version\npragma solidity >=0.4.24 <0.8.0;\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 a proxied contract can't have 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 * 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 {UpgradeableProxy-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 */\nabstract contract Initializable {\n\n    /**\n     * @dev Indicates that the contract has been initialized.\n     */\n    bool 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 Modifier to protect an initializer function from being invoked twice.\n     */\n    modifier initializer() {\n        require(_initializing || _isConstructor() || !_initialized, \"Initializable: contract is already initialized\");\n\n        bool isTopLevelCall = !_initializing;\n        if (isTopLevelCall) {\n            _initializing = true;\n            _initialized = true;\n        }\n\n        _;\n\n        if (isTopLevelCall) {\n            _initializing = false;\n        }\n    }\n\n    /// @dev Returns true if and only if the function is running in the constructor\n    function _isConstructor() private view returns (bool) {\n        return !AddressUpgradeable.isContract(address(this));\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20Upgradeable {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/token/ERC20/SafeERC20Upgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\nimport \"./IERC20Upgradeable.sol\";\nimport \"../../math/SafeMathUpgradeable.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 SafeMathUpgradeable for uint256;\n    using AddressUpgradeable for address;\n\n    function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) 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(IERC20Upgradeable token, address spender, uint256 value) 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        // solhint-disable-next-line max-line-length\n        require((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(IERC20Upgradeable token, address spender, uint256 value) internal {\n        uint256 newAllowance = token.allowance(address(this), spender).add(value);\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {\n        uint256 newAllowance = token.allowance(address(this), spender).sub(value, \"SafeERC20: decreased allowance below zero\");\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\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) { // Return data is optional\n            // solhint-disable-next-line max-line-length\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\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    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize, which returns 0 for contracts in\n        // construction, since the code is only stored at the end of the\n        // constructor execution.\n\n        uint256 size;\n        // solhint-disable-next-line no-inline-assembly\n        assembly { size := extcodesize(account) }\n        return size > 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        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value\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 functionCall(target, data, \"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(address target, bytes memory data, string memory errorMessage) 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(address target, bytes memory data, uint256 value) 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(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.call{ value: value }(data);\n        return _verifyCallResult(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(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return _verifyCallResult(success, returndata, errorMessage);\n    }\n\n    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\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\n                // solhint-disable-next-line no-inline-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}\n"},{"file_path":"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity >=0.6.0 <0.8.0;\nimport \"../proxy/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 GSN meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal initializer {\n        __Context_init_unchained();\n    }\n\n    function __Context_init_unchained() internal initializer {\n    }\n    function _msgSender() internal view virtual returns (address payable) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes memory) {\n        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691\n        return msg.data;\n    }\n    uint256[50] private __gap;\n}\n"},{"file_path":"contracts/common/math/ExponentialMovingAverageV7.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.6;\n\nimport { LogExpMathV7 } from \"./LogExpMathV7.sol\";\n\n// solhint-disable not-rely-on-time\n\n/// @dev See https://en.wikipedia.org/wiki/Exponential_smoothing\nlibrary ExponentialMovingAverageV7 {\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The precision used to compute EMA.\n  uint256 private constant PRECISION = 1e18;\n\n  /***********\n   * Structs *\n   ***********/\n\n  /// @dev Compiler will pack this into single `uint256`.\n  /// @param lastTime The last timestamp when the storage is updated.\n  /// @param sampleInterval The sampling time interval used in the EMA.\n  /// @param lastValue The last value in the data sequence, with precision 1e18.\n  /// @param lastEmaValue The last EMA value computed, with precision 1e18.\n  struct EMAStorage {\n    uint40 lastTime;\n    uint24 sampleInterval;\n    uint96 lastValue;\n    uint96 lastEmaValue;\n  }\n\n  /// @dev Save value of EMA storage.\n  /// @param s The EMA storage.\n  /// @param value The new value, with precision 1e18.\n  function saveValue(EMAStorage memory s, uint96 value) internal view {\n    s.lastEmaValue = uint96(emaValue(s));\n    s.lastValue = value;\n    s.lastTime = uint40(block.timestamp);\n  }\n\n  /// @dev Return the current ema value.\n  /// @param s The EMA storage.\n  function emaValue(EMAStorage memory s) internal view returns (uint256) {\n    if (uint256(s.lastTime) < block.timestamp) {\n      uint256 dt = block.timestamp - uint256(s.lastTime);\n      uint256 e = (dt * PRECISION) / s.sampleInterval;\n      if (e > 41e18) {\n        return s.lastValue;\n      } else {\n        uint256 alpha = uint256(LogExpMathV7.exp(-int256(e)));\n        return (s.lastValue * (PRECISION - alpha) + s.lastEmaValue * alpha) / PRECISION;\n      }\n    } else {\n      return s.lastEmaValue;\n    }\n  }\n}\n"},{"file_path":"contracts/common/math/LogExpMathV7.sol","source_code":"// SPDX-License-Identifier: MIT\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the “Software”), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n\n// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npragma solidity ^0.7.0;\n\n/* solhint-disable */\n\n/**\n * @dev Copied from https://github.com/balancer/balancer-v2-monorepo/blob/master/pkg/solidity-utils/contracts/math/LogExpMath.sol\n *\n * Some modifications are made due to compile error.\n *\n * @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument).\n *\n * Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural\n * exponentiation and logarithm (where the base is Euler's number).\n *\n * @author Fernando Martinelli - @fernandomartinelli\n * @author Sergio Yuhjtman - @sergioyuhjtman\n * @author Daniel Fernandez - @dmf7z\n */\nlibrary LogExpMathV7 {\n  // All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying\n  // two numbers, and multiply by ONE when dividing them.\n\n  // All arguments and return values are 18 decimal fixed point numbers.\n  int256 constant ONE_18 = 1e18;\n\n  // Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the\n  // case of ln36, 36 decimals.\n  int256 constant ONE_20 = 1e20;\n  int256 constant ONE_36 = 1e36;\n\n  // The domain of natural exponentiation is bound by the word size and number of decimals used.\n  //\n  // Because internally the result will be stored using 20 decimals, the largest possible result is\n  // (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221.\n  // The smallest possible result is 10^(-18), which makes largest negative argument\n  // ln(10^(-18)) = -41.446531673892822312.\n  // We use 130.0 and -41.0 to have some safety margin.\n  int256 constant MAX_NATURAL_EXPONENT = 130e18;\n  int256 constant MIN_NATURAL_EXPONENT = -41e18;\n\n  // Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point\n  // 256 bit integer.\n  int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17;\n  int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17;\n\n  uint256 constant MILD_EXPONENT_BOUND = 2**254 / uint256(ONE_20);\n\n  // 18 decimal constants\n  int256 constant x0 = 128000000000000000000; // 2ˆ7\n  int256 constant a0 = 38877084059945950922200000000000000000000000000000000000; // eˆ(x0) (no decimals)\n  int256 constant x1 = 64000000000000000000; // 2ˆ6\n  int256 constant a1 = 6235149080811616882910000000; // eˆ(x1) (no decimals)\n\n  // 20 decimal constants\n  int256 constant x2 = 3200000000000000000000; // 2ˆ5\n  int256 constant a2 = 7896296018268069516100000000000000; // eˆ(x2)\n  int256 constant x3 = 1600000000000000000000; // 2ˆ4\n  int256 constant a3 = 888611052050787263676000000; // eˆ(x3)\n  int256 constant x4 = 800000000000000000000; // 2ˆ3\n  int256 constant a4 = 298095798704172827474000; // eˆ(x4)\n  int256 constant x5 = 400000000000000000000; // 2ˆ2\n  int256 constant a5 = 5459815003314423907810; // eˆ(x5)\n  int256 constant x6 = 200000000000000000000; // 2ˆ1\n  int256 constant a6 = 738905609893065022723; // eˆ(x6)\n  int256 constant x7 = 100000000000000000000; // 2ˆ0\n  int256 constant a7 = 271828182845904523536; // eˆ(x7)\n  int256 constant x8 = 50000000000000000000; // 2ˆ-1\n  int256 constant a8 = 164872127070012814685; // eˆ(x8)\n  int256 constant x9 = 25000000000000000000; // 2ˆ-2\n  int256 constant a9 = 128402541668774148407; // eˆ(x9)\n  int256 constant x10 = 12500000000000000000; // 2ˆ-3\n  int256 constant a10 = 113314845306682631683; // eˆ(x10)\n  int256 constant x11 = 6250000000000000000; // 2ˆ-4\n  int256 constant a11 = 106449445891785942956; // eˆ(x11)\n\n  /**\n   * @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent.\n   *\n   * Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`.\n   */\n  function pow(uint256 x, uint256 y) internal pure returns (uint256) {\n    if (y == 0) {\n      // We solve the 0^0 indetermination by making it equal one.\n      return uint256(ONE_18);\n    }\n\n    if (x == 0) {\n      return 0;\n    }\n\n    // Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to\n    // arrive at that result. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means\n    // x^y = exp(y * ln(x)).\n\n    // The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range.\n    require(x >> 255 == 0, \"X_OUT_OF_BOUNDS\");\n    int256 x_int256 = int256(x);\n\n    // We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In\n    // both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end.\n\n    // This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range.\n    require(y < MILD_EXPONENT_BOUND, \"Y_OUT_OF_BOUNDS\");\n    int256 y_int256 = int256(y);\n\n    int256 logx_times_y;\n    if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) {\n      int256 ln_36_x = _ln_36(x_int256);\n\n      // ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just\n      // bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal\n      // multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the\n      // (downscaled) last 18 decimals.\n      logx_times_y = ((ln_36_x / ONE_18) * y_int256 + ((ln_36_x % ONE_18) * y_int256) / ONE_18);\n    } else {\n      logx_times_y = _ln(x_int256) * y_int256;\n    }\n    logx_times_y /= ONE_18;\n\n    // Finally, we compute exp(y * ln(x)) to arrive at x^y\n    require(MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT, \"PRODUCT_OUT_OF_BOUNDS\");\n\n    return uint256(exp(logx_times_y));\n  }\n\n  /**\n   * @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent.\n   *\n   * Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`.\n   */\n  function exp(int256 x) internal pure returns (int256) {\n    require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, \"INVALID_EXPONENT\");\n\n    if (x < 0) {\n      // We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it\n      // fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT).\n      // Fixed point division requires multiplying by ONE_18.\n      return ((ONE_18 * ONE_18) / exp(-x));\n    }\n\n    // First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n,\n    // where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7\n    // because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the\n    // decomposition.\n    // At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this\n    // decomposition, which will be lower than the smallest x_n.\n    // exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1.\n    // We mutate x by subtracting x_n, making it the remainder of the decomposition.\n\n    // The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause\n    // intermediate overflows. Instead we store them as plain integers, with 0 decimals.\n    // Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the\n    // decomposition.\n\n    // For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct\n    // it and compute the accumulated product.\n\n    int256 firstAN;\n    if (x >= x0) {\n      x -= x0;\n      firstAN = a0;\n    } else if (x >= x1) {\n      x -= x1;\n      firstAN = a1;\n    } else {\n      firstAN = 1; // One with no decimal places\n    }\n\n    // We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the\n    // smaller terms.\n    x *= 100;\n\n    // `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point\n    // one. Recall that fixed point multiplication requires dividing by ONE_20.\n    int256 product = ONE_20;\n\n    if (x >= x2) {\n      x -= x2;\n      product = (product * a2) / ONE_20;\n    }\n    if (x >= x3) {\n      x -= x3;\n      product = (product * a3) / ONE_20;\n    }\n    if (x >= x4) {\n      x -= x4;\n      product = (product * a4) / ONE_20;\n    }\n    if (x >= x5) {\n      x -= x5;\n      product = (product * a5) / ONE_20;\n    }\n    if (x >= x6) {\n      x -= x6;\n      product = (product * a6) / ONE_20;\n    }\n    if (x >= x7) {\n      x -= x7;\n      product = (product * a7) / ONE_20;\n    }\n    if (x >= x8) {\n      x -= x8;\n      product = (product * a8) / ONE_20;\n    }\n    if (x >= x9) {\n      x -= x9;\n      product = (product * a9) / ONE_20;\n    }\n\n    // x10 and x11 are unnecessary here since we have high enough precision already.\n\n    // Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series\n    // expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!).\n\n    int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places.\n    int256 term; // Each term in the sum, where the nth term is (x^n / n!).\n\n    // The first term is simply x.\n    term = x;\n    seriesSum += term;\n\n    // Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number,\n    // multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not.\n\n    term = ((term * x) / ONE_20) / 2;\n    seriesSum += term;\n\n    term = ((term * x) / ONE_20) / 3;\n    seriesSum += term;\n\n    term = ((term * x) / ONE_20) / 4;\n    seriesSum += term;\n\n    term = ((term * x) / ONE_20) / 5;\n    seriesSum += term;\n\n    term = ((term * x) / ONE_20) / 6;\n    seriesSum += term;\n\n    term = ((term * x) / ONE_20) / 7;\n    seriesSum += term;\n\n    term = ((term * x) / ONE_20) / 8;\n    seriesSum += term;\n\n    term = ((term * x) / ONE_20) / 9;\n    seriesSum += term;\n\n    term = ((term * x) / ONE_20) / 10;\n    seriesSum += term;\n\n    term = ((term * x) / ONE_20) / 11;\n    seriesSum += term;\n\n    term = ((term * x) / ONE_20) / 12;\n    seriesSum += term;\n\n    // 12 Taylor terms are sufficient for 18 decimal precision.\n\n    // We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor\n    // approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply\n    // all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication),\n    // and then drop two digits to return an 18 decimal value.\n\n    return (((product * seriesSum) / ONE_20) * firstAN) / 100;\n  }\n\n  /**\n   * @dev Logarithm (log(arg, base), with signed 18 decimal fixed point base and argument.\n   */\n  function log(int256 arg, int256 base) internal pure returns (int256) {\n    // This performs a simple base change: log(arg, base) = ln(arg) / ln(base).\n\n    // Both logBase and logArg are computed as 36 decimal fixed point numbers, either by using ln_36, or by\n    // upscaling.\n\n    int256 logBase;\n    if (LN_36_LOWER_BOUND < base && base < LN_36_UPPER_BOUND) {\n      logBase = _ln_36(base);\n    } else {\n      logBase = _ln(base) * ONE_18;\n    }\n\n    int256 logArg;\n    if (LN_36_LOWER_BOUND < arg && arg < LN_36_UPPER_BOUND) {\n      logArg = _ln_36(arg);\n    } else {\n      logArg = _ln(arg) * ONE_18;\n    }\n\n    // When dividing, we multiply by ONE_18 to arrive at a result with 18 decimal places\n    return (logArg * ONE_18) / logBase;\n  }\n\n  /**\n   * @dev Natural logarithm (ln(a)) with signed 18 decimal fixed point argument.\n   */\n  function ln(int256 a) internal pure returns (int256) {\n    // The real natural logarithm is not defined for negative numbers or zero.\n    require(a > 0, \"OUT_OF_BOUNDS\");\n    if (LN_36_LOWER_BOUND < a && a < LN_36_UPPER_BOUND) {\n      return _ln_36(a) / ONE_18;\n    } else {\n      return _ln(a);\n    }\n  }\n\n  /**\n   * @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument.\n   */\n  function _ln(int256 a) private pure returns (int256) {\n    if (a < ONE_18) {\n      // Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less\n      // than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call.\n      // Fixed point division requires multiplying by ONE_18.\n      return (-_ln((ONE_18 * ONE_18) / a));\n    }\n\n    // First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which\n    // we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is,\n    // ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot\n    // be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a.\n    // At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this\n    // decomposition, which will be lower than the smallest a_n.\n    // ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1.\n    // We mutate a by subtracting a_n, making it the remainder of the decomposition.\n\n    // For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point\n    // numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by\n    // ONE_18 to convert them to fixed point.\n    // For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide\n    // by it and compute the accumulated sum.\n\n    int256 sum = 0;\n    if (a >= a0 * ONE_18) {\n      a /= a0; // Integer, not fixed point division\n      sum += x0;\n    }\n\n    if (a >= a1 * ONE_18) {\n      a /= a1; // Integer, not fixed point division\n      sum += x1;\n    }\n\n    // All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format.\n    sum *= 100;\n    a *= 100;\n\n    // Because further a_n are  20 digit fixed point numbers, we multiply by ONE_20 when dividing by them.\n\n    if (a >= a2) {\n      a = (a * ONE_20) / a2;\n      sum += x2;\n    }\n\n    if (a >= a3) {\n      a = (a * ONE_20) / a3;\n      sum += x3;\n    }\n\n    if (a >= a4) {\n      a = (a * ONE_20) / a4;\n      sum += x4;\n    }\n\n    if (a >= a5) {\n      a = (a * ONE_20) / a5;\n      sum += x5;\n    }\n\n    if (a >= a6) {\n      a = (a * ONE_20) / a6;\n      sum += x6;\n    }\n\n    if (a >= a7) {\n      a = (a * ONE_20) / a7;\n      sum += x7;\n    }\n\n    if (a >= a8) {\n      a = (a * ONE_20) / a8;\n      sum += x8;\n    }\n\n    if (a >= a9) {\n      a = (a * ONE_20) / a9;\n      sum += x9;\n    }\n\n    if (a >= a10) {\n      a = (a * ONE_20) / a10;\n      sum += x10;\n    }\n\n    if (a >= a11) {\n      a = (a * ONE_20) / a11;\n      sum += x11;\n    }\n\n    // a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series\n    // that converges rapidly for values of `a` close to one - the same one used in ln_36.\n    // Let z = (a - 1) / (a + 1).\n    // ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))\n\n    // Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires\n    // division by ONE_20.\n    int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20);\n    int256 z_squared = (z * z) / ONE_20;\n\n    // num is the numerator of the series: the z^(2 * n + 1) term\n    int256 num = z;\n\n    // seriesSum holds the accumulated sum of each term in the series, starting with the initial z\n    int256 seriesSum = num;\n\n    // In each step, the numerator is multiplied by z^2\n    num = (num * z_squared) / ONE_20;\n    seriesSum += num / 3;\n\n    num = (num * z_squared) / ONE_20;\n    seriesSum += num / 5;\n\n    num = (num * z_squared) / ONE_20;\n    seriesSum += num / 7;\n\n    num = (num * z_squared) / ONE_20;\n    seriesSum += num / 9;\n\n    num = (num * z_squared) / ONE_20;\n    seriesSum += num / 11;\n\n    // 6 Taylor terms are sufficient for 36 decimal precision.\n\n    // Finally, we multiply by 2 (non fixed point) to compute ln(remainder)\n    seriesSum *= 2;\n\n    // We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both\n    // with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal\n    // value.\n\n    return (sum + seriesSum) / 100;\n  }\n\n  /**\n   * @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument,\n   * for x close to one.\n   *\n   * Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND.\n   */\n  function _ln_36(int256 x) private pure returns (int256) {\n    // Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits\n    // worthwhile.\n\n    // First, we transform x to a 36 digit fixed point value.\n    x *= ONE_18;\n\n    // We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1).\n    // ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))\n\n    // Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires\n    // division by ONE_36.\n    int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36);\n    int256 z_squared = (z * z) / ONE_36;\n\n    // num is the numerator of the series: the z^(2 * n + 1) term\n    int256 num = z;\n\n    // seriesSum holds the accumulated sum of each term in the series, starting with the initial z\n    int256 seriesSum = num;\n\n    // In each step, the numerator is multiplied by z^2\n    num = (num * z_squared) / ONE_36;\n    seriesSum += num / 3;\n\n    num = (num * z_squared) / ONE_36;\n    seriesSum += num / 5;\n\n    num = (num * z_squared) / ONE_36;\n    seriesSum += num / 7;\n\n    num = (num * z_squared) / ONE_36;\n    seriesSum += num / 9;\n\n    num = (num * z_squared) / ONE_36;\n    seriesSum += num / 11;\n\n    num = (num * z_squared) / ONE_36;\n    seriesSum += num / 13;\n\n    num = (num * z_squared) / ONE_36;\n    seriesSum += num / 15;\n\n    // 8 Taylor terms are sufficient for 36 decimal precision.\n\n    // All that remains is multiplying by 2 (non fixed point).\n    return seriesSum * 2;\n  }\n}\n"},{"file_path":"contracts/f(x)/math/FxLowVolatilityMath.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.6;\npragma abicoder v2;\n\nimport { SafeMathUpgradeable } from \"@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol\";\n\nlibrary FxLowVolatilityMath {\n  using SafeMathUpgradeable for uint256;\n\n  /*************\n   * Constants *\n   *************/\n\n  /// @dev The precision used to compute nav.\n  uint256 internal constant PRECISION = 1e18;\n\n  /// @dev The precision used to compute nav.\n  int256 internal constant PRECISION_I256 = 1e18;\n\n  /// @dev The maximum value of leverage ratio.\n  uint256 internal constant MAX_LEVERAGE_RATIO = 100e18;\n\n  /***********\n   * Structs *\n   ***********/\n\n  struct SwapState {\n    // Current supply of base token\n    uint256 baseSupply;\n    // Current nav of base token\n    uint256 baseNav;\n    // The multiple used to compute current nav.\n    int256 fMultiple;\n    // Current supply of fractional token\n    uint256 fSupply;\n    // Current nav of fractional token\n    uint256 fNav;\n    // Current supply of leveraged token\n    uint256 xSupply;\n    // Current nav of leveraged token\n    uint256 xNav;\n  }\n\n  /// @notice Compute the amount of base token needed to reach the new collateral ratio.\n  ///\n  /// @dev If the current collateral ratio <= new collateral ratio, we should return 0.\n  ///\n  /// @param state The current state.\n  /// @param _newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return _maxBaseIn The amount of base token needed.\n  /// @return _maxFTokenMintable The amount of fToken can be minted.\n  function maxMintableFToken(SwapState memory state, uint256 _newCollateralRatio)\n    internal\n    pure\n    returns (uint256 _maxBaseIn, uint256 _maxFTokenMintable)\n  {\n    //  n * v = nf * vf + nx * vx\n    //  (n + dn) * v = (nf + df) * vf + nx * vx\n    //  (n + dn) * v / ((nf + df) * vf) = ncr\n    // =>\n    //  n * v - ncr * nf * vf = (ncr - 1) * dn * v\n    //  n * v - ncr * nf * vf = (ncr - 1) * df * vf\n    // =>\n    //  dn = (n * v - ncr * nf * vf) / ((ncr - 1) * v)\n    //  df = (n * v - ncr * nf * vf) / ((ncr - 1) * vf)\n\n    uint256 _baseVal = state.baseSupply.mul(state.baseNav).mul(PRECISION);\n    uint256 _fVal = _newCollateralRatio.mul(state.fSupply).mul(state.fNav);\n\n    if (_baseVal > _fVal) {\n      _newCollateralRatio = _newCollateralRatio.sub(PRECISION);\n      uint256 _delta = _baseVal - _fVal;\n\n      _maxBaseIn = _delta.div(state.baseNav.mul(_newCollateralRatio));\n      _maxFTokenMintable = _delta.div(state.fNav.mul(_newCollateralRatio));\n    }\n  }\n\n  /// @notice Compute the amount of base token needed to reach the new collateral ratio.\n  ///\n  /// @dev If the current collateral ratio >= new collateral ratio, we should return 0.\n  ///\n  /// @param state The current state.\n  /// @param _newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return _maxBaseIn The amount of base token needed.\n  /// @return _maxXTokenMintable The amount of xToken can be minted.\n  function maxMintableXToken(SwapState memory state, uint256 _newCollateralRatio)\n    internal\n    pure\n    returns (uint256 _maxBaseIn, uint256 _maxXTokenMintable)\n  {\n    //  n * v = nf * vf + nx * vx\n    //  (n + dn) * v = nf * vf + (nx + dx) * vx\n    //  (n + dn) * v / (nf * vf) = ncr\n    // =>\n    //  n * v + dn * v = ncr * nf * vf\n    //  n * v + dx * vx = ncr * nf * vf\n    // =>\n    //  dn = (ncr * nf * vf - n * v) / v\n    //  dx = (ncr * nf * vf - n * v) / vx\n\n    uint256 _baseVal = state.baseNav.mul(state.baseSupply).mul(PRECISION);\n    uint256 _fVal = _newCollateralRatio.mul(state.fSupply).mul(state.fNav);\n\n    if (_fVal > _baseVal) {\n      uint256 _delta = _fVal - _baseVal;\n\n      _maxBaseIn = _delta.div(state.baseNav.mul(PRECISION));\n      _maxXTokenMintable = _delta.div(state.xNav.mul(PRECISION));\n    }\n  }\n\n  /// @notice Compute the amount of base token needed to reach the new collateral ratio, with incentive.\n  ///\n  /// @dev If the current collateral ratio >= new collateral ratio, we should return 0.\n  ///\n  /// @param state The current state.\n  /// @param _newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @param _incentiveRatio The extra incentive ratio, multipled by 1e18.\n  /// @return _maxBaseIn The amount of base token needed.\n  /// @return _maxXTokenMintable The amount of xToken can be minted.\n  function maxMintableXTokenWithIncentive(\n    SwapState memory state,\n    uint256 _newCollateralRatio,\n    uint256 _incentiveRatio\n  ) internal pure returns (uint256 _maxBaseIn, uint256 _maxXTokenMintable) {\n    //  n * v = nf * vf + nx * vx\n    //  (n + dn) * v = nf * (vf - dvf) + (nx + dx) * vx\n    //  (n + dn) * v / (nf * (vf - dvf)) = ncr\n    //  nf * dvf = lambda * dn * v\n    //  dx * vx = (1 + lambda) * dn * v\n    // =>\n    //  n * v + dn * v = ncr * nf * vf - lambda * nrc * dn * v\n    // =>\n    //  dn = (ncr * nf * vf - n * v) / (v * (1 + lambda * ncr))\n    //  dx = ((1 + lambda) * dn * v) / vx\n\n    uint256 _baseVal = state.baseNav.mul(state.baseSupply).mul(PRECISION);\n    uint256 _fVal = _newCollateralRatio.mul(state.fSupply).mul(state.fNav);\n\n    if (_fVal > _baseVal) {\n      uint256 _delta = _fVal - _baseVal;\n\n      _maxBaseIn = _delta.div(state.baseNav.mul(PRECISION + (_incentiveRatio * _newCollateralRatio) / PRECISION));\n      _maxXTokenMintable = _maxBaseIn.mul(state.baseNav).mul(PRECISION + _incentiveRatio).div(\n        state.xNav.mul(PRECISION)\n      );\n    }\n  }\n\n  /// @notice Compute the amount of fToken needed to reach the new collateral ratio.\n  ///\n  /// @dev If the current collateral ratio >= new collateral ratio, we should return 0.\n  ///\n  /// @param state The current state.\n  /// @param _newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return _maxBaseOut The amount of base token redeemed.\n  /// @return _maxFTokenRedeemable The amount of fToken needed.\n  function maxRedeemableFToken(SwapState memory state, uint256 _newCollateralRatio)\n    internal\n    pure\n    returns (uint256 _maxBaseOut, uint256 _maxFTokenRedeemable)\n  {\n    //  n * v = nf * vf + nx * vx\n    //  (n - dn) * v = (nf - df) * vf + nx * vx\n    //  (n - dn) * v / ((nf - df) * vf) = ncr\n    // =>\n    //  n * v - dn * v = ncr * nf * vf - ncr * dn * v\n    //  n * v - df * vf = ncr * nf * vf - ncr * df * vf\n    // =>\n    //  df = (ncr * nf * vf - n * v) / ((ncr - 1) * vf)\n    //  dn = (ncr * nf * vf - n * v) / ((ncr - 1) * v)\n\n    uint256 _baseVal = state.baseSupply.mul(state.baseNav).mul(PRECISION);\n    uint256 _fVal = _newCollateralRatio.mul(state.fSupply).mul(state.fNav);\n\n    if (_fVal > _baseVal) {\n      uint256 _delta = _fVal - _baseVal;\n      _newCollateralRatio = _newCollateralRatio.sub(PRECISION);\n\n      _maxFTokenRedeemable = _delta.div(_newCollateralRatio.mul(state.fNav));\n      _maxBaseOut = _delta.div(_newCollateralRatio.mul(state.baseNav));\n    }\n  }\n\n  /// @notice This function is used to compute the maximum amount of fToken that can be minted without adding base token to keep a minimum collateral ratio.\n  /// @param state The current state of the swap.\n  /// @param _newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return _maxFTokenRedeemable The maximum amount of fToken that can be minted without adding base token to keep a minimum collateral ratio.\n  function maxMintableFTokenWithoutBaseToken(SwapState memory state, uint256 _newCollateralRatio)\n    internal\n    pure\n    returns (uint256 _maxFTokenRedeemable)\n  {\n    // CR = n * v / nf * vf\n    // CR* = n * v / nf* * vf\n    // nf* = nf + df\n    // nf* = n * v / CR* * vf\n    // nf + df = n * v / CR* * vf\n    // =>\n    // df = n * v / CR* * vf - nf\n\n    uint256 _baseVal = state.baseSupply.mul(state.baseNav).mul(PRECISION);\n    uint256 _fValAtTarget = _newCollateralRatio.mul(state.fSupply).mul(state.fNav);\n    // if there is not enough base compared to the amount of fToken minted, stop.\n    if (_baseVal <= _fValAtTarget) {\n      return 0;\n    }\n\n    _maxFTokenRedeemable = _baseVal.div(_newCollateralRatio.mul(state.fNav));\n    _maxFTokenRedeemable = _maxFTokenRedeemable.sub(state.fSupply);\n  }\n\n  /// @notice Compute the amount of base token needed to reach the new collateral ratio.\n  ///\n  /// @dev If the current collateral ratio <= new collateral ratio, we should return 0.\n  ///\n  /// @param state The current state.\n  /// @param _newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return _maxBaseIn The amount of base token needed. round UP to ensure at least the target collateral ratio.\n  function maxBaseDonationForCollateralRatio(SwapState memory state, uint256 candidateNav, uint256 _newCollateralRatio) internal pure returns (uint256 _maxBaseIn) {\n    // Calculation of collateral to add to get to a new collateral ratio\n    // CR* = (n + dn) * v / (nf * vf)\n    // =>\n    // dn = (ncr * nf * vf) / v - n\n    // Ceil UP\n    // dn = ((ncr * nf * vf) + v - 1) / v - n\n\n    // Using ceil value which represents the possible value of stablecoin nav.\n    uint256 _numerator = _newCollateralRatio.mul(state.fSupply).mul(candidateNav);\n    uint256 _denominator = state.baseNav.mul(PRECISION); // not 0\n    _maxBaseIn = _numerator.add(_denominator).sub(1).div(_denominator);\n    // This means that the current collateral ratio is already greater than the target collateral ratio.\n    if (_maxBaseIn < state.baseSupply) {\n      return 0;\n    }\n    _maxBaseIn = _maxBaseIn.sub(state.baseSupply);\n  }\n\n  /// @notice Compute the amount of xToken needed to reach the new collateral ratio.\n  ///\n  /// @dev If the current collateral ratio <= new collateral ratio, we should return 0.\n  ///\n  /// @param state The current state.\n  /// @param _newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return _maxBaseOut The amount of base token redeemed.\n  /// @return _maxXTokenRedeemable The amount of xToken needed.\n  function maxRedeemableXToken(SwapState memory state, uint256 _newCollateralRatio)\n    internal\n    pure\n    returns (uint256 _maxBaseOut, uint256 _maxXTokenRedeemable)\n  {\n    //  n * v = nf * vf + nx * vx\n    //  (n - dn) * v = nf * vf + (nx - dx) * vx\n    //  (n - dn) * v / (nf * vf) = ncr\n    // =>\n    //  n * v - dn * v = ncr * nf * vf\n    //  n * v - dx * vx = ncr * nf * vf\n    // =>\n    //  dn = (n * v - ncr * nf * vf) / v\n    //  dx = (n * v - ncr * nf * vf) / vx\n\n    uint256 _baseVal = state.baseSupply.mul(state.baseNav).mul(PRECISION);\n    uint256 _fVal = _newCollateralRatio.mul(state.fSupply).mul(state.fNav);\n\n    if (_baseVal > _fVal) {\n      uint256 _delta = _baseVal - _fVal;\n\n      _maxXTokenRedeemable = _delta.div(state.xNav.mul(PRECISION));\n      _maxBaseOut = _delta.div(state.baseNav.mul(PRECISION));\n    }\n  }\n\n  /// @notice Compute the maximum amount of fToken can be liquidated.\n  ///\n  /// @dev If the current collateral ratio >= new collateral ratio, we should return 0.\n  ///\n  /// @param state The current state.\n  /// @param _newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @param _incentiveRatio The extra incentive ratio, multipled by 1e18.\n  /// @return _maxBaseOut The maximum amount of base token can liquidate, without incentive.\n  /// @return _maxFTokenLiquidatable The maximum amount of fToken can be liquidated.\n  function maxLiquidatable(\n    SwapState memory state,\n    uint256 _newCollateralRatio,\n    uint256 _incentiveRatio\n  ) internal pure returns (uint256 _maxBaseOut, uint256 _maxFTokenLiquidatable) {\n    //  n * v = nf * vf + nx * vx\n    //  (n - dn) * v = (nf - df) * (vf - dvf) + nx * vx\n    //  (n - dn) * v / ((nf - df) * (vf - dvf)) = ncr\n    //  dn * v = nf * dvf + df * (vf - dvf)\n    //  dn * v = df * vf * (1 + lambda)\n    // =>\n    //  n * v - dn * v = ncf * nf * vf - ncr * dn * v\n    // =>\n    //  dn = (ncr * nf * vf - n * v) / ((ncr - 1) * v)\n    //  df = (dn * v) / ((1 + lambda) * vf)\n\n    uint256 _fVal = _newCollateralRatio.mul(state.fSupply).mul(state.fNav);\n    uint256 _baseVal = state.baseSupply.mul(state.baseNav).mul(PRECISION);\n\n    if (_fVal > _baseVal) {\n      uint256 _delta = _fVal - _baseVal;\n      _newCollateralRatio = _newCollateralRatio.sub(PRECISION);\n\n      _maxBaseOut = _delta.div(state.baseNav.mul(_newCollateralRatio));\n      _maxFTokenLiquidatable = _delta.div(_newCollateralRatio).mul(PRECISION).div(\n        (PRECISION + _incentiveRatio).mul(state.fNav)\n      );\n    }\n  }\n\n  /// @notice Mint fToken and xToken according to current collateral ratio.\n  /// @param state The current state.\n  /// @param _baseIn The amount of base token supplied.\n  /// @return _fTokenOut The amount of fToken expected.\n  /// @return _xTokenOut The amount of xToken expected.\n  function mint(SwapState memory state, uint256 _baseIn)\n    internal\n    pure\n    returns (uint256 _fTokenOut, uint256 _xTokenOut)\n  {\n    //  n * v = nf * vf + nx * vx\n    //  (n + dn) * v = (nf + df) * vf + (nx + dx) * vx\n    //  ((nf + df) * vf) / ((n + dn) * v) = (nf * vf) / (n * v)\n    //  ((nx + dx) * vx) / ((n + dn) * v) = (nx * vx) / (n * v)\n    // =>\n    //   df = nf * dn / n\n    //   dx = nx * dn / n\n    _fTokenOut = state.fSupply.mul(_baseIn).div(state.baseSupply);\n    _xTokenOut = state.xSupply.mul(_baseIn).div(state.baseSupply);\n  }\n\n  /// @notice Mint fToken.\n  /// @param state The current state.\n  /// @param _baseIn The amount of base token supplied.\n  /// @return _fTokenOut The amount of fToken expected.\n  function mintFToken(SwapState memory state, uint256 _baseIn) internal pure returns (uint256 _fTokenOut) {\n    //  n * v = nf * vf + nx * vx\n    //  (n + dn) * v = (nf + df) * vf + nx * vx\n    // =>\n    //  df = dn * v / vf\n    _fTokenOut = _baseIn.mul(state.baseNav).div(state.fNav);\n  }\n\n  /// @notice Mint xToken.\n  /// @param state The current state.\n  /// @param _baseIn The amount of base token supplied.\n  /// @return _xTokenOut The amount of xToken expected.\n  function mintXToken(SwapState memory state, uint256 _baseIn) internal pure returns (uint256 _xTokenOut) {\n    //  n * v = nf * vf + nx * vx\n    //  (n + dn) * v = nf * vf + (nx + dx) * vx\n    // =>\n    //  dx = (dn * v * nx) / (n * v - nf * vf)\n    _xTokenOut = _baseIn.mul(state.baseNav).mul(state.xSupply);\n    _xTokenOut = _xTokenOut.div(state.baseSupply.mul(state.baseNav).sub(state.fSupply.mul(state.fNav)));\n  }\n\n  /// @notice Mint xToken with given incentive.\n  /// @param state The current state.\n  /// @param _baseIn The amount of base token supplied.\n  /// @param _incentiveRatio The extra incentive given, multiplied by 1e18.\n  /// @return _xTokenOut The amount of xToken expected.\n  /// @return _fDeltaNav The change for nav of fToken.\n  function mintXToken(\n    SwapState memory state,\n    uint256 _baseIn,\n    uint256 _incentiveRatio\n  ) internal pure returns (uint256 _xTokenOut, uint256 _fDeltaNav) {\n    //  n * v = nf * vf + nx * vx\n    //  (n + dn) * v = nf * (vf - dvf) + (nx + dx) * vx\n    // =>\n    //  dn * v = dx * vx - nf * dvf\n    //  nf * dvf = lambda * dn * v\n    // =>\n    //  dx * vx = (1 + lambda) * dn * v\n    //  dvf = lambda * dn * v / nf\n\n    uint256 _deltaVal = _baseIn.mul(state.baseNav);\n\n    _xTokenOut = _deltaVal.mul(PRECISION + _incentiveRatio).div(PRECISION);\n    _xTokenOut = _xTokenOut.div(state.xNav);\n\n    _fDeltaNav = _deltaVal.mul(_incentiveRatio).div(PRECISION);\n    _fDeltaNav = _fDeltaNav.div(state.fSupply);\n  }\n\n  /// @notice Redeem base token with fToken and xToken.\n  /// @param state The current state.\n  /// @param _fTokenIn The amount of fToken supplied.\n  /// @param _xTokenIn The amount of xToken supplied.\n  /// @return _baseOut The amount of base token expected.\n  function redeem(\n    SwapState memory state,\n    uint256 _fTokenIn,\n    uint256 _xTokenIn\n  ) internal pure returns (uint256 _baseOut) {\n    uint256 _xVal = state.baseSupply.mul(state.baseNav).sub(state.fSupply.mul(state.fNav));\n\n    //  n * v = nf * vf + nx * vx\n    //  (n - dn) * v = (nf - df) * vf + (nx - dx) * vx\n    // =>\n    //  dn = (df * vf + dx * (n * v - nf * vf) / nx) / v\n\n    if (state.xSupply == 0) {\n      _baseOut = _fTokenIn.mul(state.fNav).div(state.baseNav);\n    } else {\n      _baseOut = _fTokenIn.mul(state.fNav);\n      _baseOut = _baseOut.add(_xTokenIn.mul(_xVal).div(state.xSupply));\n      _baseOut = _baseOut.div(state.baseNav);\n    }\n  }\n\n  /// @notice Redeem base token with fToken and given incentive.\n  /// @param state The current state.\n  /// @param _fTokenIn The amount of fToken supplied.\n  /// @param _incentiveRatio The extra incentive given, multiplied by 1e18.\n  /// @return _baseOut The amount of base token expected.\n  /// @return _fDeltaNav The change for nav of fToken.\n  function liquidateWithIncentive(\n    SwapState memory state,\n    uint256 _fTokenIn,\n    uint256 _incentiveRatio\n  ) internal pure returns (uint256 _baseOut, uint256 _fDeltaNav) {\n    //  n * v = nf * vf + nx * vx\n    //  (n - dn) * v = (nf - df) * (vf - dvf) + nx * vx\n    // =>\n    //  dn * v = nf * dvf + df * (vf - dvf)\n    //  dn * v = df * vf * (1 + lambda)\n    // =>\n    //  dn = df * vf * (1 + lambda) / v\n    //  dvf = lambda * (df * vf) / (nf - df)\n\n    uint256 _fDeltaVal = _fTokenIn.mul(state.fNav);\n\n    _baseOut = _fDeltaVal.mul(PRECISION + _incentiveRatio).div(PRECISION);\n    _baseOut = _baseOut.div(state.baseNav);\n\n    _fDeltaNav = _fDeltaVal.mul(_incentiveRatio).div(PRECISION);\n    _fDeltaNav = _fDeltaNav.div(state.fSupply.sub(_fTokenIn));\n  }\n\n  /// @notice Compute current leverage ratio for xToken.\n  /// @param state The current state.\n  /// @param beta The beta value for fToken.\n  /// @param earningRatio The current accumulated earnings ratio.\n  /// @return ratio The current leverage ratio.\n  function leverageRatio(\n    SwapState memory state,\n    uint256 beta,\n    int256 earningRatio\n  ) internal pure returns (uint256 ratio) {\n    // (1 - rho * beta * (1 + r)) / (1 - rho)\n    // RHO would be infinity so cap to max.\n    if (state.baseSupply.mul(state.baseNav) == 0) return MAX_LEVERAGE_RATIO;\n    uint256 rho = state.fSupply.mul(state.fNav).mul(PRECISION).div(state.baseSupply.mul(state.baseNav));\n    if (rho >= PRECISION) {\n      return MAX_LEVERAGE_RATIO;\n    }\n    uint256 x = rho.mul(beta).mul(uint256(PRECISION_I256 + earningRatio)).div(PRECISION * PRECISION);\n    ratio = PRECISION.sub(x).mul(PRECISION).div(PRECISION - rho);\n    if (ratio > MAX_LEVERAGE_RATIO) ratio = MAX_LEVERAGE_RATIO;\n  }\n}\n"},{"file_path":"contracts/interfaces/f(x)/IAssetStrategy.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0 || ^0.8.0;\n\ninterface IAssetStrategy {\n  /// @notice Withdraw assets from strategy to treasury.\n  /// @param amount The amount of token to withdraw.\n  function withdrawToTreasury(uint256 amount) external;\n}\n"},{"file_path":"contracts/interfaces/f(x)/IFxFractionalToken.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0 || ^0.8.0;\n\ninterface IFxFractionalToken {\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the net asset value for the token.\n  function nav() external view returns (uint256);\n\n  /// @notice Compute the new nav with multiple.\n  /// @param multiple The multiplier used to update the nav, multiplied by 1e18.\n  /// @return newNav The new net asset value of the token.\n  function getNav(int256 multiple) external view returns (uint256 newNav);\n\n  /// @notice Compute the new nav with multiple.\n  /// @param multiple The multiplier used to update the nav, multiplied by 1e18.\n  /// @return newNav The new net asset value of the token.\n  function getCandidateNav(int256 multiple) external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Update the net asset value by times `(1 + multiple / 1e18)`.\n  /// @param multiple The multiplier used to update the nav, multiplied by 1e18.\n  /// @return newNav The new net asset value of the token.\n  function updateNav(int256 multiple) external returns (uint256 newNav);\n\n  /// @notice Update the net asset value by direct setting.\n  /// @param newNav The new net asset value, multiplied by 1e18.\n  function setNav(uint256 newNav) external;\n\n  /// @notice Mint some token to someone.\n  /// @param to The address of recipient.\n  /// @param amount The amount of token to mint.\n  function mint(address to, uint256 amount) external;\n\n  /// @notice Burn some token from someone.\n  /// @param from The address of owner to burn.\n  /// @param amount The amount of token to burn.\n  function burn(address from, uint256 amount) external;\n}\n"},{"file_path":"contracts/interfaces/f(x)/IFxLeveragedToken.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.6;\n\ninterface IFxLeveragedToken {\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the net asset value for the token.\n  function nav() external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Mint some token to someone.\n  /// @param to The address of recipient.\n  /// @param amount The amount of token to mint.\n  function mint(address to, uint256 amount) external;\n\n  /// @notice Burn some token from someone.\n  /// @param from The address of owner to burn.\n  /// @param amount The amount of token to burn.\n  function burn(address from, uint256 amount) external;\n}\n"},{"file_path":"contracts/interfaces/f(x)/IFxRateProvider.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0 || ^0.8.0;\n\ninterface IFxRateProvider {\n  /// @notice Return the exchange rate from wrapped token to underlying rate,\n  /// multiplied by 1e18.\n  function getRate() external view returns (uint256);\n}\n"},{"file_path":"contracts/interfaces/f(x)/IFxTreasury.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0 || ^0.8.0;\n\ninterface IFxTreasury {\n  /**********\n   * Events *\n   **********/\n\n  /// @notice Emitted when the net asset value is updated.\n  /// @param price The new price of base token.\n  /// @param fNav The new net asset value of fToken.\n  event ProtocolSettle(uint256 price, uint256 fNav);\n\n  /*********\n   * Enums *\n   *********/\n\n  enum MintOption {\n    Both,\n    FToken,\n    XToken\n  }\n\n  /*************************\n   * Public View Functions *\n   *************************/\n\n  /// @notice Return the address of base token.\n  function baseToken() external view returns (address);\n\n  /// @notice Return the address fractional base token.\n  function fToken() external view returns (address);\n\n  /// @notice Return the address leveraged base token.\n  function xToken() external view returns (address);\n\n  /// @notice Return the address of strategy contract.\n  function strategy() external view returns (address);\n\n  /// @notice The last updated permissioned base token price.\n  function lastPermissionedPrice() external view returns (uint256);\n\n  /// @notice Return the total amount of base token deposited.\n  function totalBaseToken() external view returns (uint256);\n\n  /// @notice Return the total amount of base token managed by strategy.\n  function strategyUnderlying() external view returns (uint256);\n\n  /// @notice Return the current collateral ratio of fToken, multipled by 1e18.\n  function collateralRatio() external view returns (uint256);\n\n  /// @notice Convert unwrapped token amount to wrapped token amount.\n  /// @param amount The unwrapped token amount.\n  function convertToWrapped(uint256 amount) external view returns (uint256);\n\n  /// @notice Convert wrapped token amount to unwrapped token amount.\n  /// @param amount The wrapped token amount.\n  function convertToUnwrapped(uint256 amount) external view returns (uint256);\n\n  /// @notice Return current nav for base token, fToken and xToken.\n  /// @return baseNav The nav for base token.\n  /// @return fNav The nav for fToken.\n  /// @return xNav The nav for xToken.\n  function getCurrentNav()\n    external\n    view\n    returns (\n      uint256 baseNav,\n      uint256 fNav,\n      uint256 xNav\n    );\n\n  /// @notice Compute the amount of base token needed to reach the new collateral ratio.\n  /// @param newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return maxBaseIn The amount of base token needed.\n  /// @return maxFTokenMintable The amount of fToken can be minted.\n  function maxMintableFToken(uint256 newCollateralRatio)\n    external\n    view\n    returns (uint256 maxBaseIn, uint256 maxFTokenMintable);\n\n  /// @notice Compute the amount of fToken can be minted without adding base to reach the new collateral ratio.\n  /// @param newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return maxFTokenMintable The amount of fToken can be minted without adding base.\n  function maxMintableFTokenWithoutBaseToken(uint256 newCollateralRatio)\n    external\n    view\n    returns (uint256 maxFTokenMintable);\n\n  /// @notice Compute the amount of base token needed to reach the new collateral ratio.\n  /// @param newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return maxBaseIn The amount of base token needed.\n  /// @return maxXTokenMintable The amount of xToken can be minted.\n  function maxMintableXToken(uint256 newCollateralRatio)\n    external\n    view\n    returns (uint256 maxBaseIn, uint256 maxXTokenMintable);\n\n  /// @notice Compute the amount of base token needed to reach the new collateral ratio, with incentive.\n  /// @param newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @param incentiveRatio The extra incentive ratio, multipled by 1e18.\n  /// @return maxBaseIn The amount of base token needed.\n  /// @return maxXTokenMintable The amount of xToken can be minted.\n  function maxMintableXTokenWithIncentive(uint256 newCollateralRatio, uint256 incentiveRatio)\n    external\n    view\n    returns (uint256 maxBaseIn, uint256 maxXTokenMintable);\n\n  /// @notice Compute the amount of fToken needed to reach the new collateral ratio.\n  /// @param newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return maxBaseOut The amount of base token redeemed.\n  /// @return maxFTokenRedeemable The amount of fToken needed.\n  function maxRedeemableFToken(uint256 newCollateralRatio)\n    external\n    view\n    returns (uint256 maxBaseOut, uint256 maxFTokenRedeemable);\n\n  /// @notice Compute the amount of xToken needed to reach the new collateral ratio.\n  /// @param newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return maxBaseOut The amount of base token redeemed.\n  /// @return maxXTokenRedeemable The amount of xToken needed.\n  function maxRedeemableXToken(uint256 newCollateralRatio)\n    external\n    view\n    returns (uint256 maxBaseOut, uint256 maxXTokenRedeemable);\n\n  /// @notice Return the maximum amount of base token that can be donated to reach the new collateral ratio.\n  /// @param newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @return maxBaseIn The amount of base token needed.\n  function maxBaseForCollateralRatio(uint256 newCollateralRatio) external view returns (uint256 maxBaseIn);\n\n  /// @notice Compute the maximum amount of fToken can be liquidated.\n  /// @param newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @param incentiveRatio The extra incentive ratio, multipled by 1e18.\n  /// @return maxBaseOut The maximum amount of base token can liquidate, without incentive.\n  /// @return maxFTokenLiquidatable The maximum amount of fToken can be liquidated.\n  function maxLiquidatable(uint256 newCollateralRatio, uint256 incentiveRatio)\n    external\n    view\n    returns (uint256 maxBaseOut, uint256 maxFTokenLiquidatable);\n\n  /// @notice Return the exponential moving average of the leverage ratio.\n  function leverageRatio() external view returns (uint256);\n\n  /****************************\n   * Public Mutated Functions *\n   ****************************/\n\n  /// @notice Mint fToken and xToken with some base token.\n  /// @param baseIn The amount of base token deposited.\n  /// @param recipient The address of receiver.\n  /// @param option The mint option, xToken or fToken or both.\n  /// @return fTokenOut The amount of fToken minted.\n  /// @return xTokenOut The amount of xToken minted.\n  function mint(\n    uint256 baseIn,\n    address recipient,\n    MintOption option\n  ) external returns (uint256 fTokenOut, uint256 xTokenOut);\n\n  /// @notice Redeem fToken and xToken to base tokne.\n  /// @param fTokenIn The amount of fToken to redeem.\n  /// @param xTokenIn The amount of xToken to redeem.\n  /// @param owner The owner of the fToken or xToken.\n  /// @param baseOut The amount of base token redeemed.\n  function redeem(\n    uint256 fTokenIn,\n    uint256 xTokenIn,\n    address owner\n  ) external returns (uint256 baseOut);\n\n  /// @notice Add some base token to mint xToken with incentive.\n  /// @param baseIn The amount of base token deposited.\n  /// @param incentiveRatio The incentive ratio.\n  /// @param recipient The address of receiver.\n  /// @return xTokenOut The amount of xToken minted.\n  function addBaseToken(\n    uint256 baseIn,\n    uint256 incentiveRatio,\n    address recipient\n  ) external returns (uint256 xTokenOut);\n\n  /// @notice Donate base token to the treasury.\n  /// @param baseIn The amount of base token to donate.\n  function donateBaseToken(uint256 baseIn) external;\n\n  /// @notice Mint fToken without adding base token by targeting a collateral ratio.\n  /// @param newCollateralRatio The target collateral ratio, multipled by 1e18.\n  /// @param recipient The address of receiver.\n  /// @return fTokenOut The amount of fToken minted.\n  function mintFTokenWithoutBaseToken(uint256 newCollateralRatio, address recipient)\n    external\n    returns (uint256 fTokenOut);\n\n  /// @notice Liquidate fToken to base token with incentive.\n  /// @param fTokenIn The amount of fToken to liquidate.\n  /// @param incentiveRatio The incentive ratio.\n  /// @param owner The owner of the fToken.\n  /// @param baseOut The amount of base token liquidated.\n  function liquidate(\n    uint256 fTokenIn,\n    uint256 incentiveRatio,\n    address owner\n  ) external returns (uint256 baseOut);\n\n  /// @notice Settle the nav of base token, fToken and xToken.\n  function protocolSettle() external;\n\n  /// @notice Transfer some base token to strategy contract.\n  /// @param amount The amount of token to transfer.\n  function transferToStrategy(uint256 amount) external;\n\n  /// @notice Notify base token profit from strategy contract.\n  /// @param amount The amount of base token.\n  function notifyStrategyProfit(uint256 amount) external;\n\n  /// @notice Return the current price of base token.\n  function currentBaseTokenPrice() external view returns (uint256);\n}\n"},{"file_path":"contracts/price-oracle/interfaces/IRWAVaultPriceOracle.sol","source_code":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0 || ^0.8.0;\n\n/// @title IRWAVaultPriceOracle\n/// @notice Interface for RWA Vault price oracle by Instruxi.\ninterface IRWAVaultPriceOracle {\n  function getSharePrice() external view returns (bool isValid, uint256 sharePrice);\n}\n"}],"certified":false,"conflicting_implementations":null,"abi":[{"inputs":[{"internalType":"uint256","name":"_initialMintRatio","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fNav","type":"uint256"}],"name":"ProtocolSettle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseTokenCap","type":"uint256"}],"name":"UpdateBaseTokenCap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"beta","type":"uint256"}],"name":"UpdateBeta","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"priceOracle","type":"address"},{"indexed":false,"internalType":"uint256","name":"priceOracleDecimals","type":"uint256"}],"name":"UpdatePriceOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rateProvider","type":"address"}],"name":"UpdateRateProvider","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"UpdateSettleWhitelist","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"strategy","type":"address"}],"name":"UpdateStrategy","type":"event"},{"inputs":[{"internalType":"uint256","name":"_baseIn","type":"uint256"},{"internalType":"uint256","name":"_incentiveRatio","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"addBaseToken","outputs":[{"internalType":"uint256","name":"_xTokenOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"baseToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseTokenCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"beta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"convertToUnwrapped","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"convertToWrapped","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentBaseTokenPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_baseIn","type":"uint256"}],"name":"donateBaseToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emaLeverageRatio","outputs":[{"internalType":"uint40","name":"lastTime","type":"uint40"},{"internalType":"uint24","name":"sampleInterval","type":"uint24"},{"internalType":"uint96","name":"lastValue","type":"uint96"},{"internalType":"uint96","name":"lastEmaValue","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentNav","outputs":[{"internalType":"uint256","name":"_baseNav","type":"uint256"},{"internalType":"uint256","name":"_fNav","type":"uint256"},{"internalType":"uint256","name":"_xNav","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_market","type":"address"},{"internalType":"address","name":"_baseToken","type":"address"},{"internalType":"address","name":"_fToken","type":"address"},{"internalType":"address","name":"_xToken","type":"address"},{"internalType":"address","name":"_priceOracle","type":"address"},{"internalType":"uint256","name":"_priceOracleDecimals","type":"uint256"},{"internalType":"uint256","name":"_beta","type":"uint256"},{"internalType":"uint256","name":"_baseTokenCap","type":"uint256"},{"internalType":"address","name":"_rateProvider","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initializePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"sampleInterval","type":"uint24"}],"name":"initializeV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastPermissionedPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"leverageRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fTokenIn","type":"uint256"},{"internalType":"uint256","name":"_incentiveRatio","type":"uint256"},{"internalType":"address","name":"_owner","type":"address"}],"name":"liquidate","outputs":[{"internalType":"uint256","name":"_baseOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"market","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCollateralRatio","type":"uint256"}],"name":"maxBaseForCollateralRatio","outputs":[{"internalType":"uint256","name":"_maxBaseIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCollateralRatio","type":"uint256"},{"internalType":"uint256","name":"_incentiveRatio","type":"uint256"}],"name":"maxLiquidatable","outputs":[{"internalType":"uint256","name":"_maxBaseOut","type":"uint256"},{"internalType":"uint256","name":"_maxFTokenLiquidatable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCollateralRatio","type":"uint256"}],"name":"maxMintableFToken","outputs":[{"internalType":"uint256","name":"_maxBaseIn","type":"uint256"},{"internalType":"uint256","name":"_maxFTokenMintable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCollateralRatio","type":"uint256"}],"name":"maxMintableFTokenWithoutBaseToken","outputs":[{"internalType":"uint256","name":"_maxFTokenMintable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCollateralRatio","type":"uint256"}],"name":"maxMintableXToken","outputs":[{"internalType":"uint256","name":"_maxBaseIn","type":"uint256"},{"internalType":"uint256","name":"_maxXTokenMintable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCollateralRatio","type":"uint256"},{"internalType":"uint256","name":"_incentiveRatio","type":"uint256"}],"name":"maxMintableXTokenWithIncentive","outputs":[{"internalType":"uint256","name":"_maxBaseIn","type":"uint256"},{"internalType":"uint256","name":"_maxXTokenMintable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCollateralRatio","type":"uint256"}],"name":"maxRedeemableFToken","outputs":[{"internalType":"uint256","name":"_maxBaseOut","type":"uint256"},{"internalType":"uint256","name":"_maxFTokenRedeemable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCollateralRatio","type":"uint256"}],"name":"maxRedeemableXToken","outputs":[{"internalType":"uint256","name":"_maxBaseOut","type":"uint256"},{"internalType":"uint256","name":"_maxXTokenRedeemable","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_baseIn","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"enum IFxTreasury.MintOption","name":"_option","type":"uint8"}],"name":"mint","outputs":[{"internalType":"uint256","name":"_fTokenOut","type":"uint256"},{"internalType":"uint256","name":"_xTokenOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCollateralRatio","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"}],"name":"mintFTokenWithoutBaseToken","outputs":[{"internalType":"uint256","name":"_fTokenOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"notifyStrategyProfit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceOracleDecimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolSettle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rateProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fTokenIn","type":"uint256"},{"internalType":"uint256","name":"_xTokenIn","type":"uint256"},{"internalType":"address","name":"_owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"_baseOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"settleWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategyUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBaseToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferToStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_baseTokenCap","type":"uint256"}],"name":"updateBaseTokenCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_beta","type":"uint256"}],"name":"updateBeta","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"_sampleInterval","type":"uint24"}],"name":"updateEMASampleInterval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_priceOracle","type":"address"},{"internalType":"uint256","name":"_priceOracleDecimals","type":"uint256"}],"name":"updatePriceOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rateProvider","type":"address"}],"name":"updateRateProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"updateSettleWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"updateStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"xToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}],"is_changed_bytecode":false,"is_partially_verified":false,"constructor_args":"0x0000000000000000000000000000000000000000000000000c7d713b49da0000"}