ETH Price: $2,994.08 (+2.33%)
 

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
Harvest787839402023-03-05 22:38:561053 days ago1678055936IN
0x91155c72...EB7c35e35
0 ETH0.0000991284060.001
Harvest786278472023-03-04 22:38:451054 days ago1677969525IN
0x91155c72...EB7c35e35
0 ETH0.0000948910950.001
Harvest784657712023-03-03 22:38:521055 days ago1677883132IN
0x91155c72...EB7c35e35
0 ETH0.0000910764120.001
Harvest782587002023-03-02 22:38:401056 days ago1677796720IN
0x91155c72...EB7c35e35
0 ETH0.0000960620240.001
Harvest780469892023-03-01 22:38:401057 days ago1677710320IN
0x91155c72...EB7c35e35
0 ETH0.0001108388370.001
Harvest778383402023-02-28 22:38:521058 days ago1677623932IN
0x91155c72...EB7c35e35
0 ETH0.0001008542340.001
Harvest776447102023-02-27 22:38:501059 days ago1677537530IN
0x91155c72...EB7c35e35
0 ETH0.0002244023240.001
Harvest773828972023-02-26 22:38:501060 days ago1677451130IN
0x91155c72...EB7c35e35
0 ETH0.0000943148070.001
Harvest771137772023-02-25 22:38:431061 days ago1677364723IN
0x91155c72...EB7c35e35
0 ETH0.0000701735910.001
Harvest768245242023-02-24 22:38:451062 days ago1677278325IN
0x91155c72...EB7c35e35
0 ETH0.0001019130260.001
Harvest763981292023-02-23 22:38:491063 days ago1677191929IN
0x91155c72...EB7c35e35
0 ETH0.0001501483650.001
Harvest760895352023-02-22 22:38:521064 days ago1677105532IN
0x91155c72...EB7c35e35
0 ETH0.0001158923580.001
Harvest758260912023-02-21 22:38:421065 days ago1677019122IN
0x91155c72...EB7c35e35
0 ETH0.0001070809440.001
Harvest756355462023-02-20 22:38:471066 days ago1676932727IN
0x91155c72...EB7c35e35
0 ETH0.0003369527780.001
Harvest754400002023-02-19 22:38:441067 days ago1676846324IN
0x91155c72...EB7c35e35
0 ETH0.0000897056430.001
Harvest752166242023-02-18 22:38:521068 days ago1676759932IN
0x91155c72...EB7c35e35
0 ETH0.0000696910570.001
Harvest743920482023-02-15 1:38:511072 days ago1676425131IN
0x91155c72...EB7c35e35
0 ETH0.0001285436230.001
Harvest639382512023-01-10 22:38:441107 days ago1673390324IN
0x91155c72...EB7c35e35
0 ETH0.0000959994490.001
Harvest632148382023-01-09 15:38:461108 days ago1673278726IN
0x91155c72...EB7c35e35
0 ETH0.0001014309460.001
Harvest625642882023-01-08 15:38:391109 days ago1673192319IN
0x91155c72...EB7c35e35
0 ETH0.0000679763030.001
Harvest614143972023-01-06 23:38:521111 days ago1673048332IN
0x91155c72...EB7c35e35
0 ETH0.0000668454710.001
Harvest607370202023-01-05 18:38:541112 days ago1672943934IN
0x91155c72...EB7c35e35
0 ETH0.0000848121150.001
Harvest602145322023-01-04 18:38:561113 days ago1672857536IN
0x91155c72...EB7c35e35
0 ETH0.000083382380.001
Harvest596936962023-01-03 18:38:551114 days ago1672771135IN
0x91155c72...EB7c35e35
0 ETH0.0000694119410.001
Harvest591912992023-01-02 18:38:521115 days ago1672684732IN
0x91155c72...EB7c35e35
0 ETH0.0000917507920.001
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
1075583752023-07-30 11:12:07907 days ago1690715527
0x91155c72...EB7c35e35
0 ETH
1075583752023-07-30 11:12:07907 days ago1690715527
0x91155c72...EB7c35e35
0 ETH
1075583752023-07-30 11:12:07907 days ago1690715527
0x91155c72...EB7c35e35
0 ETH
1075580652023-07-30 11:01:47907 days ago1690714907
0x91155c72...EB7c35e35
0 ETH
1075580652023-07-30 11:01:47907 days ago1690714907
0x91155c72...EB7c35e35
0 ETH
1075580652023-07-30 11:01:47907 days ago1690714907
0x91155c72...EB7c35e35
0 ETH
1075574452023-07-30 10:41:07907 days ago1690713667
0x91155c72...EB7c35e35
0 ETH
1075574452023-07-30 10:41:07907 days ago1690713667
0x91155c72...EB7c35e35
0 ETH
1075574452023-07-30 10:41:07907 days ago1690713667
0x91155c72...EB7c35e35
0 ETH
1075566822023-07-30 10:15:41907 days ago1690712141
0x91155c72...EB7c35e35
0 ETH
1075566822023-07-30 10:15:41907 days ago1690712141
0x91155c72...EB7c35e35
0 ETH
1075566822023-07-30 10:15:41907 days ago1690712141
0x91155c72...EB7c35e35
0 ETH
1075565182023-07-30 10:10:13907 days ago1690711813
0x91155c72...EB7c35e35
0 ETH
1075565182023-07-30 10:10:13907 days ago1690711813
0x91155c72...EB7c35e35
0 ETH
1075565182023-07-30 10:10:13907 days ago1690711813
0x91155c72...EB7c35e35
0 ETH
1075565172023-07-30 10:10:11907 days ago1690711811
0x91155c72...EB7c35e35
0 ETH
1075565172023-07-30 10:10:11907 days ago1690711811
0x91155c72...EB7c35e35
0 ETH
1075565172023-07-30 10:10:11907 days ago1690711811
0x91155c72...EB7c35e35
0 ETH
1075565172023-07-30 10:10:11907 days ago1690711811
0x91155c72...EB7c35e35
0 ETH
1075565172023-07-30 10:10:11907 days ago1690711811
0x91155c72...EB7c35e35
0 ETH
1075565172023-07-30 10:10:11907 days ago1690711811
0x91155c72...EB7c35e35
0 ETH
1075557252023-07-30 9:43:47907 days ago1690710227
0x91155c72...EB7c35e35
0 ETH
1075557252023-07-30 9:43:47907 days ago1690710227
0x91155c72...EB7c35e35
0 ETH
1075557252023-07-30 9:43:47907 days ago1690710227
0x91155c72...EB7c35e35
0 ETH
1075554612023-07-30 9:34:59907 days ago1690709699
0x91155c72...EB7c35e35
0 ETH
View All Internal Transactions

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ReaperAutoCompoundFlashBorrow

Compiler Version
v0.8.11+commit.d7f03943

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU AGPLv3 license
// SPDX-License-Identifier: agpl-3.0

pragma solidity ^0.8.0;

import "./ReaperBaseStrategyv3.sol";

import "./interfaces/IAaveProtocolDataProvider.sol";
import "./interfaces/IAToken.sol";
import "./interfaces/IFlashLoanReceiver.sol";
import "./interfaces/IPool.sol";
import "./interfaces/IPoolAddressesProvider.sol";
import "./interfaces/IRewardsController.sol";
import "./interfaces/IVeloRouter.sol";

import "./libraries/DataTypes.sol";

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";

/**
 * @dev Implementation of a strategy to get yields from depositing
 * the specified asset in a lending pool such as Aave.
 *
 * Flash loans are utilized during deposit() to achieve max leverage
 * without any loops, and during withdraw() to be able to repay first
 * without withdrawing anything. withdraw() can also be performed using
 * excess collateral.
 */
contract ReaperAutoCompoundFlashBorrow is ReaperBaseStrategyv3, IFlashLoanReceiver {
    using SafeERC20 for IERC20;

    // 3rd-party contract addresses
    address public constant VELO_ROUTER = 0xa132DAB612dB5cB9fC9Ac426A0Cc215A3423F9c9;
    address public constant AAVE_ADDRESSES_PROVIDER = 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb;
    address public constant AAVE_DATA_PROVIDER = 0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654;
    address public constant AAVE_REWARDS_CONTROLLER = 0x929EC64c34a17401F460460D4B9390518E5B473e;

    // this strategy's configurable tokens
    IAToken public aWant;
    IERC20 public want;

    uint256 public targetLtv; // in hundredths of percent, 9500 = 95%
    uint256 public maxLtv; // in hundredths of percent, 9700 = 97%
    uint256 public minLeverageAmount;
    uint256 public withdrawSlippageTolerance; // basis points precision, 50 = 0.5%

    /**
     * 0 - no flash loan in progress
     * 1 - deposit()-related flash loan in progress
     */
    uint256 private flashLoanStatus;
    uint256 private constant NO_FL_IN_PROGRESS = 0;
    uint256 private constant DEPOSIT_FL_IN_PROGRESS = 1;

    // Misc constants
    uint16 private constant LENDER_REFERRAL_CODE_NONE = 0;
    uint256 private constant INTEREST_RATE_MODE_VARIABLE = 2;
    uint256 private constant LTV_SAFETY_ZONE = 9800; // upper bound for maxLtv is 98% of max allowed LTV
    uint256 private constant MAX_WITHDRAW_SLIPPAGE_TOLERANCE = 200;

    /**
     * @dev Tokens Used:
     * {OP} - Reward token
     * {USDC} - For charging fees
     * {rewardClaimingTokens} - Array containing aWant + corresponding variable debt token,
     *                          used for claiming any oustanding reward tokens.
     */
    address public constant OP = 0x4200000000000000000000000000000000000042;
    address public constant USDC = 0x7F5c764cBc14f9669B88837ca1490cCa17c31607;
    address[] public rewardClaimingTokens;

    /**
     * @dev Paths used to swap tokens:
     * {opToUsdcPath} - to swap {OP} to {USDC} for charging fees
     * {opToWantPath} - to swap remaining {OP} to {want}
     */
    address[] public opToUsdcPath;
    address[] public opToWantPath;

    /**
     * @dev Initializes the strategy. Sets parameters, saves routes, and gives allowances.
     * @notice see documentation for each variable above its respective declaration.
     */
    constructor(
        address _vault,
        address[] memory _feeRemitters,
        address[] memory _strategists,
        address[] memory _multisigRoles,
        IAToken _aWant,
        address[] memory _opToWantPath,
        uint256 _targetLtv,
        uint256 _maxLtv,
        uint8 _eModeCategory
    ) ReaperBaseStrategyv3(_vault, _feeRemitters, _strategists, _multisigRoles) {
        aWant = _aWant;
        want = IERC20(_aWant.UNDERLYING_ASSET_ADDRESS());
        withdrawSlippageTolerance = 10;
        minLeverageAmount = 1000;
        opToUsdcPath = [OP, USDC];
        setOpToWantPath(_opToWantPath);

        (, , address vToken) = IAaveProtocolDataProvider(AAVE_DATA_PROVIDER).getReserveTokensAddresses(address(want));
        rewardClaimingTokens = [address(_aWant), vToken];

        POOL().setUserEMode(_eModeCategory);
        _safeUpdateTargetLtv(_targetLtv, _maxLtv);
    }

    function ADDRESSES_PROVIDER() public pure override returns (IPoolAddressesProvider) {
        return IPoolAddressesProvider(AAVE_ADDRESSES_PROVIDER);
    }

    function POOL() public view override returns (IPool) {
        return IPool(ADDRESSES_PROVIDER().getPool());
    }

    function executeOperation(
        address[] calldata,
        uint256[] calldata,
        uint256[] calldata,
        address initiator,
        bytes calldata
    ) external override returns (bool) {
        require(msg.sender == address(POOL()), "caller != lending pool");
        require(initiator == address(this), "!initiator");
        require(flashLoanStatus == DEPOSIT_FL_IN_PROGRESS, "invalid flashLoanStatus");
        flashLoanStatus = NO_FL_IN_PROGRESS;

        // simply supply everything we have
        // lender will automatically open a variable debt position
        // since flash loan was requested with interest rate mode VARIABLE
        _supply();

        return true;
    }

    /**
     * @dev Function that puts the funds to work.
     * It gets called whenever someone deposits in the strategy's vault contract.
     */
    function _deposit() internal override {
        _supply();

        (uint256 supply, uint256 borrow) = getSupplyAndBorrow();
        uint256 currentLtv = supply != 0 ? (borrow * PERCENT_DIVISOR) / supply : 0;

        if (currentLtv > maxLtv) {
            _deleverUsingAToken(0);
        } else if (currentLtv < targetLtv) {
            _leverUpMax();
        }
    }

    /**
     * @dev Withdraws funds and sends them back to the vault.
     */
    function _withdraw(uint256 _amount) internal override {
        uint256 wantBal = want.balanceOf(address(this));
        if (_amount <= wantBal) {
            want.safeTransfer(vault, _amount);
            return;
        }

        uint256 remaining = _amount - wantBal;
        (uint256 supply, uint256 borrow) = getSupplyAndBorrow();
        supply -= remaining;
        uint256 postWithdrawLtv = supply != 0 ? (borrow * PERCENT_DIVISOR) / supply : 0;

        if (postWithdrawLtv > maxLtv) {
            _deleverUsingAToken(remaining);
            _withdrawAndSendToVault(remaining, _amount);
        } else if (postWithdrawLtv < targetLtv) {
            _withdrawAndSendToVault(remaining, _amount);
            _leverUpMax();
        } else {
            _withdrawAndSendToVault(remaining, _amount);
        }
    }

    function _deleverUsingAToken(uint256 _amount) internal {
        (uint256 supply, uint256 borrow) = getSupplyAndBorrow();
        uint256 realSupply = supply - borrow;
        require(_amount <= realSupply, "invalid amount");

        // calculate amount to reduce borrow by
        uint256 newRealSupply = realSupply - _amount;
        uint256 newBorrow = (newRealSupply * targetLtv) / (PERCENT_DIVISOR - targetLtv);
        uint256 borrowReduction = borrow - newBorrow;

        // reduce borrow using aToken and withdraw _amount
        POOL().repayWithATokens(address(want), borrowReduction, INTEREST_RATE_MODE_VARIABLE);
    }

    /**
     * @dev Attempts to reach max leverage as per {targetLtv} using a flash loan.
     */
    function _leverUpMax() internal {
        (uint256 supply, uint256 borrow) = getSupplyAndBorrow();
        uint256 realSupply = supply - borrow;
        uint256 desiredBorrow = (realSupply * targetLtv) / (PERCENT_DIVISOR - targetLtv);

        if (desiredBorrow > borrow + minLeverageAmount) {
            _initFlashLoan(desiredBorrow - borrow);
        }
    }

    /**
     * @dev Withdraws {_withdrawAmount} from pool and attempts to send {_vaultExpecting} to vault.
     */
    function _withdrawAndSendToVault(uint256 _withdrawAmount, uint256 _vaultExpecting) internal {
        _withdrawUnderlying(_withdrawAmount);

        uint256 wantBal = want.balanceOf(address(this));
        if (wantBal < _vaultExpecting) {
            require(
                wantBal >= (_vaultExpecting * (PERCENT_DIVISOR - withdrawSlippageTolerance)) / PERCENT_DIVISOR,
                "withdraw: outside slippage tolerance!"
            );
        }

        want.safeTransfer(vault, Math.min(wantBal, _vaultExpecting));
    }

    /**
     * @dev Attempts to Withdraw {_withdrawAmount} from pool. Withdraws max amount that can be
     *      safely withdrawn if {_withdrawAmount} is too high.
     */
    function _withdrawUnderlying(uint256 _withdrawAmount) internal {
        (uint256 supply, uint256 borrow) = getSupplyAndBorrow();
        uint256 necessarySupply = maxLtv != 0 ? (borrow * PERCENT_DIVISOR) / maxLtv : 0; // use maxLtv instead of targetLtv here
        require(supply > necessarySupply, "can't withdraw anything!");

        uint256 withdrawable = supply - necessarySupply;
        _withdrawAmount = Math.min(_withdrawAmount, withdrawable);
        POOL().withdraw(address(want), _withdrawAmount, address(this));
    }

    /**
     * @dev Internal helper function to supply to lending pool that also gives allowance
     */
    function _supply() internal {
        uint256 wantBal = want.balanceOf(address(this));
        if (wantBal != 0) {
            want.safeIncreaseAllowance(address(POOL()), wantBal);
            POOL().supply(address(want), wantBal, address(this), LENDER_REFERRAL_CODE_NONE);
        }
    }

    /**
     * @dev Core function of the strat, in charge of collecting and re-investing rewards.
     */
    function _harvestCore() internal override returns (uint256 callerFee) {
        IRewardsController(AAVE_REWARDS_CONTROLLER).claimAllRewardsToSelf(rewardClaimingTokens);
        callerFee = _chargePerformanceFees();
        _convertOpToWant();
        deposit();
    }

    /**
     * @dev Takes out fees from the rewards.
     * callFeeToUser is set as a percentage of the fee.
     */
    function _chargePerformanceFees() internal returns (uint256 callerFee) {
        uint256 opFee = (IERC20(OP).balanceOf(address(this)) * totalFee) / PERCENT_DIVISOR;
        if (opFee == 0) {
            return 0;
        }

        IERC20 usdc = IERC20(USDC);
        uint256 usdcBalBefore = usdc.balanceOf(address(this));
        _swap(opToUsdcPath, opFee);
        uint256 usdcFee = usdc.balanceOf(address(this)) - usdcBalBefore;

        if (usdcFee != 0) {
            callerFee = (usdcFee * callFee) / PERCENT_DIVISOR;
            uint256 treasuryFeeToVault = (usdcFee * treasuryFee) / PERCENT_DIVISOR;
            uint256 feeToStrategist = (treasuryFeeToVault * strategistFee) / PERCENT_DIVISOR;
            treasuryFeeToVault -= feeToStrategist;

            usdc.safeTransfer(msg.sender, callerFee);
            usdc.safeTransfer(treasury, treasuryFeeToVault);
            usdc.safeTransfer(strategistRemitter, feeToStrategist);
        }
    }

    /**
     * @dev Converts all of this contract's {OP} balance into {want}.
     *      Typically called during harvesting to transform assets back into
     *      {want} for re-depositing.
     */
    function _convertOpToWant() internal {
        uint256 opBal = IERC20(OP).balanceOf(address(this));
        if (opBal != 0) {
            _swap(opToWantPath, opBal);
        }
    }

    /// @dev Helper function to swap given a {_path} and an {_amount}.
    function _swap(address[] memory _path, uint256 _amount) internal {
        IVeloRouter router = IVeloRouter(VELO_ROUTER);
        IVeloRouter.route[] memory routes = new IVeloRouter.route[](_path.length - 1);

        uint256 prevRouteOutput = _amount;
        uint256 output;
        bool useStable;
        for (uint256 i = 0; i < routes.length; i++) {
            (output, useStable) = router.getAmountOut(prevRouteOutput, _path[i], _path[i + 1]);
            routes[i] = IVeloRouter.route({from: _path[i], to: _path[i + 1], stable: useStable});
            prevRouteOutput = output;
        }
        IERC20(_path[0]).safeIncreaseAllowance(VELO_ROUTER, _amount);
        router.swapExactTokensForTokens(_amount, 0, routes, address(this), block.timestamp);
    }

    function _initFlashLoan(uint256 _amount) internal {
        require(_amount != 0, "FL: invalid amount!");

        // asset to be flashed
        address[] memory assets = new address[](1);
        assets[0] = address(want);

        // amount to be flashed
        uint256[] memory amounts = new uint256[](1);
        amounts[0] = _amount;

        // 0 = no debt, 1 = stable, 2 = variable
        uint256[] memory modes = new uint256[](1);
        modes[0] = INTEREST_RATE_MODE_VARIABLE;

        flashLoanStatus = DEPOSIT_FL_IN_PROGRESS;
        POOL().flashLoan(address(this), assets, amounts, modes, address(this), "", LENDER_REFERRAL_CODE_NONE);
    }

    function getSupplyAndBorrow() public view returns (uint256 supply, uint256 borrow) {
        (supply, , borrow, , , , , , ) = IAaveProtocolDataProvider(AAVE_DATA_PROVIDER).getUserReserveData(
            address(want),
            address(this)
        );
        return (supply, borrow);
    }

    // Path setters for swaps, needs at least STRATEGIST level access
    function setOpToUsdcPath(address[] calldata _path) external {
        _atLeastRole(STRATEGIST);
        require(_path[0] == OP && _path[_path.length - 1] == USDC, "Invalid opToUsdcPath");
        opToUsdcPath = _path;
    }

    function setOpToWantPath(address[] memory _path) public {
        _atLeastRole(STRATEGIST);
        require(_path[0] == OP && _path[_path.length - 1] == address(want), "Invalid opToWantPath");
        opToWantPath = _path;
    }

    /**
     * @dev Frees up {_amount} of want by manipulating supply/borrow.
     */
    function authorizedDelever(uint256 _amount) external {
        _atLeastRole(STRATEGIST);
        _deleverUsingAToken(_amount);
    }

    /**
     * @dev Attempts to safely withdraw {_amount} from the pool and optionally sends it
     *      to the vault.
     */
    function authorizedWithdrawUnderlying(uint256 _amount) external {
        _atLeastRole(STRATEGIST);
        _withdrawUnderlying(_amount);
    }

    /**
     * @dev Attempts to safely withdraw {_amount} from the pool and optionally sends it
     *      to the vault.
     */
    function authorizedSendToVault(uint256 _amount) external {
        _atLeastRole(STRATEGIST);
        want.safeTransfer(vault, _amount);
    }

    /**
     * @dev Function to calculate the total {want} held by the strat.
     * It takes into account both the funds in hand, plus the funds in the lendingPool.
     */
    function balanceOf() public view override returns (uint256) {
        (uint256 supply, uint256 borrow) = getSupplyAndBorrow();
        uint256 realSupply = supply - borrow;
        return realSupply + want.balanceOf(address(this));
    }

    /**
     * Withdraws all funds leaving rewards behind.
     */
    function _reclaimWant() internal override {
        (uint256 supply, uint256 borrow) = getSupplyAndBorrow();
        uint256 realSupply = supply - borrow;
        _deleverUsingAToken(realSupply);
        _withdrawUnderlying(realSupply);
    }

    /**
     * @dev Updates target LTV (safely).
     *      May be called by KEEPER.
     */
    function setLTVs(uint256 _newTargetLtv, uint256 _newMaxLtv) external {
        _atLeastRole(KEEPER);
        _safeUpdateTargetLtv(_newTargetLtv, _newMaxLtv);
    }

    /**
     * @dev Updates slippage tolerance (when withdrawing), and minimum
     *      amount to lever up with.
     *      Can only be called by strategist or owner.
     */
    function setLeverageParams(uint256 _newWithdrawSlippageTolerance, uint256 _newMinLeverageAmount) external {
        _atLeastRole(STRATEGIST);

        require(_newWithdrawSlippageTolerance <= MAX_WITHDRAW_SLIPPAGE_TOLERANCE, "invalid slippage!");
        withdrawSlippageTolerance = _newWithdrawSlippageTolerance;
        minLeverageAmount = _newMinLeverageAmount;
    }

    function _safeUpdateTargetLtv(uint256 _newTargetLtv, uint256 _newMaxLtv) internal {
        uint256 eMode = POOL().getUserEMode(address(this));
        uint256 ltv;
        if (eMode != 0) {
            DataTypes.EModeCategory memory eModeData = POOL().getEModeCategoryData(uint8(eMode));
            ltv = eModeData.ltv;
        } else {
            (, ltv, , , , , , , , ) = IAaveProtocolDataProvider(AAVE_DATA_PROVIDER).getReserveConfigurationData(
                address(want)
            );
        }
        require(_newMaxLtv <= (ltv * LTV_SAFETY_ZONE) / PERCENT_DIVISOR, "maxLtv not safe");
        require(_newTargetLtv <= _newMaxLtv, "targetLtv must <= maxLtv");
        maxLtv = _newMaxLtv;
        targetLtv = _newTargetLtv;
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./interfaces/IStrategy.sol";
import "./interfaces/IVault.sol";
import "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";

abstract contract ReaperBaseStrategyv3 is IStrategy, AccessControlEnumerable, Pausable {
    uint256 public constant PERCENT_DIVISOR = 10_000;
    uint256 public constant ONE_YEAR = 365 days;

    struct Harvest {
        uint256 timestamp;
        uint256 vaultSharePrice;
    }

    Harvest[] public harvestLog;
    uint256 public harvestLogCadence;
    uint256 public lastHarvestTimestamp;

    /**
     * Reaper Roles in increasing order of privilege.
     * {KEEPER} - Stricly permissioned trustless access for off-chain programs or third party keepers.
     * {STRATEGIST} - Role conferred to authors of the strategy, allows for tweaking non-critical params.
     * {GUARDIAN} - Multisig requiring 2 signatures for emergency measures such as pausing and panicking.
     * {ADMIN}- Multisig requiring 3 signatures for unpausing.
     *
     * The DEFAULT_ADMIN_ROLE (in-built access control role) will be granted to a multisig requiring 4
     * signatures. This role would have the ability to grant any other roles.
     *
     * Also note that roles are cascading. So any higher privileged role should be able to perform all the functions
     * of any lower privileged role.
     */
    bytes32 public constant KEEPER = keccak256("KEEPER");
    bytes32 public constant STRATEGIST = keccak256("STRATEGIST");
    bytes32 public constant GUARDIAN = keccak256("GUARDIAN");
    bytes32 public constant ADMIN = keccak256("ADMIN");
    bytes32[] private cascadingAccess;

    /**
     * @dev Reaper contracts:
     * {treasury} - Address of the Reaper treasury
     * {vault} - Address of the vault that controls the strategy's funds.
     * {strategistRemitter} - Address where strategist fee is remitted to.
     */
    address public treasury;
    address public vault;
    address public strategistRemitter;

    /**
     * Fee related constants:
     * {MAX_FEE} - Maximum fee allowed by the strategy. Hard-capped at 10%.
     * {STRATEGIST_MAX_FEE} - Maximum strategist fee allowed by the strategy (as % of treasury fee).
     *                        Hard-capped at 50%
     */
    uint256 public constant MAX_FEE = 1000;
    uint256 public constant STRATEGIST_MAX_FEE = 5000;

    /**
     * @dev Distribution of fees earned, expressed as % of the profit from each harvest.
     * {totalFee} - divided by 10,000 to determine the % fee. Set to 4.5% by default and
     * lowered as necessary to provide users with the most competitive APY.
     *
     * {callFee} - Percent of the totalFee reserved for the harvester (1000 = 10% of total fee: 0.45% by default)
     * {treasuryFee} - Percent of the totalFee taken by maintainers of the software (9000 = 90% of total fee: 4.05% by default)
     * {strategistFee} - Percent of the treasuryFee taken by strategist (2500 = 25% of treasury fee: 1.0125% by default)
     */
    uint256 public totalFee;
    uint256 public callFee;
    uint256 public treasuryFee;
    uint256 public strategistFee;

    /**
     * {TotalFeeUpdated} Event that is fired each time the total fee is updated.
     * {FeesUpdated} Event that is fired each time callFee+treasuryFee+strategistFee are updated.
     * {StratHarvest} Event that is fired each time the strategy gets harvested.
     * {StrategistRemitterUpdated} Event that is fired each time the strategistRemitter address is updated.
     */
    event TotalFeeUpdated(uint256 newFee);
    event FeesUpdated(uint256 newCallFee, uint256 newTreasuryFee, uint256 newStrategistFee);
    event StratHarvest(address indexed harvester);
    event StrategistRemitterUpdated(address newStrategistRemitter);

    constructor(
        address _vault,
        address[] memory _feeRemitters,
        address[] memory _strategists,
        address[] memory _multisigRoles
    ) {
        harvestLogCadence = 1 minutes;
        totalFee = 450;
        callFee = 1000;
        treasuryFee = 9000;
        strategistFee = 0;

        vault = _vault;
        treasury = _feeRemitters[0];
        strategistRemitter = _feeRemitters[1];

        for (uint256 i = 0; i < _strategists.length; i++) {
            _grantRole(STRATEGIST, _strategists[i]);
        }

        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _grantRole(DEFAULT_ADMIN_ROLE, _multisigRoles[0]);
        _grantRole(ADMIN, _multisigRoles[1]);
        _grantRole(GUARDIAN, _multisigRoles[2]);

        cascadingAccess = [DEFAULT_ADMIN_ROLE, ADMIN, GUARDIAN, STRATEGIST, KEEPER];
        harvestLog.push(Harvest({timestamp: block.timestamp, vaultSharePrice: IVault(_vault).getPricePerFullShare()}));
    }

    /**
     * @dev Function that puts the funds to work.
     *      It gets called whenever someone deposits in the strategy's vault contract.
     *      Deposits go through only when the strategy is not paused.
     */
    function deposit() public override whenNotPaused {
        _deposit();
    }

    /**
     * @dev Withdraws funds and sends them back to the vault. Can only
     *      be called by the vault. _amount must be valid and security fee
     *      is deducted up-front.
     */
    function withdraw(uint256 _amount) external override {
        require(msg.sender == vault);
        require(_amount != 0);
        require(_amount <= balanceOf());

        _withdraw(_amount);
    }

    /**
     * @dev harvest() function that takes care of logging. Subcontracts should
     *      override _harvestCore() and implement their specific logic in it.
     */
    function harvest() external override whenNotPaused returns (uint256 callerFee) {
        callerFee = _harvestCore();

        if (block.timestamp >= harvestLog[harvestLog.length - 1].timestamp + harvestLogCadence) {
            harvestLog.push(
                Harvest({timestamp: block.timestamp, vaultSharePrice: IVault(vault).getPricePerFullShare()})
            );
        }

        lastHarvestTimestamp = block.timestamp;
        emit StratHarvest(msg.sender);
    }

    function harvestLogLength() external view returns (uint256) {
        return harvestLog.length;
    }

    /**
     * @dev Traverses the harvest log backwards _n items,
     *      and returns the average APR calculated across all the included
     *      log entries. APR is multiplied by PERCENT_DIVISOR to retain precision.
     */
    function averageAPRAcrossLastNHarvests(int256 _n) external view returns (int256) {
        require(harvestLog.length >= 2);

        int256 runningAPRSum;
        int256 numLogsProcessed;

        for (uint256 i = harvestLog.length - 1; i > 0 && numLogsProcessed < _n; i--) {
            runningAPRSum += calculateAPRUsingLogs(i - 1, i);
            numLogsProcessed++;
        }

        return runningAPRSum / numLogsProcessed;
    }

    /**
     * @dev Strategists and roles with higher privilege can edit the log cadence.
     */
    function updateHarvestLogCadence(uint256 _newCadenceInSeconds) external {
        _atLeastRole(STRATEGIST);
        harvestLogCadence = _newCadenceInSeconds;
    }

    /**
     * @dev Function to calculate the total {want} held by the strat.
     *      It takes into account both the funds in hand, plus the funds in external contracts.
     */
    function balanceOf() public view virtual override returns (uint256);

    /**
     * @dev Pauses deposits. Withdraws all funds leaving rewards behind.
     *      Guardian and roles with higher privilege can panic.
     */
    function panic() external override {
        _atLeastRole(GUARDIAN);
        _reclaimWant();
        pause();
    }

    /**
     * @dev Pauses the strat. Deposits become disabled but users can still
     *      withdraw. Guardian and roles with higher privilege can pause.
     */
    function pause() public override {
        _atLeastRole(GUARDIAN);
        _pause();
    }

    /**
     * @dev Unpauses the strat. Opens up deposits again and invokes deposit().
     *      Admin and roles with higher privilege can unpause.
     */
    function unpause() external override {
        _atLeastRole(ADMIN);
        _unpause();
        deposit();
    }

    /**
     * @dev updates the total fee, capped at 5%; only DEFAULT_ADMIN_ROLE.
     */
    function updateTotalFee(uint256 _totalFee) external {
        _atLeastRole(DEFAULT_ADMIN_ROLE);
        require(_totalFee <= MAX_FEE);
        totalFee = _totalFee;
        emit TotalFeeUpdated(totalFee);
    }

    /**
     * @dev updates the call fee, treasury fee, and strategist fee
     *      call Fee + treasury Fee must add up to PERCENT_DIVISOR
     *
     *      strategist fee is expressed as % of the treasury fee and
     *      must be no more than STRATEGIST_MAX_FEE
     *
     *      only DEFAULT_ADMIN_ROLE.
     */
    function updateFees(
        uint256 _callFee,
        uint256 _treasuryFee,
        uint256 _strategistFee
    ) external returns (bool) {
        _atLeastRole(DEFAULT_ADMIN_ROLE);
        require(_callFee + _treasuryFee == PERCENT_DIVISOR);
        require(_strategistFee <= STRATEGIST_MAX_FEE);

        callFee = _callFee;
        treasuryFee = _treasuryFee;
        strategistFee = _strategistFee;
        emit FeesUpdated(callFee, treasuryFee, strategistFee);
        return true;
    }

    /**
     * @dev only DEFAULT_ADMIN_ROLE can update treasury address.
     */
    function updateTreasury(address newTreasury) external returns (bool) {
        _atLeastRole(DEFAULT_ADMIN_ROLE);
        treasury = newTreasury;
        return true;
    }

    /**
     * @dev Updates the current strategistRemitter. Only DEFAULT_ADMIN_ROLE may do this.
     */
    function updateStrategistRemitter(address _newStrategistRemitter) external {
        _atLeastRole(DEFAULT_ADMIN_ROLE);
        require(_newStrategistRemitter != address(0));
        strategistRemitter = _newStrategistRemitter;
        emit StrategistRemitterUpdated(_newStrategistRemitter);
    }

    /**
     * @dev Project an APR using the vault share price change between harvests at the provided indices.
     */
    function calculateAPRUsingLogs(uint256 _startIndex, uint256 _endIndex) public view returns (int256) {
        Harvest storage start = harvestLog[_startIndex];
        Harvest storage end = harvestLog[_endIndex];
        bool increasing = true;
        if (end.vaultSharePrice < start.vaultSharePrice) {
            increasing = false;
        }

        uint256 unsignedSharePriceChange;
        if (increasing) {
            unsignedSharePriceChange = end.vaultSharePrice - start.vaultSharePrice;
        } else {
            unsignedSharePriceChange = start.vaultSharePrice - end.vaultSharePrice;
        }

        uint256 unsignedPercentageChange = (unsignedSharePriceChange * 1e18) / start.vaultSharePrice;
        uint256 timeDifference = end.timestamp - start.timestamp;

        uint256 yearlyUnsignedPercentageChange = (unsignedPercentageChange * ONE_YEAR) / timeDifference;
        yearlyUnsignedPercentageChange /= 1e14; // restore basis points precision

        if (increasing) {
            return int256(yearlyUnsignedPercentageChange);
        }

        return -int256(yearlyUnsignedPercentageChange);
    }

    /**
     * @dev Internal function that checks cascading role privileges. Any higher privileged role
     * should be able to perform all the functions of any lower privileged role. This is
     * accomplished using the {cascadingAccess} array that lists all roles from most privileged
     * to least privileged.
     */
    function _atLeastRole(bytes32 role) internal view {
        uint256 numRoles = cascadingAccess.length;
        uint256 specifiedRoleIndex;
        for (uint256 i = 0; i < numRoles; i++) {
            if (role == cascadingAccess[i]) {
                specifiedRoleIndex = i;
                break;
            } else if (i == numRoles - 1) {
                revert("unauthorized access");
            }
        }

        for (uint256 i = 0; i <= specifiedRoleIndex; i++) {
            if (hasRole(cascadingAccess[i], msg.sender)) {
                break;
            } else if (i == specifiedRoleIndex) {
                revert("unauthorized access");
            }
        }
    }

    /**
     * @dev subclasses should add their custom deposit logic in this function.
     */
    function _deposit() internal virtual;

    /**
     * @dev subclasses should add their custom withdraw logic in this function.
     *      Note that security fee has already been deducted, so it shouldn't be deducted
     *      again within this function.
     */
    function _withdraw(uint256 _amount) internal virtual;

    /**
     * @dev subclasses should add their custom harvesting logic in this function
     *      including charging any fees. The amount of fee that is remitted to the
     *      caller must be returned.
     */
    function _harvestCore() internal virtual returns (uint256);

    /**
     * @dev subclasses should add their custom logic to withdraw the principal from
     *      any external contracts in this function. Note that we don't care about rewards,
     *      we just want to reclaim our principal as much as possible, and as quickly as possible.
     *      So keep this function lean. Principal should be left in the strategy and not sent to
     *      the vault.
     */
    function _reclaimWant() internal virtual;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IStrategy {
    //deposits all funds into the farm
    function deposit() external;

    //vault only - withdraws funds from the strategy
    function withdraw(uint256 _amount) external;

    //claims rewards, charges fees, and re-deposits; returns caller fee amount.
    function harvest() external returns (uint256);

    //returns the balance of all tokens managed by the strategy
    function balanceOf() external view returns (uint256);

    //pauses deposits, resets allowances, and withdraws all funds from farm
    function panic() external;

    //pauses deposits and resets allowances
    function pause() external;

    //unpauses deposits and maxes out allowances again
    function unpause() external;
}

// SPDX-License-Identifier: agpl-3.0

pragma solidity ^0.8.0;

interface IVault {
    function getPricePerFullShare() external view returns (uint256);
}

// SPDX-License-Identifier: agpl-3.0

pragma solidity ^0.8.0;

interface IAaveProtocolDataProvider {
    struct TokenData {
        string symbol;
        address tokenAddress;
    }

    function ADDRESSES_PROVIDER() external view returns (address);

    function getATokenTotalSupply(address asset)
        external
        view
        returns (uint256);

    function getAllATokens() external view returns (TokenData[] memory);

    function getAllReservesTokens() external view returns (TokenData[] memory);

    function getDebtCeiling(address asset) external view returns (uint256);

    function getDebtCeilingDecimals() external pure returns (uint256);

    function getInterestRateStrategyAddress(address asset)
        external
        view
        returns (address irStrategyAddress);

    function getLiquidationProtocolFee(address asset)
        external
        view
        returns (uint256);

    function getPaused(address asset) external view returns (bool isPaused);

    function getReserveCaps(address asset)
        external
        view
        returns (uint256 borrowCap, uint256 supplyCap);

    function getReserveConfigurationData(address asset)
        external
        view
        returns (
            uint256 decimals,
            uint256 ltv,
            uint256 liquidationThreshold,
            uint256 liquidationBonus,
            uint256 reserveFactor,
            bool usageAsCollateralEnabled,
            bool borrowingEnabled,
            bool stableBorrowRateEnabled,
            bool isActive,
            bool isFrozen
        );

    function getReserveData(address asset)
        external
        view
        returns (
            uint256 unbacked,
            uint256 accruedToTreasuryScaled,
            uint256 totalAToken,
            uint256 totalStableDebt,
            uint256 totalVariableDebt,
            uint256 liquidityRate,
            uint256 variableBorrowRate,
            uint256 stableBorrowRate,
            uint256 averageStableBorrowRate,
            uint256 liquidityIndex,
            uint256 variableBorrowIndex,
            uint40 lastUpdateTimestamp
        );

    function getReserveEModeCategory(address asset)
        external
        view
        returns (uint256);

    function getReserveTokensAddresses(address asset)
        external
        view
        returns (
            address aTokenAddress,
            address stableDebtTokenAddress,
            address variableDebtTokenAddress
        );

    function getUnbackedMintCap(address asset) external view returns (uint256);

    function getUserReserveData(address asset, address user)
        external
        view
        returns (
            uint256 currentATokenBalance,
            uint256 currentStableDebt,
            uint256 currentVariableDebt,
            uint256 principalStableDebt,
            uint256 scaledVariableDebt,
            uint256 stableBorrowRate,
            uint256 liquidityRate,
            uint40 stableRateLastUpdated,
            bool usageAsCollateralEnabled
        );
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.0;

import {IScaledBalanceToken} from "./IScaledBalanceToken.sol";
import {IInitializableAToken} from "./IInitializableAToken.sol";

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title IAToken
 * @author Aave
 * @notice Defines the basic interface for an AToken.
 **/
interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken {
    /**
     * @dev Emitted during the transfer action
     * @param from The user whose tokens are being transferred
     * @param to The recipient
     * @param value The amount being transferred
     * @param index The next liquidity index of the reserve
     **/
    event BalanceTransfer(
        address indexed from,
        address indexed to,
        uint256 value,
        uint256 index
    );

    /**
     * @notice Mints `amount` aTokens to `user`
     * @param caller The address performing the mint
     * @param onBehalfOf The address of the user that will receive the minted aTokens
     * @param amount The amount of tokens getting minted
     * @param index The next liquidity index of the reserve
     * @return `true` if the the previous balance of the user was 0
     */
    function mint(
        address caller,
        address onBehalfOf,
        uint256 amount,
        uint256 index
    ) external returns (bool);

    /**
     * @notice Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
     * @dev In some instances, the mint event could be emitted from a burn transaction
     * if the amount to burn is less than the interest that the user accrued
     * @param from The address from which the aTokens will be burned
     * @param receiverOfUnderlying The address that will receive the underlying
     * @param amount The amount being burned
     * @param index The next liquidity index of the reserve
     **/
    function burn(
        address from,
        address receiverOfUnderlying,
        uint256 amount,
        uint256 index
    ) external;

    /**
     * @notice Mints aTokens to the reserve treasury
     * @param amount The amount of tokens getting minted
     * @param index The next liquidity index of the reserve
     */
    function mintToTreasury(uint256 amount, uint256 index) external;

    /**
     * @notice Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
     * @param from The address getting liquidated, current owner of the aTokens
     * @param to The recipient
     * @param value The amount of tokens getting transferred
     **/
    function transferOnLiquidation(
        address from,
        address to,
        uint256 value
    ) external;

    /**
     * @notice Transfers the underlying asset to `target`.
     * @dev Used by the Pool to transfer assets in borrow(), withdraw() and flashLoan()
     * @param user The recipient of the underlying
     * @param amount The amount getting transferred
     **/
    function transferUnderlyingTo(address user, uint256 amount) external;

    /**
     * @notice Handles the underlying received by the aToken after the transfer has been completed.
     * @dev The default implementation is empty as with standard ERC20 tokens, nothing needs to be done after the
     * transfer is concluded. However in the future there may be aTokens that allow for example to stake the underlying
     * to receive LM rewards. In that case, `handleRepayment()` would perform the staking of the underlying asset.
     * @param user The user executing the repayment
     * @param amount The amount getting repaid
     **/
    function handleRepayment(address user, uint256 amount) external;

    /**
     * @notice Allow passing a signed message to approve spending
     * @dev implements the permit function as for
     * https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
     * @param owner The owner of the funds
     * @param spender The spender
     * @param value The amount
     * @param deadline The deadline timestamp, type(uint256).max for max deadline
     * @param v Signature param
     * @param s Signature param
     * @param r Signature param
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @notice Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
     * @return The address of the underlying asset
     **/
    function UNDERLYING_ASSET_ADDRESS() external view returns (address);

    /**
     * @notice Returns the address of the Aave treasury, receiving the fees on this aToken.
     * @return Address of the Aave treasury
     **/
    function RESERVE_TREASURY_ADDRESS() external view returns (address);

    /**
     * @notice Get the domain separator for the token
     * @dev Return cached value if chainId matches cache, otherwise recomputes separator
     * @return The domain separator of the token at current chain
     */
    function DOMAIN_SEPARATOR() external view returns (bytes32);

    /**
     * @notice Returns the nonce for owner.
     * @param owner The address of the owner
     * @return The nonce of the owner
     **/
    function nonces(address owner) external view returns (uint256);

    /**
     * @notice Rescue and transfer tokens locked in this contract
     * @param token The address of the token
     * @param to The address of the recipient
     * @param amount The amount of token to transfer
     */
    function rescueTokens(
        address token,
        address to,
        uint256 amount
    ) external;
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.0;

/**
 * @title IScaledBalanceToken
 * @author Aave
 * @notice Defines the basic interface for a scaledbalance token.
 **/
interface IScaledBalanceToken {
    /**
     * @dev Emitted after the mint action
     * @param caller The address performing the mint
     * @param onBehalfOf The address of the user that will receive the minted scaled balance tokens
     * @param value The amount being minted (user entered amount + balance increase from interest)
     * @param balanceIncrease The increase in balance since the last action of the user
     * @param index The next liquidity index of the reserve
     **/
    event Mint(
        address indexed caller,
        address indexed onBehalfOf,
        uint256 value,
        uint256 balanceIncrease,
        uint256 index
    );

    /**
     * @dev Emitted after scaled balance tokens are burned
     * @param from The address from which the scaled tokens will be burned
     * @param target The address that will receive the underlying, if any
     * @param value The amount being burned (user entered amount - balance increase from interest)
     * @param balanceIncrease The increase in balance since the last action of the user
     * @param index The next liquidity index of the reserve
     **/
    event Burn(
        address indexed from,
        address indexed target,
        uint256 value,
        uint256 balanceIncrease,
        uint256 index
    );

    /**
     * @notice Returns the scaled balance of the user.
     * @dev The scaled balance is the sum of all the updated stored balance divided by the reserve's liquidity index
     * at the moment of the update
     * @param user The user whose balance is calculated
     * @return The scaled balance of the user
     **/
    function scaledBalanceOf(address user) external view returns (uint256);

    /**
     * @notice Returns the scaled balance of the user and the scaled total supply.
     * @param user The address of the user
     * @return The scaled balance of the user
     * @return The scaled total supply
     **/
    function getScaledUserBalanceAndSupply(address user)
        external
        view
        returns (uint256, uint256);

    /**
     * @notice Returns the scaled total supply of the scaled balance token. Represents sum(debt/index)
     * @return The scaled total supply
     **/
    function scaledTotalSupply() external view returns (uint256);

    /**
     * @notice Returns last index interest was accrued to the user's balance
     * @param user The address of the user
     * @return The last index interest was accrued to the user's balance, expressed in ray
     **/
    function getPreviousIndex(address user) external view returns (uint256);
}

File 8 of 33 : IInitializableAToken.sol
// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.0;

import {IAaveIncentivesController} from "./IAaveIncentivesController.sol";
import {IPool} from "./IPool.sol";

/**
 * @title IInitializableAToken
 * @author Aave
 * @notice Interface for the initialize function on AToken
 **/
interface IInitializableAToken {
    /**
     * @dev Emitted when an aToken is initialized
     * @param underlyingAsset The address of the underlying asset
     * @param pool The address of the associated pool
     * @param treasury The address of the treasury
     * @param incentivesController The address of the incentives controller for this aToken
     * @param aTokenDecimals The decimals of the underlying
     * @param aTokenName The name of the aToken
     * @param aTokenSymbol The symbol of the aToken
     * @param params A set of encoded parameters for additional initialization
     **/
    event Initialized(
        address indexed underlyingAsset,
        address indexed pool,
        address treasury,
        address incentivesController,
        uint8 aTokenDecimals,
        string aTokenName,
        string aTokenSymbol,
        bytes params
    );

    /**
     * @notice Initializes the aToken
     * @param pool The pool contract that is initializing this contract
     * @param treasury The address of the Aave treasury, receiving the fees on this aToken
     * @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
     * @param incentivesController The smart contract managing potential incentives distribution
     * @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
     * @param aTokenName The name of the aToken
     * @param aTokenSymbol The symbol of the aToken
     * @param params A set of encoded parameters for additional initialization
     */
    function initialize(
        IPool pool,
        address treasury,
        address underlyingAsset,
        IAaveIncentivesController incentivesController,
        uint8 aTokenDecimals,
        string calldata aTokenName,
        string calldata aTokenSymbol,
        bytes calldata params
    ) external;
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.0;

/**
 * @title IAaveIncentivesController
 * @author Aave
 * @notice Defines the basic interface for an Aave Incentives Controller.
 **/
interface IAaveIncentivesController {
    /**
     * @dev Emitted during `handleAction`, `claimRewards` and `claimRewardsOnBehalf`
     * @param user The user that accrued rewards
     * @param amount The amount of accrued rewards
     */
    event RewardsAccrued(address indexed user, uint256 amount);

    event RewardsClaimed(
        address indexed user,
        address indexed to,
        uint256 amount
    );

    /**
     * @dev Emitted during `claimRewards` and `claimRewardsOnBehalf`
     * @param user The address that accrued rewards
     * @param to The address that will be receiving the rewards
     * @param claimer The address that performed the claim
     * @param amount The amount of rewards
     */
    event RewardsClaimed(
        address indexed user,
        address indexed to,
        address indexed claimer,
        uint256 amount
    );

    /**
     * @dev Emitted during `setClaimer`
     * @param user The address of the user
     * @param claimer The address of the claimer
     */
    event ClaimerSet(address indexed user, address indexed claimer);

    /**
     * @notice Returns the configuration of the distribution for a certain asset
     * @param asset The address of the reference asset of the distribution
     * @return The asset index
     * @return The emission per second
     * @return The last updated timestamp
     **/
    function getAssetData(address asset)
        external
        view
        returns (
            uint256,
            uint256,
            uint256
        );

    /**
     * LEGACY **************************
     * @dev Returns the configuration of the distribution for a certain asset
     * @param asset The address of the reference asset of the distribution
     * @return The asset index, the emission per second and the last updated timestamp
     **/
    function assets(address asset)
        external
        view
        returns (
            uint128,
            uint128,
            uint256
        );

    /**
     * @notice Whitelists an address to claim the rewards on behalf of another address
     * @param user The address of the user
     * @param claimer The address of the claimer
     */
    function setClaimer(address user, address claimer) external;

    /**
     * @notice Returns the whitelisted claimer for a certain address (0x0 if not set)
     * @param user The address of the user
     * @return The claimer address
     */
    function getClaimer(address user) external view returns (address);

    /**
     * @notice Configure assets for a certain rewards emission
     * @param assets The assets to incentivize
     * @param emissionsPerSecond The emission for each asset
     */
    function configureAssets(
        address[] calldata assets,
        uint256[] calldata emissionsPerSecond
    ) external;

    /**
     * @notice Called by the corresponding asset on any update that affects the rewards distribution
     * @param asset The address of the user
     * @param userBalance The balance of the user of the asset in the pool
     * @param totalSupply The total supply of the asset in the pool
     **/
    function handleAction(
        address asset,
        uint256 userBalance,
        uint256 totalSupply
    ) external;

    /**
     * @notice Returns the total of rewards of a user, already accrued + not yet accrued
     * @param assets The assets to accumulate rewards for
     * @param user The address of the user
     * @return The rewards
     **/
    function getRewardsBalance(address[] calldata assets, address user)
        external
        view
        returns (uint256);

    /**
     * @notice Claims reward for a user, on the assets of the pool, accumulating the pending rewards
     * @param assets The assets to accumulate rewards for
     * @param amount Amount of rewards to claim
     * @param to Address that will be receiving the rewards
     * @return Rewards claimed
     **/
    function claimRewards(
        address[] calldata assets,
        uint256 amount,
        address to
    ) external returns (uint256);

    /**
     * @notice Claims reward for a user on its behalf, on the assets of the pool, accumulating the pending rewards.
     * @dev The caller must be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
     * @param assets The assets to accumulate rewards for
     * @param amount The amount of rewards to claim
     * @param user The address to check and claim rewards
     * @param to The address that will be receiving the rewards
     * @return The amount of rewards claimed
     **/
    function claimRewardsOnBehalf(
        address[] calldata assets,
        uint256 amount,
        address user,
        address to
    ) external returns (uint256);

    /**
     * @notice Returns the unclaimed rewards of the user
     * @param user The address of the user
     * @return The unclaimed user rewards
     */
    function getUserUnclaimedRewards(address user)
        external
        view
        returns (uint256);

    /**
     * @notice Returns the user index for a specific asset
     * @param user The address of the user
     * @param asset The asset to incentivize
     * @return The user index for the asset
     */
    function getUserAssetData(address user, address asset)
        external
        view
        returns (uint256);

    /**
     * @notice for backward compatibility with previous implementation of the Incentives controller
     * @return The address of the reward token
     */
    function REWARD_TOKEN() external view returns (address);

    /**
     * @notice for backward compatibility with previous implementation of the Incentives controller
     * @return The precision used in the incentives controller
     */
    function PRECISION() external view returns (uint8);

    /**
     * @dev Gets the distribution end timestamp of the emissions
     */
    function DISTRIBUTION_END() external view returns (uint256);
}

File 10 of 33 : IPool.sol
// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.0;

import {IPoolAddressesProvider} from "./IPoolAddressesProvider.sol";
import {DataTypes} from "../libraries/DataTypes.sol";

/**
 * @title IPool
 * @author Aave
 * @notice Defines the basic interface for an Aave Pool.
 **/
interface IPool {
    /**
     * @dev Emitted on mintUnbacked()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The address initiating the supply
     * @param onBehalfOf The beneficiary of the supplied assets, receiving the aTokens
     * @param amount The amount of supplied assets
     * @param referralCode The referral code used
     **/
    event MintUnbacked(
        address indexed reserve,
        address user,
        address indexed onBehalfOf,
        uint256 amount,
        uint16 indexed referralCode
    );

    /**
     * @dev Emitted on backUnbacked()
     * @param reserve The address of the underlying asset of the reserve
     * @param backer The address paying for the backing
     * @param amount The amount added as backing
     * @param fee The amount paid in fees
     **/
    event BackUnbacked(
        address indexed reserve,
        address indexed backer,
        uint256 amount,
        uint256 fee
    );

    /**
     * @dev Emitted on supply()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The address initiating the supply
     * @param onBehalfOf The beneficiary of the supply, receiving the aTokens
     * @param amount The amount supplied
     * @param referralCode The referral code used
     **/
    event Supply(
        address indexed reserve,
        address user,
        address indexed onBehalfOf,
        uint256 amount,
        uint16 indexed referralCode
    );

    /**
     * @dev Emitted on withdraw()
     * @param reserve The address of the underlying asset being withdrawn
     * @param user The address initiating the withdrawal, owner of aTokens
     * @param to The address that will receive the underlying
     * @param amount The amount to be withdrawn
     **/
    event Withdraw(
        address indexed reserve,
        address indexed user,
        address indexed to,
        uint256 amount
    );

    /**
     * @dev Emitted on borrow() and flashLoan() when debt needs to be opened
     * @param reserve The address of the underlying asset being borrowed
     * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
     * initiator of the transaction on flashLoan()
     * @param onBehalfOf The address that will be getting the debt
     * @param amount The amount borrowed out
     * @param interestRateMode The rate mode: 1 for Stable, 2 for Variable
     * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray
     * @param referralCode The referral code used
     **/
    event Borrow(
        address indexed reserve,
        address user,
        address indexed onBehalfOf,
        uint256 amount,
        DataTypes.InterestRateMode interestRateMode,
        uint256 borrowRate,
        uint16 indexed referralCode
    );

    /**
     * @dev Emitted on repay()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The beneficiary of the repayment, getting his debt reduced
     * @param repayer The address of the user initiating the repay(), providing the funds
     * @param amount The amount repaid
     * @param useATokens True if the repayment is done using aTokens, `false` if done with underlying asset directly
     **/
    event Repay(
        address indexed reserve,
        address indexed user,
        address indexed repayer,
        uint256 amount,
        bool useATokens
    );

    /**
     * @dev Emitted on swapBorrowRateMode()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The address of the user swapping his rate mode
     * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable
     **/
    event SwapBorrowRateMode(
        address indexed reserve,
        address indexed user,
        DataTypes.InterestRateMode interestRateMode
    );

    /**
     * @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets
     * @param asset The address of the underlying asset of the reserve
     * @param totalDebt The total isolation mode debt for the reserve
     */
    event IsolationModeTotalDebtUpdated(
        address indexed asset,
        uint256 totalDebt
    );

    /**
     * @dev Emitted when the user selects a certain asset category for eMode
     * @param user The address of the user
     * @param categoryId The category id
     **/
    event UserEModeSet(address indexed user, uint8 categoryId);

    /**
     * @dev Emitted on setUserUseReserveAsCollateral()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The address of the user enabling the usage as collateral
     **/
    event ReserveUsedAsCollateralEnabled(
        address indexed reserve,
        address indexed user
    );

    /**
     * @dev Emitted on setUserUseReserveAsCollateral()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The address of the user enabling the usage as collateral
     **/
    event ReserveUsedAsCollateralDisabled(
        address indexed reserve,
        address indexed user
    );

    /**
     * @dev Emitted on rebalanceStableBorrowRate()
     * @param reserve The address of the underlying asset of the reserve
     * @param user The address of the user for which the rebalance has been executed
     **/
    event RebalanceStableBorrowRate(
        address indexed reserve,
        address indexed user
    );

    /**
     * @dev Emitted on flashLoan()
     * @param target The address of the flash loan receiver contract
     * @param initiator The address initiating the flash loan
     * @param asset The address of the asset being flash borrowed
     * @param amount The amount flash borrowed
     * @param interestRateMode The flashloan mode: 0 for regular flashloan, 1 for Stable debt, 2 for Variable debt
     * @param premium The fee flash borrowed
     * @param referralCode The referral code used
     **/
    event FlashLoan(
        address indexed target,
        address initiator,
        address indexed asset,
        uint256 amount,
        DataTypes.InterestRateMode interestRateMode,
        uint256 premium,
        uint16 indexed referralCode
    );

    /**
     * @dev Emitted when a borrower is liquidated.
     * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
     * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
     * @param user The address of the borrower getting liquidated
     * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
     * @param liquidatedCollateralAmount The amount of collateral received by the liquidator
     * @param liquidator The address of the liquidator
     * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants
     * to receive the underlying collateral asset directly
     **/
    event LiquidationCall(
        address indexed collateralAsset,
        address indexed debtAsset,
        address indexed user,
        uint256 debtToCover,
        uint256 liquidatedCollateralAmount,
        address liquidator,
        bool receiveAToken
    );

    /**
     * @dev Emitted when the state of a reserve is updated.
     * @param reserve The address of the underlying asset of the reserve
     * @param liquidityRate The next liquidity rate
     * @param stableBorrowRate The next stable borrow rate
     * @param variableBorrowRate The next variable borrow rate
     * @param liquidityIndex The next liquidity index
     * @param variableBorrowIndex The next variable borrow index
     **/
    event ReserveDataUpdated(
        address indexed reserve,
        uint256 liquidityRate,
        uint256 stableBorrowRate,
        uint256 variableBorrowRate,
        uint256 liquidityIndex,
        uint256 variableBorrowIndex
    );

    /**
     * @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest.
     * @param reserve The address of the reserve
     * @param amountMinted The amount minted to the treasury
     **/
    event MintedToTreasury(address indexed reserve, uint256 amountMinted);

    /**
     * @dev Mints an `amount` of aTokens to the `onBehalfOf`
     * @param asset The address of the underlying asset to mint
     * @param amount The amount to mint
     * @param onBehalfOf The address that will receive the aTokens
     * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
     *   0 if the action is executed directly by the user, without any middle-man
     **/
    function mintUnbacked(
        address asset,
        uint256 amount,
        address onBehalfOf,
        uint16 referralCode
    ) external;

    /**
     * @dev Back the current unbacked underlying with `amount` and pay `fee`.
     * @param asset The address of the underlying asset to back
     * @param amount The amount to back
     * @param fee The amount paid in fees
     **/
    function backUnbacked(
        address asset,
        uint256 amount,
        uint256 fee
    ) external;

    /**
     * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
     * - E.g. User supplies 100 USDC and gets in return 100 aUSDC
     * @param asset The address of the underlying asset to supply
     * @param amount The amount to be supplied
     * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
     *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
     *   is a different wallet
     * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
     *   0 if the action is executed directly by the user, without any middle-man
     **/
    function supply(
        address asset,
        uint256 amount,
        address onBehalfOf,
        uint16 referralCode
    ) external;

    /**
     * @notice Supply with transfer approval of asset to be supplied done via permit function
     * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713
     * @param asset The address of the underlying asset to supply
     * @param amount The amount to be supplied
     * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
     *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
     *   is a different wallet
     * @param deadline The deadline timestamp that the permit is valid
     * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
     *   0 if the action is executed directly by the user, without any middle-man
     * @param permitV The V parameter of ERC712 permit sig
     * @param permitR The R parameter of ERC712 permit sig
     * @param permitS The S parameter of ERC712 permit sig
     **/
    function supplyWithPermit(
        address asset,
        uint256 amount,
        address onBehalfOf,
        uint16 referralCode,
        uint256 deadline,
        uint8 permitV,
        bytes32 permitR,
        bytes32 permitS
    ) external;

    /**
     * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
     * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
     * @param asset The address of the underlying asset to withdraw
     * @param amount The underlying amount to be withdrawn
     *   - Send the value type(uint256).max in order to withdraw the whole aToken balance
     * @param to The address that will receive the underlying, same as msg.sender if the user
     *   wants to receive it on his own wallet, or a different address if the beneficiary is a
     *   different wallet
     * @return The final amount withdrawn
     **/
    function withdraw(
        address asset,
        uint256 amount,
        address to
    ) external returns (uint256);

    /**
     * @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
     * already supplied enough collateral, or he was given enough allowance by a credit delegator on the
     * corresponding debt token (StableDebtToken or VariableDebtToken)
     * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
     *   and 100 stable/variable debt tokens, depending on the `interestRateMode`
     * @param asset The address of the underlying asset to borrow
     * @param amount The amount to be borrowed
     * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
     * @param referralCode The code used to register the integrator originating the operation, for potential rewards.
     *   0 if the action is executed directly by the user, without any middle-man
     * @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself
     * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
     * if he has been given credit delegation allowance
     **/
    function borrow(
        address asset,
        uint256 amount,
        uint256 interestRateMode,
        uint16 referralCode,
        address onBehalfOf
    ) external;

    /**
     * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
     * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address
     * @param asset The address of the borrowed underlying asset previously borrowed
     * @param amount The amount to repay
     * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
     * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
     * @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the
     * user calling the function if he wants to reduce/remove his own debt, or the address of any other
     * other borrower whose debt should be removed
     * @return The final amount repaid
     **/
    function repay(
        address asset,
        uint256 amount,
        uint256 interestRateMode,
        address onBehalfOf
    ) external returns (uint256);

    /**
     * @notice Repay with transfer approval of asset to be repaid done via permit function
     * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713
     * @param asset The address of the borrowed underlying asset previously borrowed
     * @param amount The amount to repay
     * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
     * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
     * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the
     * user calling the function if he wants to reduce/remove his own debt, or the address of any other
     * other borrower whose debt should be removed
     * @param deadline The deadline timestamp that the permit is valid
     * @param permitV The V parameter of ERC712 permit sig
     * @param permitR The R parameter of ERC712 permit sig
     * @param permitS The S parameter of ERC712 permit sig
     * @return The final amount repaid
     **/
    function repayWithPermit(
        address asset,
        uint256 amount,
        uint256 interestRateMode,
        address onBehalfOf,
        uint256 deadline,
        uint8 permitV,
        bytes32 permitR,
        bytes32 permitS
    ) external returns (uint256);

    /**
     * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the
     * equivalent debt tokens
     * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable/stable debt tokens
     * @dev  Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken
     * balance is not enough to cover the whole debt
     * @param asset The address of the borrowed underlying asset previously borrowed
     * @param amount The amount to repay
     * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
     * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
     * @return The final amount repaid
     **/
    function repayWithATokens(
        address asset,
        uint256 amount,
        uint256 interestRateMode
    ) external returns (uint256);

    /**
     * @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa
     * @param asset The address of the underlying asset borrowed
     * @param interestRateMode The rate mode that the user wants to swap to: 1 for Stable, 2 for Variable
     **/
    function swapBorrowRateMode(address asset, uint256 interestRateMode)
        external;

    /**
     * @notice Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.
     * - Users can be rebalanced if the following conditions are satisfied:
     *     1. Usage ratio is above 95%
     *     2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too
     *        much has been borrowed at a stable rate and suppliers are not earning enough
     * @param asset The address of the underlying asset borrowed
     * @param user The address of the user to be rebalanced
     **/
    function rebalanceStableBorrowRate(address asset, address user) external;

    /**
     * @notice Allows suppliers to enable/disable a specific supplied asset as collateral
     * @param asset The address of the underlying asset supplied
     * @param useAsCollateral True if the user wants to use the supply as collateral, false otherwise
     **/
    function setUserUseReserveAsCollateral(address asset, bool useAsCollateral)
        external;

    /**
     * @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
     * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
     *   a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
     * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
     * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
     * @param user The address of the borrower getting liquidated
     * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
     * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants
     * to receive the underlying collateral asset directly
     **/
    function liquidationCall(
        address collateralAsset,
        address debtAsset,
        address user,
        uint256 debtToCover,
        bool receiveAToken
    ) external;

    /**
     * @notice Allows smartcontracts to access the liquidity of the pool within one transaction,
     * as long as the amount taken plus a fee is returned.
     * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
     * into consideration. For further details please visit https://developers.aave.com
     * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanReceiver interface
     * @param assets The addresses of the assets being flash-borrowed
     * @param amounts The amounts of the assets being flash-borrowed
     * @param interestRateModes Types of the debt to open if the flash loan is not returned:
     *   0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
     *   1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
     *   2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
     * @param onBehalfOf The address  that will receive the debt in the case of using on `modes` 1 or 2
     * @param params Variadic packed params to pass to the receiver as extra information
     * @param referralCode The code used to register the integrator originating the operation, for potential rewards.
     *   0 if the action is executed directly by the user, without any middle-man
     **/
    function flashLoan(
        address receiverAddress,
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata interestRateModes,
        address onBehalfOf,
        bytes calldata params,
        uint16 referralCode
    ) external;

    /**
     * @notice Allows smartcontracts to access the liquidity of the pool within one transaction,
     * as long as the amount taken plus a fee is returned.
     * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
     * into consideration. For further details please visit https://developers.aave.com
     * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface
     * @param asset The address of the asset being flash-borrowed
     * @param amount The amount of the asset being flash-borrowed
     * @param params Variadic packed params to pass to the receiver as extra information
     * @param referralCode The code used to register the integrator originating the operation, for potential rewards.
     *   0 if the action is executed directly by the user, without any middle-man
     **/
    function flashLoanSimple(
        address receiverAddress,
        address asset,
        uint256 amount,
        bytes calldata params,
        uint16 referralCode
    ) external;

    /**
     * @notice Returns the user account data across all the reserves
     * @param user The address of the user
     * @return totalCollateralBase The total collateral of the user in the base currency used by the price feed
     * @return totalDebtBase The total debt of the user in the base currency used by the price feed
     * @return availableBorrowsBase The borrowing power left of the user in the base currency used by the price feed
     * @return currentLiquidationThreshold The liquidation threshold of the user
     * @return ltv The loan to value of The user
     * @return healthFactor The current health factor of the user
     **/
    function getUserAccountData(address user)
        external
        view
        returns (
            uint256 totalCollateralBase,
            uint256 totalDebtBase,
            uint256 availableBorrowsBase,
            uint256 currentLiquidationThreshold,
            uint256 ltv,
            uint256 healthFactor
        );

    /**
     * @notice Initializes a reserve, activating it, assigning an aToken and debt tokens and an
     * interest rate strategy
     * @dev Only callable by the PoolConfigurator contract
     * @param asset The address of the underlying asset of the reserve
     * @param aTokenAddress The address of the aToken that will be assigned to the reserve
     * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve
     * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve
     * @param interestRateStrategyAddress The address of the interest rate strategy contract
     **/
    function initReserve(
        address asset,
        address aTokenAddress,
        address stableDebtAddress,
        address variableDebtAddress,
        address interestRateStrategyAddress
    ) external;

    /**
     * @notice Drop a reserve
     * @dev Only callable by the PoolConfigurator contract
     * @param asset The address of the underlying asset of the reserve
     **/
    function dropReserve(address asset) external;

    /**
     * @notice Updates the address of the interest rate strategy contract
     * @dev Only callable by the PoolConfigurator contract
     * @param asset The address of the underlying asset of the reserve
     * @param rateStrategyAddress The address of the interest rate strategy contract
     **/
    function setReserveInterestRateStrategyAddress(
        address asset,
        address rateStrategyAddress
    ) external;

    /**
     * @notice Sets the configuration bitmap of the reserve as a whole
     * @dev Only callable by the PoolConfigurator contract
     * @param asset The address of the underlying asset of the reserve
     * @param configuration The new configuration bitmap
     **/
    function setConfiguration(
        address asset,
        DataTypes.ReserveConfigurationMap calldata configuration
    ) external;

    /**
     * @notice Returns the configuration of the reserve
     * @param asset The address of the underlying asset of the reserve
     * @return The configuration of the reserve
     **/
    function getConfiguration(address asset)
        external
        view
        returns (DataTypes.ReserveConfigurationMap memory);

    /**
     * @notice Returns the configuration of the user across all the reserves
     * @param user The user address
     * @return The configuration of the user
     **/
    function getUserConfiguration(address user)
        external
        view
        returns (DataTypes.UserConfigurationMap memory);

    /**
     * @notice Returns the normalized income normalized income of the reserve
     * @param asset The address of the underlying asset of the reserve
     * @return The reserve's normalized income
     */
    function getReserveNormalizedIncome(address asset)
        external
        view
        returns (uint256);

    /**
     * @notice Returns the normalized variable debt per unit of asset
     * @param asset The address of the underlying asset of the reserve
     * @return The reserve normalized variable debt
     */
    function getReserveNormalizedVariableDebt(address asset)
        external
        view
        returns (uint256);

    /**
     * @notice Returns the state and configuration of the reserve
     * @param asset The address of the underlying asset of the reserve
     * @return The state and configuration data of the reserve
     **/
    function getReserveData(address asset)
        external
        view
        returns (DataTypes.ReserveData memory);

    /**
     * @notice Validates and finalizes an aToken transfer
     * @dev Only callable by the overlying aToken of the `asset`
     * @param asset The address of the underlying asset of the aToken
     * @param from The user from which the aTokens are transferred
     * @param to The user receiving the aTokens
     * @param amount The amount being transferred/withdrawn
     * @param balanceFromBefore The aToken balance of the `from` user before the transfer
     * @param balanceToBefore The aToken balance of the `to` user before the transfer
     */
    function finalizeTransfer(
        address asset,
        address from,
        address to,
        uint256 amount,
        uint256 balanceFromBefore,
        uint256 balanceToBefore
    ) external;

    /**
     * @notice Returns the list of the initialized reserves
     * @dev It does not include dropped reserves
     * @return The addresses of the reserves
     **/
    function getReservesList() external view returns (address[] memory);

    /**
     * @notice Returns the PoolAddressesProvider connected to this contract
     * @return The address of the PoolAddressesProvider
     **/
    function ADDRESSES_PROVIDER()
        external
        view
        returns (IPoolAddressesProvider);

    /**
     * @notice Updates the protocol fee on the bridging
     * @param bridgeProtocolFee The part of the premium sent to the protocol treasury
     */
    function updateBridgeProtocolFee(uint256 bridgeProtocolFee) external;

    /**
     * @notice Updates flash loan premiums. Flash loan premium consists of two parts:
     * - A part is sent to aToken holders as extra, one time accumulated interest
     * - A part is collected by the protocol treasury
     * @dev The total premium is calculated on the total borrowed amount
     * @dev The premium to protocol is calculated on the total premium, being a percentage of `flashLoanPremiumTotal`
     * @dev Only callable by the PoolConfigurator contract
     * @param flashLoanPremiumTotal The total premium, expressed in bps
     * @param flashLoanPremiumToProtocol The part of the premium sent to the protocol treasury, expressed in bps
     */
    function updateFlashloanPremiums(
        uint128 flashLoanPremiumTotal,
        uint128 flashLoanPremiumToProtocol
    ) external;

    /**
     * @notice Configures a new category for the eMode.
     * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category.
     * The category 0 is reserved as it's the default for volatile assets
     * @param id The id of the category
     * @param config The configuration of the category
     */
    function configureEModeCategory(
        uint8 id,
        DataTypes.EModeCategory memory config
    ) external;

    /**
     * @notice Returns the data of an eMode category
     * @param id The id of the category
     * @return The configuration data of the category
     */
    function getEModeCategoryData(uint8 id)
        external
        view
        returns (DataTypes.EModeCategory memory);

    /**
     * @notice Allows a user to use the protocol in eMode
     * @param categoryId The id of the category
     */
    function setUserEMode(uint8 categoryId) external;

    /**
     * @notice Returns the eMode the user is using
     * @param user The address of the user
     * @return The eMode id
     */
    function getUserEMode(address user) external view returns (uint256);

    /**
     * @notice Resets the isolation mode total debt of the given asset to zero
     * @dev It requires the given asset has zero debt ceiling
     * @param asset The address of the underlying asset to reset the isolationModeTotalDebt
     */
    function resetIsolationModeTotalDebt(address asset) external;

    /**
     * @notice Returns the percentage of available liquidity that can be borrowed at once at stable rate
     * @return The percentage of available liquidity to borrow, expressed in bps
     */
    function MAX_STABLE_RATE_BORROW_SIZE_PERCENT()
        external
        view
        returns (uint256);

    /**
     * @notice Returns the total fee on flash loans
     * @return The total fee on flashloans
     */
    function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128);

    /**
     * @notice Returns the part of the bridge fees sent to protocol
     * @return The bridge fee sent to the protocol treasury
     */
    function BRIDGE_PROTOCOL_FEE() external view returns (uint256);

    /**
     * @notice Returns the part of the flashloan fees sent to protocol
     * @return The flashloan fee sent to the protocol treasury
     */
    function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128);

    /**
     * @notice Returns the maximum number of reserves supported to be listed in this Pool
     * @return The maximum number of reserves supported
     */
    function MAX_NUMBER_RESERVES() external view returns (uint16);

    /**
     * @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens
     * @param assets The list of reserves for which the minting needs to be executed
     **/
    function mintToTreasury(address[] calldata assets) external;

    /**
     * @notice Rescue and transfer tokens locked in this contract
     * @param token The address of the token
     * @param to The address of the recipient
     * @param amount The amount of token to transfer
     */
    function rescueTokens(
        address token,
        address to,
        uint256 amount
    ) external;

    /**
     * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
     * - E.g. User supplies 100 USDC and gets in return 100 aUSDC
     * @dev Deprecated: Use the `supply` function instead
     * @param asset The address of the underlying asset to supply
     * @param amount The amount to be supplied
     * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
     *   wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
     *   is a different wallet
     * @param referralCode Code used to register the integrator originating the operation, for potential rewards.
     *   0 if the action is executed directly by the user, without any middle-man
     **/
    function deposit(
        address asset,
        uint256 amount,
        address onBehalfOf,
        uint16 referralCode
    ) external;
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.0;

/**
 * @title IPoolAddressesProvider
 * @author Aave
 * @notice Defines the basic interface for a Pool Addresses Provider.
 **/
interface IPoolAddressesProvider {
    /**
     * @dev Emitted when the market identifier is updated.
     * @param oldMarketId The old id of the market
     * @param newMarketId The new id of the market
     */
    event MarketIdSet(string indexed oldMarketId, string indexed newMarketId);

    /**
     * @dev Emitted when the pool is updated.
     * @param oldAddress The old address of the Pool
     * @param newAddress The new address of the Pool
     */
    event PoolUpdated(address indexed oldAddress, address indexed newAddress);

    /**
     * @dev Emitted when the pool configurator is updated.
     * @param oldAddress The old address of the PoolConfigurator
     * @param newAddress The new address of the PoolConfigurator
     */
    event PoolConfiguratorUpdated(
        address indexed oldAddress,
        address indexed newAddress
    );

    /**
     * @dev Emitted when the price oracle is updated.
     * @param oldAddress The old address of the PriceOracle
     * @param newAddress The new address of the PriceOracle
     */
    event PriceOracleUpdated(
        address indexed oldAddress,
        address indexed newAddress
    );

    /**
     * @dev Emitted when the ACL manager is updated.
     * @param oldAddress The old address of the ACLManager
     * @param newAddress The new address of the ACLManager
     */
    event ACLManagerUpdated(
        address indexed oldAddress,
        address indexed newAddress
    );

    /**
     * @dev Emitted when the ACL admin is updated.
     * @param oldAddress The old address of the ACLAdmin
     * @param newAddress The new address of the ACLAdmin
     */
    event ACLAdminUpdated(
        address indexed oldAddress,
        address indexed newAddress
    );

    /**
     * @dev Emitted when the price oracle sentinel is updated.
     * @param oldAddress The old address of the PriceOracleSentinel
     * @param newAddress The new address of the PriceOracleSentinel
     */
    event PriceOracleSentinelUpdated(
        address indexed oldAddress,
        address indexed newAddress
    );

    /**
     * @dev Emitted when the pool data provider is updated.
     * @param oldAddress The old address of the PoolDataProvider
     * @param newAddress The new address of the PoolDataProvider
     */
    event PoolDataProviderUpdated(
        address indexed oldAddress,
        address indexed newAddress
    );

    /**
     * @dev Emitted when a new proxy is created.
     * @param id The identifier of the proxy
     * @param proxyAddress The address of the created proxy contract
     * @param implementationAddress The address of the implementation contract
     */
    event ProxyCreated(
        bytes32 indexed id,
        address indexed proxyAddress,
        address indexed implementationAddress
    );

    /**
     * @dev Emitted when a new non-proxied contract address is registered.
     * @param id The identifier of the contract
     * @param oldAddress The address of the old contract
     * @param newAddress The address of the new contract
     */
    event AddressSet(
        bytes32 indexed id,
        address indexed oldAddress,
        address indexed newAddress
    );

    /**
     * @dev Emitted when the implementation of the proxy registered with id is updated
     * @param id The identifier of the contract
     * @param proxyAddress The address of the proxy contract
     * @param oldImplementationAddress The address of the old implementation contract
     * @param newImplementationAddress The address of the new implementation contract
     */
    event AddressSetAsProxy(
        bytes32 indexed id,
        address indexed proxyAddress,
        address oldImplementationAddress,
        address indexed newImplementationAddress
    );

    /**
     * @notice Returns the id of the Aave market to which this contract points to.
     * @return The market id
     **/
    function getMarketId() external view returns (string memory);

    /**
     * @notice Associates an id with a specific PoolAddressesProvider.
     * @dev This can be used to create an onchain registry of PoolAddressesProviders to
     * identify and validate multiple Aave markets.
     * @param newMarketId The market id
     */
    function setMarketId(string calldata newMarketId) external;

    /**
     * @notice Returns an address by its identifier.
     * @dev The returned address might be an EOA or a contract, potentially proxied
     * @dev It returns ZERO if there is no registered address with the given id
     * @param id The id
     * @return The address of the registered for the specified id
     */
    function getAddress(bytes32 id) external view returns (address);

    /**
     * @notice General function to update the implementation of a proxy registered with
     * certain `id`. If there is no proxy registered, it will instantiate one and
     * set as implementation the `newImplementationAddress`.
     * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit
     * setter function, in order to avoid unexpected consequences
     * @param id The id
     * @param newImplementationAddress The address of the new implementation
     */
    function setAddressAsProxy(bytes32 id, address newImplementationAddress)
        external;

    /**
     * @notice Sets an address for an id replacing the address saved in the addresses map.
     * @dev IMPORTANT Use this function carefully, as it will do a hard replacement
     * @param id The id
     * @param newAddress The address to set
     */
    function setAddress(bytes32 id, address newAddress) external;

    /**
     * @notice Returns the address of the Pool proxy.
     * @return The Pool proxy address
     **/
    function getPool() external view returns (address);

    /**
     * @notice Updates the implementation of the Pool, or creates a proxy
     * setting the new `pool` implementation when the function is called for the first time.
     * @param newPoolImpl The new Pool implementation
     **/
    function setPoolImpl(address newPoolImpl) external;

    /**
     * @notice Returns the address of the PoolConfigurator proxy.
     * @return The PoolConfigurator proxy address
     **/
    function getPoolConfigurator() external view returns (address);

    /**
     * @notice Updates the implementation of the PoolConfigurator, or creates a proxy
     * setting the new `PoolConfigurator` implementation when the function is called for the first time.
     * @param newPoolConfiguratorImpl The new PoolConfigurator implementation
     **/
    function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external;

    /**
     * @notice Returns the address of the price oracle.
     * @return The address of the PriceOracle
     */
    function getPriceOracle() external view returns (address);

    /**
     * @notice Updates the address of the price oracle.
     * @param newPriceOracle The address of the new PriceOracle
     */
    function setPriceOracle(address newPriceOracle) external;

    /**
     * @notice Returns the address of the ACL manager.
     * @return The address of the ACLManager
     */
    function getACLManager() external view returns (address);

    /**
     * @notice Updates the address of the ACL manager.
     * @param newAclManager The address of the new ACLManager
     **/
    function setACLManager(address newAclManager) external;

    /**
     * @notice Returns the address of the ACL admin.
     * @return The address of the ACL admin
     */
    function getACLAdmin() external view returns (address);

    /**
     * @notice Updates the address of the ACL admin.
     * @param newAclAdmin The address of the new ACL admin
     */
    function setACLAdmin(address newAclAdmin) external;

    /**
     * @notice Returns the address of the price oracle sentinel.
     * @return The address of the PriceOracleSentinel
     */
    function getPriceOracleSentinel() external view returns (address);

    /**
     * @notice Updates the address of the price oracle sentinel.
     * @param newPriceOracleSentinel The address of the new PriceOracleSentinel
     **/
    function setPriceOracleSentinel(address newPriceOracleSentinel) external;

    /**
     * @notice Returns the address of the data provider.
     * @return The address of the DataProvider
     */
    function getPoolDataProvider() external view returns (address);

    /**
     * @notice Updates the address of the data provider.
     * @param newDataProvider The address of the new DataProvider
     **/
    function setPoolDataProvider(address newDataProvider) external;
}

File 12 of 33 : DataTypes.sol
// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.0;

library DataTypes {
    struct ReserveData {
        //stores the reserve configuration
        ReserveConfigurationMap configuration;
        //the liquidity index. Expressed in ray
        uint128 liquidityIndex;
        //the current supply rate. Expressed in ray
        uint128 currentLiquidityRate;
        //variable borrow index. Expressed in ray
        uint128 variableBorrowIndex;
        //the current variable borrow rate. Expressed in ray
        uint128 currentVariableBorrowRate;
        //the current stable borrow rate. Expressed in ray
        uint128 currentStableBorrowRate;
        //timestamp of last update
        uint40 lastUpdateTimestamp;
        //the id of the reserve. Represents the position in the list of the active reserves
        uint16 id;
        //aToken address
        address aTokenAddress;
        //stableDebtToken address
        address stableDebtTokenAddress;
        //variableDebtToken address
        address variableDebtTokenAddress;
        //address of the interest rate strategy
        address interestRateStrategyAddress;
        //the current treasury balance, scaled
        uint128 accruedToTreasury;
        //the outstanding unbacked aTokens minted through the bridging feature
        uint128 unbacked;
        //the outstanding debt borrowed against this asset in isolation mode
        uint128 isolationModeTotalDebt;
    }

    struct ReserveConfigurationMap {
        //bit 0-15: LTV
        //bit 16-31: Liq. threshold
        //bit 32-47: Liq. bonus
        //bit 48-55: Decimals
        //bit 56: reserve is active
        //bit 57: reserve is frozen
        //bit 58: borrowing is enabled
        //bit 59: stable rate borrowing enabled
        //bit 60: asset is paused
        //bit 61: borrowing in isolation mode is enabled
        //bit 62-63: reserved
        //bit 64-79: reserve factor
        //bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap
        //bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap
        //bit 152-167 liquidation protocol fee
        //bit 168-175 eMode category
        //bit 176-211 unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled
        //bit 212-251 debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals
        //bit 252-255 unused

        uint256 data;
    }

    struct UserConfigurationMap {
        /**
         * @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one pair per asset.
         * The first bit indicates if an asset is used as collateral by the user, the second whether an
         * asset is borrowed by the user.
         */
        uint256 data;
    }

    struct EModeCategory {
        // each eMode category has a custom ltv and liquidation threshold
        uint16 ltv;
        uint16 liquidationThreshold;
        uint16 liquidationBonus;
        // each eMode category may or may not have a custom oracle to override the individual assets price oracles
        address priceSource;
        string label;
    }

    enum InterestRateMode {
        NONE,
        STABLE,
        VARIABLE
    }

    struct ReserveCache {
        uint256 currScaledVariableDebt;
        uint256 nextScaledVariableDebt;
        uint256 currPrincipalStableDebt;
        uint256 currAvgStableBorrowRate;
        uint256 currTotalStableDebt;
        uint256 nextAvgStableBorrowRate;
        uint256 nextTotalStableDebt;
        uint256 currLiquidityIndex;
        uint256 nextLiquidityIndex;
        uint256 currVariableBorrowIndex;
        uint256 nextVariableBorrowIndex;
        uint256 currLiquidityRate;
        uint256 currVariableBorrowRate;
        uint256 reserveFactor;
        ReserveConfigurationMap reserveConfiguration;
        address aTokenAddress;
        address stableDebtTokenAddress;
        address variableDebtTokenAddress;
        uint40 reserveLastUpdateTimestamp;
        uint40 stableDebtLastUpdateTimestamp;
    }

    struct ExecuteLiquidationCallParams {
        uint256 reservesCount;
        uint256 debtToCover;
        address collateralAsset;
        address debtAsset;
        address user;
        bool receiveAToken;
        address priceOracle;
        uint8 userEModeCategory;
        address priceOracleSentinel;
    }

    struct ExecuteSupplyParams {
        address asset;
        uint256 amount;
        address onBehalfOf;
        uint16 referralCode;
    }

    struct ExecuteBorrowParams {
        address asset;
        address user;
        address onBehalfOf;
        uint256 amount;
        InterestRateMode interestRateMode;
        uint16 referralCode;
        bool releaseUnderlying;
        uint256 maxStableRateBorrowSizePercent;
        uint256 reservesCount;
        address oracle;
        uint8 userEModeCategory;
        address priceOracleSentinel;
    }

    struct ExecuteRepayParams {
        address asset;
        uint256 amount;
        InterestRateMode interestRateMode;
        address onBehalfOf;
        bool useATokens;
    }

    struct ExecuteWithdrawParams {
        address asset;
        uint256 amount;
        address to;
        uint256 reservesCount;
        address oracle;
        uint8 userEModeCategory;
    }

    struct ExecuteSetUserEModeParams {
        uint256 reservesCount;
        address oracle;
        uint8 categoryId;
    }

    struct FinalizeTransferParams {
        address asset;
        address from;
        address to;
        uint256 amount;
        uint256 balanceFromBefore;
        uint256 balanceToBefore;
        uint256 reservesCount;
        address oracle;
        uint8 fromEModeCategory;
    }

    struct FlashloanParams {
        address receiverAddress;
        address[] assets;
        uint256[] amounts;
        uint256[] interestRateModes;
        address onBehalfOf;
        bytes params;
        uint16 referralCode;
        uint256 flashLoanPremiumToProtocol;
        uint256 flashLoanPremiumTotal;
        uint256 maxStableRateBorrowSizePercent;
        uint256 reservesCount;
        address addressesProvider;
        uint8 userEModeCategory;
        bool isAuthorizedFlashBorrower;
    }

    struct FlashloanSimpleParams {
        address receiverAddress;
        address asset;
        uint256 amount;
        bytes params;
        uint16 referralCode;
        uint256 flashLoanPremiumToProtocol;
        uint256 flashLoanPremiumTotal;
    }

    struct FlashLoanRepaymentParams {
        uint256 amount;
        uint256 totalPremium;
        uint256 flashLoanPremiumToProtocol;
        address asset;
        address receiverAddress;
        uint16 referralCode;
    }

    struct CalculateUserAccountDataParams {
        UserConfigurationMap userConfig;
        uint256 reservesCount;
        address user;
        address oracle;
        uint8 userEModeCategory;
    }

    struct ValidateBorrowParams {
        ReserveCache reserveCache;
        UserConfigurationMap userConfig;
        address asset;
        address userAddress;
        uint256 amount;
        InterestRateMode interestRateMode;
        uint256 maxStableLoanPercent;
        uint256 reservesCount;
        address oracle;
        uint8 userEModeCategory;
        address priceOracleSentinel;
        bool isolationModeActive;
        address isolationModeCollateralAddress;
        uint256 isolationModeDebtCeiling;
    }

    struct ValidateLiquidationCallParams {
        ReserveCache debtReserveCache;
        uint256 totalDebt;
        uint256 healthFactor;
        address priceOracleSentinel;
    }

    struct CalculateInterestRatesParams {
        uint256 unbacked;
        uint256 liquidityAdded;
        uint256 liquidityTaken;
        uint256 totalStableDebt;
        uint256 totalVariableDebt;
        uint256 averageStableBorrowRate;
        uint256 reserveFactor;
        address reserve;
        address aToken;
    }

    struct InitReserveParams {
        address asset;
        address aTokenAddress;
        address stableDebtAddress;
        address variableDebtAddress;
        address interestRateStrategyAddress;
        uint16 reservesCount;
        uint16 maxNumberReserves;
    }
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.0;

import {IPoolAddressesProvider} from "./IPoolAddressesProvider.sol";
import {IPool} from "./IPool.sol";

/**
 * @title IFlashLoanReceiver
 * @author Aave
 * @notice Defines the basic interface of a flashloan-receiver contract.
 * @dev Implement this interface to develop a flashloan-compatible flashLoanReceiver contract
 **/
interface IFlashLoanReceiver {
    /**
     * @notice Executes an operation after receiving the flash-borrowed assets
     * @dev Ensure that the contract can return the debt + premium, e.g., has
     *      enough funds to repay and has approved the Pool to pull the total amount
     * @param assets The addresses of the flash-borrowed assets
     * @param amounts The amounts of the flash-borrowed assets
     * @param premiums The fee of each flash-borrowed asset
     * @param initiator The address of the flashloan initiator
     * @param params The byte-encoded params passed when initiating the flashloan
     * @return True if the execution of the operation succeeds, false otherwise
     */
    function executeOperation(
        address[] calldata assets,
        uint256[] calldata amounts,
        uint256[] calldata premiums,
        address initiator,
        bytes calldata params
    ) external returns (bool);

    function ADDRESSES_PROVIDER()
        external
        view
        returns (IPoolAddressesProvider);

    function POOL() external view returns (IPool);
}

// SPDX-License-Identifier: agpl-3.0

pragma solidity ^0.8.0;

import {IRewardsDistributor} from "./IRewardsDistributor.sol";
import {ITransferStrategyBase} from "./ITransferStrategyBase.sol";
import {IEACAggregatorProxy} from "./IEACAggregatorProxy.sol";

import {RewardsDistributorTypes} from "../libraries/RewardsDistributorTypes.sol";

interface IRewardsController is IRewardsDistributor {
    event ClaimerSet(address indexed user, address indexed claimer);

    event RewardsClaimed(
        address indexed user,
        address indexed reward,
        address indexed to,
        address claimer,
        uint256 amount
    );

    event TransferStrategyInstalled(
        address indexed reward,
        address indexed transferStrategy
    );

    event RewardOracleUpdated(
        address indexed reward,
        address indexed rewardOracle
    );

    /**
     * @dev Whitelists an address to claim the rewards on behalf of another address
     * @param user The address of the user
     * @param claimer The address of the claimer
     */
    function setClaimer(address user, address claimer) external;

    /**
     * @dev Sets a TransferStrategy logic contract that determines the logic of the rewards transfer
     * @param reward The address of the reward token
     * @param transferStrategy The address of the TransferStrategy logic contract
     */
    function setTransferStrategy(
        address reward,
        ITransferStrategyBase transferStrategy
    ) external;

    /**
     * @dev Sets an Aave Oracle contract to enforce rewards with a source of value.
     * @notice At the moment of reward configuration, the Incentives Controller performs
     * a check to see if the reward asset oracle is compatible with IEACAggregator proxy.
     * This check is enforced for integrators to be able to show incentives at
     * the current Aave UI without the need to setup an external price registry
     * @param reward The address of the reward to set the price aggregator
     * @param rewardOracle The address of price aggregator that follows IEACAggregatorProxy interface
     */
    function setRewardOracle(address reward, IEACAggregatorProxy rewardOracle)
        external;

    /**
     * @dev Get the price aggregator oracle address
     * @param reward The address of the reward
     * @return The price oracle of the reward
     */
    function getRewardOracle(address reward) external view returns (address);

    /**
     * @dev Returns the whitelisted claimer for a certain address (0x0 if not set)
     * @param user The address of the user
     * @return The claimer address
     */
    function getClaimer(address user) external view returns (address);

    /**
     * @dev Returns the Transfer Strategy implementation contract address being used for a reward address
     * @param reward The address of the reward
     * @return The address of the TransferStrategy contract
     */
    function getTransferStrategy(address reward)
        external
        view
        returns (address);

    /**
     * @dev Configure assets to incentivize with an emission of rewards per second until the end of distribution.
     * @param config The assets configuration input, the list of structs contains the following fields:
     *   uint104 emissionPerSecond: The emission per second following rewards unit decimals.
     *   uint256 totalSupply: The total supply of the asset to incentivize
     *   uint40 distributionEnd: The end of the distribution of the incentives for an asset
     *   address asset: The asset address to incentivize
     *   address reward: The reward token address
     *   ITransferStrategy transferStrategy: The TransferStrategy address with the install hook and claim logic.
     *   IEACAggregatorProxy rewardOracle: The Price Oracle of a reward to visualize the incentives at the UI Frontend.
     *                                     Must follow Chainlink Aggregator IEACAggregatorProxy interface to be compatible.
     */
    function configureAssets(
        RewardsDistributorTypes.RewardsConfigInput[] memory config
    ) external;

    /**
     * @dev Called by the corresponding asset on any update that affects the rewards distribution
     * @param user The address of the user
     * @param userBalance The user balance of the asset
     * @param totalSupply The total supply of the asset
     **/
    function handleAction(
        address user,
        uint256 userBalance,
        uint256 totalSupply
    ) external;

    /**
     * @dev Claims reward for an user to the desired address, on all the assets of the lending pool, accumulating the pending rewards
     * @param assets List of assets to check eligible distributions before claiming rewards
     * @param amount Amount of rewards to claim
     * @param to Address that will be receiving the rewards
     * @param reward Address of the reward token
     * @return Rewards claimed
     **/
    function claimRewards(
        address[] calldata assets,
        uint256 amount,
        address to,
        address reward
    ) external returns (uint256);

    /**
     * @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards. The caller must
     * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
     * @param assets List of assets to check eligible distributions before claiming rewards
     * @param amount Amount of rewards to claim
     * @param user Address to check and claim rewards
     * @param to Address that will be receiving the rewards
     * @param reward Address of the reward token
     * @return Rewards claimed
     **/
    function claimRewardsOnBehalf(
        address[] calldata assets,
        uint256 amount,
        address user,
        address to,
        address reward
    ) external returns (uint256);

    /**
     * @dev Claims reward for msg.sender, on all the assets of the lending pool, accumulating the pending rewards
     * @param assets List of assets to check eligible distributions before claiming rewards
     * @param amount Amount of rewards to claim
     * @param reward Address of the reward token
     * @return Rewards claimed
     **/
    function claimRewardsToSelf(
        address[] calldata assets,
        uint256 amount,
        address reward
    ) external returns (uint256);

    /**
     * @dev Claims all rewards for an user to the desired address, on all the assets of the lending pool, accumulating the pending rewards
     * @param assets List of assets to check eligible distributions before claiming rewards
     * @param to Address that will be receiving the rewards
     * @return rewardsList List of addresses of the reward tokens and claimedAmounts, the list that contains the claimed amount per reward, following same order as "rewardList"
     * @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardList"
     **/
    function claimAllRewards(address[] calldata assets, address to)
        external
        returns (address[] memory rewardsList, uint256[] memory claimedAmounts);

    /**
     * @dev Claims all rewards for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards. The caller must
     * be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
     * @param assets List of assets to check eligible distributions before claiming rewards
     * @param user Address to check and claim rewards
     * @param to Address that will be receiving the rewards
     * @return rewardsList List of addresses of the reward tokens and claimedAmounts, the list that contains the claimed amount per reward, following same order as "rewardList"
     * @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardsList"
     **/
    function claimAllRewardsOnBehalf(
        address[] calldata assets,
        address user,
        address to
    )
        external
        returns (address[] memory rewardsList, uint256[] memory claimedAmounts);

    /**
     * @dev Claims all reward for msg.sender, on all the assets of the lending pool, accumulating the pending rewards
     * @param assets List of assets to check eligible distributions before claiming rewards
     * @return rewardsList List of addresses of the reward tokens and claimedAmounts, the list that contains the claimed amount per reward, following same order as "rewardList"
     * @return claimedAmounts List that contains the claimed amount per reward, following same order as "rewardsList"
     **/
    function claimAllRewardsToSelf(address[] calldata assets)
        external
        returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
}

// SPDX-License-Identifier: agpl-3.0

pragma solidity ^0.8.0;

import {RewardsDistributorTypes} from "../libraries/RewardsDistributorTypes.sol";

interface IRewardsDistributor {
    event AssetConfigUpdated(
        address indexed asset,
        address indexed reward,
        uint256 emission,
        uint256 distributionEnd
    );
    event AssetIndexUpdated(
        address indexed asset,
        address indexed reward,
        uint256 index
    );
    event UserIndexUpdated(
        address indexed user,
        address indexed asset,
        address indexed reward,
        uint256 index
    );

    event RewardsAccrued(
        address indexed user,
        address indexed reward,
        uint256 amount
    );

    /**
     * @dev Sets the end date for the distribution
     * @param asset The asset to incentivize
     * @param reward The reward token that incentives the asset
     * @param distributionEnd The end date of the incentivization, in unix time format
     **/
    function setDistributionEnd(
        address asset,
        address reward,
        uint32 distributionEnd
    ) external;

    /**
     * @dev Gets the end date for the distribution
     * @param asset The incentivized asset
     * @param reward The reward token of the incentivized asset
     * @return The timestamp with the end of the distribution, in unix time format
     **/
    function getDistributionEnd(address asset, address reward)
        external
        view
        returns (uint256);

    /**
     * @dev Returns the index of an user on a reward distribution
     * @param user Address of the user
     * @param asset The incentivized asset
     * @param reward The reward token of the incentivized asset
     * @return The current user asset index in storage, not including new distributions
     **/
    function getUserAssetData(
        address user,
        address asset,
        address reward
    ) external view returns (uint256);

    /**
     * @dev Returns the configuration of the distribution for a certain asset
     * @param asset The incentivized asset
     * @param reward The reward token of the incentivized asset
     * @return The asset index, the emission per second, the last updated timestamp and the distribution end timestamp
     **/
    function getRewardsData(address asset, address reward)
        external
        view
        returns (
            uint256,
            uint256,
            uint256,
            uint256
        );

    /**
     * @dev Returns the list of available reward token addresses of an incentivized asset
     * @param asset The incentivized asset
     * @return List of rewards addresses of the input asset
     **/
    function getRewardsByAsset(address asset)
        external
        view
        returns (address[] memory);

    /**
     * @dev Returns the list of available reward addresses
     * @return List of rewards supported in this contract
     **/
    function getRewardsList() external view returns (address[] memory);

    /**
     * @dev Returns a single rewards balance of an user from contract storage state, not including virtually accrued rewards since last distribution.
     * @param user The address of the user
     * @param reward The address of the reward token
     * @return Unclaimed rewards, from storage
     **/
    function getUserUnclaimedRewardsFromStorage(address user, address reward)
        external
        view
        returns (uint256);

    /**
     * @dev Returns a single rewards balance of an user, including virtually accrued and unrealized claimable rewards.
     * @param assets List of incentivized assets to check eligible distributions
     * @param user The address of the user
     * @param reward The address of the reward token
     * @return The rewards amount
     **/
    function getUserRewardsBalance(
        address[] calldata assets,
        address user,
        address reward
    ) external view returns (uint256);

    /**
     * @dev Returns a list all rewards of an user, including already accrued and unrealized claimable rewards
     * @param assets List of incentivized assets to check eligible distributions
     * @param user The address of the user
     * @return The function returns a Tuple of rewards list and the unclaimed rewards list
     **/
    function getAllUserRewardsBalance(address[] calldata assets, address user)
        external
        view
        returns (address[] memory, uint256[] memory);

    /**
     * @dev Returns the decimals of an asset to calculate the distribution delta
     * @param asset The address to retrieve decimals saved at storage
     * @return The decimals of an underlying asset
     */
    function getAssetDecimals(address asset) external view returns (uint8);
}

File 16 of 33 : RewardsDistributorTypes.sol
// SPDX-License-Identifier: agpl-3.0

pragma solidity ^0.8.0;

import {ITransferStrategyBase} from "../interfaces/ITransferStrategyBase.sol";
import {IEACAggregatorProxy} from "../interfaces/IEACAggregatorProxy.sol";

library RewardsDistributorTypes {
    struct RewardsConfigInput {
        uint88 emissionPerSecond;
        uint256 totalSupply;
        uint32 distributionEnd;
        address asset;
        address reward;
        ITransferStrategyBase transferStrategy;
        IEACAggregatorProxy rewardOracle;
    }

    struct UserAssetStatsInput {
        address underlyingAsset;
        uint256 userBalance;
        uint256 totalSupply;
    }
}

// SPDX-License-Identifier: AGPL-3.0

pragma solidity ^0.8.0;

interface ITransferStrategyBase {
    event EmergencyWithdrawal(
        address indexed caller,
        address indexed token,
        address indexed to,
        uint256 amount
    );

    /**
     * @dev Perform custom transfer logic via delegate call from source contract to a TransferStrategy implementation
     * @param to Account to transfer rewards
     * @param reward Address of the reward token
     * @param amount Amount to transfer to the "to" address parameter
     * @return Returns true bool if transfer logic succeeds
     */
    function performTransfer(
        address to,
        address reward,
        uint256 amount
    ) external returns (bool);

    /**
     * @return Returns the address of the Incentives Controller
     */
    function getIncentivesController() external view returns (address);

    /**
     * @return Returns the address of the Rewards admin
     */
    function getRewardsAdmin() external view returns (address);

    /**
     * @dev Perform an emergency token withdrawal only callable by the Rewards admin
     * @param token Address of the token to withdraw funds from this contract
     * @param to Address of the recipient of the withdrawal
     * @param amount Amount of the withdrawal
     */
    function emergencyWithdrawal(
        address token,
        address to,
        uint256 amount
    ) external;
}

// SPDX-License-Identifier: agpl-3.0

pragma solidity ^0.8.0;

interface IEACAggregatorProxy {
    function decimals() external view returns (uint8);

    function latestAnswer() external view returns (int256);

    function latestTimestamp() external view returns (uint256);

    function latestRound() external view returns (uint256);

    function getAnswer(uint256 roundId) external view returns (int256);

    function getTimestamp(uint256 roundId) external view returns (uint256);

    event AnswerUpdated(
        int256 indexed current,
        uint256 indexed roundId,
        uint256 timestamp
    );
    event NewRound(uint256 indexed roundId, address indexed startedBy);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IRouter {
    function pairFor(
        address tokenA,
        address tokenB,
        bool stable
    ) external view returns (address pair);
}

interface IWETH {
    function deposit() external payable returns (uint256);

    function transfer(address to, uint256 value) external returns (bool);

    function withdraw(uint256) external returns (uint256);
}

interface IVeloRouter is IRouter {
    struct route {
        address from;
        address to;
        bool stable;
    }

    function factory() external view returns (address);

    function weth() external view returns (IWETH);

    function sortTokens(address tokenA, address tokenB) external pure returns (address token0, address token1);

    function pairFor(
        address tokenA,
        address tokenB,
        bool stable
    ) external view returns (address pair);

    function getReserves(
        address tokenA,
        address tokenB,
        bool stable
    ) external view returns (uint256 reserveA, uint256 reserveB);

    function getAmountOut(
        uint256 amountIn,
        address tokenIn,
        address tokenOut
    ) external view returns (uint256 amount, bool stable);

    function getAmountsOut(uint256 amountIn, route[] memory routes) external view returns (uint256[] memory amounts);

    function isPair(address pair) external view returns (bool);

    function quoteAddLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 amountADesired,
        uint256 amountBDesired
    )
        external
        view
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        );

    function quoteRemoveLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 liquidity
    ) external view returns (uint256 amountA, uint256 amountB);

    function addLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 amountADesired,
        uint256 amountBDesired,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    )
        external
        returns (
            uint256 amountA,
            uint256 amountB,
            uint256 liquidity
        );

    function addLiquidityETH(
        address token,
        bool stable,
        uint256 amountTokenDesired,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    )
        external
        payable
        returns (
            uint256 amountToken,
            uint256 amountETH,
            uint256 liquidity
        );

    function removeLiquidity(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETH(
        address token,
        bool stable,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline
    ) external returns (uint256 amountToken, uint256 amountETH);

    function removeLiquidityWithPermit(
        address tokenA,
        address tokenB,
        bool stable,
        uint256 liquidity,
        uint256 amountAMin,
        uint256 amountBMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountA, uint256 amountB);

    function removeLiquidityETHWithPermit(
        address token,
        bool stable,
        uint256 liquidity,
        uint256 amountTokenMin,
        uint256 amountETHMin,
        address to,
        uint256 deadline,
        bool approveMax,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external returns (uint256 amountToken, uint256 amountETH);

    function swapExactTokensForTokensSimple(
        uint256 amountIn,
        uint256 amountOutMin,
        address tokenFrom,
        address tokenTo,
        bool stable,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        route[] calldata routes,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function swapExactETHForTokens(
        uint256 amountOutMin,
        route[] calldata routes,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts);

    function swapExactTokensForETH(
        uint256 amountIn,
        uint256 amountOutMin,
        route[] calldata routes,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts);

    function UNSAFE_swapExactTokensForTokens(
        uint256[] memory amounts,
        route[] calldata routes,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.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 SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 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(
        IERC20 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));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @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(IERC20 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");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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 `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, 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 `sender` to `recipient` 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 sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /**
     * @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);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Address.sol)

pragma solidity ^0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 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://diligence.consensys.net/posts/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.5.11/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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason 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 {
            // 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a / b + (a % b == 0 ? 0 : 1);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/AccessControlEnumerable.sol)

pragma solidity ^0.8.0;

import "./IAccessControlEnumerable.sol";
import "./AccessControl.sol";
import "../utils/structs/EnumerableSet.sol";

/**
 * @dev Extension of {AccessControl} that allows enumerating the members of each role.
 */
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
    using EnumerableSet for EnumerableSet.AddressSet;

    mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {
        return _roleMembers[role].at(index);
    }

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) public view override returns (uint256) {
        return _roleMembers[role].length();
    }

    /**
     * @dev Overload {_grantRole} to track enumerable memberships
     */
    function _grantRole(bytes32 role, address account) internal virtual override {
        super._grantRole(role, account);
        _roleMembers[role].add(account);
    }

    /**
     * @dev Overload {_revokeRole} to track enumerable memberships
     */
    function _revokeRole(bytes32 role, address account) internal virtual override {
        super._revokeRole(role, account);
        _roleMembers[role].remove(account);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";

/**
 * @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
 */
interface IAccessControlEnumerable is IAccessControl {
    /**
     * @dev Returns one of the accounts that have `role`. `index` must be a
     * value between 0 and {getRoleMemberCount}, non-inclusive.
     *
     * Role bearers are not sorted in any particular way, and their ordering may
     * change at any point.
     *
     * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
     * you perform all queries on the same block. See the following
     * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
     * for more information.
     */
    function getRoleMember(bytes32 role, uint256 index) external view returns (address);

    /**
     * @dev Returns the number of accounts that have `role`. Can be used
     * together with {getRoleMember} to enumerate all bearers of a role.
     */
    function getRoleMemberCount(bytes32 role) external view returns (uint256);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)

pragma solidity ^0.8.0;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     * _Available since v3.1._
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)

pragma solidity ^0.8.0;

import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address => bool) members;
        bytes32 adminRole;
    }

    mapping(bytes32 => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with a standardized message including the required role.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     *
     * _Available since v4.1._
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role, _msgSender());
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view override returns (bool) {
        return _roles[role].members[account];
    }

    /**
     * @dev Revert with a standard message if `account` is missing `role`.
     *
     * The format of the revert reason is given by the following regular expression:
     *
     *  /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
     */
    function _checkRole(bytes32 role, address account) internal view {
        if (!hasRole(role, account)) {
            revert(
                string(
                    abi.encodePacked(
                        "AccessControl: account ",
                        Strings.toHexString(uint160(account), 20),
                        " is missing role ",
                        Strings.toHexString(uint256(role), 32)
                    )
                )
            );
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) public virtual override {
        require(account == _msgSender(), "AccessControl: can only renounce roles for self");

        _revokeRole(role, account);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event. Note that unlike {grantRole}, this function doesn't perform any
     * checks on the calling account.
     *
     * [WARNING]
     * ====
     * This function should only be called from the constructor when setting
     * up the initial roles for the system.
     *
     * Using this function in any other way is effectively circumventing the admin
     * system imposed by {AccessControl}.
     * ====
     *
     * NOTE: This function is deprecated in favor of {_grantRole}.
     */
    function _setupRole(bytes32 role, address account) internal virtual {
        _grantRole(role, account);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * Internal function without access restriction.
     */
    function _grantRole(bytes32 role, address account) internal virtual {
        if (!hasRole(role, account)) {
            _roles[role].members[account] = true;
            emit RoleGranted(role, account, _msgSender());
        }
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * Internal function without access restriction.
     */
    function _revokeRole(bytes32 role, address account) internal virtual {
        if (hasRole(role, account)) {
            _roles[role].members[account] = false;
            emit RoleRevoked(role, account, _msgSender());
        }
    }
}

// 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;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastvalue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastvalue;
                // Update the index for the moved value
                set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        return _values(set._inner);
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        assembly {
            result := store
        }

        return result;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.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 Pausable is Context {
    /**
     * @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.
     */
    constructor() {
        _paused = false;
    }

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

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

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        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());
    }
}

Settings
{
  "metadata": {
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address[]","name":"_feeRemitters","type":"address[]"},{"internalType":"address[]","name":"_strategists","type":"address[]"},{"internalType":"address[]","name":"_multisigRoles","type":"address[]"},{"internalType":"contract IAToken","name":"_aWant","type":"address"},{"internalType":"address[]","name":"_opToWantPath","type":"address[]"},{"internalType":"uint256","name":"_targetLtv","type":"uint256"},{"internalType":"uint256","name":"_maxLtv","type":"uint256"},{"internalType":"uint8","name":"_eModeCategory","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newCallFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newTreasuryFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newStrategistFee","type":"uint256"}],"name":"FeesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"harvester","type":"address"}],"name":"StratHarvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newStrategistRemitter","type":"address"}],"name":"StrategistRemitterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newFee","type":"uint256"}],"name":"TotalFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"AAVE_ADDRESSES_PROVIDER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AAVE_DATA_PROVIDER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AAVE_REWARDS_CONTROLLER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ADDRESSES_PROVIDER","outputs":[{"internalType":"contract IPoolAddressesProvider","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"ADMIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARDIAN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"KEEPER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_YEAR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OP","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERCENT_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POOL","outputs":[{"internalType":"contract IPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STRATEGIST","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STRATEGIST_MAX_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VELO_ROUTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aWant","outputs":[{"internalType":"contract IAToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"authorizedDelever","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"authorizedSendToVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"authorizedWithdrawUnderlying","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"_n","type":"int256"}],"name":"averageAPRAcrossLastNHarvests","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startIndex","type":"uint256"},{"internalType":"uint256","name":"_endIndex","type":"uint256"}],"name":"calculateAPRUsingLogs","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"callFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"executeOperation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupplyAndBorrow","outputs":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"borrow","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"harvest","outputs":[{"internalType":"uint256","name":"callerFee","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"harvestLog","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"uint256","name":"vaultSharePrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvestLogCadence","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvestLogLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastHarvestTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxLtv","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minLeverageAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"opToUsdcPath","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"opToWantPath","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"panic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardClaimingTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newTargetLtv","type":"uint256"},{"internalType":"uint256","name":"_newMaxLtv","type":"uint256"}],"name":"setLTVs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newWithdrawSlippageTolerance","type":"uint256"},{"internalType":"uint256","name":"_newMinLeverageAmount","type":"uint256"}],"name":"setLeverageParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_path","type":"address[]"}],"name":"setOpToUsdcPath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_path","type":"address[]"}],"name":"setOpToWantPath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategistFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategistRemitter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"targetLtv","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasuryFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_callFee","type":"uint256"},{"internalType":"uint256","name":"_treasuryFee","type":"uint256"},{"internalType":"uint256","name":"_strategistFee","type":"uint256"}],"name":"updateFees","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newCadenceInSeconds","type":"uint256"}],"name":"updateHarvestLogCadence","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newStrategistRemitter","type":"address"}],"name":"updateStrategistRemitter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalFee","type":"uint256"}],"name":"updateTotalFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasury","type":"address"}],"name":"updateTreasury","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"want","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawSlippageTolerance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b506040516200528138038062005281833981016040819052620000349162000e4c565b6002805460ff19169055603c6004556101c2600a556103e8600b55612328600c556000600d819055600880546001600160a01b0319166001600160a01b038c1617905588518a918a918a918a9184919062000093576200009362000f52565b6020026020010151600760006101000a8154816001600160a01b0302191690836001600160a01b0316021790555082600181518110620000d757620000d762000f52565b6020026020010151600960006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060005b825181101562000164576200014f600080516020620052618339815191528483815181106200013b576200013b62000f52565b60200260200101516200057960201b60201c565b806200015b8162000f7e565b91505062000108565b506200017260003362000579565b620001906000801b826000815181106200013b576200013b62000f52565b620001ba60008051602062005241833981519152826001815181106200013b576200013b62000f52565b620001f57f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe8826002815181106200013b576200013b62000f52565b6040805160a081018252600081526000805160206200524183398151915260208201527f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe8918101919091526000805160206200526183398151915260608201527f71a9859d7dd21b24504a6f306077ffc2d510b4d4b61128e931fe937441ad183660808201526200028b90600690600562000c49565b5060036040518060400160405280428152602001866001600160a01b03166377c7b8fc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620002de573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000304919062000f9c565b90528154600180820184556000938452602093849020835160029093020191825591830151910155600e80546001600160a01b0319166001600160a01b038c16908117909155604080516358b50cef60e11b8152905191965063b16a19de9550600480820195509293509091908290030181865afa1580156200038b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003b1919062000fb6565b600f80546001600160a01b0319166001600160a01b0392909216919091179055600a6013556103e8601255604080518082019091527342000000000000000000000000000000000000428152737f5c764cbc14f9669b88837ca1490cca17c3160760208201526200042790601690600262000c99565b506200043384620005bc565b600f546040516334924edb60e21b81526001600160a01b0390911660048201526000907369fa688f1dc47d4b5d8029d5a35fb7a5483106549063d2493b6c90602401606060405180830381865afa15801562000493573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004b9919062000fdd565b604080518082019091526001600160a01b03808b16825282166020820152909350620004ec925060159150600262000c99565b50620004f7620006d6565b6040516328530a4760e01b815260ff841660048201526001600160a01b0391909116906328530a4790602401600060405180830381600087803b1580156200053e57600080fd5b505af115801562000553573d6000803e3d6000fd5b505050506200056984846200075660201b60201c565b5050505050505050505062001295565b620005908282620009b660201b620016441760201c565b6000828152600160209081526040909120620005b7918390620016c862000a56821b17901c565b505050565b620005d66000805160206200526183398151915262000a76565b7342000000000000000000000000000000000000426001600160a01b0316816000815181106200060a576200060a62000f52565b60200260200101516001600160a01b03161480156200066b5750600f5481516001600160a01b03909116908290620006459060019062001031565b8151811062000658576200065862000f52565b60200260200101516001600160a01b0316145b620006bd5760405162461bcd60e51b815260206004820152601460248201527f496e76616c6964206f70546f57616e745061746800000000000000000000000060448201526064015b60405180910390fd5b8051620006d290601790602084019062000c99565b5050565b600073a97684ead0e402dc232d5a977953df7ecbab3cdb6001600160a01b031663026b1d5f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200072b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000751919062000fb6565b905090565b600062000762620006d6565b60405163eddf1b7960e01b81523060048201526001600160a01b03919091169063eddf1b7990602401602060405180830381865afa158015620007a9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007cf919062000f9c565b90506000811562000869576000620007e6620006d6565b604051636c6f6ae160e01b815260ff851660048201526001600160a01b039190911690636c6f6ae190602401600060405180830381865afa15801562000830573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200085a91908101906200105e565b5161ffff169150620008fa9050565b600f54604051633e15014160e01b81526001600160a01b0390911660048201527369fa688f1dc47d4b5d8029d5a35fb7a54831065490633e1501419060240161014060405180830381865afa158015620008c7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620008ed9190620011ae565b5096985050505050505050505b6127106200090b6126488362001250565b62000917919062001272565b8311156200095a5760405162461bcd60e51b815260206004820152600f60248201526e6d61784c7476206e6f74207361666560881b6044820152606401620006b4565b82841115620009ac5760405162461bcd60e51b815260206004820152601860248201527f7461726765744c7476206d757374203c3d206d61784c747600000000000000006044820152606401620006b4565b5050601155601055565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620006d2576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905562000a123390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b600062000a6d836001600160a01b03841662000bf7565b90505b92915050565b6006546000805b8281101562000b21576006818154811062000a9c5762000a9c62000f52565b906000526020600020015484141562000ab85780915062000b21565b62000ac560018462001031565b81141562000b0c5760405162461bcd60e51b8152602060048201526013602482015272756e617574686f72697a65642061636365737360681b6044820152606401620006b4565b8062000b188162000f7e565b91505062000a7d565b5060005b81811162000bc85762000b5f6006828154811062000b475762000b4762000f52565b90600052602060002001543362000bce60201b60201c565b1562000b6b5762000bc8565b8181141562000bb35760405162461bcd60e51b8152602060048201526013602482015272756e617574686f72697a65642061636365737360681b6044820152606401620006b4565b8062000bbf8162000f7e565b91505062000b25565b50505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b600081815260018301602052604081205462000c405750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000a70565b50600062000a70565b82805482825590600052602060002090810192821562000c87579160200282015b8281111562000c8757825182559160200191906001019062000c6a565b5062000c9592915062000cf1565b5090565b82805482825590600052602060002090810192821562000c87579160200282015b8281111562000c8757825182546001600160a01b0319166001600160a01b0390911617825560209092019160019091019062000cba565b5b8082111562000c95576000815560010162000cf2565b6001600160a01b038116811462000d1e57600080fd5b50565b805162000d2e8162000d08565b919050565b634e487b7160e01b600052604160045260246000fd5b60405160a081016001600160401b038111828210171562000d6e5762000d6e62000d33565b60405290565b604051601f8201601f191681016001600160401b038111828210171562000d9f5762000d9f62000d33565b604052919050565b600082601f83011262000db957600080fd5b815160206001600160401b0382111562000dd75762000dd762000d33565b8160051b62000de882820162000d74565b928352848101820192828101908785111562000e0357600080fd5b83870192505b8483101562000e2f57825162000e1f8162000d08565b8252918301919083019062000e09565b979650505050505050565b805160ff8116811462000d2e57600080fd5b60008060008060008060008060006101208a8c03121562000e6c57600080fd5b62000e778a62000d21565b60208b01519099506001600160401b038082111562000e9557600080fd5b62000ea38d838e0162000da7565b995060408c015191508082111562000eba57600080fd5b62000ec88d838e0162000da7565b985060608c015191508082111562000edf57600080fd5b62000eed8d838e0162000da7565b975062000efd60808d0162000d21565b965060a08c015191508082111562000f1457600080fd5b5062000f238c828d0162000da7565b94505060c08a0151925060e08a0151915062000f436101008b0162000e3a565b90509295985092959850929598565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060001982141562000f955762000f9562000f68565b5060010190565b60006020828403121562000faf57600080fd5b5051919050565b60006020828403121562000fc957600080fd5b815162000fd68162000d08565b9392505050565b60008060006060848603121562000ff357600080fd5b8351620010008162000d08565b6020850151909350620010138162000d08565b6040850151909250620010268162000d08565b809150509250925092565b60008282101562001046576200104662000f68565b500390565b805161ffff8116811462000d2e57600080fd5b600060208083850312156200107257600080fd5b82516001600160401b03808211156200108a57600080fd5b9084019060a082870312156200109f57600080fd5b620010a962000d49565b620010b4836200104b565b8152620010c38484016200104b565b84820152620010d5604084016200104b565b60408201526060830151620010ea8162000d08565b60608201526080830151828111156200110257600080fd5b80840193505086601f8401126200111857600080fd5b8251828111156200112d576200112d62000d33565b62001141601f8201601f1916860162000d74565b925080835287858286010111156200115857600080fd5b60005b81811015620011785784810186015184820187015285016200115b565b818111156200118a5760008683860101525b5050608081019190915295945050505050565b8051801515811462000d2e57600080fd5b6000806000806000806000806000806101408b8d031215620011cf57600080fd5b8a51995060208b0151985060408b0151975060608b0151965060808b01519550620011fd60a08c016200119d565b94506200120d60c08c016200119d565b93506200121d60e08c016200119d565b92506200122e6101008c016200119d565b91506200123f6101208c016200119d565b90509295989b9194979a5092959850565b60008160001904831182151516156200126d576200126d62000f68565b500290565b6000826200129057634e487b7160e01b600052601260045260246000fd5b500490565b613f9c80620012a56000396000f3fe608060405234801561001057600080fd5b50600436106104075760003560e01c806372c95e5611610220578063b8b63adc11610130578063d547741f116100b8578063ecf173ff11610087578063ecf173ff1461089c578063f37ae328146108a5578063f4852a81146108b8578063fb355494146108cb578063fbfa77cf146108de57600080fd5b8063d547741f1461085a578063e46257d21461086d578063ec90b12214610880578063ec921dc11461089357600080fd5b8063cb7faf19116100ff578063cb7faf191461081a578063cc32d1761461082d578063d0e30db014610836578063d2f129051461083e578063d32b96041461084757600080fd5b8063b8b63adc146107e2578063bc063e1a146107f5578063c191464e146107fe578063ca15c8731461080757600080fd5b806389a30271116101b357806391d148541161018257806391d148541461078c578063920f5c841461079f5780639cfdede3146107b2578063a217fddf146107c7578063abdcadbe146107cf57600080fd5b806389a30271146107425780638cf558821461075d5780639010d07c1461077057806390321e1a1461078357600080fd5b80637f51bb1f116101ef5780637f51bb1f146106ed5780638456cb5914610700578063862a179e146107085780638888f9f61461072f57600080fd5b806372c95e56146106b35780637535d246146106bc5780637c9c3472146106c45780637e0bce10146106d257600080fd5b8063398d4e1a1161031b5780634b73de96116102ae57806363a8910d1161027d57806363a8910d146106435780636c9010d8146106565780637002783914610669578063722713f714610684578063724c184c1461068c57600080fd5b80634b73de96146105ff578063526e10801461061c5780635c975abb1461062557806361d027b31461063057600080fd5b80634234214c116102ea5780634234214c146105d35780634641257d146105e65780634700d305146105ee5780634870dd9a146105f657600080fd5b8063398d4e1a146105945780633a12c6da146105a75780633a6d2652146105b05780633f4ba83a146105cb57600080fd5b80632257a7381161039e5780632d6f4baa1161036d5780632d6f4baa1461053e5780632e1a7d4d146105465780632e2a25971461055b5780632f2ff15d1461056e57806336568abe1461058157600080fd5b80632257a738146104d8578063248a9ca3146104e15780632a0acc6a146105045780632ac081151461052b57600080fd5b806316d3bfbb116103da57806316d3bfbb146104905780631df4ccfc146104a95780631f1fcd51146104b257806322429085146104c557600080fd5b806301ffc9a71461040c5780630542975c146104345780630a399d2c1461046257806311b2e10e14610475575b600080fd5b61041f61041a3660046132fd565b6108f1565b60405190151581526020015b60405180910390f35b73a97684ead0e402dc232d5a977953df7ecbab3cdb5b6040516001600160a01b03909116815260200161042b565b61044a610470366004613327565b61091c565b61044a73a97684ead0e402dc232d5a977953df7ecbab3cdb81565b61049b6301e1338081565b60405190815260200161042b565b61049b600a5481565b600f5461044a906001600160a01b031681565b61041f6104d3366004613340565b610946565b61049b60055481565b61049b6104ef366004613327565b60009081526020819052604090206001015490565b61049b7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec4281565b600e5461044a906001600160a01b031681565b60035461049b565b610559610554366004613327565b6109d2565b005b61044a610569366004613327565b610a13565b61055961057c366004613381565b610a23565b61055961058f366004613381565b610a4e565b61044a6105a2366004613327565b610ad1565b61049b60115481565b61044a73929ec64c34a17401f460460d4b9390518e5b473e81565b610559610ae1565b6105596105e13660046133b1565b610b1c565b61049b610b83565b610559610cd8565b61049b61271081565b610607610d11565b6040805192835260208301919091520161042b565b61049b600d5481565b60025460ff1661041f565b60075461044a906001600160a01b031681565b610559610651366004613327565b610dae565b6105596106643660046133b1565b610de2565b61044a73a132dab612db5cb9fc9ac426a0cc215a3423f9c981565b61049b610e15565b61049b7f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe881565b61049b60045481565b61044a610eb2565b61044a6042602160991b0181565b61044a7369fa688f1dc47d4b5d8029d5a35fb7a54831065481565b61041f6106fb3660046133d3565b610f2f565b610559610f60565b61049b7f71a9859d7dd21b24504a6f306077ffc2d510b4d4b61128e931fe937441ad183681565b60095461044a906001600160a01b031681565b61044a737f5c764cbc14f9669b88837ca1490cca17c3160781565b61049b61076b3660046133b1565b610f91565b61044a61077e3660046133b1565b6110c4565b61049b600b5481565b61041f61079a366004613381565b6110dc565b61041f6107ad36600461343c565b611105565b61049b600080516020613f4783398151915281565b61049b600081565b6105596107dd366004613327565b61121c565b6105596107f03660046135d5565b61123c565b61049b6103e881565b61049b60135481565b61049b610815366004613327565b611328565b610559610828366004613669565b61133f565b61049b600c5481565b610559611435565b61049b60125481565b610559610855366004613327565b611460565b610559610868366004613381565b6114b5565b61055961087b3660046133d3565b6114db565b61055961088e366004613327565b611546565b61049b60105481565b61049b61138881565b6106076108b3366004613327565b611562565b61049b6108c6366004613327565b611590565b6105596108d9366004613327565b611624565b60085461044a906001600160a01b031681565b60006001600160e01b03198216635a05180f60e01b14806109165750610916826116dd565b92915050565b6015818154811061092c57600080fd5b6000918252602090912001546001600160a01b0316905081565b600061095181611712565b61271061095e84866136c1565b1461096857600080fd5b61138882111561097757600080fd5b600b849055600c839055600d82905560408051858152602081018590529081018390527fcf8a1e1d5f09cf3c97dbb653cd9a4d7aace9292fbc1bb8211febf2d400febbdd9060600160405180910390a15060015b9392505050565b6008546001600160a01b031633146109e957600080fd5b806109f357600080fd5b6109fb610e15565b811115610a0757600080fd5b610a108161184a565b50565b6017818154811061092c57600080fd5b600082815260208190526040902060010154610a3f813361197e565b610a4983836119e2565b505050565b6001600160a01b0381163314610ac35760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610acd8282611a04565b5050565b6016818154811061092c57600080fd5b610b0a7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42611712565b610b12611a26565b610b1a611435565b565b610b33600080516020613f47833981519152611712565b60c8821115610b785760405162461bcd60e51b8152602060048201526011602482015270696e76616c696420736c6970706167652160781b6044820152606401610aba565b601391909155601255565b6000610b9160025460ff1690565b15610bae5760405162461bcd60e51b8152600401610aba906136d9565b610bb6611ab9565b905060045460036001600380549050610bcf9190613703565b81548110610bdf57610bdf61371a565b906000526020600020906002020160000154610bfb91906136c1565b4210610ca6576040805180820182524281526008548251631df1ee3f60e21b815292516003936020808501936001600160a01b0316926377c7b8fc9260048082019392918290030181865afa158015610c58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7c9190613730565b90528154600181810184556000938452602093849020835160029093020191825592909101519101555b4260055560405133907f577a37fdb49a88d66684922c6f913df5239b4f214b2b97c53ef8e3bbb2034cb590600090a290565b610d017f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe8611712565b610d09611b5a565b610b1a610f60565b600f546040516328dd2d0160e01b81526001600160a01b03909116600482015230602482015260009081907369fa688f1dc47d4b5d8029d5a35fb7a548310654906328dd2d019060440161012060405180830381865afa158015610d79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9d919061375e565b509699949850939650505050505050565b610dc5600080516020613f47833981519152611712565b600854600f54610a10916001600160a01b03918216911683611b8a565b610e0b7f71a9859d7dd21b24504a6f306077ffc2d510b4d4b61128e931fe937441ad1836611712565b610acd8282611bed565b6000806000610e22610d11565b90925090506000610e338284613703565b600f546040516370a0823160e01b81523060048201529192506001600160a01b0316906370a0823190602401602060405180830381865afa158015610e7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea09190613730565b610eaa90826136c1565b935050505090565b600073a97684ead0e402dc232d5a977953df7ecbab3cdb6001600160a01b031663026b1d5f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2a91906137e1565b905090565b6000610f3a81611712565b50600780546001600160a01b0319166001600160a01b0392909216919091179055600190565b610f897f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe8611712565b610b1a611e36565b60008060038481548110610fa757610fa761371a565b90600052602060002090600202019050600060038481548110610fcc57610fcc61371a565b90600052602060002090600202019050600060019050826001015482600101541015610ff6575060005b6000811561101957836001015483600101546110129190613703565b9050611030565b8260010154846001015461102d9190613703565b90505b600184015460009061104a83670de0b6b3a76400006137fe565b6110549190613833565b855485549192506000916110689190613703565b905060008161107b6301e13380856137fe565b6110859190613833565b9050611097655af3107a400082613833565b905084156110ad57965061091695505050505050565b6110b681613847565b9a9950505050505050505050565b60008281526001602052604081206109cb9083611e8e565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b600061110f610eb2565b6001600160a01b0316336001600160a01b0316146111685760405162461bcd60e51b815260206004820152601660248201527518d85b1b195c88084f481b195b991a5b99c81c1bdbdb60521b6044820152606401610aba565b6001600160a01b03841630146111ad5760405162461bcd60e51b815260206004820152600a60248201526910b4b734ba34b0ba37b960b11b6044820152606401610aba565b6001601454146111ff5760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420666c6173684c6f616e5374617475730000000000000000006044820152606401610aba565b600060145561120c611e9a565b5060019998505050505050505050565b611233600080516020613f47833981519152611712565b610a1081611faa565b611253600080516020613f47833981519152611712565b6042602160991b016001600160a01b0316816000815181106112775761127761371a565b60200260200101516001600160a01b03161480156112d25750600f5481516001600160a01b039091169082906112af90600190613703565b815181106112bf576112bf61371a565b60200260200101516001600160a01b0316145b6113155760405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840dee0a8deaec2dce8a0c2e8d60631b6044820152606401610aba565b8051610acd906017906020840190613230565b6000818152600160205260408120610916906120d5565b611356600080516020613f47833981519152611712565b6042602160991b01828260008161136f5761136f61371a565b905060200201602081019061138491906133d3565b6001600160a01b03161480156113e65750737f5c764cbc14f9669b88837ca1490cca17c3160782826113b7600182613703565b8181106113c6576113c661371a565b90506020020160208101906113db91906133d3565b6001600160a01b0316145b6114295760405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840dee0a8deaae6c8c6a0c2e8d60631b6044820152606401610aba565b610a4960168383613295565b60025460ff16156114585760405162461bcd60e51b8152600401610aba906136d9565b610b1a6120df565b61146a6000611712565b6103e881111561147957600080fd5b600a8190556040518181527f2e59d502792bca3d730c472cd3acfbc16d0f9fe6ce0cddbdf0f80830251dfaca906020015b60405180910390a150565b6000828152602081905260409020600101546114d1813361197e565b610a498383611a04565b6114e56000611712565b6001600160a01b0381166114f857600080fd5b600980546001600160a01b0319166001600160a01b0383169081179091556040519081527fa11c447ac90d9534769dc85d422963d67c1d8d899de887301417cedf4dec738d906020016114aa565b61155d600080516020613f47833981519152611712565b600455565b6003818154811061157257600080fd5b60009182526020909120600290910201805460019091015490915082565b600354600090600211156115a357600080fd5b600080600060016003805490506115ba9190613703565b90505b6000811180156115cc57508482125b15611611576115e56115df600183613703565b82610f91565b6115ef9084613864565b9250816115fb816138a5565b9250508080611609906138c5565b9150506115bd565b5061161c81836138dc565b949350505050565b61163b600080516020613f47833981519152611712565b610a1081612147565b61164e82826110dc565b610acd576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556116843390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60006109cb836001600160a01b03841661227c565b60006001600160e01b03198216637965db0b60e01b148061091657506301ffc9a760e01b6001600160e01b0319831614610916565b6006546000805b828110156117b057600681815481106117345761173461371a565b906000526020600020015484141561174e578091506117b0565b611759600184613703565b81141561179e5760405162461bcd60e51b8152602060048201526013602482015272756e617574686f72697a65642061636365737360681b6044820152606401610aba565b806117a88161390a565b915050611719565b5060005b818111611844576117e2600682815481106117d1576117d161371a565b9060005260206000200154336110dc565b156117ec57611844565b818114156118325760405162461bcd60e51b8152602060048201526013602482015272756e617574686f72697a65642061636365737360681b6044820152606401610aba565b8061183c8161390a565b9150506117b4565b50505050565b600f546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611893573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b79190613730565b90508082116118dd57600854600f54610acd916001600160a01b03918216911684611b8a565b60006118e98284613703565b90506000806118f6610d11565b90925090506119058383613703565b915060008261191557600061192c565b82611922612710846137fe565b61192c9190613833565b90506011548111156119505761194184612147565b61194b84876122cb565b611976565b60105481101561196c5761196484876122cb565b61194b6123fc565b61197684876122cb565b505050505050565b61198882826110dc565b610acd576119a0816001600160a01b0316601461246c565b6119ab83602061246c565b6040516020016119bc92919061394a565b60408051601f198184030181529082905262461bcd60e51b8252610aba916004016139bf565b6119ec8282611644565b6000828152600160205260409020610a4990826116c8565b611a0e8282612608565b6000828152600160205260409020610a49908261266d565b60025460ff16611a6f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610aba565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b604051635fc87b1d60e11b815260009073929ec64c34a17401f460460d4b9390518e5b473e9063bf90f63a90611af4906015906004016139f2565b6000604051808303816000875af1158015611b13573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b3b9190810190613aa8565b5050611b45612682565b9050611b4f61292e565b611b57611435565b90565b600080611b65610d11565b90925090506000611b768284613703565b9050611b8181612147565b610a4981611faa565b6040516001600160a01b038316602482015260448101829052610a4990849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612a03565b6000611bf7610eb2565b60405163eddf1b7960e01b81523060048201526001600160a01b03919091169063eddf1b7990602401602060405180830381865afa158015611c3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c619190613730565b905060008115611cf4576000611c75610eb2565b604051636c6f6ae160e01b815260ff851660048201526001600160a01b039190911690636c6f6ae190602401600060405180830381865afa158015611cbe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ce69190810190613b7f565b5161ffff169150611d829050565b600f54604051633e15014160e01b81526001600160a01b0390911660048201527369fa688f1dc47d4b5d8029d5a35fb7a54831065490633e1501419060240161014060405180830381865afa158015611d51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d759190613c86565b5096985050505050505050505b612710611d91612648836137fe565b611d9b9190613833565b831115611ddc5760405162461bcd60e51b815260206004820152600f60248201526e6d61784c7476206e6f74207361666560881b6044820152606401610aba565b82841115611e2c5760405162461bcd60e51b815260206004820152601860248201527f7461726765744c7476206d757374203c3d206d61784c747600000000000000006044820152606401610aba565b5050601155601055565b60025460ff1615611e595760405162461bcd60e51b8152600401610aba906136d9565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611a9c3390565b60006109cb8383612ad5565b600f546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611ee3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f079190613730565b90508015610a1057611f2d611f1a610eb2565b600f546001600160a01b03169083612aff565b611f35610eb2565b600f5460405163617ba03760e01b81526001600160a01b039182166004820152602481018490523060448201526000606482015291169063617ba03790608401600060405180830381600087803b158015611f8f57600080fd5b505af1158015611fa3573d6000803e3d6000fd5b5050505050565b600080611fb5610d11565b91509150600060115460001415611fcd576000611fe6565b601154611fdc612710846137fe565b611fe69190613833565b90508083116120375760405162461bcd60e51b815260206004820152601860248201527f63616e277420776974686472617720616e797468696e672100000000000000006044820152606401610aba565b60006120438285613703565b905061204f8582612bb1565b9450612059610eb2565b600f54604051631a4ca37b60e21b81526001600160a01b039182166004820152602481018890523060448201529116906369328dec906064016020604051808303816000875af11580156120b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119769190613730565b6000610916825490565b6120e7611e9a565b6000806120f2610d11565b915091506000826000141561210857600061211f565b82612115612710846137fe565b61211f9190613833565b905060115481111561213557610a496000612147565b601054811015610a4957610a496123fc565b600080612152610d11565b909250905060006121638284613703565b9050808411156121a65760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a5908185b5bdd5b9d60921b6044820152606401610aba565b60006121b28583613703565b905060006010546127106121c69190613703565b6010546121d390846137fe565b6121dd9190613833565b905060006121eb8286613703565b90506121f5610eb2565b600f54604051630b6b65f560e21b81526001600160a01b0391821660048201526024810184905260026044820152911690632dad97d4906064016020604051808303816000875af115801561224e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122729190613730565b5050505050505050565b60008181526001830160205260408120546122c357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610916565b506000610916565b6122d482611faa565b600f546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561231d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123419190613730565b9050818110156123cf5761271060135461271061235e9190613703565b61236890846137fe565b6123729190613833565b8110156123cf5760405162461bcd60e51b815260206004820152602560248201527f77697468647261773a206f75747369646520736c69707061676520746f6c6572604482015264616e63652160d81b6064820152608401610aba565b600854610a49906001600160a01b03166123e98385612bb1565b600f546001600160a01b03169190611b8a565b600080612407610d11565b909250905060006124188284613703565b9050600060105461271061242c9190613703565b60105461243990846137fe565b6124439190613833565b90506012548361245391906136c1565b811115611844576118446124678483613703565b612bc7565b6060600061247b8360026137fe565b6124869060026136c1565b67ffffffffffffffff81111561249e5761249e613541565b6040519080825280601f01601f1916602001820160405280156124c8576020820181803683370190505b509050600360fc1b816000815181106124e3576124e361371a565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106125125761251261371a565b60200101906001600160f81b031916908160001a90535060006125368460026137fe565b6125419060016136c1565b90505b60018111156125b9576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106125755761257561371a565b1a60f81b82828151811061258b5761258b61371a565b60200101906001600160f81b031916908160001a90535060049490941c936125b2816138c5565b9050612544565b5083156109cb5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610aba565b61261282826110dc565b15610acd576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60006109cb836001600160a01b038416612d5d565b600a546040516370a0823160e01b8152306004820152600091829161271091906042602160991b01906370a0823190602401602060405180830381865afa1580156126d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f59190613730565b6126ff91906137fe565b6127099190613833565b90508061271857600091505090565b6040516370a0823160e01b8152306004820152737f5c764cbc14f9669b88837ca1490cca17c316079060009082906370a0823190602401602060405180830381865afa15801561276c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127909190613730565b90506127f660168054806020026020016040519081016040528092919081815260200182805480156127eb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127cd575b505050505084612e50565b6040516370a0823160e01b815230600482015260009082906001600160a01b038516906370a0823190602401602060405180830381865afa15801561283f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128639190613730565b61286d9190613703565b9050801561292757612710600b548261288691906137fe565b6128909190613833565b94506000612710600c54836128a591906137fe565b6128af9190613833565b90506000612710600d54836128c491906137fe565b6128ce9190613833565b90506128da8183613703565b91506128f06001600160a01b0386163389611b8a565b60075461290a906001600160a01b03878116911684611b8a565b600954612924906001600160a01b03878116911683611b8a565b50505b5050505090565b6040516370a0823160e01b81523060048201526000906042602160991b01906370a0823190602401602060405180830381865afa158015612973573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129979190613730565b90508015610a1057610a1060178054806020026020016040519081016040528092919081815260200182805480156129f857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116129da575b505050505082612e50565b6000612a58826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131259092919063ffffffff16565b805190915015610a495780806020019051810190612a769190613d1d565b610a495760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610aba565b6000826000018281548110612aec57612aec61371a565b9060005260206000200154905092915050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015612b50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b749190613730565b612b7e91906136c1565b6040516001600160a01b03851660248201526044810182905290915061184490859063095ea7b360e01b90606401611bb6565b6000818310612bc057816109cb565b5090919050565b80612c0a5760405162461bcd60e51b8152602060048201526013602482015272464c3a20696e76616c696420616d6f756e742160681b6044820152606401610aba565b604080516001808252818301909252600091602080830190803683375050600f5482519293506001600160a01b031691839150600090612c4c57612c4c61371a565b6001600160a01b0392909216602092830291909101909101526040805160018082528183019092526000918160200160208202803683370190505090508281600081518110612c9d57612c9d61371a565b6020908102919091010152604080516001808252818301909252600091816020016020820280368337019050509050600281600081518110612ce157612ce161371a565b60209081029190910101526001601455612cf9610eb2565b6001600160a01b031663ab9c4b5d308585853060006040518763ffffffff1660e01b8152600401612d2f96959493929190613d73565b600060405180830381600087803b158015612d4957600080fd5b505af1158015612272573d6000803e3d6000fd5b60008181526001830160205260408120548015612e46576000612d81600183613703565b8554909150600090612d9590600190613703565b9050818114612dfa576000866000018281548110612db557612db561371a565b9060005260206000200154905080876000018481548110612dd857612dd861371a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612e0b57612e0b613e1e565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610916565b6000915050610916565b815173a132dab612db5cb9fc9ac426a0cc215a3423f9c990600090612e7790600190613703565b67ffffffffffffffff811115612e8f57612e8f613541565b604051908082528060200260200182016040528015612eda57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612ead5790505b50905082600080805b845181101561305c57856001600160a01b0316635e1e6325858a8481518110612f0e57612f0e61371a565b60200260200101518b856001612f2491906136c1565b81518110612f3457612f3461371a565b60200260200101516040518463ffffffff1660e01b8152600401612f74939291909283526001600160a01b03918216602084015216604082015260600190565b6040805180830381865afa158015612f90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fb49190613e34565b80935081945050506040518060600160405280898381518110612fd957612fd961371a565b60200260200101516001600160a01b0316815260200189836001612ffd91906136c1565b8151811061300d5761300d61371a565b60200260200101516001600160a01b0316815260200183151581525085828151811061303b5761303b61371a565b602002602001018190525082935080806130549061390a565b915050612ee3565b506130a973a132dab612db5cb9fc9ac426a0cc215a3423f9c987896000815181106130895761308961371a565b60200260200101516001600160a01b0316612aff9092919063ffffffff16565b604051631e82ecdb60e31b81526001600160a01b0386169063f41766d8906130de908990600090899030904290600401613e60565b6000604051808303816000875af11580156130fd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122729190810190613ef5565b606061161c848460008585843b61317e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610aba565b600080866001600160a01b0316858760405161319a9190613f2a565b60006040518083038185875af1925050503d80600081146131d7576040519150601f19603f3d011682016040523d82523d6000602084013e6131dc565b606091505b50915091506131ec8282866131f7565b979650505050505050565b606083156132065750816109cb565b8251156132165782518084602001fd5b8160405162461bcd60e51b8152600401610aba91906139bf565b828054828255906000526020600020908101928215613285579160200282015b8281111561328557825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613250565b506132919291506132e8565b5090565b828054828255906000526020600020908101928215613285579160200282015b828111156132855781546001600160a01b0319166001600160a01b038435161782556020909201916001909101906132b5565b5b8082111561329157600081556001016132e9565b60006020828403121561330f57600080fd5b81356001600160e01b0319811681146109cb57600080fd5b60006020828403121561333957600080fd5b5035919050565b60008060006060848603121561335557600080fd5b505081359360208301359350604090920135919050565b6001600160a01b0381168114610a1057600080fd5b6000806040838503121561339457600080fd5b8235915060208301356133a68161336c565b809150509250929050565b600080604083850312156133c457600080fd5b50508035926020909101359150565b6000602082840312156133e557600080fd5b81356109cb8161336c565b60008083601f84011261340257600080fd5b50813567ffffffffffffffff81111561341a57600080fd5b6020830191508360208260051b850101111561343557600080fd5b9250929050565b600080600080600080600080600060a08a8c03121561345a57600080fd5b893567ffffffffffffffff8082111561347257600080fd5b61347e8d838e016133f0565b909b50995060208c013591508082111561349757600080fd5b6134a38d838e016133f0565b909950975060408c01359150808211156134bc57600080fd5b6134c88d838e016133f0565b909750955060608c013591506134dd8261336c565b90935060808b013590808211156134f357600080fd5b818c0191508c601f83011261350757600080fd5b81358181111561351657600080fd5b8d602082850101111561352857600080fd5b6020830194508093505050509295985092959850929598565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171561357a5761357a613541565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156135a9576135a9613541565b604052919050565b600067ffffffffffffffff8211156135cb576135cb613541565b5060051b60200190565b600060208083850312156135e857600080fd5b823567ffffffffffffffff8111156135ff57600080fd5b8301601f8101851361361057600080fd5b803561362361361e826135b1565b613580565b81815260059190911b8201830190838101908783111561364257600080fd5b928401925b828410156131ec57833561365a8161336c565b82529284019290840190613647565b6000806020838503121561367c57600080fd5b823567ffffffffffffffff81111561369357600080fd5b61369f858286016133f0565b90969095509350505050565b634e487b7160e01b600052601160045260246000fd5b600082198211156136d4576136d46136ab565b500190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b600082821015613715576137156136ab565b500390565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561374257600080fd5b5051919050565b8051801515811461375957600080fd5b919050565b60008060008060008060008060006101208a8c03121561377d57600080fd5b8951985060208a0151975060408a0151965060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a015164ffffffffff811681146137c357600080fd5b91506137d26101008b01613749565b90509295985092959850929598565b6000602082840312156137f357600080fd5b81516109cb8161336c565b6000816000190483118215151615613818576138186136ab565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826138425761384261381d565b500490565b6000600160ff1b82141561385d5761385d6136ab565b5060000390565b600080821280156001600160ff1b0384900385131615613886576138866136ab565b600160ff1b839003841281161561389f5761389f6136ab565b50500190565b60006001600160ff1b038214156138be576138be6136ab565b5060010190565b6000816138d4576138d46136ab565b506000190190565b6000826138eb576138eb61381d565b600160ff1b821460001984141615613905576139056136ab565b500590565b60006000198214156138be576138be6136ab565b60005b83811015613939578181015183820152602001613921565b838111156118445750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161398281601785016020880161391e565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516139b381602884016020880161391e565b01602801949350505050565b60208152600082518060208401526139de81604085016020870161391e565b601f01601f19169190910160400192915050565b6020808252825482820181905260008481528281209092916040850190845b81811015613a365783546001600160a01b031683526001938401939285019201613a11565b50909695505050505050565b600082601f830112613a5357600080fd5b81516020613a6361361e836135b1565b82815260059290921b84018101918181019086841115613a8257600080fd5b8286015b84811015613a9d5780518352918301918301613a86565b509695505050505050565b60008060408385031215613abb57600080fd5b825167ffffffffffffffff80821115613ad357600080fd5b818501915085601f830112613ae757600080fd5b81516020613af761361e836135b1565b82815260059290921b84018101918181019089841115613b1657600080fd5b948201945b83861015613b3d578551613b2e8161336c565b82529482019490820190613b1b565b91880151919650909350505080821115613b5657600080fd5b50613b6385828601613a42565b9150509250929050565b805161ffff8116811461375957600080fd5b60006020808385031215613b9257600080fd5b825167ffffffffffffffff80821115613baa57600080fd5b9084019060a08287031215613bbe57600080fd5b613bc6613557565b613bcf83613b6d565b8152613bdc848401613b6d565b84820152613bec60408401613b6d565b60408201526060830151613bff8161336c565b6060820152608083015182811115613c1657600080fd5b80840193505086601f840112613c2b57600080fd5b825182811115613c3d57613c3d613541565b613c4f601f8201601f19168601613580565b92508083528785828601011115613c6557600080fd5b613c748186850187870161391e565b50608081019190915295945050505050565b6000806000806000806000806000806101408b8d031215613ca657600080fd5b8a51995060208b0151985060408b0151975060608b0151965060808b01519550613cd260a08c01613749565b9450613ce060c08c01613749565b9350613cee60e08c01613749565b9250613cfd6101008c01613749565b9150613d0c6101208c01613749565b90509295989b9194979a5092959850565b600060208284031215613d2f57600080fd5b6109cb82613749565b600081518084526020808501945080840160005b83811015613d6857815187529582019590820190600101613d4c565b509495945050505050565b6001600160a01b03878116825260e06020808401829052885191840182905260009289820192909190610100860190855b81811015613dc2578551851683529483019491830191600101613da4565b50508581036040870152613dd6818b613d38565b93505050508281036060840152613ded8187613d38565b6001600160a01b038616608085015283810360a08501526000815261ffff851660c085015260200191506131ec9050565b634e487b7160e01b600052603160045260246000fd5b60008060408385031215613e4757600080fd5b82519150613e5760208401613749565b90509250929050565b600060a0820187835260208781850152604060a08186015282885180855260c087019150838a01945060005b81811015613ec957855180516001600160a01b03908116855286820151168685015284015115158484015294840194606090920191600101613e8c565b50506001600160a01b03881660608701529350613ee592505050565b8260808301529695505050505050565b600060208284031215613f0757600080fd5b815167ffffffffffffffff811115613f1e57600080fd5b61161c84828501613a42565b60008251613f3c81846020870161391e565b919091019291505056feb17d0a42cc710456bf9c3efb785dcd0cb93a0ac358113307b5c64b285b516b5ca2646970667358221220981d059dfaa6c075b82a22a796b5a234884ad2a520dc2a196ffd10dfeecf69cb64736f6c634300080b0033df8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42b17d0a42cc710456bf9c3efb785dcd0cb93a0ac358113307b5c64b285b516b5c000000000000000000000000df2d2c477078d2cd563648abbb913da3db247c00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000e50fa9b3c56ffb159cb0fca61f5c9d750e8128c800000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000001e140000000000000000000000000000000000000000000000000000000000001e7800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b0000000000000000000000002b394b228908fb7dacaff5f340f1b442a39b056c00000000000000000000000000000000000000000000000000000000000000030000000000000000000000001e71aee6081f62053123140aacc7a06021d7734800000000000000000000000081876677843d00a7d792e1617459ac2e932025760000000000000000000000001a20d7a31e5b3bc5f02c8a146ef6f394502a10c400000000000000000000000000000000000000000000000000000000000000030000000000000000000000003aa60c3ae4b94515fa1fd0ffee77d02b6a0609f3000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b000000000000000000000000b0c9d5851def8a2aac4a23031ca2610f8c3483f9000000000000000000000000000000000000000000000000000000000000000200000000000000000000000042000000000000000000000000000000000000420000000000000000000000004200000000000000000000000000000000000006

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106104075760003560e01c806372c95e5611610220578063b8b63adc11610130578063d547741f116100b8578063ecf173ff11610087578063ecf173ff1461089c578063f37ae328146108a5578063f4852a81146108b8578063fb355494146108cb578063fbfa77cf146108de57600080fd5b8063d547741f1461085a578063e46257d21461086d578063ec90b12214610880578063ec921dc11461089357600080fd5b8063cb7faf19116100ff578063cb7faf191461081a578063cc32d1761461082d578063d0e30db014610836578063d2f129051461083e578063d32b96041461084757600080fd5b8063b8b63adc146107e2578063bc063e1a146107f5578063c191464e146107fe578063ca15c8731461080757600080fd5b806389a30271116101b357806391d148541161018257806391d148541461078c578063920f5c841461079f5780639cfdede3146107b2578063a217fddf146107c7578063abdcadbe146107cf57600080fd5b806389a30271146107425780638cf558821461075d5780639010d07c1461077057806390321e1a1461078357600080fd5b80637f51bb1f116101ef5780637f51bb1f146106ed5780638456cb5914610700578063862a179e146107085780638888f9f61461072f57600080fd5b806372c95e56146106b35780637535d246146106bc5780637c9c3472146106c45780637e0bce10146106d257600080fd5b8063398d4e1a1161031b5780634b73de96116102ae57806363a8910d1161027d57806363a8910d146106435780636c9010d8146106565780637002783914610669578063722713f714610684578063724c184c1461068c57600080fd5b80634b73de96146105ff578063526e10801461061c5780635c975abb1461062557806361d027b31461063057600080fd5b80634234214c116102ea5780634234214c146105d35780634641257d146105e65780634700d305146105ee5780634870dd9a146105f657600080fd5b8063398d4e1a146105945780633a12c6da146105a75780633a6d2652146105b05780633f4ba83a146105cb57600080fd5b80632257a7381161039e5780632d6f4baa1161036d5780632d6f4baa1461053e5780632e1a7d4d146105465780632e2a25971461055b5780632f2ff15d1461056e57806336568abe1461058157600080fd5b80632257a738146104d8578063248a9ca3146104e15780632a0acc6a146105045780632ac081151461052b57600080fd5b806316d3bfbb116103da57806316d3bfbb146104905780631df4ccfc146104a95780631f1fcd51146104b257806322429085146104c557600080fd5b806301ffc9a71461040c5780630542975c146104345780630a399d2c1461046257806311b2e10e14610475575b600080fd5b61041f61041a3660046132fd565b6108f1565b60405190151581526020015b60405180910390f35b73a97684ead0e402dc232d5a977953df7ecbab3cdb5b6040516001600160a01b03909116815260200161042b565b61044a610470366004613327565b61091c565b61044a73a97684ead0e402dc232d5a977953df7ecbab3cdb81565b61049b6301e1338081565b60405190815260200161042b565b61049b600a5481565b600f5461044a906001600160a01b031681565b61041f6104d3366004613340565b610946565b61049b60055481565b61049b6104ef366004613327565b60009081526020819052604090206001015490565b61049b7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec4281565b600e5461044a906001600160a01b031681565b60035461049b565b610559610554366004613327565b6109d2565b005b61044a610569366004613327565b610a13565b61055961057c366004613381565b610a23565b61055961058f366004613381565b610a4e565b61044a6105a2366004613327565b610ad1565b61049b60115481565b61044a73929ec64c34a17401f460460d4b9390518e5b473e81565b610559610ae1565b6105596105e13660046133b1565b610b1c565b61049b610b83565b610559610cd8565b61049b61271081565b610607610d11565b6040805192835260208301919091520161042b565b61049b600d5481565b60025460ff1661041f565b60075461044a906001600160a01b031681565b610559610651366004613327565b610dae565b6105596106643660046133b1565b610de2565b61044a73a132dab612db5cb9fc9ac426a0cc215a3423f9c981565b61049b610e15565b61049b7f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe881565b61049b60045481565b61044a610eb2565b61044a6042602160991b0181565b61044a7369fa688f1dc47d4b5d8029d5a35fb7a54831065481565b61041f6106fb3660046133d3565b610f2f565b610559610f60565b61049b7f71a9859d7dd21b24504a6f306077ffc2d510b4d4b61128e931fe937441ad183681565b60095461044a906001600160a01b031681565b61044a737f5c764cbc14f9669b88837ca1490cca17c3160781565b61049b61076b3660046133b1565b610f91565b61044a61077e3660046133b1565b6110c4565b61049b600b5481565b61041f61079a366004613381565b6110dc565b61041f6107ad36600461343c565b611105565b61049b600080516020613f4783398151915281565b61049b600081565b6105596107dd366004613327565b61121c565b6105596107f03660046135d5565b61123c565b61049b6103e881565b61049b60135481565b61049b610815366004613327565b611328565b610559610828366004613669565b61133f565b61049b600c5481565b610559611435565b61049b60125481565b610559610855366004613327565b611460565b610559610868366004613381565b6114b5565b61055961087b3660046133d3565b6114db565b61055961088e366004613327565b611546565b61049b60105481565b61049b61138881565b6106076108b3366004613327565b611562565b61049b6108c6366004613327565b611590565b6105596108d9366004613327565b611624565b60085461044a906001600160a01b031681565b60006001600160e01b03198216635a05180f60e01b14806109165750610916826116dd565b92915050565b6015818154811061092c57600080fd5b6000918252602090912001546001600160a01b0316905081565b600061095181611712565b61271061095e84866136c1565b1461096857600080fd5b61138882111561097757600080fd5b600b849055600c839055600d82905560408051858152602081018590529081018390527fcf8a1e1d5f09cf3c97dbb653cd9a4d7aace9292fbc1bb8211febf2d400febbdd9060600160405180910390a15060015b9392505050565b6008546001600160a01b031633146109e957600080fd5b806109f357600080fd5b6109fb610e15565b811115610a0757600080fd5b610a108161184a565b50565b6017818154811061092c57600080fd5b600082815260208190526040902060010154610a3f813361197e565b610a4983836119e2565b505050565b6001600160a01b0381163314610ac35760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b610acd8282611a04565b5050565b6016818154811061092c57600080fd5b610b0a7fdf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec42611712565b610b12611a26565b610b1a611435565b565b610b33600080516020613f47833981519152611712565b60c8821115610b785760405162461bcd60e51b8152602060048201526011602482015270696e76616c696420736c6970706167652160781b6044820152606401610aba565b601391909155601255565b6000610b9160025460ff1690565b15610bae5760405162461bcd60e51b8152600401610aba906136d9565b610bb6611ab9565b905060045460036001600380549050610bcf9190613703565b81548110610bdf57610bdf61371a565b906000526020600020906002020160000154610bfb91906136c1565b4210610ca6576040805180820182524281526008548251631df1ee3f60e21b815292516003936020808501936001600160a01b0316926377c7b8fc9260048082019392918290030181865afa158015610c58573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c7c9190613730565b90528154600181810184556000938452602093849020835160029093020191825592909101519101555b4260055560405133907f577a37fdb49a88d66684922c6f913df5239b4f214b2b97c53ef8e3bbb2034cb590600090a290565b610d017f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe8611712565b610d09611b5a565b610b1a610f60565b600f546040516328dd2d0160e01b81526001600160a01b03909116600482015230602482015260009081907369fa688f1dc47d4b5d8029d5a35fb7a548310654906328dd2d019060440161012060405180830381865afa158015610d79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d9d919061375e565b509699949850939650505050505050565b610dc5600080516020613f47833981519152611712565b600854600f54610a10916001600160a01b03918216911683611b8a565b610e0b7f71a9859d7dd21b24504a6f306077ffc2d510b4d4b61128e931fe937441ad1836611712565b610acd8282611bed565b6000806000610e22610d11565b90925090506000610e338284613703565b600f546040516370a0823160e01b81523060048201529192506001600160a01b0316906370a0823190602401602060405180830381865afa158015610e7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ea09190613730565b610eaa90826136c1565b935050505090565b600073a97684ead0e402dc232d5a977953df7ecbab3cdb6001600160a01b031663026b1d5f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2a91906137e1565b905090565b6000610f3a81611712565b50600780546001600160a01b0319166001600160a01b0392909216919091179055600190565b610f897f8b5b16d04624687fcf0d0228f19993c9157c1ed07b41d8d430fd9100eb099fe8611712565b610b1a611e36565b60008060038481548110610fa757610fa761371a565b90600052602060002090600202019050600060038481548110610fcc57610fcc61371a565b90600052602060002090600202019050600060019050826001015482600101541015610ff6575060005b6000811561101957836001015483600101546110129190613703565b9050611030565b8260010154846001015461102d9190613703565b90505b600184015460009061104a83670de0b6b3a76400006137fe565b6110549190613833565b855485549192506000916110689190613703565b905060008161107b6301e13380856137fe565b6110859190613833565b9050611097655af3107a400082613833565b905084156110ad57965061091695505050505050565b6110b681613847565b9a9950505050505050505050565b60008281526001602052604081206109cb9083611e8e565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b600061110f610eb2565b6001600160a01b0316336001600160a01b0316146111685760405162461bcd60e51b815260206004820152601660248201527518d85b1b195c88084f481b195b991a5b99c81c1bdbdb60521b6044820152606401610aba565b6001600160a01b03841630146111ad5760405162461bcd60e51b815260206004820152600a60248201526910b4b734ba34b0ba37b960b11b6044820152606401610aba565b6001601454146111ff5760405162461bcd60e51b815260206004820152601760248201527f696e76616c696420666c6173684c6f616e5374617475730000000000000000006044820152606401610aba565b600060145561120c611e9a565b5060019998505050505050505050565b611233600080516020613f47833981519152611712565b610a1081611faa565b611253600080516020613f47833981519152611712565b6042602160991b016001600160a01b0316816000815181106112775761127761371a565b60200260200101516001600160a01b03161480156112d25750600f5481516001600160a01b039091169082906112af90600190613703565b815181106112bf576112bf61371a565b60200260200101516001600160a01b0316145b6113155760405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840dee0a8deaec2dce8a0c2e8d60631b6044820152606401610aba565b8051610acd906017906020840190613230565b6000818152600160205260408120610916906120d5565b611356600080516020613f47833981519152611712565b6042602160991b01828260008161136f5761136f61371a565b905060200201602081019061138491906133d3565b6001600160a01b03161480156113e65750737f5c764cbc14f9669b88837ca1490cca17c3160782826113b7600182613703565b8181106113c6576113c661371a565b90506020020160208101906113db91906133d3565b6001600160a01b0316145b6114295760405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840dee0a8deaae6c8c6a0c2e8d60631b6044820152606401610aba565b610a4960168383613295565b60025460ff16156114585760405162461bcd60e51b8152600401610aba906136d9565b610b1a6120df565b61146a6000611712565b6103e881111561147957600080fd5b600a8190556040518181527f2e59d502792bca3d730c472cd3acfbc16d0f9fe6ce0cddbdf0f80830251dfaca906020015b60405180910390a150565b6000828152602081905260409020600101546114d1813361197e565b610a498383611a04565b6114e56000611712565b6001600160a01b0381166114f857600080fd5b600980546001600160a01b0319166001600160a01b0383169081179091556040519081527fa11c447ac90d9534769dc85d422963d67c1d8d899de887301417cedf4dec738d906020016114aa565b61155d600080516020613f47833981519152611712565b600455565b6003818154811061157257600080fd5b60009182526020909120600290910201805460019091015490915082565b600354600090600211156115a357600080fd5b600080600060016003805490506115ba9190613703565b90505b6000811180156115cc57508482125b15611611576115e56115df600183613703565b82610f91565b6115ef9084613864565b9250816115fb816138a5565b9250508080611609906138c5565b9150506115bd565b5061161c81836138dc565b949350505050565b61163b600080516020613f47833981519152611712565b610a1081612147565b61164e82826110dc565b610acd576000828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556116843390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60006109cb836001600160a01b03841661227c565b60006001600160e01b03198216637965db0b60e01b148061091657506301ffc9a760e01b6001600160e01b0319831614610916565b6006546000805b828110156117b057600681815481106117345761173461371a565b906000526020600020015484141561174e578091506117b0565b611759600184613703565b81141561179e5760405162461bcd60e51b8152602060048201526013602482015272756e617574686f72697a65642061636365737360681b6044820152606401610aba565b806117a88161390a565b915050611719565b5060005b818111611844576117e2600682815481106117d1576117d161371a565b9060005260206000200154336110dc565b156117ec57611844565b818114156118325760405162461bcd60e51b8152602060048201526013602482015272756e617574686f72697a65642061636365737360681b6044820152606401610aba565b8061183c8161390a565b9150506117b4565b50505050565b600f546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611893573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b79190613730565b90508082116118dd57600854600f54610acd916001600160a01b03918216911684611b8a565b60006118e98284613703565b90506000806118f6610d11565b90925090506119058383613703565b915060008261191557600061192c565b82611922612710846137fe565b61192c9190613833565b90506011548111156119505761194184612147565b61194b84876122cb565b611976565b60105481101561196c5761196484876122cb565b61194b6123fc565b61197684876122cb565b505050505050565b61198882826110dc565b610acd576119a0816001600160a01b0316601461246c565b6119ab83602061246c565b6040516020016119bc92919061394a565b60408051601f198184030181529082905262461bcd60e51b8252610aba916004016139bf565b6119ec8282611644565b6000828152600160205260409020610a4990826116c8565b611a0e8282612608565b6000828152600160205260409020610a49908261266d565b60025460ff16611a6f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610aba565b6002805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b604051635fc87b1d60e11b815260009073929ec64c34a17401f460460d4b9390518e5b473e9063bf90f63a90611af4906015906004016139f2565b6000604051808303816000875af1158015611b13573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611b3b9190810190613aa8565b5050611b45612682565b9050611b4f61292e565b611b57611435565b90565b600080611b65610d11565b90925090506000611b768284613703565b9050611b8181612147565b610a4981611faa565b6040516001600160a01b038316602482015260448101829052610a4990849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612a03565b6000611bf7610eb2565b60405163eddf1b7960e01b81523060048201526001600160a01b03919091169063eddf1b7990602401602060405180830381865afa158015611c3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c619190613730565b905060008115611cf4576000611c75610eb2565b604051636c6f6ae160e01b815260ff851660048201526001600160a01b039190911690636c6f6ae190602401600060405180830381865afa158015611cbe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ce69190810190613b7f565b5161ffff169150611d829050565b600f54604051633e15014160e01b81526001600160a01b0390911660048201527369fa688f1dc47d4b5d8029d5a35fb7a54831065490633e1501419060240161014060405180830381865afa158015611d51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d759190613c86565b5096985050505050505050505b612710611d91612648836137fe565b611d9b9190613833565b831115611ddc5760405162461bcd60e51b815260206004820152600f60248201526e6d61784c7476206e6f74207361666560881b6044820152606401610aba565b82841115611e2c5760405162461bcd60e51b815260206004820152601860248201527f7461726765744c7476206d757374203c3d206d61784c747600000000000000006044820152606401610aba565b5050601155601055565b60025460ff1615611e595760405162461bcd60e51b8152600401610aba906136d9565b6002805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611a9c3390565b60006109cb8383612ad5565b600f546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015611ee3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f079190613730565b90508015610a1057611f2d611f1a610eb2565b600f546001600160a01b03169083612aff565b611f35610eb2565b600f5460405163617ba03760e01b81526001600160a01b039182166004820152602481018490523060448201526000606482015291169063617ba03790608401600060405180830381600087803b158015611f8f57600080fd5b505af1158015611fa3573d6000803e3d6000fd5b5050505050565b600080611fb5610d11565b91509150600060115460001415611fcd576000611fe6565b601154611fdc612710846137fe565b611fe69190613833565b90508083116120375760405162461bcd60e51b815260206004820152601860248201527f63616e277420776974686472617720616e797468696e672100000000000000006044820152606401610aba565b60006120438285613703565b905061204f8582612bb1565b9450612059610eb2565b600f54604051631a4ca37b60e21b81526001600160a01b039182166004820152602481018890523060448201529116906369328dec906064016020604051808303816000875af11580156120b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119769190613730565b6000610916825490565b6120e7611e9a565b6000806120f2610d11565b915091506000826000141561210857600061211f565b82612115612710846137fe565b61211f9190613833565b905060115481111561213557610a496000612147565b601054811015610a4957610a496123fc565b600080612152610d11565b909250905060006121638284613703565b9050808411156121a65760405162461bcd60e51b815260206004820152600e60248201526d1a5b9d985b1a5908185b5bdd5b9d60921b6044820152606401610aba565b60006121b28583613703565b905060006010546127106121c69190613703565b6010546121d390846137fe565b6121dd9190613833565b905060006121eb8286613703565b90506121f5610eb2565b600f54604051630b6b65f560e21b81526001600160a01b0391821660048201526024810184905260026044820152911690632dad97d4906064016020604051808303816000875af115801561224e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122729190613730565b5050505050505050565b60008181526001830160205260408120546122c357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610916565b506000610916565b6122d482611faa565b600f546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa15801561231d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123419190613730565b9050818110156123cf5761271060135461271061235e9190613703565b61236890846137fe565b6123729190613833565b8110156123cf5760405162461bcd60e51b815260206004820152602560248201527f77697468647261773a206f75747369646520736c69707061676520746f6c6572604482015264616e63652160d81b6064820152608401610aba565b600854610a49906001600160a01b03166123e98385612bb1565b600f546001600160a01b03169190611b8a565b600080612407610d11565b909250905060006124188284613703565b9050600060105461271061242c9190613703565b60105461243990846137fe565b6124439190613833565b90506012548361245391906136c1565b811115611844576118446124678483613703565b612bc7565b6060600061247b8360026137fe565b6124869060026136c1565b67ffffffffffffffff81111561249e5761249e613541565b6040519080825280601f01601f1916602001820160405280156124c8576020820181803683370190505b509050600360fc1b816000815181106124e3576124e361371a565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106125125761251261371a565b60200101906001600160f81b031916908160001a90535060006125368460026137fe565b6125419060016136c1565b90505b60018111156125b9576f181899199a1a9b1b9c1cb0b131b232b360811b85600f16601081106125755761257561371a565b1a60f81b82828151811061258b5761258b61371a565b60200101906001600160f81b031916908160001a90535060049490941c936125b2816138c5565b9050612544565b5083156109cb5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610aba565b61261282826110dc565b15610acd576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60006109cb836001600160a01b038416612d5d565b600a546040516370a0823160e01b8152306004820152600091829161271091906042602160991b01906370a0823190602401602060405180830381865afa1580156126d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126f59190613730565b6126ff91906137fe565b6127099190613833565b90508061271857600091505090565b6040516370a0823160e01b8152306004820152737f5c764cbc14f9669b88837ca1490cca17c316079060009082906370a0823190602401602060405180830381865afa15801561276c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127909190613730565b90506127f660168054806020026020016040519081016040528092919081815260200182805480156127eb57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116127cd575b505050505084612e50565b6040516370a0823160e01b815230600482015260009082906001600160a01b038516906370a0823190602401602060405180830381865afa15801561283f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128639190613730565b61286d9190613703565b9050801561292757612710600b548261288691906137fe565b6128909190613833565b94506000612710600c54836128a591906137fe565b6128af9190613833565b90506000612710600d54836128c491906137fe565b6128ce9190613833565b90506128da8183613703565b91506128f06001600160a01b0386163389611b8a565b60075461290a906001600160a01b03878116911684611b8a565b600954612924906001600160a01b03878116911683611b8a565b50505b5050505090565b6040516370a0823160e01b81523060048201526000906042602160991b01906370a0823190602401602060405180830381865afa158015612973573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129979190613730565b90508015610a1057610a1060178054806020026020016040519081016040528092919081815260200182805480156129f857602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116129da575b505050505082612e50565b6000612a58826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131259092919063ffffffff16565b805190915015610a495780806020019051810190612a769190613d1d565b610a495760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610aba565b6000826000018281548110612aec57612aec61371a565b9060005260206000200154905092915050565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015612b50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b749190613730565b612b7e91906136c1565b6040516001600160a01b03851660248201526044810182905290915061184490859063095ea7b360e01b90606401611bb6565b6000818310612bc057816109cb565b5090919050565b80612c0a5760405162461bcd60e51b8152602060048201526013602482015272464c3a20696e76616c696420616d6f756e742160681b6044820152606401610aba565b604080516001808252818301909252600091602080830190803683375050600f5482519293506001600160a01b031691839150600090612c4c57612c4c61371a565b6001600160a01b0392909216602092830291909101909101526040805160018082528183019092526000918160200160208202803683370190505090508281600081518110612c9d57612c9d61371a565b6020908102919091010152604080516001808252818301909252600091816020016020820280368337019050509050600281600081518110612ce157612ce161371a565b60209081029190910101526001601455612cf9610eb2565b6001600160a01b031663ab9c4b5d308585853060006040518763ffffffff1660e01b8152600401612d2f96959493929190613d73565b600060405180830381600087803b158015612d4957600080fd5b505af1158015612272573d6000803e3d6000fd5b60008181526001830160205260408120548015612e46576000612d81600183613703565b8554909150600090612d9590600190613703565b9050818114612dfa576000866000018281548110612db557612db561371a565b9060005260206000200154905080876000018481548110612dd857612dd861371a565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612e0b57612e0b613e1e565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610916565b6000915050610916565b815173a132dab612db5cb9fc9ac426a0cc215a3423f9c990600090612e7790600190613703565b67ffffffffffffffff811115612e8f57612e8f613541565b604051908082528060200260200182016040528015612eda57816020015b6040805160608101825260008082526020808301829052928201528252600019909201910181612ead5790505b50905082600080805b845181101561305c57856001600160a01b0316635e1e6325858a8481518110612f0e57612f0e61371a565b60200260200101518b856001612f2491906136c1565b81518110612f3457612f3461371a565b60200260200101516040518463ffffffff1660e01b8152600401612f74939291909283526001600160a01b03918216602084015216604082015260600190565b6040805180830381865afa158015612f90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fb49190613e34565b80935081945050506040518060600160405280898381518110612fd957612fd961371a565b60200260200101516001600160a01b0316815260200189836001612ffd91906136c1565b8151811061300d5761300d61371a565b60200260200101516001600160a01b0316815260200183151581525085828151811061303b5761303b61371a565b602002602001018190525082935080806130549061390a565b915050612ee3565b506130a973a132dab612db5cb9fc9ac426a0cc215a3423f9c987896000815181106130895761308961371a565b60200260200101516001600160a01b0316612aff9092919063ffffffff16565b604051631e82ecdb60e31b81526001600160a01b0386169063f41766d8906130de908990600090899030904290600401613e60565b6000604051808303816000875af11580156130fd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526122729190810190613ef5565b606061161c848460008585843b61317e5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610aba565b600080866001600160a01b0316858760405161319a9190613f2a565b60006040518083038185875af1925050503d80600081146131d7576040519150601f19603f3d011682016040523d82523d6000602084013e6131dc565b606091505b50915091506131ec8282866131f7565b979650505050505050565b606083156132065750816109cb565b8251156132165782518084602001fd5b8160405162461bcd60e51b8152600401610aba91906139bf565b828054828255906000526020600020908101928215613285579160200282015b8281111561328557825182546001600160a01b0319166001600160a01b03909116178255602090920191600190910190613250565b506132919291506132e8565b5090565b828054828255906000526020600020908101928215613285579160200282015b828111156132855781546001600160a01b0319166001600160a01b038435161782556020909201916001909101906132b5565b5b8082111561329157600081556001016132e9565b60006020828403121561330f57600080fd5b81356001600160e01b0319811681146109cb57600080fd5b60006020828403121561333957600080fd5b5035919050565b60008060006060848603121561335557600080fd5b505081359360208301359350604090920135919050565b6001600160a01b0381168114610a1057600080fd5b6000806040838503121561339457600080fd5b8235915060208301356133a68161336c565b809150509250929050565b600080604083850312156133c457600080fd5b50508035926020909101359150565b6000602082840312156133e557600080fd5b81356109cb8161336c565b60008083601f84011261340257600080fd5b50813567ffffffffffffffff81111561341a57600080fd5b6020830191508360208260051b850101111561343557600080fd5b9250929050565b600080600080600080600080600060a08a8c03121561345a57600080fd5b893567ffffffffffffffff8082111561347257600080fd5b61347e8d838e016133f0565b909b50995060208c013591508082111561349757600080fd5b6134a38d838e016133f0565b909950975060408c01359150808211156134bc57600080fd5b6134c88d838e016133f0565b909750955060608c013591506134dd8261336c565b90935060808b013590808211156134f357600080fd5b818c0191508c601f83011261350757600080fd5b81358181111561351657600080fd5b8d602082850101111561352857600080fd5b6020830194508093505050509295985092959850929598565b634e487b7160e01b600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171561357a5761357a613541565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156135a9576135a9613541565b604052919050565b600067ffffffffffffffff8211156135cb576135cb613541565b5060051b60200190565b600060208083850312156135e857600080fd5b823567ffffffffffffffff8111156135ff57600080fd5b8301601f8101851361361057600080fd5b803561362361361e826135b1565b613580565b81815260059190911b8201830190838101908783111561364257600080fd5b928401925b828410156131ec57833561365a8161336c565b82529284019290840190613647565b6000806020838503121561367c57600080fd5b823567ffffffffffffffff81111561369357600080fd5b61369f858286016133f0565b90969095509350505050565b634e487b7160e01b600052601160045260246000fd5b600082198211156136d4576136d46136ab565b500190565b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b600082821015613715576137156136ab565b500390565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561374257600080fd5b5051919050565b8051801515811461375957600080fd5b919050565b60008060008060008060008060006101208a8c03121561377d57600080fd5b8951985060208a0151975060408a0151965060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a015164ffffffffff811681146137c357600080fd5b91506137d26101008b01613749565b90509295985092959850929598565b6000602082840312156137f357600080fd5b81516109cb8161336c565b6000816000190483118215151615613818576138186136ab565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826138425761384261381d565b500490565b6000600160ff1b82141561385d5761385d6136ab565b5060000390565b600080821280156001600160ff1b0384900385131615613886576138866136ab565b600160ff1b839003841281161561389f5761389f6136ab565b50500190565b60006001600160ff1b038214156138be576138be6136ab565b5060010190565b6000816138d4576138d46136ab565b506000190190565b6000826138eb576138eb61381d565b600160ff1b821460001984141615613905576139056136ab565b500590565b60006000198214156138be576138be6136ab565b60005b83811015613939578181015183820152602001613921565b838111156118445750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081526000835161398281601785016020880161391e565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516139b381602884016020880161391e565b01602801949350505050565b60208152600082518060208401526139de81604085016020870161391e565b601f01601f19169190910160400192915050565b6020808252825482820181905260008481528281209092916040850190845b81811015613a365783546001600160a01b031683526001938401939285019201613a11565b50909695505050505050565b600082601f830112613a5357600080fd5b81516020613a6361361e836135b1565b82815260059290921b84018101918181019086841115613a8257600080fd5b8286015b84811015613a9d5780518352918301918301613a86565b509695505050505050565b60008060408385031215613abb57600080fd5b825167ffffffffffffffff80821115613ad357600080fd5b818501915085601f830112613ae757600080fd5b81516020613af761361e836135b1565b82815260059290921b84018101918181019089841115613b1657600080fd5b948201945b83861015613b3d578551613b2e8161336c565b82529482019490820190613b1b565b91880151919650909350505080821115613b5657600080fd5b50613b6385828601613a42565b9150509250929050565b805161ffff8116811461375957600080fd5b60006020808385031215613b9257600080fd5b825167ffffffffffffffff80821115613baa57600080fd5b9084019060a08287031215613bbe57600080fd5b613bc6613557565b613bcf83613b6d565b8152613bdc848401613b6d565b84820152613bec60408401613b6d565b60408201526060830151613bff8161336c565b6060820152608083015182811115613c1657600080fd5b80840193505086601f840112613c2b57600080fd5b825182811115613c3d57613c3d613541565b613c4f601f8201601f19168601613580565b92508083528785828601011115613c6557600080fd5b613c748186850187870161391e565b50608081019190915295945050505050565b6000806000806000806000806000806101408b8d031215613ca657600080fd5b8a51995060208b0151985060408b0151975060608b0151965060808b01519550613cd260a08c01613749565b9450613ce060c08c01613749565b9350613cee60e08c01613749565b9250613cfd6101008c01613749565b9150613d0c6101208c01613749565b90509295989b9194979a5092959850565b600060208284031215613d2f57600080fd5b6109cb82613749565b600081518084526020808501945080840160005b83811015613d6857815187529582019590820190600101613d4c565b509495945050505050565b6001600160a01b03878116825260e06020808401829052885191840182905260009289820192909190610100860190855b81811015613dc2578551851683529483019491830191600101613da4565b50508581036040870152613dd6818b613d38565b93505050508281036060840152613ded8187613d38565b6001600160a01b038616608085015283810360a08501526000815261ffff851660c085015260200191506131ec9050565b634e487b7160e01b600052603160045260246000fd5b60008060408385031215613e4757600080fd5b82519150613e5760208401613749565b90509250929050565b600060a0820187835260208781850152604060a08186015282885180855260c087019150838a01945060005b81811015613ec957855180516001600160a01b03908116855286820151168685015284015115158484015294840194606090920191600101613e8c565b50506001600160a01b03881660608701529350613ee592505050565b8260808301529695505050505050565b600060208284031215613f0757600080fd5b815167ffffffffffffffff811115613f1e57600080fd5b61161c84828501613a42565b60008251613f3c81846020870161391e565b919091019291505056feb17d0a42cc710456bf9c3efb785dcd0cb93a0ac358113307b5c64b285b516b5ca2646970667358221220981d059dfaa6c075b82a22a796b5a234884ad2a520dc2a196ffd10dfeecf69cb64736f6c634300080b0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000df2d2c477078d2cd563648abbb913da3db247c00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000e50fa9b3c56ffb159cb0fca61f5c9d750e8128c800000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000001e140000000000000000000000000000000000000000000000000000000000001e7800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b0000000000000000000000002b394b228908fb7dacaff5f340f1b442a39b056c00000000000000000000000000000000000000000000000000000000000000030000000000000000000000001e71aee6081f62053123140aacc7a06021d7734800000000000000000000000081876677843d00a7d792e1617459ac2e932025760000000000000000000000001a20d7a31e5b3bc5f02c8a146ef6f394502a10c400000000000000000000000000000000000000000000000000000000000000030000000000000000000000003aa60c3ae4b94515fa1fd0ffee77d02b6a0609f3000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b000000000000000000000000b0c9d5851def8a2aac4a23031ca2610f8c3483f9000000000000000000000000000000000000000000000000000000000000000200000000000000000000000042000000000000000000000000000000000000420000000000000000000000004200000000000000000000000000000000000006

-----Decoded View---------------
Arg [0] : _vault (address): 0xdf2D2c477078D2cD563648abbb913dA3Db247c00
Arg [1] : _feeRemitters (address[]): 0xeb9C9b785aA7818B2EBC8f9842926c4B9f707e4B,0x2b394b228908fb7DAcafF5F340f1b442a39B056C
Arg [2] : _strategists (address[]): 0x1E71AEE6081f62053123140aacC7a06021D77348,0x81876677843D00a7D792E1617459aC2E93202576,0x1A20D7A31e5B3Bc5f02c8A146EF6f394502a10c4
Arg [3] : _multisigRoles (address[]): 0x3aa60C3ae4b94515Fa1FD0fFEe77d02B6a0609f3,0xeb9C9b785aA7818B2EBC8f9842926c4B9f707e4B,0xb0C9D5851deF8A2Aac4A23031CA2610f8C3483F9
Arg [4] : _aWant (address): 0xe50fA9b3c56FfB159cB0FCA61F5c9D750e8128c8
Arg [5] : _opToWantPath (address[]): 0x4200000000000000000000000000000000000042,0x4200000000000000000000000000000000000006
Arg [6] : _targetLtv (uint256): 7700
Arg [7] : _maxLtv (uint256): 7800
Arg [8] : _eModeCategory (uint8): 0

-----Encoded View---------------
23 Constructor Arguments found :
Arg [0] : 000000000000000000000000df2d2c477078d2cd563648abbb913da3db247c00
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [4] : 000000000000000000000000e50fa9b3c56ffb159cb0fca61f5c9d750e8128c8
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000280
Arg [6] : 0000000000000000000000000000000000000000000000000000000000001e14
Arg [7] : 0000000000000000000000000000000000000000000000000000000000001e78
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [10] : 000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b
Arg [11] : 0000000000000000000000002b394b228908fb7dacaff5f340f1b442a39b056c
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [13] : 0000000000000000000000001e71aee6081f62053123140aacc7a06021d77348
Arg [14] : 00000000000000000000000081876677843d00a7d792e1617459ac2e93202576
Arg [15] : 0000000000000000000000001a20d7a31e5b3bc5f02c8a146ef6f394502a10c4
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [17] : 0000000000000000000000003aa60c3ae4b94515fa1fd0ffee77d02b6a0609f3
Arg [18] : 000000000000000000000000eb9c9b785aa7818b2ebc8f9842926c4b9f707e4b
Arg [19] : 000000000000000000000000b0c9d5851def8a2aac4a23031ca2610f8c3483f9
Arg [20] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [21] : 0000000000000000000000004200000000000000000000000000000000000042
Arg [22] : 0000000000000000000000004200000000000000000000000000000000000006


Deployed Bytecode Sourcemap

928:15804:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;619:212:20;;;;;;:::i;:::-;;:::i;:::-;;;470:14:33;;463:22;445:41;;433:2;418:18;619:212:20;;;;;;;;4200:155:0;1222:42;4200:155;;;-1:-1:-1;;;;;692:32:33;;;674:51;;662:2;647:18;4200:155:0;497:234:33;2814:37:0;;;;;;:::i;:::-;;:::i;1172:92::-;;1222:42;1172:92;;402:43:1;;437:8;402:43;;;;;1384:25:33;;;1372:2;1357:18;402:43:1;1238:177:33;3085:23:1;;;;;;1531:18:0;;;;;-1:-1:-1;;;;;1531:18:0;;;8911:492:1;;;;;;:::i;:::-;;:::i;611:35::-;;;;;;3977:121:19;;;;;;:::i;:::-;4043:7;4069:12;;;;;;;;;;:22;;;;3977:121;1636:50:1;;1668:18;1636:50;;1505:20:0;;;;;-1:-1:-1;;;;;1505:20:0;;;6169:101:1;6246:10;:17;6169:101;;5313:199;;;;;;:::i;:::-;;:::i;:::-;;3070:29:0;;;;;;:::i;:::-;;:::i;4348:145:19:-;;;;;;:::i;:::-;;:::i;5365:214::-;;;;;;:::i;:::-;;:::i;3035:29:0:-;;;;;;:::i;:::-;;:::i;1626:21::-;;;;;;1363:92;;1413:42;1363:92;;8165:112:1;;;:::i;15611:370:0:-;;;;;;:::i;:::-;;:::i;5691:472:1:-;;;:::i;7625:115::-;;;:::i;348:48::-;;390:6;348:48;;12824:294:0;;;:::i;:::-;;;;3438:25:33;;;3494:2;3479:18;;3472:34;;;;3411:18;12824:294:0;3264:248:33;3174:28:1;;;;;;1098:84:23;1168:7;;;;1098:84;;1978:23:1;;;;;-1:-1:-1;;;;;1978:23:1;;;14290:141:0;;;;;;:::i;:::-;;:::i;15263:163::-;;;;;;:::i;:::-;;:::i;1086:80::-;;1124:42;1086:80;;14611:237;;;:::i;1574:56:1:-;;1609:21;1574:56;;573:32;;;;;;4361:114:0;;;:::i;2658:71::-;;-1:-1:-1;;;;;2658:71:0;;1270:87;;1315:42;1270:87;;9490:171:1;;;;;;:::i;:::-;;:::i;7911:90::-;;;:::i;1450:52::-;;1483:19;1450:52;;2033:33;;;;;-1:-1:-1;;;;;2033:33:1;;;2735:73:0;;2766:42;2735:73;;10194:1124:1;;;;;;:::i;:::-;;:::i;1416:143:20:-;;;;;;:::i;:::-;;:::i;3114:22:1:-;;;;;;2894:137:19;;;;;;:::i;:::-;;:::i;4481:700:0:-;;;;;;:::i;:::-;;:::i;1508:60:1:-;;-1:-1:-1;;;;;;;;;;;1508:60:1;;2012:49:19;;2057:4;2012:49;;14011:143:0;;;;;;:::i;:::-;;:::i;13423:228::-;;;;;;:::i;:::-;;:::i;2345:38:1:-;;2379:4;2345:38;;1731:40:0;;;;;;1727:132:20;;;;;;:::i;:::-;;:::i;13194:223:0:-;;;;;;:::i;:::-;;:::i;3142:26:1:-;;;;;;5035:76;;;:::i;1693:32:0:-;;;;;;8373:210:1;;;;;;:::i;:::-;;:::i;4727:147:19:-;;;;;;:::i;:::-;;:::i;9772:296:1:-;;;;;;:::i;:::-;;:::i;7047:163::-;;;;;;:::i;:::-;;:::i;1556:24:0:-;;;;;;2389:49:1;;2434:4;2389:49;;540:27;;;;;;:::i;:::-;;:::i;6508:435::-;;;;;;:::i;:::-;;:::i;13743:132:0:-;;;;;;:::i;:::-;;:::i;2007:20:1:-;;;;;-1:-1:-1;;;;;2007:20:1;;;619:212:20;704:4;-1:-1:-1;;;;;;727:57:20;;-1:-1:-1;;;727:57:20;;:97;;;788:36;812:11;788:23;:36::i;:::-;720:104;619:212;-1:-1:-1;;619:212:20:o;2814:37:0:-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;2814:37:0;;-1:-1:-1;2814:37:0;:::o;8911:492:1:-;9043:4;9059:32;9043:4;9059:12;:32::i;:::-;390:6;9109:23;9120:12;9109:8;:23;:::i;:::-;:42;9101:51;;;;;;2434:4;9170:14;:36;;9162:45;;;;;;9218:7;:18;;;9246:11;:26;;;9282:13;:30;;;9327:48;;;9396:25:33;;;9452:2;9437:18;;9430:34;;;9480:18;;;9473:34;;;9327:48:1;;9384:2:33;9369:18;9327:48:1;;;;;;;-1:-1:-1;9392:4:1;8911:492;;;;;;:::o;5313:199::-;5398:5;;-1:-1:-1;;;;;5398:5:1;5384:10;:19;5376:28;;;;;;5422:12;5414:21;;;;;;5464:11;:9;:11::i;:::-;5453:7;:22;;5445:31;;;;;;5487:18;5497:7;5487:9;:18::i;:::-;5313:199;:::o;3070:29:0:-;;;;;;;;;;;;4348:145:19;4043:7;4069:12;;;;;;;;;;:22;;;2490:30;2501:4;719:10:27;2490::19;:30::i;:::-;4461:25:::1;4472:4;4478:7;4461:10;:25::i;:::-;4348:145:::0;;;:::o;5365:214::-;-1:-1:-1;;;;;5460:23:19;;719:10:27;5460:23:19;5452:83;;;;-1:-1:-1;;;5452:83:19;;9862:2:33;5452:83:19;;;9844:21:33;9901:2;9881:18;;;9874:30;9940:34;9920:18;;;9913:62;-1:-1:-1;;;9991:18:33;;;9984:45;10046:19;;5452:83:19;;;;;;;;;5546:26;5558:4;5564:7;5546:11;:26::i;:::-;5365:214;;:::o;3035:29:0:-;;;;;;;;;;;;8165:112:1;8212:19;1668:18;8212:12;:19::i;:::-;8241:10;:8;:10::i;:::-;8261:9;:7;:9::i;:::-;8165:112::o;15611:370:0:-;15727:24;-1:-1:-1;;;;;;;;;;;15727:12:0;:24::i;:::-;2374:3;15770:29;:64;;15762:94;;;;-1:-1:-1;;;15762:94:0;;10278:2:33;15762:94:0;;;10260:21:33;10317:2;10297:18;;;10290:30;-1:-1:-1;;;10336:18:33;;;10329:47;10393:18;;15762:94:0;10076:341:33;15762:94:0;15866:25;:57;;;;15933:17;:41;15611:370::o;5691:472:1:-;5751:17;1412:8:23;1168:7;;;;;1098:84;1412:8;1411:9;1403:38;;;;-1:-1:-1;;;1403:38:23;;;;;;;:::i;:::-;5792:14:1::1;:12;:14::i;:::-;5780:26;;5886:17;;5840:10;5871:1;5851:10;:17;;;;:21;;;;:::i;:::-;5840:33;;;;;;;;:::i;:::-;;;;;;;;;;;:43;;;:63;;;;:::i;:::-;5821:15;:82;5817:252;;5952:92;::::0;;;;::::1;::::0;;5972:15:::1;5952:92:::0;;6013:5:::1;::::0;6006:36;;-1:-1:-1;;;6006:36:1;;;;5919:10:::1;::::0;5952:92:::1;::::0;;::::1;::::0;-1:-1:-1;;;;;6013:5:1::1;::::0;6006:34:::1;::::0;:36:::1;::::0;;::::1;::::0;5952:92;6006:36;;;;;;6013:5;6006:36:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5952:92:::0;;5919:139;;::::1;::::0;;::::1;::::0;;-1:-1:-1;5919:139:1;;;::::1;::::0;;;;;;::::1;::::0;;::::1;;::::0;;;;;;::::1;::::0;;::::1;::::0;5817:252:::1;6102:15;6079:20;:38:::0;6132:24:::1;::::0;6145:10:::1;::::0;6132:24:::1;::::0;;;::::1;5691:472:::0;:::o;7625:115::-;7670:22;1609:21;7670:12;:22::i;:::-;7702:14;:12;:14::i;:::-;7726:7;:5;:7::i;12824:294:0:-;13036:4;;12950:128;;-1:-1:-1;;;12950:128:0;;-1:-1:-1;;;;;13036:4:0;;;12950:128;;;11430:34:33;13063:4:0;11480:18:33;;;11473:43;12875:14:0;;;;1315:42;;12950:64;;11365:18:33;;12950:128:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;12917:161:0;;;;-1:-1:-1;12824:294:0;;-1:-1:-1;;;;;;;12824:294:0:o;14290:141::-;14357:24;-1:-1:-1;;;;;;;;;;;14357:12:0;:24::i;:::-;14409:5;;14391:4;;:33;;-1:-1:-1;;;;;14391:4:0;;;;14409:5;14416:7;14391:17;:33::i;15263:163::-;15342:20;1483:19:1;15342:12:0;:20::i;:::-;15372:47;15393:13;15408:10;15372:20;:47::i;14611:237::-;14662:7;14682:14;14698;14716:20;:18;:20::i;:::-;14681:55;;-1:-1:-1;14681:55:0;-1:-1:-1;14746:18:0;14767:15;14681:55;;14767:15;:::i;:::-;14812:4;;:29;;-1:-1:-1;;;14812:29:0;;14835:4;14812:29;;;674:51:33;14746:36:0;;-1:-1:-1;;;;;;14812:4:0;;:14;;647:18:33;;14812:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;14799:42;;:10;:42;:::i;:::-;14792:49;;;;;14611:237;:::o;4361:114::-;4407:5;1222:42;-1:-1:-1;;;;;4437:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4424:44;;4361:114;:::o;9490:171:1:-;9553:4;9569:32;9553:4;9569:12;:32::i;:::-;-1:-1:-1;9611:8:1;:22;;-1:-1:-1;;;;;;9611:22:1;-1:-1:-1;;;;;9611:22:1;;;;;;;;;;-1:-1:-1;;9490:171:1:o;7911:90::-;7954:22;1609:21;7954:12;:22::i;:::-;7986:8;:6;:8::i;10194:1124::-;10286:6;10304:21;10328:10;10339:11;10328:23;;;;;;;;:::i;:::-;;;;;;;;;;;10304:47;;10361:19;10383:10;10394:9;10383:21;;;;;;;;:::i;:::-;;;;;;;;;;;10361:43;;10414:15;10432:4;10414:22;;10472:5;:21;;;10450:3;:19;;;:43;10446:92;;;-1:-1:-1;10522:5:1;10446:92;10548:32;10594:10;10590:212;;;10669:5;:21;;;10647:3;:19;;;:43;;;;:::i;:::-;10620:70;;10590:212;;;10772:3;:19;;;10748:5;:21;;;:43;;;;:::i;:::-;10721:70;;10590:212;10883:21;;;;10812:32;;10848:31;:24;10875:4;10848:31;:::i;:::-;10847:57;;;;:::i;:::-;10955:15;;10939:13;;10812:92;;-1:-1:-1;10914:22:1;;10939:31;;10955:15;10939:31;:::i;:::-;10914:56;-1:-1:-1;10981:38:1;10914:56;11023:35;437:8;11023:24;:35;:::i;:::-;11022:54;;;;:::i;:::-;10981:95;-1:-1:-1;11086:38:1;11120:4;10981:95;11086:38;:::i;:::-;;;11173:10;11169:86;;;11213:30;-1:-1:-1;11199:45:1;;-1:-1:-1;;;;;;11199:45:1;11169:86;11272:39;11280:30;11272:39;:::i;:::-;11265:46;10194:1124;-1:-1:-1;;;;;;;;;;10194:1124:1:o;1416:143:20:-;1498:7;1524:18;;;:12;:18;;;;;:28;;1546:5;1524:21;:28::i;2894:137:19:-;2972:4;2995:12;;;;;;;;;;;-1:-1:-1;;;;;2995:29:19;;;;;;;;;;;;;;;2894:137::o;4481:700:0:-;4675:4;4721:6;:4;:6::i;:::-;-1:-1:-1;;;;;4699:29:0;:10;-1:-1:-1;;;;;4699:29:0;;4691:64;;;;-1:-1:-1;;;4691:64:0;;13524:2:33;4691:64:0;;;13506:21:33;13563:2;13543:18;;;13536:30;-1:-1:-1;;;13582:18:33;;;13575:52;13644:18;;4691:64:0;13322:346:33;4691:64:0;-1:-1:-1;;;;;4773:26:0;;4794:4;4773:26;4765:49;;;;-1:-1:-1;;;4765:49:0;;13875:2:33;4765:49:0;;;13857:21:33;13914:2;13894:18;;;13887:30;-1:-1:-1;;;13933:18:33;;;13926:40;13983:18;;4765:49:0;13673:334:33;4765:49:0;2059:1;4832:15;;:41;4824:77;;;;-1:-1:-1;;;4824:77:0;;14214:2:33;4824:77:0;;;14196:21:33;14253:2;14233:18;;;14226:30;14292:25;14272:18;;;14265:53;14335:18;;4824:77:0;14012:347:33;4824:77:0;2002:1;4911:15;:35;5143:9;:7;:9::i;:::-;-1:-1:-1;5170:4:0;4481:700;;;;;;;;;;;:::o;14011:143::-;14085:24;-1:-1:-1;;;;;;;;;;;14085:12:0;:24::i;:::-;14119:28;14139:7;14119:19;:28::i;13423:228::-;13489:24;-1:-1:-1;;;;;;;;;;;13489:12:0;:24::i;:::-;-1:-1:-1;;;;;;;;;;13531:14:0;:5;13537:1;13531:8;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;13531:14:0;;:58;;;;-1:-1:-1;13584:4:0;;13555:12;;-1:-1:-1;;;;;13584:4:0;;;;13549:5;;13555:16;;13584:4;;13555:16;:::i;:::-;13549:23;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;13549:40:0;;13531:58;13523:91;;;;-1:-1:-1;;;13523:91:0;;14566:2:33;13523:91:0;;;14548:21:33;14605:2;14585:18;;;14578:30;-1:-1:-1;;;14624:18:33;;;14617:50;14684:18;;13523:91:0;14364:344:33;13523:91:0;13624:20;;;;:12;;:20;;;;;:::i;1727:132:20:-;1799:7;1825:18;;;:12;:18;;;;;:27;;:25;:27::i;13194:223:0:-;13264:24;-1:-1:-1;;;;;;;;;;;13264:12:0;:24::i;:::-;-1:-1:-1;;;;;13306:5:0;;13312:1;13306:8;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;13306:14:0;;:49;;;;-1:-1:-1;2766:42:0;13324:5;;13330:16;13345:1;13324:5;13330:16;:::i;:::-;13324:23;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;13324:31:0;;13306:49;13298:82;;;;-1:-1:-1;;;13298:82:0;;14915:2:33;13298:82:0;;;14897:21:33;14954:2;14934:18;;;14927:30;-1:-1:-1;;;14973:18:33;;;14966:50;15033:18;;13298:82:0;14713:344:33;13298:82:0;13390:20;:12;13405:5;;13390:20;:::i;5035:76:1:-;1168:7:23;;;;1411:9;1403:38;;;;-1:-1:-1;;;1403:38:23;;;;;;;:::i;:::-;5094:10:1::1;:8;:10::i;8373:210::-:0;8435:32;2057:4:19;8435:12:1;:32::i;:::-;2379:4;8485:9;:20;;8477:29;;;;;;8516:8;:20;;;8551:25;;1384::33;;;8551::1;;1372:2:33;1357:18;8551:25:1;;;;;;;;8373:210;:::o;4727:147:19:-;4043:7;4069:12;;;;;;;;;;:22;;;2490:30;2501:4;719:10:27;2490::19;:30::i;:::-;4841:26:::1;4853:4;4859:7;4841:11;:26::i;9772:296:1:-:0;9857:32;2057:4:19;9857:12:1;:32::i;:::-;-1:-1:-1;;;;;9907:36:1;;9899:45;;;;;;9954:18;:43;;-1:-1:-1;;;;;;9954:43:1;-1:-1:-1;;;;;9954:43:1;;;;;;;;10012:49;;674:51:33;;;10012:49:1;;662:2:33;647:18;10012:49:1;497:234:33;7047:163:1;7129:24;-1:-1:-1;;;;;;;;;;;7129:12:1;:24::i;:::-;7163:17;:40;7047:163::o;540:27::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;540:27:1;:::o;6508:435::-;6607:10;:17;6581:6;;6628:1;-1:-1:-1;6607:22:1;6599:31;;;;;;6641:20;6671:23;6710:9;6742:1;6722:10;:17;;;;:21;;;;:::i;:::-;6710:33;;6705:182;6749:1;6745;:5;:30;;;;;6773:2;6754:16;:21;6745:30;6705:182;;;6813:31;6835:5;6839:1;6835;:5;:::i;:::-;6842:1;6813:21;:31::i;:::-;6796:48;;;;:::i;:::-;;-1:-1:-1;6858:18:1;;;;:::i;:::-;;;;6777:3;;;;;:::i;:::-;;;;6705:182;;;-1:-1:-1;6904:32:1;6920:16;6904:13;:32;:::i;:::-;6897:39;6508:435;-1:-1:-1;;;;6508:435:1:o;13743:132:0:-;13806:24;-1:-1:-1;;;;;;;;;;;13806:12:0;:24::i;:::-;13840:28;13860:7;13840:19;:28::i;6822:233:19:-;6905:22;6913:4;6919:7;6905;:22::i;:::-;6900:149;;6943:6;:12;;;;;;;;;;;-1:-1:-1;;;;;6943:29:19;;;;;;;;;:36;;-1:-1:-1;;6943:36:19;6975:4;6943:36;;;7025:12;719:10:27;;640:96;7025:12:19;-1:-1:-1;;;;;6998:40:19;7016:7;-1:-1:-1;;;;;6998:40:19;7010:4;6998:40;;;;;;;;;;6822:233;;:::o;7612:150:32:-;7682:4;7705:50;7710:3;-1:-1:-1;;;;;7730:23:32;;7705:4;:50::i;2605:202:19:-;2690:4;-1:-1:-1;;;;;;2713:47:19;;-1:-1:-1;;;2713:47:19;;:87;;-1:-1:-1;;;;;;;;;;937:40:29;;;2764:36:19;829:155:29;11649:681:1;11728:15;:22;11709:16;;11796:264;11820:8;11816:1;:12;11796:264;;;11861:15;11877:1;11861:18;;;;;;;;:::i;:::-;;;;;;;;;11853:4;:26;11849:201;;;11920:1;11899:22;;11939:5;;11849:201;11974:12;11985:1;11974:8;:12;:::i;:::-;11969:1;:17;11965:85;;;12006:29;;-1:-1:-1;;;12006:29:1;;16025:2:33;12006:29:1;;;16007:21:33;16064:2;16044:18;;;16037:30;-1:-1:-1;;;16083:18:33;;;16076:49;16142:18;;12006:29:1;15823:343:33;11965:85:1;11830:3;;;;:::i;:::-;;;;11796:264;;;;12075:9;12070:254;12095:18;12090:1;:23;12070:254;;12138:39;12146:15;12162:1;12146:18;;;;;;;;:::i;:::-;;;;;;;;;12166:10;12138:7;:39::i;:::-;12134:180;;;12197:5;;12134:180;12232:18;12227:1;:23;12223:91;;;12270:29;;-1:-1:-1;;;12270:29:1;;16025:2:33;12270:29:1;;;16007:21:33;16064:2;16044:18;;;16037:30;-1:-1:-1;;;16083:18:33;;;16076:49;16142:18;;12270:29:1;15823:343:33;12223:91:1;12115:3;;;;:::i;:::-;;;;12070:254;;;;11699:631;;11649:681;:::o;5787:820:0:-;5869:4;;:29;;-1:-1:-1;;;5869:29:0;;5892:4;5869:29;;;674:51:33;5851:15:0;;-1:-1:-1;;;;;5869:4:0;;:14;;647:18:33;;5869:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5851:47;;5923:7;5912;:18;5908:102;;5964:5;;5946:4;;:33;;-1:-1:-1;;;;;5946:4:0;;;;5964:5;5971:7;5946:17;:33::i;5908:102::-;6020:17;6040;6050:7;6040;:17;:::i;:::-;6020:37;;6068:14;6084;6102:20;:18;:20::i;:::-;6067:55;;-1:-1:-1;6067:55:0;-1:-1:-1;6132:19:0;6142:9;6067:55;6132:19;:::i;:::-;;-1:-1:-1;6161:23:0;6187:11;:53;;6239:1;6187:53;;;6230:6;6202:24;390:6:1;6202::0;:24;:::i;:::-;6201:35;;;;:::i;:::-;6161:79;;6273:6;;6255:15;:24;6251:350;;;6295:30;6315:9;6295:19;:30::i;:::-;6339:43;6363:9;6374:7;6339:23;:43::i;:::-;6251:350;;;6421:9;;6403:15;:27;6399:202;;;6446:43;6470:9;6481:7;6446:23;:43::i;:::-;6503:13;:11;:13::i;6399:202::-;6547:43;6571:9;6582:7;6547:23;:43::i;:::-;5841:766;;;;;5787:820;:::o;3312:484:19:-;3392:22;3400:4;3406:7;3392;:22::i;:::-;3387:403;;3575:41;3603:7;-1:-1:-1;;;;;3575:41:19;3613:2;3575:19;:41::i;:::-;3687:38;3715:4;3722:2;3687:19;:38::i;:::-;3482:265;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;3482:265:19;;;;;;;;;;-1:-1:-1;;;3430:349:19;;;;;;;:::i;1947:166:20:-;2034:31;2051:4;2057:7;2034:16;:31::i;:::-;2075:18;;;;:12;:18;;;;;:31;;2098:7;2075:22;:31::i;2202:171::-;2290:32;2308:4;2314:7;2290:17;:32::i;:::-;2332:18;;;;:12;:18;;;;;:34;;2358:7;2332:25;:34::i;2110:117:23:-;1168:7;;;;1669:41;;;;-1:-1:-1;;;1669:41:23;;17955:2:33;1669:41:23;;;17937:21:33;17994:2;17974:18;;;17967:30;-1:-1:-1;;;18013:18:33;;;18006:50;18073:18;;1669:41:23;17753:344:33;1669:41:23;2168:7:::1;:15:::0;;-1:-1:-1;;2168:15:23::1;::::0;;2198:22:::1;719:10:27::0;2207:12:23::1;2198:22;::::0;-1:-1:-1;;;;;692:32:33;;;674:51;;662:2;647:18;2198:22:23::1;;;;;;;2110:117::o:0;9583:267:0:-;9663:87;;-1:-1:-1;;;9663:87:0;;9634:17;;1413:42;;9663:65;;:87;;9729:20;;9663:87;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;9663:87:0;;;;;;;;;;;;:::i;:::-;;;9772:24;:22;:24::i;:::-;9760:36;;9806:18;:16;:18::i;:::-;9834:9;:7;:9::i;:::-;9583:267;:::o;14921:242::-;14974:14;14990;15008:20;:18;:20::i;:::-;14973:55;;-1:-1:-1;14973:55:0;-1:-1:-1;15038:18:0;15059:15;14973:55;;15059:15;:::i;:::-;15038:36;;15084:31;15104:10;15084:19;:31::i;:::-;15125;15145:10;15125:19;:31::i;701:205:25:-;840:58;;-1:-1:-1;;;;;20858:32:33;;840:58:25;;;20840:51:33;20907:18;;;20900:34;;;813:86:25;;833:5;;-1:-1:-1;;;863:23:25;20813:18:33;;840:58:25;;;;-1:-1:-1;;840:58:25;;;;;;;;;;;;;;-1:-1:-1;;;;;840:58:25;-1:-1:-1;;;;;;840:58:25;;;;;;;;;;813:19;:86::i;15987:743:0:-;16079:13;16095:6;:4;:6::i;:::-;:34;;-1:-1:-1;;;16095:34:0;;16123:4;16095:34;;;674:51:33;-1:-1:-1;;;;;16095:19:0;;;;;;;647:18:33;;16095:34:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;16079:50;-1:-1:-1;16139:11:0;16164:10;;16160:333;;16190:40;16233:6;:4;:6::i;:::-;:41;;-1:-1:-1;;;16233:41:0;;21117:4:33;21105:17;;16233:41:0;;;21087:36:33;-1:-1:-1;;;;;16233:27:0;;;;;;;21060:18:33;;16233:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;16233:41:0;;;;;;;;;;;;:::i;:::-;16294:13;16288:19;;;-1:-1:-1;16160:333:0;;-1:-1:-1;16160:333:0;;16463:4;;16364:118;;-1:-1:-1;;;16364:118:0;;-1:-1:-1;;;;;16463:4:0;;;16364:118;;;674:51:33;1315:42:0;;16364:73;;647:18:33;;16364:118:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;16338:144:0;;-1:-1:-1;;;;;;;;;16160:333:0;390:6:1;16525:21:0;2253:4;16525:3;:21;:::i;:::-;16524:41;;;;:::i;:::-;16510:10;:55;;16502:83;;;;-1:-1:-1;;;16502:83:0;;23684:2:33;16502:83:0;;;23666:21:33;23723:2;23703:18;;;23696:30;-1:-1:-1;;;23742:18:33;;;23735:45;23797:18;;16502:83:0;23482:339:33;16502:83:0;16620:10;16603:13;:27;;16595:64;;;;-1:-1:-1;;;16595:64:0;;24028:2:33;16595:64:0;;;24010:21:33;24067:2;24047:18;;;24040:30;24106:26;24086:18;;;24079:54;24150:18;;16595:64:0;23826:348:33;16595:64:0;-1:-1:-1;;16669:6:0;:19;16698:9;:25;15987:743::o;1863:115:23:-;1168:7;;;;1411:9;1403:38;;;;-1:-1:-1;;;1403:38:23;;;;;;;:::i;:::-;1922:7:::1;:14:::0;;-1:-1:-1;;1922:14:23::1;1932:4;1922:14;::::0;;1951:20:::1;1958:12;719:10:27::0;;640:96;8870:156:32;8944:7;8994:22;8998:3;9010:5;8994:3;:22::i;9182:289:0:-;9238:4;;:29;;-1:-1:-1;;;9238:29:0;;9261:4;9238:29;;;674:51:33;9220:15:0;;-1:-1:-1;;;;;9238:4:0;;:14;;647:18:33;;9238:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9220:47;-1:-1:-1;9281:12:0;;9277:188;;9309:52;9344:6;:4;:6::i;:::-;9309:4;;-1:-1:-1;;;;;9309:4:0;;9353:7;9309:26;:52::i;:::-;9375:6;:4;:6::i;:::-;9397:4;;9375:79;;-1:-1:-1;;;9375:79:0;;-1:-1:-1;;;;;9397:4:0;;;9375:79;;;24541:34:33;24591:18;;;24584:34;;;9421:4:0;24634:18:33;;;24627:43;9397:4:0;24686:18:33;;;24679:47;9375:13:0;;;;;24475:19:33;;9375:79:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9210:261;9182:289::o;8539:532::-;8613:14;8629;8647:20;:18;:20::i;:::-;8612:55;;;;8677:23;8703:6;;8713:1;8703:11;;:53;;8755:1;8703:53;;;8746:6;;8718:24;390:6:1;8718::0;:24;:::i;:::-;8717:35;;;;:::i;:::-;8677:79;;8823:15;8814:6;:24;8806:61;;;;-1:-1:-1;;;8806:61:0;;24939:2:33;8806:61:0;;;24921:21:33;24978:2;24958:18;;;24951:30;25017:26;24997:18;;;24990:54;25061:18;;8806:61:0;24737:348:33;8806:61:0;8878:20;8901:24;8910:15;8901:6;:24;:::i;:::-;8878:47;;8953:39;8962:15;8979:12;8953:8;:39::i;:::-;8935:57;;9002:6;:4;:6::i;:::-;9026:4;;9002:62;;-1:-1:-1;;;9002:62:0;;-1:-1:-1;;;;;9026:4:0;;;9002:62;;;25330:34:33;25380:18;;;25373:34;;;9058:4:0;25423:18:33;;;25416:43;9002:15:0;;;;;25265:18:33;;9002:62:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;8413:115:32:-;8476:7;8502:19;8510:3;4028:18;;3946:107;5335:368:0;5383:9;:7;:9::i;:::-;5404:14;5420;5438:20;:18;:20::i;:::-;5403:55;;;;5468:18;5489:6;5499:1;5489:11;;:53;;5541:1;5489:53;;;5532:6;5504:24;390:6:1;5504::0;:24;:::i;:::-;5503:35;;;;:::i;:::-;5468:74;;5570:6;;5557:10;:19;5553:144;;;5592:22;5612:1;5592:19;:22::i;5553:144::-;5648:9;;5635:10;:22;5631:66;;;5673:13;:11;:13::i;6613:631::-;6679:14;6695;6713:20;:18;:20::i;:::-;6678:55;;-1:-1:-1;6678:55:0;-1:-1:-1;6743:18:0;6764:15;6678:55;;6764:15;:::i;:::-;6743:36;;6808:10;6797:7;:21;;6789:48;;;;-1:-1:-1;;;6789:48:0;;25672:2:33;6789:48:0;;;25654:21:33;25711:2;25691:18;;;25684:30;-1:-1:-1;;;25730:18:33;;;25723:44;25784:18;;6789:48:0;25470:338:33;6789:48:0;6896:21;6920:20;6933:7;6920:10;:20;:::i;:::-;6896:44;;6950:17;7019:9;;390:6:1;7001:27:0;;;;:::i;:::-;6987:9;;6971:25;;:13;:25;:::i;:::-;6970:59;;;;:::i;:::-;6950:79;-1:-1:-1;7039:23:0;7065:18;6950:79;7065:6;:18;:::i;:::-;7039:44;;7153:6;:4;:6::i;:::-;7185:4;;7153:84;;-1:-1:-1;;;7153:84:0;;-1:-1:-1;;;;;7185:4:0;;;7153:84;;;26015:51:33;26082:18;;;26075:34;;;2203:1:0;26125:18:33;;;26118:34;7153:23:0;;;;;25988:18:33;;7153:84:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;6668:576;;;;;;6613:631;:::o;1697:404:32:-;1760:4;3834:19;;;:12;;;:19;;;;;;1776:319;;-1:-1:-1;1818:23:32;;;;;;;;:11;:23;;;;;;;;;;;;;1998:18;;1976:19;;;:12;;;:19;;;;;;:40;;;;2030:11;;1776:319;-1:-1:-1;2079:5:32;2072:12;;7830:529:0;7932:36;7952:15;7932:19;:36::i;:::-;7997:4;;:29;;-1:-1:-1;;;7997:29:0;;8020:4;7997:29;;;674:51:33;7979:15:0;;-1:-1:-1;;;;;7997:4:0;;:14;;647:18:33;;7997:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;7979:47;;8050:15;8040:7;:25;8036:246;;;390:6:1;8155:25:0;;390:6:1;8137:43:0;;;;:::i;:::-;8118:63;;:15;:63;:::i;:::-;8117:83;;;;:::i;:::-;8106:7;:94;;8081:190;;;;-1:-1:-1;;;8081:190:0;;26365:2:33;8081:190:0;;;26347:21:33;26404:2;26384:18;;;26377:30;26443:34;26423:18;;;26416:62;-1:-1:-1;;;26494:18:33;;;26487:35;26539:19;;8081:190:0;26163:401:33;8081:190:0;8310:5;;8292:60;;-1:-1:-1;;;;;8310:5:0;8317:34;8326:7;8335:15;8317:8;:34::i;:::-;8292:4;;-1:-1:-1;;;;;8292:4:0;;:60;:17;:60::i;7348:361::-;7391:14;7407;7425:20;:18;:20::i;:::-;7390:55;;-1:-1:-1;7390:55:0;-1:-1:-1;7455:18:0;7476:15;7390:55;;7476:15;:::i;:::-;7455:36;;7501:21;7571:9;;390:6:1;7553:27:0;;;;:::i;:::-;7539:9;;7526:22;;:10;:22;:::i;:::-;7525:56;;;;:::i;:::-;7501:80;;7621:17;;7612:6;:26;;;;:::i;:::-;7596:13;:42;7592:111;;;7654:38;7669:22;7685:6;7669:13;:22;:::i;:::-;7654:14;:38::i;1588:441:28:-;1663:13;1688:19;1720:10;1724:6;1720:1;:10;:::i;:::-;:14;;1733:1;1720:14;:::i;:::-;1710:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1710:25:28;;1688:47;;-1:-1:-1;;;1745:6:28;1752:1;1745:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;1745:15:28;;;;;;;;;-1:-1:-1;;;1770:6:28;1777:1;1770:9;;;;;;;;:::i;:::-;;;;:15;-1:-1:-1;;;;;1770:15:28;;;;;;;;-1:-1:-1;1800:9:28;1812:10;1816:6;1812:1;:10;:::i;:::-;:14;;1825:1;1812:14;:::i;:::-;1800:26;;1795:132;1832:1;1828;:5;1795:132;;;-1:-1:-1;;;1879:5:28;1887:3;1879:11;1866:25;;;;;;;:::i;:::-;;;;1854:6;1861:1;1854:9;;;;;;;;:::i;:::-;;;;:37;-1:-1:-1;;;;;1854:37:28;;;;;;;;-1:-1:-1;1915:1:28;1905:11;;;;;1835:3;;;:::i;:::-;;;1795:132;;;-1:-1:-1;1944:10:28;;1936:55;;;;-1:-1:-1;;;1936:55:28;;26771:2:33;1936:55:28;;;26753:21:33;;;26790:18;;;26783:30;26849:34;26829:18;;;26822:62;26901:18;;1936:55:28;26569:356:33;7180:234:19;7263:22;7271:4;7277:7;7263;:22::i;:::-;7259:149;;;7333:5;7301:12;;;;;;;;;;;-1:-1:-1;;;;;7301:29:19;;;;;;;;;;:37;;-1:-1:-1;;7301:37:19;;;7357:40;719:10:27;;7301:12:19;;7357:40;;7333:5;7357:40;7180:234;;:::o;7930:156:32:-;8003:4;8026:53;8034:3;-1:-1:-1;;;;;8054:23:32;;8026:7;:53::i;9973:952:0:-;10109:8;;10071:35;;-1:-1:-1;;;10071:35:0;;10100:4;10071:35;;;674:51:33;10025:17:0;;;;390:6:1;;10109:8:0;-1:-1:-1;;;;;2687:42:0;10071:20;;647:18:33;;10071:35:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:46;;;;:::i;:::-;10070:66;;;;:::i;:::-;10054:82;-1:-1:-1;10150:10:0;10146:49;;10183:1;10176:8;;;9973:952;:::o;10146:49::-;10265:29;;-1:-1:-1;;;10265:29:0;;10288:4;10265:29;;;674:51:33;2766:42:0;;10205:11;;2766:42;;10265:14;;647:18:33;;10265:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;10241:53;;10304:26;10310:12;10304:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;10304:26:0;;;;;;;;;;;;;;;;;;;;;10324:5;10304;:26::i;:::-;10358:29;;-1:-1:-1;;;10358:29:0;;10381:4;10358:29;;;674:51:33;10340:15:0;;10390:13;;-1:-1:-1;;;;;10358:14:0;;;;;647:18:33;;10358:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:45;;;;:::i;:::-;10340:63;-1:-1:-1;10418:12:0;;10414:505;;390:6:1;10469:7:0;;10459;:17;;;;:::i;:::-;10458:37;;;;:::i;:::-;10446:49;;10509:26;390:6:1;10549:11:0;;10539:7;:21;;;;:::i;:::-;10538:41;;;;:::i;:::-;10509:70;;10593:23;390:6:1;10641:13:0;;10620:18;:34;;;;:::i;:::-;10619:54;;;;:::i;:::-;10593:80;-1:-1:-1;10687:37:0;10593:80;10687:37;;:::i;:::-;;-1:-1:-1;10739:40:0;-1:-1:-1;;;;;10739:17:0;;10757:10;10769:9;10739:17;:40::i;:::-;10811:8;;10793:47;;-1:-1:-1;;;;;10793:17:0;;;;10811:8;10821:18;10793:17;:47::i;:::-;10872:18;;10854:54;;-1:-1:-1;;;;;10854:17:0;;;;10872:18;10892:15;10854:17;:54::i;:::-;10432:487;;10414:505;10044:881;;;;9973:952;:::o;11132:181::-;11195:35;;-1:-1:-1;;;11195:35:0;;11224:4;11195:35;;;674:51:33;11179:13:0;;-1:-1:-1;;;;;2687:42:0;11195:20;;647:18:33;;11195:35:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11179:51;-1:-1:-1;11244:10:0;;11240:67;;11270:26;11276:12;11270:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;11270:26:0;;;;;;;;;;;;;;;;;;;;;11290:5;11270;:26::i;3207:706:25:-;3626:23;3652:69;3680:4;3652:69;;;;;;;;;;;;;;;;;3660:5;-1:-1:-1;;;;;3652:27:25;;;:69;;;;;:::i;:::-;3735:17;;3626:95;;-1:-1:-1;3735:21:25;3731:176;;3830:10;3819:30;;;;;;;;;;;;:::i;:::-;3811:85;;;;-1:-1:-1;;;3811:85:25;;27339:2:33;3811:85:25;;;27321:21:33;27378:2;27358:18;;;27351:30;27417:34;27397:18;;;27390:62;-1:-1:-1;;;27468:18:33;;;27461:40;27518:19;;3811:85:25;27137:406:33;4395:118:32;4462:7;4488:3;:11;;4500:5;4488:18;;;;;;;;:::i;:::-;;;;;;;;;4481:25;;4395:118;;;;:::o;2022:310:25:-;2171:39;;-1:-1:-1;;;2171:39:25;;2195:4;2171:39;;;11430:34:33;-1:-1:-1;;;;;11500:15:33;;;11480:18;;;11473:43;2148:20:25;;2213:5;;2171:15;;;;;11365:18:33;;2171:39:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:47;;;;:::i;:::-;2255:69;;-1:-1:-1;;;;;20858:32:33;;2255:69:25;;;20840:51:33;20907:18;;;20900:34;;;2148:70:25;;-1:-1:-1;2228:97:25;;2248:5;;-1:-1:-1;;;2278:22:25;20813:18:33;;2255:69:25;20666:274:33;446:104:31;504:7;534:1;530;:5;:13;;542:1;530:13;;;-1:-1:-1;538:1:31;;446:104;-1:-1:-1;446:104:31:o;12161:657:0:-;12229:12;12221:44;;;;-1:-1:-1;;;12221:44:0;;27750:2:33;12221:44:0;;;27732:21:33;27789:2;27769:18;;;27762:30;-1:-1:-1;;;27808:18:33;;;27801:49;27867:18;;12221:44:0;27548:343:33;12221:44:0;12333:16;;;12347:1;12333:16;;;;;;;;;12307:23;;12333:16;;;;;;;;;-1:-1:-1;;12379:4:0;;12359:9;;;;-1:-1:-1;;;;;;12379:4:0;;12359:9;;-1:-1:-1;12379:4:0;;12359:9;;;;:::i;:::-;-1:-1:-1;;;;;12359:25:0;;;;:9;;;;;;;;;;;:25;12454:16;;;12468:1;12454:16;;;;;;;;;12427:24;;12454:16;;;;;;;;;;;;-1:-1:-1;12454:16:0;12427:43;;12493:7;12480;12488:1;12480:10;;;;;;;;:::i;:::-;;;;;;;;;;:20;12585:16;;;12599:1;12585:16;;;;;;;;;12560:22;;12585:16;;;;;;;;;;;;-1:-1:-1;12585:16:0;12560:41;;2203:1;12611:5;12617:1;12611:8;;;;;;;;:::i;:::-;;;;;;;;;;:38;2059:1;12660:15;:40;12710:6;:4;:6::i;:::-;-1:-1:-1;;;;;12710:16:0;;12735:4;12742:6;12750:7;12759:5;12774:4;2141:1;12710:101;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2269:1388:32;2335:4;2472:19;;;:12;;;:19;;;;;;2506:15;;2502:1149;;2875:21;2899:14;2912:1;2899:10;:14;:::i;:::-;2947:18;;2875:38;;-1:-1:-1;2927:17:32;;2947:22;;2968:1;;2947:22;:::i;:::-;2927:42;;3001:13;2988:9;:26;2984:398;;3034:17;3054:3;:11;;3066:9;3054:22;;;;;;;;:::i;:::-;;;;;;;;;3034:42;;3205:9;3176:3;:11;;3188:13;3176:26;;;;;;;;:::i;:::-;;;;;;;;;;;;:38;;;;3288:23;;;:12;;;:23;;;;;:36;;;2984:398;3460:17;;:3;;:17;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;3552:3;:12;;:19;3565:5;3552:19;;;;;;;;;;;3545:26;;;3593:4;3586:11;;;;;;;2502:1149;3635:5;3628:12;;;;;11390:765:0;11580:12;;1124:42;;11465:18;;11580:16;;11595:1;;11580:16;:::i;:::-;11556:41;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;11556:41:0;;-1:-1:-1;;11556:41:0;;;;;;;;;;;-1:-1:-1;11520:77:0;-1:-1:-1;11634:7:0;11608:23;;;11699:287;11723:6;:13;11719:1;:17;11699:287;;;11779:6;-1:-1:-1;;;;;11779:19:0;;11799:15;11816:5;11822:1;11816:8;;;;;;;;:::i;:::-;;;;;;;11826:5;11832:1;11836;11832:5;;;;:::i;:::-;11826:12;;;;;;;;:::i;:::-;;;;;;;11779:60;;;;;;;;;;;;;;;;30204:25:33;;;-1:-1:-1;;;;;30303:15:33;;;30298:2;30283:18;;30276:43;30355:15;30350:2;30335:18;;30328:43;30192:2;30177:18;;30002:375;11779:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11757:82;;;;;;;;11865:72;;;;;;;;11890:5;11896:1;11890:8;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;11865:72:0;;;;;11904:5;11910:1;11914;11910:5;;;;:::i;:::-;11904:12;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;11865:72:0;;;;;11926:9;11865:72;;;;;11853:6;11860:1;11853:9;;;;;;;;:::i;:::-;;;;;;:84;;;;11969:6;11951:24;;11738:3;;;;;:::i;:::-;;;;11699:287;;;;11995:60;1124:42;12047:7;12002:5;12008:1;12002:8;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1;;;;;11995:38:0;;;:60;;;;;:::i;:::-;12065:83;;-1:-1:-1;;;12065:83:0;;-1:-1:-1;;;;;12065:31:0;;;;;:83;;12097:7;;12106:1;;12109:6;;12125:4;;12132:15;;12065:83;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;12065:83:0;;;;;;;;;;;;:::i;3514:223:26:-;3647:12;3678:52;3700:6;3708:4;3714:1;3717:12;3647;1087:20;;4881:60;;;;-1:-1:-1;;;4881:60:26;;32857:2:33;4881:60:26;;;32839:21:33;32896:2;32876:18;;;32869:30;32935:31;32915:18;;;32908:59;32984:18;;4881:60:26;32655:353:33;4881:60:26;4953:12;4967:23;4994:6;-1:-1:-1;;;;;4994:11:26;5013:5;5020:4;4994:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4952:73;;;;5042:51;5059:7;5068:10;5080:12;5042:16;:51::i;:::-;5035:58;4601:499;-1:-1:-1;;;;;;;4601:499:26:o;7214:692::-;7360:12;7388:7;7384:516;;;-1:-1:-1;7418:10:26;7411:17;;7384:516;7529:17;;:21;7525:365;;7723:10;7717:17;7783:15;7770:10;7766:2;7762:19;7755:44;7525:365;7862:12;7855:20;;-1:-1:-1;;;7855:20:26;;;;;;;;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14:286:33;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;167:23;;-1:-1:-1;;;;;;219:32:33;;209:43;;199:71;;266:1;263;256:12;736:180;795:6;848:2;836:9;827:7;823:23;819:32;816:52;;;864:1;861;854:12;816:52;-1:-1:-1;887:23:33;;736:180;-1:-1:-1;736:180:33:o;1643:316::-;1720:6;1728;1736;1789:2;1777:9;1768:7;1764:23;1760:32;1757:52;;;1805:1;1802;1795:12;1757:52;-1:-1:-1;;1828:23:33;;;1898:2;1883:18;;1870:32;;-1:-1:-1;1949:2:33;1934:18;;;1921:32;;1643:316;-1:-1:-1;1643:316:33:o;2555:131::-;-1:-1:-1;;;;;2630:31:33;;2620:42;;2610:70;;2676:1;2673;2666:12;2691:315;2759:6;2767;2820:2;2808:9;2799:7;2795:23;2791:32;2788:52;;;2836:1;2833;2826:12;2788:52;2872:9;2859:23;2849:33;;2932:2;2921:9;2917:18;2904:32;2945:31;2970:5;2945:31;:::i;:::-;2995:5;2985:15;;;2691:315;;;;;:::o;3011:248::-;3079:6;3087;3140:2;3128:9;3119:7;3115:23;3111:32;3108:52;;;3156:1;3153;3146:12;3108:52;-1:-1:-1;;3179:23:33;;;3249:2;3234:18;;;3221:32;;-1:-1:-1;3011:248:33:o;3739:247::-;3798:6;3851:2;3839:9;3830:7;3826:23;3822:32;3819:52;;;3867:1;3864;3857:12;3819:52;3906:9;3893:23;3925:31;3950:5;3925:31;:::i;4424:367::-;4487:8;4497:6;4551:3;4544:4;4536:6;4532:17;4528:27;4518:55;;4569:1;4566;4559:12;4518:55;-1:-1:-1;4592:20:33;;4635:18;4624:30;;4621:50;;;4667:1;4664;4657:12;4621:50;4704:4;4696:6;4692:17;4680:29;;4764:3;4757:4;4747:6;4744:1;4740:14;4732:6;4728:27;4724:38;4721:47;4718:67;;;4781:1;4778;4771:12;4718:67;4424:367;;;;;:::o;4796:1673::-;4983:6;4991;4999;5007;5015;5023;5031;5039;5047;5100:3;5088:9;5079:7;5075:23;5071:33;5068:53;;;5117:1;5114;5107:12;5068:53;5157:9;5144:23;5186:18;5227:2;5219:6;5216:14;5213:34;;;5243:1;5240;5233:12;5213:34;5282:70;5344:7;5335:6;5324:9;5320:22;5282:70;:::i;:::-;5371:8;;-1:-1:-1;5256:96:33;-1:-1:-1;5459:2:33;5444:18;;5431:32;;-1:-1:-1;5475:16:33;;;5472:36;;;5504:1;5501;5494:12;5472:36;5543:72;5607:7;5596:8;5585:9;5581:24;5543:72;:::i;:::-;5634:8;;-1:-1:-1;5517:98:33;-1:-1:-1;5722:2:33;5707:18;;5694:32;;-1:-1:-1;5738:16:33;;;5735:36;;;5767:1;5764;5757:12;5735:36;5806:72;5870:7;5859:8;5848:9;5844:24;5806:72;:::i;:::-;5897:8;;-1:-1:-1;5780:98:33;-1:-1:-1;5982:2:33;5967:18;;5954:32;;-1:-1:-1;5995:31:33;5954:32;5995:31;:::i;:::-;6045:5;;-1:-1:-1;6103:3:33;6088:19;;6075:33;;6120:16;;;6117:36;;;6149:1;6146;6139:12;6117:36;6187:8;6176:9;6172:24;6162:34;;6234:7;6227:4;6223:2;6219:13;6215:27;6205:55;;6256:1;6253;6246:12;6205:55;6296:2;6283:16;6322:2;6314:6;6311:14;6308:34;;;6338:1;6335;6328:12;6308:34;6383:7;6378:2;6369:6;6365:2;6361:15;6357:24;6354:37;6351:57;;;6404:1;6401;6394:12;6351:57;6435:2;6431;6427:11;6417:21;;6457:6;6447:16;;;;;4796:1673;;;;;;;;;;;:::o;6474:127::-;6535:10;6530:3;6526:20;6523:1;6516:31;6566:4;6563:1;6556:15;6590:4;6587:1;6580:15;6606:253;6678:2;6672:9;6720:4;6708:17;;6755:18;6740:34;;6776:22;;;6737:62;6734:88;;;6802:18;;:::i;:::-;6838:2;6831:22;6606:253;:::o;6864:275::-;6935:2;6929:9;7000:2;6981:13;;-1:-1:-1;;6977:27:33;6965:40;;7035:18;7020:34;;7056:22;;;7017:62;7014:88;;;7082:18;;:::i;:::-;7118:2;7111:22;6864:275;;-1:-1:-1;6864:275:33:o;7144:183::-;7204:4;7237:18;7229:6;7226:30;7223:56;;;7259:18;;:::i;:::-;-1:-1:-1;7304:1:33;7300:14;7316:4;7296:25;;7144:183::o;7332:966::-;7416:6;7447:2;7490;7478:9;7469:7;7465:23;7461:32;7458:52;;;7506:1;7503;7496:12;7458:52;7546:9;7533:23;7579:18;7571:6;7568:30;7565:50;;;7611:1;7608;7601:12;7565:50;7634:22;;7687:4;7679:13;;7675:27;-1:-1:-1;7665:55:33;;7716:1;7713;7706:12;7665:55;7752:2;7739:16;7775:60;7791:43;7831:2;7791:43;:::i;:::-;7775:60;:::i;:::-;7869:15;;;7951:1;7947:10;;;;7939:19;;7935:28;;;7900:12;;;;7975:19;;;7972:39;;;8007:1;8004;7997:12;7972:39;8031:11;;;;8051:217;8067:6;8062:3;8059:15;8051:217;;;8147:3;8134:17;8164:31;8189:5;8164:31;:::i;:::-;8208:18;;8084:12;;;;8246;;;;8051:217;;8303:437;8389:6;8397;8450:2;8438:9;8429:7;8425:23;8421:32;8418:52;;;8466:1;8463;8456:12;8418:52;8506:9;8493:23;8539:18;8531:6;8528:30;8525:50;;;8571:1;8568;8561:12;8525:50;8610:70;8672:7;8663:6;8652:9;8648:22;8610:70;:::i;:::-;8699:8;;8584:96;;-1:-1:-1;8303:437:33;-1:-1:-1;;;;8303:437:33:o;8929:127::-;8990:10;8985:3;8981:20;8978:1;8971:31;9021:4;9018:1;9011:15;9045:4;9042:1;9035:15;9061:128;9101:3;9132:1;9128:6;9125:1;9122:13;9119:39;;;9138:18;;:::i;:::-;-1:-1:-1;9174:9:33;;9061:128::o;10422:340::-;10624:2;10606:21;;;10663:2;10643:18;;;10636:30;-1:-1:-1;;;10697:2:33;10682:18;;10675:46;10753:2;10738:18;;10422:340::o;10767:125::-;10807:4;10835:1;10832;10829:8;10826:34;;;10840:18;;:::i;:::-;-1:-1:-1;10877:9:33;;10767:125::o;10897:127::-;10958:10;10953:3;10949:20;10946:1;10939:31;10989:4;10986:1;10979:15;11013:4;11010:1;11003:15;11029:184;11099:6;11152:2;11140:9;11131:7;11127:23;11123:32;11120:52;;;11168:1;11165;11158:12;11120:52;-1:-1:-1;11191:16:33;;11029:184;-1:-1:-1;11029:184:33:o;11527:164::-;11603:13;;11652;;11645:21;11635:32;;11625:60;;11681:1;11678;11671:12;11625:60;11527:164;;;:::o;11696:794::-;11834:6;11842;11850;11858;11866;11874;11882;11890;11898;11951:3;11939:9;11930:7;11926:23;11922:33;11919:53;;;11968:1;11965;11958:12;11919:53;11997:9;11991:16;11981:26;;12047:2;12036:9;12032:18;12026:25;12016:35;;12091:2;12080:9;12076:18;12070:25;12060:35;;12135:2;12124:9;12120:18;12114:25;12104:35;;12179:3;12168:9;12164:19;12158:26;12148:36;;12224:3;12213:9;12209:19;12203:26;12193:36;;12269:3;12258:9;12254:19;12248:26;12238:36;;12317:3;12306:9;12302:19;12296:26;12362:12;12355:5;12351:24;12344:5;12341:35;12331:63;;12390:1;12387;12380:12;12331:63;12413:5;-1:-1:-1;12437:47:33;12479:3;12464:19;;12437:47;:::i;:::-;12427:57;;11696:794;;;;;;;;;;;:::o;12495:251::-;12565:6;12618:2;12606:9;12597:7;12593:23;12589:32;12586:52;;;12634:1;12631;12624:12;12586:52;12666:9;12660:16;12685:31;12710:5;12685:31;:::i;12751:168::-;12791:7;12857:1;12853;12849:6;12845:14;12842:1;12839:21;12834:1;12827:9;12820:17;12816:45;12813:71;;;12864:18;;:::i;:::-;-1:-1:-1;12904:9:33;;12751:168::o;12924:127::-;12985:10;12980:3;12976:20;12973:1;12966:31;13016:4;13013:1;13006:15;13040:4;13037:1;13030:15;13056:120;13096:1;13122;13112:35;;13127:18;;:::i;:::-;-1:-1:-1;13161:9:33;;13056:120::o;13181:136::-;13216:3;-1:-1:-1;;;13237:22:33;;13234:48;;;13262:18;;:::i;:::-;-1:-1:-1;13302:1:33;13298:13;;13181:136::o;15062:265::-;15101:3;15129:9;;;15154:10;;-1:-1:-1;;;;;15173:27:33;;;15166:35;;15150:52;15147:78;;;15205:18;;:::i;:::-;-1:-1:-1;;;15252:19:33;;;15245:27;;15237:36;;15234:62;;;15276:18;;:::i;:::-;-1:-1:-1;;15312:9:33;;15062:265::o;15332:147::-;15370:3;-1:-1:-1;;;;;15391:30:33;;15388:56;;;15424:18;;:::i;:::-;-1:-1:-1;15471:1:33;15460:13;;15332:147::o;15484:136::-;15523:3;15551:5;15541:39;;15560:18;;:::i;:::-;-1:-1:-1;;;15596:18:33;;15484:136::o;15625:193::-;15664:1;15690;15680:35;;15695:18;;:::i;:::-;-1:-1:-1;;;15731:18:33;;-1:-1:-1;;15751:13:33;;15727:38;15724:64;;;15768:18;;:::i;:::-;-1:-1:-1;15802:10:33;;15625:193::o;16171:135::-;16210:3;-1:-1:-1;;16231:17:33;;16228:43;;;16251:18;;:::i;16311:258::-;16383:1;16393:113;16407:6;16404:1;16401:13;16393:113;;;16483:11;;;16477:18;16464:11;;;16457:39;16429:2;16422:10;16393:113;;;16524:6;16521:1;16518:13;16515:48;;;-1:-1:-1;;16559:1:33;16541:16;;16534:27;16311:258::o;16574:786::-;16985:25;16980:3;16973:38;16955:3;17040:6;17034:13;17056:62;17111:6;17106:2;17101:3;17097:12;17090:4;17082:6;17078:17;17056:62;:::i;:::-;-1:-1:-1;;;17177:2:33;17137:16;;;17169:11;;;17162:40;17227:13;;17249:63;17227:13;17298:2;17290:11;;17283:4;17271:17;;17249:63;:::i;:::-;17332:17;17351:2;17328:26;;16574:786;-1:-1:-1;;;;16574:786:33:o;17365:383::-;17514:2;17503:9;17496:21;17477:4;17546:6;17540:13;17589:6;17584:2;17573:9;17569:18;17562:34;17605:66;17664:6;17659:2;17648:9;17644:18;17639:2;17631:6;17627:15;17605:66;:::i;:::-;17732:2;17711:15;-1:-1:-1;;17707:29:33;17692:45;;;;17739:2;17688:54;;17365:383;-1:-1:-1;;17365:383:33:o;18102:681::-;18270:2;18322:21;;;18392:13;;18295:18;;;18414:22;;;18241:4;18479:17;;;18519:16;;;18241:4;;18270:2;18467;18452:18;;;18241:4;18563:194;18577:6;18574:1;18571:13;18563:194;;;18642:13;;-1:-1:-1;;;;;18638:39:33;18626:52;;18674:1;18733:14;;;;18698:12;;;;18592:9;18563:194;;;-1:-1:-1;18774:3:33;;18102:681;-1:-1:-1;;;;;;18102:681:33:o;18788:659::-;18853:5;18906:3;18899:4;18891:6;18887:17;18883:27;18873:55;;18924:1;18921;18914:12;18873:55;18953:6;18947:13;18979:4;19003:60;19019:43;19059:2;19019:43;:::i;19003:60::-;19097:15;;;19183:1;19179:10;;;;19167:23;;19163:32;;;19128:12;;;;19207:15;;;19204:35;;;19235:1;19232;19225:12;19204:35;19271:2;19263:6;19259:15;19283:135;19299:6;19294:3;19291:15;19283:135;;;19365:10;;19353:23;;19396:12;;;;19316;;19283:135;;;-1:-1:-1;19436:5:33;18788:659;-1:-1:-1;;;;;;18788:659:33:o;19452:1209::-;19581:6;19589;19642:2;19630:9;19621:7;19617:23;19613:32;19610:52;;;19658:1;19655;19648:12;19610:52;19691:9;19685:16;19720:18;19761:2;19753:6;19750:14;19747:34;;;19777:1;19774;19767:12;19747:34;19815:6;19804:9;19800:22;19790:32;;19860:7;19853:4;19849:2;19845:13;19841:27;19831:55;;19882:1;19879;19872:12;19831:55;19911:2;19905:9;19933:4;19957:60;19973:43;20013:2;19973:43;:::i;19957:60::-;20051:15;;;20133:1;20129:10;;;;20121:19;;20117:28;;;20082:12;;;;20157:19;;;20154:39;;;20189:1;20186;20179:12;20154:39;20213:11;;;;20233:210;20249:6;20244:3;20241:15;20233:210;;;20322:3;20316:10;20339:31;20364:5;20339:31;:::i;:::-;20383:18;;20266:12;;;;20421;;;;20233:210;;;20498:18;;;20492:25;20462:5;;-1:-1:-1;20492:25:33;;-1:-1:-1;;;20529:16:33;;;20526:36;;;20558:1;20555;20548:12;20526:36;;20581:74;20647:7;20636:8;20625:9;20621:24;20581:74;:::i;:::-;20571:84;;;19452:1209;;;;;:::o;21134:163::-;21212:13;;21265:6;21254:18;;21244:29;;21234:57;;21287:1;21284;21277:12;21302:1340;21403:6;21434:2;21477;21465:9;21456:7;21452:23;21448:32;21445:52;;;21493:1;21490;21483:12;21445:52;21526:9;21520:16;21555:18;21596:2;21588:6;21585:14;21582:34;;;21612:1;21609;21602:12;21582:34;21635:22;;;;21691:4;21673:16;;;21669:27;21666:47;;;21709:1;21706;21699:12;21666:47;21735:22;;:::i;:::-;21780:32;21809:2;21780:32;:::i;:::-;21773:5;21766:47;21845:41;21882:2;21878;21874:11;21845:41;:::i;:::-;21840:2;21833:5;21829:14;21822:65;21919:41;21956:2;21952;21948:11;21919:41;:::i;:::-;21914:2;21907:5;21903:14;21896:65;21999:2;21995;21991:11;21985:18;22012:33;22037:7;22012:33;:::i;:::-;22072:2;22061:14;;22054:31;22124:3;22116:12;;22110:19;22141:16;;;22138:36;;;22170:1;22167;22160:12;22138:36;22201:8;22197:2;22193:17;22183:27;;;22248:7;22241:4;22237:2;22233:13;22229:27;22219:55;;22270:1;22267;22260:12;22219:55;22299:2;22293:9;22321:2;22317;22314:10;22311:36;;;22327:18;;:::i;:::-;22369:53;22412:2;22393:13;;-1:-1:-1;;22389:27:33;22385:36;;22369:53;:::i;:::-;22356:66;;22445:2;22438:5;22431:17;22485:7;22480:2;22475;22471;22467:11;22463:20;22460:33;22457:53;;;22506:1;22503;22496:12;22457:53;22519:54;22570:2;22565;22558:5;22554:14;22549:2;22545;22541:11;22519:54;:::i;:::-;-1:-1:-1;22600:3:33;22589:15;;22582:30;;;;22593:5;21302:1340;-1:-1:-1;;;;;21302:1340:33:o;22647:830::-;22783:6;22791;22799;22807;22815;22823;22831;22839;22847;22855;22908:3;22896:9;22887:7;22883:23;22879:33;22876:53;;;22925:1;22922;22915:12;22876:53;22954:9;22948:16;22938:26;;23004:2;22993:9;22989:18;22983:25;22973:35;;23048:2;23037:9;23033:18;23027:25;23017:35;;23092:2;23081:9;23077:18;23071:25;23061:35;;23136:3;23125:9;23121:19;23115:26;23105:36;;23160:47;23202:3;23191:9;23187:19;23160:47;:::i;:::-;23150:57;;23226:47;23268:3;23257:9;23253:19;23226:47;:::i;:::-;23216:57;;23292:47;23334:3;23323:9;23319:19;23292:47;:::i;:::-;23282:57;;23358:47;23400:3;23389:9;23385:19;23358:47;:::i;:::-;23348:57;;23424:47;23466:3;23455:9;23451:19;23424:47;:::i;:::-;23414:57;;22647:830;;;;;;;;;;;;;:::o;26930:202::-;26997:6;27050:2;27038:9;27029:7;27025:23;27021:32;27018:52;;;27066:1;27063;27056:12;27018:52;27089:37;27116:9;27089:37;:::i;27896:435::-;27949:3;27987:5;27981:12;28014:6;28009:3;28002:19;28040:4;28069:2;28064:3;28060:12;28053:19;;28106:2;28099:5;28095:14;28127:1;28137:169;28151:6;28148:1;28145:13;28137:169;;;28212:13;;28200:26;;28246:12;;;;28281:15;;;;28173:1;28166:9;28137:169;;;-1:-1:-1;28322:3:33;;27896:435;-1:-1:-1;;;;;27896:435:33:o;28336:1529::-;-1:-1:-1;;;;;28933:15:33;;;28915:34;;28864:3;28968:2;28986:18;;;28979:31;;;29059:13;;28849:19;;;29081:22;;;28816:4;;29161:15;;;;28887:19;;28968:2;29134:3;29119:19;;;28816:4;29204:178;29218:6;29215:1;29212:13;29204:178;;;29283:13;;29279:22;;29267:35;;29357:15;;;;29322:12;;;;29240:1;29233:9;29204:178;;;29208:3;;29427:9;29422:3;29418:19;29413:2;29402:9;29398:18;29391:47;29461:41;29498:3;29490:6;29461:41;:::i;:::-;29447:55;;;;;29550:9;29542:6;29538:22;29533:2;29522:9;29518:18;29511:50;29584:44;29621:6;29613;29584:44;:::i;:::-;-1:-1:-1;;;;;987:31:33;;29679:3;29664:19;;975:44;29721:22;;;29715:3;29700:19;;29693:51;-1:-1:-1;9597:14:33;;24255:6;24244:18;;29854:3;29839:19;;24232:31;9644:4;9635:14;;-1:-1:-1;29813:46:33;;-1:-1:-1;24179:90:33;29870:127;29931:10;29926:3;29922:20;29919:1;29912:31;29962:4;29959:1;29952:15;29986:4;29983:1;29976:15;30382:263;30458:6;30466;30519:2;30507:9;30498:7;30494:23;30490:32;30487:52;;;30535:1;30532;30525:12;30487:52;30564:9;30558:16;30548:26;;30593:46;30635:2;30624:9;30620:18;30593:46;:::i;:::-;30583:56;;30382:263;;;;;:::o;30650:1225::-;30958:4;31006:3;30995:9;30991:19;31037:6;31026:9;31019:25;31063:2;31101:6;31096:2;31085:9;31081:18;31074:34;31127:2;31165:3;31160:2;31149:9;31145:18;31138:31;31189:6;31224;31218:13;31255:6;31247;31240:22;31293:3;31282:9;31278:19;31271:26;;31332:2;31324:6;31320:15;31306:29;;31353:1;31363:385;31377:6;31374:1;31371:13;31363:385;;;31436:13;;31520:9;;-1:-1:-1;;;;;31516:18:33;;;31504:31;;31579:11;;;31573:18;31569:27;31555:12;;;31548:49;31651:11;;31645:18;31638:26;31631:34;31617:12;;;31610:56;31723:15;;;;31695:4;31686:14;;;;31489:1;31392:9;31363:385;;;-1:-1:-1;;;;;;;987:31:33;;31819:4;31804:20;;975:44;31765:3;-1:-1:-1;31777:48:33;;-1:-1:-1;;;921:104:33;31777:48;31862:6;31856:3;31845:9;31841:19;31834:35;30650:1225;;;;;;;;:::o;31880:363::-;31975:6;32028:2;32016:9;32007:7;32003:23;31999:32;31996:52;;;32044:1;32041;32034:12;31996:52;32077:9;32071:16;32110:18;32102:6;32099:30;32096:50;;;32142:1;32139;32132:12;32096:50;32165:72;32229:7;32220:6;32209:9;32205:22;32165:72;:::i;33013:274::-;33142:3;33180:6;33174:13;33196:53;33242:6;33237:3;33230:4;33222:6;33218:17;33196:53;:::i;:::-;33265:16;;;;;33013:274;-1:-1:-1;;33013:274:33:o

Swarm Source

ipfs://981d059dfaa6c075b82a22a796b5a234884ad2a520dc2a196ffd10dfeecf69cb

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ 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.