ETH Price: $2,541.70 (+0.11%)

Contract

0x6b8A1e78Ac707F9b0b5eB4f34B02D9af84D2b689

Overview

ETH Balance

0 ETH

ETH Value

$0.00

Sponsored

Transaction Hash
Method
Block
From
To
0x608060401104490522023-10-05 9:08:01351 days ago1696496881IN
 Create: IdleCDOOptimism
0 ETH0.0019688660710.05

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
IdleCDOOptimism

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 170 runs

Other Settings:
default evmVersion
File 1 of 24 : IdleCDOOptimism.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.10;

import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

import "../interfaces/IERC20Detailed.sol";
import "../IdleCDO.sol";

/// @title A perpetual tranche implementation, deployed on Optimism
/// @author Idle Labs Inc.
/// @notice More info and high level overview in the README
/// @dev The contract is upgradable, to add storage slots, create IdleCDOStorageVX and inherit from IdleCDOStorage, then update the definitaion below
contract IdleCDOOptimism is IdleCDO {
  using SafeERC20Upgradeable for IERC20Detailed;

  /// @notice used by child contracts (cdo variants) if anything needs to be done on/after init
  function _additionalInit() internal override {
    weth = address(0x4200000000000000000000000000000000000006);
    feeReceiver = address(0xFDbB4d606C199F091143BD604C85c191a526fbd0); // treasury multisig
    releaseBlocksPeriod = 302400; // 60 * 60 * 24 / 2 * 7 = ~1 week (blocktime 2s)
  }

  /// @notice method used to sell `_rewardToken` for `_token` on uniswap
  /// @param _rewardToken address of the token to sell
  /// @param _path to buy
  /// @param _amount of `_rewardToken` to sell
  /// @param _minAmount min amount of `_token` to buy
  /// @return _amount of _rewardToken sold
  /// @return _amount received for the sell
  function _sellReward(address _rewardToken, bytes memory _path, uint256 _amount, uint256 _minAmount)
    internal override
    returns (uint256, uint256) {
    // If 0 is passed as sell amount, we get the whole contract balance
    if (_amount == 0) {
      _amount = _contractTokenBalance(_rewardToken);
    }
    if (_amount == 0) {
      return (0, 0);
    }
  
    // Uni v3 swap
    ISwapRouter _swapRouter = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
    IERC20Detailed(_rewardToken).safeIncreaseAllowance(address(_swapRouter), _amount);
    // multi hop swap params
    ISwapRouter.ExactInputParams memory params = ISwapRouter.ExactInputParams({
      path: _path,
      recipient: address(this),
      deadline: block.timestamp + 100,
      amountIn: _amount,
      amountOutMinimum: _minAmount
    });
    // do the swap and return the amount swapped and the amount received
    return (_amount, _swapRouter.exactInput(params));
  }
}

File 2 of 24 : ISwapRouter.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;

import '@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol';

/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
    struct ExactInputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);

    struct ExactInputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountIn;
        uint256 amountOutMinimum;
    }

    /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
    /// @return amountOut The amount of the received token
    function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);

    struct ExactOutputSingleParams {
        address tokenIn;
        address tokenOut;
        uint24 fee;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
        uint160 sqrtPriceLimitX96;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another token
    /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn);

    struct ExactOutputParams {
        bytes path;
        address recipient;
        uint256 deadline;
        uint256 amountOut;
        uint256 amountInMaximum;
    }

    /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
    /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
    /// @return amountIn The amount of the input token
    function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn);
}

File 3 of 24 : IUniswapV2Router02.sol
pragma solidity >=0.6.2;

import './IUniswapV2Router01.sol';

interface IUniswapV2Router02 is IUniswapV2Router01 {
    function removeLiquidityETHSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountETH);
    function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountETH);

    function swapExactTokensForTokensSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
    function swapExactETHForTokensSupportingFeeOnTransferTokens(
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external payable;
    function swapExactTokensForETHSupportingFeeOnTransferTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external;
}

File 4 of 24 : SafeERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20Upgradeable.sol";
import "../extensions/IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20Upgradeable {
    using AddressUpgradeable for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20Upgradeable token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20Upgradeable token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20Upgradeable token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20Upgradeable token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20PermitUpgradeable token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20Upgradeable token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && AddressUpgradeable.isContract(address(token));
    }
}

File 5 of 24 : IERC20Detailed.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";

interface IERC20Detailed is IERC20Upgradeable {
  function name() external view returns(string memory);
  function symbol() external view returns(string memory);
  function decimals() external view returns(uint256);
}

File 6 of 24 : IdleCDO.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.10;

import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
import '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";

import "./interfaces/IIdleCDOStrategy.sol";
import "./interfaces/IERC20Detailed.sol";

import "./GuardedLaunchUpgradable.sol";
import "./IdleCDOTranche.sol";
import "./IdleCDOStorage.sol";

/// @title A perpetual tranche implementation
/// @author Idle Labs Inc.
/// @notice More info and high level overview in the README
/// @dev The contract is upgradable, to add storage slots, create IdleCDOStorageVX and inherit from IdleCDOStorage, then update the definitaion below
contract IdleCDO is PausableUpgradeable, GuardedLaunchUpgradable, IdleCDOStorage {
  using SafeERC20Upgradeable for IERC20Detailed;

  // ERROR MESSAGES:
  // 0 = is 0
  // 1 = already initialized
  // 2 = Contract limit reached
  // 3 = Tranche withdraw not allowed (Paused or in shutdown)
  // 4 = Default, wait shutdown
  // 5 = Amount too low
  // 6 = Not authorized
  // 7 = Amount too high
  // 8 = Same block
  // 9 = Invalid

  // Used to prevent initialization of the implementation contract
  /// @custom:oz-upgrades-unsafe-allow constructor
  constructor() {
    token = address(1);
  }

  // ###################
  // Initializer
  // ###################

  /// @notice can only be called once
  /// @dev Initialize the upgradable contract
  /// @param _limit contract value limit, can be 0
  /// @param _guardedToken underlying token
  /// @param _governanceFund address where funds will be sent in case of emergency
  /// @param _owner guardian address (can pause, unpause and call emergencyShutdown)
  /// @param _rebalancer rebalancer address
  /// @param _strategy strategy address
  /// @param _trancheAPRSplitRatio trancheAPRSplitRatio value
  /// @param // deprecated
  /// @param // deprecated _incentiveTokens array of addresses for incentive tokens
  function initialize(
    uint256 _limit, address _guardedToken, address _governanceFund, address _owner, // GuardedLaunch args
    address _rebalancer,
    address _strategy,
    uint256 _trancheAPRSplitRatio, // for AA tranches, so eg 10000 means 10% interest to AA and 90% BB
    uint256, // Deprecated
    address[] memory // Deprecated
  ) external initializer {
    require(token == address(0), '1');
    require(_rebalancer != address(0), '0');
    require(_strategy != address(0), '0');
    require(_guardedToken != address(0), '0');
    require( _trancheAPRSplitRatio <= FULL_ALLOC, '7');
    // Initialize contracts
    PausableUpgradeable.__Pausable_init();
    // check for _governanceFund and _owner != address(0) are inside GuardedLaunchUpgradable
    GuardedLaunchUpgradable.__GuardedLaunch_init(_limit, _governanceFund, _owner);
    // Deploy Tranches tokens
    address _strategyToken = IIdleCDOStrategy(_strategy).strategyToken();
    // get strategy token symbol (eg. idleDAI)
    string memory _symbol = IERC20Detailed(_strategyToken).symbol();
    // create tranche tokens (concat strategy token symbol in the name and symbol of the tranche tokens)
    AATranche = address(new IdleCDOTranche(_concat(string("IdleCDO AA Tranche - "), _symbol), _concat(string("AA_"), _symbol)));
    BBTranche = address(new IdleCDOTranche(_concat(string("IdleCDO BB Tranche - "), _symbol), _concat(string("BB_"), _symbol)));
    // Set CDO params
    token = _guardedToken;
    strategy = _strategy;
    strategyToken = _strategyToken;
    rebalancer = _rebalancer;
    trancheAPRSplitRatio = _trancheAPRSplitRatio;
    uint256 _oneToken = 10**(IERC20Detailed(_guardedToken).decimals());
    oneToken = _oneToken;
    uniswapRouterV2 = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
    weth = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
    // incentiveTokens = _incentiveTokens; [DEPRECATED]
    priceAA = _oneToken;
    priceBB = _oneToken;
    unlentPerc = 2000; // 2%
    // # blocks, after an harvest, during which harvested rewards gets progressively unlocked
    releaseBlocksPeriod = 6400; // about 1 day
    // Set flags
    allowAAWithdraw = true;
    allowBBWithdraw = true;
    revertIfTooLow = true;
    // skipDefaultCheck = false is the default value
    // Set allowance for strategy
    _allowUnlimitedSpend(_guardedToken, _strategy);
    _allowUnlimitedSpend(strategyToken, _strategy);
    // Save current strategy price
    lastStrategyPrice = _strategyPrice();
    // Fee params
    fee = 15000; // 15% performance fee
    feeReceiver = address(0xFb3bD022D5DAcF95eE28a6B07825D4Ff9C5b3814); // treasury multisig
    guardian = _owner;
    // feeSplit = 0; // default all to feeReceiver
    isAYSActive = true; // adaptive yield split
    minAprSplitAYS = AA_RATIO_LIM_DOWN; // AA tranche will get min 50% of the yield

    maxDecreaseDefault = 5000; // 5% decrease for triggering a default
    _additionalInit();
  }

  /// @notice used by child contracts (cdo variants) if anything needs to be done on/after init
  function _additionalInit() internal virtual {}

  // ###############
  // Public methods
  // ###############

  /// @notice pausable
  /// @dev msg.sender should approve this contract first to spend `_amount` of `token`
  /// @param _amount amount of `token` to deposit
  /// @return AA tranche tokens minted
  function depositAA(uint256 _amount) external returns (uint256) {
    return _deposit(_amount, AATranche, address(0));
  }

  /// @notice pausable in _deposit
  /// @dev msg.sender should approve this contract first to spend `_amount` of `token`
  /// @param _amount amount of `token` to deposit
  /// @return BB tranche tokens minted
  function depositBB(uint256 _amount) external returns (uint256) {
    return _deposit(_amount, BBTranche, address(0));
  }

  /// @notice pausable
  /// @dev msg.sender should approve this contract first to spend `_amount` of `token`
  /// @param _amount amount of `token` to deposit
  /// @param _referral address of the referral
  /// @return AA tranche tokens minted
  function depositAARef(uint256 _amount, address _referral) external returns (uint256) {
    return _deposit(_amount, AATranche, _referral);
  }

  /// @notice pausable in _deposit
  /// @dev msg.sender should approve this contract first to spend `_amount` of `token`
  /// @param _amount amount of `token` to deposit
  /// @param _referral address of the referral
  /// @return BB tranche tokens minted
  function depositBBRef(uint256 _amount, address _referral) external returns (uint256) {
    return _deposit(_amount, BBTranche, _referral);
  }

  /// @notice pausable in _deposit
  /// @param _amount amount of AA tranche tokens to burn
  /// @return underlying tokens redeemed
  function withdrawAA(uint256 _amount) external returns (uint256) {
    require(!paused() || allowAAWithdraw, '3');
    return _withdraw(_amount, AATranche);
  }

  /// @notice pausable
  /// @param _amount amount of BB tranche tokens to burn
  /// @return underlying tokens redeemed
  function withdrawBB(uint256 _amount) external returns (uint256) {
    require(!paused() || allowBBWithdraw, '3');
    return _withdraw(_amount, BBTranche);
  }

  // ###############
  // Views
  // ###############

  /// @param _tranche tranche address
  /// @return tranche price, in underlyings, at the last interaction (not considering interest earned 
  /// since last interaction)
  function tranchePrice(address _tranche) external view returns (uint256) {
    return _tranchePrice(_tranche);
  }

  /// @notice calculates the current net TVL (in `token` terms)
  /// @dev unclaimed rewards (gov tokens) and `unclaimedFees` are not counted. 
  /// Harvested rewards are counted only if enough blocks have passed (`_lockedRewards`)
  function getContractValue() public override view returns (uint256) {
    address _strategyToken = strategyToken;
    uint256 strategyTokenDecimals = IERC20Detailed(_strategyToken).decimals();
    // TVL is the sum of unlent balance in the contract + the balance in lending - harvested but locked rewards - unclaimedFees
    // Balance in lending is the value of the interest bearing assets (strategyTokens) in this contract
    // TVL = (strategyTokens * strategy token price) + unlent balance - lockedRewards - unclaimedFees
    return (_contractTokenBalance(_strategyToken) * _strategyPrice() / (10**(strategyTokenDecimals))) +
            _contractTokenBalance(token) -
            _lockedRewards() -
            unclaimedFees;
  }

  /// @param _tranche tranche address
  /// @return actual apr given current ratio between AA and BB tranches
  function getApr(address _tranche) external view returns (uint256) {
    return _getApr(_tranche, _getAARatio(false));
  }

  /// @notice calculates the current AA tranches ratio
  /// @dev _virtualBalance is used to have a more accurate/recent value for the AA ratio
  /// because it calculates the balance after splitting the accrued interest since the
  /// last depositXX/withdrawXX/harvest
  /// @return AA tranches ratio (in underlying value) considering all interest
  function getCurrentAARatio() external view returns (uint256) {
    return _getAARatio(false);
  }

  /// @notice calculates the current tranches price considering the interest/loss that is yet to be splitted
  /// ie the interest/loss generated since the last update of priceAA and priceBB (done on depositXX/withdrawXX/harvest)
  /// @param _tranche address of the requested tranche
  /// @return _virtualPrice tranche price considering all interest/losses
  function virtualPrice(address _tranche) public virtual view returns (uint256 _virtualPrice) {
    // get both NAVs, because we need the total NAV anyway
    uint256 _lastNAVAA = lastNAVAA;
    uint256 _lastNAVBB = lastNAVBB;

    (_virtualPrice, ) = _virtualPriceAux(
      _tranche,
      getContractValue(), // nav
      _lastNAVAA + _lastNAVBB, // lastNAV
      _tranche == AATranche ? _lastNAVAA : _lastNAVBB, // lastTrancheNAV
      trancheAPRSplitRatio
    );
  }

  /// @notice [DEPRECATED]
  /// @return array with addresses of incentiveTokens (can be empty)
  function getIncentiveTokens() external view returns (address[] memory) {
    return incentiveTokens;
  }

  // ###############
  // Internal
  // ###############

  /// @notice method used to check if depositor has enough stkIDLE per unit of underlying to access the vault
  /// @param _amount amount of underlying to deposit
  function _checkStkIDLEBal(address _tranche, uint256 _amount) internal view {
    uint256 _stkIDLEPerUnderlying = stkIDLEPerUnderlying;
    // check if stkIDLE requirement is active for _tranche
    if (_stkIDLEPerUnderlying == 0 || 
      (_tranche == BBTranche && BBStaking == address(0)) || 
      (_tranche == AATranche && AAStaking == address(0))) {
      return;
    }

    uint256 trancheBal = IERC20Detailed(_tranche).balanceOf(msg.sender);
    // We check if sender deposited in the same tranche previously and add the bal to _amount
    uint256 bal = _amount + (trancheBal > 0 ? (trancheBal * _tranchePrice(_tranche) / ONE_TRANCHE_TOKEN) : 0);
    require(
      IERC20(STK_IDLE).balanceOf(msg.sender) >= 
      bal * _stkIDLEPerUnderlying / oneToken, 
      '7'
    );
  }

  /// @notice method used to deposit `token` and mint tranche tokens
  /// Ideally users should deposit right after an `harvest` call to maximize profit
  /// @dev this contract must be approved to spend at least _amount of `token` before calling this method
  /// automatically reverts on lending provider default (_strategyPrice decreased)
  /// @param _amount amount of underlyings (`token`) to deposit
  /// @param _tranche tranche address
  /// @param _referral referral address
  /// @return _minted number of tranche tokens minted
  function _deposit(uint256 _amount, address _tranche, address _referral) internal virtual whenNotPaused returns (uint256 _minted) {
    if (_amount == 0) {
      return _minted;
    }
    // check that we are not depositing more than the contract available limit
    _guarded(_amount);
    // set _lastCallerBlock hash
    _updateCallerBlock();
    // check if _strategyPrice decreased
    _checkDefault();
    // interest accrued since last depositXX/withdrawXX/harvest is splitted between AA and BB
    // according to trancheAPRSplitRatio. NAVs of AA and BB are updated and tranche
    // prices adjusted accordingly
    _updateAccounting();
    // check if depositor has enough stkIDLE for the amount to be deposited
    _checkStkIDLEBal(_tranche, _amount);
    // get underlyings from sender
    address _token = token;
    uint256 _preBal = _contractTokenBalance(_token);
    IERC20Detailed(_token).safeTransferFrom(msg.sender, address(this), _amount);
    // mint tranche tokens according to the current tranche price
    _minted = _mintShares(_contractTokenBalance(_token) - _preBal, msg.sender, _tranche);
    // update trancheAPRSplitRatio
    _updateSplitRatio(_getAARatio(true));

    if (_referral != address(0)) {
      emit Referral(_amount, _referral);
    }
  }

  /// @notice this method is called on depositXX/withdrawXX/harvest and
  /// updates the accounting of the contract and effectively splits the yield/loss between the
  /// AA and BB tranches
  /// @dev this method:
  /// - update tranche prices (priceAA and priceBB)
  /// - update net asset value for both tranches (lastNAVAA and lastNAVBB)
  /// - update fee accounting (unclaimedFees)
  function _updateAccounting() internal virtual {
    uint256 _lastNAVAA = lastNAVAA;
    uint256 _lastNAVBB = lastNAVBB;
    uint256 _lastNAV = _lastNAVAA + _lastNAVBB;
    uint256 nav = getContractValue();
    uint256 _aprSplitRatio = trancheAPRSplitRatio;
    // If gain is > 0, then collect some fees in `unclaimedFees`
    if (nav > _lastNAV) {
      unclaimedFees += (nav - _lastNAV) * fee / FULL_ALLOC;
    }
    (uint256 _priceAA, int256 _totalAAGain) = _virtualPriceAux(AATranche, nav, _lastNAV, _lastNAVAA, _aprSplitRatio);
    (uint256 _priceBB, int256 _totalBBGain) = _virtualPriceAux(BBTranche, nav, _lastNAV, _lastNAVBB, _aprSplitRatio);
    lastNAVAA = uint256(int256(_lastNAVAA) + _totalAAGain);

    // if we have a loss and it's gte last junior NAV we trigger a default
    if (_totalBBGain < 0 && -_totalBBGain >= int256(_lastNAVBB)) {
      // revert with 'default' error (4) if skipDefaultCheck is false, as seniors will have a loss too not covered. 
      // `updateAccounting` should be manually called to distribute loss
      require(skipDefaultCheck, "4");
      // This path will be called when a default happens and guardian calls
      // `updateAccounting` after setting skipDefaultCheck
      lastNAVBB = 0;
      _emergencyShutdown();
    } else {
      // we add the gain to last saved NAV
      lastNAVBB = uint256(int256(_lastNAVBB) + _totalBBGain);
    }
    priceAA = _priceAA;
    priceBB = _priceBB;
  }

  /// @notice calculates the NAV for a tranche considering the interest that is yet to be splitted
  /// @param _tranche address of the requested tranche
  /// @return net asset value, in underlying tokens, for _tranche considering all nav
  function _virtualBalance(address _tranche) internal view returns (uint256) {
    // balance is: tranche supply * virtual tranche price
    return IdleCDOTranche(_tranche).totalSupply() * virtualPrice(_tranche) / ONE_TRANCHE_TOKEN;
  }

  /// @notice calculates the NAV for a tranche without considering the interest that is yet to be splitted
  /// @param _tranche address of the requested tranche
  /// @return net asset value, in underlying tokens, for _tranche
  function _instantBalance(address _tranche) internal view returns (uint256) {
    return IdleCDOTranche(_tranche).totalSupply() * _tranchePrice(_tranche) / ONE_TRANCHE_TOKEN;
  }

  /// @notice calculates the current tranches price considering the interest/loss that is yet to be splitted and the
  /// total gain/loss for a specific tranche
  /// @dev Main scenarios covered:
  /// - if there is a loss on the lending protocol (ie strategy price decrease) up to maxDecreaseDefault (_checkDefault method), the loss is
  ///     - totally absorbed by junior holders if they have enough TVL and deposits/redeems work as normal
  ///     - otherwise a 'default' error (4) is raised and deposits/redeems are blocked
  /// - if there is a loss on the lending protocol (ie strategy price decrease) more than maxDecreaseDefault all deposits and redeems
  ///   are blocked and a 'default' error (4) is raised
  /// - if there is a loss somewhere not in the lending protocol (ie in our contracts) and the TVL decreases then the same process as above
  ///   applies, the only difference is that maxDecreaseDefault is not considered
  /// In any case, once a loss happens, it only gets accounted when new deposits/redeems are made, but those are blocked.
  /// For this reason a protected updateAccounting method has been added which should be used to distributed the loss after a default event
  /// @param _tranche address of the requested tranche
  /// @param _nav current NAV
  /// @param _lastNAV last saved NAV
  /// @param _lastTrancheNAV last saved tranche NAV
  /// @param _trancheAPRSplitRatio APR split ratio for AA tranche
  /// @return _virtualPrice tranche price considering all interest
  /// @return _totalTrancheGain (int256) tranche gain/loss since last update
  function _virtualPriceAux(
    address _tranche,
    uint256 _nav,
    uint256 _lastNAV,
    uint256 _lastTrancheNAV,
    uint256 _trancheAPRSplitRatio
  ) internal virtual view returns (uint256 _virtualPrice, int256 _totalTrancheGain) {
    // Check if there are tranche holders
    uint256 trancheSupply = IdleCDOTranche(_tranche).totalSupply();
    if (_lastNAV == 0 || trancheSupply == 0) {
      return (oneToken, 0);
    }

    // In order to correctly split the interest generated between AA and BB tranche holders
    // (according to the trancheAPRSplitRatio) we need to know how much interest/loss we gained
    // since the last price update (during a depositXX/withdrawXX/harvest)
    // To do that we need to get the current value of the assets in this contract
    // and the last saved one (always during a depositXX/withdrawXX/harvest)
    // Calculate the total gain/loss
    int256 totalGain = int256(_nav) - int256(_lastNAV);
    // If there is no gain/loss return the current price
    if (totalGain == 0) {
      return (_tranchePrice(_tranche), 0);
    }

    // Remove performance fee for gains
    if (totalGain > 0) {
      totalGain -= totalGain * int256(fee) / int256(FULL_ALLOC);
    }

    address _AATranche = AATranche;
    address _BBTranche = BBTranche;
    bool _isAATranche = _tranche == _AATranche;
    // Get the supply of the other tranche and
    // if it's 0 then give all gain to the current `_tranche` holders
    if (IdleCDOTranche(_isAATranche ? _BBTranche : _AATranche).totalSupply() == 0) {
      _totalTrancheGain = totalGain;
    } else {
      // if we gained something or the loss is between 0 and lossToleranceBps then we socialize the gain/loss
      if (totalGain > 0) {
        // Split the net gain, according to _trancheAPRSplitRatio, with precision loss favoring the AA tranche.
        int256 totalBBGain = totalGain * int256(FULL_ALLOC - _trancheAPRSplitRatio) / int256(FULL_ALLOC);
        // The new NAV for the tranche is old NAV + total gain for the tranche
        _totalTrancheGain = _isAATranche ? (totalGain - totalBBGain) : totalBBGain;
      } else if (uint256(-totalGain) <= (lossToleranceBps * _lastNAV) / FULL_ALLOC) {
        // Split the loss, according to TVL ratio instead of _trancheAPRSplitRatio (loss socialized between all tranches)
        uint256 _lastNAVBB = lastNAVBB;
        int256 totalBBLoss = totalGain * int256(_lastNAVBB) / int256(lastNAVAA + _lastNAVBB);
        // The new NAV for the tranche is old NAV - loss for the tranche
        _totalTrancheGain = _isAATranche ? (totalGain - totalBBLoss) : totalBBLoss;
      } else { // totalGain is negative here
        // Redirect the whole loss (which should be < maxDecreaseDefault) to junior holders
        int256 _juniorTVL = int256(_isAATranche ? _lastNAV - _lastTrancheNAV : _lastTrancheNAV);
        int256 _newJuniorTVL = _juniorTVL + totalGain; 
        // if junior holders have enough TVL to cover
        if (_newJuniorTVL > 0) {
          // then juniors get all loss (totalGain) and senior gets 0 loss
          _totalTrancheGain = _isAATranche ? int256(0) : totalGain;
        } else {
          // otherwise all loss minus junior tvl to senior
          if (!_isAATranche) {
            // juniors have no more claims, price is set to 0, gain is set to -juniorTVL
            return (0, -_juniorTVL);
          }
          // seniors get the loss - old junior TVL
          _totalTrancheGain = _newJuniorTVL;
        }
      }
    }
    // Split the new NAV (_lastTrancheNAV + _totalTrancheGain) per tranche token
    _virtualPrice = uint256(int256(_lastTrancheNAV) + _totalTrancheGain) * ONE_TRANCHE_TOKEN / trancheSupply;
  }

  /// @notice mint tranche tokens and updates tranche last NAV
  /// @param _amount, in underlyings, to convert in tranche tokens
  /// @param _to receiver address of the newly minted tranche tokens
  /// @param _tranche tranche address
  /// @return _minted number of tranche tokens minted
  function _mintShares(uint256 _amount, address _to, address _tranche) internal virtual returns (uint256 _minted) {
    // calculate # of tranche token to mint based on current tranche price: _amount / tranchePrice
    _minted = _amount * ONE_TRANCHE_TOKEN / _tranchePrice(_tranche);
    IdleCDOTranche(_tranche).mint(_to, _minted);
    // update NAV with the _amount of underlyings added
    if (_tranche == AATranche) {
      lastNAVAA += _amount;
    } else {
      lastNAVBB += _amount;
    }
  }

  /// @notice convert fees (`unclaimedFees`) in AA tranche tokens
  /// @dev this will be called only during harvests
  function _depositFees() internal {
    uint256 _amount = unclaimedFees;
    if (_amount != 0) {
      // mint tranches tokens (always AA) to this contract
      _mintShares(_amount, feeReceiver, AATranche);
      // reset unclaimedFees counter
      unclaimedFees = 0;
    }
  }

  /// @notice It allows users to burn their tranche token and redeem their principal + interest back
  /// @dev automatically reverts on lending provider default (_strategyPrice decreased).
  /// @param _amount in tranche tokens
  /// @param _tranche tranche address
  /// @return toRedeem number of underlyings redeemed
  function _withdraw(uint256 _amount, address _tranche) virtual internal nonReentrant returns (uint256 toRedeem) {
    // check if a deposit is made in the same block from the same user
    _checkSameTx();
    // check if _strategyPrice decreased
    _checkDefault();
    // accrue interest to tranches and updates tranche prices
    _updateAccounting();
    // redeem all user balance if 0 is passed as _amount
    if (_amount == 0) {
      _amount = IERC20Detailed(_tranche).balanceOf(msg.sender);
    }
    require(_amount != 0, '0');
    address _token = token;
    // get current available unlent balance
    uint256 balanceUnderlying = _contractTokenBalance(_token);
    // Calculate the amount to redeem
    toRedeem = _amount * _tranchePrice(_tranche) / ONE_TRANCHE_TOKEN;
    uint256 _want = toRedeem;
    if (toRedeem > balanceUnderlying) {
      // if the unlent balance is not enough we try to redeem what's missing directly from the strategy
      // and then add it to the current unlent balance
      // NOTE: A difference of up to 100 wei due to rounding is tolerated
      toRedeem = _liquidate(toRedeem - balanceUnderlying, revertIfTooLow) + balanceUnderlying;
    }
    // burn tranche token
    IdleCDOTranche(_tranche).burn(msg.sender, _amount);

    // update NAV with the _amount of underlyings removed
    if (_tranche == AATranche) {
      lastNAVAA -= _want;
    } else {
      lastNAVBB -= _want;
    }

    // update trancheAPRSplitRatio
    _updateSplitRatio(_getAARatio(true));
  
    // send underlying to msg.sender. Keep this at the end of the function to avoid 
    // potential read only reentrancy on cdo variants that have hooks (eg with nfts)
    IERC20Detailed(_token).safeTransfer(msg.sender, toRedeem);
  }

  /// @notice updates trancheAPRSplitRatio based on the current tranches TVL ratio between AA and BB
  /// @dev the idea here is to limit the min and max APR that the senior tranche can get
  function _updateSplitRatio(uint256 tvlAARatio) internal virtual {
    uint256 _minSplit = minAprSplitAYS;
    _minSplit = _minSplit == 0 ? AA_RATIO_LIM_DOWN : _minSplit;

    if (isAYSActive) {
      uint256 aux;
      if (tvlAARatio >= AA_RATIO_LIM_UP) {
        aux = AA_RATIO_LIM_UP;
      } else if (tvlAARatio > _minSplit) {
        aux = tvlAARatio;
      } else {
        aux = _minSplit;
      }
      trancheAPRSplitRatio = aux * tvlAARatio / FULL_ALLOC;
    }
  }

  /// @notice calculates the current AA tranches ratio
  /// @dev it does count accrued interest not yet split since last
  /// depositXX/withdrawXX/harvest only if _instant flag is true
  /// @param _instant if true, it returns the current ratio without accrued interest
  /// @return AA tranches ratio (in underlying value) considering all interest
  function _getAARatio(bool _instant) internal view returns (uint256) {
    function(address) internal view returns (uint256) _getNAV =
      _instant ? _instantBalance : _virtualBalance;
    uint256 AABal = _getNAV(AATranche);
    uint256 contractVal = AABal + _getNAV(BBTranche);
    if (contractVal == 0) {
      return 0;
    }
    // Current AA tranche split ratio = AABal * FULL_ALLOC / (AABal + BBBal)
    return AABal * FULL_ALLOC / contractVal;
  }

  /// @dev check if _strategyPrice is decreased more than X% with X configurable since last update 
  /// and updates last saved strategy price
  function _checkDefault() virtual internal {
    uint256 currPrice = _strategyPrice();
    if (!skipDefaultCheck) {
      // calculate if % of decrease of strategyPrice is within maxDecreaseDefault
      require(lastStrategyPrice * (FULL_ALLOC - maxDecreaseDefault) / FULL_ALLOC <= currPrice, "4");
    }
    lastStrategyPrice = currPrice;
  }

  /// @return strategy price, in underlyings
  function _strategyPrice() internal view returns (uint256) {
    return IIdleCDOStrategy(strategy).price();
  }

  /// @dev this should liquidate at least _amount of `token` from the lending provider or revertIfNeeded
  /// @param _amount in underlying tokens
  /// @param _revertIfNeeded flag whether to revert or not if the redeemed amount is not enough
  /// @return _redeemedTokens number of underlyings redeemed
  function _liquidate(uint256 _amount, bool _revertIfNeeded) internal virtual returns (uint256 _redeemedTokens) {
    _redeemedTokens = IIdleCDOStrategy(strategy).redeemUnderlying(_amount);
    if (_revertIfNeeded) {
      uint256 _tolerance = liquidationTolerance;
      if (_tolerance == 0) {
        _tolerance = 100;
      }
      // keep `_tolerance` wei as margin for rounding errors
      require(_redeemedTokens + _tolerance >= _amount, '5');
    }

    if (_redeemedTokens > _amount) {
      _redeemedTokens = _amount;
    }
  }

  /// @notice method used to sell `_rewardToken` for `_token` on uniswap
  /// @param _rewardToken address of the token to sell
  /// @param _path to buy
  /// @param _amount of `_rewardToken` to sell
  /// @param _minAmount min amount of `_token` to buy
  /// @return _amount of _rewardToken sold
  /// @return _amount received for the sell
  function _sellReward(address _rewardToken, bytes memory _path, uint256 _amount, uint256 _minAmount)
    internal virtual
    returns (uint256, uint256) {
    // If 0 is passed as sell amount, we get the whole contract balance
    if (_amount == 0) {
      _amount = _contractTokenBalance(_rewardToken);
    }
    if (_amount == 0) {
      return (0, 0);
    }
  
    if (_path.length != 0) {
      // Uni v3 swap
      ISwapRouter _swapRouter = ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
      IERC20Detailed(_rewardToken).safeIncreaseAllowance(address(_swapRouter), _amount);
      // multi hop swap params
      ISwapRouter.ExactInputParams memory params = ISwapRouter.ExactInputParams({
        path: _path,
        recipient: address(this),
        deadline: block.timestamp + 100,
        amountIn: _amount,
        amountOutMinimum: _minAmount
      });
      // do the swap and return the amount swapped and the amount received
      return (_amount, _swapRouter.exactInput(params));
    } else {
      // Uni v2 swap
      IUniswapV2Router02 _uniRouter = uniswapRouterV2;
      // approve the uniswap router to spend our reward
      IERC20Detailed(_rewardToken).safeIncreaseAllowance(address(_uniRouter), _amount);
      // do the trade with all `_rewardToken` in this contract
      address[] memory _pathUniv2 = new address[](3);
      _pathUniv2[0] = _rewardToken;
      _pathUniv2[1] = weth;
      _pathUniv2[2] = token;
      uint256[] memory _amounts = _uniRouter.swapExactTokensForTokens(
        _amount,
        _minAmount,
        _pathUniv2,
        address(this),
        block.timestamp + 100
      );
      // return the amount swapped and the amount received
      return (_amounts[0], _amounts[_amounts.length - 1]);
    }
  }

  /// @notice method used to sell all sellable rewards for `_token` on uniswap
  /// @param _strategy IIdleCDOStrategy stategy instance
  /// @param _sellAmounts array with amounts of rewards to sell
  /// @param _minAmount array with amounts of _token buy for each reward sold. (should have the same length as _sellAmounts)
  /// @param _skipReward array of flags for skipping the market sell of specific rewards (should have the same length as _sellAmounts)
  /// @return _soldAmounts array with amounts of rewards actually sold
  /// @return _swappedAmounts array with amounts of _token actually bought
  /// @return _totSold total rewards sold in `_token`
  function _sellAllRewards(IIdleCDOStrategy _strategy, uint256[] memory _sellAmounts, uint256[] memory _minAmount, bool[] memory _skipReward, bytes memory _extraData)
    internal
    returns (uint256[] memory _soldAmounts, uint256[] memory _swappedAmounts, uint256 _totSold) {
    // Fetch state variables once to save gas
    // get all rewards addresses
    address[] memory _rewards = _strategy.getRewardTokens();
    address _rewardToken;
    bytes[] memory _paths = new bytes[](_rewards.length);
    if (_extraData.length > 0) {
      _paths = abi.decode(_extraData, (bytes[]));
    }
    uint256 rewardsLen = _rewards.length;
    // Initialize the return array, containing the amounts received after swapping reward tokens
    _soldAmounts = new uint256[](rewardsLen);
    _swappedAmounts = new uint256[](rewardsLen);
    // loop through all reward tokens
    for (uint256 i; i < rewardsLen; ++i) {
      _rewardToken = _rewards[i];
      // check if it should be sold or not
      if (_skipReward[i]) { continue; }
      // do not sell stkAAVE but only AAVE if present
      if (_rewardToken == stkAave) {
        _rewardToken = AAVE;
      }
      // Market sell _rewardToken in this contract for _token
      (_soldAmounts[i], _swappedAmounts[i]) = _sellReward(_rewardToken, _paths[i], _sellAmounts[i], _minAmount[i]);
      _totSold += _swappedAmounts[i];
    }
  }

  /// @param _tranche tranche address
  /// @return last saved tranche price, in underlyings
  function _tranchePrice(address _tranche) internal view returns (uint256) {
    if (IdleCDOTranche(_tranche).totalSupply() == 0) {
      return oneToken;
    }
    return _tranche == AATranche ? priceAA : priceBB;
  }

  /// @notice returns the current apr for a tranche based on trancheAPRSplitRatio and the provided AA ratio
  /// @dev the apr for a tranche can be higher than the strategy apr
  /// @param _tranche tranche token address
  /// @param _AATrancheSplitRatio AA split ratio used for calculations
  /// @return apr for the specific tranche
  function _getApr(address _tranche, uint256 _AATrancheSplitRatio) internal view returns (uint256) {
    uint256 stratApr = IIdleCDOStrategy(strategy).getApr();
    uint256 _trancheAPRSplitRatio = trancheAPRSplitRatio;
    bool isAATranche = _tranche == AATranche;
    if (_AATrancheSplitRatio == 0) {
      // if there are no AA tranches, apr for AA is 0 (all apr to BB and it will be equal to stratApr)
      return isAATranche ? 0 : stratApr;
    }
    return isAATranche ?
      // AA apr is: stratApr * AAaprSplitRatio / AASplitRatio
      stratApr * _trancheAPRSplitRatio / _AATrancheSplitRatio :
      // BB apr is: stratApr * BBaprSplitRatio / BBSplitRatio -> where
      // BBaprSplitRatio is: (FULL_ALLOC - _trancheAPRSplitRatio) and
      // BBSplitRatio is: (FULL_ALLOC - _AATrancheSplitRatio)
      stratApr * (FULL_ALLOC - _trancheAPRSplitRatio) / (FULL_ALLOC - _AATrancheSplitRatio);
  }

  /// @return _locked amount of harvested rewards that are still not available to be redeemed
  function _lockedRewards() internal view returns (uint256 _locked) {
    uint256 _releaseBlocksPeriod = releaseBlocksPeriod;
    uint256 _blocksSinceLastHarvest = block.number - latestHarvestBlock;
    uint256 _harvestedRewards = harvestedRewards;

    // NOTE: _harvestedRewards is never set to 0, but rather to 1 to save some gas
    if (_harvestedRewards > 1 && _blocksSinceLastHarvest < _releaseBlocksPeriod) {
      // progressively release harvested rewards
      _locked = _harvestedRewards * (_releaseBlocksPeriod - _blocksSinceLastHarvest) / _releaseBlocksPeriod;
    }
  }

  // ###################
  // Protected
  // ###################

  /// @notice This method is used to lend user funds in the lending provider through an IIdleCDOStrategy
  /// The method:
  /// - redeems rewards (if any) from the lending provider
  /// - converts the rewards in underlyings through uniswap v2 or v3
  /// - calls _updateAccounting to update the accounting of the system with the new underlyings received
  /// - it then convert fees in tranche tokens
  /// - finally it deposits the (initial unlent balance + the underlyings get from uniswap - fees) in the
  ///   lending provider through the IIdleCDOStrategy `deposit` call
  /// The method will be called by an external, whitelisted, keeper bot which will call the method sistematically (eg once a day)
  /// @dev can be called only by the rebalancer or the owner
  /// @param _skipFlags array of flags, [0] = skip reward redemption, [1] = skip incentives update, [2] = skip fee deposit, [3] = skip all
  /// @param _skipReward array of flags for skipping the market sell of specific rewards. Length should be equal to the `IIdleCDOStrategy(strategy).getRewardTokens()` array
  /// @param _minAmount array of min amounts for uniswap trades. Lenght should be equal to the _skipReward array
  /// @param _sellAmounts array of amounts (of reward tokens) to sell on uniswap. Lenght should be equal to the _minAmount array
  /// if a sellAmount is 0 the whole contract balance for that token is swapped
  /// @param _extraData bytes to be passed to the redeemRewards call
  /// @return _res array of arrays with the following elements:
  ///   [0] _soldAmounts array with amounts of rewards actually sold
  ///   [1] _swappedAmounts array with amounts of _token actually bought
  ///   [2] _redeemedRewards array with amounts of rewards redeemed
  function harvest(
    // _skipFlags[0] _skipRedeem,
    // _skipFlags[1] _skipIncentivesUpdate, [DEPRECATED]
    // _skipFlags[2] _skipFeeDeposit,
    // _skipFlags[3] _skipRedeem && _skipIncentivesUpdate && _skipFeeDeposit,
    bool[] calldata _skipFlags,
    bool[] calldata _skipReward,
    uint256[] calldata _minAmount,
    uint256[] calldata _sellAmounts,
    bytes[] calldata _extraData
  ) public
    virtual
    returns (uint256[][] memory _res) {
    _checkOnlyOwnerOrRebalancer();
    // initalize the returned array (elements will be [_soldAmounts, _swappedAmounts, _redeemedRewards])
    _res = new uint256[][](3);
    // Fetch state variable once to save gas
    IIdleCDOStrategy _strategy = IIdleCDOStrategy(strategy);
    // Check whether to redeem rewards from strategy or not
    if (!_skipFlags[3]) {
      uint256 _totSold;

      if (!_skipFlags[0]) {
        // Redeem all rewards associated with the strategy
        _res[2] = _strategy.redeemRewards(_extraData[0]);
        // Sell rewards
        (_res[0], _res[1], _totSold) = _sellAllRewards(_strategy, _sellAmounts, _minAmount, _skipReward, _extraData[1]);
      }
      // update last saved harvest block number
      latestHarvestBlock = block.number;
      // update harvested rewards value (avoid setting it to 0 to save some gas)
      harvestedRewards = _totSold == 0 ? 1 : _totSold;

      // split converted rewards if any and update tranche prices
      // NOTE: harvested rewards won't be counted directly but released over time
      _updateAccounting();

      if (!_skipFlags[2]) {
        // Get fees in the form of totalSupply diluition
        _depositFees();
      }
    }

    // Deposit the remaining balance in the lending provider and 
    // keep some unlent balance for cheap redeems and as reserve of last resort
    uint256 underlyingBal = _contractTokenBalance(token);
    uint256 idealUnlent = getContractValue() * unlentPerc / FULL_ALLOC;
    if (underlyingBal > idealUnlent) {
      // Put unlent balance at work in the lending provider
      _strategy.deposit(underlyingBal - idealUnlent);
    }
  }

  /// @notice method used to redeem underlyings from the lending provider
  /// @dev can be called only by the rebalancer or the owner
  /// @param _amount in underlyings to liquidate from lending provider
  /// @param _revertIfNeeded flag to revert if amount liquidated is too low
  /// @return liquidated amount in underlyings
  function liquidate(uint256 _amount, bool _revertIfNeeded) external returns (uint256) {
    _checkOnlyOwnerOrRebalancer();
    return _liquidate(_amount, _revertIfNeeded);
  }

  // ###################
  // onlyOwner
  // ###################

  /// @dev automatically reverts if strategyPrice decreased more than `_maxDecreaseDefault`
  /// @param _maxDecreaseDefault max value, in % where `100000` = 100%, of accettable price decrease for the strategy
  function setMaxDecreaseDefault(uint256 _maxDecreaseDefault) external {
    _checkOnlyOwner();
    require(_maxDecreaseDefault < FULL_ALLOC, '7');
    maxDecreaseDefault = _maxDecreaseDefault;
  }

  /// @param _active flag to allow Adaptive Yield Split
  function setIsAYSActive(bool _active) external {
    _checkOnlyOwner();
    isAYSActive = _active;
  }

  /// @param _allowed flag to allow AA withdraws
  function setAllowAAWithdraw(bool _allowed) external {
    _checkOnlyOwner();
    allowAAWithdraw = _allowed;
  }

  /// @param _allowed flag to allow BB withdraws
  function setAllowBBWithdraw(bool _allowed) external {
    _checkOnlyOwner();
    allowBBWithdraw = _allowed;
  }

  /// @param _allowed flag to enable the 'default' check (whether _strategyPrice decreased or not)
  function setSkipDefaultCheck(bool _allowed) external {
    _checkOnlyOwner();
    skipDefaultCheck = _allowed;
  }

  /// @param _allowed flag to enable the check if redeemed amount during liquidations is enough
  function setRevertIfTooLow(bool _allowed) external {
    _checkOnlyOwner();
    revertIfTooLow = _allowed;
  }

  /// @param _rebalancer new rebalancer address
  function setRebalancer(address _rebalancer) external {
    _checkOnlyOwner();
    require((rebalancer = _rebalancer) != address(0), '0');
  }

  /// @param _feeReceiver new fee receiver address
  function setFeeReceiver(address _feeReceiver) external {
    _checkOnlyOwner();
    require((feeReceiver = _feeReceiver) != address(0), '0');
  }

  /// @param _guardian new guardian (pauser) address
  function setGuardian(address _guardian) external {
    _checkOnlyOwner();
    require((guardian = _guardian) != address(0), '0');
  }

  /// @param _diff max liquidation diff tolerance in underlyings
  function setLiquidationTolerance(uint256 _diff) external {
    _checkOnlyOwner();
    liquidationTolerance = _diff;
  }

  /// @param _val stkIDLE per underlying required for deposits
  function setStkIDLEPerUnderlying(uint256 _val) external {
    _checkOnlyOwner();
    stkIDLEPerUnderlying = _val;
  }

  /// @param _aprSplit min apr split for AA, considering FULL_ALLOC = 100%
  function setMinAprSplitAYS(uint256 _aprSplit) external {
    _checkOnlyOwner();
    require((minAprSplitAYS = _aprSplit) <= FULL_ALLOC, '7');
    minAprSplitAYS = _aprSplit;
  }

  /// @param _fee new fee
  function setFee(uint256 _fee) external {
    _checkOnlyOwner();
    require((fee = _fee) <= MAX_FEE, '7');
  }

  /// @param _unlentPerc new unlent percentage
  function setUnlentPerc(uint256 _unlentPerc) external {
    _checkOnlyOwner();
    require((unlentPerc = _unlentPerc) <= FULL_ALLOC, '7');
  }

  /// @notice set new release block period. WARN: this should be called only when there 
  /// are no active rewards being unlocked
  /// @param _releaseBlocksPeriod new # of blocks after an harvest during which
  /// harvested rewards gets progressively redistriburted to users
  function setReleaseBlocksPeriod(uint256 _releaseBlocksPeriod) external {
    _checkOnlyOwner();
    releaseBlocksPeriod = _releaseBlocksPeriod;
  }

  /// @param _trancheAPRSplitRatio new apr split ratio
  function setTrancheAPRSplitRatio(uint256 _trancheAPRSplitRatio) external {
    _checkOnlyOwner();
    require((trancheAPRSplitRatio = _trancheAPRSplitRatio) <= FULL_ALLOC, '7');
  }

  /// @param _diffBps tolerance in % (FULL_ALLOC = 100%) for socializing small losses 
  function setLossToleranceBps(uint256 _diffBps) external {
      _checkOnlyOwner();
      lossToleranceBps = _diffBps;
  }

  /// @dev toggle stkIDLE requirement for tranche
  /// @param _tranche address
  function toggleStkIDLEForTranche(address _tranche) external {
    _checkOnlyOwner();
    address aa = AATranche;
    require(_tranche == BBTranche || _tranche == aa, '9');
    if (_tranche == aa) {
      AAStaking = AAStaking == address(0) ? address(1) : address(0);
      return;
    }

    BBStaking = BBStaking == address(0) ? address(1) : address(0);
  }

  /// @notice this method updates the accounting of the contract and effectively splits the yield/loss between the
  /// AA and BB tranches. This can be called at any time as is called automatically on each deposit/redeem. It's here
  /// just to be called when a default happened, as deposits/redeems are paused, but we need to update
  /// the loss for junior holders
  function updateAccounting() external {
    _checkOnlyOwnerOrGuardian();
    skipDefaultCheck = true;
    _updateAccounting();
    // _updateAccounting can set `skipDefaultCheck` to true in case of default
    // but this can be manually be reset to true if needed
    skipDefaultCheck = false;
  }

  /// @notice pause deposits and redeems for all classes of tranches
  /// @dev can be called by both the owner and the guardian
  function emergencyShutdown() external {
    _checkOnlyOwnerOrGuardian();
    _emergencyShutdown();
  }

  function _emergencyShutdown() internal {
    // prevent deposits
    _pause();
    // prevent withdraws
    allowAAWithdraw = false;
    allowBBWithdraw = false;
    // Allow deposits/withdraws (once selectively re-enabled, eg for AA holders)
    // without checking for lending protocol default
    skipDefaultCheck = true;
    revertIfTooLow = true;
  }

  /// @notice allow deposits and redeems for all classes of tranches
  /// @dev can be called by the owner only
  function restoreOperations() external {
    _checkOnlyOwner();
    // restore deposits
    _unpause();
    // restore withdraws
    allowAAWithdraw = true;
    allowBBWithdraw = true;
    // Allow deposits/withdraws but checks for lending protocol default
    skipDefaultCheck = false;
    revertIfTooLow = true;
  }

  /// @notice Pauses deposits
  /// @dev can be called by both the owner and the guardian
  function pause() external  {
    _checkOnlyOwnerOrGuardian();
    _pause();
  }

  /// @notice Unpauses deposits
  /// @dev can be called by both the owner and the guardian
  function unpause() external {
    _checkOnlyOwnerOrGuardian();
    _unpause();
  }

  // ###################
  // Helpers
  // ###################

  /// @dev Check that the msg.sender is the either the owner or the guardian
  function _checkOnlyOwnerOrGuardian() internal view {
    require(msg.sender == guardian || msg.sender == owner(), "6");
  }

  /// @dev Check that the msg.sender is the either the owner or the rebalancer
  function _checkOnlyOwnerOrRebalancer() internal view {
    require(msg.sender == rebalancer || msg.sender == owner(), "6");
  }

  /// @notice returns the current balance of this contract for a specific token
  /// @param _token token address
  /// @return balance of `_token` for this contract
  function _contractTokenBalance(address _token) internal view returns (uint256) {
    return IERC20Detailed(_token).balanceOf(address(this));
  }

  /// @dev Set allowance for _token to unlimited for _spender
  /// @param _token token address
  /// @param _spender spender address
  function _allowUnlimitedSpend(address _token, address _spender) internal {
    IERC20Detailed(_token).safeIncreaseAllowance(_spender, type(uint256).max);
  }

  /// @dev Set last caller and block.number hash. This should be called at the beginning of the first function to protect
  function _updateCallerBlock() internal {
    _lastCallerBlock = keccak256(abi.encodePacked(tx.origin, block.number));
  }

  /// @dev Check that the second function is not called in the same tx from the same tx.origin
  function _checkSameTx() internal view {
    require(keccak256(abi.encodePacked(tx.origin, block.number)) != _lastCallerBlock, "8");
  }

  /// @notice concat 2 strings in a single one
  /// @param a first string
  /// @param b second string
  /// @return new string with a and b concatenated
  function _concat(string memory a, string memory b) internal pure returns (string memory) {
    return string(abi.encodePacked(a, b));
  }
}

File 7 of 24 : IUniswapV3SwapCallback.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
    /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
    /// @dev In the implementation you must pay the pool tokens owed for the swap.
    /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
    /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
    /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
    /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
    /// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
    /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
    function uniswapV3SwapCallback(
        int256 amount0Delta,
        int256 amount1Delta,
        bytes calldata data
    ) external;
}

File 8 of 24 : IUniswapV2Router01.sol
pragma solidity >=0.6.2;

interface IUniswapV2Router01 {
    function factory() external pure returns (address);
    function WETH() external pure returns (address);

    function addLiquidity(
        address tokenA,
        address tokenB,
        uint amountADesired,
        uint amountBDesired,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB, uint liquidity);
    function addLiquidityETH(
        address token,
        uint amountTokenDesired,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    function removeLiquidity(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETH(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline
    ) external returns (uint amountToken, uint amountETH);
    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        uint liquidity,
        uint amountAMin,
        uint amountBMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountA, uint amountB);
    function removeLiquidityETHWithPermit(
        address token,
        uint liquidity,
        uint amountTokenMin,
        uint amountETHMin,
        address to,
        uint deadline,
        bool approveMax, uint8 v, bytes32 r, bytes32 s
    ) external returns (uint amountToken, uint amountETH);
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapTokensForExactTokens(
        uint amountOut,
        uint amountInMax,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
    function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);
    function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
        external
        returns (uint[] memory amounts);
    function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
        external
        payable
        returns (uint[] memory amounts);

    function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
    function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
    function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
    function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}

File 9 of 24 : IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 10 of 24 : IERC20PermitUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20PermitUpgradeable {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 11 of 24 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 12 of 24 : PausableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    function __Pausable_init() internal onlyInitializing {
        __Pausable_init_unchained();
    }

    function __Pausable_init_unchained() internal onlyInitializing {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 13 of 24 : IIdleCDOStrategy.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;

interface IIdleCDOStrategy {
  function strategyToken() external view returns(address);
  function token() external view returns(address);
  function tokenDecimals() external view returns(uint256);
  function oneToken() external view returns(uint256);
  function redeemRewards(bytes calldata _extraData) external returns(uint256[] memory);
  function pullStkAAVE() external returns(uint256);
  function price() external view returns(uint256);
  function getRewardTokens() external view returns(address[] memory);
  function deposit(uint256 _amount) external returns(uint256);
  // _amount in `strategyToken`
  function redeem(uint256 _amount) external returns(uint256);
  // _amount in `token`
  function redeemUnderlying(uint256 _amount) external returns(uint256);
  function getApr() external view returns(uint256);
}

File 14 of 24 : GuardedLaunchUpgradable.sol
//SPDX-License-Identifier: Apache 2.0
pragma solidity 0.8.10;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

/// @notice This abstract contract is used to add an updatable limit on the total value locked
/// that the contract can have. It also have an emergency method that allows the owner to pull
/// funds into predefined recovery address
/// @dev Inherit this contract and add the _guarded method to the child contract
abstract contract GuardedLaunchUpgradable is Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable {
  using SafeERC20Upgradeable for IERC20Upgradeable;

  // ERROR MESSAGES:
  // 0 = is 0
  // 1 = already initialized
  // 2 = Contract limit reached

  // TVL limit in underlying value
  uint256 public limit;
  // recovery address
  address public governanceRecoveryFund;

  /// @param _limit TVL limit. (0 means unlimited)
  /// @param _governanceRecoveryFund recovery address
  /// @param _owner owner address
  function __GuardedLaunch_init(uint256 _limit, address _governanceRecoveryFund, address _owner) internal {
    require(_governanceRecoveryFund != address(0), '0');
    require(_owner != address(0), '0');
    // Initialize inherited contracts
    OwnableUpgradeable.__Ownable_init();
    ReentrancyGuardUpgradeable.__ReentrancyGuard_init();
    // Initialize state variables
    limit = _limit;
    governanceRecoveryFund = _governanceRecoveryFund;
    // Transfer ownership
    transferOwnership(_owner);
  }

  /// @notice this check should be called inside the child contract on deposits to check that the
  /// TVL didn't exceed a threshold
  /// @param _amount new amount to deposit
  function _guarded(uint256 _amount) internal view {
    uint256 _limit = limit;
    if (_limit == 0) {
      return;
    }
    require(getContractValue() + _amount <= _limit, '2');
  }

  /// @dev Check that the second function is not called in the same tx from the same tx.origin
  function _checkOnlyOwner() internal view {
    require(owner() == msg.sender, '6');
  }

  /// @notice abstract method, should return the TVL in underlyings
  function getContractValue() public virtual view returns (uint256);

  /// @notice set contract TVL limit
  /// @param _limit limit in underlying value, 0 means no limit
  function _setLimit(uint256 _limit) external {
    _checkOnlyOwner();
    limit = _limit;
  }

  /// @notice Emergency method, tokens gets transferred to the governanceRecoveryFund address
  /// @param _token address of the token to transfer
  /// @param _value amount to transfer
  function transferToken(address _token, uint256 _value) external {
    _checkOnlyOwner();
    IERC20Upgradeable(_token).safeTransfer(governanceRecoveryFund, _value);
  }
}

File 15 of 24 : IdleCDOTranche.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/// @dev ERC20 representing a tranche token
contract IdleCDOTranche is ERC20 {
  // allowed minter address
  address public minter;

  /// @param _name tranche name
  /// @param _symbol tranche symbol
  constructor(
    string memory _name, // eg. IdleDAI
    string memory _symbol // eg. IDLEDAI
  ) ERC20(_name, _symbol) {
    // minter is msg.sender which is IdleCDO (in initialize)
    minter = msg.sender;
  }

  /// @param account that should receive the tranche tokens
  /// @param amount of tranche tokens to mint
  function mint(address account, uint256 amount) external {
    require(msg.sender == minter, 'TRANCHE:!AUTH');
    _mint(account, amount);
  }

  /// @param account that should have the tranche tokens burned
  /// @param amount of tranche tokens to burn
  function burn(address account, uint256 amount) external {
    require(msg.sender == minter, 'TRANCHE:!AUTH');
    _burn(account, amount);
  }
}

File 16 of 24 : IdleCDOStorage.sol
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.10;

import '@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol';

contract IdleCDOStorage {
  // constant to represent 100%
  uint256 public constant FULL_ALLOC = 100000;
  // max fee, relative to FULL_ALLOC
  uint256 public constant MAX_FEE = 20000;
  // one token
  uint256 public constant ONE_TRANCHE_TOKEN = 10**18;
  // variable used to save the last tx.origin and block.number
  bytes32 internal _lastCallerBlock;
  // variable used to save the block of the latest harvest
  uint256 internal latestHarvestBlock;
  // WETH address
  address public weth;
  // [DEPRECATED] tokens used to incentivize the idle tranche ideal ratio
  address[] public incentiveTokens;
  // underlying token (eg DAI)
  address public token;
  // address that can only pause/unpause the contract in case of emergency
  address public guardian;
  // one `token` (eg for DAI 10**18)
  uint256 public oneToken;
  // address that can call the 'harvest' method and lend pool assets
  address public rebalancer;
  // address of the uniswap v2 router
  IUniswapV2Router02 internal uniswapRouterV2;

  // Flag for allowing AA withdraws
  bool public allowAAWithdraw;
  // Flag for allowing BB withdraws
  bool public allowBBWithdraw;
  // Flag for allowing to enable reverting in case the strategy gives back less
  // amount than the requested one
  bool public revertIfTooLow;
  // Flag to enable the `Default Check` (related to the emergency shutdown)
  bool public skipDefaultCheck;

  // address of the strategy used to lend funds
  address public strategy;
  // address of the strategy token which represent the position in the lending provider
  address public strategyToken;
  // address of AA Tranche token contract
  address public AATranche;
  // address of BB Tranche token contract
  address public BBTranche;
  // address for stkIDLE gating for AA tranche. addr(0) -> inactive, addr(1) -> active
  address public AAStaking;
  // address for stkIDLE gating for BB tranche. addr(0) -> inactive, addr(1) -> active
  address public BBStaking;

  // Apr split ratio for AA tranches
  // (relative to FULL_ALLOC so 50% => 50000 => 50% of the interest to tranche AA)
  uint256 public trancheAPRSplitRatio; //
  // [DEPRECATED] Ideal tranche split ratio in `token` value
  // (relative to FULL_ALLOC so 50% => 50000 means 50% of tranches (in value) should be AA)
  uint256 public trancheIdealWeightRatio;
  // Price for minting AA tranche, in underlyings
  uint256 public priceAA;
  // Price for minting BB tranche, in underlyings
  uint256 public priceBB;
  // last saved net asset value (in `token`) for AA tranches
  uint256 public lastNAVAA;
  // last saved net asset value (in `token`) for BB tranches
  uint256 public lastNAVBB;
  // last saved lending provider price
  uint256 public lastStrategyPrice;
  // Keeps track of unclaimed fees for feeReceiver
  uint256 public unclaimedFees;
  // Keeps an unlent balance both for cheap redeem and as 'insurance of last resort'
  uint256 public unlentPerc;

  // Fee amount (relative to FULL_ALLOC)
  uint256 public fee;
  // address of the fee receiver
  address public feeReceiver;

  // [DEPRECATED] trancheIdealWeightRatio ± idealRanges, used in updateIncentives
  uint256 public idealRange;
  // period, in blocks, for progressively releasing harvested rewards to users
  uint256 public releaseBlocksPeriod;
  // amount of rewards sold in the last harvest (in `token`)
  uint256 internal harvestedRewards;
  // stkAave address
  address internal constant stkAave = address(0x4da27a545c0c5B758a6BA100e3a049001de870f5);
  // aave address
  address internal constant AAVE = address(0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9);
  // [DEPRECATED] if the cdo receive stkAAVE
  bool internal isStkAAVEActive;
  // referral address of the strategy developer
  address public referral;
  // amount of fee for feeReceiver. Max is FULL_ALLOC
  uint256 public feeSplit;

  // if Adaptive Yield Split is active
  bool public isAYSActive;
  // constant to represent 99% (for ADS AA ratio upper limit)
  uint256 internal constant AA_RATIO_LIM_UP = 99000;
  // constant to represent 50% (for ADS AA ratio lower limit)
  uint256 internal constant AA_RATIO_LIM_DOWN = 50000;

  address internal constant STK_IDLE = address(0xaAC13a116eA7016689993193FcE4BadC8038136f);

  // Referral event
  event Referral(uint256 _amount, address _ref);
  // tolerance in underlyings when redeeming
  uint256 public liquidationTolerance;

  // Add new variables here. For each storage slot
  // used, reduce the __gap length by 1. 
  // ####################### 
  // Min apr ratio for AA tranches when using AYS
  uint256 public minAprSplitAYS;
  // Max strategy price decrease before triggering a default
  uint256 public maxDecreaseDefault;
  // The tolerance for the loss socialized so equally distributed between junior and senior tranches.
  uint256 public lossToleranceBps;
  // Amount of stkIDLE required to mint 1 underlying
  uint256 public stkIDLEPerUnderlying;
  // uint256 public test;



  // ####################### 
  // This is empty reserved space in storage that is put 
  // in place in Upgradeable contracts. It allows us to 
  // freely add new state variables in the future without 
  // compromising the storage compatibility with existing 
  // deployments.
  // The size of the __gap array is calculated so that the 
  // amount of storage used by a contract always adds up to 
  // always the same number, 50 in this case.
  uint256[46] private __gap;
  // uint256[45] private __gap; -> after adding `test`
  // #######################
  // IMPORTANT: Do not add any variables below `__gap`
}

File 17 of 24 : ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract ContextUpgradeable is Initializable {
    function __Context_init() internal onlyInitializing {
    }

    function __Context_init_unchained() internal onlyInitializing {
    }
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[50] private __gap;
}

File 18 of 24 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```solidity
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 *
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized != type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 19 of 24 : OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    function __Ownable_init() internal onlyInitializing {
        __Ownable_init_unchained();
    }

    function __Ownable_init_unchained() internal onlyInitializing {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

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

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 20 of 24 : ReentrancyGuardUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuardUpgradeable is Initializable {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    function __ReentrancyGuard_init() internal onlyInitializing {
        __ReentrancyGuard_init_unchained();
    }

    function __ReentrancyGuard_init_unchained() internal onlyInitializing {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;
}

File 21 of 24 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(address from, address to, uint256 amount) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}

File 22 of 24 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 23 of 24 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 24 of 24 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 170
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_ref","type":"address"}],"name":"Referral","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"AAStaking","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AATranche","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BBStaking","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BBTranche","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FULL_ALLOC","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_TRANCHE_TOKEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"}],"name":"_setLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"allowAAWithdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"allowBBWithdraw","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositAA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_referral","type":"address"}],"name":"depositAARef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositBB","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_referral","type":"address"}],"name":"depositBBRef","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"emergencyShutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeSplit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tranche","type":"address"}],"name":"getApr","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContractValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentAARatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getIncentiveTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governanceRecoveryFund","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool[]","name":"_skipFlags","type":"bool[]"},{"internalType":"bool[]","name":"_skipReward","type":"bool[]"},{"internalType":"uint256[]","name":"_minAmount","type":"uint256[]"},{"internalType":"uint256[]","name":"_sellAmounts","type":"uint256[]"},{"internalType":"bytes[]","name":"_extraData","type":"bytes[]"}],"name":"harvest","outputs":[{"internalType":"uint256[][]","name":"_res","type":"uint256[][]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"idealRange","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"incentiveTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"},{"internalType":"address","name":"_guardedToken","type":"address"},{"internalType":"address","name":"_governanceFund","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_rebalancer","type":"address"},{"internalType":"address","name":"_strategy","type":"address"},{"internalType":"uint256","name":"_trancheAPRSplitRatio","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address[]","name":"","type":"address[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isAYSActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastNAVAA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastNAVBB","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastStrategyPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"limit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_revertIfNeeded","type":"bool"}],"name":"liquidate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidationTolerance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lossToleranceBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDecreaseDefault","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minAprSplitAYS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oneToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceAA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceBB","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalancer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"referral","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"releaseBlocksPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"restoreOperations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revertIfTooLow","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_allowed","type":"bool"}],"name":"setAllowAAWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_allowed","type":"bool"}],"name":"setAllowBBWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeReceiver","type":"address"}],"name":"setFeeReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_guardian","type":"address"}],"name":"setGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_active","type":"bool"}],"name":"setIsAYSActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_diff","type":"uint256"}],"name":"setLiquidationTolerance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_diffBps","type":"uint256"}],"name":"setLossToleranceBps","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxDecreaseDefault","type":"uint256"}],"name":"setMaxDecreaseDefault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_aprSplit","type":"uint256"}],"name":"setMinAprSplitAYS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rebalancer","type":"address"}],"name":"setRebalancer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_releaseBlocksPeriod","type":"uint256"}],"name":"setReleaseBlocksPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_allowed","type":"bool"}],"name":"setRevertIfTooLow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_allowed","type":"bool"}],"name":"setSkipDefaultCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_val","type":"uint256"}],"name":"setStkIDLEPerUnderlying","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_trancheAPRSplitRatio","type":"uint256"}],"name":"setTrancheAPRSplitRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_unlentPerc","type":"uint256"}],"name":"setUnlentPerc","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"skipDefaultCheck","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stkIDLEPerUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategyToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tranche","type":"address"}],"name":"toggleStkIDLEForTranche","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trancheAPRSplitRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trancheIdealWeightRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_tranche","type":"address"}],"name":"tranchePrice","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":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unclaimedFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unlentPerc","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateAccounting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tranche","type":"address"}],"name":"virtualPrice","outputs":[{"internalType":"uint256","name":"_virtualPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawAA","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawBB","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b5060cf80546001600160a01b031916600117905561597a806100336000396000f3fe60806040523480156200001157600080fd5b5060043610620005295760003560e01c80636f47d99b11620002ad578063a8c62e761162000179578063e3e3936811620000df578063efdcd974116200009e578063efdcd9741462000afc578063f2fde38b1462000b13578063f8623d9b1462000b2a578063fc0c546a1462000b41578063fdf4c0dc1462000b55578063fe81a0241462000b5f57600080fd5b8063e3e393681462000a9c578063e70875ad1462000ab0578063e86d8c341462000ac7578063eb120bf41462000ade578063edd636fb1462000af257600080fd5b8063cc1158051162000138578063cc1158051462000a38578063d816f5dc1462000a4f578063dc82697c1462000a66578063ddca3f431462000a70578063dfd5b1c91462000a7a578063e07eace61462000a8557600080fd5b8063a8c62e7614620009df578063b3f0067414620009f3578063b450dfce1462000a07578063bc063e1a1462000a1e578063c9aba3561462000a2857600080fd5b80638f5aa090116200021f5780639af6485411620001de5780639af6485414620009715780639d3ef4b21462000988578063a219d218146200099d578063a27eccc114620009b4578063a3d0bd4814620009be578063a4d66daf14620009d557600080fd5b80638f5aa090146200090b5780639290d427146200092257806392b29be3146200093957806394929dc1146200094357806399abe5e8146200095a57600080fd5b806383975b67116200026c57806383975b6714620008b75780638456cb5914620008c157806387109ffd14620008cb5780638a0dac4a14620008e25780638da5cb5b14620008f957600080fd5b80636f47d99b1462000870578063715018a61462000885578063734d8287146200088f578063747efea114620008995780637509539214620008ad57600080fd5b80632c2a7ca411620003f957806344966ba0116200035f5780635c975abb116200031e5780635c975abb146200081857806362adade514620008245780636373ea69146200082e57806366a4c633146200083857806369fe0e2d14620008425780636cfd1553146200085957600080fd5b806344966ba014620007ba578063452a932014620007ce5780634684059014620007e2578063494347e714620007f957806355c70701146200080357600080fd5b80633f4ba83a11620003b85780633f4ba83a146200075a5780633fc8cef31462000764578063400f7d321462000778578063408f3a30146200078257806340bd61091462000799578063435d44d914620007a357600080fd5b80632c2a7ca414620007025780632cc0800e146200070c5780633403c2fc1462000723578063387af1bd146200072d5780633b28d537146200074157600080fd5b806318dc7195116200049f5780632047782a116200045e5780632047782a146200069f57806325cdd86014620006a957806325f66adf14620006b35780632758db0c14620006bd57806329811ee514620006d45780632a3e4dc214620006eb57600080fd5b806318dc719514620006265780631a7e0ce5146200063d5780631cac6454146200065c5780631cf7a8ff14620006735780631ed4fd97146200068a57600080fd5b80631072cbea11620004ec5780631072cbea14620005c157806312361ac214620005d85780631441a5a914620005e25780631533c31e14620005fb57806315c44b8b146200061257600080fd5b806301d22ccd146200052e57806303311d75146200055f57806306a9a8bf1462000585578063085a2b78146200059e578063088f4b7814620005a8575b600080fd5b60d25462000542906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b620005766200057036600462003e17565b62000b69565b60405162000556919062003f17565b6200058f60ed5481565b60405190815260200162000556565b6200058f60da5481565b620005bf620005b936600462003fb4565b62000f88565b005b620005bf620005d236600462003fea565b62000fa5565b6200058f60dc5481565b60e854620005429061010090046001600160a01b031681565b620005bf6200060c36600462004019565b62000fcf565b60d95462000542906001600160a01b031681565b620005bf62000637366004620040a2565b62000fde565b60ea546200064b9060ff1681565b604051901515815260200162000556565b620005bf6200066d36600462004019565b620015fa565b620005bf6200068436600462004019565b62001609565b60d3546200064b90600160b81b900460ff1681565b6200058f60e55481565b6200058f62001641565b6200058f60db5481565b6200058f620006ce366004620041d3565b62001654565b6200058f620006e536600462004206565b62001675565b62000542620006fc36600462004019565b6200168e565b6200058f60ec5481565b6200058f6200071d36600462004226565b620016b9565b620005bf620016d6565b60ca5462000542906001600160a01b031681565b6200074b620016ec565b6040516200055691906200424e565b620005bf62001750565b60cd5462000542906001600160a01b031681565b6200058f60dd5481565b620005bf6200079336600462004019565b62001764565b6200058f60ee5481565b620005bf620007b436600462004019565b62001773565b60d65462000542906001600160a01b031681565b60d05462000542906001600160a01b031681565b620005bf620007f336600462003fb4565b620017ad565b620005bf620017d5565b60d3546200064b90600160a01b900460ff1681565b60335460ff166200064b565b6200058f60de5481565b6200058f60e95481565b6200058f60ef5481565b620005bf6200085336600462004019565b6200180b565b620005bf6200086a36600462004206565b6200183f565b60d3546200064b90600160b01b900460ff1681565b620005bf62001886565b6200058f60e15481565b60d55462000542906001600160a01b031681565b6200058f60eb5481565b620005bf6200189c565b620005bf620018ca565b620005bf620008dc36600462004019565b620018de565b620005bf620008f336600462004206565b62001912565b6065546001600160a01b031662000542565b620005bf6200091c36600462003fb4565b62001959565b6200058f6200093336600462004206565b62001981565b6200058f60e25481565b620005bf6200095436600462004019565b620019d7565b6200058f6200096b36600462004019565b620019e6565b6200058f6200098236600462004019565b62001a56565b60d3546200064b90600160a81b900460ff1681565b6200058f620009ae36600462004206565b62001ac6565b6200058f60d15481565b620005bf620009cf36600462004019565b62001ad3565b6200058f60c95481565b60d45462000542906001600160a01b031681565b60e45462000542906001600160a01b031681565b6200058f62000a1836600462004019565b62001b08565b6200058f614e2081565b6200058f670de0b6b3a764000081565b620005bf62000a4936600462003fb4565b62001b25565b6200058f62000a6036600462004226565b62001b4d565b6200058f62001b6a565b6200058f60e35481565b6200058f620186a081565b620005bf62000a9636600462003fb4565b62001c6a565b60d75462000542906001600160a01b031681565b6200058f62000ac136600462004019565b62001c92565b620005bf62000ad836600462004019565b62001caf565b60d85462000542906001600160a01b031681565b6200058f60e65481565b620005bf62000b0d36600462004206565b62001cbe565b620005bf62000b2436600462004206565b62001d05565b620005bf62000b3b36600462004206565b62001d81565b60cf5462000542906001600160a01b031681565b6200058f60e05481565b6200058f60df5481565b606062000b7562001e8f565b6040805160038082526080820190925290816020015b606081526020019060019003908162000b8b57505060d4549091506001600160a01b03168b8b600381811062000bc55762000bc56200429d565b905060200201602081019062000bdc919062003fb4565b62000ea35760008c8c600081811062000bf95762000bf96200429d565b905060200201602081019062000c10919062003fb4565b62000e4357816001600160a01b0316638ec71e0c8686600081811062000c3a5762000c3a6200429d565b905060200281019062000c4e9190620042b3565b6040518363ffffffff1660e01b815260040162000c6d929190620042fc565b6000604051808303816000875af115801562000c8d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000cb791908101906200432b565b8360028151811062000ccd5762000ccd6200429d565b602002602001018190525062000dfc82888880806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508b8b80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508e8e808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c92508b91506001905081811062000dad5762000dad6200429d565b905060200281019062000dc19190620042b3565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525062001ef892505050565b8560008151811062000e125762000e126200429d565b602002602001018660018151811062000e2f5762000e2f6200429d565b602002602001018295508390528390525050505b4360cc55801562000e55578062000e58565b60015b60e75562000e65620021fa565b8c8c600281811062000e7b5762000e7b6200429d565b905060200201602081019062000e92919062003fb4565b62000ea15762000ea162002360565b505b60cf5460009062000ebd906001600160a01b031662002393565b90506000620186a060e25462000ed262001b6a565b62000ede9190620043cf565b62000eea919062004407565b90508082111562000f77576001600160a01b03831663b6b55f2562000f1083856200441e565b6040518263ffffffff1660e01b815260040162000f2f91815260200190565b6020604051808303816000875af115801562000f4f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000f75919062004438565b505b5050509a9950505050505050505050565b62000f9262002401565b60ea805460ff1916911515919091179055565b62000faf62002401565b60ca5462000fcb906001600160a01b0384811691168362002451565b5050565b62000fd962002401565b60ee55565b600054610100900460ff161580801562000fff5750600054600160ff909116105b806200101b5750303b1580156200101b575060005460ff166001145b620010845760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015620010a8576000805461ff0019166101001790555b60cf546001600160a01b031615620010e75760405162461bcd60e51b81526020600482015260016024820152603160f81b60448201526064016200107b565b6001600160a01b038616620011105760405162461bcd60e51b81526004016200107b9062004452565b6001600160a01b038516620011395760405162461bcd60e51b81526004016200107b9062004452565b6001600160a01b038916620011625760405162461bcd60e51b81526004016200107b9062004452565b620186a0841115620011885760405162461bcd60e51b81526004016200107b906200446d565b62001192620024bb565b6200119f8a8989620024ef565b6000856001600160a01b031663747efea16040518163ffffffff1660e01b8152600401602060405180830381865afa158015620011e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001206919062004488565b90506000816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562001249573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200127391908101906200452d565b9050620012ae60405180604001604052806015815260200174024b23632a1a2279020a0902a3930b731b43290169605d1b8152508262002580565b620012d56040518060400160405280600381526020016241415f60e81b8152508362002580565b604051620012e39062003db1565b620012f0929190620045a8565b604051809103906000f0801580156200130d573d6000803e3d6000fd5b5060d680546001600160a01b0319166001600160a01b0392909216919091179055604080518082019091526015815274024b23632a1a227902121102a3930b731b43290169605d1b602082015262001366908262002580565b6200138d6040518060400160405280600381526020016242425f60e81b8152508362002580565b6040516200139b9062003db1565b620013a8929190620045a8565b604051809103906000f080158015620013c5573d6000803e3d6000fd5b5060d780546001600160a01b03199081166001600160a01b039384161790915560cf805482168e841690811790915560d4805483168b851617905560d58054831686851617905560d28054909216928b1692909217905560da8790556040805163313ce56760e01b815290516000929163313ce5679160048083019260209291908290030181865afa15801562001460573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001486919062004438565b6200149390600a620046ce565b60d181905560d3805460cd80546001600160a01b03191673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc217905560dc83905560dd8390556107d060e25561190060e655760101017a250d5630b4cf539739df2c5dacb4c659f2488d6001600160b81b031990911617905590506200150d8c89620025ae565b60d55462001525906001600160a01b031689620025ae565b6200152f620025c6565b60e055613a9860e35560e4805460d080546001600160a01b038e166001600160a01b03199182161790915560ea805460ff1916600117905561c35060ec5561138860ed5560cd805482166006602160991b011790551673fdbb4d606c199f091143bd604c85c191a526fbd017905562049d4060e6555050508015620015ee576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050505050565b6200160462002401565b60ef55565b6200161362002401565b620186a08160e281905511156200163e5760405162461bcd60e51b81526004016200107b906200446d565b50565b60006200164f600062002637565b905090565b60006200166062001e8f565b6200166c8383620026d6565b90505b92915050565b60006200166f8262001688600062002637565b620027b2565b60ce81815481106200169f57600080fd5b6000918252602090912001546001600160a01b0316905081565b60d7546000906200166c9084906001600160a01b031684620028cd565b620016e062002a1f565b620016ea62002a46565b565b606060ce8054806020026020016040519081016040528092919081815260200182805480156200174657602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001727575b5050505050905090565b6200175a62002a1f565b620016ea62002a69565b6200176e62002401565b60c955565b6200177d62002401565b620186a08160ec8190551115620017a85760405162461bcd60e51b81526004016200107b906200446d565b60ec55565b620017b762002401565b60d38054911515600160b81b0260ff60b81b19909216919091179055565b620017df62002a1f565b60d3805460ff60b81b1916600160b81b179055620017fc620021fa565b60d3805460ff60b81b19169055565b6200181562002401565b614e208160e381905511156200163e5760405162461bcd60e51b81526004016200107b906200446d565b6200184962002401565b60d280546001600160a01b0319166001600160a01b0383169081179091556200163e5760405162461bcd60e51b81526004016200107b9062004452565b6200189062002abd565b620016ea600062002b19565b620018a662002401565b620018b062002a69565b60d3805463ffffffff60a01b19166201010160a01b179055565b620018d462002a1f565b620016ea62002b6b565b620018e862002401565b620186a081106200190d5760405162461bcd60e51b81526004016200107b906200446d565b60ed55565b6200191c62002401565b60d080546001600160a01b0319166001600160a01b0383169081179091556200163e5760405162461bcd60e51b81526004016200107b9062004452565b6200196362002401565b60d38054911515600160a81b0260ff60a81b19909216919091179055565b60de5460df5460009190620019ce846200199a62001b6a565b620019a68486620046dc565b60d6546001600160a01b03898116911614620019c35784620019c5565b855b60da5462002bab565b50949350505050565b620019e162002401565b60e655565b6000620019f560335460ff1690565b158062001a0b575060d354600160a81b900460ff165b62001a3d5760405162461bcd60e51b81526020600482015260016024820152603360f81b60448201526064016200107b565b60d7546200166f9083906001600160a01b031662002ed1565b600062001a6560335460ff1690565b158062001a7b575060d354600160a01b900460ff165b62001aad5760405162461bcd60e51b81526020600482015260016024820152603360f81b60448201526064016200107b565b60d6546200166f9083906001600160a01b031662002ed1565b60006200166f82620030fe565b62001add62002401565b620186a08160da81905511156200163e5760405162461bcd60e51b81526004016200107b906200446d565b60d6546000906200166f9083906001600160a01b031683620028cd565b62001b2f62002401565b60d38054911515600160a01b0260ff60a01b19909216919091179055565b60d6546000906200166c9084906001600160a01b031684620028cd565b60d5546040805163313ce56760e01b815290516000926001600160a01b0316918391839163313ce5679160048083019260209291908290030181865afa15801562001bb9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001bdf919062004438565b905060e15462001bee62003199565b60cf5462001c05906001600160a01b031662002393565b62001c1284600a620046ce565b62001c1c620025c6565b62001c278762002393565b62001c339190620043cf565b62001c3f919062004407565b62001c4b9190620046dc565b62001c5791906200441e565b62001c6391906200441e565b9250505090565b62001c7462002401565b60d38054911515600160b01b0260ff60b01b19909216919091179055565b60d7546000906200166f9083906001600160a01b031683620028cd565b62001cb962002401565b60eb55565b62001cc862002401565b60e480546001600160a01b0319166001600160a01b0383169081179091556200163e5760405162461bcd60e51b81526004016200107b9062004452565b62001d0f62002abd565b6001600160a01b03811662001d765760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016200107b565b6200163e8162002b19565b62001d8b62002401565b60d65460d7546001600160a01b03918216918381169116148062001dc05750806001600160a01b0316826001600160a01b0316145b62001df25760405162461bcd60e51b81526020600482015260016024820152603960f81b60448201526064016200107b565b806001600160a01b0316826001600160a01b0316141562001e4e5760d8546001600160a01b03161562001e2757600062001e2a565b60015b60d880546001600160a01b0319166001600160a01b03929092169190911790555050565b60d9546001600160a01b03161562001e6857600062001e6b565b60015b60d980546001600160a01b0319166001600160a01b03929092169190911790555050565b60d2546001600160a01b031633148062001ec657506065546001600160a01b03165b6001600160a01b0316336001600160a01b0316145b620016ea5760405162461bcd60e51b81526020600482015260016024820152601b60f91b60448201526064016200107b565b606080600080886001600160a01b031663c4f59f9b6040518163ffffffff1660e01b8152600401600060405180830381865afa15801562001f3d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001f679190810190620046f7565b905060008082516001600160401b0381111562001f885762001f8862004033565b60405190808252806020026020018201604052801562001fbd57816020015b606081526020019060019003908162001fa75790505b5087519091501562001fe2578680602001905181019062001fdf919062004790565b90505b8251806001600160401b0381111562001fff5762001fff62004033565b60405190808252806020026020018201604052801562002029578160200160208202803683370190505b509650806001600160401b0381111562002047576200204762004033565b60405190808252806020026020018201604052801562002071578160200160208202803683370190505b50955060005b81811015620021ea578481815181106200209557620020956200429d565b60200260200101519350898181518110620020b457620020b46200429d565b602002602001015115620020c857620021d7565b6001600160a01b038416734da27a545c0c5b758a6ba100e3a049001de870f514156200210657737fc66500c84a76ad7e9c93437bfc5ac33e2ddae993505b62002168848483815181106200212057620021206200429d565b60200260200101518e84815181106200213d576200213d6200429d565b60200260200101518e85815181106200215a576200215a6200429d565b6020026020010151620031fb565b8983815181106200217d576200217d6200429d565b602002602001018984815181106200219957620021996200429d565b6020026020010182815250828152505050868181518110620021bf57620021bf6200429d565b602002602001015186620021d49190620046dc565b95505b620021e28162004862565b905062002077565b5050505050955095509592505050565b60de5460df5460006200220e8284620046dc565b905060006200221c62001b6a565b60da5490915082821115620022705760e354620186a0906200223f85856200441e565b6200224b9190620043cf565b62002257919062004407565b60e160008282546200226a9190620046dc565b90915550505b60d654600090819062002290906001600160a01b031685878a8762002bab565b60d75491935091506000908190620022b5906001600160a01b031687898b8962002bab565b9092509050620022c6838a62004880565b60de55600081128015620022e4575087620022e182620048c7565b12155b156200233e5760d354600160b81b900460ff16620023295760405162461bcd60e51b81526020600482015260016024820152600d60fa1b60448201526064016200107b565b600060df556200233862002a46565b6200234e565b6200234a818962004880565b60df555b5060dc929092555060dd555050505050565b60e15480156200163e5760e45460d6546200238a9183916001600160a01b0391821691166200330a565b50600060e15550565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015620023db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200166f919062004438565b33620024156065546001600160a01b031690565b6001600160a01b031614620016ea5760405162461bcd60e51b81526020600482015260016024820152601b60f91b60448201526064016200107b565b6040516001600160a01b038316602482015260448101829052620024b690849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152620033f8565b505050565b600054610100900460ff16620024e55760405162461bcd60e51b81526004016200107b90620048e7565b620016ea620034d4565b6001600160a01b038216620025185760405162461bcd60e51b81526004016200107b9062004452565b6001600160a01b038116620025415760405162461bcd60e51b81526004016200107b9062004452565b6200254b6200350a565b620025556200353e565b60c983905560ca80546001600160a01b0319166001600160a01b038416179055620024b68162001d05565b606082826040516020016200259792919062004932565b604051602081830303815290604052905092915050565b62000fcb6001600160a01b0383168260001962003572565b60d4546040805163501ad8ff60e11b815290516000926001600160a01b03169163a035b1fe9160048083019260209291908290030181865afa15801562002611573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200164f919062004438565b600062003dbf826200264d576200362c62002652565b620036bf5b60d65490915060009062002672906001600160a01b031663ffffffff8416565b60d75490915060009062002692906001600160a01b031663ffffffff8516565b6200269e9083620046dc565b905080620026b157506000949350505050565b80620026c1620186a084620043cf565b620026cd919062004407565b95945050505050565b60d45460405163852a12e360e01b8152600481018490526000916001600160a01b03169063852a12e3906024016020604051808303816000875af115801562002723573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002749919062004438565b90508115620027a25760eb54806200275f575060645b836200276c8284620046dc565b1015620027a05760405162461bcd60e51b81526020600482015260016024820152603560f81b60448201526064016200107b565b505b828111156200166f575090919050565b60008060d460009054906101000a90046001600160a01b03166001600160a01b031663845bc8046040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002809573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200282f919062004438565b60da5460d654919250906001600160a01b03868116911614846200286857806200285a57826200285d565b60005b93505050506200166f565b80620028aa576200287d85620186a06200441e565b6200288c83620186a06200441e565b620028989085620043cf565b620028a4919062004407565b620028c3565b84620028b78385620043cf565b620028c3919062004407565b9695505050505050565b6000620028d9620036d5565b83620028e55762002a18565b620028f0846200371d565b620029356040516bffffffffffffffffffffffff193260601b16602082015243603482015260540160408051601f19818403018152919052805160209091012060cb55565b6200293f62003776565b62002949620021fa565b62002955838562003803565b60cf546001600160a01b031660006200296e8262002393565b9050620029876001600160a01b038316333089620039e5565b620029ab81620029978462002393565b620029a391906200441e565b33876200330a565b9250620029c3620029bd600162002637565b62003a1f565b6001600160a01b0384161562002a1557604080518781526001600160a01b03861660208201527f496d589d8b7eb829a8d7b30e24a326ac33991f5cea96429b69231a6b15b54b1d910160405180910390a15b50505b9392505050565b60d0546001600160a01b031633148062001ec657506065546001600160a01b031662001eb1565b62002a5062002b6b565b60d3805463ffffffff60a01b191661010160b01b179055565b62002a7362003a93565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6065546001600160a01b03163314620016ea5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016200107b565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b62002b75620036d5565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25862002aa03390565b6000806000876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002bef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002c15919062004438565b905085158062002c23575080155b1562002c3857505060d1549050600062002ec7565b600062002c46878962004965565b90508062002c675762002c5989620030fe565b600093509350505062002ec7565b600081131562002ca057620186a060e3548262002c859190620049aa565b62002c91919062004a3b565b62002c9d908262004965565b90505b60d65460d7546001600160a01b0391821691908116908b1682148062002cc7578262002cc9565b815b6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002d07573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002d2d919062004438565b62002d3b5783955062002e91565b600084131562002d93576000620186a062002d578a826200441e565b62002d639087620049aa565b62002d6f919062004a3b565b90508162002d7e578062002d8a565b62002d8a818662004965565b96505062002e91565b620186a08a60ee5462002da79190620043cf565b62002db3919062004407565b62002dbe85620048c7565b1162002e175760df5460de5460009062002dda908390620046dc565b62002de68388620049aa565b62002df2919062004a3b565b90508262002e01578062002e0d565b62002e0d818762004965565b9750505062002e91565b60008162002e26578962002e32565b62002e328a8c6200441e565b9050600062002e42868362004880565b9050600081131562002e66578262002e5b578562002e5e565b60005b975062002e8e565b8262002e8a57600062002e7983620048c7565b985098505050505050505062002ec7565b8097505b50505b84670de0b6b3a764000062002ea7888c62004880565b62002eb39190620043cf565b62002ebf919062004407565b965050505050505b9550959350505050565b600062002edd62003ade565b62002ee762003b3a565b62002ef162003776565b62002efb620021fa565b8262002f6f576040516370a0823160e01b81523360048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801562002f46573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002f6c919062004438565b92505b8262002f8f5760405162461bcd60e51b81526004016200107b9062004452565b60cf546001600160a01b0316600062002fa88262002393565b9050670de0b6b3a764000062002fbe85620030fe565b62002fca9087620043cf565b62002fd6919062004407565b925082818111156200301557816200300662002ff382876200441e565b60d354600160b01b900460ff16620026d6565b620030129190620046dc565b93505b604051632770a7eb60e21b8152336004820152602481018790526001600160a01b03861690639dc29fac90604401600060405180830381600087803b1580156200305e57600080fd5b505af115801562003073573d6000803e3d6000fd5b505060d6546001600160a01b03888116911614159150620030b09050578060de6000828254620030a491906200441e565b90915550620030ca9050565b8060df6000828254620030c491906200441e565b90915550505b620030da620029bd600162002637565b620030f06001600160a01b038416338662002451565b5050506200166f6001609755565b6000816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200313f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003165919062004438565b6200317257505060d15490565b60d6546001600160a01b03838116911614620031915760dd546200166f565b505060dc5490565b60e65460cc54600091908290620031b190436200441e565b60e754909150600181118015620031c757508282105b15620031f55782620031da83826200441e565b620031e69083620043cf565b620031f2919062004407565b93505b50505090565b6000808362003212576200320f8662002393565b93505b83620032245750600090508062003301565b73e592427a0aece92de3edee1f18e0157c058615646200324f6001600160a01b038816828762003572565b6040805160a081018252878152306020820152600091810162003274426064620046dc565b815260200187815260200186815250905085826001600160a01b031663c04b8d59836040518263ffffffff1660e01b8152600401620032b4919062004a6f565b6020604051808303816000875af1158015620032d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620032fa919062004438565b9350935050505b94509492505050565b60006200331782620030fe565b6200332b670de0b6b3a764000086620043cf565b62003337919062004407565b6040516340c10f1960e01b81526001600160a01b03858116600483015260248201839052919250908316906340c10f1990604401600060405180830381600087803b1580156200338657600080fd5b505af11580156200339b573d6000803e3d6000fd5b505060d6546001600160a01b03858116911614159150620033d89050578360de6000828254620033cc9190620046dc565b9091555062002a189050565b8360df6000828254620033ec9190620046dc565b90915550509392505050565b60006200344f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031662003bb29092919063ffffffff16565b90508051600014806200347357508080602001905181019062003473919062004ac9565b620024b65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016200107b565b600054610100900460ff16620034fe5760405162461bcd60e51b81526004016200107b90620048e7565b6033805460ff19169055565b600054610100900460ff16620035345760405162461bcd60e51b81526004016200107b90620048e7565b620016ea62003bcb565b600054610100900460ff16620035685760405162461bcd60e51b81526004016200107b90620048e7565b620016ea62003c00565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015620035c3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620035e9919062004438565b9050620036268463095ea7b360e01b85620036058686620046dc565b6040516001600160a01b03909216602483015260448201526064016200247e565b50505050565b6000670de0b6b3a7640000620036428362001981565b836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562003681573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620036a7919062004438565b620036b39190620043cf565b6200166f919062004407565b6000670de0b6b3a76400006200364283620030fe565b60335460ff1615620016ea5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016200107b565b60c954806200372a575050565b80826200373662001b6a565b620037429190620046dc565b111562000fcb5760405162461bcd60e51b81526020600482015260016024820152601960f91b60448201526064016200107b565b600062003782620025c6565b60d354909150600160b81b900460ff16620037fe5780620186a060ed54620186a0620037af91906200441e565b60e054620037be9190620043cf565b620037ca919062004407565b1115620037fe5760405162461bcd60e51b81526020600482015260016024820152600d60fa1b60448201526064016200107b565b60e055565b60ef5480158062003836575060d7546001600160a01b03848116911614801562003836575060d9546001600160a01b0316155b8062003864575060d6546001600160a01b03848116911614801562003864575060d8546001600160a01b0316155b156200386f57505050565b6040516370a0823160e01b81523360048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015620038b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620038dd919062004438565b90506000808211620038f15760006200391d565b670de0b6b3a76400006200390586620030fe565b620039119084620043cf565b6200391d919062004407565b620039299085620046dc565b60d1549091506200393b8483620043cf565b62003947919062004407565b6040516370a0823160e01b815233600482015273aac13a116ea7016689993193fce4badc8038136f906370a0823190602401602060405180830381865afa15801562003997573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620039bd919062004438565b1015620039de5760405162461bcd60e51b81526004016200107b906200446d565b5050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052620036269085906323b872dd60e01b906084016200247e565b60ec54801562003a30578062003a34565b61c3505b60ea5490915060ff161562000fcb576000620182b8831062003a5b5750620182b862003a6f565b8183111562003a6c57508162003a6f565b50805b620186a062003a7f8483620043cf565b62003a8b919062004407565b60da55505050565b60335460ff16620016ea5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016200107b565b6002609754141562003b335760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016200107b565b6002609755565b60cb546040516bffffffffffffffffffffffff193260601b166020820152436034820152605401604051602081830303815290604052805190602001201415620016ea5760405162461bcd60e51b81526020600482015260016024820152600760fb1b60448201526064016200107b565b6001609755565b606062003bc3848460008562003c2a565b949350505050565b600054610100900460ff1662003bf55760405162461bcd60e51b81526004016200107b90620048e7565b620016ea3362002b19565b600054610100900460ff1662003bab5760405162461bcd60e51b81526004016200107b90620048e7565b60608247101562003c8d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016200107b565b600080866001600160a01b0316858760405162003cab919062004ae9565b60006040518083038185875af1925050503d806000811462003cea576040519150601f19603f3d011682016040523d82523d6000602084013e62003cef565b606091505b509150915062003d028783838762003d0d565b979650505050505050565b6060831562003d7e57825162003d76576001600160a01b0385163b62003d765760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016200107b565b508162003bc3565b62003bc3838381511562003d955781518083602001fd5b8060405162461bcd60e51b81526004016200107b919062004b07565b610e128062004b3383390190565b620016ea62004b1c565b60008083601f84011262003ddc57600080fd5b5081356001600160401b0381111562003df457600080fd5b6020830191508360208260051b850101111562003e1057600080fd5b9250929050565b60008060008060008060008060008060a08b8d03121562003e3757600080fd5b8a356001600160401b038082111562003e4f57600080fd5b62003e5d8e838f0162003dc9565b909c509a5060208d013591508082111562003e7757600080fd5b62003e858e838f0162003dc9565b909a50985060408d013591508082111562003e9f57600080fd5b62003ead8e838f0162003dc9565b909850965060608d013591508082111562003ec757600080fd5b62003ed58e838f0162003dc9565b909650945060808d013591508082111562003eef57600080fd5b5062003efe8d828e0162003dc9565b915080935050809150509295989b9194979a5092959850565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b8381101562003f9757888603603f19018552825180518088529088019088880190845b8181101562003f805783518352928a0192918a019160010162003f62565b509097505050938601939186019160010162003f3f565b509398975050505050505050565b80151581146200163e57600080fd5b60006020828403121562003fc757600080fd5b813562002a188162003fa5565b6001600160a01b03811681146200163e57600080fd5b6000806040838503121562003ffe57600080fd5b82356200400b8162003fd4565b946020939093013593505050565b6000602082840312156200402c57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171562004074576200407462004033565b604052919050565b60006001600160401b0382111562004098576200409862004033565b5060051b60200190565b60008060008060008060008060006101208a8c031215620040c257600080fd5b893598506020808b0135620040d78162003fd4565b985060408b0135620040e98162003fd4565b975060608b0135620040fb8162003fd4565b965060808b01356200410d8162003fd4565b955060a08b01356200411f8162003fd4565b945060c08b0135935060e08b013592506101008b01356001600160401b038111156200414a57600080fd5b8b01601f81018d136200415c57600080fd5b8035620041736200416d826200407c565b62004049565b81815260059190911b8201830190838101908f8311156200419357600080fd5b928401925b82841015620041be578335620041ae8162003fd4565b8252928401929084019062004198565b80955050505050509295985092959850929598565b60008060408385031215620041e757600080fd5b823591506020830135620041fb8162003fa5565b809150509250929050565b6000602082840312156200421957600080fd5b813562002a188162003fd4565b600080604083850312156200423a57600080fd5b823591506020830135620041fb8162003fd4565b6020808252825182820181905260009190848201906040850190845b81811015620042915783516001600160a01b0316835292840192918401916001016200426a565b50909695505050505050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112620042cb57600080fd5b8301803591506001600160401b03821115620042e657600080fd5b60200191503681900382131562003e1057600080fd5b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600060208083850312156200433f57600080fd5b82516001600160401b038111156200435657600080fd5b8301601f810185136200436857600080fd5b8051620043796200416d826200407c565b81815260059190911b820183019083810190878311156200439957600080fd5b928401925b8284101562003d02578351825292840192908401906200439e565b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615620043ec57620043ec620043b9565b500290565b634e487b7160e01b600052601260045260246000fd5b600082620044195762004419620043f1565b500490565b600082821015620044335762004433620043b9565b500390565b6000602082840312156200444b57600080fd5b5051919050565b6020808252600190820152600360fc1b604082015260600190565b6020808252600190820152603760f81b604082015260600190565b6000602082840312156200449b57600080fd5b815162002a188162003fd4565b60005b83811015620044c5578181015183820152602001620044ab565b83811115620036265750506000910152565b60006001600160401b03831115620044f357620044f362004033565b62004508601f8401601f191660200162004049565b90508281528383830111156200451d57600080fd5b62002a18836020830184620044a8565b6000602082840312156200454057600080fd5b81516001600160401b038111156200455757600080fd5b8201601f810184136200456957600080fd5b62003bc384825160208401620044d7565b6000815180845262004594816020860160208601620044a8565b601f01601f19169290920160200192915050565b604081526000620045bd60408301856200457a565b8281036020840152620026cd81856200457a565b600181815b8085111562004612578160001904821115620045f657620045f6620043b9565b808516156200460457918102915b93841c9390800290620045d6565b509250929050565b6000826200462b575060016200166f565b816200463a575060006200166f565b81600181146200465357600281146200465e576200467e565b60019150506200166f565b60ff841115620046725762004672620043b9565b50506001821b6200166f565b5060208310610133831016604e8410600b8410161715620046a3575081810a6200166f565b620046af8383620045d1565b8060001904821115620046c657620046c6620043b9565b029392505050565b60006200166c83836200461a565b60008219821115620046f257620046f2620043b9565b500190565b600060208083850312156200470b57600080fd5b82516001600160401b038111156200472257600080fd5b8301601f810185136200473457600080fd5b8051620047456200416d826200407c565b81815260059190911b820183019083810190878311156200476557600080fd5b928401925b8284101562003d02578351620047808162003fd4565b825292840192908401906200476a565b60006020808385031215620047a457600080fd5b82516001600160401b0380821115620047bc57600080fd5b818501915085601f830112620047d157600080fd5b8151620047e26200416d826200407c565b81815260059190911b830184019084810190888311156200480257600080fd5b8585015b838110156200485557805185811115620048205760008081fd5b8601603f81018b13620048335760008081fd5b620048468b8983015160408401620044d7565b84525091860191860162004806565b5098975050505050505050565b6000600019821415620048795762004879620043b9565b5060010190565b600080821280156001600160ff1b0384900385131615620048a557620048a5620043b9565b600160ff1b8390038412811615620048c157620048c1620043b9565b50500190565b6000600160ff1b821415620048e057620048e0620043b9565b5060000390565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000835162004946818460208801620044a8565b8351908301906200495c818360208801620044a8565b01949350505050565b60008083128015600160ff1b850184121615620049865762004986620043b9565b6001600160ff1b0384018313811615620049a457620049a4620043b9565b50500390565b60006001600160ff1b0381841382841380821686840486111615620049d357620049d3620043b9565b600160ff1b6000871282811687830589121615620049f557620049f5620043b9565b6000871292508782058712848416161562004a145762004a14620043b9565b8785058712818416161562004a2d5762004a2d620043b9565b505050929093029392505050565b60008262004a4d5762004a4d620043f1565b600160ff1b82146000198414161562004a6a5762004a6a620043b9565b500590565b602081526000825160a0602084015262004a8d60c08401826200457a565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60006020828403121562004adc57600080fd5b815162002a188162003fa5565b6000825162004afd818460208701620044a8565b9190910192915050565b6020815260006200166c60208301846200457a565b634e487b7160e01b600052605160045260246000fdfe60806040523480156200001157600080fd5b5060405162000e1238038062000e128339810160408190526200003491620001f4565b8151829082906200004d90600390602085019062000081565b5080516200006390600490602084019062000081565b5050600580546001600160a01b03191633179055506200029b915050565b8280546200008f906200025e565b90600052602060002090601f016020900481019282620000b35760008555620000fe565b82601f10620000ce57805160ff1916838001178555620000fe565b82800160010185558215620000fe579182015b82811115620000fe578251825591602001919060010190620000e1565b506200010c92915062000110565b5090565b5b808211156200010c576000815560010162000111565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200014f57600080fd5b81516001600160401b03808211156200016c576200016c62000127565b604051601f8301601f19908116603f0116810190828211818310171562000197576200019762000127565b81604052838152602092508683858801011115620001b457600080fd5b600091505b83821015620001d85785820183015181830184015290820190620001b9565b83821115620001ea5760008385830101525b9695505050505050565b600080604083850312156200020857600080fd5b82516001600160401b03808211156200022057600080fd5b6200022e868387016200013d565b935060208501519150808211156200024557600080fd5b5062000254858286016200013d565b9150509250929050565b600181811c908216806200027357607f821691505b602082108114156200029557634e487b7160e01b600052602260045260246000fd5b50919050565b610b6780620002ab6000396000f3fe608060405234801561001057600080fd5b50600436106100ca5760003560e01c806340c10f191161007c57806340c10f191461018257806370a082311461019757806395d89b41146101c05780639dc29fac146101c8578063a457c2d7146101db578063a9059cbb146101ee578063dd62ed3e1461020157600080fd5b806306fdde03146100cf57806307546172146100ed578063095ea7b31461011857806318160ddd1461013b57806323b872dd1461014d578063313ce56714610160578063395093511461016f575b600080fd5b6100d7610214565b6040516100e491906109a4565b60405180910390f35b600554610100906001600160a01b031681565b6040516001600160a01b0390911681526020016100e4565b61012b610126366004610a15565b6102a6565b60405190151581526020016100e4565b6002545b6040519081526020016100e4565b61012b61015b366004610a3f565b6102be565b604051601281526020016100e4565b61012b61017d366004610a15565b6102e2565b610195610190366004610a15565b610304565b005b61013f6101a5366004610a7b565b6001600160a01b031660009081526020819052604090205490565b6100d7610361565b6101956101d6366004610a15565b610370565b61012b6101e9366004610a15565b6103c4565b61012b6101fc366004610a15565b61043f565b61013f61020f366004610a9d565b61044d565b60606003805461022390610ad0565b80601f016020809104026020016040519081016040528092919081815260200182805461024f90610ad0565b801561029c5780601f106102715761010080835404028352916020019161029c565b820191906000526020600020905b81548152906001019060200180831161027f57829003601f168201915b5050505050905090565b6000336102b4818585610478565b5060019392505050565b6000336102cc85828561059d565b6102d7858585610617565b506001949350505050565b6000336102b48185856102f5838361044d565b6102ff9190610b0b565b610478565b6005546001600160a01b031633146103535760405162461bcd60e51b815260206004820152600d60248201526c0a8a4829c86908a744282aaa89609b1b60448201526064015b60405180910390fd5b61035d82826107bb565b5050565b60606004805461022390610ad0565b6005546001600160a01b031633146103ba5760405162461bcd60e51b815260206004820152600d60248201526c0a8a4829c86908a744282aaa89609b1b604482015260640161034a565b61035d828261087a565b600033816103d2828661044d565b9050838110156104325760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161034a565b6102d78286868403610478565b6000336102b4818585610617565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166104da5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161034a565b6001600160a01b03821661053b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161034a565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006105a9848461044d565b9050600019811461061157818110156106045760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161034a565b6106118484848403610478565b50505050565b6001600160a01b03831661067b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161034a565b6001600160a01b0382166106dd5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161034a565b6001600160a01b038316600090815260208190526040902054818110156107555760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161034a565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610611565b6001600160a01b0382166108115760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161034a565b80600260008282546108239190610b0b565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b0382166108da5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161034a565b6001600160a01b0382166000908152602081905260409020548181101561094e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161034a565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610590565b600060208083528351808285015260005b818110156109d1578581018301518582016040015282016109b5565b818111156109e3576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b0381168114610a1057600080fd5b919050565b60008060408385031215610a2857600080fd5b610a31836109f9565b946020939093013593505050565b600080600060608486031215610a5457600080fd5b610a5d846109f9565b9250610a6b602085016109f9565b9150604084013590509250925092565b600060208284031215610a8d57600080fd5b610a96826109f9565b9392505050565b60008060408385031215610ab057600080fd5b610ab9836109f9565b9150610ac7602084016109f9565b90509250929050565b600181811c90821680610ae457607f821691505b60208210811415610b0557634e487b7160e01b600052602260045260246000fd5b50919050565b60008219821115610b2c57634e487b7160e01b600052601160045260246000fd5b50019056fea2646970667358221220a4ff320bee61a8bbf6fca5851081eb415647af1a4d8f34bb4fdcdc9edeabb68064736f6c634300080a0033a2646970667358221220e25a489a3ba56c1cc9b802371a92d25190461103841dc3d8c7efe29fc0dc0d7d64736f6c634300080a0033

Deployed Bytecode

0x60806040523480156200001157600080fd5b5060043610620005295760003560e01c80636f47d99b11620002ad578063a8c62e761162000179578063e3e3936811620000df578063efdcd974116200009e578063efdcd9741462000afc578063f2fde38b1462000b13578063f8623d9b1462000b2a578063fc0c546a1462000b41578063fdf4c0dc1462000b55578063fe81a0241462000b5f57600080fd5b8063e3e393681462000a9c578063e70875ad1462000ab0578063e86d8c341462000ac7578063eb120bf41462000ade578063edd636fb1462000af257600080fd5b8063cc1158051162000138578063cc1158051462000a38578063d816f5dc1462000a4f578063dc82697c1462000a66578063ddca3f431462000a70578063dfd5b1c91462000a7a578063e07eace61462000a8557600080fd5b8063a8c62e7614620009df578063b3f0067414620009f3578063b450dfce1462000a07578063bc063e1a1462000a1e578063c9aba3561462000a2857600080fd5b80638f5aa090116200021f5780639af6485411620001de5780639af6485414620009715780639d3ef4b21462000988578063a219d218146200099d578063a27eccc114620009b4578063a3d0bd4814620009be578063a4d66daf14620009d557600080fd5b80638f5aa090146200090b5780639290d427146200092257806392b29be3146200093957806394929dc1146200094357806399abe5e8146200095a57600080fd5b806383975b67116200026c57806383975b6714620008b75780638456cb5914620008c157806387109ffd14620008cb5780638a0dac4a14620008e25780638da5cb5b14620008f957600080fd5b80636f47d99b1462000870578063715018a61462000885578063734d8287146200088f578063747efea114620008995780637509539214620008ad57600080fd5b80632c2a7ca411620003f957806344966ba0116200035f5780635c975abb116200031e5780635c975abb146200081857806362adade514620008245780636373ea69146200082e57806366a4c633146200083857806369fe0e2d14620008425780636cfd1553146200085957600080fd5b806344966ba014620007ba578063452a932014620007ce5780634684059014620007e2578063494347e714620007f957806355c70701146200080357600080fd5b80633f4ba83a11620003b85780633f4ba83a146200075a5780633fc8cef31462000764578063400f7d321462000778578063408f3a30146200078257806340bd61091462000799578063435d44d914620007a357600080fd5b80632c2a7ca414620007025780632cc0800e146200070c5780633403c2fc1462000723578063387af1bd146200072d5780633b28d537146200074157600080fd5b806318dc7195116200049f5780632047782a116200045e5780632047782a146200069f57806325cdd86014620006a957806325f66adf14620006b35780632758db0c14620006bd57806329811ee514620006d45780632a3e4dc214620006eb57600080fd5b806318dc719514620006265780631a7e0ce5146200063d5780631cac6454146200065c5780631cf7a8ff14620006735780631ed4fd97146200068a57600080fd5b80631072cbea11620004ec5780631072cbea14620005c157806312361ac214620005d85780631441a5a914620005e25780631533c31e14620005fb57806315c44b8b146200061257600080fd5b806301d22ccd146200052e57806303311d75146200055f57806306a9a8bf1462000585578063085a2b78146200059e578063088f4b7814620005a8575b600080fd5b60d25462000542906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b620005766200057036600462003e17565b62000b69565b60405162000556919062003f17565b6200058f60ed5481565b60405190815260200162000556565b6200058f60da5481565b620005bf620005b936600462003fb4565b62000f88565b005b620005bf620005d236600462003fea565b62000fa5565b6200058f60dc5481565b60e854620005429061010090046001600160a01b031681565b620005bf6200060c36600462004019565b62000fcf565b60d95462000542906001600160a01b031681565b620005bf62000637366004620040a2565b62000fde565b60ea546200064b9060ff1681565b604051901515815260200162000556565b620005bf6200066d36600462004019565b620015fa565b620005bf6200068436600462004019565b62001609565b60d3546200064b90600160b81b900460ff1681565b6200058f60e55481565b6200058f62001641565b6200058f60db5481565b6200058f620006ce366004620041d3565b62001654565b6200058f620006e536600462004206565b62001675565b62000542620006fc36600462004019565b6200168e565b6200058f60ec5481565b6200058f6200071d36600462004226565b620016b9565b620005bf620016d6565b60ca5462000542906001600160a01b031681565b6200074b620016ec565b6040516200055691906200424e565b620005bf62001750565b60cd5462000542906001600160a01b031681565b6200058f60dd5481565b620005bf6200079336600462004019565b62001764565b6200058f60ee5481565b620005bf620007b436600462004019565b62001773565b60d65462000542906001600160a01b031681565b60d05462000542906001600160a01b031681565b620005bf620007f336600462003fb4565b620017ad565b620005bf620017d5565b60d3546200064b90600160a01b900460ff1681565b60335460ff166200064b565b6200058f60de5481565b6200058f60e95481565b6200058f60ef5481565b620005bf6200085336600462004019565b6200180b565b620005bf6200086a36600462004206565b6200183f565b60d3546200064b90600160b01b900460ff1681565b620005bf62001886565b6200058f60e15481565b60d55462000542906001600160a01b031681565b6200058f60eb5481565b620005bf6200189c565b620005bf620018ca565b620005bf620008dc36600462004019565b620018de565b620005bf620008f336600462004206565b62001912565b6065546001600160a01b031662000542565b620005bf6200091c36600462003fb4565b62001959565b6200058f6200093336600462004206565b62001981565b6200058f60e25481565b620005bf6200095436600462004019565b620019d7565b6200058f6200096b36600462004019565b620019e6565b6200058f6200098236600462004019565b62001a56565b60d3546200064b90600160a81b900460ff1681565b6200058f620009ae36600462004206565b62001ac6565b6200058f60d15481565b620005bf620009cf36600462004019565b62001ad3565b6200058f60c95481565b60d45462000542906001600160a01b031681565b60e45462000542906001600160a01b031681565b6200058f62000a1836600462004019565b62001b08565b6200058f614e2081565b6200058f670de0b6b3a764000081565b620005bf62000a4936600462003fb4565b62001b25565b6200058f62000a6036600462004226565b62001b4d565b6200058f62001b6a565b6200058f60e35481565b6200058f620186a081565b620005bf62000a9636600462003fb4565b62001c6a565b60d75462000542906001600160a01b031681565b6200058f62000ac136600462004019565b62001c92565b620005bf62000ad836600462004019565b62001caf565b60d85462000542906001600160a01b031681565b6200058f60e65481565b620005bf62000b0d36600462004206565b62001cbe565b620005bf62000b2436600462004206565b62001d05565b620005bf62000b3b36600462004206565b62001d81565b60cf5462000542906001600160a01b031681565b6200058f60e05481565b6200058f60df5481565b606062000b7562001e8f565b6040805160038082526080820190925290816020015b606081526020019060019003908162000b8b57505060d4549091506001600160a01b03168b8b600381811062000bc55762000bc56200429d565b905060200201602081019062000bdc919062003fb4565b62000ea35760008c8c600081811062000bf95762000bf96200429d565b905060200201602081019062000c10919062003fb4565b62000e4357816001600160a01b0316638ec71e0c8686600081811062000c3a5762000c3a6200429d565b905060200281019062000c4e9190620042b3565b6040518363ffffffff1660e01b815260040162000c6d929190620042fc565b6000604051808303816000875af115801562000c8d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262000cb791908101906200432b565b8360028151811062000ccd5762000ccd6200429d565b602002602001018190525062000dfc82888880806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508b8b80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508e8e808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c92508b91506001905081811062000dad5762000dad6200429d565b905060200281019062000dc19190620042b3565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525062001ef892505050565b8560008151811062000e125762000e126200429d565b602002602001018660018151811062000e2f5762000e2f6200429d565b602002602001018295508390528390525050505b4360cc55801562000e55578062000e58565b60015b60e75562000e65620021fa565b8c8c600281811062000e7b5762000e7b6200429d565b905060200201602081019062000e92919062003fb4565b62000ea15762000ea162002360565b505b60cf5460009062000ebd906001600160a01b031662002393565b90506000620186a060e25462000ed262001b6a565b62000ede9190620043cf565b62000eea919062004407565b90508082111562000f77576001600160a01b03831663b6b55f2562000f1083856200441e565b6040518263ffffffff1660e01b815260040162000f2f91815260200190565b6020604051808303816000875af115801562000f4f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000f75919062004438565b505b5050509a9950505050505050505050565b62000f9262002401565b60ea805460ff1916911515919091179055565b62000faf62002401565b60ca5462000fcb906001600160a01b0384811691168362002451565b5050565b62000fd962002401565b60ee55565b600054610100900460ff161580801562000fff5750600054600160ff909116105b806200101b5750303b1580156200101b575060005460ff166001145b620010845760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084015b60405180910390fd5b6000805460ff191660011790558015620010a8576000805461ff0019166101001790555b60cf546001600160a01b031615620010e75760405162461bcd60e51b81526020600482015260016024820152603160f81b60448201526064016200107b565b6001600160a01b038616620011105760405162461bcd60e51b81526004016200107b9062004452565b6001600160a01b038516620011395760405162461bcd60e51b81526004016200107b9062004452565b6001600160a01b038916620011625760405162461bcd60e51b81526004016200107b9062004452565b620186a0841115620011885760405162461bcd60e51b81526004016200107b906200446d565b62001192620024bb565b6200119f8a8989620024ef565b6000856001600160a01b031663747efea16040518163ffffffff1660e01b8152600401602060405180830381865afa158015620011e0573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001206919062004488565b90506000816001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801562001249573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200127391908101906200452d565b9050620012ae60405180604001604052806015815260200174024b23632a1a2279020a0902a3930b731b43290169605d1b8152508262002580565b620012d56040518060400160405280600381526020016241415f60e81b8152508362002580565b604051620012e39062003db1565b620012f0929190620045a8565b604051809103906000f0801580156200130d573d6000803e3d6000fd5b5060d680546001600160a01b0319166001600160a01b0392909216919091179055604080518082019091526015815274024b23632a1a227902121102a3930b731b43290169605d1b602082015262001366908262002580565b6200138d6040518060400160405280600381526020016242425f60e81b8152508362002580565b6040516200139b9062003db1565b620013a8929190620045a8565b604051809103906000f080158015620013c5573d6000803e3d6000fd5b5060d780546001600160a01b03199081166001600160a01b039384161790915560cf805482168e841690811790915560d4805483168b851617905560d58054831686851617905560d28054909216928b1692909217905560da8790556040805163313ce56760e01b815290516000929163313ce5679160048083019260209291908290030181865afa15801562001460573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001486919062004438565b6200149390600a620046ce565b60d181905560d3805460cd80546001600160a01b03191673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc217905560dc83905560dd8390556107d060e25561190060e655760101017a250d5630b4cf539739df2c5dacb4c659f2488d6001600160b81b031990911617905590506200150d8c89620025ae565b60d55462001525906001600160a01b031689620025ae565b6200152f620025c6565b60e055613a9860e35560e4805460d080546001600160a01b038e166001600160a01b03199182161790915560ea805460ff1916600117905561c35060ec5561138860ed5560cd805482166006602160991b011790551673fdbb4d606c199f091143bd604c85c191a526fbd017905562049d4060e6555050508015620015ee576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050505050565b6200160462002401565b60ef55565b6200161362002401565b620186a08160e281905511156200163e5760405162461bcd60e51b81526004016200107b906200446d565b50565b60006200164f600062002637565b905090565b60006200166062001e8f565b6200166c8383620026d6565b90505b92915050565b60006200166f8262001688600062002637565b620027b2565b60ce81815481106200169f57600080fd5b6000918252602090912001546001600160a01b0316905081565b60d7546000906200166c9084906001600160a01b031684620028cd565b620016e062002a1f565b620016ea62002a46565b565b606060ce8054806020026020016040519081016040528092919081815260200182805480156200174657602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831162001727575b5050505050905090565b6200175a62002a1f565b620016ea62002a69565b6200176e62002401565b60c955565b6200177d62002401565b620186a08160ec8190551115620017a85760405162461bcd60e51b81526004016200107b906200446d565b60ec55565b620017b762002401565b60d38054911515600160b81b0260ff60b81b19909216919091179055565b620017df62002a1f565b60d3805460ff60b81b1916600160b81b179055620017fc620021fa565b60d3805460ff60b81b19169055565b6200181562002401565b614e208160e381905511156200163e5760405162461bcd60e51b81526004016200107b906200446d565b6200184962002401565b60d280546001600160a01b0319166001600160a01b0383169081179091556200163e5760405162461bcd60e51b81526004016200107b9062004452565b6200189062002abd565b620016ea600062002b19565b620018a662002401565b620018b062002a69565b60d3805463ffffffff60a01b19166201010160a01b179055565b620018d462002a1f565b620016ea62002b6b565b620018e862002401565b620186a081106200190d5760405162461bcd60e51b81526004016200107b906200446d565b60ed55565b6200191c62002401565b60d080546001600160a01b0319166001600160a01b0383169081179091556200163e5760405162461bcd60e51b81526004016200107b9062004452565b6200196362002401565b60d38054911515600160a81b0260ff60a81b19909216919091179055565b60de5460df5460009190620019ce846200199a62001b6a565b620019a68486620046dc565b60d6546001600160a01b03898116911614620019c35784620019c5565b855b60da5462002bab565b50949350505050565b620019e162002401565b60e655565b6000620019f560335460ff1690565b158062001a0b575060d354600160a81b900460ff165b62001a3d5760405162461bcd60e51b81526020600482015260016024820152603360f81b60448201526064016200107b565b60d7546200166f9083906001600160a01b031662002ed1565b600062001a6560335460ff1690565b158062001a7b575060d354600160a01b900460ff165b62001aad5760405162461bcd60e51b81526020600482015260016024820152603360f81b60448201526064016200107b565b60d6546200166f9083906001600160a01b031662002ed1565b60006200166f82620030fe565b62001add62002401565b620186a08160da81905511156200163e5760405162461bcd60e51b81526004016200107b906200446d565b60d6546000906200166f9083906001600160a01b031683620028cd565b62001b2f62002401565b60d38054911515600160a01b0260ff60a01b19909216919091179055565b60d6546000906200166c9084906001600160a01b031684620028cd565b60d5546040805163313ce56760e01b815290516000926001600160a01b0316918391839163313ce5679160048083019260209291908290030181865afa15801562001bb9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062001bdf919062004438565b905060e15462001bee62003199565b60cf5462001c05906001600160a01b031662002393565b62001c1284600a620046ce565b62001c1c620025c6565b62001c278762002393565b62001c339190620043cf565b62001c3f919062004407565b62001c4b9190620046dc565b62001c5791906200441e565b62001c6391906200441e565b9250505090565b62001c7462002401565b60d38054911515600160b01b0260ff60b01b19909216919091179055565b60d7546000906200166f9083906001600160a01b031683620028cd565b62001cb962002401565b60eb55565b62001cc862002401565b60e480546001600160a01b0319166001600160a01b0383169081179091556200163e5760405162461bcd60e51b81526004016200107b9062004452565b62001d0f62002abd565b6001600160a01b03811662001d765760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016200107b565b6200163e8162002b19565b62001d8b62002401565b60d65460d7546001600160a01b03918216918381169116148062001dc05750806001600160a01b0316826001600160a01b0316145b62001df25760405162461bcd60e51b81526020600482015260016024820152603960f81b60448201526064016200107b565b806001600160a01b0316826001600160a01b0316141562001e4e5760d8546001600160a01b03161562001e2757600062001e2a565b60015b60d880546001600160a01b0319166001600160a01b03929092169190911790555050565b60d9546001600160a01b03161562001e6857600062001e6b565b60015b60d980546001600160a01b0319166001600160a01b03929092169190911790555050565b60d2546001600160a01b031633148062001ec657506065546001600160a01b03165b6001600160a01b0316336001600160a01b0316145b620016ea5760405162461bcd60e51b81526020600482015260016024820152601b60f91b60448201526064016200107b565b606080600080886001600160a01b031663c4f59f9b6040518163ffffffff1660e01b8152600401600060405180830381865afa15801562001f3d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405262001f679190810190620046f7565b905060008082516001600160401b0381111562001f885762001f8862004033565b60405190808252806020026020018201604052801562001fbd57816020015b606081526020019060019003908162001fa75790505b5087519091501562001fe2578680602001905181019062001fdf919062004790565b90505b8251806001600160401b0381111562001fff5762001fff62004033565b60405190808252806020026020018201604052801562002029578160200160208202803683370190505b509650806001600160401b0381111562002047576200204762004033565b60405190808252806020026020018201604052801562002071578160200160208202803683370190505b50955060005b81811015620021ea578481815181106200209557620020956200429d565b60200260200101519350898181518110620020b457620020b46200429d565b602002602001015115620020c857620021d7565b6001600160a01b038416734da27a545c0c5b758a6ba100e3a049001de870f514156200210657737fc66500c84a76ad7e9c93437bfc5ac33e2ddae993505b62002168848483815181106200212057620021206200429d565b60200260200101518e84815181106200213d576200213d6200429d565b60200260200101518e85815181106200215a576200215a6200429d565b6020026020010151620031fb565b8983815181106200217d576200217d6200429d565b602002602001018984815181106200219957620021996200429d565b6020026020010182815250828152505050868181518110620021bf57620021bf6200429d565b602002602001015186620021d49190620046dc565b95505b620021e28162004862565b905062002077565b5050505050955095509592505050565b60de5460df5460006200220e8284620046dc565b905060006200221c62001b6a565b60da5490915082821115620022705760e354620186a0906200223f85856200441e565b6200224b9190620043cf565b62002257919062004407565b60e160008282546200226a9190620046dc565b90915550505b60d654600090819062002290906001600160a01b031685878a8762002bab565b60d75491935091506000908190620022b5906001600160a01b031687898b8962002bab565b9092509050620022c6838a62004880565b60de55600081128015620022e4575087620022e182620048c7565b12155b156200233e5760d354600160b81b900460ff16620023295760405162461bcd60e51b81526020600482015260016024820152600d60fa1b60448201526064016200107b565b600060df556200233862002a46565b6200234e565b6200234a818962004880565b60df555b5060dc929092555060dd555050505050565b60e15480156200163e5760e45460d6546200238a9183916001600160a01b0391821691166200330a565b50600060e15550565b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a0823190602401602060405180830381865afa158015620023db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200166f919062004438565b33620024156065546001600160a01b031690565b6001600160a01b031614620016ea5760405162461bcd60e51b81526020600482015260016024820152601b60f91b60448201526064016200107b565b6040516001600160a01b038316602482015260448101829052620024b690849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152620033f8565b505050565b600054610100900460ff16620024e55760405162461bcd60e51b81526004016200107b90620048e7565b620016ea620034d4565b6001600160a01b038216620025185760405162461bcd60e51b81526004016200107b9062004452565b6001600160a01b038116620025415760405162461bcd60e51b81526004016200107b9062004452565b6200254b6200350a565b620025556200353e565b60c983905560ca80546001600160a01b0319166001600160a01b038416179055620024b68162001d05565b606082826040516020016200259792919062004932565b604051602081830303815290604052905092915050565b62000fcb6001600160a01b0383168260001962003572565b60d4546040805163501ad8ff60e11b815290516000926001600160a01b03169163a035b1fe9160048083019260209291908290030181865afa15801562002611573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200164f919062004438565b600062003dbf826200264d576200362c62002652565b620036bf5b60d65490915060009062002672906001600160a01b031663ffffffff8416565b60d75490915060009062002692906001600160a01b031663ffffffff8516565b6200269e9083620046dc565b905080620026b157506000949350505050565b80620026c1620186a084620043cf565b620026cd919062004407565b95945050505050565b60d45460405163852a12e360e01b8152600481018490526000916001600160a01b03169063852a12e3906024016020604051808303816000875af115801562002723573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002749919062004438565b90508115620027a25760eb54806200275f575060645b836200276c8284620046dc565b1015620027a05760405162461bcd60e51b81526020600482015260016024820152603560f81b60448201526064016200107b565b505b828111156200166f575090919050565b60008060d460009054906101000a90046001600160a01b03166001600160a01b031663845bc8046040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002809573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200282f919062004438565b60da5460d654919250906001600160a01b03868116911614846200286857806200285a57826200285d565b60005b93505050506200166f565b80620028aa576200287d85620186a06200441e565b6200288c83620186a06200441e565b620028989085620043cf565b620028a4919062004407565b620028c3565b84620028b78385620043cf565b620028c3919062004407565b9695505050505050565b6000620028d9620036d5565b83620028e55762002a18565b620028f0846200371d565b620029356040516bffffffffffffffffffffffff193260601b16602082015243603482015260540160408051601f19818403018152919052805160209091012060cb55565b6200293f62003776565b62002949620021fa565b62002955838562003803565b60cf546001600160a01b031660006200296e8262002393565b9050620029876001600160a01b038316333089620039e5565b620029ab81620029978462002393565b620029a391906200441e565b33876200330a565b9250620029c3620029bd600162002637565b62003a1f565b6001600160a01b0384161562002a1557604080518781526001600160a01b03861660208201527f496d589d8b7eb829a8d7b30e24a326ac33991f5cea96429b69231a6b15b54b1d910160405180910390a15b50505b9392505050565b60d0546001600160a01b031633148062001ec657506065546001600160a01b031662001eb1565b62002a5062002b6b565b60d3805463ffffffff60a01b191661010160b01b179055565b62002a7362003a93565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6065546001600160a01b03163314620016ea5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016200107b565b606580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b62002b75620036d5565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25862002aa03390565b6000806000876001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002bef573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002c15919062004438565b905085158062002c23575080155b1562002c3857505060d1549050600062002ec7565b600062002c46878962004965565b90508062002c675762002c5989620030fe565b600093509350505062002ec7565b600081131562002ca057620186a060e3548262002c859190620049aa565b62002c91919062004a3b565b62002c9d908262004965565b90505b60d65460d7546001600160a01b0391821691908116908b1682148062002cc7578262002cc9565b815b6001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562002d07573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002d2d919062004438565b62002d3b5783955062002e91565b600084131562002d93576000620186a062002d578a826200441e565b62002d639087620049aa565b62002d6f919062004a3b565b90508162002d7e578062002d8a565b62002d8a818662004965565b96505062002e91565b620186a08a60ee5462002da79190620043cf565b62002db3919062004407565b62002dbe85620048c7565b1162002e175760df5460de5460009062002dda908390620046dc565b62002de68388620049aa565b62002df2919062004a3b565b90508262002e01578062002e0d565b62002e0d818762004965565b9750505062002e91565b60008162002e26578962002e32565b62002e328a8c6200441e565b9050600062002e42868362004880565b9050600081131562002e66578262002e5b578562002e5e565b60005b975062002e8e565b8262002e8a57600062002e7983620048c7565b985098505050505050505062002ec7565b8097505b50505b84670de0b6b3a764000062002ea7888c62004880565b62002eb39190620043cf565b62002ebf919062004407565b965050505050505b9550959350505050565b600062002edd62003ade565b62002ee762003b3a565b62002ef162003776565b62002efb620021fa565b8262002f6f576040516370a0823160e01b81523360048201526001600160a01b038316906370a0823190602401602060405180830381865afa15801562002f46573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062002f6c919062004438565b92505b8262002f8f5760405162461bcd60e51b81526004016200107b9062004452565b60cf546001600160a01b0316600062002fa88262002393565b9050670de0b6b3a764000062002fbe85620030fe565b62002fca9087620043cf565b62002fd6919062004407565b925082818111156200301557816200300662002ff382876200441e565b60d354600160b01b900460ff16620026d6565b620030129190620046dc565b93505b604051632770a7eb60e21b8152336004820152602481018790526001600160a01b03861690639dc29fac90604401600060405180830381600087803b1580156200305e57600080fd5b505af115801562003073573d6000803e3d6000fd5b505060d6546001600160a01b03888116911614159150620030b09050578060de6000828254620030a491906200441e565b90915550620030ca9050565b8060df6000828254620030c491906200441e565b90915550505b620030da620029bd600162002637565b620030f06001600160a01b038416338662002451565b5050506200166f6001609755565b6000816001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200313f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062003165919062004438565b6200317257505060d15490565b60d6546001600160a01b03838116911614620031915760dd546200166f565b505060dc5490565b60e65460cc54600091908290620031b190436200441e565b60e754909150600181118015620031c757508282105b15620031f55782620031da83826200441e565b620031e69083620043cf565b620031f2919062004407565b93505b50505090565b6000808362003212576200320f8662002393565b93505b83620032245750600090508062003301565b73e592427a0aece92de3edee1f18e0157c058615646200324f6001600160a01b038816828762003572565b6040805160a081018252878152306020820152600091810162003274426064620046dc565b815260200187815260200186815250905085826001600160a01b031663c04b8d59836040518263ffffffff1660e01b8152600401620032b4919062004a6f565b6020604051808303816000875af1158015620032d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620032fa919062004438565b9350935050505b94509492505050565b60006200331782620030fe565b6200332b670de0b6b3a764000086620043cf565b62003337919062004407565b6040516340c10f1960e01b81526001600160a01b03858116600483015260248201839052919250908316906340c10f1990604401600060405180830381600087803b1580156200338657600080fd5b505af11580156200339b573d6000803e3d6000fd5b505060d6546001600160a01b03858116911614159150620033d89050578360de6000828254620033cc9190620046dc565b9091555062002a189050565b8360df6000828254620033ec9190620046dc565b90915550509392505050565b60006200344f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031662003bb29092919063ffffffff16565b90508051600014806200347357508080602001905181019062003473919062004ac9565b620024b65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016200107b565b600054610100900460ff16620034fe5760405162461bcd60e51b81526004016200107b90620048e7565b6033805460ff19169055565b600054610100900460ff16620035345760405162461bcd60e51b81526004016200107b90620048e7565b620016ea62003bcb565b600054610100900460ff16620035685760405162461bcd60e51b81526004016200107b90620048e7565b620016ea62003c00565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa158015620035c3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620035e9919062004438565b9050620036268463095ea7b360e01b85620036058686620046dc565b6040516001600160a01b03909216602483015260448201526064016200247e565b50505050565b6000670de0b6b3a7640000620036428362001981565b836001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562003681573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620036a7919062004438565b620036b39190620043cf565b6200166f919062004407565b6000670de0b6b3a76400006200364283620030fe565b60335460ff1615620016ea5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016200107b565b60c954806200372a575050565b80826200373662001b6a565b620037429190620046dc565b111562000fcb5760405162461bcd60e51b81526020600482015260016024820152601960f91b60448201526064016200107b565b600062003782620025c6565b60d354909150600160b81b900460ff16620037fe5780620186a060ed54620186a0620037af91906200441e565b60e054620037be9190620043cf565b620037ca919062004407565b1115620037fe5760405162461bcd60e51b81526020600482015260016024820152600d60fa1b60448201526064016200107b565b60e055565b60ef5480158062003836575060d7546001600160a01b03848116911614801562003836575060d9546001600160a01b0316155b8062003864575060d6546001600160a01b03848116911614801562003864575060d8546001600160a01b0316155b156200386f57505050565b6040516370a0823160e01b81523360048201526000906001600160a01b038516906370a0823190602401602060405180830381865afa158015620038b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620038dd919062004438565b90506000808211620038f15760006200391d565b670de0b6b3a76400006200390586620030fe565b620039119084620043cf565b6200391d919062004407565b620039299085620046dc565b60d1549091506200393b8483620043cf565b62003947919062004407565b6040516370a0823160e01b815233600482015273aac13a116ea7016689993193fce4badc8038136f906370a0823190602401602060405180830381865afa15801562003997573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620039bd919062004438565b1015620039de5760405162461bcd60e51b81526004016200107b906200446d565b5050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052620036269085906323b872dd60e01b906084016200247e565b60ec54801562003a30578062003a34565b61c3505b60ea5490915060ff161562000fcb576000620182b8831062003a5b5750620182b862003a6f565b8183111562003a6c57508162003a6f565b50805b620186a062003a7f8483620043cf565b62003a8b919062004407565b60da55505050565b60335460ff16620016ea5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016200107b565b6002609754141562003b335760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016200107b565b6002609755565b60cb546040516bffffffffffffffffffffffff193260601b166020820152436034820152605401604051602081830303815290604052805190602001201415620016ea5760405162461bcd60e51b81526020600482015260016024820152600760fb1b60448201526064016200107b565b6001609755565b606062003bc3848460008562003c2a565b949350505050565b600054610100900460ff1662003bf55760405162461bcd60e51b81526004016200107b90620048e7565b620016ea3362002b19565b600054610100900460ff1662003bab5760405162461bcd60e51b81526004016200107b90620048e7565b60608247101562003c8d5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016200107b565b600080866001600160a01b0316858760405162003cab919062004ae9565b60006040518083038185875af1925050503d806000811462003cea576040519150601f19603f3d011682016040523d82523d6000602084013e62003cef565b606091505b509150915062003d028783838762003d0d565b979650505050505050565b6060831562003d7e57825162003d76576001600160a01b0385163b62003d765760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016200107b565b508162003bc3565b62003bc3838381511562003d955781518083602001fd5b8060405162461bcd60e51b81526004016200107b919062004b07565b610e128062004b3383390190565b620016ea62004b1c565b60008083601f84011262003ddc57600080fd5b5081356001600160401b0381111562003df457600080fd5b6020830191508360208260051b850101111562003e1057600080fd5b9250929050565b60008060008060008060008060008060a08b8d03121562003e3757600080fd5b8a356001600160401b038082111562003e4f57600080fd5b62003e5d8e838f0162003dc9565b909c509a5060208d013591508082111562003e7757600080fd5b62003e858e838f0162003dc9565b909a50985060408d013591508082111562003e9f57600080fd5b62003ead8e838f0162003dc9565b909850965060608d013591508082111562003ec757600080fd5b62003ed58e838f0162003dc9565b909650945060808d013591508082111562003eef57600080fd5b5062003efe8d828e0162003dc9565b915080935050809150509295989b9194979a5092959850565b6000602080830181845280855180835260408601915060408160051b87010192508387016000805b8381101562003f9757888603603f19018552825180518088529088019088880190845b8181101562003f805783518352928a0192918a019160010162003f62565b509097505050938601939186019160010162003f3f565b509398975050505050505050565b80151581146200163e57600080fd5b60006020828403121562003fc757600080fd5b813562002a188162003fa5565b6001600160a01b03811681146200163e57600080fd5b6000806040838503121562003ffe57600080fd5b82356200400b8162003fd4565b946020939093013593505050565b6000602082840312156200402c57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171562004074576200407462004033565b604052919050565b60006001600160401b0382111562004098576200409862004033565b5060051b60200190565b60008060008060008060008060006101208a8c031215620040c257600080fd5b893598506020808b0135620040d78162003fd4565b985060408b0135620040e98162003fd4565b975060608b0135620040fb8162003fd4565b965060808b01356200410d8162003fd4565b955060a08b01356200411f8162003fd4565b945060c08b0135935060e08b013592506101008b01356001600160401b038111156200414a57600080fd5b8b01601f81018d136200415c57600080fd5b8035620041736200416d826200407c565b62004049565b81815260059190911b8201830190838101908f8311156200419357600080fd5b928401925b82841015620041be578335620041ae8162003fd4565b8252928401929084019062004198565b80955050505050509295985092959850929598565b60008060408385031215620041e757600080fd5b823591506020830135620041fb8162003fa5565b809150509250929050565b6000602082840312156200421957600080fd5b813562002a188162003fd4565b600080604083850312156200423a57600080fd5b823591506020830135620041fb8162003fd4565b6020808252825182820181905260009190848201906040850190845b81811015620042915783516001600160a01b0316835292840192918401916001016200426a565b50909695505050505050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e19843603018112620042cb57600080fd5b8301803591506001600160401b03821115620042e657600080fd5b60200191503681900382131562003e1057600080fd5b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600060208083850312156200433f57600080fd5b82516001600160401b038111156200435657600080fd5b8301601f810185136200436857600080fd5b8051620043796200416d826200407c565b81815260059190911b820183019083810190878311156200439957600080fd5b928401925b8284101562003d02578351825292840192908401906200439e565b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615620043ec57620043ec620043b9565b500290565b634e487b7160e01b600052601260045260246000fd5b600082620044195762004419620043f1565b500490565b600082821015620044335762004433620043b9565b500390565b6000602082840312156200444b57600080fd5b5051919050565b6020808252600190820152600360fc1b604082015260600190565b6020808252600190820152603760f81b604082015260600190565b6000602082840312156200449b57600080fd5b815162002a188162003fd4565b60005b83811015620044c5578181015183820152602001620044ab565b83811115620036265750506000910152565b60006001600160401b03831115620044f357620044f362004033565b62004508601f8401601f191660200162004049565b90508281528383830111156200451d57600080fd5b62002a18836020830184620044a8565b6000602082840312156200454057600080fd5b81516001600160401b038111156200455757600080fd5b8201601f810184136200456957600080fd5b62003bc384825160208401620044d7565b6000815180845262004594816020860160208601620044a8565b601f01601f19169290920160200192915050565b604081526000620045bd60408301856200457a565b8281036020840152620026cd81856200457a565b600181815b8085111562004612578160001904821115620045f657620045f6620043b9565b808516156200460457918102915b93841c9390800290620045d6565b509250929050565b6000826200462b575060016200166f565b816200463a575060006200166f565b81600181146200465357600281146200465e576200467e565b60019150506200166f565b60ff841115620046725762004672620043b9565b50506001821b6200166f565b5060208310610133831016604e8410600b8410161715620046a3575081810a6200166f565b620046af8383620045d1565b8060001904821115620046c657620046c6620043b9565b029392505050565b60006200166c83836200461a565b60008219821115620046f257620046f2620043b9565b500190565b600060208083850312156200470b57600080fd5b82516001600160401b038111156200472257600080fd5b8301601f810185136200473457600080fd5b8051620047456200416d826200407c565b81815260059190911b820183019083810190878311156200476557600080fd5b928401925b8284101562003d02578351620047808162003fd4565b825292840192908401906200476a565b60006020808385031215620047a457600080fd5b82516001600160401b0380821115620047bc57600080fd5b818501915085601f830112620047d157600080fd5b8151620047e26200416d826200407c565b81815260059190911b830184019084810190888311156200480257600080fd5b8585015b838110156200485557805185811115620048205760008081fd5b8601603f81018b13620048335760008081fd5b620048468b8983015160408401620044d7565b84525091860191860162004806565b5098975050505050505050565b6000600019821415620048795762004879620043b9565b5060010190565b600080821280156001600160ff1b0384900385131615620048a557620048a5620043b9565b600160ff1b8390038412811615620048c157620048c1620043b9565b50500190565b6000600160ff1b821415620048e057620048e0620043b9565b5060000390565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6000835162004946818460208801620044a8565b8351908301906200495c818360208801620044a8565b01949350505050565b60008083128015600160ff1b850184121615620049865762004986620043b9565b6001600160ff1b0384018313811615620049a457620049a4620043b9565b50500390565b60006001600160ff1b0381841382841380821686840486111615620049d357620049d3620043b9565b600160ff1b6000871282811687830589121615620049f557620049f5620043b9565b6000871292508782058712848416161562004a145762004a14620043b9565b8785058712818416161562004a2d5762004a2d620043b9565b505050929093029392505050565b60008262004a4d5762004a4d620043f1565b600160ff1b82146000198414161562004a6a5762004a6a620043b9565b500590565b602081526000825160a0602084015262004a8d60c08401826200457a565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a08401528091505092915050565b60006020828403121562004adc57600080fd5b815162002a188162003fa5565b6000825162004afd818460208701620044a8565b9190910192915050565b6020815260006200166c60208301846200457a565b634e487b7160e01b600052605160045260246000fdfe60806040523480156200001157600080fd5b5060405162000e1238038062000e128339810160408190526200003491620001f4565b8151829082906200004d90600390602085019062000081565b5080516200006390600490602084019062000081565b5050600580546001600160a01b03191633179055506200029b915050565b8280546200008f906200025e565b90600052602060002090601f016020900481019282620000b35760008555620000fe565b82601f10620000ce57805160ff1916838001178555620000fe565b82800160010185558215620000fe579182015b82811115620000fe578251825591602001919060010190620000e1565b506200010c92915062000110565b5090565b5b808211156200010c576000815560010162000111565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200014f57600080fd5b81516001600160401b03808211156200016c576200016c62000127565b604051601f8301601f19908116603f0116810190828211818310171562000197576200019762000127565b81604052838152602092508683858801011115620001b457600080fd5b600091505b83821015620001d85785820183015181830184015290820190620001b9565b83821115620001ea5760008385830101525b9695505050505050565b600080604083850312156200020857600080fd5b82516001600160401b03808211156200022057600080fd5b6200022e868387016200013d565b935060208501519150808211156200024557600080fd5b5062000254858286016200013d565b9150509250929050565b600181811c908216806200027357607f821691505b602082108114156200029557634e487b7160e01b600052602260045260246000fd5b50919050565b610b6780620002ab6000396000f3fe608060405234801561001057600080fd5b50600436106100ca5760003560e01c806340c10f191161007c57806340c10f191461018257806370a082311461019757806395d89b41146101c05780639dc29fac146101c8578063a457c2d7146101db578063a9059cbb146101ee578063dd62ed3e1461020157600080fd5b806306fdde03146100cf57806307546172146100ed578063095ea7b31461011857806318160ddd1461013b57806323b872dd1461014d578063313ce56714610160578063395093511461016f575b600080fd5b6100d7610214565b6040516100e491906109a4565b60405180910390f35b600554610100906001600160a01b031681565b6040516001600160a01b0390911681526020016100e4565b61012b610126366004610a15565b6102a6565b60405190151581526020016100e4565b6002545b6040519081526020016100e4565b61012b61015b366004610a3f565b6102be565b604051601281526020016100e4565b61012b61017d366004610a15565b6102e2565b610195610190366004610a15565b610304565b005b61013f6101a5366004610a7b565b6001600160a01b031660009081526020819052604090205490565b6100d7610361565b6101956101d6366004610a15565b610370565b61012b6101e9366004610a15565b6103c4565b61012b6101fc366004610a15565b61043f565b61013f61020f366004610a9d565b61044d565b60606003805461022390610ad0565b80601f016020809104026020016040519081016040528092919081815260200182805461024f90610ad0565b801561029c5780601f106102715761010080835404028352916020019161029c565b820191906000526020600020905b81548152906001019060200180831161027f57829003601f168201915b5050505050905090565b6000336102b4818585610478565b5060019392505050565b6000336102cc85828561059d565b6102d7858585610617565b506001949350505050565b6000336102b48185856102f5838361044d565b6102ff9190610b0b565b610478565b6005546001600160a01b031633146103535760405162461bcd60e51b815260206004820152600d60248201526c0a8a4829c86908a744282aaa89609b1b60448201526064015b60405180910390fd5b61035d82826107bb565b5050565b60606004805461022390610ad0565b6005546001600160a01b031633146103ba5760405162461bcd60e51b815260206004820152600d60248201526c0a8a4829c86908a744282aaa89609b1b604482015260640161034a565b61035d828261087a565b600033816103d2828661044d565b9050838110156104325760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161034a565b6102d78286868403610478565b6000336102b4818585610617565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6001600160a01b0383166104da5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161034a565b6001600160a01b03821661053b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161034a565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b60006105a9848461044d565b9050600019811461061157818110156106045760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161034a565b6106118484848403610478565b50505050565b6001600160a01b03831661067b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161034a565b6001600160a01b0382166106dd5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161034a565b6001600160a01b038316600090815260208190526040902054818110156107555760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161034a565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3610611565b6001600160a01b0382166108115760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161034a565b80600260008282546108239190610b0b565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b6001600160a01b0382166108da5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161034a565b6001600160a01b0382166000908152602081905260409020548181101561094e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161034a565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610590565b600060208083528351808285015260005b818110156109d1578581018301518582016040015282016109b5565b818111156109e3576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b0381168114610a1057600080fd5b919050565b60008060408385031215610a2857600080fd5b610a31836109f9565b946020939093013593505050565b600080600060608486031215610a5457600080fd5b610a5d846109f9565b9250610a6b602085016109f9565b9150604084013590509250925092565b600060208284031215610a8d57600080fd5b610a96826109f9565b9392505050565b60008060408385031215610ab057600080fd5b610ab9836109f9565b9150610ac7602084016109f9565b90509250929050565b600181811c90821680610ae457607f821691505b60208210811415610b0557634e487b7160e01b600052602260045260246000fd5b50919050565b60008219821115610b2c57634e487b7160e01b600052601160045260246000fd5b50019056fea2646970667358221220a4ff320bee61a8bbf6fca5851081eb415647af1a4d8f34bb4fdcdc9edeabb68064736f6c634300080a0033a2646970667358221220e25a489a3ba56c1cc9b802371a92d25190461103841dc3d8c7efe29fc0dc0d7d64736f6c634300080a0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.