ETH Price: $3,683.71 (+19.62%)

Token

Vesper pool (vPool)
 

Overview

Max Total Supply

0 vPool

Holders

0

Total Transfers

-

Market

Price

$0.00 @ 0.000000 ETH

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
VPool

Compiler Version
v0.8.9+commit.e5eed63a

Optimization Enabled:
Yes with 100 runs

Other Settings:
default evmVersion, MIT license
File 1 of 23 : IStrategy.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

interface IStrategy {
    function rebalance() external returns (uint256 _profit, uint256 _loss, uint256 _payback);

    function sweep(address _fromToken) external;

    function withdraw(uint256 _amount) external;

    function feeCollector() external view returns (address);

    function isReservedToken(address _token) external view returns (bool);

    function keepers() external view returns (address[] memory);

    function migrate(address _newStrategy) external;

    function token() external view returns (address);

    function pool() external view returns (address);

    // solhint-disable-next-line func-name-mixedcase
    function VERSION() external view returns (string memory);

    function collateral() external view returns (address);
}

File 2 of 23 : Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;

/// @title Errors library
library Errors {
    string public constant INVALID_COLLATERAL_AMOUNT = "1"; // Collateral must be greater than 0 or > defined limit
    string public constant INVALID_SHARE_AMOUNT = "2"; // Share must be greater than 0
    string public constant INVALID_INPUT_LENGTH = "3"; // Input array length must be greater than 0
    string public constant INPUT_LENGTH_MISMATCH = "4"; // Input array length mismatch with another array length
    string public constant NOT_WHITELISTED_ADDRESS = "5"; // Caller is not whitelisted to withdraw without fee
    string public constant MULTI_TRANSFER_FAILED = "6"; // Multi transfer of tokens has failed
    string public constant FEE_COLLECTOR_NOT_SET = "7"; // Fee Collector is not set
    string public constant NOT_ALLOWED_TO_SWEEP = "8"; // Token is not allowed to sweep
    string public constant INSUFFICIENT_BALANCE = "9"; // Insufficient balance to performs operations to follow
    string public constant INPUT_ADDRESS_IS_ZERO = "10"; // Input address is zero
    string public constant FEE_LIMIT_REACHED = "11"; // Fee must be less than MAX_BPS
    string public constant ALREADY_INITIALIZED = "12"; // Data structure, contract, or logic already initialized and can not be called again
    string public constant ADD_IN_LIST_FAILED = "13"; // Cannot add address in address list
    string public constant REMOVE_FROM_LIST_FAILED = "14"; // Cannot remove address from address list
    string public constant STRATEGY_IS_ACTIVE = "15"; // Strategy is already active, an inactive strategy is required
    string public constant STRATEGY_IS_NOT_ACTIVE = "16"; // Strategy is not active, an active strategy is required
    string public constant INVALID_STRATEGY = "17"; // Given strategy is not a strategy of this pool
    string public constant DEBT_RATIO_LIMIT_REACHED = "18"; // Debt ratio limit reached. It must be less than MAX_BPS
    string public constant TOTAL_DEBT_IS_NOT_ZERO = "19"; // Strategy total debt must be 0
    string public constant LOSS_TOO_HIGH = "20"; // Strategy reported loss must be less than current debt
    string public constant INVALID_MAX_BORROW_LIMIT = "21"; // Max borrow limit is beyond range.
    string public constant MAX_LIMIT_LESS_THAN_MIN = "22"; // Max limit should be greater than min limit.
    string public constant INVALID_SLIPPAGE = "23"; // Slippage should be less than MAX_BPS
    string public constant WRONG_RECEIPT_TOKEN = "24"; // Wrong receipt token address
    string public constant AAVE_FLASH_LOAN_NOT_ACTIVE = "25"; // aave flash loan is not active
    string public constant DYDX_FLASH_LOAN_NOT_ACTIVE = "26"; // DYDX flash loan is not active
    string public constant INVALID_FLASH_LOAN = "27"; // invalid-flash-loan
    string public constant INVALID_INITIATOR = "28"; // "invalid-initiator"
    string public constant INCORRECT_WITHDRAW_AMOUNT = "29"; // withdrawn amount is not correct
    string public constant NO_MARKET_ID_FOUND = "30"; // dydx flash loan no marketId found for token
    string public constant SAME_AS_PREVIOUS = "31"; // Input should not be same as previous value.
    string public constant INVALID_INPUT = "32"; // Generic invalid input error code
}

File 3 of 23 : Governable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "./dependencies/openzeppelin/contracts/proxy/utils/Initializable.sol";
import "./dependencies/openzeppelin/contracts/utils/Context.sol";
import "./interfaces/vesper/IGovernable.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (governor) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the governor account will be the one that deploys the contract. This
 * can later be changed with {transferGovernorship}.
 *
 */
abstract contract Governable is IGovernable, Context, Initializable {
    address public governor;
    address private proposedGovernor;

    event UpdatedGovernor(address indexed previousGovernor, address indexed proposedGovernor);

    /**
     * @dev Initializes the contract setting the deployer as the initial governor.
     */
    constructor() {
        address msgSender = _msgSender();
        governor = msgSender;
        emit UpdatedGovernor(address(0), msgSender);
    }

    /**
     * @dev If inheriting child is using proxy then child contract can use
     * __Governable_init() function to initialization this contract
     */
    // solhint-disable-next-line func-name-mixedcase
    function __Governable_init() internal initializer {
        address msgSender = _msgSender();
        governor = msgSender;
        emit UpdatedGovernor(address(0), msgSender);
    }

    /**
     * @dev Throws if called by any account other than the governor.
     */
    modifier onlyGovernor() {
        require(governor == _msgSender(), "not-governor");
        _;
    }

    /**
     * @dev Transfers governorship of the contract to a new account (`proposedGovernor`).
     * Can only be called by the current owner.
     */
    function transferGovernorship(address _proposedGovernor) external onlyGovernor {
        require(_proposedGovernor != address(0), "proposed-governor-is-zero");
        proposedGovernor = _proposedGovernor;
    }

    /**
     * @dev Allows new governor to accept governorship of the contract.
     */
    function acceptGovernorship() external {
        require(proposedGovernor == _msgSender(), "not-the-proposed-governor");
        emit UpdatedGovernor(governor, proposedGovernor);
        governor = proposedGovernor;
        proposedGovernor = address(0);
    }
}

File 4 of 23 : Pausable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "./dependencies/openzeppelin/contracts/utils/Context.sol";
import "./interfaces/vesper/IPausable.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 */
abstract contract Pausable is IPausable, Context {
    event Paused(address account);
    event Shutdown(address account);
    event Unpaused(address account);
    event Open(address account);

    bool public paused;
    bool public stopEverything;

    modifier whenNotPaused() {
        require(!paused, "paused");
        _;
    }
    modifier whenPaused() {
        require(paused, "not-paused");
        _;
    }

    modifier whenNotShutdown() {
        require(!stopEverything, "shutdown");
        _;
    }

    modifier whenShutdown() {
        require(stopEverything, "not-shutdown");
        _;
    }

    /// @dev Pause contract operations, if contract is not paused.
    function _pause() internal virtual whenNotPaused {
        paused = true;
        emit Paused(_msgSender());
    }

    /// @dev Unpause contract operations, allow only if contract is paused and not shutdown.
    function _unpause() internal virtual whenPaused whenNotShutdown {
        paused = false;
        emit Unpaused(_msgSender());
    }

    /// @dev Shutdown contract operations, if not already shutdown.
    function _shutdown() internal virtual whenNotShutdown {
        stopEverything = true;
        paused = true;
        emit Shutdown(_msgSender());
    }

    /// @dev Open contract operations, if contract is in shutdown state
    function _open() internal virtual whenShutdown {
        stopEverything = false;
        emit Open(_msgSender());
    }
}

File 5 of 23 : Initializable.sol
// SPDX-License-Identifier: MIT

// solhint-disable-next-line compiler-version
pragma solidity ^0.8.0;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 */
abstract contract Initializable {

    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

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

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(_initializing || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }
}

File 6 of 23 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

    uint256 private _status;

    constructor () {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

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

        _;

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

File 7 of 23 : IERC20.sol
// SPDX-License-Identifier: MIT

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

File 8 of 23 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "../IERC20.sol";

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

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

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

File 9 of 23 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

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

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

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

File 10 of 23 : SafeERC20.sol
// SPDX-License-Identifier: MIT

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'
        // solhint-disable-next-line max-line-length
        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
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 11 of 23 : Address.sol
// SPDX-License-Identifier: MIT

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;
        // solhint-disable-next-line no-inline-assembly
        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");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (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");

        // solhint-disable-next-line avoid-low-level-calls
        (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");

        // solhint-disable-next-line avoid-low-level-calls
        (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");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private 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

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 12 of 23 : Context.sol
// SPDX-License-Identifier: MIT

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) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 13 of 23 : ECDSA.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        // Divide the signature in r, s and v variables
        bytes32 r;
        bytes32 s;
        uint8 v;

        // Check the signature length
        // - case 65: r,s,v signature (standard)
        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
        if (signature.length == 65) {
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            // solhint-disable-next-line no-inline-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
        } else if (signature.length == 64) {
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            // solhint-disable-next-line no-inline-assembly
            assembly {
                let vs := mload(add(signature, 0x40))
                r := mload(add(signature, 0x20))
                s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
                v := add(shr(255, vs), 27)
            }
        } else {
            revert("ECDSA: invalid signature length");
        }

        return recover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value");
        require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value");

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        require(signer != address(0), "ECDSA: invalid signature");

        return signer;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 14 of 23 : EnumerableSet.sol
// SPDX-License-Identifier: MIT

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

File 15 of 23 : IGovernable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

/**
 * @notice Governable interface
 */
interface IGovernable {
    function governor() external view returns (address _governor);

    function transferGovernorship(address _proposedGovernor) external;
}

File 16 of 23 : IPausable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

/**
 * @notice Pausable interface
 */
interface IPausable {
    function paused() external view returns (bool);

    function stopEverything() external view returns (bool);

    function pause() external;

    function unpause() external;

    function shutdown() external;

    function open() external;
}

File 17 of 23 : IPoolAccountant.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

interface IPoolAccountant {
    function decreaseDebt(address strategy_, uint256 decreaseBy_) external;

    function migrateStrategy(address old_, address new_) external;

    function reportEarning(
        address strategy_,
        uint256 profit_,
        uint256 loss_,
        uint256 payback_
    ) external returns (uint256 _actualPayback, uint256 _creditLine);

    function reportLoss(address strategy_, uint256 loss_) external;

    function availableCreditLimit(address strategy_) external view returns (uint256);

    function excessDebt(address strategy_) external view returns (uint256);

    function getStrategies() external view returns (address[] memory);

    function getWithdrawQueue() external view returns (address[] memory);

    function strategy(
        address strategy_
    )
        external
        view
        returns (
            bool _active,
            uint256 _interestFee, // Obsolete
            uint256 _debtRate, // Obsolete
            uint256 _lastRebalance,
            uint256 _totalDebt,
            uint256 _totalLoss,
            uint256 _totalProfit,
            uint256 _debtRatio,
            uint256 _externalDepositFee
        );

    function externalDepositFee() external view returns (uint256);

    function totalDebt() external view returns (uint256);

    function totalDebtOf(address strategy_) external view returns (uint256);

    function totalDebtRatio() external view returns (uint256);
}

File 18 of 23 : IPoolRewards.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

interface IPoolRewards {
    /// Emitted after reward added
    event RewardAdded(address indexed rewardToken, uint256 reward, uint256 rewardDuration);
    /// Emitted whenever any user claim rewards
    event RewardPaid(address indexed user, address indexed rewardToken, uint256 reward);
    /// Emitted after adding new rewards token into rewardTokens array
    event RewardTokenAdded(address indexed rewardToken, address[] existingRewardTokens);

    function claimReward(address) external;

    function notifyRewardAmount(address rewardToken_, uint256 _rewardAmount, uint256 _rewardDuration) external;

    function notifyRewardAmount(
        address[] memory rewardTokens_,
        uint256[] memory rewardAmounts_,
        uint256[] memory rewardDurations_
    ) external;

    function updateReward(address) external;

    function claimable(
        address account_
    ) external view returns (address[] memory _rewardTokens, uint256[] memory _claimableAmounts);

    function lastTimeRewardApplicable(address rewardToken_) external view returns (uint256);

    function rewardForDuration()
        external
        view
        returns (address[] memory _rewardTokens, uint256[] memory _rewardForDuration);

    function rewardPerToken()
        external
        view
        returns (address[] memory _rewardTokens, uint256[] memory _rewardPerTokenRate);
}

File 19 of 23 : IVesperPool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../../dependencies/openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./IGovernable.sol";
import "./IPausable.sol";

interface IVesperPool is IGovernable, IPausable, IERC20Metadata {
    function calculateUniversalFee(uint256 profit_) external view returns (uint256 _fee);

    function deposit(uint256 collateralAmount_) external;

    function excessDebt(address strategy_) external view returns (uint256);

    function poolAccountant() external view returns (address);

    function poolRewards() external view returns (address);

    function reportEarning(uint256 profit_, uint256 loss_, uint256 payback_) external;

    function reportLoss(uint256 loss_) external;

    function sweepERC20(address fromToken_) external;

    function withdraw(uint256 share_) external;

    function keepers() external view returns (address[] memory);

    function isKeeper(address address_) external view returns (bool);

    function maintainers() external view returns (address[] memory);

    function isMaintainer(address address_) external view returns (bool);

    function pricePerShare() external view returns (uint256);

    function strategy(
        address strategy_
    )
        external
        view
        returns (
            bool _active,
            uint256 _interestFee, // Obsolete
            uint256 _debtRate, // Obsolete
            uint256 _lastRebalance,
            uint256 _totalDebt,
            uint256 _totalLoss,
            uint256 _totalProfit,
            uint256 _debtRatio,
            uint256 _externalDepositFee
        );

    function token() external view returns (IERC20);

    function tokensHere() external view returns (uint256);

    function totalDebtOf(address strategy_) external view returns (uint256);

    function totalValue() external view returns (uint256);

    function totalDebt() external view returns (uint256);
}

File 20 of 23 : PoolERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../dependencies/openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../dependencies/openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../dependencies/openzeppelin/contracts/utils/Context.sol";

// solhint-disable reason-string, no-empty-blocks
///@title Pool ERC20 to use with proxy. Inspired by OpenZeppelin ERC20
abstract contract PoolERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Sets the values for {name} and {symbol} for proxy
     */
    // solhint-disable-next-line func-name-mixedcase
    function __ERC20_init(string memory name_, string memory symbol_) internal {
        _name = name_;
        _symbol = symbol_;
    }

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

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

    /**
     * @dev Returns the decimals of the token. default to 18
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev Returns total supply of the token.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev  Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

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

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

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * Requirements:
     *
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        _approve(sender, _msgSender(), currentAllowance - amount);

        return true;
    }

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

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        _balances[sender] = senderBalance - amount;
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);
    }

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

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

        _totalSupply += amount;
        _balances[account] += amount;

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

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

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

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        _balances[account] = accountBalance - amount;
        _totalSupply -= amount;

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

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

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

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

File 21 of 23 : PoolERC20Permit.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../dependencies/openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "../dependencies/openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "./PoolERC20.sol";

///@title Pool ERC20 Permit to use with proxy. Inspired by OpenZeppelin ERC20Permit
// solhint-disable var-name-mixedcase
abstract contract PoolERC20Permit is PoolERC20, IERC20Permit {
    bytes32 private constant _EIP712_VERSION = keccak256(bytes("1"));
    bytes32 private constant _EIP712_DOMAIN_TYPEHASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
    bytes32 private constant _PERMIT_TYPEHASH =
        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    bytes32 private _CACHED_DOMAIN_SEPARATOR;
    bytes32 private _HASHED_NAME;
    uint256 private _CACHED_CHAIN_ID;

    /**
     * @dev See {IERC20Permit-nonces}.
     */
    mapping(address => uint256) public override nonces;

    /**
     * @dev Initializes the domain separator using the `name` parameter, and setting `version` to `"1"`.
     * It's a good idea to use the same `name` that is defined as the ERC20 token name.
     */
    // solhint-disable-next-line func-name-mixedcase
    function __ERC20Permit_init(string memory name_) internal {
        _HASHED_NAME = keccak256(bytes(name_));
        _CACHED_CHAIN_ID = block.chainid;
        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(_EIP712_DOMAIN_TYPEHASH, _HASHED_NAME, _EIP712_VERSION);
    }

    /**
     * @dev See {IERC20Permit-permit}.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual override {
        // solhint-disable-next-line not-rely-on-time
        require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
        uint256 _currentNonce = nonces[owner];
        bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _currentNonce, deadline));
        bytes32 hash = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash));

        address signer = ECDSA.recover(hash, v, r, s);
        require(signer == owner, "ERC20Permit: invalid signature");
        nonces[owner] = _currentNonce + 1;
        _approve(owner, spender, value);
    }

    /**
     * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view override returns (bytes32) {
        return _domainSeparatorV4();
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() private view returns (bytes32) {
        if (block.chainid == _CACHED_CHAIN_ID) {
            return _CACHED_DOMAIN_SEPARATOR;
        } else {
            return _buildDomainSeparator(_EIP712_DOMAIN_TYPEHASH, _HASHED_NAME, _EIP712_VERSION);
        }
    }

    function _buildDomainSeparator(bytes32 typeHash, bytes32 name, bytes32 version) private view returns (bytes32) {
        return keccak256(abi.encode(typeHash, name, version, block.chainid, address(this)));
    }
}

File 22 of 23 : PoolStorage.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../dependencies/openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../dependencies/openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "../interfaces/vesper/IVesperPool.sol";

abstract contract PoolStorageV1 is IVesperPool {
    ///@notice Collateral token address
    IERC20 public token;
    /// @notice PoolAccountant address
    address public poolAccountant;
    /// @notice PoolRewards contract address
    address public poolRewards;
    address private feeWhitelistObsolete; // Obsolete in favor of AddressSet of feeWhitelist
    address private keepersObsolete; // Obsolete in favor of AddressSet of keepers
    address private maintainersObsolete; // Obsolete in favor of AddressSet of maintainers
    address private feeCollectorObsolete; // Fee collector address. Obsolete as there is no fee to collect
    uint256 private withdrawFeeObsolete; // Withdraw fee for this pool. Obsolete in favor of universal fee
    uint256 private decimalConversionFactorObsolete; // It can be used in converting value to/from 18 decimals
    bool internal withdrawInETH; // This flag will be used by VETH pool as switch to withdraw ETH or WETH
}

abstract contract PoolStorageV2 is PoolStorageV1 {
    EnumerableSet.AddressSet private _feeWhitelistObsolete; // Obsolete in favor of universal fee
    EnumerableSet.AddressSet internal _keepers; // List of keeper addresses
    EnumerableSet.AddressSet internal _maintainers; // List of maintainer addresses
}

abstract contract PoolStorageV3 is PoolStorageV2 {
    /// @notice Universal fee of this pool. Default to 2%
    uint256 public universalFee = 200;
    /// @notice Maximum percentage of profit that can be counted as universal fee. Default to 50%
    uint256 public maxProfitAsFee = 5_000;
    /// @notice Minimum deposit limit.
    /// @dev Do not set it to 0 as deposit() is checking if amount >= limit
    uint256 public minDepositLimit = 1;
}

File 23 of 23 : VPool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.9;

import "../dependencies/openzeppelin/contracts/proxy/utils/Initializable.sol";
import "../dependencies/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../dependencies/openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./PoolERC20Permit.sol";
import "./PoolStorage.sol";
import "../Errors.sol";
import "../Governable.sol";
import "../Pausable.sol";
import "../interfaces/vesper/IPoolAccountant.sol";
import "../interfaces/vesper/IPoolRewards.sol";
import "vesper-commons/contracts/interfaces/vesper/IStrategy.sol";

/// @title Holding pool share token
// solhint-disable no-empty-blocks
contract VPool is Initializable, PoolERC20Permit, Governable, Pausable, ReentrancyGuard, PoolStorageV3 {
    using SafeERC20 for IERC20;
    using EnumerableSet for EnumerableSet.AddressSet;

    string public constant VERSION = "5.1.0";

    uint256 public constant MAX_BPS = 10_000;
    // For simplicity we are assuming 365 days as 1 year
    uint256 public constant ONE_YEAR = 365 days;

    event UpdatedMaximumProfitAsFee(uint256 oldMaxProfitAsFee, uint256 newMaxProfitAsFee);
    event UpdatedMinimumDepositLimit(uint256 oldDepositLimit, uint256 newDepositLimit);
    event Deposit(address indexed owner, uint256 shares, uint256 amount);
    event Withdraw(address indexed owner, uint256 shares, uint256 amount);
    event UpdatedUniversalFee(uint256 oldUniversalFee, uint256 newUniversalFee);
    event UpdatedPoolRewards(address indexed previousPoolRewards, address indexed newPoolRewards);
    event UpdatedWithdrawFee(uint256 previousWithdrawFee, uint256 newWithdrawFee);
    event UniversalFeePaid(uint256 strategyDebt, uint256 profit, uint256 fee);

    // We are using constructor to initialize implementation with basic details
    constructor(string memory name_, string memory symbol_, address token_) PoolERC20(name_, symbol_) {
        // 0x0 is acceptable as has no effect on functionality
        token = IERC20(token_);
    }

    /// @dev Equivalent to constructor for proxy. It can be called only once per proxy.
    function initialize(
        string memory name_,
        string memory symbol_,
        address token_,
        address poolAccountant_
    ) public initializer {
        require(token_ != address(0), Errors.INPUT_ADDRESS_IS_ZERO);
        require(poolAccountant_ != address(0), Errors.INPUT_ADDRESS_IS_ZERO);
        __ERC20_init(name_, symbol_);
        __ERC20Permit_init(name_);
        __Governable_init();
        token = IERC20(token_);

        require(_keepers.add(_msgSender()), Errors.ADD_IN_LIST_FAILED);
        require(_maintainers.add(_msgSender()), Errors.ADD_IN_LIST_FAILED);
        poolAccountant = poolAccountant_;
        universalFee = 200; // 2%
        maxProfitAsFee = 5_000; // 50%
        minDepositLimit = 1;
    }

    modifier onlyKeeper() {
        require(governor == _msgSender() || _keepers.contains(_msgSender()), "not-a-keeper");
        _;
    }

    modifier onlyMaintainer() {
        require(governor == _msgSender() || _maintainers.contains(_msgSender()), "not-a-maintainer");
        _;
    }

    /**
     * @notice Get available credit limit of strategy. This is the amount strategy can borrow from pool
     * @dev Available credit limit is calculated based on current debt of pool and strategy, current debt limit of pool and strategy.
     * credit available = min(pool's debt limit, strategy's debt limit, max debt per rebalance)
     * when some strategy do not pay back outstanding debt, this impact credit line of other strategy if totalDebt of pool >= debtLimit of pool
     * @param strategy_ Strategy address
     */
    function availableCreditLimit(address strategy_) external view returns (uint256) {
        return IPoolAccountant(poolAccountant).availableCreditLimit(strategy_);
    }

    /**
     * @notice Calculate how much shares user will get for given amount. Also return externalDepositFee if any.
     * @param amount_ Collateral amount
     * @return _shares Amount of share that user will get
     * @dev Amount should be >= minimum deposit limit which default to 1
     */
    function calculateMintage(uint256 amount_) public view returns (uint256 _shares) {
        require(amount_ >= minDepositLimit, Errors.INVALID_COLLATERAL_AMOUNT);
        uint256 _externalDepositFee = (amount_ * IPoolAccountant(poolAccountant).externalDepositFee()) / MAX_BPS;
        _shares = _calculateShares(amount_ - _externalDepositFee);
    }

    /**
     * @notice Calculate universal fee for calling strategy. This is only strategy function.
     * @dev Earn strategies will call this during rebalance.
     */
    function calculateUniversalFee(uint256 profit_) external view returns (uint256 _fee) {
        return _calculateUniversalFee(_msgSender(), profit_);
    }

    /**
     * @notice Deposit ERC20 tokens and receive pool shares depending on the current share price.
     * @param amount_ ERC20 token amount.
     */
    function deposit(uint256 amount_) external nonReentrant whenNotPaused {
        _updateRewards(_msgSender());
        _deposit(amount_);
    }

    /**
     * @notice Deposit ERC20 tokens and claim rewards if any
     * @param amount_ ERC20 token amount.
     */
    function depositAndClaim(uint256 amount_) external nonReentrant whenNotPaused {
        _claimRewards(_msgSender());
        _deposit(amount_);
    }

    /**
     * @notice Deposit ERC20 tokens with permit aka gasless approval.
     * @param amount_ ERC20 token amount.
     * @param deadline_ The time at which signature will expire
     * @param v_ The recovery byte of the signature
     * @param r_ Half of the ECDSA signature pair
     * @param s_ Half of the ECDSA signature pair
     */
    function depositWithPermit(
        uint256 amount_,
        uint256 deadline_,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) external nonReentrant whenNotPaused {
        IERC20Permit(address(token)).permit(_msgSender(), address(this), amount_, deadline_, v_, r_, s_);
        _updateRewards(_msgSender());
        _deposit(amount_);
    }

    /**
     * @notice Debt above current debt limit
     * @param strategy_ Address of strategy
     */
    function excessDebt(address strategy_) external view returns (uint256) {
        return IPoolAccountant(poolAccountant).excessDebt(strategy_);
    }

    function getStrategies() external view returns (address[] memory) {
        return IPoolAccountant(poolAccountant).getStrategies();
    }

    function getWithdrawQueue() public view returns (address[] memory) {
        return IPoolAccountant(poolAccountant).getWithdrawQueue();
    }

    /**
     * @notice Get price per share
     * @dev Return value will be in token defined decimals.
     */
    function pricePerShare() public view returns (uint256) {
        if (totalSupply() == 0 || totalValue() == 0) {
            return 10 ** IERC20Metadata(address(token)).decimals();
        }
        return (totalValue() * 1e18) / totalSupply();
    }

    /**
     * @notice Strategy call this in regular interval. Only strategy function.
     * @param profit_ yield generated by strategy. Strategy get performance fee on this amount
     * @param loss_  Reduce debt ,also reduce debtRatio, increase loss in record.
     * @param payback_ strategy willing to payback outstanding above debtLimit. no performance fee on this amount.
     *  when governance has reduced debtRatio of strategy, strategy will report profit and payback amount separately.
     */
    function reportEarning(uint256 profit_, uint256 loss_, uint256 payback_) external {
        address _strategy = _msgSender();
        // Calculate universal fee
        if (profit_ > 0) {
            (, , , uint256 _lastRebalanceAt, uint256 _totalDebt, , , , ) = IPoolAccountant(poolAccountant).strategy(
                _strategy
            );
            uint256 _fee = _calculateUniversalFee(_lastRebalanceAt, _totalDebt, profit_);
            // Mint shares equal to universal fee
            if (_fee > 0) {
                _mint(IStrategy(_strategy).feeCollector(), _calculateShares(_fee));
                emit UniversalFeePaid(_totalDebt, profit_, _fee);
            }
        }

        // Report earning in pool accountant
        (uint256 _actualPayback, uint256 _creditLine) = IPoolAccountant(poolAccountant).reportEarning(
            _strategy,
            profit_,
            loss_,
            payback_
        );
        uint256 _totalPayback = profit_ + _actualPayback;
        // After payback, if strategy has credit line available then send more fund to strategy
        // If payback is more than available credit line then get fund from strategy
        if (_totalPayback < _creditLine) {
            token.safeTransfer(_strategy, _creditLine - _totalPayback);
        } else if (_totalPayback > _creditLine) {
            token.safeTransferFrom(_strategy, address(this), _totalPayback - _creditLine);
        }
    }

    /**
     * @notice Report loss outside of rebalance activity.
     * @dev Some strategies pay deposit fee thus realizing loss at deposit.
     * For example: Curve's 3pool has some slippage due to deposit of one asset in 3pool.
     * Strategy may want report this loss instead of waiting for next rebalance.
     * @param loss_ Loss that strategy want to report
     */
    function reportLoss(uint256 loss_) external {
        if (loss_ > 0) {
            IPoolAccountant(poolAccountant).reportLoss(_msgSender(), loss_);
        }
    }

    function strategy(
        address strategy_
    )
        public
        view
        returns (
            bool _active,
            uint256 _interestFee, // Obsolete
            uint256 _debtRate, // Obsolete
            uint256 _lastRebalance,
            uint256 _totalDebt,
            uint256 _totalLoss,
            uint256 _totalProfit,
            uint256 _debtRatio,
            uint256 _externalDepositFee
        )
    {
        return IPoolAccountant(poolAccountant).strategy(strategy_);
    }

    /// @dev Returns the token stored in the pool. It will be in token defined decimals.
    function tokensHere() public view returns (uint256) {
        return token.balanceOf(address(this));
    }

    /// @notice Get total debt of pool
    function totalDebt() external view returns (uint256) {
        return IPoolAccountant(poolAccountant).totalDebt();
    }

    /**
     * @notice Get total debt of given strategy
     * @param strategy_ Strategy address
     */
    function totalDebtOf(address strategy_) external view returns (uint256) {
        return IPoolAccountant(poolAccountant).totalDebtOf(strategy_);
    }

    /// @notice Get total debt ratio. Total debt ratio helps us keep buffer in pool
    function totalDebtRatio() external view returns (uint256) {
        return IPoolAccountant(poolAccountant).totalDebtRatio();
    }

    /**
     * @notice Returns sum of token locked in other contracts and token stored in the pool.
     * It will be in token defined decimals.
     */
    function totalValue() public view returns (uint256) {
        return IPoolAccountant(poolAccountant).totalDebt() + tokensHere();
    }

    /**
     * @notice Withdraw collateral based on given shares and the current share price.
     * Burn remaining shares and return collateral.
     * @param shares_ Pool shares. It will be in 18 decimals.
     */
    function withdraw(uint256 shares_) external nonReentrant whenNotShutdown {
        _updateRewards(_msgSender());
        _withdraw(shares_);
    }

    /**
     * @notice Withdraw collateral and claim rewards if any
     * @param shares_ Pool shares. It will be in 18 decimals.
     */
    function withdrawAndClaim(uint256 shares_) external nonReentrant whenNotShutdown {
        _claimRewards(_msgSender());
        _withdraw(shares_);
    }

    /**
     * @dev Hook that is called just after burning tokens.
     * @param amount_ Collateral amount in collateral token defined decimals.
     */
    function _afterBurning(uint256 amount_) internal virtual returns (uint256) {
        token.safeTransfer(_msgSender(), amount_);
        return amount_;
    }

    /**
     * @dev Before burning hook.
     * withdraw amount from strategies
     */
    function _beforeBurning(uint256 share_) private returns (uint256 _amount, bool _isPartial) {
        _amount = (share_ * pricePerShare()) / 1e18;
        uint256 _tokensHere = tokensHere();
        // Check for partial withdraw scenario
        // If we do not have enough tokens then withdraw whats needed from strategy
        if (_amount > _tokensHere) {
            // Strategy may withdraw partial
            _withdrawCollateral(_amount - _tokensHere);
            _tokensHere = tokensHere();
            if (_amount > _tokensHere) {
                _amount = _tokensHere;
                _isPartial = true;
            }
        }
        require(_amount > 0, Errors.INVALID_COLLATERAL_AMOUNT);
    }

    /**
     * @dev Calculate shares to mint/burn based on the current share price and given amount.
     * @param amount_ Collateral amount in collateral token defined decimals.
     * @return share amount in 18 decimal
     */
    function _calculateShares(uint256 amount_) private view returns (uint256) {
        uint256 _share = ((amount_ * 1e18) / pricePerShare());
        return amount_ > ((_share * pricePerShare()) / 1e18) ? _share + 1 : _share;
    }

    /**
     * @dev Calculate universal fee based on strategy's TVL, profit earned and duration between rebalance and now.
     */
    function _calculateUniversalFee(address strategy_, uint256 profit_) private view returns (uint256 _fee) {
        // Calculate universal fee
        (, , , uint256 _lastRebalance, uint256 _totalDebt, , , , ) = IPoolAccountant(poolAccountant).strategy(
            strategy_
        );
        return _calculateUniversalFee(_lastRebalance, _totalDebt, profit_);
    }

    function _calculateUniversalFee(
        uint256 lastRebalance_,
        uint256 totalDebt_,
        uint256 profit_
    ) private view returns (uint256 _fee) {
        _fee = (universalFee * (block.timestamp - lastRebalance_) * totalDebt_) / (MAX_BPS * ONE_YEAR);
        uint256 _maxFee = (profit_ * maxProfitAsFee) / MAX_BPS;
        if (_fee > _maxFee) {
            _fee = _maxFee;
        }
    }

    /// @notice claim rewards of account
    function _claimRewards(address account_) internal {
        if (poolRewards != address(0)) {
            IPoolRewards(poolRewards).claimReward(account_);
        }
    }

    /// @dev Deposit incoming token and mint pool token i.e. shares.
    function _deposit(uint256 amount_) internal {
        uint256 _shares = calculateMintage(amount_);
        token.safeTransferFrom(_msgSender(), address(this), amount_);
        _mint(_msgSender(), _shares);
        emit Deposit(_msgSender(), _shares, amount_);
    }

    /// @dev Update pool rewards of sender and receiver during transfer.
    /// @dev _beforeTokenTransfer can be used to replace _transfer and _updateRewards but that
    /// will increase gas cost of deposit, withdraw and transfer.
    function _transfer(address sender_, address recipient_, uint256 amount_) internal override {
        if (poolRewards != address(0)) {
            IPoolRewards(poolRewards).updateReward(sender_);
            IPoolRewards(poolRewards).updateReward(recipient_);
        }
        super._transfer(sender_, recipient_, amount_);
    }

    function _updateRewards(address account_) internal {
        if (poolRewards != address(0)) {
            IPoolRewards(poolRewards).updateReward(account_);
        }
    }

    /// @dev Burns shares and returns the collateral value, after fee, of those.
    function _withdraw(uint256 shares_) internal {
        require(shares_ > 0, Errors.INVALID_SHARE_AMOUNT);

        (uint256 _amountWithdrawn, bool _isPartial) = _beforeBurning(shares_);
        // There may be scenarios when pool is not able to withdraw all of requested amount
        if (_isPartial) {
            // Recalculate proportional share on actual amount withdrawn
            uint256 _proportionalShares = _calculateShares(_amountWithdrawn);
            if (_proportionalShares < shares_) {
                shares_ = _proportionalShares;
            }
        }
        _burn(_msgSender(), shares_);
        _afterBurning(_amountWithdrawn);
        emit Withdraw(_msgSender(), shares_, _amountWithdrawn);
    }

    function _withdrawCollateral(uint256 amount_) internal {
        // Withdraw amount from queue
        uint256 _debt;
        uint256 _balanceBefore;
        uint256 _amountWithdrawn;
        uint256 _totalAmountWithdrawn;
        address[] memory _withdrawQueue = getWithdrawQueue();
        uint256 _len = _withdrawQueue.length;
        for (uint256 i; i < _len; i++) {
            uint256 _amountNeeded = amount_ - _totalAmountWithdrawn;
            address _strategy = _withdrawQueue[i];
            _debt = IPoolAccountant(poolAccountant).totalDebtOf(_strategy);
            if (_debt == 0) {
                continue;
            }
            if (_amountNeeded > _debt) {
                // Should not withdraw more than current debt of strategy.
                _amountNeeded = _debt;
            }
            _balanceBefore = tokensHere();
            //solhint-disable no-empty-blocks
            try IStrategy(_strategy).withdraw(_amountNeeded) {} catch {
                continue;
            }
            _amountWithdrawn = tokensHere() - _balanceBefore;
            // Adjusting totalDebt. Assuming that during next reportEarning(), strategy will report loss if amountWithdrawn < _amountNeeded
            IPoolAccountant(poolAccountant).decreaseDebt(_strategy, _amountWithdrawn);
            _totalAmountWithdrawn += _amountWithdrawn;
            if (_totalAmountWithdrawn >= amount_) {
                // withdraw done
                break;
            }
        }
    }

    /************************************************************************************************
     *                                     Authorized function                                      *
     ***********************************************************************************************/

    ////////////////////////////// Only Governor //////////////////////////////

    /**
     * @notice Migrate existing strategy to new strategy.
     * @dev Migrating strategy aka old and new strategy should be of same type.
     * @param old_ Address of strategy being migrated
     * @param new_ Address of new strategy
     */
    function migrateStrategy(address old_, address new_) external onlyGovernor {
        require(
            IStrategy(new_).pool() == address(this) && IStrategy(old_).pool() == address(this),
            Errors.INVALID_STRATEGY
        );
        IPoolAccountant(poolAccountant).migrateStrategy(old_, new_);
        IStrategy(old_).migrate(new_);
    }

    /**
     * Only Governor:: Update maximum profit that can be used as universal fee
     * @param newMaxProfitAsFee_ New max profit as fee
     */
    function updateMaximumProfitAsFee(uint256 newMaxProfitAsFee_) external onlyGovernor {
        require(newMaxProfitAsFee_ != maxProfitAsFee, Errors.SAME_AS_PREVIOUS);
        emit UpdatedMaximumProfitAsFee(maxProfitAsFee, newMaxProfitAsFee_);
        maxProfitAsFee = newMaxProfitAsFee_;
    }

    /**
     * Only Governor:: Update minimum deposit limit
     * @param newLimit_ New minimum deposit limit
     */
    function updateMinimumDepositLimit(uint256 newLimit_) external onlyGovernor {
        require(newLimit_ > 0, Errors.INVALID_INPUT);
        require(newLimit_ != minDepositLimit, Errors.SAME_AS_PREVIOUS);
        emit UpdatedMinimumDepositLimit(minDepositLimit, newLimit_);
        minDepositLimit = newLimit_;
    }

    /**
     * @notice Update pool rewards address for this pool
     * @param newPoolRewards_ new pool rewards address
     */
    function updatePoolRewards(address newPoolRewards_) external onlyGovernor {
        require(newPoolRewards_ != address(0), Errors.INPUT_ADDRESS_IS_ZERO);
        emit UpdatedPoolRewards(poolRewards, newPoolRewards_);
        poolRewards = newPoolRewards_;
    }

    /**
     * @notice Update universal fee for this pool
     * @dev Format: 1500 = 15% fee, 100 = 1%
     * @param newUniversalFee_ new universal fee
     */
    function updateUniversalFee(uint256 newUniversalFee_) external onlyGovernor {
        require(newUniversalFee_ <= MAX_BPS, Errors.FEE_LIMIT_REACHED);
        emit UpdatedUniversalFee(universalFee, newUniversalFee_);
        universalFee = newUniversalFee_;
    }

    ///////////////////////////// Only Keeper ///////////////////////////////
    /**
     * @dev Transfer given ERC20 token to governor
     * @param fromToken_ Token address to sweep
     */
    function sweepERC20(address fromToken_) external onlyKeeper {
        require(fromToken_ != address(token), Errors.NOT_ALLOWED_TO_SWEEP);
        IERC20(fromToken_).safeTransfer(governor, IERC20(fromToken_).balanceOf(address(this)));
    }

    function pause() external onlyKeeper {
        _pause();
    }

    function unpause() external onlyKeeper {
        _unpause();
    }

    function shutdown() external onlyKeeper {
        _shutdown();
    }

    function open() external onlyKeeper {
        _open();
    }

    /// @notice Return list of keepers
    function keepers() external view returns (address[] memory) {
        return _keepers.values();
    }

    function isKeeper(address address_) external view returns (bool) {
        return _keepers.contains(address_);
    }

    /**
     * @notice Add given address in keepers list.
     * @param keeperAddress_ keeper address to add.
     */
    function addKeeper(address keeperAddress_) external onlyKeeper {
        require(_keepers.add(keeperAddress_), Errors.ADD_IN_LIST_FAILED);
    }

    /**
     * @notice Remove given address from keepers list.
     * @param keeperAddress_ keeper address to remove.
     */
    function removeKeeper(address keeperAddress_) external onlyKeeper {
        require(_keepers.remove(keeperAddress_), Errors.REMOVE_FROM_LIST_FAILED);
    }

    /// @notice Return list of maintainers
    function maintainers() external view returns (address[] memory) {
        return _maintainers.values();
    }

    function isMaintainer(address address_) external view returns (bool) {
        return _maintainers.contains(address_);
    }

    /**
     * @notice Add given address in maintainers list.
     * @param maintainerAddress_ maintainer address to add.
     */
    function addMaintainer(address maintainerAddress_) external onlyKeeper {
        require(_maintainers.add(maintainerAddress_), Errors.ADD_IN_LIST_FAILED);
    }

    /**
     * @notice Remove given address from maintainers list.
     * @param maintainerAddress_ maintainer address to remove.
     */
    function removeMaintainer(address maintainerAddress_) external onlyKeeper {
        require(_maintainers.remove(maintainerAddress_), Errors.REMOVE_FROM_LIST_FAILED);
    }

    ///////////////////////////////////////////////////////////////////////////
}

Settings
{
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 100
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"address","name":"token_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Open","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Shutdown","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"strategyDebt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"UniversalFeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernor","type":"address"},{"indexed":true,"internalType":"address","name":"proposedGovernor","type":"address"}],"name":"UpdatedGovernor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaxProfitAsFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxProfitAsFee","type":"uint256"}],"name":"UpdatedMaximumProfitAsFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldDepositLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDepositLimit","type":"uint256"}],"name":"UpdatedMinimumDepositLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousPoolRewards","type":"address"},{"indexed":true,"internalType":"address","name":"newPoolRewards","type":"address"}],"name":"UpdatedPoolRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldUniversalFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newUniversalFee","type":"uint256"}],"name":"UpdatedUniversalFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousWithdrawFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newWithdrawFee","type":"uint256"}],"name":"UpdatedWithdrawFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BPS","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":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptGovernorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"keeperAddress_","type":"address"}],"name":"addKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"maintainerAddress_","type":"address"}],"name":"addMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"strategy_","type":"address"}],"name":"availableCreditLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"calculateMintage","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"profit_","type":"uint256"}],"name":"calculateUniversalFee","outputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"depositAndClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"depositWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"strategy_","type":"address"}],"name":"excessDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStrategies","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawQueue","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"address","name":"token_","type":"address"},{"internalType":"address","name":"poolAccountant_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"address_","type":"address"}],"name":"isKeeper","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"address_","type":"address"}],"name":"isMaintainer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keepers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maintainers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxProfitAsFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"old_","type":"address"},{"internalType":"address","name":"new_","type":"address"}],"name":"migrateStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minDepositLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"open","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":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"poolAccountant","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolRewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"keeperAddress_","type":"address"}],"name":"removeKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"maintainerAddress_","type":"address"}],"name":"removeMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"profit_","type":"uint256"},{"internalType":"uint256","name":"loss_","type":"uint256"},{"internalType":"uint256","name":"payback_","type":"uint256"}],"name":"reportEarning","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loss_","type":"uint256"}],"name":"reportLoss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopEverything","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"strategy_","type":"address"}],"name":"strategy","outputs":[{"internalType":"bool","name":"_active","type":"bool"},{"internalType":"uint256","name":"_interestFee","type":"uint256"},{"internalType":"uint256","name":"_debtRate","type":"uint256"},{"internalType":"uint256","name":"_lastRebalance","type":"uint256"},{"internalType":"uint256","name":"_totalDebt","type":"uint256"},{"internalType":"uint256","name":"_totalLoss","type":"uint256"},{"internalType":"uint256","name":"_totalProfit","type":"uint256"},{"internalType":"uint256","name":"_debtRatio","type":"uint256"},{"internalType":"uint256","name":"_externalDepositFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromToken_","type":"address"}],"name":"sweepERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokensHere","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"strategy_","type":"address"}],"name":"totalDebtOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDebtRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_proposedGovernor","type":"address"}],"name":"transferGovernorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"universalFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMaxProfitAsFee_","type":"uint256"}],"name":"updateMaximumProfitAsFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLimit_","type":"uint256"}],"name":"updateMinimumDepositLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPoolRewards_","type":"address"}],"name":"updatePoolRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newUniversalFee_","type":"uint256"}],"name":"updateUniversalFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares_","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares_","type":"uint256"}],"name":"withdrawAndClaim","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405260c8601d55611388601e556001601f553480156200002157600080fd5b50604051620046933803806200469383398101604081905262000044916200027b565b8251839083906200005d90600390602085019062000108565b5080516200007390600490602084019062000108565b5050506000620000886200010460201b60201c565b600a80546001600160a01b0319166001600160a01b038316908117909155604051919250906000907fd4459d5b8b913cab0244230fd9b1c08b6ceace7fe9230e60d0f74cbffdf849d0908290a3506001600c55600d80546001600160a01b0319166001600160a01b039290921691909117905550620003459050565b3390565b828054620001169062000308565b90600052602060002090601f0160209004810192826200013a576000855562000185565b82601f106200015557805160ff191683800117855562000185565b8280016001018555821562000185579182015b828111156200018557825182559160200191906001019062000168565b506200019392915062000197565b5090565b5b8082111562000193576000815560010162000198565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001d657600080fd5b81516001600160401b0380821115620001f357620001f3620001ae565b604051601f8301601f19908116603f011681019082821181831017156200021e576200021e620001ae565b816040528381526020925086838588010111156200023b57600080fd5b600091505b838210156200025f578582018301518183018401529082019062000240565b83821115620002715760008385830101525b9695505050505050565b6000806000606084860312156200029157600080fd5b83516001600160401b0380821115620002a957600080fd5b620002b787838801620001c4565b94506020860151915080821115620002ce57600080fd5b50620002dd86828701620001c4565b604086015190935090506001600160a01b0381168114620002fd57600080fd5b809150509250925092565b600181811c908216806200031d57607f821691505b602082108114156200033f57634e487b7160e01b600052602260045260246000fd5b50919050565b61433e80620003556000396000f3fe608060405234801561001057600080fd5b506004361061035b5760003560e01c80638d3d0a26116101ca578063c01e0d4011610105578063ddd6d260116100a8578063ddd6d260146107a5578063e00af4a7146107b8578063f3b27bc3146107cb578063fc0c546a146107d3578063fc0e74d1146107e6578063fc7b9c18146107ee578063fcfff16f146107f6578063fd967f47146107fe578063ffa1ad741461080757600080fd5b8063c01e0d40146106f2578063c12d636b14610705578063d4c3eea014610718578063d505accf14610720578063d53ddc2614610733578063d8baf7cf14610746578063dd57366a14610759578063dd62ed3e1461076c57600080fd5b80639fd5be181161016d5780639fd5be181461067a578063a9059cbb14610683578063a941a90e14610696578063b49a60bb146106a9578063b64321ec146106b1578063b6aa515b146106c4578063b6b55f25146106d7578063b8cb343d146106ea57600080fd5b80638d3d0a26146106035780638f15b41414610616578063940c408214610629578063951dc22c1461063c57806395d89b411461064457806399530b061461064c5780639b6da8df146106545780639f2b28331461066757600080fd5b80633e7729251161029a5780635f895e541161023d5780635f895e541461055d5780636b453c1f146105665780636ba42aaa146105795780636cb56d191461058c57806370a082311461059f5780637ecebe00146105c85780638456cb59146105e85780638bc6beb2146105f057600080fd5b80633e772925146104e35780633f4ba83a146104ec5780634032b72b146104f4578063448a1047146105075780634938649a1461051a57806349eeb8601461052e5780634a970be7146105365780635c975abb1461054957600080fd5b806318160ddd1161030257806318160ddd1461042a578063228bfd9f1461043257806323b872dd1461048b5780632df9eab91461049e5780632e1a7d4d146104a6578063313ce567146104b957806332dd0f49146104c85780633644e515146104db57600080fd5b806305bed0461461036057806306fdde0314610375578063095ea7b3146103935780630c340a24146103b65780630da3fe20146103d657806311183052146103e957806314ae9f2e146103fe57806316d3bfbb14610411575b600080fd5b61037361036e3660046139f6565b61082b565b005b61037d610aac565b60405161038a9190613a4e565b60405180910390f35b6103a66103a1366004613a96565b610b3e565b604051901515815260200161038a565b600a546103c9906001600160a01b031681565b60405161038a9190613ac2565b6103736103e4366004613ad6565b610b55565b6103f1610c41565b60405161038a9190613aef565b61037361040c366004613b3c565b610cc7565b61041c6301e1338081565b60405190815260200161038a565b60025461041c565b610445610440366004613b3c565b610d4c565b604080519915158a5260208a0198909852968801959095526060870193909352608086019190915260a085015260c084015260e08301526101008201526101200161038a565b6103a6610499366004613b59565b610dfd565b61041c610eb0565b6103736104b4366004613ad6565b610f2d565b6040516012815260200161038a565b61041c6104d6366004613ad6565b610f9e565b61041c610faa565b61041c601e5481565b610373610fb4565b610373610502366004613b3c565b610ff7565b610373610515366004613ad6565b611074565b600b546103a690600160a81b900460ff1681565b6103f16110cf565b610373610544366004613ba9565b6110db565b600b546103a690600160a01b900460ff1681565b61041c601d5481565b610373610574366004613b3c565b6111e2565b6103a6610587366004613b3c565b611226565b61037361059a366004613bf2565b611233565b61041c6105ad366004613b3c565b6001600160a01b031660009081526020819052604090205490565b61041c6105d6366004613b3c565b60096020526000908152604090205481565b610373611472565b600f546103c9906001600160a01b031681565b610373610611366004613ad6565b6114b3565b610373610624366004613ce2565b61155b565b610373610637366004613b3c565b611739565b6103f1611800565b61037d61180c565b61041c61181b565b610373610662366004613ad6565b6118f4565b61041c610675366004613b3c565b61199f565b61041c601f5481565b6103a6610691366004613a96565b611a20565b6103736106a4366004613ad6565b611a2d565b6103f1611a91565b61041c6106bf366004613b3c565b611ad6565b6103736106d2366004613b3c565b611b07565b6103736106e5366004613ad6565b611ba5565b61041c611c00565b61041c610700366004613ad6565b611c49565b600e546103c9906001600160a01b031681565b61041c611d3d565b61037361072e366004613d6b565b611dd7565b61041c610741366004613b3c565b611f97565b610373610754366004613b3c565b611fc8565b6103a6610767366004613b3c565b61200c565b61041c61077a366004613bf2565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6103736107b3366004613ad6565b612019565b6103736107c6366004613b3c565b612080565b61037361219b565b600d546103c9906001600160a01b031681565b610373612257565b61041c612298565b6103736122dd565b61041c61271081565b61037d604051806040016040528060058152602001640352e312e360dc1b81525081565b3383156109a057600e5460405163228bfd9f60e01b815260009182916001600160a01b039091169063228bfd9f90610867908690600401613ac2565b6101206040518083038186803b15801561088057600080fd5b505afa158015610894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b89190613df1565b505050509450945050505060006108d083838961231e565b9050801561099c5761095a846001600160a01b031663c415b95c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561091457600080fd5b505afa158015610928573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094c9190613e61565b61095583612391565b6123f6565b60408051838152602081018990529081018290527f692ef79cc704efab4328e6c217b5fb3b1045d0a0314e3e8137029bcb2d59ce4a9060600160405180910390a15b5050505b600e5460405163a066654b60e01b81526001600160a01b038381166004830152602482018790526044820186905260648201859052600092839291169063a066654b906084016040805180830381600087803b1580156109ff57600080fd5b505af1158015610a13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a379190613e7e565b90925090506000610a488388613eb8565b905081811015610a7857610a7384610a608385613ed0565b600d546001600160a01b031691906124c3565b610aa3565b81811115610aa357610aa38430610a8f8585613ed0565b600d546001600160a01b031692919061251e565b50505050505050565b606060038054610abb90613ee7565b80601f0160208091040260200160405190810160405280929190818152602001828054610ae790613ee7565b8015610b345780601f10610b0957610100808354040283529160200191610b34565b820191906000526020600020905b815481529060010190602001808311610b1757829003601f168201915b5050505050905090565b6000610b4b33848461255c565b5060015b92915050565b600a546001600160a01b03163314610b885760405162461bcd60e51b8152600401610b7f90613f22565b60405180910390fd5b604080518082019091526002815261199960f11b602082015281610bbf5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601f5481141560405180604001604052806002815260200161333160f01b81525090610bff5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601f5460408051918252602082018390527f25c9f41f0fb7a055d44b070262516fbd0111daea3b55d40fae1983827dc99292910160405180910390a1601f55565b600e546040805163088c182960e11b815290516060926001600160a01b0316916311183052916004808301926000929190829003018186803b158015610c8657600080fd5b505afa158015610c9a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cc29190810190613f48565b905090565b600a546001600160a01b0316331480610ce85750610ce8335b601990612681565b610d045760405162461bcd60e51b8152600401610b7f90613ffa565b610d0f6019826126a3565b604051806040016040528060028152602001610c4d60f21b81525090610d485760405162461bcd60e51b8152600401610b7f9190613a4e565b5050565b600e5460405163228bfd9f60e01b8152600091829182918291829182918291829182916001600160a01b03169063228bfd9f90610d8d908d90600401613ac2565b6101206040518083038186803b158015610da657600080fd5b505afa158015610dba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dde9190613df1565b9850985098509850985098509850985098509193959799909294969850565b6000610e0a8484846126b8565b6001600160a01b038416600090815260016020908152604080832033845290915290205482811015610e8f5760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b6064820152608401610b7f565b610ea38533610e9e8685613ed0565b61255c565b60019150505b9392505050565b600e5460408051632df9eab960e01b815290516000926001600160a01b031691632df9eab9916004808301926020929190829003018186803b158015610ef557600080fd5b505afa158015610f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc29190614020565b6002600c541415610f505760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a81b900460ff1615610f7f5760405162461bcd60e51b8152600401610b7f90614070565b610f8d33612799565b612799565b610f96816127da565b506001600c55565b6000610b4f3383612896565b6000610cc261293b565b600a546001600160a01b0316331480610fd15750610fd133610ce0565b610fed5760405162461bcd60e51b8152600401610b7f90613ffa565b610ff56129b6565b565b600a546001600160a01b0316331480611014575061101433610ce0565b6110305760405162461bcd60e51b8152600401610b7f90613ffa565b61103b601982612a6d565b60405180604001604052806002815260200161313360f01b81525090610d485760405162461bcd60e51b8152600401610b7f9190613a4e565b6002600c5414156110975760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a81b900460ff16156110c65760405162461bcd60e51b8152600401610b7f90614070565b610f8d33612a82565b6060610cc2601b612ac3565b6002600c5414156110fe5760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff161561112d5760405162461bcd60e51b8152600401610b7f90614092565b600d546001600160a01b031663d505accf336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604481018890526064810187905260ff8616608482015260a4810185905260c4810184905260e401600060405180830381600087803b1580156111ab57600080fd5b505af11580156111bf573d6000803e3d6000fd5b505050506111cd610f883390565b6111d685612ad0565b50506001600c55505050565b600a546001600160a01b03163314806111ff57506111ff33610ce0565b61121b5760405162461bcd60e51b8152600401610b7f90613ffa565b61103b601b82612a6d565b6000610b4f601983612681565b600a546001600160a01b0316331461125d5760405162461bcd60e51b8152600401610b7f90613f22565b306001600160a01b0316816001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112a057600080fd5b505afa1580156112b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d89190613e61565b6001600160a01b031614801561136f5750306001600160a01b0316826001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561132c57600080fd5b505afa158015611340573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113649190613e61565b6001600160a01b0316145b60405180604001604052806002815260200161313760f01b815250906113a85760405162461bcd60e51b8152600401610b7f9190613a4e565b50600e54604051636cb56d1960e01b81526001600160a01b038481166004830152838116602483015290911690636cb56d1990604401600060405180830381600087803b1580156113f857600080fd5b505af115801561140c573d6000803e3d6000fd5b505060405163ce5494bb60e01b81526001600160a01b038516925063ce5494bb915061143c908490600401613ac2565b600060405180830381600087803b15801561145657600080fd5b505af115801561146a573d6000803e3d6000fd5b505050505050565b600a546001600160a01b031633148061148f575061148f33610ce0565b6114ab5760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612b3e565b600a546001600160a01b031633146114dd5760405162461bcd60e51b8152600401610b7f90613f22565b604080518082019091526002815261313160f01b60208201526127108211156115195760405162461bcd60e51b8152600401610b7f9190613a4e565b50601d5460408051918252602082018390527f905d672396c48f9d1e13c57aec0819f00d39364ab4bf40a46a687aa607b67d81910160405180910390a1601d55565b600554610100900460ff1680611574575060055460ff16155b6115905760405162461bcd60e51b8152600401610b7f906140b2565b600554610100900460ff161580156115b2576005805461ffff19166101011790555b604080518082019091526002815261031360f41b60208201526001600160a01b0384166115f25760405162461bcd60e51b8152600401610b7f9190613a4e565b50604080518082019091526002815261031360f41b60208201526001600160a01b0383166116335760405162461bcd60e51b8152600401610b7f9190613a4e565b5061163e8585612ba3565b61164785612bca565b61164f612c49565b600d80546001600160a01b0319166001600160a01b03851617905561167633601990612a6d565b60405180604001604052806002815260200161313360f01b815250906116af5760405162461bcd60e51b8152600401610b7f9190613a4e565b506116bb601b33612a6d565b60405180604001604052806002815260200161313360f01b815250906116f45760405162461bcd60e51b8152600401610b7f9190613a4e565b50600e80546001600160a01b0319166001600160a01b03841617905560c8601d55611388601e556001601f558015611732576005805461ff00191690555b5050505050565b600a546001600160a01b031633146117635760405162461bcd60e51b8152600401610b7f90613f22565b604080518082019091526002815261031360f41b60208201526001600160a01b0382166117a35760405162461bcd60e51b8152600401610b7f9190613a4e565b50600f546040516001600160a01b038084169216907fe239974dad08ac696e723caf1886bd0b5afc0870088f9a1266082757f824927690600090a3600f80546001600160a01b0319166001600160a01b0392909216919091179055565b6060610cc26019612ac3565b606060048054610abb90613ee7565b600061182660025490565b15806118375750611835611d3d565b155b156118cd57600d60009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561188a57600080fd5b505afa15801561189e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c29190614100565b610cc290600a614201565b6002546118d8611d3d565b6118ea90670de0b6b3a7640000614210565b610cc2919061422f565b600a546001600160a01b0316331461191e5760405162461bcd60e51b8152600401610b7f90613f22565b601e5481141560405180604001604052806002815260200161333160f01b8152509061195d5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601e5460408051918252602082018390527fafe4d3ceb3295a8d4ef49288a92d32d94e39396e823d414b81caff61b9fc3990910160405180910390a1601e55565b600e54604051639f2b283360e01b81526000916001600160a01b031690639f2b2833906119d0908590600401613ac2565b60206040518083038186803b1580156119e857600080fd5b505afa1580156119fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4f9190614020565b6000610b4b3384846126b8565b6002600c541415611a505760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff1615611a7f5760405162461bcd60e51b8152600401610b7f90614092565b611a8833612a82565b610f9681612ad0565b600e546040805163b49a60bb60e01b815290516060926001600160a01b03169163b49a60bb916004808301926000929190829003018186803b158015610c8657600080fd5b600e54604051632d90c87b60e21b81526000916001600160a01b03169063b64321ec906119d0908590600401613ac2565b600a546001600160a01b03163314611b315760405162461bcd60e51b8152600401610b7f90613f22565b6001600160a01b038116611b835760405162461bcd60e51b815260206004820152601960248201527870726f706f7365642d676f7665726e6f722d69732d7a65726f60381b6044820152606401610b7f565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6002600c541415611bc85760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff1615611bf75760405162461bcd60e51b8152600401610b7f90614092565b611a8833612799565b600d546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611c31903090600401613ac2565b60206040518083038186803b158015610ef557600080fd5b6000601f54821015604051806040016040528060018152602001603160f81b81525090611c895760405162461bcd60e51b8152600401610b7f9190613a4e565b506000612710600e60009054906101000a90046001600160a01b03166001600160a01b031663346162d56040518163ffffffff1660e01b815260040160206040518083038186803b158015611cdd57600080fd5b505afa158015611cf1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d159190614020565b611d1f9085614210565b611d29919061422f565b9050610ea9611d388285613ed0565b612391565b6000611d47611c00565b600e60009054906101000a90046001600160a01b03166001600160a01b031663fc7b9c186040518163ffffffff1660e01b815260040160206040518083038186803b158015611d9557600080fd5b505afa158015611da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dcd9190614020565b610cc29190613eb8565b83421115611e275760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610b7f565b6001600160a01b0387811660008181526009602090815260408083205481517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98185015280830195909552948b166060850152608084018a905260a0840185905260c08085018a90528151808603909101815260e09094019052825192019190912090611eb261293b565b60405161190160f01b60208201526022810191909152604281018390526062016040516020818303038152906040528051906020012090506000611ef882888888612cf7565b90508a6001600160a01b0316816001600160a01b031614611f5b5760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610b7f565b611f66846001613eb8565b6001600160a01b038c16600090815260096020526040902055611f8a8b8b8b61255c565b5050505050505050505050565b600e54604051636a9eee1360e11b81526000916001600160a01b03169063d53ddc26906119d0908590600401613ac2565b600a546001600160a01b0316331480611fe55750611fe533610ce0565b6120015760405162461bcd60e51b8152600401610b7f90613ffa565b610d0f601b826126a3565b6000610b4f601b83612681565b801561207d57600e546001600160a01b0316637f13086e33836040518363ffffffff1660e01b815260040161204f929190614251565b600060405180830381600087803b15801561206957600080fd5b505af1158015611732573d6000803e3d6000fd5b50565b600a546001600160a01b031633148061209d575061209d33610ce0565b6120b95760405162461bcd60e51b8152600401610b7f90613ffa565b600d546040805180820190915260018152600760fb1b6020820152906001600160a01b03838116911614156121015760405162461bcd60e51b8152600401610b7f9190613a4e565b50600a546040516370a0823160e01b815261207d916001600160a01b0390811691908416906370a082319061213a903090600401613ac2565b60206040518083038186803b15801561215257600080fd5b505afa158015612166573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218a9190614020565b6001600160a01b03841691906124c3565b600b546001600160a01b031633146121f15760405162461bcd60e51b81526020600482015260196024820152783737ba16ba343296b83937b837b9b2b216b3b7bb32b93737b960391b6044820152606401610b7f565b600b54600a546040516001600160a01b0392831692909116907fd4459d5b8b913cab0244230fd9b1c08b6ceace7fe9230e60d0f74cbffdf849d090600090a3600b8054600a80546001600160a01b03199081166001600160a01b03841617909155169055565b600a546001600160a01b0316331480612274575061227433610ce0565b6122905760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612e88565b600e5460408051631f8f738360e31b815290516000926001600160a01b03169163fc7b9c18916004808301926020929190829003018186803b158015610ef557600080fd5b600a546001600160a01b03163314806122fa57506122fa33610ce0565b6123165760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612eee565b60006123306301e13380612710614210565b8361233b8642613ed0565b601d546123489190614210565b6123529190614210565b61235c919061422f565b90506000612710601e54846123719190614210565b61237b919061422f565b905080821115612389578091505b509392505050565b60008061239c61181b565b6123ae84670de0b6b3a7640000614210565b6123b8919061422f565b9050670de0b6b3a76400006123cb61181b565b6123d59083614210565b6123df919061422f565b83116123eb5780610ea9565b610ea9816001613eb8565b6001600160a01b03821661244c5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610b7f565b806002600082825461245e9190613eb8565b90915550506001600160a01b0382166000908152602081905260408120805483929061248b908490613eb8565b90915550506040518181526001600160a01b038316906000906000805160206142e98339815191529060200160405180910390a35050565b6125198363a9059cbb60e01b84846040516024016124e2929190614251565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f6a565b505050565b6040516001600160a01b03808516602483015283166044820152606481018290526125569085906323b872dd60e01b906084016124e2565b50505050565b6001600160a01b0383166125be5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610b7f565b6001600160a01b03821661261f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610b7f565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03811660009081526001830160205260408120541515610ea9565b6000610ea9836001600160a01b03841661303c565b600f546001600160a01b03161561278e57600f5460405163632447c960e01b81526001600160a01b039091169063632447c9906126f9908690600401613ac2565b600060405180830381600087803b15801561271357600080fd5b505af1158015612727573d6000803e3d6000fd5b5050600f5460405163632447c960e01b81526001600160a01b03909116925063632447c9915061275b908590600401613ac2565b600060405180830381600087803b15801561277557600080fd5b505af1158015612789573d6000803e3d6000fd5b505050505b61251983838361312f565b600f546001600160a01b03161561207d57600f5460405163632447c960e01b81526001600160a01b039091169063632447c99061204f908490600401613ac2565b6040805180820190915260018152601960f91b6020820152816128105760405162461bcd60e51b8152600401610b7f9190613a4e565b5060008061281d836132f5565b91509150801561284257600061283283612391565b905083811015612840578093505b505b61284c338461339c565b612855826134d9565b50604080518481526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a2505050565b600e5460405163228bfd9f60e01b8152600091829182916001600160a01b03169063228bfd9f906128cb908890600401613ac2565b6101206040518083038186803b1580156128e457600080fd5b505afa1580156128f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291c9190613df1565b505050509450945050505061293282828661231e565b95945050505050565b600060085446141561294e575060065490565b6007546040805180820190915260018152603160f81b602090910152610cc2907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f907fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66134f6565b600b54600160a01b900460ff166129fc5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd0b5c185d5cd95960b21b6044820152606401610b7f565b600b54600160a81b900460ff1615612a265760405162461bcd60e51b8152600401610b7f90614070565b600b805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b604051612a639190613ac2565b60405180910390a1565b6000610ea9836001600160a01b03841661353f565b600f546001600160a01b03161561207d57600f5460405163d279c19160e01b81526001600160a01b039091169063d279c1919061204f908490600401613ac2565b60606000610ea98361358e565b6000612adb82611c49565b9050612af533600d546001600160a01b031690308561251e565b612aff33826123f6565b604080518281526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a25050565b600b54600160a01b900460ff1615612b685760405162461bcd60e51b8152600401610b7f90614092565b600b805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a563390565b8151612bb6906003906020850190613966565b508051612519906004906020840190613966565b80516020808301919091206007819055466008556040805180820190915260018152603160f81b920191909152612c43907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f907fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66134f6565b60065550565b600554610100900460ff1680612c62575060055460ff16155b612c7e5760405162461bcd60e51b8152600401610b7f906140b2565b600554610100900460ff16158015612ca0576005805461ffff19166101011790555b600a80546001600160a01b0319163390811790915560405181906000907fd4459d5b8b913cab0244230fd9b1c08b6ceace7fe9230e60d0f74cbffdf849d0908290a350801561207d576005805461ff001916905550565b60006fa2a8918ca85bafe22016d0b997e4df60600160ff1b03821115612d6a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610b7f565b8360ff16601b1480612d7f57508360ff16601c145b612dd65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610b7f565b6040805160008082526020820180845288905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa158015612e2a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166129325760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610b7f565b600b54600160a81b900460ff1615612eb25760405162461bcd60e51b8152600401610b7f90614070565b600b805461ffff60a01b191661010160a01b1790557f28b4c24cb1012c094cd2f59f98e89d791973295f8fda6eaa118022d6d318960a33612a56565b600b54600160a81b900460ff16612f365760405162461bcd60e51b815260206004820152600c60248201526b3737ba16b9b43aba3237bbb760a11b6044820152606401610b7f565b600b805460ff60a81b191690557fece7583a70a505ef0e36d4dec768f5ae597713e09c26011022599ee01abdabfc33612a56565b6000612fbf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135ea9092919063ffffffff16565b8051909150156125195780806020019051810190612fdd919061426a565b6125195760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610b7f565b60008181526001830160205260408120548015613125576000613060600183613ed0565b855490915060009061307490600190613ed0565b90508181146130d957600086600001828154811061309457613094614285565b90600052602060002001549050808760000184815481106130b7576130b7614285565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806130ea576130ea61429b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b4f565b6000915050610b4f565b6001600160a01b0383166131935760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610b7f565b6001600160a01b0382166131f55760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610b7f565b6001600160a01b0383166000908152602081905260409020548181101561326d5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610b7f565b6132778282613ed0565b6001600160a01b0380861660009081526020819052604080822093909355908516815290812080548492906132ad908490613eb8565b92505081905550826001600160a01b0316846001600160a01b03166000805160206142e9833981519152846040516132e791815260200190565b60405180910390a350505050565b600080670de0b6b3a764000061330961181b565b6133139085614210565b61331d919061422f565b91506000613329611c00565b90508083111561335f576133456133408285613ed0565b613601565b61334d611c00565b90508083111561335f57809250600191505b6040805180820190915260018152603160f81b6020820152836133955760405162461bcd60e51b8152600401610b7f9190613a4e565b5050915091565b6001600160a01b0382166133fc5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610b7f565b6001600160a01b038216600090815260208190526040902054818110156134705760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610b7f565b61347a8282613ed0565b6001600160a01b038416600090815260208190526040812091909155600280548492906134a8908490613ed0565b90915550506040518281526000906001600160a01b038516906000805160206142e983398151915290602001612674565b60006134f233600d546001600160a01b031690846124c3565b5090565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b600081815260018301602052604081205461358657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b4f565b506000610b4f565b6060816000018054806020026020016040519081016040528092919081815260200182805480156135de57602002820191906000526020600020905b8154815260200190600101908083116135ca575b50505050509050919050565b60606135f98484600085613805565b949350505050565b6000806000806000613611610c41565b805190915060005b818110156137fb57600061362d858a613ed0565b9050600084838151811061364357613643614285565b6020908102919091010151600e54604051639f2b283360e01b81529192506001600160a01b031690639f2b28339061367f908490600401613ac2565b60206040518083038186803b15801561369757600080fd5b505afa1580156136ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136cf9190614020565b9850886136dd5750506137e9565b888211156136e9578891505b6136f1611c00565b604051632e1a7d4d60e01b8152600481018490529098506001600160a01b03821690632e1a7d4d90602401600060405180830381600087803b15801561373657600080fd5b505af1925050508015613747575060015b6137525750506137e9565b8761375b611c00565b6137659190613ed0565b600e54604051632fb9ba3160e01b81529198506001600160a01b031690632fb9ba31906137989084908b90600401614251565b600060405180830381600087803b1580156137b257600080fd5b505af11580156137c6573d6000803e3d6000fd5b5050505086866137d69190613eb8565b95508986106137e65750506137fb565b50505b806137f3816142b1565b915050613619565b5050505050505050565b6060824710156138665760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610b7f565b843b6138b45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7f565b600080866001600160a01b031685876040516138d091906142cc565b60006040518083038185875af1925050503d806000811461390d576040519150601f19603f3d011682016040523d82523d6000602084013e613912565b606091505b509150915061392282828661392d565b979650505050505050565b6060831561393c575081610ea9565b82511561394c5782518084602001fd5b8160405162461bcd60e51b8152600401610b7f9190613a4e565b82805461397290613ee7565b90600052602060002090601f01602090048101928261399457600085556139da565b82601f106139ad57805160ff19168380011785556139da565b828001600101855582156139da579182015b828111156139da5782518255916020019190600101906139bf565b506134f29291505b808211156134f257600081556001016139e2565b600080600060608486031215613a0b57600080fd5b505081359360208301359350604090920135919050565b60005b83811015613a3d578181015183820152602001613a25565b838111156125565750506000910152565b6020815260008251806020840152613a6d816040850160208701613a22565b601f01601f19169190910160400192915050565b6001600160a01b038116811461207d57600080fd5b60008060408385031215613aa957600080fd5b8235613ab481613a81565b946020939093013593505050565b6001600160a01b0391909116815260200190565b600060208284031215613ae857600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015613b305783516001600160a01b031683529284019291840191600101613b0b565b50909695505050505050565b600060208284031215613b4e57600080fd5b8135610ea981613a81565b600080600060608486031215613b6e57600080fd5b8335613b7981613a81565b92506020840135613b8981613a81565b929592945050506040919091013590565b60ff8116811461207d57600080fd5b600080600080600060a08688031215613bc157600080fd5b85359450602086013593506040860135613bda81613b9a565b94979396509394606081013594506080013592915050565b60008060408385031215613c0557600080fd5b8235613c1081613a81565b91506020830135613c2081613a81565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613c6a57613c6a613c2b565b604052919050565b600082601f830112613c8357600080fd5b813567ffffffffffffffff811115613c9d57613c9d613c2b565b613cb0601f8201601f1916602001613c41565b818152846020838601011115613cc557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613cf857600080fd5b843567ffffffffffffffff80821115613d1057600080fd5b613d1c88838901613c72565b95506020870135915080821115613d3257600080fd5b50613d3f87828801613c72565b9350506040850135613d5081613a81565b91506060850135613d6081613a81565b939692955090935050565b600080600080600080600060e0888a031215613d8657600080fd5b8735613d9181613a81565b96506020880135613da181613a81565b955060408801359450606088013593506080880135613dbf81613b9a565b9699959850939692959460a0840135945060c09093013592915050565b80518015158114613dec57600080fd5b919050565b60008060008060008060008060006101208a8c031215613e1057600080fd5b613e198a613ddc565b985060208a0151975060408a0151965060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a015191506101008a015190509295985092959850929598565b600060208284031215613e7357600080fd5b8151610ea981613a81565b60008060408385031215613e9157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b60008219821115613ecb57613ecb613ea2565b500190565b600082821015613ee257613ee2613ea2565b500390565b600181811c90821680613efb57607f821691505b60208210811415613f1c57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600c908201526b3737ba16b3b7bb32b93737b960a11b604082015260600190565b60006020808385031215613f5b57600080fd5b825167ffffffffffffffff80821115613f7357600080fd5b818501915085601f830112613f8757600080fd5b815181811115613f9957613f99613c2b565b8060051b9150613faa848301613c41565b8181529183018401918481019088841115613fc457600080fd5b938501935b83851015613fee5784519250613fde83613a81565b8282529385019390850190613fc9565b98975050505050505050565b6020808252600c908201526b3737ba16b096b5b2b2b832b960a11b604082015260600190565b60006020828403121561403257600080fd5b5051919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526008908201526739b43aba3237bbb760c11b604082015260600190565b6020808252600690820152651c185d5cd95960d21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60006020828403121561411257600080fd5b8151610ea981613b9a565b600181815b8085111561415857816000190482111561413e5761413e613ea2565b8085161561414b57918102915b93841c9390800290614122565b509250929050565b60008261416f57506001610b4f565b8161417c57506000610b4f565b8160018114614192576002811461419c576141b8565b6001915050610b4f565b60ff8411156141ad576141ad613ea2565b50506001821b610b4f565b5060208310610133831016604e8410600b84101617156141db575081810a610b4f565b6141e5838361411d565b80600019048211156141f9576141f9613ea2565b029392505050565b6000610ea960ff841683614160565b600081600019048311821515161561422a5761422a613ea2565b500290565b60008261424c57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b03929092168252602082015260400190565b60006020828403121561427c57600080fd5b610ea982613ddc565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60006000198214156142c5576142c5613ea2565b5060010190565b600082516142de818460208701613a22565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220abf1e07fafbaa608304f172200235d161aa1ebbaa8b9d8c1ba464cd12f8d9be264736f6c63430008090033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b56657370657220706f6f6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000576506f6f6c000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061035b5760003560e01c80638d3d0a26116101ca578063c01e0d4011610105578063ddd6d260116100a8578063ddd6d260146107a5578063e00af4a7146107b8578063f3b27bc3146107cb578063fc0c546a146107d3578063fc0e74d1146107e6578063fc7b9c18146107ee578063fcfff16f146107f6578063fd967f47146107fe578063ffa1ad741461080757600080fd5b8063c01e0d40146106f2578063c12d636b14610705578063d4c3eea014610718578063d505accf14610720578063d53ddc2614610733578063d8baf7cf14610746578063dd57366a14610759578063dd62ed3e1461076c57600080fd5b80639fd5be181161016d5780639fd5be181461067a578063a9059cbb14610683578063a941a90e14610696578063b49a60bb146106a9578063b64321ec146106b1578063b6aa515b146106c4578063b6b55f25146106d7578063b8cb343d146106ea57600080fd5b80638d3d0a26146106035780638f15b41414610616578063940c408214610629578063951dc22c1461063c57806395d89b411461064457806399530b061461064c5780639b6da8df146106545780639f2b28331461066757600080fd5b80633e7729251161029a5780635f895e541161023d5780635f895e541461055d5780636b453c1f146105665780636ba42aaa146105795780636cb56d191461058c57806370a082311461059f5780637ecebe00146105c85780638456cb59146105e85780638bc6beb2146105f057600080fd5b80633e772925146104e35780633f4ba83a146104ec5780634032b72b146104f4578063448a1047146105075780634938649a1461051a57806349eeb8601461052e5780634a970be7146105365780635c975abb1461054957600080fd5b806318160ddd1161030257806318160ddd1461042a578063228bfd9f1461043257806323b872dd1461048b5780632df9eab91461049e5780632e1a7d4d146104a6578063313ce567146104b957806332dd0f49146104c85780633644e515146104db57600080fd5b806305bed0461461036057806306fdde0314610375578063095ea7b3146103935780630c340a24146103b65780630da3fe20146103d657806311183052146103e957806314ae9f2e146103fe57806316d3bfbb14610411575b600080fd5b61037361036e3660046139f6565b61082b565b005b61037d610aac565b60405161038a9190613a4e565b60405180910390f35b6103a66103a1366004613a96565b610b3e565b604051901515815260200161038a565b600a546103c9906001600160a01b031681565b60405161038a9190613ac2565b6103736103e4366004613ad6565b610b55565b6103f1610c41565b60405161038a9190613aef565b61037361040c366004613b3c565b610cc7565b61041c6301e1338081565b60405190815260200161038a565b60025461041c565b610445610440366004613b3c565b610d4c565b604080519915158a5260208a0198909852968801959095526060870193909352608086019190915260a085015260c084015260e08301526101008201526101200161038a565b6103a6610499366004613b59565b610dfd565b61041c610eb0565b6103736104b4366004613ad6565b610f2d565b6040516012815260200161038a565b61041c6104d6366004613ad6565b610f9e565b61041c610faa565b61041c601e5481565b610373610fb4565b610373610502366004613b3c565b610ff7565b610373610515366004613ad6565b611074565b600b546103a690600160a81b900460ff1681565b6103f16110cf565b610373610544366004613ba9565b6110db565b600b546103a690600160a01b900460ff1681565b61041c601d5481565b610373610574366004613b3c565b6111e2565b6103a6610587366004613b3c565b611226565b61037361059a366004613bf2565b611233565b61041c6105ad366004613b3c565b6001600160a01b031660009081526020819052604090205490565b61041c6105d6366004613b3c565b60096020526000908152604090205481565b610373611472565b600f546103c9906001600160a01b031681565b610373610611366004613ad6565b6114b3565b610373610624366004613ce2565b61155b565b610373610637366004613b3c565b611739565b6103f1611800565b61037d61180c565b61041c61181b565b610373610662366004613ad6565b6118f4565b61041c610675366004613b3c565b61199f565b61041c601f5481565b6103a6610691366004613a96565b611a20565b6103736106a4366004613ad6565b611a2d565b6103f1611a91565b61041c6106bf366004613b3c565b611ad6565b6103736106d2366004613b3c565b611b07565b6103736106e5366004613ad6565b611ba5565b61041c611c00565b61041c610700366004613ad6565b611c49565b600e546103c9906001600160a01b031681565b61041c611d3d565b61037361072e366004613d6b565b611dd7565b61041c610741366004613b3c565b611f97565b610373610754366004613b3c565b611fc8565b6103a6610767366004613b3c565b61200c565b61041c61077a366004613bf2565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6103736107b3366004613ad6565b612019565b6103736107c6366004613b3c565b612080565b61037361219b565b600d546103c9906001600160a01b031681565b610373612257565b61041c612298565b6103736122dd565b61041c61271081565b61037d604051806040016040528060058152602001640352e312e360dc1b81525081565b3383156109a057600e5460405163228bfd9f60e01b815260009182916001600160a01b039091169063228bfd9f90610867908690600401613ac2565b6101206040518083038186803b15801561088057600080fd5b505afa158015610894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b89190613df1565b505050509450945050505060006108d083838961231e565b9050801561099c5761095a846001600160a01b031663c415b95c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561091457600080fd5b505afa158015610928573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094c9190613e61565b61095583612391565b6123f6565b60408051838152602081018990529081018290527f692ef79cc704efab4328e6c217b5fb3b1045d0a0314e3e8137029bcb2d59ce4a9060600160405180910390a15b5050505b600e5460405163a066654b60e01b81526001600160a01b038381166004830152602482018790526044820186905260648201859052600092839291169063a066654b906084016040805180830381600087803b1580156109ff57600080fd5b505af1158015610a13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a379190613e7e565b90925090506000610a488388613eb8565b905081811015610a7857610a7384610a608385613ed0565b600d546001600160a01b031691906124c3565b610aa3565b81811115610aa357610aa38430610a8f8585613ed0565b600d546001600160a01b031692919061251e565b50505050505050565b606060038054610abb90613ee7565b80601f0160208091040260200160405190810160405280929190818152602001828054610ae790613ee7565b8015610b345780601f10610b0957610100808354040283529160200191610b34565b820191906000526020600020905b815481529060010190602001808311610b1757829003601f168201915b5050505050905090565b6000610b4b33848461255c565b5060015b92915050565b600a546001600160a01b03163314610b885760405162461bcd60e51b8152600401610b7f90613f22565b60405180910390fd5b604080518082019091526002815261199960f11b602082015281610bbf5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601f5481141560405180604001604052806002815260200161333160f01b81525090610bff5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601f5460408051918252602082018390527f25c9f41f0fb7a055d44b070262516fbd0111daea3b55d40fae1983827dc99292910160405180910390a1601f55565b600e546040805163088c182960e11b815290516060926001600160a01b0316916311183052916004808301926000929190829003018186803b158015610c8657600080fd5b505afa158015610c9a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cc29190810190613f48565b905090565b600a546001600160a01b0316331480610ce85750610ce8335b601990612681565b610d045760405162461bcd60e51b8152600401610b7f90613ffa565b610d0f6019826126a3565b604051806040016040528060028152602001610c4d60f21b81525090610d485760405162461bcd60e51b8152600401610b7f9190613a4e565b5050565b600e5460405163228bfd9f60e01b8152600091829182918291829182918291829182916001600160a01b03169063228bfd9f90610d8d908d90600401613ac2565b6101206040518083038186803b158015610da657600080fd5b505afa158015610dba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dde9190613df1565b9850985098509850985098509850985098509193959799909294969850565b6000610e0a8484846126b8565b6001600160a01b038416600090815260016020908152604080832033845290915290205482811015610e8f5760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b6064820152608401610b7f565b610ea38533610e9e8685613ed0565b61255c565b60019150505b9392505050565b600e5460408051632df9eab960e01b815290516000926001600160a01b031691632df9eab9916004808301926020929190829003018186803b158015610ef557600080fd5b505afa158015610f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc29190614020565b6002600c541415610f505760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a81b900460ff1615610f7f5760405162461bcd60e51b8152600401610b7f90614070565b610f8d33612799565b612799565b610f96816127da565b506001600c55565b6000610b4f3383612896565b6000610cc261293b565b600a546001600160a01b0316331480610fd15750610fd133610ce0565b610fed5760405162461bcd60e51b8152600401610b7f90613ffa565b610ff56129b6565b565b600a546001600160a01b0316331480611014575061101433610ce0565b6110305760405162461bcd60e51b8152600401610b7f90613ffa565b61103b601982612a6d565b60405180604001604052806002815260200161313360f01b81525090610d485760405162461bcd60e51b8152600401610b7f9190613a4e565b6002600c5414156110975760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a81b900460ff16156110c65760405162461bcd60e51b8152600401610b7f90614070565b610f8d33612a82565b6060610cc2601b612ac3565b6002600c5414156110fe5760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff161561112d5760405162461bcd60e51b8152600401610b7f90614092565b600d546001600160a01b031663d505accf336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604481018890526064810187905260ff8616608482015260a4810185905260c4810184905260e401600060405180830381600087803b1580156111ab57600080fd5b505af11580156111bf573d6000803e3d6000fd5b505050506111cd610f883390565b6111d685612ad0565b50506001600c55505050565b600a546001600160a01b03163314806111ff57506111ff33610ce0565b61121b5760405162461bcd60e51b8152600401610b7f90613ffa565b61103b601b82612a6d565b6000610b4f601983612681565b600a546001600160a01b0316331461125d5760405162461bcd60e51b8152600401610b7f90613f22565b306001600160a01b0316816001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112a057600080fd5b505afa1580156112b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d89190613e61565b6001600160a01b031614801561136f5750306001600160a01b0316826001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561132c57600080fd5b505afa158015611340573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113649190613e61565b6001600160a01b0316145b60405180604001604052806002815260200161313760f01b815250906113a85760405162461bcd60e51b8152600401610b7f9190613a4e565b50600e54604051636cb56d1960e01b81526001600160a01b038481166004830152838116602483015290911690636cb56d1990604401600060405180830381600087803b1580156113f857600080fd5b505af115801561140c573d6000803e3d6000fd5b505060405163ce5494bb60e01b81526001600160a01b038516925063ce5494bb915061143c908490600401613ac2565b600060405180830381600087803b15801561145657600080fd5b505af115801561146a573d6000803e3d6000fd5b505050505050565b600a546001600160a01b031633148061148f575061148f33610ce0565b6114ab5760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612b3e565b600a546001600160a01b031633146114dd5760405162461bcd60e51b8152600401610b7f90613f22565b604080518082019091526002815261313160f01b60208201526127108211156115195760405162461bcd60e51b8152600401610b7f9190613a4e565b50601d5460408051918252602082018390527f905d672396c48f9d1e13c57aec0819f00d39364ab4bf40a46a687aa607b67d81910160405180910390a1601d55565b600554610100900460ff1680611574575060055460ff16155b6115905760405162461bcd60e51b8152600401610b7f906140b2565b600554610100900460ff161580156115b2576005805461ffff19166101011790555b604080518082019091526002815261031360f41b60208201526001600160a01b0384166115f25760405162461bcd60e51b8152600401610b7f9190613a4e565b50604080518082019091526002815261031360f41b60208201526001600160a01b0383166116335760405162461bcd60e51b8152600401610b7f9190613a4e565b5061163e8585612ba3565b61164785612bca565b61164f612c49565b600d80546001600160a01b0319166001600160a01b03851617905561167633601990612a6d565b60405180604001604052806002815260200161313360f01b815250906116af5760405162461bcd60e51b8152600401610b7f9190613a4e565b506116bb601b33612a6d565b60405180604001604052806002815260200161313360f01b815250906116f45760405162461bcd60e51b8152600401610b7f9190613a4e565b50600e80546001600160a01b0319166001600160a01b03841617905560c8601d55611388601e556001601f558015611732576005805461ff00191690555b5050505050565b600a546001600160a01b031633146117635760405162461bcd60e51b8152600401610b7f90613f22565b604080518082019091526002815261031360f41b60208201526001600160a01b0382166117a35760405162461bcd60e51b8152600401610b7f9190613a4e565b50600f546040516001600160a01b038084169216907fe239974dad08ac696e723caf1886bd0b5afc0870088f9a1266082757f824927690600090a3600f80546001600160a01b0319166001600160a01b0392909216919091179055565b6060610cc26019612ac3565b606060048054610abb90613ee7565b600061182660025490565b15806118375750611835611d3d565b155b156118cd57600d60009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561188a57600080fd5b505afa15801561189e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c29190614100565b610cc290600a614201565b6002546118d8611d3d565b6118ea90670de0b6b3a7640000614210565b610cc2919061422f565b600a546001600160a01b0316331461191e5760405162461bcd60e51b8152600401610b7f90613f22565b601e5481141560405180604001604052806002815260200161333160f01b8152509061195d5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601e5460408051918252602082018390527fafe4d3ceb3295a8d4ef49288a92d32d94e39396e823d414b81caff61b9fc3990910160405180910390a1601e55565b600e54604051639f2b283360e01b81526000916001600160a01b031690639f2b2833906119d0908590600401613ac2565b60206040518083038186803b1580156119e857600080fd5b505afa1580156119fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4f9190614020565b6000610b4b3384846126b8565b6002600c541415611a505760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff1615611a7f5760405162461bcd60e51b8152600401610b7f90614092565b611a8833612a82565b610f9681612ad0565b600e546040805163b49a60bb60e01b815290516060926001600160a01b03169163b49a60bb916004808301926000929190829003018186803b158015610c8657600080fd5b600e54604051632d90c87b60e21b81526000916001600160a01b03169063b64321ec906119d0908590600401613ac2565b600a546001600160a01b03163314611b315760405162461bcd60e51b8152600401610b7f90613f22565b6001600160a01b038116611b835760405162461bcd60e51b815260206004820152601960248201527870726f706f7365642d676f7665726e6f722d69732d7a65726f60381b6044820152606401610b7f565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6002600c541415611bc85760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff1615611bf75760405162461bcd60e51b8152600401610b7f90614092565b611a8833612799565b600d546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611c31903090600401613ac2565b60206040518083038186803b158015610ef557600080fd5b6000601f54821015604051806040016040528060018152602001603160f81b81525090611c895760405162461bcd60e51b8152600401610b7f9190613a4e565b506000612710600e60009054906101000a90046001600160a01b03166001600160a01b031663346162d56040518163ffffffff1660e01b815260040160206040518083038186803b158015611cdd57600080fd5b505afa158015611cf1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d159190614020565b611d1f9085614210565b611d29919061422f565b9050610ea9611d388285613ed0565b612391565b6000611d47611c00565b600e60009054906101000a90046001600160a01b03166001600160a01b031663fc7b9c186040518163ffffffff1660e01b815260040160206040518083038186803b158015611d9557600080fd5b505afa158015611da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dcd9190614020565b610cc29190613eb8565b83421115611e275760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610b7f565b6001600160a01b0387811660008181526009602090815260408083205481517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98185015280830195909552948b166060850152608084018a905260a0840185905260c08085018a90528151808603909101815260e09094019052825192019190912090611eb261293b565b60405161190160f01b60208201526022810191909152604281018390526062016040516020818303038152906040528051906020012090506000611ef882888888612cf7565b90508a6001600160a01b0316816001600160a01b031614611f5b5760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610b7f565b611f66846001613eb8565b6001600160a01b038c16600090815260096020526040902055611f8a8b8b8b61255c565b5050505050505050505050565b600e54604051636a9eee1360e11b81526000916001600160a01b03169063d53ddc26906119d0908590600401613ac2565b600a546001600160a01b0316331480611fe55750611fe533610ce0565b6120015760405162461bcd60e51b8152600401610b7f90613ffa565b610d0f601b826126a3565b6000610b4f601b83612681565b801561207d57600e546001600160a01b0316637f13086e33836040518363ffffffff1660e01b815260040161204f929190614251565b600060405180830381600087803b15801561206957600080fd5b505af1158015611732573d6000803e3d6000fd5b50565b600a546001600160a01b031633148061209d575061209d33610ce0565b6120b95760405162461bcd60e51b8152600401610b7f90613ffa565b600d546040805180820190915260018152600760fb1b6020820152906001600160a01b03838116911614156121015760405162461bcd60e51b8152600401610b7f9190613a4e565b50600a546040516370a0823160e01b815261207d916001600160a01b0390811691908416906370a082319061213a903090600401613ac2565b60206040518083038186803b15801561215257600080fd5b505afa158015612166573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218a9190614020565b6001600160a01b03841691906124c3565b600b546001600160a01b031633146121f15760405162461bcd60e51b81526020600482015260196024820152783737ba16ba343296b83937b837b9b2b216b3b7bb32b93737b960391b6044820152606401610b7f565b600b54600a546040516001600160a01b0392831692909116907fd4459d5b8b913cab0244230fd9b1c08b6ceace7fe9230e60d0f74cbffdf849d090600090a3600b8054600a80546001600160a01b03199081166001600160a01b03841617909155169055565b600a546001600160a01b0316331480612274575061227433610ce0565b6122905760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612e88565b600e5460408051631f8f738360e31b815290516000926001600160a01b03169163fc7b9c18916004808301926020929190829003018186803b158015610ef557600080fd5b600a546001600160a01b03163314806122fa57506122fa33610ce0565b6123165760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612eee565b60006123306301e13380612710614210565b8361233b8642613ed0565b601d546123489190614210565b6123529190614210565b61235c919061422f565b90506000612710601e54846123719190614210565b61237b919061422f565b905080821115612389578091505b509392505050565b60008061239c61181b565b6123ae84670de0b6b3a7640000614210565b6123b8919061422f565b9050670de0b6b3a76400006123cb61181b565b6123d59083614210565b6123df919061422f565b83116123eb5780610ea9565b610ea9816001613eb8565b6001600160a01b03821661244c5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610b7f565b806002600082825461245e9190613eb8565b90915550506001600160a01b0382166000908152602081905260408120805483929061248b908490613eb8565b90915550506040518181526001600160a01b038316906000906000805160206142e98339815191529060200160405180910390a35050565b6125198363a9059cbb60e01b84846040516024016124e2929190614251565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f6a565b505050565b6040516001600160a01b03808516602483015283166044820152606481018290526125569085906323b872dd60e01b906084016124e2565b50505050565b6001600160a01b0383166125be5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610b7f565b6001600160a01b03821661261f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610b7f565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03811660009081526001830160205260408120541515610ea9565b6000610ea9836001600160a01b03841661303c565b600f546001600160a01b03161561278e57600f5460405163632447c960e01b81526001600160a01b039091169063632447c9906126f9908690600401613ac2565b600060405180830381600087803b15801561271357600080fd5b505af1158015612727573d6000803e3d6000fd5b5050600f5460405163632447c960e01b81526001600160a01b03909116925063632447c9915061275b908590600401613ac2565b600060405180830381600087803b15801561277557600080fd5b505af1158015612789573d6000803e3d6000fd5b505050505b61251983838361312f565b600f546001600160a01b03161561207d57600f5460405163632447c960e01b81526001600160a01b039091169063632447c99061204f908490600401613ac2565b6040805180820190915260018152601960f91b6020820152816128105760405162461bcd60e51b8152600401610b7f9190613a4e565b5060008061281d836132f5565b91509150801561284257600061283283612391565b905083811015612840578093505b505b61284c338461339c565b612855826134d9565b50604080518481526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a2505050565b600e5460405163228bfd9f60e01b8152600091829182916001600160a01b03169063228bfd9f906128cb908890600401613ac2565b6101206040518083038186803b1580156128e457600080fd5b505afa1580156128f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291c9190613df1565b505050509450945050505061293282828661231e565b95945050505050565b600060085446141561294e575060065490565b6007546040805180820190915260018152603160f81b602090910152610cc2907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f907fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66134f6565b600b54600160a01b900460ff166129fc5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd0b5c185d5cd95960b21b6044820152606401610b7f565b600b54600160a81b900460ff1615612a265760405162461bcd60e51b8152600401610b7f90614070565b600b805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b604051612a639190613ac2565b60405180910390a1565b6000610ea9836001600160a01b03841661353f565b600f546001600160a01b03161561207d57600f5460405163d279c19160e01b81526001600160a01b039091169063d279c1919061204f908490600401613ac2565b60606000610ea98361358e565b6000612adb82611c49565b9050612af533600d546001600160a01b031690308561251e565b612aff33826123f6565b604080518281526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a25050565b600b54600160a01b900460ff1615612b685760405162461bcd60e51b8152600401610b7f90614092565b600b805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a563390565b8151612bb6906003906020850190613966565b508051612519906004906020840190613966565b80516020808301919091206007819055466008556040805180820190915260018152603160f81b920191909152612c43907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f907fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66134f6565b60065550565b600554610100900460ff1680612c62575060055460ff16155b612c7e5760405162461bcd60e51b8152600401610b7f906140b2565b600554610100900460ff16158015612ca0576005805461ffff19166101011790555b600a80546001600160a01b0319163390811790915560405181906000907fd4459d5b8b913cab0244230fd9b1c08b6ceace7fe9230e60d0f74cbffdf849d0908290a350801561207d576005805461ff001916905550565b60006fa2a8918ca85bafe22016d0b997e4df60600160ff1b03821115612d6a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610b7f565b8360ff16601b1480612d7f57508360ff16601c145b612dd65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610b7f565b6040805160008082526020820180845288905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa158015612e2a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166129325760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610b7f565b600b54600160a81b900460ff1615612eb25760405162461bcd60e51b8152600401610b7f90614070565b600b805461ffff60a01b191661010160a01b1790557f28b4c24cb1012c094cd2f59f98e89d791973295f8fda6eaa118022d6d318960a33612a56565b600b54600160a81b900460ff16612f365760405162461bcd60e51b815260206004820152600c60248201526b3737ba16b9b43aba3237bbb760a11b6044820152606401610b7f565b600b805460ff60a81b191690557fece7583a70a505ef0e36d4dec768f5ae597713e09c26011022599ee01abdabfc33612a56565b6000612fbf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135ea9092919063ffffffff16565b8051909150156125195780806020019051810190612fdd919061426a565b6125195760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610b7f565b60008181526001830160205260408120548015613125576000613060600183613ed0565b855490915060009061307490600190613ed0565b90508181146130d957600086600001828154811061309457613094614285565b90600052602060002001549050808760000184815481106130b7576130b7614285565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806130ea576130ea61429b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b4f565b6000915050610b4f565b6001600160a01b0383166131935760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610b7f565b6001600160a01b0382166131f55760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610b7f565b6001600160a01b0383166000908152602081905260409020548181101561326d5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610b7f565b6132778282613ed0565b6001600160a01b0380861660009081526020819052604080822093909355908516815290812080548492906132ad908490613eb8565b92505081905550826001600160a01b0316846001600160a01b03166000805160206142e9833981519152846040516132e791815260200190565b60405180910390a350505050565b600080670de0b6b3a764000061330961181b565b6133139085614210565b61331d919061422f565b91506000613329611c00565b90508083111561335f576133456133408285613ed0565b613601565b61334d611c00565b90508083111561335f57809250600191505b6040805180820190915260018152603160f81b6020820152836133955760405162461bcd60e51b8152600401610b7f9190613a4e565b5050915091565b6001600160a01b0382166133fc5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610b7f565b6001600160a01b038216600090815260208190526040902054818110156134705760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610b7f565b61347a8282613ed0565b6001600160a01b038416600090815260208190526040812091909155600280548492906134a8908490613ed0565b90915550506040518281526000906001600160a01b038516906000805160206142e983398151915290602001612674565b60006134f233600d546001600160a01b031690846124c3565b5090565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b600081815260018301602052604081205461358657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b4f565b506000610b4f565b6060816000018054806020026020016040519081016040528092919081815260200182805480156135de57602002820191906000526020600020905b8154815260200190600101908083116135ca575b50505050509050919050565b60606135f98484600085613805565b949350505050565b6000806000806000613611610c41565b805190915060005b818110156137fb57600061362d858a613ed0565b9050600084838151811061364357613643614285565b6020908102919091010151600e54604051639f2b283360e01b81529192506001600160a01b031690639f2b28339061367f908490600401613ac2565b60206040518083038186803b15801561369757600080fd5b505afa1580156136ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136cf9190614020565b9850886136dd5750506137e9565b888211156136e9578891505b6136f1611c00565b604051632e1a7d4d60e01b8152600481018490529098506001600160a01b03821690632e1a7d4d90602401600060405180830381600087803b15801561373657600080fd5b505af1925050508015613747575060015b6137525750506137e9565b8761375b611c00565b6137659190613ed0565b600e54604051632fb9ba3160e01b81529198506001600160a01b031690632fb9ba31906137989084908b90600401614251565b600060405180830381600087803b1580156137b257600080fd5b505af11580156137c6573d6000803e3d6000fd5b5050505086866137d69190613eb8565b95508986106137e65750506137fb565b50505b806137f3816142b1565b915050613619565b5050505050505050565b6060824710156138665760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610b7f565b843b6138b45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7f565b600080866001600160a01b031685876040516138d091906142cc565b60006040518083038185875af1925050503d806000811461390d576040519150601f19603f3d011682016040523d82523d6000602084013e613912565b606091505b509150915061392282828661392d565b979650505050505050565b6060831561393c575081610ea9565b82511561394c5782518084602001fd5b8160405162461bcd60e51b8152600401610b7f9190613a4e565b82805461397290613ee7565b90600052602060002090601f01602090048101928261399457600085556139da565b82601f106139ad57805160ff19168380011785556139da565b828001600101855582156139da579182015b828111156139da5782518255916020019190600101906139bf565b506134f29291505b808211156134f257600081556001016139e2565b600080600060608486031215613a0b57600080fd5b505081359360208301359350604090920135919050565b60005b83811015613a3d578181015183820152602001613a25565b838111156125565750506000910152565b6020815260008251806020840152613a6d816040850160208701613a22565b601f01601f19169190910160400192915050565b6001600160a01b038116811461207d57600080fd5b60008060408385031215613aa957600080fd5b8235613ab481613a81565b946020939093013593505050565b6001600160a01b0391909116815260200190565b600060208284031215613ae857600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015613b305783516001600160a01b031683529284019291840191600101613b0b565b50909695505050505050565b600060208284031215613b4e57600080fd5b8135610ea981613a81565b600080600060608486031215613b6e57600080fd5b8335613b7981613a81565b92506020840135613b8981613a81565b929592945050506040919091013590565b60ff8116811461207d57600080fd5b600080600080600060a08688031215613bc157600080fd5b85359450602086013593506040860135613bda81613b9a565b94979396509394606081013594506080013592915050565b60008060408385031215613c0557600080fd5b8235613c1081613a81565b91506020830135613c2081613a81565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613c6a57613c6a613c2b565b604052919050565b600082601f830112613c8357600080fd5b813567ffffffffffffffff811115613c9d57613c9d613c2b565b613cb0601f8201601f1916602001613c41565b818152846020838601011115613cc557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613cf857600080fd5b843567ffffffffffffffff80821115613d1057600080fd5b613d1c88838901613c72565b95506020870135915080821115613d3257600080fd5b50613d3f87828801613c72565b9350506040850135613d5081613a81565b91506060850135613d6081613a81565b939692955090935050565b600080600080600080600060e0888a031215613d8657600080fd5b8735613d9181613a81565b96506020880135613da181613a81565b955060408801359450606088013593506080880135613dbf81613b9a565b9699959850939692959460a0840135945060c09093013592915050565b80518015158114613dec57600080fd5b919050565b60008060008060008060008060006101208a8c031215613e1057600080fd5b613e198a613ddc565b985060208a0151975060408a0151965060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a015191506101008a015190509295985092959850929598565b600060208284031215613e7357600080fd5b8151610ea981613a81565b60008060408385031215613e9157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b60008219821115613ecb57613ecb613ea2565b500190565b600082821015613ee257613ee2613ea2565b500390565b600181811c90821680613efb57607f821691505b60208210811415613f1c57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600c908201526b3737ba16b3b7bb32b93737b960a11b604082015260600190565b60006020808385031215613f5b57600080fd5b825167ffffffffffffffff80821115613f7357600080fd5b818501915085601f830112613f8757600080fd5b815181811115613f9957613f99613c2b565b8060051b9150613faa848301613c41565b8181529183018401918481019088841115613fc457600080fd5b938501935b83851015613fee5784519250613fde83613a81565b8282529385019390850190613fc9565b98975050505050505050565b6020808252600c908201526b3737ba16b096b5b2b2b832b960a11b604082015260600190565b60006020828403121561403257600080fd5b5051919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526008908201526739b43aba3237bbb760c11b604082015260600190565b6020808252600690820152651c185d5cd95960d21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60006020828403121561411257600080fd5b8151610ea981613b9a565b600181815b8085111561415857816000190482111561413e5761413e613ea2565b8085161561414b57918102915b93841c9390800290614122565b509250929050565b60008261416f57506001610b4f565b8161417c57506000610b4f565b8160018114614192576002811461419c576141b8565b6001915050610b4f565b60ff8411156141ad576141ad613ea2565b50506001821b610b4f565b5060208310610133831016604e8410600b84101617156141db575081810a610b4f565b6141e5838361411d565b80600019048211156141f9576141f9613ea2565b029392505050565b6000610ea960ff841683614160565b600081600019048311821515161561422a5761422a613ea2565b500290565b60008261424c57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b03929092168252602082015260400190565b60006020828403121561427c57600080fd5b610ea982613ddc565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60006000198214156142c5576142c5613ea2565b5060010190565b600082516142de818460208701613a22565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220abf1e07fafbaa608304f172200235d161aa1ebbaa8b9d8c1ba464cd12f8d9be264736f6c63430008090033

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

000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b56657370657220706f6f6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000576506f6f6c000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : name_ (string): Vesper pool
Arg [1] : symbol_ (string): vPool
Arg [2] : token_ (address): 0x0000000000000000000000000000000000000000

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [4] : 56657370657220706f6f6c000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [6] : 76506f6f6c000000000000000000000000000000000000000000000000000000


[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.