ETH Price: $2,046.34 (+0.96%)

Token

StrategyBalancerbb-a-USD ()
 

Overview

Max Total Supply

0 StrategyBalancerbb-a-USD

Holders

0

Transfers

-
0

Market

Onchain Market Cap

-

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 0 Decimals)

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

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
StrategyBalancerClonable

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, GNU AGPLv3 license
/**
 *Submitted for verification at Etherscan.io on 2022-08-26
*/

// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

// File: Address.sol

/**
 * @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) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @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");
        return _functionCallWithValue(target, data, value, errorMessage);
    }

    function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
        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: Context.sol

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN 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 payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

// File: IERC20.sol

/**
 * @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: IGauge.sol

interface IGauge {
    function deposit(uint256 amount) external;

    function withdraw(uint256 amount) external;

    function balanceOf(address) external view returns (uint256);

    /**
     * @notice Claim available reward tokens for `_addr`
     * @param _addr Address to claim for
     * @param _receiver Address to transfer rewards to - if set to
     *                  ZERO_ADDRESS, uses the default reward receiver
     *                  for the caller
     */
    function claim_rewards(address _addr, address _receiver) external;

    // The address of the LP token that may be deposited into the gauge.
    function lp_token() external view returns (address);

    function rewarded_token() external returns (address);

    // Number of rewards tokens.
    function reward_count() external view returns (uint256);

    // Address of a reward token at a given index.
    function reward_tokens(uint256 index) external view returns (address);
}
// File: ITradeFactory.sol

interface ITradeFactory {
    function enable(address, address) external;
}
// File: IVoteEscrow.sol

interface IVoteEscrow {
    function create_lock(uint256, uint256) external;

    function increase_amount(uint256) external;

    function withdraw() external;
}
// File: Math.sol

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

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

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

// File: ReentrancyGuard.sol

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
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 () internal {
        _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: SafeMath.sol

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

// File: ERC20.sol

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

    mapping (address => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name, string memory symbol) public {
        _name = name;
        _symbol = symbol;
        _decimals = 18;
    }

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

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

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

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

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view 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);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

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

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

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(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 = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(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);

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     *
     * This is 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 Sets {decimals} to a value other than the default one of 18.
     *
     * WARNING: This function should only be called from the constructor. Most
     * applications that interact with token contracts will not expect
     * {decimals} to ever change, and may work incorrectly if it does.
     */
    function _setupDecimals(uint8 decimals_) internal {
        _decimals = decimals_;
    }

    /**
     * @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: SafeERC20.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 SafeMath for uint256;
    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).add(value);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
        _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");
        }
    }
}

interface IBalancerPool is IERC20 {
    enum SwapKind {GIVEN_IN, GIVEN_OUT}

    struct SwapRequest {
        SwapKind kind;
        IERC20 tokenIn;
        IERC20 tokenOut;
        uint256 amount;
        // Misc data
        bytes32 poolId;
        uint256 lastChangeBlock;
        address from;
        address to;
        bytes userData;
    }

    // virtual price of bpt
    function getRate() external view returns (uint);

    function getPoolId() external view returns (bytes32 poolId);

    function symbol() external view returns (string memory s);

    function onSwap(
        SwapRequest memory swapRequest,
        uint256[] memory balances,
        uint256 indexIn,
        uint256 indexOut
    ) external view returns (uint256 amount);
}

interface IBalancerVault {
    enum PoolSpecialization {GENERAL, MINIMAL_SWAP_INFO, TWO_TOKEN}
    enum JoinKind {INIT, EXACT_TOKENS_IN_FOR_BPT_OUT, TOKEN_IN_FOR_EXACT_BPT_OUT, ALL_TOKENS_IN_FOR_EXACT_BPT_OUT}
    enum ExitKind {EXACT_BPT_IN_FOR_ONE_TOKEN_OUT, EXACT_BPT_IN_FOR_TOKENS_OUT, BPT_IN_FOR_EXACT_TOKENS_OUT}
    enum SwapKind {GIVEN_IN, GIVEN_OUT}

    /**
     * @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the
     * `assets` array passed to that function, and ETH assets are converted to WETH.
     *
     * If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out
     * from the previous swap, depending on the swap kind.
     *
     * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
     * used to extend swap behavior.
     */
    struct BatchSwapStep {
        bytes32 poolId;
        uint256 assetInIndex;
        uint256 assetOutIndex;
        uint256 amount;
        bytes userData;
    }
    /**
     * @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the
     * `recipient` account.
     *
     * If the caller is not `sender`, it must be an authorized relayer for them.
     *
     * If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20
     * transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender`
     * must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of
     * `joinPool`.
     *
     * If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of
     * transferred. This matches the behavior of `exitPool`.
     *
     * Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a
     * revert.
     */
    struct FundManagement {
        address sender;
        bool fromInternalBalance;
        address payable recipient;
        bool toInternalBalance;
    }

    /**
     * @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on
     * the `kind` value.
     *
     * `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address).
     * Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault.
     *
     * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
     * used to extend swap behavior.
     */
    struct SingleSwap {
        bytes32 poolId;
        SwapKind kind;
        IAsset assetIn;
        IAsset assetOut;
        uint256 amount;
        bytes userData;
    }

    // enconding formats https://github.com/balancer-labs/balancer-v2-monorepo/blob/master/pkg/balancer-js/src/pool-weighted/encoder.ts
    struct JoinPoolRequest {
        address[] assets;
        uint256[] maxAmountsIn;
        bytes userData;
        bool fromInternalBalance;
    }

    struct ExitPoolRequest {
        address[] assets;
        uint256[] minAmountsOut;
        bytes userData;
        bool toInternalBalance;
    }

    function joinPool(
        bytes32 poolId,
        address sender,
        address recipient,
        JoinPoolRequest memory request
    ) external payable;

    function exitPool(
        bytes32 poolId,
        address sender,
        address payable recipient,
        ExitPoolRequest calldata request
    ) external;

    function getPool(bytes32 poolId) external view returns (address poolAddress, PoolSpecialization);

    function getPoolTokenInfo(bytes32 poolId, IERC20 token) external view returns (
        uint256 cash,
        uint256 managed,
        uint256 lastChangeBlock,
        address assetManager
    );

    function getPoolTokens(bytes32 poolId) external view returns (
        IERC20[] calldata tokens,
        uint256[] calldata balances,
        uint256 lastChangeBlock
    );
    /**
     * @dev Performs a swap with a single Pool.
     *
     * If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens
     * taken from the Pool, which must be greater than or equal to `limit`.
     *
     * If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens
     * sent to the Pool, which must be less than or equal to `limit`.
     *
     * Internal Balance usage and the recipient are determined by the `funds` struct.
     *
     * Emits a `Swap` event.
     */
    function swap(
        SingleSwap memory singleSwap,
        FundManagement memory funds,
        uint256 limit,
        uint256 deadline
    ) external returns (uint256 amountCalculated);

    /**
     * @dev Performs a series of swaps with one or multiple Pools. In each individual swap, the caller determines either
     * the amount of tokens sent to or received from the Pool, depending on the `kind` value.
     *
     * Returns an array with the net Vault asset balance deltas. Positive amounts represent tokens (or ETH) sent to the
     * Vault, and negative amounts represent tokens (or ETH) sent by the Vault. Each delta corresponds to the asset at
     * the same index in the `assets` array.
     *
     * Swaps are executed sequentially, in the order specified by the `swaps` array. Each array element describes a
     * Pool, the token to be sent to this Pool, the token to receive from it, and an amount that is either `amountIn` or
     * `amountOut` depending on the swap kind.
     *
     * Multihop swaps can be executed by passing an `amount` value of zero for a swap. This will cause the amount in/out
     * of the previous swap to be used as the amount in for the current one. In a 'given in' swap, 'tokenIn' must equal
     * the previous swap's `tokenOut`. For a 'given out' swap, `tokenOut` must equal the previous swap's `tokenIn`.
     *
     * The `assets` array contains the addresses of all assets involved in the swaps. These are either token addresses,
     * or the IAsset sentinel value for ETH (the zero address). Each entry in the `swaps` array specifies tokens in and
     * out by referencing an index in `assets`. Note that Pools never interact with ETH directly: it will be wrapped to
     * or unwrapped from WETH by the Vault.
     *
     * Internal Balance usage, sender, and recipient are determined by the `funds` struct. The `limits` array specifies
     * the minimum or maximum amount of each token the vault is allowed to transfer.
     *
     * `batchSwap` can be used to make a single swap, like `swap` does, but doing so requires more gas than the
     * equivalent `swap` call.
     *
     * Emits `Swap` events.
     */
    function batchSwap(
        SwapKind kind,
        BatchSwapStep[] memory swaps,
        IAsset[] memory assets,
        FundManagement memory funds,
        int256[] memory limits,
        uint256 deadline
    ) external payable returns (int256[] memory);
}

interface IAsset {
    // solhint-disable-previous-line no-empty-blocks
}

interface IBalancerVaultHelper {
    struct JoinPoolRequest {
        IAsset[] assets;
        uint256[] maxAmountsIn;
        bytes userData;
        bool fromInternalBalance;
    }

    struct ExitPoolRequest {
        IAsset[] assets;
        uint256[] minAmountsOut;
        bytes userData;
        bool toInternalBalance;
    }

    function queryJoin(
        bytes32 poolId,
        address sender,
        address recipient,
        IBalancerVault.JoinPoolRequest memory request
    ) external view returns (uint256 bptOut, uint256[] memory amountsIn);

    function queryExit(
        bytes32 poolId,
        address sender,
        address recipient,
        IBalancerVault.ExitPoolRequest memory request
    ) external view returns (uint256 bptIn, uint256[] memory amountsOut);
}

interface ILiquidityGaugeFactory {
    // Gets the gauge for a given pool.
    function getPoolGauge(address pool) external view returns (address);
}

// File: YearnBalancerVoter.sol

/**
 * @dev Where Yearn stores veBAL and boosted BPTs (balancer's LP tokens).
 */
contract YearnBalancerVoter {
    using SafeERC20 for IERC20;
    using Address for address;
    using SafeMath for uint256;

    IERC20 internal constant WETH =
        IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
    IERC20 internal constant BAL =
        IERC20(0xba100000625a3754423978a60c9317c58a424e3D);
    IERC20 internal constant balWethLP =
        IERC20(0x5c6Ee304399DBdB9C8Ef030aB642B10820DB8F56);
    IVoteEscrow internal constant veBAL =
        IVoteEscrow(0xC128a9954e6c874eA3d62ce62B468bA073093F25);

    address public governance;
    address public pendingGovernance;
    address public proxy;
    IBalancerVault internal constant balancerVault =
        IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
    address[] internal assets;

    modifier onlyProxyOrGovernance() {
        require(msg.sender == proxy || msg.sender == governance, "!authorized");
        _;
    }

    constructor() public {
        governance = 0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52;
        assets = [address(BAL), address(WETH)];
    }

    function execute(
        address to,
        uint256 value,
        bytes calldata data
    ) external onlyProxyOrGovernance returns (bool, bytes memory) {
        (bool success, bytes memory result) = to.call{value: value}(data);

        return (success, result);
    }

    function getName() external pure returns (string memory) {
        return "YearnBalancerVoter";
    }

    function setProxy(address _proxy) external {
        require(msg.sender == governance, "!governance");
        proxy = _proxy;
    }

    function setGovernance(address _governance) external {
        require(msg.sender == governance, "!governance");
        pendingGovernance = _governance;
    }

    function acceptGovernance() external {
        require(msg.sender == pendingGovernance, "!pending_governance");
        governance = msg.sender;
        pendingGovernance = address(0);
    }

    // Controller only function for creating additional rewards from dust
    function withdraw(IERC20 _asset) external returns (uint256 balance) {
        require(msg.sender == proxy, "!controller");
        _asset.safeTransfer(proxy, _asset.balanceOf(address(this)));
    }

    function createLock(uint256 _value, uint256 _unlockTime)
        external
        onlyProxyOrGovernance
    {
        _checkAllowance(address(veBAL), balWethLP, _value);
        veBAL.create_lock(_value, _unlockTime);
    }

    function increaseAmountMax() external onlyProxyOrGovernance {
        uint256 _balanceOfBPT = balWethLP.balanceOf(address(this));
        _checkAllowance(address(veBAL), balWethLP, _balanceOfBPT);
        veBAL.increase_amount(_balanceOfBPT);
    }

    function increaseAmountExact(uint256 _amount)
        external
        onlyProxyOrGovernance
    {
        uint256 _balanceOfBPT = balWethLP.balanceOf(address(this));
        require(_amount <= _balanceOfBPT, "!too_much");
        _checkAllowance(address(veBAL), balWethLP, _amount);
        veBAL.increase_amount(_amount);
    }

    function release() external onlyProxyOrGovernance {
        veBAL.withdraw();
    }

    function convertBALIntoBPT(uint256 _amount) external onlyProxyOrGovernance {
        _convertBALIntoBPT(_amount);
    }

    function convertLooseBALIntoBPT() external onlyProxyOrGovernance {
        uint256 _balanceOfBal = BAL.balanceOf(address(this));
        if (_balanceOfBal > 0) {
            _convertBALIntoBPT(_balanceOfBal);
        }
    }

    function convertBPTIntoBAL(uint256 _amount) external onlyProxyOrGovernance {
        _convertBPTIntoBAL(_amount);
    }

    function convertLooseBPTIntoBAL() external onlyProxyOrGovernance {
        uint256 _balanceOfBpt = balWethLP.balanceOf(address(this));
        if (_balanceOfBpt > 0) {
            _convertBPTIntoBAL(_balanceOfBpt);
        }
    }

    // Converts BAL into the BAL/WETH BPT used for veBAL
    function _convertBALIntoBPT(uint256 _amount) internal {
        _checkAllowance(address(balancerVault), BAL, _amount);
        uint256[] memory amounts = new uint256[](2);
        amounts[0] = _amount; // BAL
        bytes memory userData =
            abi.encode(
                IBalancerVault.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT,
                amounts,
                0
            );
        IBalancerVault.JoinPoolRequest memory request =
            IBalancerVault.JoinPoolRequest(assets, amounts, userData, false);
        balancerVault.joinPool(
            IBalancerPool(address(balWethLP)).getPoolId(),
            address(this),
            address(this),
            request
        );
    }

    function _convertBPTIntoBAL(uint256 _amount) internal {
        _checkAllowance(address(balancerVault), balWethLP, _amount);
        uint256[] memory amounts = new uint256[](2);
        amounts[0] = _amount;
        bytes memory userData =
            abi.encode(
                IBalancerVault.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT,
                _amount,
                0
            );
        IBalancerVault.ExitPoolRequest memory request =
            IBalancerVault.ExitPoolRequest(assets, amounts, userData, false);
        balancerVault.exitPool(
            IBalancerPool(address(balWethLP)).getPoolId(),
            address(this),
            payable(address(this)),
            request
        );
    }

    // _checkAllowance adapted from https://github.com/therealmonoloco/liquity-stability-pool-strategy/blob/1fb0b00d24e0f5621f1e57def98c26900d551089/contracts/Strategy.sol#L316

    function _checkAllowance(
        address _spender,
        IERC20 _token,
        uint256 _amount
    ) internal {
        uint256 _currentAllowance = _token.allowance(address(this), _spender);
        if (_currentAllowance < _amount) {
            _token.safeIncreaseAllowance(_spender, _amount - _currentAllowance);
        }
    }
}

// File: BalancerStrategyVoterProxy.sol

library SafeVoter {
    function safeExecute(
        YearnBalancerVoter voter,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        (bool success, ) = voter.execute(to, value, data);
        require(success);
    }
}

/**
 * @dev Yearn strategies which auto-compound BPT tokens communicate with the Yearn
 * Balancer voter through this contract. We use a proxy because the voter itself holds
 * veBAL, which are locked and prevent us from migrating / upgrading that contract.
 */
contract BalancerStrategyVoterProxy {
    using SafeERC20 for IERC20;
    using Address for address;
    using SafeMath for uint256;
    using SafeVoter for YearnBalancerVoter;

    enum ROLE {GOVERNANCE, VOTER, LOCKER}

    YearnBalancerVoter public voter;

    address public constant balMinter =
        address(0x239e55F427D44C3cc793f49bFB507ebe76638a2b);
    address public constant bal =
        address(0xba100000625a3754423978a60c9317c58a424e3D);
    address public constant gaugeController =
        address(0xC128468b7Ce63eA702C1f104D55A2566b13D3ABD);

    // gauge => strategies
    mapping(address => address) public strategies;
    mapping(address => bool) public voters;
    mapping(address => bool) public lockers;
    address public governance;

    event VoterApproved(address voter);
    event VoterRevoked(address voter);
    event LockerApproved(address locker);
    event LockerRevoked(address locker);
    event StrategyApproved(address strategy);
    event StrategyRevoked(address strategy);
    event NewGovernance(address governance);

    modifier hasRole(ROLE _role) {
        _checkRole(_role);
        _;
    }

    modifier isStrategy(address _gauge) {
        require(strategies[_gauge] == msg.sender, "!strategy");
        _;
    }

    constructor(address _voter) public {
        governance = msg.sender;
        voter = YearnBalancerVoter(_voter);
    }

    function setGovernance(address _governance)
        external
        hasRole(ROLE.GOVERNANCE)
    {
        require(_governance != address(0));
        governance = _governance;
        emit NewGovernance(_governance);
    }

    function approveStrategy(address _gauge, address _strategy)
        external
        hasRole(ROLE.GOVERNANCE)
    {
        strategies[_gauge] = _strategy;
        emit StrategyApproved(_strategy);
    }

    function revokeStrategy(address _gauge) external hasRole(ROLE.GOVERNANCE) {
        require(strategies[_gauge] != address(0), "!exists");
        address _strategy = strategies[_gauge];
        strategies[_gauge] = address(0);
        emit StrategyRevoked(_strategy);
    }

    function approveVoter(address _voter) external hasRole(ROLE.GOVERNANCE) {
        voters[_voter] = true;
        emit VoterApproved(_voter);
    }

    function revokeVoter(address _voter) external hasRole(ROLE.GOVERNANCE) {
        voters[_voter] = false;
        emit VoterRevoked(_voter);
    }

    function approveLocker(address _locker) external hasRole(ROLE.GOVERNANCE) {
        lockers[_locker] = true;
        emit LockerApproved(_locker);
    }

    function revokeLocker(address _locker) external hasRole(ROLE.GOVERNANCE) {
        lockers[_locker] = false;
        emit LockerRevoked(_locker);
    }

    function lock() external {
        voter.increaseAmountMax();
    }

    function transferBALToVoter() external {
        IERC20(bal).transfer(
            address(voter),
            IERC20(bal).balanceOf(address(this))
        );
    }

    function convertAndLockMax() external hasRole(ROLE.LOCKER) {
        voter.convertLooseBALIntoBPT();
        voter.increaseAmountMax();
    }

    function convertAndLockExact(uint256 _amount)
        external
        hasRole(ROLE.LOCKER)
    {
        if (_amount > 0) voter.increaseAmountExact(_amount);
    }

    function withdrawAll(address _gauge, address _token)
        external
        isStrategy(_gauge)
        returns (uint256)
    {
        return withdraw(_gauge, _token, balanceOf(_gauge));
    }

    function deposit(address _gauge, address _token)
        external
        isStrategy(_gauge)
    {
        uint256 _balance = IERC20(_token).balanceOf(address(this));
        IERC20(_token).safeTransfer(address(voter), _balance);
        _balance = IERC20(_token).balanceOf(address(voter));

        voter.safeExecute(
            _token,
            0,
            abi.encodeWithSignature("approve(address,uint256)", _gauge, 0)
        );
        voter.safeExecute(
            _token,
            0,
            abi.encodeWithSignature(
                "approve(address,uint256)",
                _gauge,
                _balance
            )
        );
        voter.safeExecute(
            _gauge,
            0,
            abi.encodeWithSignature("deposit(uint256)", _balance)
        );
    }

    // Claim BAL rewards
    function claimBal(address _gauge) external isStrategy(_gauge) {
        uint256 _balance = IERC20(bal).balanceOf(address(voter));
        voter.safeExecute(
            balMinter,
            0,
            abi.encodeWithSignature("mint(address)", _gauge)
        );
        _balance = (IERC20(bal).balanceOf(address(voter))).sub(_balance);
        voter.safeExecute(
            bal,
            0,
            abi.encodeWithSignature(
                "transfer(address,uint256)",
                msg.sender,
                _balance
            )
        );
    }

    // Claim other rewards
    function claimRewards(address _gauge) external isStrategy(_gauge) {
        voter.safeExecute(
            _gauge,
            0,
            abi.encodeWithSelector(
                IGauge.claim_rewards.selector,
                address(voter),
                msg.sender // This should forward along all rewards to the strategy
            )
        );
    }

    function vote(address _gauge, uint256 _amount)
        external
        hasRole(ROLE.VOTER)
    {
        voter.safeExecute(
            gaugeController,
            0,
            abi.encodeWithSignature(
                "vote_for_gauge_weights(address,uint256)",
                _gauge,
                _amount
            )
        );
    }

    function withdraw(
        address _gauge,
        address _token,
        uint256 _amount
    ) public isStrategy(_gauge) returns (uint256) {
        uint256 _balance = IERC20(_token).balanceOf(address(voter));
        voter.safeExecute(
            _gauge,
            0,
            abi.encodeWithSignature("withdraw(uint256)", _amount)
        );
        _balance = IERC20(_token).balanceOf(address(voter)).sub(_balance);
        voter.safeExecute(
            _token,
            0,
            abi.encodeWithSignature(
                "transfer(address,uint256)",
                msg.sender,
                _balance
            )
        );
        return _balance;
    }

    function balanceOf(address _gauge) public view returns (uint256) {
        return IERC20(_gauge).balanceOf(address(voter));
    }

    function _checkRole(ROLE _role) internal view {
        if (_role == ROLE.GOVERNANCE) {
            require(msg.sender == governance, "!governance");
        } else if (_role == ROLE.VOTER) {
            require(voters[msg.sender], "!voter");
        } else {
            require(lockers[msg.sender], "!locker");
        }
    }
}

// File: BaseStrategy.sol

struct StrategyParams {
    uint256 performanceFee;
    uint256 activation;
    uint256 debtRatio;
    uint256 minDebtPerHarvest;
    uint256 maxDebtPerHarvest;
    uint256 lastReport;
    uint256 totalDebt;
    uint256 totalGain;
    uint256 totalLoss;
}

interface VaultAPI is IERC20 {
    function name() external view returns (string calldata);

    function symbol() external view returns (string calldata);

    function decimals() external view returns (uint256);

    function apiVersion() external pure returns (string memory);

    function permit(
        address owner,
        address spender,
        uint256 amount,
        uint256 expiry,
        bytes calldata signature
    ) external returns (bool);

    // NOTE: Vyper produces multiple signatures for a given function with "default" args
    function deposit() external returns (uint256);

    function deposit(uint256 amount) external returns (uint256);

    function deposit(uint256 amount, address recipient) external returns (uint256);

    // NOTE: Vyper produces multiple signatures for a given function with "default" args
    function withdraw() external returns (uint256);

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

    function withdraw(uint256 maxShares, address recipient) external returns (uint256);

    function token() external view returns (address);

    function strategies(address _strategy) external view returns (StrategyParams memory);

    function pricePerShare() external view returns (uint256);

    function totalAssets() external view returns (uint256);

    function depositLimit() external view returns (uint256);

    function maxAvailableShares() external view returns (uint256);

    /**
     * View how much the Vault would increase this Strategy's borrow limit,
     * based on its present performance (since its last report). Can be used to
     * determine expectedReturn in your Strategy.
     */
    function creditAvailable() external view returns (uint256);

    /**
     * View how much the Vault would like to pull back from the Strategy,
     * based on its present performance (since its last report). Can be used to
     * determine expectedReturn in your Strategy.
     */
    function debtOutstanding() external view returns (uint256);

    /**
     * View how much the Vault expect this Strategy to return at the current
     * block, based on its present performance (since its last report). Can be
     * used to determine expectedReturn in your Strategy.
     */
    function expectedReturn() external view returns (uint256);

    /**
     * This is the main contact point where the Strategy interacts with the
     * Vault. It is critical that this call is handled as intended by the
     * Strategy. Therefore, this function will be called by BaseStrategy to
     * make sure the integration is correct.
     */
    function report(
        uint256 _gain,
        uint256 _loss,
        uint256 _debtPayment
    ) external returns (uint256);

    /**
     * This function should only be used in the scenario where the Strategy is
     * being retired but no migration of the positions are possible, or in the
     * extreme scenario that the Strategy needs to be put into "Emergency Exit"
     * mode in order for it to exit as quickly as possible. The latter scenario
     * could be for any reason that is considered "critical" that the Strategy
     * exits its position as fast as possible, such as a sudden change in
     * market conditions leading to losses, or an imminent failure in an
     * external dependency.
     */
    function revokeStrategy() external;

    /**
     * View the governance address of the Vault to assert privileged functions
     * can only be called by governance. The Strategy serves the Vault, so it
     * is subject to governance defined by the Vault.
     */
    function governance() external view returns (address);

    /**
     * View the management address of the Vault to assert privileged functions
     * can only be called by management. The Strategy serves the Vault, so it
     * is subject to management defined by the Vault.
     */
    function management() external view returns (address);

    /**
     * View the guardian address of the Vault to assert privileged functions
     * can only be called by guardian. The Strategy serves the Vault, so it
     * is subject to guardian defined by the Vault.
     */
    function guardian() external view returns (address);
}

/**
 * This interface is here for the keeper bot to use.
 */
interface StrategyAPI {
    function name() external view returns (string memory);

    function vault() external view returns (address);

    function want() external view returns (address);

    function apiVersion() external pure returns (string memory);

    function keeper() external view returns (address);

    function isActive() external view returns (bool);

    function delegatedAssets() external view returns (uint256);

    function estimatedTotalAssets() external view returns (uint256);

    function tendTrigger(uint256 callCost) external view returns (bool);

    function tend() external;

    function harvestTrigger(uint256 callCost) external view returns (bool);

    function harvest() external;

    event Harvested(uint256 profit, uint256 loss, uint256 debtPayment, uint256 debtOutstanding);
}

interface HealthCheck {
    function check(
        uint256 profit,
        uint256 loss,
        uint256 debtPayment,
        uint256 debtOutstanding,
        uint256 totalDebt
    ) external view returns (bool);
}

/**
 * @title Yearn Base Strategy
 * @author yearn.finance
 * @notice
 *  BaseStrategy implements all of the required functionality to interoperate
 *  closely with the Vault contract. This contract should be inherited and the
 *  abstract methods implemented to adapt the Strategy to the particular needs
 *  it has to create a return.
 *
 *  Of special interest is the relationship between `harvest()` and
 *  `vault.report()'. `harvest()` may be called simply because enough time has
 *  elapsed since the last report, and not because any funds need to be moved
 *  or positions adjusted. This is critical so that the Vault may maintain an
 *  accurate picture of the Strategy's performance. See  `vault.report()`,
 *  `harvest()`, and `harvestTrigger()` for further details.
 */

abstract contract BaseStrategy {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;
    string public metadataURI;

    // health checks
    bool public doHealthCheck;
    address public healthCheck;

    /**
     * @notice
     *  Used to track which version of `StrategyAPI` this Strategy
     *  implements.
     * @dev The Strategy's version must match the Vault's `API_VERSION`.
     * @return A string which holds the current API version of this contract.
     */
    function apiVersion() public pure returns (string memory) {
        return "0.4.3";
    }

    /**
     * @notice This Strategy's name.
     * @dev
     *  You can use this field to manage the "version" of this Strategy, e.g.
     *  `StrategySomethingOrOtherV1`. However, "API Version" is managed by
     *  `apiVersion()` function above.
     * @return This Strategy's name.
     */
    function name() external view virtual returns (string memory);

    /**
     * @notice
     *  The amount (priced in want) of the total assets managed by this strategy should not count
     *  towards Yearn's TVL calculations.
     * @dev
     *  You can override this field to set it to a non-zero value if some of the assets of this
     *  Strategy is somehow delegated inside another part of of Yearn's ecosystem e.g. another Vault.
     *  Note that this value must be strictly less than or equal to the amount provided by
     *  `estimatedTotalAssets()` below, as the TVL calc will be total assets minus delegated assets.
     *  Also note that this value is used to determine the total assets under management by this
     *  strategy, for the purposes of computing the management fee in `Vault`
     * @return
     *  The amount of assets this strategy manages that should not be included in Yearn's Total Value
     *  Locked (TVL) calculation across it's ecosystem.
     */
    function delegatedAssets() external view virtual returns (uint256) {
        return 0;
    }

    VaultAPI public vault;
    address public strategist;
    address public rewards;
    address public keeper;

    IERC20 public want;

    // So indexers can keep track of this
    event Harvested(uint256 profit, uint256 loss, uint256 debtPayment, uint256 debtOutstanding);

    event UpdatedStrategist(address newStrategist);

    event UpdatedKeeper(address newKeeper);

    event UpdatedRewards(address rewards);

    event UpdatedMinReportDelay(uint256 delay);

    event UpdatedMaxReportDelay(uint256 delay);

    event UpdatedProfitFactor(uint256 profitFactor);

    event UpdatedDebtThreshold(uint256 debtThreshold);

    event EmergencyExitEnabled();

    event UpdatedMetadataURI(string metadataURI);

    // The minimum number of seconds between harvest calls. See
    // `setMinReportDelay()` for more details.
    uint256 public minReportDelay;

    // The maximum number of seconds between harvest calls. See
    // `setMaxReportDelay()` for more details.
    uint256 public maxReportDelay;

    // The minimum multiple that `callCost` must be above the credit/profit to
    // be "justifiable". See `setProfitFactor()` for more details.
    uint256 public profitFactor;

    // Use this to adjust the threshold at which running a debt causes a
    // harvest trigger. See `setDebtThreshold()` for more details.
    uint256 public debtThreshold;

    // See note on `setEmergencyExit()`.
    bool public emergencyExit;

    // modifiers
    modifier onlyAuthorized() {
        require(msg.sender == strategist || msg.sender == governance(), "!authorized");
        _;
    }

    modifier onlyEmergencyAuthorized() {
        require(
            msg.sender == strategist || msg.sender == governance() || msg.sender == vault.guardian() || msg.sender == vault.management(),
            "!authorized"
        );
        _;
    }

    modifier onlyStrategist() {
        require(msg.sender == strategist, "!strategist");
        _;
    }

    modifier onlyGovernance() {
        require(msg.sender == governance(), "!authorized");
        _;
    }

    modifier onlyKeepers() {
        require(
            msg.sender == keeper ||
                msg.sender == strategist ||
                msg.sender == governance() ||
                msg.sender == vault.guardian() ||
                msg.sender == vault.management(),
            "!authorized"
        );
        _;
    }

    modifier onlyVaultManagers() {
        require(msg.sender == vault.management() || msg.sender == governance(), "!authorized");
        _;
    }

    constructor(address _vault) public {
        _initialize(_vault, msg.sender, msg.sender, msg.sender);
    }

    /**
     * @notice
     *  Initializes the Strategy, this is called only once, when the
     *  contract is deployed.
     * @dev `_vault` should implement `VaultAPI`.
     * @param _vault The address of the Vault responsible for this Strategy.
     * @param _strategist The address to assign as `strategist`.
     * The strategist is able to change the reward address
     * @param _rewards  The address to use for pulling rewards.
     * @param _keeper The adddress of the _keeper. _keeper
     * can harvest and tend a strategy.
     */
    function _initialize(
        address _vault,
        address _strategist,
        address _rewards,
        address _keeper
    ) internal {
        require(address(want) == address(0), "Strategy already initialized");

        vault = VaultAPI(_vault);
        want = IERC20(vault.token());
        want.safeApprove(_vault, uint256(-1)); // Give Vault unlimited access (might save gas)
        strategist = _strategist;
        rewards = _rewards;
        keeper = _keeper;

        // initialize variables
        minReportDelay = 0;
        maxReportDelay = 86400;
        profitFactor = 100;
        debtThreshold = 0;

        vault.approve(rewards, uint256(-1)); // Allow rewards to be pulled
    }

    function setHealthCheck(address _healthCheck) external onlyVaultManagers {
        healthCheck = _healthCheck;
    }

    function setDoHealthCheck(bool _doHealthCheck) external onlyVaultManagers {
        doHealthCheck = _doHealthCheck;
    }

    /**
     * @notice
     *  Used to change `strategist`.
     *
     *  This may only be called by governance or the existing strategist.
     * @param _strategist The new address to assign as `strategist`.
     */
    function setStrategist(address _strategist) external onlyAuthorized {
        require(_strategist != address(0));
        strategist = _strategist;
        emit UpdatedStrategist(_strategist);
    }

    /**
     * @notice
     *  Used to change `keeper`.
     *
     *  `keeper` is the only address that may call `tend()` or `harvest()`,
     *  other than `governance()` or `strategist`. However, unlike
     *  `governance()` or `strategist`, `keeper` may *only* call `tend()`
     *  and `harvest()`, and no other authorized functions, following the
     *  principle of least privilege.
     *
     *  This may only be called by governance or the strategist.
     * @param _keeper The new address to assign as `keeper`.
     */
    function setKeeper(address _keeper) external onlyAuthorized {
        require(_keeper != address(0));
        keeper = _keeper;
        emit UpdatedKeeper(_keeper);
    }

    /**
     * @notice
     *  Used to change `rewards`. EOA or smart contract which has the permission
     *  to pull rewards from the vault.
     *
     *  This may only be called by the strategist.
     * @param _rewards The address to use for pulling rewards.
     */
    function setRewards(address _rewards) external onlyStrategist {
        require(_rewards != address(0));
        vault.approve(rewards, 0);
        rewards = _rewards;
        vault.approve(rewards, uint256(-1));
        emit UpdatedRewards(_rewards);
    }

    /**
     * @notice
     *  Used to change `minReportDelay`. `minReportDelay` is the minimum number
     *  of blocks that should pass for `harvest()` to be called.
     *
     *  For external keepers (such as the Keep3r network), this is the minimum
     *  time between jobs to wait. (see `harvestTrigger()`
     *  for more details.)
     *
     *  This may only be called by governance or the strategist.
     * @param _delay The minimum number of seconds to wait between harvests.
     */
    function setMinReportDelay(uint256 _delay) external onlyAuthorized {
        minReportDelay = _delay;
        emit UpdatedMinReportDelay(_delay);
    }

    /**
     * @notice
     *  Used to change `maxReportDelay`. `maxReportDelay` is the maximum number
     *  of blocks that should pass for `harvest()` to be called.
     *
     *  For external keepers (such as the Keep3r network), this is the maximum
     *  time between jobs to wait. (see `harvestTrigger()`
     *  for more details.)
     *
     *  This may only be called by governance or the strategist.
     * @param _delay The maximum number of seconds to wait between harvests.
     */
    function setMaxReportDelay(uint256 _delay) external onlyAuthorized {
        maxReportDelay = _delay;
        emit UpdatedMaxReportDelay(_delay);
    }

    /**
     * @notice
     *  Used to change `profitFactor`. `profitFactor` is used to determine
     *  if it's worthwhile to harvest, given gas costs. (See `harvestTrigger()`
     *  for more details.)
     *
     *  This may only be called by governance or the strategist.
     * @param _profitFactor A ratio to multiply anticipated
     * `harvest()` gas cost against.
     */
    function setProfitFactor(uint256 _profitFactor) external onlyAuthorized {
        profitFactor = _profitFactor;
        emit UpdatedProfitFactor(_profitFactor);
    }

    /**
     * @notice
     *  Sets how far the Strategy can go into loss without a harvest and report
     *  being required.
     *
     *  By default this is 0, meaning any losses would cause a harvest which
     *  will subsequently report the loss to the Vault for tracking. (See
     *  `harvestTrigger()` for more details.)
     *
     *  This may only be called by governance or the strategist.
     * @param _debtThreshold How big of a loss this Strategy may carry without
     * being required to report to the Vault.
     */
    function setDebtThreshold(uint256 _debtThreshold) external onlyAuthorized {
        debtThreshold = _debtThreshold;
        emit UpdatedDebtThreshold(_debtThreshold);
    }

    /**
     * @notice
     *  Used to change `metadataURI`. `metadataURI` is used to store the URI
     * of the file describing the strategy.
     *
     *  This may only be called by governance or the strategist.
     * @param _metadataURI The URI that describe the strategy.
     */
    function setMetadataURI(string calldata _metadataURI) external onlyAuthorized {
        metadataURI = _metadataURI;
        emit UpdatedMetadataURI(_metadataURI);
    }

    /**
     * Resolve governance address from Vault contract, used to make assertions
     * on protected functions in the Strategy.
     */
    function governance() internal view returns (address) {
        return vault.governance();
    }

    /**
     * @notice
     *  Provide an accurate conversion from `_amtInWei` (denominated in wei)
     *  to `want` (using the native decimal characteristics of `want`).
     * @dev
     *  Care must be taken when working with decimals to assure that the conversion
     *  is compatible. As an example:
     *
     *      given 1e17 wei (0.1 ETH) as input, and want is USDC (6 decimals),
     *      with USDC/ETH = 1800, this should give back 1800000000 (180 USDC)
     *
     * @param _amtInWei The amount (in wei/1e-18 ETH) to convert to `want`
     * @return The amount in `want` of `_amtInEth` converted to `want`
     **/
    function ethToWant(uint256 _amtInWei) public view virtual returns (uint256);

    /**
     * @notice
     *  Provide an accurate estimate for the total amount of assets
     *  (principle + return) that this Strategy is currently managing,
     *  denominated in terms of `want` tokens.
     *
     *  This total should be "realizable" e.g. the total value that could
     *  *actually* be obtained from this Strategy if it were to divest its
     *  entire position based on current on-chain conditions.
     * @dev
     *  Care must be taken in using this function, since it relies on external
     *  systems, which could be manipulated by the attacker to give an inflated
     *  (or reduced) value produced by this function, based on current on-chain
     *  conditions (e.g. this function is possible to influence through
     *  flashloan attacks, oracle manipulations, or other DeFi attack
     *  mechanisms).
     *
     *  It is up to governance to use this function to correctly order this
     *  Strategy relative to its peers in the withdrawal queue to minimize
     *  losses for the Vault based on sudden withdrawals. This value should be
     *  higher than the total debt of the Strategy and higher than its expected
     *  value to be "safe".
     * @return The estimated total assets in this Strategy.
     */
    function estimatedTotalAssets() public view virtual returns (uint256);

    /*
     * @notice
     *  Provide an indication of whether this strategy is currently "active"
     *  in that it is managing an active position, or will manage a position in
     *  the future. This should correlate to `harvest()` activity, so that Harvest
     *  events can be tracked externally by indexing agents.
     * @return True if the strategy is actively managing a position.
     */
    function isActive() public view returns (bool) {
        return vault.strategies(address(this)).debtRatio > 0 || estimatedTotalAssets() > 0;
    }

    /**
     * Perform any Strategy unwinding or other calls necessary to capture the
     * "free return" this Strategy has generated since the last time its core
     * position(s) were adjusted. Examples include unwrapping extra rewards.
     * This call is only used during "normal operation" of a Strategy, and
     * should be optimized to minimize losses as much as possible.
     *
     * This method returns any realized profits and/or realized losses
     * incurred, and should return the total amounts of profits/losses/debt
     * payments (in `want` tokens) for the Vault's accounting (e.g.
     * `want.balanceOf(this) >= _debtPayment + _profit`).
     *
     * `_debtOutstanding` will be 0 if the Strategy is not past the configured
     * debt limit, otherwise its value will be how far past the debt limit
     * the Strategy is. The Strategy's debt limit is configured in the Vault.
     *
     * NOTE: `_debtPayment` should be less than or equal to `_debtOutstanding`.
     *       It is okay for it to be less than `_debtOutstanding`, as that
     *       should only used as a guide for how much is left to pay back.
     *       Payments should be made to minimize loss from slippage, debt,
     *       withdrawal fees, etc.
     *
     * See `vault.debtOutstanding()`.
     */
    function prepareReturn(uint256 _debtOutstanding)
        internal
        virtual
        returns (
            uint256 _profit,
            uint256 _loss,
            uint256 _debtPayment
        );

    /**
     * Perform any adjustments to the core position(s) of this Strategy given
     * what change the Vault made in the "investable capital" available to the
     * Strategy. Note that all "free capital" in the Strategy after the report
     * was made is available for reinvestment. Also note that this number
     * could be 0, and you should handle that scenario accordingly.
     *
     * See comments regarding `_debtOutstanding` on `prepareReturn()`.
     */
    function adjustPosition(uint256 _debtOutstanding) internal virtual;

    /**
     * Liquidate up to `_amountNeeded` of `want` of this strategy's positions,
     * irregardless of slippage. Any excess will be re-invested with `adjustPosition()`.
     * This function should return the amount of `want` tokens made available by the
     * liquidation. If there is a difference between them, `_loss` indicates whether the
     * difference is due to a realized loss, or if there is some other sitution at play
     * (e.g. locked funds) where the amount made available is less than what is needed.
     *
     * NOTE: The invariant `_liquidatedAmount + _loss <= _amountNeeded` should always be maintained
     */
    function liquidatePosition(uint256 _amountNeeded) internal virtual returns (uint256 _liquidatedAmount, uint256 _loss);

    /**
     * Liquidate everything and returns the amount that got freed.
     * This function is used during emergency exit instead of `prepareReturn()` to
     * liquidate all of the Strategy's positions back to the Vault.
     */

    function liquidateAllPositions() internal virtual returns (uint256 _amountFreed);

    /**
     * @notice
     *  Provide a signal to the keeper that `tend()` should be called. The
     *  keeper will provide the estimated gas cost that they would pay to call
     *  `tend()`, and this function should use that estimate to make a
     *  determination if calling it is "worth it" for the keeper. This is not
     *  the only consideration into issuing this trigger, for example if the
     *  position would be negatively affected if `tend()` is not called
     *  shortly, then this can return `true` even if the keeper might be
     *  "at a loss" (keepers are always reimbursed by Yearn).
     * @dev
     *  `callCostInWei` must be priced in terms of `wei` (1e-18 ETH).
     *
     *  This call and `harvestTrigger()` should never return `true` at the same
     *  time.
     * @param callCostInWei The keeper's estimated gas cost to call `tend()` (in wei).
     * @return `true` if `tend()` should be called, `false` otherwise.
     */
    function tendTrigger(uint256 callCostInWei) public view virtual returns (bool) {
        // We usually don't need tend, but if there are positions that need
        // active maintainence, overriding this function is how you would
        // signal for that.
        // If your implementation uses the cost of the call in want, you can
        // use uint256 callCost = ethToWant(callCostInWei);

        return false;
    }

    /**
     * @notice
     *  Adjust the Strategy's position. The purpose of tending isn't to
     *  realize gains, but to maximize yield by reinvesting any returns.
     *
     *  See comments on `adjustPosition()`.
     *
     *  This may only be called by governance, the strategist, or the keeper.
     */
    function tend() external onlyKeepers {
        // Don't take profits with this call, but adjust for better gains
        adjustPosition(vault.debtOutstanding());
    }

    /**
     * @notice
     *  Provide a signal to the keeper that `harvest()` should be called. The
     *  keeper will provide the estimated gas cost that they would pay to call
     *  `harvest()`, and this function should use that estimate to make a
     *  determination if calling it is "worth it" for the keeper. This is not
     *  the only consideration into issuing this trigger, for example if the
     *  position would be negatively affected if `harvest()` is not called
     *  shortly, then this can return `true` even if the keeper might be "at a
     *  loss" (keepers are always reimbursed by Yearn).
     * @dev
     *  `callCostInWei` must be priced in terms of `wei` (1e-18 ETH).
     *
     *  This call and `tendTrigger` should never return `true` at the
     *  same time.
     *
     *  See `min/maxReportDelay`, `profitFactor`, `debtThreshold` to adjust the
     *  strategist-controlled parameters that will influence whether this call
     *  returns `true` or not. These parameters will be used in conjunction
     *  with the parameters reported to the Vault (see `params`) to determine
     *  if calling `harvest()` is merited.
     *
     *  It is expected that an external system will check `harvestTrigger()`.
     *  This could be a script run off a desktop or cloud bot (e.g.
     *  https://github.com/iearn-finance/yearn-vaults/blob/main/scripts/keep.py),
     *  or via an integration with the Keep3r network (e.g.
     *  https://github.com/Macarse/GenericKeep3rV2/blob/master/contracts/keep3r/GenericKeep3rV2.sol).
     * @param callCostInWei The keeper's estimated gas cost to call `harvest()` (in wei).
     * @return `true` if `harvest()` should be called, `false` otherwise.
     */
    function harvestTrigger(uint256 callCostInWei) public view virtual returns (bool) {
        uint256 callCost = ethToWant(callCostInWei);
        StrategyParams memory params = vault.strategies(address(this));

        // Should not trigger if Strategy is not activated
        if (params.activation == 0) return false;

        // Should not trigger if we haven't waited long enough since previous harvest
        if (block.timestamp.sub(params.lastReport) < minReportDelay) return false;

        // Should trigger if hasn't been called in a while
        if (block.timestamp.sub(params.lastReport) >= maxReportDelay) return true;

        // If some amount is owed, pay it back
        // NOTE: Since debt is based on deposits, it makes sense to guard against large
        //       changes to the value from triggering a harvest directly through user
        //       behavior. This should ensure reasonable resistance to manipulation
        //       from user-initiated withdrawals as the outstanding debt fluctuates.
        uint256 outstanding = vault.debtOutstanding();
        if (outstanding > debtThreshold) return true;

        // Check for profits and losses
        uint256 total = estimatedTotalAssets();
        // Trigger if we have a loss to report
        if (total.add(debtThreshold) < params.totalDebt) return true;

        uint256 profit = 0;
        if (total > params.totalDebt) profit = total.sub(params.totalDebt); // We've earned a profit!

        // Otherwise, only trigger if it "makes sense" economically (gas cost
        // is <N% of value moved)
        uint256 credit = vault.creditAvailable();
        return (profitFactor.mul(callCost) < credit.add(profit));
    }

    /**
     * @notice
     *  Harvests the Strategy, recognizing any profits or losses and adjusting
     *  the Strategy's position.
     *
     *  In the rare case the Strategy is in emergency shutdown, this will exit
     *  the Strategy's position.
     *
     *  This may only be called by governance, the strategist, or the keeper.
     * @dev
     *  When `harvest()` is called, the Strategy reports to the Vault (via
     *  `vault.report()`), so in some cases `harvest()` must be called in order
     *  to take in profits, to borrow newly available funds from the Vault, or
     *  otherwise adjust its position. In other cases `harvest()` must be
     *  called to report to the Vault on the Strategy's position, especially if
     *  any losses have occurred.
     */
    function harvest() external onlyKeepers {
        uint256 profit = 0;
        uint256 loss = 0;
        uint256 debtOutstanding = vault.debtOutstanding();
        uint256 debtPayment = 0;
        if (emergencyExit) {
            // Free up as much capital as possible
            uint256 amountFreed = liquidateAllPositions();
            if (amountFreed < debtOutstanding) {
                loss = debtOutstanding.sub(amountFreed);
            } else if (amountFreed > debtOutstanding) {
                profit = amountFreed.sub(debtOutstanding);
            }
            debtPayment = debtOutstanding.sub(loss);
        } else {
            // Free up returns for Vault to pull
            (profit, loss, debtPayment) = prepareReturn(debtOutstanding);
        }

        // Allow Vault to take up to the "harvested" balance of this contract,
        // which is the amount it has earned since the last time it reported to
        // the Vault.
        uint256 totalDebt = vault.strategies(address(this)).totalDebt;
        debtOutstanding = vault.report(profit, loss, debtPayment);

        // Check if free returns are left, and re-invest them
        adjustPosition(debtOutstanding);

        // call healthCheck contract
        if (doHealthCheck && healthCheck != address(0)) {
            require(HealthCheck(healthCheck).check(profit, loss, debtPayment, debtOutstanding, totalDebt), "!healthcheck");
        } else {
            doHealthCheck = true;
        }

        emit Harvested(profit, loss, debtPayment, debtOutstanding);
    }

    /**
     * @notice
     *  Withdraws `_amountNeeded` to `vault`.
     *
     *  This may only be called by the Vault.
     * @param _amountNeeded How much `want` to withdraw.
     * @return _loss Any realized losses
     */
    function withdraw(uint256 _amountNeeded) external returns (uint256 _loss) {
        require(msg.sender == address(vault), "!vault");
        // Liquidate as much as possible to `want`, up to `_amountNeeded`
        uint256 amountFreed;
        (amountFreed, _loss) = liquidatePosition(_amountNeeded);
        // Send it directly back (NOTE: Using `msg.sender` saves some gas here)
        want.safeTransfer(msg.sender, amountFreed);
        // NOTE: Reinvest anything leftover on next `tend`/`harvest`
    }

    /**
     * Do anything necessary to prepare this Strategy for migration, such as
     * transferring any reserve or LP tokens, CDPs, or other tokens or stores of
     * value.
     */
    function prepareMigration(address _newStrategy) internal virtual;

    /**
     * @notice
     *  Transfers all `want` from this Strategy to `_newStrategy`.
     *
     *  This may only be called by the Vault.
     * @dev
     * The new Strategy's Vault must be the same as this Strategy's Vault.
     *  The migration process should be carefully performed to make sure all
     * the assets are migrated to the new address, which should have never
     * interacted with the vault before.
     * @param _newStrategy The Strategy to migrate to.
     */
    function migrate(address _newStrategy) external {
        require(msg.sender == address(vault));
        require(BaseStrategy(_newStrategy).vault() == vault);
        prepareMigration(_newStrategy);
        want.safeTransfer(_newStrategy, want.balanceOf(address(this)));
    }

    /**
     * @notice
     *  Activates emergency exit. Once activated, the Strategy will exit its
     *  position upon the next harvest, depositing all funds into the Vault as
     *  quickly as is reasonable given on-chain conditions.
     *
     *  This may only be called by governance or the strategist.
     * @dev
     *  See `vault.setEmergencyShutdown()` and `harvest()` for further details.
     */
    function setEmergencyExit() external onlyEmergencyAuthorized {
        emergencyExit = true;
        vault.revokeStrategy();

        emit EmergencyExitEnabled();
    }

    /**
     * Override this to add all tokens/tokenized positions this contract
     * manages on a *persistent* basis (e.g. not just for swapping back to
     * want ephemerally).
     *
     * NOTE: Do *not* include `want`, already included in `sweep` below.
     *
     * Example:
     * ```
     *    function protectedTokens() internal override view returns (address[] memory) {
     *      address[] memory protected = new address[](3);
     *      protected[0] = tokenA;
     *      protected[1] = tokenB;
     *      protected[2] = tokenC;
     *      return protected;
     *    }
     * ```
     */
    function protectedTokens() internal view virtual returns (address[] memory);

    /**
     * @notice
     *  Removes tokens from this Strategy that are not the type of tokens
     *  managed by this Strategy. This may be used in case of accidentally
     *  sending the wrong kind of token to this Strategy.
     *
     *  Tokens will be sent to `governance()`.
     *
     *  This will fail if an attempt is made to sweep `want`, or any tokens
     *  that are protected by this Strategy.
     *
     *  This may only be called by governance.
     * @dev
     *  Implement `protectedTokens()` to specify any additional tokens that
     *  should be protected from sweeping in addition to `want`.
     * @param _token The token to transfer out of this vault.
     */
    function sweep(address _token) external onlyGovernance {
        require(_token != address(want), "!want");
        require(_token != address(vault), "!shares");

        address[] memory _protectedTokens = protectedTokens();
        for (uint256 i; i < _protectedTokens.length; i++) require(_token != _protectedTokens[i], "!protected");

        IERC20(_token).safeTransfer(governance(), IERC20(_token).balanceOf(address(this)));
    }
}

abstract contract BaseStrategyInitializable is BaseStrategy {
    bool public isOriginal = true;
    event Cloned(address indexed clone);

    constructor(address _vault) public BaseStrategy(_vault) {}

    function initialize(
        address _vault,
        address _strategist,
        address _rewards,
        address _keeper
    ) external virtual {
        _initialize(_vault, _strategist, _rewards, _keeper);
    }

    function clone(address _vault) external returns (address) {
        require(isOriginal, "!clone");
        return this.clone(_vault, msg.sender, msg.sender, msg.sender);
    }

    function clone(
        address _vault,
        address _strategist,
        address _rewards,
        address _keeper
    ) external returns (address newStrategy) {
        // Copied from https://github.com/optionality/clone-factory/blob/master/contracts/CloneFactory.sol
        bytes20 addressBytes = bytes20(address(this));

        assembly {
            // EIP-1167 bytecode
            let clone_code := mload(0x40)
            mstore(clone_code, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(clone_code, 0x14), addressBytes)
            mstore(add(clone_code, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            newStrategy := create(0, clone_code, 0x37)
        }

        BaseStrategyInitializable(newStrategy).initialize(_vault, _strategist, _rewards, _keeper);

        emit Cloned(newStrategy);
    }
}

// File: BaseWrapper.sol

interface RegistryAPI {
    function governance() external view returns (address);

    function latestVault(address token) external view returns (address);

    function numVaults(address token) external view returns (uint256);

    function vaults(address token, uint256 deploymentId) external view returns (address);
}

/**
 * @title Yearn Base Wrapper
 * @author yearn.finance
 * @notice
 *  BaseWrapper implements all of the required functionality to interoperate
 *  closely with the Vault contract. This contract should be inherited and the
 *  abstract methods implemented to adapt the Wrapper.
 *  A good starting point to build a wrapper is https://github.com/yearn/brownie-wrapper-mix
 *
 */
abstract contract BaseWrapper {
    using Math for uint256;
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    IERC20 public token;

    // Reduce number of external calls (SLOADs stay the same)
    VaultAPI[] private _cachedVaults;

    RegistryAPI public registry;

    // ERC20 Unlimited Approvals (short-circuits VaultAPI.transferFrom)
    uint256 constant UNLIMITED_APPROVAL = type(uint256).max;
    // Sentinal values used to save gas on deposit/withdraw/migrate
    // NOTE: DEPOSIT_EVERYTHING == WITHDRAW_EVERYTHING == MIGRATE_EVERYTHING
    uint256 constant DEPOSIT_EVERYTHING = type(uint256).max;
    uint256 constant WITHDRAW_EVERYTHING = type(uint256).max;
    uint256 constant MIGRATE_EVERYTHING = type(uint256).max;
    // VaultsAPI.depositLimit is unlimited
    uint256 constant UNCAPPED_DEPOSITS = type(uint256).max;

    constructor(address _token, address _registry) public {
        // Recommended to use a token with a `Registry.latestVault(_token) != address(0)`
        token = IERC20(_token);
        // Recommended to use `v2.registry.ychad.eth`
        registry = RegistryAPI(_registry);
    }

    /**
     * @notice
     *  Used to update the yearn registry.
     * @param _registry The new _registry address.
     */
    function setRegistry(address _registry) external {
        require(msg.sender == registry.governance());
        // In case you want to override the registry instead of re-deploying
        registry = RegistryAPI(_registry);
        // Make sure there's no change in governance
        // NOTE: Also avoid bricking the wrapper from setting a bad registry
        require(msg.sender == registry.governance());
    }

    /**
     * @notice
     *  Used to get the most revent vault for the token using the registry.
     * @return An instance of a VaultAPI
     */
    function bestVault() public view virtual returns (VaultAPI) {
        return VaultAPI(registry.latestVault(address(token)));
    }

    /**
     * @notice
     *  Used to get all vaults from the registery for the token
     * @return An array containing instances of VaultAPI
     */
    function allVaults() public view virtual returns (VaultAPI[] memory) {
        uint256 cache_length = _cachedVaults.length;
        uint256 num_vaults = registry.numVaults(address(token));

        // Use cached
        if (cache_length == num_vaults) {
            return _cachedVaults;
        }

        VaultAPI[] memory vaults = new VaultAPI[](num_vaults);

        for (uint256 vault_id = 0; vault_id < cache_length; vault_id++) {
            vaults[vault_id] = _cachedVaults[vault_id];
        }

        for (uint256 vault_id = cache_length; vault_id < num_vaults; vault_id++) {
            vaults[vault_id] = VaultAPI(registry.vaults(address(token), vault_id));
        }

        return vaults;
    }

    function _updateVaultCache(VaultAPI[] memory vaults) internal {
        // NOTE: even though `registry` is update-able by Yearn, the intended behavior
        //       is that any future upgrades to the registry will replay the version
        //       history so that this cached value does not get out of date.
        if (vaults.length > _cachedVaults.length) {
            _cachedVaults = vaults;
        }
    }

    /**
     * @notice
     *  Used to get the balance of an account accross all the vaults for a token.
     *  @dev will be used to get the wrapper balance using totalVaultBalance(address(this)).
     *  @param account The address of the account.
     *  @return balance of token for the account accross all the vaults.
     */
    function totalVaultBalance(address account) public view returns (uint256 balance) {
        VaultAPI[] memory vaults = allVaults();

        for (uint256 id = 0; id < vaults.length; id++) {
            balance = balance.add(vaults[id].balanceOf(account).mul(vaults[id].pricePerShare()).div(10**uint256(vaults[id].decimals())));
        }
    }

    /**
     * @notice
     *  Used to get the TVL on the underlying vaults.
     *  @return assets the sum of all the assets managed by the underlying vaults.
     */
    function totalAssets() public view returns (uint256 assets) {
        VaultAPI[] memory vaults = allVaults();

        for (uint256 id = 0; id < vaults.length; id++) {
            assets = assets.add(vaults[id].totalAssets());
        }
    }

    function _deposit(
        address depositor,
        address receiver,
        uint256 amount, // if `MAX_UINT256`, just deposit everything
        bool pullFunds // If true, funds need to be pulled from `depositor` via `transferFrom`
    ) internal returns (uint256 deposited) {
        VaultAPI _bestVault = bestVault();

        if (pullFunds) {
            if (amount != DEPOSIT_EVERYTHING) {
                token.safeTransferFrom(depositor, address(this), amount);
            } else {
                token.safeTransferFrom(depositor, address(this), token.balanceOf(depositor));
            }
        }

        if (token.allowance(address(this), address(_bestVault)) < amount) {
            token.safeApprove(address(_bestVault), 0); // Avoid issues with some tokens requiring 0
            token.safeApprove(address(_bestVault), UNLIMITED_APPROVAL); // Vaults are trusted
        }

        // Depositing returns number of shares deposited
        // NOTE: Shortcut here is assuming the number of tokens deposited is equal to the
        //       number of shares credited, which helps avoid an occasional multiplication
        //       overflow if trying to adjust the number of shares by the share price.
        uint256 beforeBal = token.balanceOf(address(this));
        if (receiver != address(this)) {
            _bestVault.deposit(amount, receiver);
        } else if (amount != DEPOSIT_EVERYTHING) {
            _bestVault.deposit(amount);
        } else {
            _bestVault.deposit();
        }

        uint256 afterBal = token.balanceOf(address(this));
        deposited = beforeBal.sub(afterBal);
        // `receiver` now has shares of `_bestVault` as balance, converted to `token` here
        // Issue a refund if not everything was deposited
        if (depositor != address(this) && afterBal > 0) token.safeTransfer(depositor, afterBal);
    }

    function _withdraw(
        address sender,
        address receiver,
        uint256 amount, // if `MAX_UINT256`, just withdraw everything
        bool withdrawFromBest // If true, also withdraw from `_bestVault`
    ) internal returns (uint256 withdrawn) {
        VaultAPI _bestVault = bestVault();

        VaultAPI[] memory vaults = allVaults();
        _updateVaultCache(vaults);

        // NOTE: This loop will attempt to withdraw from each Vault in `allVaults` that `sender`
        //       is deposited in, up to `amount` tokens. The withdraw action can be expensive,
        //       so it if there is a denial of service issue in withdrawing, the downstream usage
        //       of this wrapper contract must give an alternative method of withdrawing using
        //       this function so that `amount` is less than the full amount requested to withdraw
        //       (e.g. "piece-wise withdrawals"), leading to less loop iterations such that the
        //       DoS issue is mitigated (at a tradeoff of requiring more txns from the end user).
        for (uint256 id = 0; id < vaults.length; id++) {
            if (!withdrawFromBest && vaults[id] == _bestVault) {
                continue; // Don't withdraw from the best
            }

            // Start with the total shares that `sender` has
            uint256 availableShares = vaults[id].balanceOf(sender);

            // Restrict by the allowance that `sender` has to this contract
            // NOTE: No need for allowance check if `sender` is this contract
            if (sender != address(this)) {
                availableShares = Math.min(availableShares, vaults[id].allowance(sender, address(this)));
            }

            // Limit by maximum withdrawal size from each vault
            availableShares = Math.min(availableShares, vaults[id].maxAvailableShares());

            if (availableShares > 0) {
                // Intermediate step to move shares to this contract before withdrawing
                // NOTE: No need for share transfer if this contract is `sender`
                if (sender != address(this)) vaults[id].transferFrom(sender, address(this), availableShares);

                if (amount != WITHDRAW_EVERYTHING) {
                    // Compute amount to withdraw fully to satisfy the request
                    uint256 estimatedShares = amount
                    .sub(withdrawn) // NOTE: Changes every iteration
                    .mul(10**uint256(vaults[id].decimals()))
                    .div(vaults[id].pricePerShare()); // NOTE: Every Vault is different

                    // Limit amount to withdraw to the maximum made available to this contract
                    // NOTE: Avoid corner case where `estimatedShares` isn't precise enough
                    // NOTE: If `0 < estimatedShares < 1` but `availableShares > 1`, this will withdraw more than necessary
                    if (estimatedShares > 0 && estimatedShares < availableShares) {
                        withdrawn = withdrawn.add(vaults[id].withdraw(estimatedShares));
                    } else {
                        withdrawn = withdrawn.add(vaults[id].withdraw(availableShares));
                    }
                } else {
                    withdrawn = withdrawn.add(vaults[id].withdraw());
                }

                // Check if we have fully satisfied the request
                // NOTE: use `amount = WITHDRAW_EVERYTHING` for withdrawing everything
                if (amount <= withdrawn) break; // withdrawn as much as we needed
            }
        }

        // If we have extra, deposit back into `_bestVault` for `sender`
        // NOTE: Invariant is `withdrawn <= amount`
        if (withdrawn > amount && withdrawn.sub(amount) > _bestVault.pricePerShare().div(10**_bestVault.decimals())) {
            // Don't forget to approve the deposit
            if (token.allowance(address(this), address(_bestVault)) < withdrawn.sub(amount)) {
                token.safeApprove(address(_bestVault), UNLIMITED_APPROVAL); // Vaults are trusted
            }

            _bestVault.deposit(withdrawn.sub(amount), sender);
            withdrawn = amount;
        }

        // `receiver` now has `withdrawn` tokens as balance
        if (receiver != address(this)) token.safeTransfer(receiver, withdrawn);
    }

    function _migrate(address account) internal returns (uint256) {
        return _migrate(account, MIGRATE_EVERYTHING);
    }

    function _migrate(address account, uint256 amount) internal returns (uint256) {
        // NOTE: In practice, it was discovered that <50 was the maximum we've see for this variance
        return _migrate(account, amount, 0);
    }

    function _migrate(
        address account,
        uint256 amount,
        uint256 maxMigrationLoss
    ) internal returns (uint256 migrated) {
        VaultAPI _bestVault = bestVault();

        // NOTE: Only override if we aren't migrating everything
        uint256 _depositLimit = _bestVault.depositLimit();
        uint256 _totalAssets = _bestVault.totalAssets();
        if (_depositLimit <= _totalAssets) return 0; // Nothing to migrate (not a failure)

        uint256 _amount = amount;
        if (_depositLimit < UNCAPPED_DEPOSITS && _amount < WITHDRAW_EVERYTHING) {
            // Can only deposit up to this amount
            uint256 _depositLeft = _depositLimit.sub(_totalAssets);
            if (_amount > _depositLeft) _amount = _depositLeft;
        }

        if (_amount > 0) {
            // NOTE: `false` = don't withdraw from `_bestVault`
            uint256 withdrawn = _withdraw(account, address(this), _amount, false);
            if (withdrawn == 0) return 0; // Nothing to migrate (not a failure)

            // NOTE: `false` = don't do `transferFrom` because it's already local
            migrated = _deposit(address(this), account, withdrawn, false);
            // NOTE: Due to the precision loss of certain calculations, there is a small inefficency
            //       on how migrations are calculated, and this could lead to a DoS issue. Hence, this
            //       value is made to be configurable to allow the user to specify how much is acceptable
            require(withdrawn.sub(migrated) <= maxMigrationLoss);
        } // else: nothing to migrate! (not a failure)
    }
}

// File: yToken.sol

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

contract yToken is IERC20, BaseWrapper {
    using SafeMath for uint256;

    mapping(address => mapping(address => uint256)) public override allowance;

    constructor(address _token, address _registry) public BaseWrapper(_token, _registry) {}

    function name() external view returns (string memory) {
        return string(abi.encodePacked("Yearn ", IERC20Metadata(address(token)).name()));
    }

    function symbol() external view returns (string memory) {
        return string(abi.encodePacked("y", IERC20Metadata(address(token)).symbol()));
    }

    function decimals() external view returns (uint256) {
        return IERC20Metadata(address(token)).decimals();
    }

    function totalSupply() external view override returns (uint256 total) {
        return totalAssets();
    }

    function balanceOf(address account) external view override returns (uint256 balance) {
        return totalVaultBalance(account);
    }

    function _transfer(
        address sender,
        address receiver,
        uint256 amount
    ) internal {
        require(receiver != address(0), "ERC20: transfer to the zero address");
        require(amount == _withdraw(sender, receiver, amount, true)); // `true` means use `bestVault`
        emit Transfer(sender, receiver, amount);
    }

    function transfer(address receiver, uint256 amount) public virtual override returns (bool) {
        _transfer(msg.sender, receiver, amount);
        return true;
    }

    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

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

    function approve(address spender, uint256 amount) public override returns (bool) {
        _approve(msg.sender, spender, amount);
        return true;
    }

    function transferFrom(
        address sender,
        address receiver,
        uint256 amount
    ) public virtual override returns (bool) {
        _transfer(sender, receiver, amount);
        _approve(sender, msg.sender, allowance[sender][msg.sender].sub(amount));
        return true;
    }

    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(msg.sender, spender, allowance[msg.sender][spender].add(addedValue));
        return true;
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        _approve(msg.sender, spender, allowance[msg.sender][spender].sub(subtractedValue));
        return true;
    }

    function deposit(uint256 amount) external returns (uint256) {
        return _deposit(msg.sender, msg.sender, amount, true); // `true` = pull from sender
    }

    function withdraw(uint256 amount) external returns (uint256) {
        return _withdraw(msg.sender, msg.sender, amount, true); // `true` = withdraw from `bestVault`
    }

    function _permitAll(
        address user,
        VaultAPI[] calldata vaults,
        bytes[] calldata signatures
    ) internal {
        require(vaults.length == signatures.length);
        for (uint256 i = 0; i < vaults.length; i++) {
            require(vaults[i].permit(user, address(this), uint256(-1), 0, signatures[i]));
        }
    }

    function permitAll(VaultAPI[] calldata vaults, bytes[] calldata signatures) public {
        _permitAll(msg.sender, vaults, signatures);
    }

    function migrate() external returns (uint256) {
        return _migrate(msg.sender);
    }

    function migrate(uint256 amount) external returns (uint256) {
        return _migrate(msg.sender, amount);
    }

    function migrate(uint256 amount, uint256 maxMigrationLoss) external returns (uint256) {
        return _migrate(msg.sender, amount, maxMigrationLoss);
    }

    function migrate(VaultAPI[] calldata vaults, bytes[] calldata signatures) external returns (uint256) {
        _permitAll(msg.sender, vaults, signatures);
        return _migrate(msg.sender);
    }

    function migrate(
        VaultAPI[] calldata vaults,
        bytes[] calldata signatures,
        uint256 amount
    ) external returns (uint256) {
        _permitAll(msg.sender, vaults, signatures);
        return _migrate(msg.sender, amount);
    }

    function migrate(
        VaultAPI[] calldata vaults,
        bytes[] calldata signatures,
        address user,
        uint256 amount
    ) external returns (uint256) {
        _permitAll(user, vaults, signatures);
        return _migrate(user, amount);
    }

    function revokeAll(VaultAPI[] calldata vaults, bytes[] calldata signatures) external {
        require(vaults.length == signatures.length);
        for (uint256 i = 0; i < vaults.length; i++) {
            require(vaults[i].permit(msg.sender, address(this), 0, 0, signatures[i]));
        }
    }
}

interface IWETH {
    function deposit() external payable;

    function withdraw(uint256 wad) external;
}

contract yWETH is ReentrancyGuard, yToken {
    using Address for address payable;

    constructor(address _weth, address _registry) public yToken(_weth, _registry) {}

    function depositETH() public payable returns (uint256) {
        uint256 amount = msg.value;
        // NOTE: `BaseWrapper.token` is WETH
        IWETH(address(token)).deposit{value: amount}();
        // NOTE: Deposit handles approvals
        // NOTE: Need to use different method to deposit than `yToken`
        return _deposit(address(this), msg.sender, amount, false); // `false` = pull from `this`
    }

    function withdrawETH(uint256 amount) external nonReentrant returns (uint256 withdrawn) {
        // NOTE: Need to use different method to withdraw than `yToken`
        withdrawn = _withdraw(msg.sender, address(this), amount, true); // `true` = withdraw from `bestVault`
        // NOTE: `BaseWrapper.token` is WETH
        IWETH(address(token)).withdraw(withdrawn);
        // NOTE: Any unintentionally
        msg.sender.sendValue(address(this).balance);
    }

    receive() external payable {
        if (msg.sender != address(token)) {
            depositETH();
        } // else: WETH is sending us back ETH, so don't do anything (to avoid recursion)
    }
}

// File: StrategyBalancerClonable.sol

contract StrategyBalancerClonable is BaseStrategy {
    using SafeERC20 for IERC20;
    using Address for address;
    using SafeMath for uint256;

    BalancerStrategyVoterProxy public voterProxy;
    address public gauge; // Gauge that voter stakes in to recieve BAL rewards

    address public tradeFactory = address(0);

    uint256 public keepBAL; // the percentage of BAL that we re-lock for boost (in bips)
    uint256 public constant BIPS_DENOMINATOR = 10000; // 10k bips in 100%

    IERC20 internal constant BAL =
        IERC20(0xba100000625a3754423978a60c9317c58a424e3D);
    IERC20 internal constant WETH =
        IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
    ILiquidityGaugeFactory internal constant liquidityGaugeFactory =
        ILiquidityGaugeFactory(0x4E7bBd911cf1EFa442BC1b2e9Ea01ffE785412EC);

    IBalancerVault internal constant balancerVault =
        IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
    address[] public rewardTokens;

    bool internal forceHarvestTriggerOnce; // only set this to true externally when we want to trigger our keepers to harvest for us

    bool public isOriginal = true;
    event Cloned(address indexed clone);

    constructor(address _vault, address _voterProxy)
        public
        BaseStrategy(_vault)
    {
        _initializeStrategy(_voterProxy);
    }

    function initialize(
        address _vault,
        address _strategist,
        address _rewards,
        address _keeper,
        address _voterProxy
    ) external {
        _initialize(_vault, _strategist, _rewards, _keeper);
        _initializeStrategy(_voterProxy);
    }

    function _initializeStrategy(address _voterProxy) internal {
        voterProxy = BalancerStrategyVoterProxy(_voterProxy);

        want.safeApprove(address(_voterProxy), type(uint256).max);

        gauge = liquidityGaugeFactory.getPoolGauge(address(want));
        keepBAL = 1000;

        uint256 _numOfRewardTokens = IGauge(gauge).reward_count(); // FYI – technically, reward tokens can change dynamically, so we may need to re-clone a strategy
        for (uint256 i = 0; i < _numOfRewardTokens; i++) {
            rewardTokens.push(IGauge(gauge).reward_tokens(i));
        }
        healthCheck = 0xDDCea799fF1699e98EDF118e0629A974Df7DF012; // health.ychad.eth
    }

    function clone(
        address _vault,
        address _strategist,
        address _rewards,
        address _keeper,
        address _voterProxy
    ) external returns (address newStrategy) {
        require(isOriginal, "!clone");
        bytes20 addressBytes = bytes20(address(this));

        assembly {
            // EIP-1167 bytecode
            let clone_code := mload(0x40)
            mstore(
                clone_code,
                0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
            )
            mstore(add(clone_code, 0x14), addressBytes)
            mstore(
                add(clone_code, 0x28),
                0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
            )
            newStrategy := create(0, clone_code, 0x37)
        }

        StrategyBalancerClonable(newStrategy).initialize(
            _vault,
            _strategist,
            _rewards,
            _keeper,
            _voterProxy
        );

        emit Cloned(newStrategy);
    }

    function name() external view override returns (string memory) {
        return
            string(
                abi.encodePacked(
                    "StrategyBalancer",
                    IERC20Metadata(address(want)).symbol()
                )
            );
    }

    // We don't send rewards to new strategy in prepareMigration in case something is rekt, so migration can also include a manual claimRewards + sweep if needed
    function claimRewards() external onlyKeepers() {
        // Should be a harmless function, so 'onlyKeepers' is appropriate
        _claimRewards();
    }

    function setVoterProxy(address _voterProxy) external onlyGovernance {
        voterProxy = BalancerStrategyVoterProxy(_voterProxy);
    }

    // Set the amount of BAL to be locked in Yearn's veBAL voter from each harvest. Default is 10%.
    function setKeepBAL(uint256 _keepBAL) external onlyAuthorized {
        require(_keepBAL <= 10_000);
        keepBAL = _keepBAL;
    }

    // This allows us to manually harvest with our keeper as needed
    function setForceHarvestTriggerOnce(bool _forceHarvestTriggerOnce)
        external
        onlyAuthorized
    {
        forceHarvestTriggerOnce = _forceHarvestTriggerOnce;
    }

    function setTradeFactory(address _tradeFactory) external onlyGovernance {
        if (tradeFactory != address(0)) {
            _removeTradeFactoryPermissions();
        }

        ITradeFactory tf = ITradeFactory(_tradeFactory);

        BAL.safeApprove(_tradeFactory, type(uint256).max);
        tf.enable(address(BAL), address(want));

        for (uint256 i = 0; i < rewardTokens.length; i++) {
            address rewardToken = rewardTokens[i];
            IERC20(rewardToken).safeApprove(_tradeFactory, type(uint256).max);
            tf.enable(rewardToken, address(want));
        }
        tradeFactory = _tradeFactory;
    }

    function removeTradeFactoryPermissions() external onlyEmergencyAuthorized {
        _removeTradeFactoryPermissions();
    }

    function harvestTrigger(uint256 callCostinEth)
        public
        view
        override
        returns (bool)
    {
        // trigger if we want to manually harvest
        if (forceHarvestTriggerOnce) {
            return true;
        }

        // Should not trigger if strategy is not active (no assets and no debtRatio). This means we don't need to adjust keeper job.
        if (!isActive()) {
            return false;
        }

        return super.harvestTrigger(callCostinEth);
    }

    function _removeTradeFactoryPermissions() internal {
        BAL.safeApprove(tradeFactory, 0);
        for (uint256 i = 0; i < rewardTokens.length; i++) {
            IERC20(rewardTokens[i]).safeApprove(tradeFactory, 0);
        }
        tradeFactory = address(0);
    }

    function stakedBalance() public view returns (uint256) {
        return voterProxy.balanceOf(gauge);
    }

    function balanceOfWant() public view returns (uint256) {
        return want.balanceOf(address(this));
    }

    function estimatedTotalAssets() public view override returns (uint256) {
        return balanceOfWant().add(stakedBalance());
    }

    function ethToWant(uint256 _ethAmount)
        public
        view
        override
        returns (uint256)
    {}

    function adjustPosition(uint256 _debtOutstanding) internal override {
        if (emergencyExit) {
            return;
        }
        // Send all of our LP tokens to the proxy and deposit to the gauge if we have any
        uint256 _toInvest = balanceOfWant();
        if (_toInvest > 0) {
            want.safeTransfer(address(voterProxy), _toInvest);
            voterProxy.deposit(gauge, address(want));
        }

        _claimRewards();
    }

    function _claimRewards() internal {
        // Non-BAL rewards (e.g., LDO)
        if (rewardTokens.length > 0) {
            voterProxy.claimRewards(gauge);
        }

        // BAL rewards
        uint256 _stakedBalance = stakedBalance();
        if (_stakedBalance > 0) {
            uint256 _balanceOfBalBeforeClaim = BAL.balanceOf(address(this));
            voterProxy.claimBal(gauge);
            uint256 _balClaimed =
                BAL.balanceOf(address(this)).sub(_balanceOfBalBeforeClaim);

            if (_balClaimed > 0) {
                uint256 _sendToVoter =
                    _balClaimed.mul(keepBAL).div(BIPS_DENOMINATOR);

                if (_sendToVoter > 0) {
                    BAL.safeTransfer(address(voterProxy), _sendToVoter); // So that strategy doesn't need to know about voter, we send BAL via voter proxy
                    voterProxy.transferBALToVoter();
                }
            }
        }
    }

    function liquidatePosition(uint256 _amountNeeded)
        internal
        override
        returns (uint256 _liquidatedAmount, uint256 _loss)
    {
        uint256 _wantBalance = balanceOfWant();
        if (_amountNeeded > _wantBalance) {
            // check if we have enough free funds to cover the withdrawal
            uint256 _stakedBalance = stakedBalance();
            if (_stakedBalance > 0) {
                voterProxy.withdraw(
                    gauge,
                    address(want),
                    Math.min(_stakedBalance, _amountNeeded.sub(_wantBalance))
                );
            }
            uint256 _withdrawnBalance = balanceOfWant();
            _liquidatedAmount = Math.min(_amountNeeded, _withdrawnBalance);
            _loss = _amountNeeded.sub(_liquidatedAmount);
        } else {
            // we have enough balance to cover the liquidation available
            return (_amountNeeded, 0);
        }
    }

    // fire sale, get rid of it all!
    function liquidateAllPositions() internal override returns (uint256) {
        uint256 _stakedBalance = stakedBalance();
        if (_stakedBalance > 0) {
            // don't bother withdrawing zero
            voterProxy.withdraw(gauge, address(want), _stakedBalance);
        }
        return balanceOfWant();
    }

    function prepareReturn(uint256 _debtOutstanding)
        internal
        override
        returns (
            uint256 _profit,
            uint256 _loss,
            uint256 _debtPayment
        )
    {
        uint256 totalDebt = vault.strategies(address(this)).totalDebt;
        uint256 totalAssetsAfterProfit = estimatedTotalAssets();

        _profit = totalAssetsAfterProfit > totalDebt
            ? totalAssetsAfterProfit.sub(totalDebt)
            : 0;

        uint256 _amountFreed;
        uint256 _toLiquidate = _debtOutstanding.add(_profit);
        if (_toLiquidate > 0) {
            (_amountFreed, _loss) = liquidatePosition(_toLiquidate);
        }

        _debtPayment = Math.min(_debtOutstanding, _amountFreed);

        if (_loss > _profit) {
            // Example:
            // debtOutstanding 100, profit 50, _amountFreed 100, _loss 50
            // loss should be 0, (50-50)
            // profit should endup in 0
            _loss = _loss.sub(_profit);
            _profit = 0;
        } else {
            // Example:
            // debtOutstanding 100, profit 50, _amountFreed 140, _loss 10
            // _profit should be 40, (50 profit - 10 loss)
            // loss should end up in 0
            _profit = _profit.sub(_loss);
            _loss = 0;
        }

        // we're done harvesting, so reset our trigger if we used it
        forceHarvestTriggerOnce = false;
    }

    function prepareMigration(address _newStrategy) internal override {
        uint256 _stakedBalance = stakedBalance();
        if (_stakedBalance > 0) {
            voterProxy.withdraw(gauge, address(want), _stakedBalance);
        }
    }

    function protectedTokens()
        internal
        view
        override
        returns (address[] memory)
    {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_voterProxy","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"}],"name":"Cloned","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyExitEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loss","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtPayment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtOutstanding","type":"uint256"}],"name":"Harvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"debtThreshold","type":"uint256"}],"name":"UpdatedDebtThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newKeeper","type":"address"}],"name":"UpdatedKeeper","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"UpdatedMaxReportDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"metadataURI","type":"string"}],"name":"UpdatedMetadataURI","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"UpdatedMinReportDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"profitFactor","type":"uint256"}],"name":"UpdatedProfitFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rewards","type":"address"}],"name":"UpdatedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newStrategist","type":"address"}],"name":"UpdatedStrategist","type":"event"},{"inputs":[],"name":"BIPS_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"apiVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"balanceOfWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_strategist","type":"address"},{"internalType":"address","name":"_rewards","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_voterProxy","type":"address"}],"name":"clone","outputs":[{"internalType":"address","name":"newStrategy","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"debtThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegatedAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"doHealthCheck","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyExit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"estimatedTotalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethAmount","type":"uint256"}],"name":"ethToWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gauge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCostinEth","type":"uint256"}],"name":"harvestTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"healthCheck","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_strategist","type":"address"},{"internalType":"address","name":"_rewards","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_voterProxy","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOriginal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keepBAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxReportDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newStrategy","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minReportDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"profitFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"removeTradeFactoryPermissions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debtThreshold","type":"uint256"}],"name":"setDebtThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_doHealthCheck","type":"bool"}],"name":"setDoHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setEmergencyExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_forceHarvestTriggerOnce","type":"bool"}],"name":"setForceHarvestTriggerOnce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_healthCheck","type":"address"}],"name":"setHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_keepBAL","type":"uint256"}],"name":"setKeepBAL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"setKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setMaxReportDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_metadataURI","type":"string"}],"name":"setMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setMinReportDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_profitFactor","type":"uint256"}],"name":"setProfitFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewards","type":"address"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategist","type":"address"}],"name":"setStrategist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tradeFactory","type":"address"}],"name":"setTradeFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_voterProxy","type":"address"}],"name":"setVoterProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategist","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCostInWei","type":"uint256"}],"name":"tendTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradeFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract VaultAPI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voterProxy","outputs":[{"internalType":"contract BalancerStrategyVoterProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"want","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountNeeded","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"_loss","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

6080604052600d80546001600160a01b03191690556010805461ff0019166101001790553480156200003057600080fd5b5060405162004b5a38038062004b5a8339810160408190526200005391620007d1565b81620000628133808062000076565b506200006e816200025a565b505062000a4e565b6006546001600160a01b031615620000ab5760405162461bcd60e51b8152600401620000a290620008e4565b60405180910390fd5b600280546001600160a01b0319166001600160a01b03868116919091179182905560408051637e062a3560e11b81529051929091169163fc0c546a91600480820192602092909190829003018186803b1580156200010857600080fd5b505afa1580156200011d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001439190620007a1565b600680546001600160a01b0319166001600160a01b0392831617908190556200017d911685600019620004d2602090811b6200258517901c565b600380546001600160a01b038086166001600160a01b03199283161790925560048054858416908316178082556005805486861694169390931790925560006007819055620151806008556064600955600a5560025460405163095ea7b360e01b81529084169363095ea7b393620001fd93911691600019910162000896565b602060405180830381600087803b1580156200021857600080fd5b505af11580156200022d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200025391906200080f565b5050505050565b600b8054610100600160a81b0319166101006001600160a01b038481169190910291909117909155600654620002a1911682600019620004d2602090811b6200258517901c565b60065460405163a8ea687560e01b8152734e7bbd911cf1efa442bc1b2e9ea01ffe785412ec9163a8ea687591620002e5916001600160a01b03169060040162000868565b60206040518083038186803b158015620002fe57600080fd5b505afa15801562000313573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003399190620007a1565b600c80546001600160a01b0319166001600160a01b0392831617908190556103e8600e556040805163963c94b960e01b81529051600093929092169163963c94b991600480820192602092909190829003018186803b1580156200039c57600080fd5b505afa158015620003b1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620003d7919062000831565b905060005b81811015620004a557600c546040516354c49fe960e01b8152600f916001600160a01b0316906354c49fe99062000418908590600401620009f9565b60206040518083038186803b1580156200043157600080fd5b505afa15801562000446573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200046c9190620007a1565b815460018082018455600093845260209093200180546001600160a01b0319166001600160a01b039290921691909117905501620003dc565b505060018054610100600160a81b03191674ddcea799ff1699e98edf118e0629a974df7df0120017905550565b801580620005615750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906200050b90309086906004016200087c565b60206040518083038186803b1580156200052457600080fd5b505afa15801562000539573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200055f919062000831565b155b620005805760405162461bcd60e51b8152600401620000a2906200099c565b620005db8363095ea7b360e01b8484604051602401620005a292919062000896565b60408051808303601f190181529190526020810180516001600160e01b0319939093166001600160e01b0393841617905290620005e016565b505050565b60606200063c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200067c60201b62002684179092919060201c565b805190915015620005db57808060200190518101906200065d91906200080f565b620005db5760405162461bcd60e51b8152600401620000a29062000952565b60606200068d848460008562000695565b949350505050565b6060620006a28562000767565b620006c15760405162461bcd60e51b8152600401620000a2906200091b565b60006060866001600160a01b03168587604051620006e091906200084a565b60006040518083038185875af1925050503d80600081146200071f576040519150601f19603f3d011682016040523d82523d6000602084013e62000724565b606091505b509150915081156200073a5791506200068d9050565b8051156200074b5780518082602001fd5b8360405162461bcd60e51b8152600401620000a29190620008af565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906200068d575050151592915050565b600060208284031215620007b3578081fd5b81516001600160a01b0381168114620007ca578182fd5b9392505050565b60008060408385031215620007e4578081fd5b8251620007f18162000a35565b6020840151909250620008048162000a35565b809150509250929050565b60006020828403121562000821578081fd5b81518015158114620007ca578182fd5b60006020828403121562000843578081fd5b5051919050565b600082516200085e81846020870162000a02565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b03929092168252602082015260400190565b6000602082528251806020840152620008d081604085016020870162000a02565b601f01601f19169190910160400192915050565b6020808252601c908201527f537472617465677920616c726561647920696e697469616c697a656400000000604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606082015260800190565b90815260200190565b60005b8381101562000a1f57818101518382015260200162000a05565b8381111562000a2f576000848401525b50505050565b6001600160a01b038116811462000a4b57600080fd5b50565b6140fc8062000a5e6000396000f3fe608060405234801561001057600080fd5b50600436106103425760003560e01c80636f392ce7116101b8578063aced166111610104578063ed882c2b116100a2578063f45d75041161007c578063f45d750414610603578063fbfa77cf1461060b578063fcf2d0ad14610613578063ffea40081461061b57610342565b8063ed882c2b146105d5578063efbb5cb0146105e8578063f017c92f146105f057610342565b8063c7b9d530116100de578063c7b9d53014610594578063ce5494bb146105a7578063e5e19b4a146105ba578063ec38a862146105c257610342565b8063aced16611461057c578063b252720b14610584578063c1a3d44c1461058c57610342565b80638cdfe1661161017157806395e80c501161014b57806395e80c50146105515780639ec5a89414610559578063a6f19c8414610561578063ac00ff261461056957610342565b80638cdfe1661461052e5780638e6350e21461053657806391397ab41461053e57610342565b80636f392ce7146104d7578063748747e6146104df578063750521f5146104f2578063780022a0146105055780637bb7bed1146105135780637fcd3a851461052657610342565b806325829410116102925780634641257d11610230578063650d18801161020a578063650d1880146104a157806365210942146104b45780636718835f146104c75780636d51a20f146104cf57610342565b80634641257d146104895780635641ec03146104915780635b9f00161461049957610342565b8063372500ab1161026c578063372500ab1461045357806339a172a81461045b57806340bb9ee21461046e578063440368a31461048157610342565b8063258294101461043057806328b7ccf7146104385780632e1a7d4d1461044057610342565b806311bc8245116102ff5780631d12f28b116102d95780631d12f28b146103f65780631f1fcd511461040b5780631fe4a6861461041357806322f3e2d41461041b57610342565b806311bc8245146103bb5780631459457a146103ce5780631ba980b3146103e157610342565b806301681a621461034757806303ee438c1461035c578063052cdc0c1461037a57806306fdde031461038d5780630ada4dab146103955780630f969b87146103a8575b600080fd5b61035a610355366004613974565b61062e565b005b6103646107cd565b6040516103719190613d26565b60405180910390f35b61035a610388366004613974565b61085b565b6103646108bb565b61035a6103a3366004613a1c565b610960565b61035a6103b6366004613bcb565b6109c0565b61035a6103c9366004613974565b610a4d565b61035a6103dc3660046139ac565b610b4e565b6103e9610b6a565b6040516103719190613c4f565b6103fe610b7e565b6040516103719190613ff3565b6103e9610b84565b6103e9610b93565b610423610ba2565b6040516103719190613cec565b610364610c44565b6103fe610c63565b6103fe61044e366004613bcb565b610c69565b61035a610cc4565b61035a610469366004613bcb565b610e72565b61035a61047c366004613bcb565b610ef4565b61035a610f55565b61035a61117c565b610423611655565b6103fe61165e565b6104236104af366004613bcb565b6116eb565b61035a6104c2366004613974565b6116f3565b6104236118b3565b61035a6118bc565b610423611a53565b61035a6104ed366004613974565b611a61565b61035a610500366004613a54565b611b0c565b6103fe6104af366004613bcb565b6103e9610521366004613bcb565b611ba3565b6103fe611bca565b6103fe611bd0565b6103fe611bd6565b61035a61054c366004613bcb565b611bdb565b6103fe611c5d565b6103e9611c63565b6103e9611c72565b61035a610577366004613a1c565b611c81565b6103e9611d6d565b6103e9611d7c565b6103fe611d90565b61035a6105a2366004613974565b611dc1565b61035a6105b5366004613974565b611e6c565b6103e9611fba565b61035a6105d0366004613974565b611fc9565b6104236105e3366004613bcb565b61215c565b6103fe612195565b61035a6105fe366004613bcb565b6121b0565b6103fe612232565b6103e9612238565b61035a612247565b6103e96106293660046139ac565b61246c565b61063661269b565b6001600160a01b0316336001600160a01b03161461066f5760405162461bcd60e51b815260040161066690613f0a565b60405180910390fd5b6006546001600160a01b038281169116141561069d5760405162461bcd60e51b815260040161066690613d7e565b6002546001600160a01b03828116911614156106cb5760405162461bcd60e51b815260040161066690613e92565b60606106d5612718565b905060005b8151811015610730578181815181106106ef57fe5b60200260200101516001600160a01b0316836001600160a01b031614156107285760405162461bcd60e51b815260040161066690613f79565b6001016106da565b506107c961073c61269b565b6040516370a0823160e01b81526001600160a01b038516906370a0823190610768903090600401613c4f565b60206040518083038186803b15801561078057600080fd5b505afa158015610794573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b89190613be3565b6001600160a01b038516919061271d565b5050565b6000805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156108535780601f1061082857610100808354040283529160200191610853565b820191906000526020600020905b81548152906001019060200180831161083657829003601f168201915b505050505081565b61086361269b565b6001600160a01b0316336001600160a01b0316146108935760405162461bcd60e51b815260040161066690613f0a565b600b80546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600654604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b41916004808301926000929190829003018186803b15801561090057600080fd5b505afa158015610914573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261093c9190810190613ac1565b60405160200161094c9190613c17565b604051602081830303815290604052905090565b6003546001600160a01b0316331480610991575061097c61269b565b6001600160a01b0316336001600160a01b0316145b6109ad5760405162461bcd60e51b815260040161066690613f0a565b6010805460ff1916911515919091179055565b6003546001600160a01b03163314806109f157506109dc61269b565b6001600160a01b0316336001600160a01b0316145b610a0d5760405162461bcd60e51b815260040161066690613f0a565b600a8190556040517fa68ba126373d04c004c5748c300c9fca12bd444b3d4332e261f3bd2bac4a860090610a42908390613ff3565b60405180910390a150565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610a9b57600080fd5b505afa158015610aaf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad39190613990565b6001600160a01b0316336001600160a01b03161480610b0a5750610af561269b565b6001600160a01b0316336001600160a01b0316145b610b265760405162461bcd60e51b815260040161066690613f0a565b600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b610b5a8585858561273c565b610b63816128f5565b5050505050565b600b5461010090046001600160a01b031681565b600a5481565b6006546001600160a01b031681565b6003546001600160a01b031681565b6002546040516339ebf82360e01b815260009182916001600160a01b03909116906339ebf82390610bd7903090600401613c4f565b6101206040518083038186803b158015610bf057600080fd5b505afa158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c289190613b4d565b604001511180610c3f57506000610c3d612195565b115b905090565b604080518082019091526005815264302e342e3360d81b602082015290565b60085481565b6002546000906001600160a01b03163314610c965760405162461bcd60e51b815260040161066690613e72565b6000610ca183612b4c565b600654909350909150610cbe906001600160a01b0316338361271d565b50919050565b6005546001600160a01b0316331480610ce757506003546001600160a01b031633145b80610d0a5750610cf561269b565b6001600160a01b0316336001600160a01b0316145b80610dab5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610d5e57600080fd5b505afa158015610d72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d969190613990565b6001600160a01b0316336001600160a01b0316145b80610e4c5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610dff57600080fd5b505afa158015610e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e379190613990565b6001600160a01b0316336001600160a01b0316145b610e685760405162461bcd60e51b815260040161066690613f0a565b610e70612c5d565b565b6003546001600160a01b0316331480610ea35750610e8e61269b565b6001600160a01b0316336001600160a01b0316145b610ebf5760405162461bcd60e51b815260040161066690613f0a565b60078190556040517fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b190610a42908390613ff3565b6003546001600160a01b0316331480610f255750610f1061269b565b6001600160a01b0316336001600160a01b0316145b610f415760405162461bcd60e51b815260040161066690613f0a565b612710811115610f5057600080fd5b600e55565b6005546001600160a01b0316331480610f7857506003546001600160a01b031633145b80610f9b5750610f8661269b565b6001600160a01b0316336001600160a01b0316145b8061103c5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610fef57600080fd5b505afa158015611003573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110279190613990565b6001600160a01b0316336001600160a01b0316145b806110dd5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561109057600080fd5b505afa1580156110a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c89190613990565b6001600160a01b0316336001600160a01b0316145b6110f95760405162461bcd60e51b815260040161066690613f0a565b6002546040805163bf3759b560e01b81529051610e70926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b15801561113f57600080fd5b505afa158015611153573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111779190613be3565b612f43565b6005546001600160a01b031633148061119f57506003546001600160a01b031633145b806111c257506111ad61269b565b6001600160a01b0316336001600160a01b0316145b806112635750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561121657600080fd5b505afa15801561122a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124e9190613990565b6001600160a01b0316336001600160a01b0316145b806113045750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156112b757600080fd5b505afa1580156112cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ef9190613990565b6001600160a01b0316336001600160a01b0316145b6113205760405162461bcd60e51b815260040161066690613f0a565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b815260040160206040518083038186803b15801561137357600080fd5b505afa158015611387573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ab9190613be3565b600b5490915060009060ff16156114085760006113c6613003565b9050828110156113e1576113da83826130ba565b93506113f6565b828111156113f6576113f381846130ba565b94505b61140083856130ba565b915050611419565b61141182613103565b919550935090505b6002546040516339ebf82360e01b81526000916001600160a01b0316906339ebf8239061144a903090600401613c4f565b6101206040518083038186803b15801561146357600080fd5b505afa158015611477573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149b9190613b4d565b60c001516002546040516328766ebf60e21b81529192506001600160a01b03169063a1d9bafc906114d490889088908790600401613ffc565b602060405180830381600087803b1580156114ee57600080fd5b505af1158015611502573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115269190613be3565b925061153183612f43565b60015460ff168015611552575060015461010090046001600160a01b031615155b156116045760015460405163c70fa00b60e01b81526101009091046001600160a01b03169063c70fa00b90611593908890889087908990889060040161402d565b60206040518083038186803b1580156115ab57600080fd5b505afa1580156115bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e39190613a38565b6115ff5760405162461bcd60e51b815260040161066690613dd4565b611611565b6001805460ff1916811790555b7f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d509858584866040516116469493929190614012565b60405180910390a15050505050565b600b5460ff1681565b600b54600c546040516370a0823160e01b815260009261010090046001600160a01b03908116926370a082319261169b9290911690600401613c4f565b60206040518083038186803b1580156116b357600080fd5b505afa1580156116c7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3f9190613be3565b60005b919050565b6116fb61269b565b6001600160a01b0316336001600160a01b03161461172b5760405162461bcd60e51b815260040161066690613f0a565b600d546001600160a01b0316156117445761174461322c565b8061176673ba100000625a3754423978a60c9317c58a424e3d82600019612585565b600654604051632642a09360e11b81526001600160a01b0380841692634c854126926117ac9273ba100000625a3754423978a60c9317c58a424e3d921690600401613c63565b600060405180830381600087803b1580156117c657600080fd5b505af11580156117da573d6000803e3d6000fd5b5050505060005b600f5481101561188f576000600f82815481106117fa57fe5b6000918252602090912001546001600160a01b0316905061181e8185600019612585565b600654604051632642a09360e11b81526001600160a01b0380861692634c854126926118509286921690600401613c63565b600060405180830381600087803b15801561186a57600080fd5b505af115801561187e573d6000803e3d6000fd5b5050600190930192506117e1915050565b5050600d80546001600160a01b0319166001600160a01b0392909216919091179055565b60015460ff1681565b6003546001600160a01b03163314806118ed57506118d861269b565b6001600160a01b0316336001600160a01b0316145b8061198e5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561194157600080fd5b505afa158015611955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119799190613990565b6001600160a01b0316336001600160a01b0316145b80611a2f5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156119e257600080fd5b505afa1580156119f6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1a9190613990565b6001600160a01b0316336001600160a01b0316145b611a4b5760405162461bcd60e51b815260040161066690613f0a565b610e7061322c565b601054610100900460ff1681565b6003546001600160a01b0316331480611a925750611a7d61269b565b6001600160a01b0316336001600160a01b0316145b611aae5760405162461bcd60e51b815260040161066690613f0a565b6001600160a01b038116611ac157600080fd5b600580546001600160a01b0319166001600160a01b0383161790556040517f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe715490610a42908390613c4f565b6003546001600160a01b0316331480611b3d5750611b2861269b565b6001600160a01b0316336001600160a01b0316145b611b595760405162461bcd60e51b815260040161066690613f0a565b611b6560008383613895565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda68282604051611b97929190613cf7565b60405180910390a15050565b600f8181548110611bb057fe5b6000918252602090912001546001600160a01b0316905081565b600e5481565b60095481565b600090565b6003546001600160a01b0316331480611c0c5750611bf761269b565b6001600160a01b0316336001600160a01b0316145b611c285760405162461bcd60e51b815260040161066690613f0a565b60098190556040517fd94596337df4c2f0f44d30a7fc5db1c7bb60d9aca4185ed77c6fd96eb45ec29890610a42908390613ff3565b60075481565b6004546001600160a01b031681565b600c546001600160a01b031681565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015611ccf57600080fd5b505afa158015611ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d079190613990565b6001600160a01b0316336001600160a01b03161480611d3e5750611d2961269b565b6001600160a01b0316336001600160a01b0316145b611d5a5760405162461bcd60e51b815260040161066690613f0a565b6001805460ff1916911515919091179055565b6005546001600160a01b031681565b60015461010090046001600160a01b031681565b6006546040516370a0823160e01b81526000916001600160a01b0316906370a082319061169b903090600401613c4f565b6003546001600160a01b0316331480611df25750611ddd61269b565b6001600160a01b0316336001600160a01b0316145b611e0e5760405162461bcd60e51b815260040161066690613f0a565b6001600160a01b038116611e2157600080fd5b600380546001600160a01b0319166001600160a01b0383161790556040517f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b490610a42908390613c4f565b6002546001600160a01b03163314611e8357600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf916004808301926020929190829003018186803b158015611eca57600080fd5b505afa158015611ede573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f029190613990565b6001600160a01b031614611f1557600080fd5b611f1e816132bf565b6006546040516370a0823160e01b8152611fb79183916001600160a01b03909116906370a0823190611f54903090600401613c4f565b60206040518083038186803b158015611f6c57600080fd5b505afa158015611f80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa49190613be3565b6006546001600160a01b0316919061271d565b50565b600d546001600160a01b031681565b6003546001600160a01b03163314611ff35760405162461bcd60e51b815260040161066690613d59565b6001600160a01b03811661200657600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b039384169363095ea7b39361203d939091169160009101613cd3565b602060405180830381600087803b15801561205757600080fd5b505af115801561206b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208f9190613a38565b50600480546001600160a01b0319166001600160a01b038381169190911780835560025460405163095ea7b360e01b81529083169363095ea7b3936120da9316916000199101613cd3565b602060405180830381600087803b1580156120f457600080fd5b505af1158015612108573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061212c9190613a38565b507fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a06981604051610a429190613c4f565b60105460009060ff1615612172575060016116ee565b61217a610ba2565b612186575060006116ee565b61218f82613365565b92915050565b6000610c3f6121a261165e565b6121aa611d90565b906135ef565b6003546001600160a01b03163314806121e157506121cc61269b565b6001600160a01b0316336001600160a01b0316145b6121fd5760405162461bcd60e51b815260040161066690613f0a565b60088190556040517f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c590610a42908390613ff3565b61271081565b6002546001600160a01b031681565b6003546001600160a01b0316331480612278575061226361269b565b6001600160a01b0316336001600160a01b0316145b806123195750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b1580156122cc57600080fd5b505afa1580156122e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123049190613990565b6001600160a01b0316336001600160a01b0316145b806123ba5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561236d57600080fd5b505afa158015612381573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a59190613990565b6001600160a01b0316336001600160a01b0316145b6123d65760405162461bcd60e51b815260040161066690613f0a565b600b805460ff191660011790556002546040805163507257cd60e11b815290516001600160a01b039092169163a0e4af9a9160048082019260009290919082900301818387803b15801561242957600080fd5b505af115801561243d573d6000803e3d6000fd5b50506040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b925060009150a1565b601054600090610100900460ff166124965760405162461bcd60e51b815260040161066690613eb3565b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81523060601b601482018190526e5af43d82803e903d91602b57fd5bf360881b6028830152906037816000f0604051630a2ca2bd60e11b81529093506001600160a01b0384169150631459457a90612515908a908a908a908a908a90600401613c7d565b600060405180830381600087803b15801561252f57600080fd5b505af1158015612543573d6000803e3d6000fd5b50506040516001600160a01b03851692507f783540fb4221a3238720dc7038937d0d79982bcf895274aa6ad179f82cf0d53c9150600090a25095945050505050565b80158061260d5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906125bb9030908690600401613c63565b60206040518083038186803b1580156125d357600080fd5b505afa1580156125e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061260b9190613be3565b155b6126295760405162461bcd60e51b815260040161066690613f9d565b61267f8363095ea7b360e01b8484604051602401612648929190613cd3565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613614565b505050565b606061269384846000856136a3565b949350505050565b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e675916004808301926020929190829003018186803b1580156126e057600080fd5b505afa1580156126f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3f9190613990565b606090565b61267f8363a9059cbb60e01b8484604051602401612648929190613cd3565b6006546001600160a01b0316156127655760405162461bcd60e51b815260040161066690613dfa565b600280546001600160a01b0319166001600160a01b03868116919091179182905560408051637e062a3560e11b81529051929091169163fc0c546a91600480820192602092909190829003018186803b1580156127c157600080fd5b505afa1580156127d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127f99190613990565b600680546001600160a01b0319166001600160a01b039283161790819055612825911685600019612585565b600380546001600160a01b038086166001600160a01b03199283161790925560048054858416908316178082556005805486861694169390931790925560006007819055620151806008556064600955600a5560025460405163095ea7b360e01b81529084169363095ea7b3936128a3939116916000199101613cd3565b602060405180830381600087803b1580156128bd57600080fd5b505af11580156128d1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b639190613a38565b600b80546001600160a01b0380841661010002610100600160a81b03199092169190911790915560065461292d911682600019612585565b60065460405163a8ea687560e01b8152734e7bbd911cf1efa442bc1b2e9ea01ffe785412ec9163a8ea68759161296f916001600160a01b031690600401613c4f565b60206040518083038186803b15801561298757600080fd5b505afa15801561299b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129bf9190613990565b600c80546001600160a01b0319166001600160a01b0392831617908190556103e8600e556040805163963c94b960e01b81529051600093929092169163963c94b991600480820192602092909190829003018186803b158015612a2157600080fd5b505afa158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613be3565b905060005b81811015612b1f57600c546040516354c49fe960e01b8152600f916001600160a01b0316906354c49fe990612a97908590600401613ff3565b60206040518083038186803b158015612aaf57600080fd5b505afa158015612ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae79190613990565b815460018082018455600093845260209093200180546001600160a01b0319166001600160a01b039290921691909117905501612a5e565b505060018054610100600160a81b03191674ddcea799ff1699e98edf118e0629a974df7df0120017905550565b6000806000612b59611d90565b905080841115612c49576000612b6d61165e565b90508015612c1e57600b54600c546006546001600160a01b0361010090930483169263d9caed129281169116612bac85612ba78b896130ba565b613767565b6040518463ffffffff1660e01b8152600401612bca93929190613caf565b602060405180830381600087803b158015612be457600080fd5b505af1158015612bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c1c9190613be3565b505b6000612c28611d90565b9050612c348682613767565b9450612c4086866130ba565b93505050612c56565b8360009250925050612c58565b505b915091565b600f5415612cd157600b54600c54604051633bd73ee360e21b81526001600160a01b0361010090930483169263ef5cfb8c92612c9e92911690600401613c4f565b600060405180830381600087803b158015612cb857600080fd5b505af1158015612ccc573d6000803e3d6000fd5b505050505b6000612cdb61165e565b90508015611fb7576040516370a0823160e01b815260009073ba100000625a3754423978a60c9317c58a424e3d906370a0823190612d1d903090600401613c4f565b60206040518083038186803b158015612d3557600080fd5b505afa158015612d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6d9190613be3565b600b54600c54604051630f258cb560e11b81529293506001600160a01b03610100909204821692631e4b196a92612da8921690600401613c4f565b600060405180830381600087803b158015612dc257600080fd5b505af1158015612dd6573d6000803e3d6000fd5b50506040516370a0823160e01b815260009250612e709150839073ba100000625a3754423978a60c9317c58a424e3d906370a0823190612e1a903090600401613c4f565b60206040518083038186803b158015612e3257600080fd5b505afa158015612e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6a9190613be3565b906130ba565b9050801561267f576000612e9b612710612e95600e548561377d90919063ffffffff16565b906137b7565b90508015612f3d57600b54612ed49073ba100000625a3754423978a60c9317c58a424e3d9061010090046001600160a01b03168361271d565b600b60019054906101000a90046001600160a01b03166001600160a01b031663d788f3716040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612f2457600080fd5b505af1158015612f38573d6000803e3d6000fd5b505050505b50505050565b600b5460ff1615612f5357611fb7565b6000612f5d611d90565b90508015612ffb57600b54600654612f88916001600160a01b0391821691610100909104168361271d565b600b54600c54600654604051631f2c13e160e31b81526001600160a01b0361010090940484169363f9609f0893612fc89390821692911690600401613c63565b600060405180830381600087803b158015612fe257600080fd5b505af1158015612ff6573d6000803e3d6000fd5b505050505b6107c9612c5d565b60008061300e61165e565b905080156130ac57600b54600c54600654604051636ce5768960e11b81526001600160a01b0361010090940484169363d9caed129361305893908216929116908690600401613caf565b602060405180830381600087803b15801561307257600080fd5b505af1158015613086573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130aa9190613be3565b505b6130b4611d90565b91505090565b60006130fc83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506137f9565b9392505050565b6002546040516339ebf82360e01b81526000918291829182916001600160a01b03909116906339ebf8239061313c903090600401613c4f565b6101206040518083038186803b15801561315557600080fd5b505afa158015613169573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061318d9190613b4d565b60c001519050600061319d612195565b90508181116131ad5760006131b7565b6131b781836130ba565b94506000806131c688886135ef565b905080156131dc576131d781612b4c565b965091505b6131e68883613767565b945086861115613205576131fa86886130ba565b955060009650613216565b61320f87876130ba565b9650600095505b50506010805460ff191690555092949193509150565b600d546132599073ba100000625a3754423978a60c9317c58a424e3d906001600160a01b03166000612585565b60005b600f548110156132ac57600d54600f80546132a4926001600160a01b0316916000918590811061328857fe5b6000918252602090912001546001600160a01b03169190612585565b60010161325c565b50600d80546001600160a01b0319169055565b60006132c961165e565b905080156107c957600b54600c54600654604051636ce5768960e11b81526001600160a01b0361010090940484169363d9caed129361331393908216929116908690600401613caf565b602060405180830381600087803b15801561332d57600080fd5b505af1158015613341573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267f9190613be3565b600080613371836116eb565b905061337b613913565b6002546040516339ebf82360e01b81526001600160a01b03909116906339ebf823906133ab903090600401613c4f565b6101206040518083038186803b1580156133c457600080fd5b505afa1580156133d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133fc9190613b4d565b9050806020015160001415613416576000925050506116ee565b60075460a08201516134299042906130ba565b101561343a576000925050506116ee565b60085460a082015161344d9042906130ba565b1061345d576001925050506116ee565b6002546040805163bf3759b560e01b815290516000926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b1580156134a257600080fd5b505afa1580156134b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134da9190613be3565b9050600a548111156134f257600193505050506116ee565b60006134fc612195565b90508260c00151613518600a54836135ef90919063ffffffff16565b101561352b5760019450505050506116ee565b60008360c0015182111561354c5760c08401516135499083906130ba565b90505b6002546040805163112c1f9b60e01b815290516000926001600160a01b03169163112c1f9b916004808301926020929190829003018186803b15801561359157600080fd5b505afa1580156135a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135c99190613be3565b90506135d581836135ef565b6009546135e2908861377d565b1098975050505050505050565b6000828201838110156130fc5760405162461bcd60e51b815260040161066690613d9d565b6060613669826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166126849092919063ffffffff16565b80519091501561267f57808060200190518101906136879190613a38565b61267f5760405162461bcd60e51b815260040161066690613f2f565b60606136ae85613825565b6136ca5760405162461bcd60e51b815260040161066690613ed3565b60006060866001600160a01b031685876040516136e79190613bfb565b60006040518083038185875af1925050503d8060008114613724576040519150601f19603f3d011682016040523d82523d6000602084013e613729565b606091505b5091509150811561373d5791506126939050565b80511561374d5780518082602001fd5b8360405162461bcd60e51b81526004016106669190613d26565b600081831061377657816130fc565b5090919050565b60008261378c5750600061218f565b8282028284828161379957fe5b04146130fc5760405162461bcd60e51b815260040161066690613e31565b60006130fc83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061385e565b6000818484111561381d5760405162461bcd60e51b81526004016106669190613d26565b505050900390565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590612693575050151592915050565b6000818361387f5760405162461bcd60e51b81526004016106669190613d26565b50600083858161388b57fe5b0495945050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106138d65782800160ff19823516178555613903565b82800160010185558215613903579182015b828111156139035782358255916020019190600101906138e8565b5061390f92915061395f565b5090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b5b8082111561390f5760008155600101613960565b600060208284031215613985578081fd5b81356130fc816140a3565b6000602082840312156139a1578081fd5b81516130fc816140a3565b600080600080600060a086880312156139c3578081fd5b85356139ce816140a3565b945060208601356139de816140a3565b935060408601356139ee816140a3565b925060608601356139fe816140a3565b91506080860135613a0e816140a3565b809150509295509295909350565b600060208284031215613a2d578081fd5b81356130fc816140b8565b600060208284031215613a49578081fd5b81516130fc816140b8565b60008060208385031215613a66578182fd5b823567ffffffffffffffff80821115613a7d578384fd5b818501915085601f830112613a90578384fd5b813581811115613a9e578485fd5b866020828501011115613aaf578485fd5b60209290920196919550909350505050565b600060208284031215613ad2578081fd5b815167ffffffffffffffff80821115613ae9578283fd5b818401915084601f830112613afc578283fd5b815181811115613b0a578384fd5b613b1d601f8201601f1916602001614050565b9150808252856020828501011115613b33578384fd5b613b44816020840160208601614077565b50949350505050565b6000610120808385031215613b60578182fd5b613b6981614050565b9050825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b600060208284031215613bdc578081fd5b5035919050565b600060208284031215613bf4578081fd5b5051919050565b60008251613c0d818460208701614077565b9190910192915050565b60006f29ba3930ba32b3bca130b630b731b2b960811b82528251613c42816010850160208701614077565b9190910160100192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0395861681529385166020850152918416604084015283166060830152909116608082015260a00190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b60006020825282602083015282846040840137818301604090810191909152601f909201601f19160101919050565b6000602082528251806020840152613d45816040850160208701614077565b601f01601f19169190910160400192915050565b6020808252600b908201526a085cdd1c985d1959da5cdd60aa1b604082015260600190565b602080825260059082015264085dd85b9d60da1b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252600c908201526b216865616c7468636865636b60a01b604082015260600190565b6020808252601c908201527f537472617465677920616c726561647920696e697469616c697a656400000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b602080825260069082015265085d985d5b1d60d21b604082015260600190565b6020808252600790820152662173686172657360c81b604082015260600190565b60208082526006908201526521636c6f6e6560d01b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252600a9082015269085c1c9bdd1958dd195960b21b604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b90815260200190565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b948552602085019390935260408401919091526060830152608082015260a00190565b60405181810167ffffffffffffffff8111828210171561406f57600080fd5b604052919050565b60005b8381101561409257818101518382015260200161407a565b83811115612f3d5750506000910152565b6001600160a01b0381168114611fb757600080fd5b8015158114611fb757600080fdfea264697066735822122021c2dcc2013f1034d7e422e7a76a7c23314dd1d7026623fe02a62f3a8639a9c464736f6c634300060c00330000000000000000000000004213458c69c19e6792510e1153cb0c5834665fdc000000000000000000000000c999de72bfafb936cb399b94a8048d24a27ed1ff

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103425760003560e01c80636f392ce7116101b8578063aced166111610104578063ed882c2b116100a2578063f45d75041161007c578063f45d750414610603578063fbfa77cf1461060b578063fcf2d0ad14610613578063ffea40081461061b57610342565b8063ed882c2b146105d5578063efbb5cb0146105e8578063f017c92f146105f057610342565b8063c7b9d530116100de578063c7b9d53014610594578063ce5494bb146105a7578063e5e19b4a146105ba578063ec38a862146105c257610342565b8063aced16611461057c578063b252720b14610584578063c1a3d44c1461058c57610342565b80638cdfe1661161017157806395e80c501161014b57806395e80c50146105515780639ec5a89414610559578063a6f19c8414610561578063ac00ff261461056957610342565b80638cdfe1661461052e5780638e6350e21461053657806391397ab41461053e57610342565b80636f392ce7146104d7578063748747e6146104df578063750521f5146104f2578063780022a0146105055780637bb7bed1146105135780637fcd3a851461052657610342565b806325829410116102925780634641257d11610230578063650d18801161020a578063650d1880146104a157806365210942146104b45780636718835f146104c75780636d51a20f146104cf57610342565b80634641257d146104895780635641ec03146104915780635b9f00161461049957610342565b8063372500ab1161026c578063372500ab1461045357806339a172a81461045b57806340bb9ee21461046e578063440368a31461048157610342565b8063258294101461043057806328b7ccf7146104385780632e1a7d4d1461044057610342565b806311bc8245116102ff5780631d12f28b116102d95780631d12f28b146103f65780631f1fcd511461040b5780631fe4a6861461041357806322f3e2d41461041b57610342565b806311bc8245146103bb5780631459457a146103ce5780631ba980b3146103e157610342565b806301681a621461034757806303ee438c1461035c578063052cdc0c1461037a57806306fdde031461038d5780630ada4dab146103955780630f969b87146103a8575b600080fd5b61035a610355366004613974565b61062e565b005b6103646107cd565b6040516103719190613d26565b60405180910390f35b61035a610388366004613974565b61085b565b6103646108bb565b61035a6103a3366004613a1c565b610960565b61035a6103b6366004613bcb565b6109c0565b61035a6103c9366004613974565b610a4d565b61035a6103dc3660046139ac565b610b4e565b6103e9610b6a565b6040516103719190613c4f565b6103fe610b7e565b6040516103719190613ff3565b6103e9610b84565b6103e9610b93565b610423610ba2565b6040516103719190613cec565b610364610c44565b6103fe610c63565b6103fe61044e366004613bcb565b610c69565b61035a610cc4565b61035a610469366004613bcb565b610e72565b61035a61047c366004613bcb565b610ef4565b61035a610f55565b61035a61117c565b610423611655565b6103fe61165e565b6104236104af366004613bcb565b6116eb565b61035a6104c2366004613974565b6116f3565b6104236118b3565b61035a6118bc565b610423611a53565b61035a6104ed366004613974565b611a61565b61035a610500366004613a54565b611b0c565b6103fe6104af366004613bcb565b6103e9610521366004613bcb565b611ba3565b6103fe611bca565b6103fe611bd0565b6103fe611bd6565b61035a61054c366004613bcb565b611bdb565b6103fe611c5d565b6103e9611c63565b6103e9611c72565b61035a610577366004613a1c565b611c81565b6103e9611d6d565b6103e9611d7c565b6103fe611d90565b61035a6105a2366004613974565b611dc1565b61035a6105b5366004613974565b611e6c565b6103e9611fba565b61035a6105d0366004613974565b611fc9565b6104236105e3366004613bcb565b61215c565b6103fe612195565b61035a6105fe366004613bcb565b6121b0565b6103fe612232565b6103e9612238565b61035a612247565b6103e96106293660046139ac565b61246c565b61063661269b565b6001600160a01b0316336001600160a01b03161461066f5760405162461bcd60e51b815260040161066690613f0a565b60405180910390fd5b6006546001600160a01b038281169116141561069d5760405162461bcd60e51b815260040161066690613d7e565b6002546001600160a01b03828116911614156106cb5760405162461bcd60e51b815260040161066690613e92565b60606106d5612718565b905060005b8151811015610730578181815181106106ef57fe5b60200260200101516001600160a01b0316836001600160a01b031614156107285760405162461bcd60e51b815260040161066690613f79565b6001016106da565b506107c961073c61269b565b6040516370a0823160e01b81526001600160a01b038516906370a0823190610768903090600401613c4f565b60206040518083038186803b15801561078057600080fd5b505afa158015610794573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107b89190613be3565b6001600160a01b038516919061271d565b5050565b6000805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156108535780601f1061082857610100808354040283529160200191610853565b820191906000526020600020905b81548152906001019060200180831161083657829003601f168201915b505050505081565b61086361269b565b6001600160a01b0316336001600160a01b0316146108935760405162461bcd60e51b815260040161066690613f0a565b600b80546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b600654604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b41916004808301926000929190829003018186803b15801561090057600080fd5b505afa158015610914573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261093c9190810190613ac1565b60405160200161094c9190613c17565b604051602081830303815290604052905090565b6003546001600160a01b0316331480610991575061097c61269b565b6001600160a01b0316336001600160a01b0316145b6109ad5760405162461bcd60e51b815260040161066690613f0a565b6010805460ff1916911515919091179055565b6003546001600160a01b03163314806109f157506109dc61269b565b6001600160a01b0316336001600160a01b0316145b610a0d5760405162461bcd60e51b815260040161066690613f0a565b600a8190556040517fa68ba126373d04c004c5748c300c9fca12bd444b3d4332e261f3bd2bac4a860090610a42908390613ff3565b60405180910390a150565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610a9b57600080fd5b505afa158015610aaf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ad39190613990565b6001600160a01b0316336001600160a01b03161480610b0a5750610af561269b565b6001600160a01b0316336001600160a01b0316145b610b265760405162461bcd60e51b815260040161066690613f0a565b600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b610b5a8585858561273c565b610b63816128f5565b5050505050565b600b5461010090046001600160a01b031681565b600a5481565b6006546001600160a01b031681565b6003546001600160a01b031681565b6002546040516339ebf82360e01b815260009182916001600160a01b03909116906339ebf82390610bd7903090600401613c4f565b6101206040518083038186803b158015610bf057600080fd5b505afa158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c289190613b4d565b604001511180610c3f57506000610c3d612195565b115b905090565b604080518082019091526005815264302e342e3360d81b602082015290565b60085481565b6002546000906001600160a01b03163314610c965760405162461bcd60e51b815260040161066690613e72565b6000610ca183612b4c565b600654909350909150610cbe906001600160a01b0316338361271d565b50919050565b6005546001600160a01b0316331480610ce757506003546001600160a01b031633145b80610d0a5750610cf561269b565b6001600160a01b0316336001600160a01b0316145b80610dab5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610d5e57600080fd5b505afa158015610d72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d969190613990565b6001600160a01b0316336001600160a01b0316145b80610e4c5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015610dff57600080fd5b505afa158015610e13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e379190613990565b6001600160a01b0316336001600160a01b0316145b610e685760405162461bcd60e51b815260040161066690613f0a565b610e70612c5d565b565b6003546001600160a01b0316331480610ea35750610e8e61269b565b6001600160a01b0316336001600160a01b0316145b610ebf5760405162461bcd60e51b815260040161066690613f0a565b60078190556040517fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b190610a42908390613ff3565b6003546001600160a01b0316331480610f255750610f1061269b565b6001600160a01b0316336001600160a01b0316145b610f415760405162461bcd60e51b815260040161066690613f0a565b612710811115610f5057600080fd5b600e55565b6005546001600160a01b0316331480610f7857506003546001600160a01b031633145b80610f9b5750610f8661269b565b6001600160a01b0316336001600160a01b0316145b8061103c5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b158015610fef57600080fd5b505afa158015611003573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110279190613990565b6001600160a01b0316336001600160a01b0316145b806110dd5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561109057600080fd5b505afa1580156110a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110c89190613990565b6001600160a01b0316336001600160a01b0316145b6110f95760405162461bcd60e51b815260040161066690613f0a565b6002546040805163bf3759b560e01b81529051610e70926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b15801561113f57600080fd5b505afa158015611153573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111779190613be3565b612f43565b6005546001600160a01b031633148061119f57506003546001600160a01b031633145b806111c257506111ad61269b565b6001600160a01b0316336001600160a01b0316145b806112635750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561121657600080fd5b505afa15801561122a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061124e9190613990565b6001600160a01b0316336001600160a01b0316145b806113045750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156112b757600080fd5b505afa1580156112cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ef9190613990565b6001600160a01b0316336001600160a01b0316145b6113205760405162461bcd60e51b815260040161066690613f0a565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b815260040160206040518083038186803b15801561137357600080fd5b505afa158015611387573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ab9190613be3565b600b5490915060009060ff16156114085760006113c6613003565b9050828110156113e1576113da83826130ba565b93506113f6565b828111156113f6576113f381846130ba565b94505b61140083856130ba565b915050611419565b61141182613103565b919550935090505b6002546040516339ebf82360e01b81526000916001600160a01b0316906339ebf8239061144a903090600401613c4f565b6101206040518083038186803b15801561146357600080fd5b505afa158015611477573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061149b9190613b4d565b60c001516002546040516328766ebf60e21b81529192506001600160a01b03169063a1d9bafc906114d490889088908790600401613ffc565b602060405180830381600087803b1580156114ee57600080fd5b505af1158015611502573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115269190613be3565b925061153183612f43565b60015460ff168015611552575060015461010090046001600160a01b031615155b156116045760015460405163c70fa00b60e01b81526101009091046001600160a01b03169063c70fa00b90611593908890889087908990889060040161402d565b60206040518083038186803b1580156115ab57600080fd5b505afa1580156115bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115e39190613a38565b6115ff5760405162461bcd60e51b815260040161066690613dd4565b611611565b6001805460ff1916811790555b7f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d509858584866040516116469493929190614012565b60405180910390a15050505050565b600b5460ff1681565b600b54600c546040516370a0823160e01b815260009261010090046001600160a01b03908116926370a082319261169b9290911690600401613c4f565b60206040518083038186803b1580156116b357600080fd5b505afa1580156116c7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3f9190613be3565b60005b919050565b6116fb61269b565b6001600160a01b0316336001600160a01b03161461172b5760405162461bcd60e51b815260040161066690613f0a565b600d546001600160a01b0316156117445761174461322c565b8061176673ba100000625a3754423978a60c9317c58a424e3d82600019612585565b600654604051632642a09360e11b81526001600160a01b0380841692634c854126926117ac9273ba100000625a3754423978a60c9317c58a424e3d921690600401613c63565b600060405180830381600087803b1580156117c657600080fd5b505af11580156117da573d6000803e3d6000fd5b5050505060005b600f5481101561188f576000600f82815481106117fa57fe5b6000918252602090912001546001600160a01b0316905061181e8185600019612585565b600654604051632642a09360e11b81526001600160a01b0380861692634c854126926118509286921690600401613c63565b600060405180830381600087803b15801561186a57600080fd5b505af115801561187e573d6000803e3d6000fd5b5050600190930192506117e1915050565b5050600d80546001600160a01b0319166001600160a01b0392909216919091179055565b60015460ff1681565b6003546001600160a01b03163314806118ed57506118d861269b565b6001600160a01b0316336001600160a01b0316145b8061198e5750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b15801561194157600080fd5b505afa158015611955573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119799190613990565b6001600160a01b0316336001600160a01b0316145b80611a2f5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b1580156119e257600080fd5b505afa1580156119f6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1a9190613990565b6001600160a01b0316336001600160a01b0316145b611a4b5760405162461bcd60e51b815260040161066690613f0a565b610e7061322c565b601054610100900460ff1681565b6003546001600160a01b0316331480611a925750611a7d61269b565b6001600160a01b0316336001600160a01b0316145b611aae5760405162461bcd60e51b815260040161066690613f0a565b6001600160a01b038116611ac157600080fd5b600580546001600160a01b0319166001600160a01b0383161790556040517f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe715490610a42908390613c4f565b6003546001600160a01b0316331480611b3d5750611b2861269b565b6001600160a01b0316336001600160a01b0316145b611b595760405162461bcd60e51b815260040161066690613f0a565b611b6560008383613895565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda68282604051611b97929190613cf7565b60405180910390a15050565b600f8181548110611bb057fe5b6000918252602090912001546001600160a01b0316905081565b600e5481565b60095481565b600090565b6003546001600160a01b0316331480611c0c5750611bf761269b565b6001600160a01b0316336001600160a01b0316145b611c285760405162461bcd60e51b815260040161066690613f0a565b60098190556040517fd94596337df4c2f0f44d30a7fc5db1c7bb60d9aca4185ed77c6fd96eb45ec29890610a42908390613ff3565b60075481565b6004546001600160a01b031681565b600c546001600160a01b031681565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b158015611ccf57600080fd5b505afa158015611ce3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d079190613990565b6001600160a01b0316336001600160a01b03161480611d3e5750611d2961269b565b6001600160a01b0316336001600160a01b0316145b611d5a5760405162461bcd60e51b815260040161066690613f0a565b6001805460ff1916911515919091179055565b6005546001600160a01b031681565b60015461010090046001600160a01b031681565b6006546040516370a0823160e01b81526000916001600160a01b0316906370a082319061169b903090600401613c4f565b6003546001600160a01b0316331480611df25750611ddd61269b565b6001600160a01b0316336001600160a01b0316145b611e0e5760405162461bcd60e51b815260040161066690613f0a565b6001600160a01b038116611e2157600080fd5b600380546001600160a01b0319166001600160a01b0383161790556040517f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b490610a42908390613c4f565b6002546001600160a01b03163314611e8357600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf916004808301926020929190829003018186803b158015611eca57600080fd5b505afa158015611ede573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f029190613990565b6001600160a01b031614611f1557600080fd5b611f1e816132bf565b6006546040516370a0823160e01b8152611fb79183916001600160a01b03909116906370a0823190611f54903090600401613c4f565b60206040518083038186803b158015611f6c57600080fd5b505afa158015611f80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fa49190613be3565b6006546001600160a01b0316919061271d565b50565b600d546001600160a01b031681565b6003546001600160a01b03163314611ff35760405162461bcd60e51b815260040161066690613d59565b6001600160a01b03811661200657600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b039384169363095ea7b39361203d939091169160009101613cd3565b602060405180830381600087803b15801561205757600080fd5b505af115801561206b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061208f9190613a38565b50600480546001600160a01b0319166001600160a01b038381169190911780835560025460405163095ea7b360e01b81529083169363095ea7b3936120da9316916000199101613cd3565b602060405180830381600087803b1580156120f457600080fd5b505af1158015612108573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061212c9190613a38565b507fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a06981604051610a429190613c4f565b60105460009060ff1615612172575060016116ee565b61217a610ba2565b612186575060006116ee565b61218f82613365565b92915050565b6000610c3f6121a261165e565b6121aa611d90565b906135ef565b6003546001600160a01b03163314806121e157506121cc61269b565b6001600160a01b0316336001600160a01b0316145b6121fd5760405162461bcd60e51b815260040161066690613f0a565b60088190556040517f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c590610a42908390613ff3565b61271081565b6002546001600160a01b031681565b6003546001600160a01b0316331480612278575061226361269b565b6001600160a01b0316336001600160a01b0316145b806123195750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b815260040160206040518083038186803b1580156122cc57600080fd5b505afa1580156122e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123049190613990565b6001600160a01b0316336001600160a01b0316145b806123ba5750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b815260040160206040518083038186803b15801561236d57600080fd5b505afa158015612381573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a59190613990565b6001600160a01b0316336001600160a01b0316145b6123d65760405162461bcd60e51b815260040161066690613f0a565b600b805460ff191660011790556002546040805163507257cd60e11b815290516001600160a01b039092169163a0e4af9a9160048082019260009290919082900301818387803b15801561242957600080fd5b505af115801561243d573d6000803e3d6000fd5b50506040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b925060009150a1565b601054600090610100900460ff166124965760405162461bcd60e51b815260040161066690613eb3565b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81523060601b601482018190526e5af43d82803e903d91602b57fd5bf360881b6028830152906037816000f0604051630a2ca2bd60e11b81529093506001600160a01b0384169150631459457a90612515908a908a908a908a908a90600401613c7d565b600060405180830381600087803b15801561252f57600080fd5b505af1158015612543573d6000803e3d6000fd5b50506040516001600160a01b03851692507f783540fb4221a3238720dc7038937d0d79982bcf895274aa6ad179f82cf0d53c9150600090a25095945050505050565b80158061260d5750604051636eb1769f60e11b81526001600160a01b0384169063dd62ed3e906125bb9030908690600401613c63565b60206040518083038186803b1580156125d357600080fd5b505afa1580156125e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061260b9190613be3565b155b6126295760405162461bcd60e51b815260040161066690613f9d565b61267f8363095ea7b360e01b8484604051602401612648929190613cd3565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613614565b505050565b606061269384846000856136a3565b949350505050565b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e675916004808301926020929190829003018186803b1580156126e057600080fd5b505afa1580156126f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3f9190613990565b606090565b61267f8363a9059cbb60e01b8484604051602401612648929190613cd3565b6006546001600160a01b0316156127655760405162461bcd60e51b815260040161066690613dfa565b600280546001600160a01b0319166001600160a01b03868116919091179182905560408051637e062a3560e11b81529051929091169163fc0c546a91600480820192602092909190829003018186803b1580156127c157600080fd5b505afa1580156127d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127f99190613990565b600680546001600160a01b0319166001600160a01b039283161790819055612825911685600019612585565b600380546001600160a01b038086166001600160a01b03199283161790925560048054858416908316178082556005805486861694169390931790925560006007819055620151806008556064600955600a5560025460405163095ea7b360e01b81529084169363095ea7b3936128a3939116916000199101613cd3565b602060405180830381600087803b1580156128bd57600080fd5b505af11580156128d1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b639190613a38565b600b80546001600160a01b0380841661010002610100600160a81b03199092169190911790915560065461292d911682600019612585565b60065460405163a8ea687560e01b8152734e7bbd911cf1efa442bc1b2e9ea01ffe785412ec9163a8ea68759161296f916001600160a01b031690600401613c4f565b60206040518083038186803b15801561298757600080fd5b505afa15801561299b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129bf9190613990565b600c80546001600160a01b0319166001600160a01b0392831617908190556103e8600e556040805163963c94b960e01b81529051600093929092169163963c94b991600480820192602092909190829003018186803b158015612a2157600080fd5b505afa158015612a35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a599190613be3565b905060005b81811015612b1f57600c546040516354c49fe960e01b8152600f916001600160a01b0316906354c49fe990612a97908590600401613ff3565b60206040518083038186803b158015612aaf57600080fd5b505afa158015612ac3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ae79190613990565b815460018082018455600093845260209093200180546001600160a01b0319166001600160a01b039290921691909117905501612a5e565b505060018054610100600160a81b03191674ddcea799ff1699e98edf118e0629a974df7df0120017905550565b6000806000612b59611d90565b905080841115612c49576000612b6d61165e565b90508015612c1e57600b54600c546006546001600160a01b0361010090930483169263d9caed129281169116612bac85612ba78b896130ba565b613767565b6040518463ffffffff1660e01b8152600401612bca93929190613caf565b602060405180830381600087803b158015612be457600080fd5b505af1158015612bf8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c1c9190613be3565b505b6000612c28611d90565b9050612c348682613767565b9450612c4086866130ba565b93505050612c56565b8360009250925050612c58565b505b915091565b600f5415612cd157600b54600c54604051633bd73ee360e21b81526001600160a01b0361010090930483169263ef5cfb8c92612c9e92911690600401613c4f565b600060405180830381600087803b158015612cb857600080fd5b505af1158015612ccc573d6000803e3d6000fd5b505050505b6000612cdb61165e565b90508015611fb7576040516370a0823160e01b815260009073ba100000625a3754423978a60c9317c58a424e3d906370a0823190612d1d903090600401613c4f565b60206040518083038186803b158015612d3557600080fd5b505afa158015612d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6d9190613be3565b600b54600c54604051630f258cb560e11b81529293506001600160a01b03610100909204821692631e4b196a92612da8921690600401613c4f565b600060405180830381600087803b158015612dc257600080fd5b505af1158015612dd6573d6000803e3d6000fd5b50506040516370a0823160e01b815260009250612e709150839073ba100000625a3754423978a60c9317c58a424e3d906370a0823190612e1a903090600401613c4f565b60206040518083038186803b158015612e3257600080fd5b505afa158015612e46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e6a9190613be3565b906130ba565b9050801561267f576000612e9b612710612e95600e548561377d90919063ffffffff16565b906137b7565b90508015612f3d57600b54612ed49073ba100000625a3754423978a60c9317c58a424e3d9061010090046001600160a01b03168361271d565b600b60019054906101000a90046001600160a01b03166001600160a01b031663d788f3716040518163ffffffff1660e01b8152600401600060405180830381600087803b158015612f2457600080fd5b505af1158015612f38573d6000803e3d6000fd5b505050505b50505050565b600b5460ff1615612f5357611fb7565b6000612f5d611d90565b90508015612ffb57600b54600654612f88916001600160a01b0391821691610100909104168361271d565b600b54600c54600654604051631f2c13e160e31b81526001600160a01b0361010090940484169363f9609f0893612fc89390821692911690600401613c63565b600060405180830381600087803b158015612fe257600080fd5b505af1158015612ff6573d6000803e3d6000fd5b505050505b6107c9612c5d565b60008061300e61165e565b905080156130ac57600b54600c54600654604051636ce5768960e11b81526001600160a01b0361010090940484169363d9caed129361305893908216929116908690600401613caf565b602060405180830381600087803b15801561307257600080fd5b505af1158015613086573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130aa9190613be3565b505b6130b4611d90565b91505090565b60006130fc83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f7700008152506137f9565b9392505050565b6002546040516339ebf82360e01b81526000918291829182916001600160a01b03909116906339ebf8239061313c903090600401613c4f565b6101206040518083038186803b15801561315557600080fd5b505afa158015613169573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061318d9190613b4d565b60c001519050600061319d612195565b90508181116131ad5760006131b7565b6131b781836130ba565b94506000806131c688886135ef565b905080156131dc576131d781612b4c565b965091505b6131e68883613767565b945086861115613205576131fa86886130ba565b955060009650613216565b61320f87876130ba565b9650600095505b50506010805460ff191690555092949193509150565b600d546132599073ba100000625a3754423978a60c9317c58a424e3d906001600160a01b03166000612585565b60005b600f548110156132ac57600d54600f80546132a4926001600160a01b0316916000918590811061328857fe5b6000918252602090912001546001600160a01b03169190612585565b60010161325c565b50600d80546001600160a01b0319169055565b60006132c961165e565b905080156107c957600b54600c54600654604051636ce5768960e11b81526001600160a01b0361010090940484169363d9caed129361331393908216929116908690600401613caf565b602060405180830381600087803b15801561332d57600080fd5b505af1158015613341573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061267f9190613be3565b600080613371836116eb565b905061337b613913565b6002546040516339ebf82360e01b81526001600160a01b03909116906339ebf823906133ab903090600401613c4f565b6101206040518083038186803b1580156133c457600080fd5b505afa1580156133d8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133fc9190613b4d565b9050806020015160001415613416576000925050506116ee565b60075460a08201516134299042906130ba565b101561343a576000925050506116ee565b60085460a082015161344d9042906130ba565b1061345d576001925050506116ee565b6002546040805163bf3759b560e01b815290516000926001600160a01b03169163bf3759b5916004808301926020929190829003018186803b1580156134a257600080fd5b505afa1580156134b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134da9190613be3565b9050600a548111156134f257600193505050506116ee565b60006134fc612195565b90508260c00151613518600a54836135ef90919063ffffffff16565b101561352b5760019450505050506116ee565b60008360c0015182111561354c5760c08401516135499083906130ba565b90505b6002546040805163112c1f9b60e01b815290516000926001600160a01b03169163112c1f9b916004808301926020929190829003018186803b15801561359157600080fd5b505afa1580156135a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135c99190613be3565b90506135d581836135ef565b6009546135e2908861377d565b1098975050505050505050565b6000828201838110156130fc5760405162461bcd60e51b815260040161066690613d9d565b6060613669826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166126849092919063ffffffff16565b80519091501561267f57808060200190518101906136879190613a38565b61267f5760405162461bcd60e51b815260040161066690613f2f565b60606136ae85613825565b6136ca5760405162461bcd60e51b815260040161066690613ed3565b60006060866001600160a01b031685876040516136e79190613bfb565b60006040518083038185875af1925050503d8060008114613724576040519150601f19603f3d011682016040523d82523d6000602084013e613729565b606091505b5091509150811561373d5791506126939050565b80511561374d5780518082602001fd5b8360405162461bcd60e51b81526004016106669190613d26565b600081831061377657816130fc565b5090919050565b60008261378c5750600061218f565b8282028284828161379957fe5b04146130fc5760405162461bcd60e51b815260040161066690613e31565b60006130fc83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f00000000000081525061385e565b6000818484111561381d5760405162461bcd60e51b81526004016106669190613d26565b505050900390565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590612693575050151592915050565b6000818361387f5760405162461bcd60e51b81526004016106669190613d26565b50600083858161388b57fe5b0495945050505050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106138d65782800160ff19823516178555613903565b82800160010185558215613903579182015b828111156139035782358255916020019190600101906138e8565b5061390f92915061395f565b5090565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b5b8082111561390f5760008155600101613960565b600060208284031215613985578081fd5b81356130fc816140a3565b6000602082840312156139a1578081fd5b81516130fc816140a3565b600080600080600060a086880312156139c3578081fd5b85356139ce816140a3565b945060208601356139de816140a3565b935060408601356139ee816140a3565b925060608601356139fe816140a3565b91506080860135613a0e816140a3565b809150509295509295909350565b600060208284031215613a2d578081fd5b81356130fc816140b8565b600060208284031215613a49578081fd5b81516130fc816140b8565b60008060208385031215613a66578182fd5b823567ffffffffffffffff80821115613a7d578384fd5b818501915085601f830112613a90578384fd5b813581811115613a9e578485fd5b866020828501011115613aaf578485fd5b60209290920196919550909350505050565b600060208284031215613ad2578081fd5b815167ffffffffffffffff80821115613ae9578283fd5b818401915084601f830112613afc578283fd5b815181811115613b0a578384fd5b613b1d601f8201601f1916602001614050565b9150808252856020828501011115613b33578384fd5b613b44816020840160208601614077565b50949350505050565b6000610120808385031215613b60578182fd5b613b6981614050565b9050825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b600060208284031215613bdc578081fd5b5035919050565b600060208284031215613bf4578081fd5b5051919050565b60008251613c0d818460208701614077565b9190910192915050565b60006f29ba3930ba32b3bca130b630b731b2b960811b82528251613c42816010850160208701614077565b9190910160100192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0395861681529385166020850152918416604084015283166060830152909116608082015260a00190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b60006020825282602083015282846040840137818301604090810191909152601f909201601f19160101919050565b6000602082528251806020840152613d45816040850160208701614077565b601f01601f19169190910160400192915050565b6020808252600b908201526a085cdd1c985d1959da5cdd60aa1b604082015260600190565b602080825260059082015264085dd85b9d60da1b604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b6020808252600c908201526b216865616c7468636865636b60a01b604082015260600190565b6020808252601c908201527f537472617465677920616c726561647920696e697469616c697a656400000000604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b602080825260069082015265085d985d5b1d60d21b604082015260600190565b6020808252600790820152662173686172657360c81b604082015260600190565b60208082526006908201526521636c6f6e6560d01b604082015260600190565b6020808252601d908201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604082015260600190565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b6020808252602a908201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6040820152691bdd081cdd58d8d9595960b21b606082015260800190565b6020808252600a9082015269085c1c9bdd1958dd195960b21b604082015260600190565b60208082526036908201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60408201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606082015260800190565b90815260200190565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b948552602085019390935260408401919091526060830152608082015260a00190565b60405181810167ffffffffffffffff8111828210171561406f57600080fd5b604052919050565b60005b8381101561409257818101518382015260200161407a565b83811115612f3d5750506000910152565b6001600160a01b0381168114611fb757600080fd5b8015158114611fb757600080fdfea264697066735822122021c2dcc2013f1034d7e422e7a76a7c23314dd1d7026623fe02a62f3a8639a9c464736f6c634300060c0033

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

0000000000000000000000004213458c69c19e6792510e1153cb0c5834665fdc000000000000000000000000c999de72bfafb936cb399b94a8048d24a27ed1ff

-----Decoded View---------------
Arg [0] : _vault (address): 0x4213458C69c19E6792510E1153cb0c5834665fdC
Arg [1] : _voterProxy (address): 0xc999dE72BFAFB936Cb399B94A8048D24a27eD1Ff

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000004213458c69c19e6792510e1153cb0c5834665fdc
Arg [1] : 000000000000000000000000c999de72bfafb936cb399b94a8048d24a27ed1ff


Deployed Bytecode Sourcemap

115584:11455:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;92978:444;;;;;;:::i;:::-;;:::i;:::-;;64207:25;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;119644:139;;;;;;:::i;:::-;;:::i;119030:279::-;;;:::i;120106:183::-;;;;;;:::i;:::-;;:::i;74580:175::-;;;;;;:::i;:::-;;:::i;70148:118::-;;;;;;:::i;:::-;;:::i;116970:287::-;;;;;;:::i;:::-;;:::i;115741:44::-;;;:::i;:::-;;;;;;;:::i;67486:28::-;;;:::i;:::-;;;;;;;:::i;66234:18::-;;;:::i;66143:25::-;;;:::i;77982:148::-;;;:::i;:::-;;;;;;;:::i;64606:91::-;;;:::i;67122:29::-;;;:::i;89382:515::-;;;;;;:::i;:::-;;:::i;119480:156::-;;;:::i;72629:154::-;;;;;;:::i;:::-;;:::i;119892:137::-;;;;;;:::i;:::-;;:::i;83079:170::-;;;:::i;87558:1580::-;;;:::i;67565:25::-;;;:::i;121897:108::-;;;:::i;82318:432::-;;;;;;:::i;:::-;;:::i;120297:649::-;;;;;;:::i;:::-;;:::i;64263:25::-;;;:::i;120954:125::-;;;:::i;116731:29::-;;;:::i;71386:174::-;;;;;;:::i;:::-;;:::i;75058:171::-;;;;;;:::i;:::-;;:::i;122272:121::-;;;;;;:::i;116557:29::-;;;;;;:::i;:::-;;:::i;115923:22::-;;;:::i;67308:27::-;;;:::i;66013:94::-;;;:::i;73854:169::-;;;;;;:::i;:::-;;:::i;66971:29::-;;;:::i;66175:22::-;;;:::i;115792:20::-;;;:::i;70274:123::-;;;;;;:::i;:::-;;:::i;66204:21::-;;;:::i;64295:26::-;;;:::i;122013:110::-;;;:::i;70630:202::-;;;;;;:::i;:::-;;:::i;90669:281::-;;;;;;:::i;:::-;;:::i;115874:40::-;;;:::i;71849:263::-;;;;;;:::i;:::-;;:::i;121087:517::-;;;;;;:::i;:::-;;:::i;122131:133::-;;;:::i;73300:154::-;;;;;;:::i;:::-;;:::i;116013:48::-;;;:::i;66115:21::-;;;:::i;91379:173::-;;;:::i;117960:1062::-;;;;;;:::i;:::-;;:::i;92978:444::-;68191:12;:10;:12::i;:::-;-1:-1:-1;;;;;68177:26:0;:10;-1:-1:-1;;;;;68177:26:0;;68169:50;;;;-1:-1:-1;;;68169:50:0;;;;;;;:::i;:::-;;;;;;;;;93070:4:::1;::::0;-1:-1:-1;;;;;93052:23:0;;::::1;93070:4:::0;::::1;93052:23;;93044:41;;;;-1:-1:-1::0;;;93044:41:0::1;;;;;;;:::i;:::-;93122:5;::::0;-1:-1:-1;;;;;93104:24:0;;::::1;93122:5:::0;::::1;93104:24;;93096:44;;;;-1:-1:-1::0;;;93096:44:0::1;;;;;;;:::i;:::-;93153:33;93189:17;:15;:17::i;:::-;93153:53;;93222:9;93217:102;93237:16;:23;93233:1;:27;93217:102;;;93285:16;93302:1;93285:19;;;;;;;;;;;;;;-1:-1:-1::0;;;;;93275:29:0::1;:6;-1:-1:-1::0;;;;;93275:29:0::1;;;93267:52;;;;-1:-1:-1::0;;;93267:52:0::1;;;;;;;:::i;:::-;93262:3;;93217:102;;;;93332:82;93360:12;:10;:12::i;:::-;93374:39;::::0;-1:-1:-1;;;93374:39:0;;-1:-1:-1;;;;;93374:24:0;::::1;::::0;::::1;::::0;:39:::1;::::0;93407:4:::1;::::0;93374:39:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;93332:27:0;::::1;::::0;:82;:27:::1;:82::i;:::-;68230:1;92978:444:::0;:::o;64207:25::-;;;;;;;;;;;;;;;-1:-1:-1;;64207:25:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;119644:139::-;68191:12;:10;:12::i;:::-;-1:-1:-1;;;;;68177:26:0;:10;-1:-1:-1;;;;;68177:26:0;;68169:50;;;;-1:-1:-1;;;68169:50:0;;;;;;;:::i;:::-;119723:10:::1;:52:::0;;-1:-1:-1;;;;;119723:52:0;;::::1;;;-1:-1:-1::0;;;;;;119723:52:0;;::::1;::::0;;;::::1;::::0;;119644:139::o;119030:279::-;119252:4;;119229:38;;;-1:-1:-1;;;119229:38:0;;;;119078:13;;-1:-1:-1;;;;;119252:4:0;;119229:36;;:38;;;;;119252:4;;119229:38;;;;;;;119252:4;119229:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;119229:38:0;;;;;;;;;;;;:::i;:::-;119149:137;;;;;;;;:::i;:::-;;;;;;;;;;;;;119104:197;;119030:279;:::o;120106:183::-;67676:10;;-1:-1:-1;;;;;67676:10:0;67662;:24;;:54;;;67704:12;:10;:12::i;:::-;-1:-1:-1;;;;;67690:26:0;:10;-1:-1:-1;;;;;67690:26:0;;67662:54;67654:78;;;;-1:-1:-1;;;67654:78:0;;;;;;;:::i;:::-;120231:23:::1;:50:::0;;-1:-1:-1;;120231:50:0::1;::::0;::::1;;::::0;;;::::1;::::0;;120106:183::o;74580:175::-;67676:10;;-1:-1:-1;;;;;67676:10:0;67662;:24;;:54;;;67704:12;:10;:12::i;:::-;-1:-1:-1;;;;;67690:26:0;:10;-1:-1:-1;;;;;67690:26:0;;67662:54;67654:78;;;;-1:-1:-1;;;67654:78:0;;;;;;;:::i;:::-;74665:13:::1;:30:::0;;;74711:36:::1;::::0;::::1;::::0;::::1;::::0;74681:14;;74711:36:::1;:::i;:::-;;;;;;;;74580:175:::0;:::o;70148:118::-;68648:5;;;;;;;;;-1:-1:-1;;;;;68648:5:0;-1:-1:-1;;;;;68648:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68634:32:0;:10;-1:-1:-1;;;;;68634:32:0;;:62;;;;68684:12;:10;:12::i;:::-;-1:-1:-1;;;;;68670:26:0;:10;-1:-1:-1;;;;;68670:26:0;;68634:62;68626:86;;;;-1:-1:-1;;;68626:86:0;;;;;;;:::i;:::-;70232:11:::1;:26:::0;;-1:-1:-1;;;;;70232:26:0;;::::1;;;-1:-1:-1::0;;;;;;70232:26:0;;::::1;::::0;;;::::1;::::0;;70148:118::o;116970:287::-;117155:51;117167:6;117175:11;117188:8;117198:7;117155:11;:51::i;:::-;117217:32;117237:11;117217:19;:32::i;:::-;116970:287;;;;;:::o;115741:44::-;;;;;;-1:-1:-1;;;;;115741:44:0;;:::o;67486:28::-;;;;:::o;66234:18::-;;;-1:-1:-1;;;;;66234:18:0;;:::o;66143:25::-;;;-1:-1:-1;;;;;66143:25:0;;:::o;77982:148::-;78047:5;;:31;;-1:-1:-1;;;78047:31:0;;78023:4;;;;-1:-1:-1;;;;;78047:5:0;;;;:16;;:31;;78072:4;;78047:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;;:45;:75;;;;78121:1;78096:22;:20;:22::i;:::-;:26;78047:75;78040:82;;77982:148;:::o;64606:91::-;64675:14;;;;;;;;;;;;-1:-1:-1;;;64675:14:0;;;;64606:91;:::o;67122:29::-;;;;:::o;89382:515::-;89497:5;;89441:13;;-1:-1:-1;;;;;89497:5:0;89475:10;:28;89467:47;;;;-1:-1:-1;;;89467:47:0;;;;;;;:::i;:::-;89600:19;89653:32;89671:13;89653:17;:32::i;:::-;89777:4;;89630:55;;-1:-1:-1;89630:55:0;;-1:-1:-1;89777:42:0;;-1:-1:-1;;;;;89777:4:0;89795:10;89630:55;89777:17;:42::i;:::-;89382:515;;;;:::o;119480:156::-;68317:6;;-1:-1:-1;;;;;68317:6:0;68303:10;:20;;:65;;-1:-1:-1;68358:10:0;;-1:-1:-1;;;;;68358:10:0;68344;:24;68303:65;:112;;;;68403:12;:10;:12::i;:::-;-1:-1:-1;;;;;68389:26:0;:10;-1:-1:-1;;;;;68389:26:0;;68303:112;:163;;;;68450:5;;;;;;;;;-1:-1:-1;;;;;68450:5:0;-1:-1:-1;;;;;68450:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68436:30:0;:10;-1:-1:-1;;;;;68436:30:0;;68303:163;:216;;;;68501:5;;;;;;;;;-1:-1:-1;;;;;68501:5:0;-1:-1:-1;;;;;68501:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68487:32:0;:10;-1:-1:-1;;;;;68487:32:0;;68303:216;68281:277;;;;-1:-1:-1;;;68281:277:0;;;;;;;:::i;:::-;119613:15:::1;:13;:15::i;:::-;119480:156::o:0;72629:154::-;67676:10;;-1:-1:-1;;;;;67676:10:0;67662;:24;;:54;;;67704:12;:10;:12::i;:::-;-1:-1:-1;;;;;67690:26:0;:10;-1:-1:-1;;;;;67690:26:0;;67662:54;67654:78;;;;-1:-1:-1;;;67654:78:0;;;;;;;:::i;:::-;72707:14:::1;:23:::0;;;72746:29:::1;::::0;::::1;::::0;::::1;::::0;72724:6;;72746:29:::1;:::i;119892:137::-:0;67676:10;;-1:-1:-1;;;;;67676:10:0;67662;:24;;:54;;;67704:12;:10;:12::i;:::-;-1:-1:-1;;;;;67690:26:0;:10;-1:-1:-1;;;;;67690:26:0;;67662:54;67654:78;;;;-1:-1:-1;;;67654:78:0;;;;;;;:::i;:::-;119985:6:::1;119973:8;:18;;119965:27;;;::::0;::::1;;120003:7;:18:::0;119892:137::o;83079:170::-;68317:6;;-1:-1:-1;;;;;68317:6:0;68303:10;:20;;:65;;-1:-1:-1;68358:10:0;;-1:-1:-1;;;;;68358:10:0;68344;:24;68303:65;:112;;;;68403:12;:10;:12::i;:::-;-1:-1:-1;;;;;68389:26:0;:10;-1:-1:-1;;;;;68389:26:0;;68303:112;:163;;;;68450:5;;;;;;;;;-1:-1:-1;;;;;68450:5:0;-1:-1:-1;;;;;68450:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68436:30:0;:10;-1:-1:-1;;;;;68436:30:0;;68303:163;:216;;;;68501:5;;;;;;;;;-1:-1:-1;;;;;68501:5:0;-1:-1:-1;;;;;68501:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68487:32:0;:10;-1:-1:-1;;;;;68487:32:0;;68303:216;68281:277;;;;-1:-1:-1;;;68281:277:0;;;;;;;:::i;:::-;83217:5:::1;::::0;:23:::1;::::0;;-1:-1:-1;;;83217:23:0;;;;83202:39:::1;::::0;-1:-1:-1;;;;;83217:5:0::1;::::0;:21:::1;::::0;:23:::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;:5;:23;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;83202:14;:39::i;87558:1580::-:0;68317:6;;-1:-1:-1;;;;;68317:6:0;68303:10;:20;;:65;;-1:-1:-1;68358:10:0;;-1:-1:-1;;;;;68358:10:0;68344;:24;68303:65;:112;;;;68403:12;:10;:12::i;:::-;-1:-1:-1;;;;;68389:26:0;:10;-1:-1:-1;;;;;68389:26:0;;68303:112;:163;;;;68450:5;;;;;;;;;-1:-1:-1;;;;;68450:5:0;-1:-1:-1;;;;;68450:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68436:30:0;:10;-1:-1:-1;;;;;68436:30:0;;68303:163;:216;;;;68501:5;;;;;;;;;-1:-1:-1;;;;;68501:5:0;-1:-1:-1;;;;;68501:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68487:32:0;:10;-1:-1:-1;;;;;68487:32:0;;68303:216;68281:277;;;;-1:-1:-1;;;68281:277:0;;;;;;;:::i;:::-;87609:14:::1;87638:12:::0;87665:23:::1;87691:5;;;;;;;;;-1:-1:-1::0;;;;;87691:5:0::1;-1:-1:-1::0;;;;;87691:21:0::1;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;87763:13;::::0;87665:49;;-1:-1:-1;87725:19:0::1;::::0;87763:13:::1;;87759:580;;;87845:19;87867:23;:21;:23::i;:::-;87845:45;;87923:15;87909:11;:29;87905:226;;;87966:32;:15:::0;87986:11;87966:19:::1;:32::i;:::-;87959:39;;87905:226;;;88038:15;88024:11;:29;88020:111;;;88083:32;:11:::0;88099:15;88083::::1;:32::i;:::-;88074:41;;88020:111;88159:25;:15:::0;88179:4;88159:19:::1;:25::i;:::-;88145:39;;87759:580;;;;88297:30;88311:15;88297:13;:30::i;:::-;88267:60:::0;;-1:-1:-1;88267:60:0;-1:-1:-1;88267:60:0;-1:-1:-1;87759:580:0::1;88555:5;::::0;:31:::1;::::0;-1:-1:-1;;;88555:31:0;;88535:17:::1;::::0;-1:-1:-1;;;;;88555:5:0::1;::::0;:16:::1;::::0;:31:::1;::::0;88580:4:::1;::::0;88555:31:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;::::0;88625:5:::1;::::0;:39:::1;::::0;-1:-1:-1;;;88625:39:0;;88555:41;;-1:-1:-1;;;;;;88625:5:0::1;::::0;:12:::1;::::0;:39:::1;::::0;88638:6;;88646:4;;88652:11;;88625:39:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;88607:57;;88740:31;88755:15;88740:14;:31::i;:::-;88826:13;::::0;::::1;;:42:::0;::::1;;;-1:-1:-1::0;88843:11:0::1;::::0;::::1;::::0;::::1;-1:-1:-1::0;;;;;88843:11:0::1;:25:::0;::::1;88826:42;88822:238;;;88905:11;::::0;88893:85:::1;::::0;-1:-1:-1;;;88893:85:0;;88905:11:::1;::::0;;::::1;-1:-1:-1::0;;;;;88905:11:0::1;::::0;88893:30:::1;::::0;:85:::1;::::0;88924:6;;88932:4;;88938:11;;88951:15;;88968:9;;88893:85:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;88885:110;;;;-1:-1:-1::0;;;88885:110:0::1;;;;;;;:::i;:::-;88822:238;;;89044:4;89028:20:::0;;-1:-1:-1;;89028:20:0::1;::::0;::::1;::::0;;88822:238:::1;89077:53;89087:6;89095:4;89101:11;89114:15;89077:53;;;;;;;;;:::i;:::-;;;;;;;;68569:1;;;;;87558:1580::o:0;67565:25::-;;;;;;:::o;121897:108::-;121970:10;;121991:5;;121970:27;;-1:-1:-1;;;121970:27:0;;121943:7;;121970:10;;;-1:-1:-1;;;;;121970:10:0;;;;:20;;:27;;121991:5;;;;121970:27;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;82318:432::-;82391:4;82318:432;;;;:::o;120297:649::-;68191:12;:10;:12::i;:::-;-1:-1:-1;;;;;68177:26:0;:10;-1:-1:-1;;;;;68177:26:0;;68169:50;;;;-1:-1:-1;;;68169:50:0;;;;;;;:::i;:::-;120384:12:::1;::::0;-1:-1:-1;;;;;120384:12:0::1;:26:::0;120380:91:::1;;120427:32;:30;:32::i;:::-;120516:13:::0;120543:49:::1;116137:42;120516:13:::0;-1:-1:-1;;120543:15:0::1;:49::i;:::-;120635:4;::::0;120603:38:::1;::::0;-1:-1:-1;;;120603:38:0;;-1:-1:-1;;;;;120603:9:0;;::::1;::::0;::::1;::::0;:38:::1;::::0;116137:42:::1;::::0;120635:4:::1;::::0;120603:38:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;120659:9;120654:246;120678:12;:19:::0;120674:23;::::1;120654:246;;;120719:19;120741:12;120754:1;120741:15;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;-1:-1:-1;;;;;120741:15:0::1;::::0;-1:-1:-1;120771:65:0::1;120741:15:::0;120803:13;-1:-1:-1;;120771:31:0::1;:65::i;:::-;120882:4;::::0;120851:37:::1;::::0;-1:-1:-1;;;120851:37:0;;-1:-1:-1;;;;;120851:9:0;;::::1;::::0;::::1;::::0;:37:::1;::::0;120861:11;;120882:4:::1;::::0;120851:37:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;120699:3:0::1;::::0;;::::1;::::0;-1:-1:-1;120654:246:0::1;::::0;-1:-1:-1;;120654:246:0::1;;-1:-1:-1::0;;120910:12:0::1;:28:::0;;-1:-1:-1;;;;;;120910:28:0::1;-1:-1:-1::0;;;;;120910:28:0;;;::::1;::::0;;;::::1;::::0;;120297:649::o;64263:25::-;;;;;;:::o;120954:125::-;67842:10;;-1:-1:-1;;;;;67842:10:0;67828;:24;;:54;;;67870:12;:10;:12::i;:::-;-1:-1:-1;;;;;67856:26:0;:10;-1:-1:-1;;;;;67856:26:0;;67828:54;:88;;;;67900:5;;;;;;;;;-1:-1:-1;;;;;67900:5:0;-1:-1:-1;;;;;67900:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;67886:30:0;:10;-1:-1:-1;;;;;67886:30:0;;67828:88;:124;;;;67934:5;;;;;;;;;-1:-1:-1;;;;;67934:5:0;-1:-1:-1;;;;;67934:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;67920:32:0;:10;-1:-1:-1;;;;;67920:32:0;;67828:124;67806:185;;;;-1:-1:-1;;;67806:185:0;;;;;;;:::i;:::-;121039:32:::1;:30;:32::i;116731:29::-:0;;;;;;;;;:::o;71386:174::-;67676:10;;-1:-1:-1;;;;;67676:10:0;67662;:24;;:54;;;67704:12;:10;:12::i;:::-;-1:-1:-1;;;;;67690:26:0;:10;-1:-1:-1;;;;;67690:26:0;;67662:54;67654:78;;;;-1:-1:-1;;;67654:78:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;71465:21:0;::::1;71457:30;;;::::0;::::1;;71498:6;:16:::0;;-1:-1:-1;;;;;;71498:16:0::1;-1:-1:-1::0;;;;;71498:16:0;::::1;;::::0;;71530:22:::1;::::0;::::1;::::0;::::1;::::0;71498:16;;71530:22:::1;:::i;75058:171::-:0;67676:10;;-1:-1:-1;;;;;67676:10:0;67662;:24;;:54;;;67704:12;:10;:12::i;:::-;-1:-1:-1;;;;;67690:26:0;:10;-1:-1:-1;;;;;67690:26:0;;67662:54;67654:78;;;;-1:-1:-1;;;67654:78:0;;;;;;;:::i;:::-;75147:26:::1;:11;75161:12:::0;;75147:26:::1;:::i;:::-;;75189:32;75208:12;;75189:32;;;;;;;:::i;:::-;;;;;;;;75058:171:::0;;:::o;116557:29::-;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;116557:29:0;;-1:-1:-1;116557:29:0;:::o;115923:22::-;;;;:::o;67308:27::-;;;;:::o;66013:94::-;66071:7;66013:94;:::o;73854:169::-;67676:10;;-1:-1:-1;;;;;67676:10:0;67662;:24;;:54;;;67704:12;:10;:12::i;:::-;-1:-1:-1;;;;;67690:26:0;:10;-1:-1:-1;;;;;67690:26:0;;67662:54;67654:78;;;;-1:-1:-1;;;67654:78:0;;;;;;;:::i;:::-;73937:12:::1;:28:::0;;;73981:34:::1;::::0;::::1;::::0;::::1;::::0;73952:13;;73981:34:::1;:::i;66971:29::-:0;;;;:::o;66175:22::-;;;-1:-1:-1;;;;;66175:22:0;;:::o;115792:20::-;;;-1:-1:-1;;;;;115792:20:0;;:::o;70274:123::-;68648:5;;;;;;;;;-1:-1:-1;;;;;68648:5:0;-1:-1:-1;;;;;68648:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;68634:32:0;:10;-1:-1:-1;;;;;68634:32:0;;:62;;;;68684:12;:10;:12::i;:::-;-1:-1:-1;;;;;68670:26:0;:10;-1:-1:-1;;;;;68670:26:0;;68634:62;68626:86;;;;-1:-1:-1;;;68626:86:0;;;;;;;:::i;:::-;70359:13:::1;:30:::0;;-1:-1:-1;;70359:30:0::1;::::0;::::1;;::::0;;;::::1;::::0;;70274:123::o;66204:21::-;;;-1:-1:-1;;;;;66204:21:0;;:::o;64295:26::-;;;;;;-1:-1:-1;;;;;64295:26:0;;:::o;122013:110::-;122086:4;;:29;;-1:-1:-1;;;122086:29:0;;122059:7;;-1:-1:-1;;;;;122086:4:0;;:14;;:29;;122109:4;;122086:29;;;:::i;70630:202::-;67676:10;;-1:-1:-1;;;;;67676:10:0;67662;:24;;:54;;;67704:12;:10;:12::i;:::-;-1:-1:-1;;;;;67690:26:0;:10;-1:-1:-1;;;;;67690:26:0;;67662:54;67654:78;;;;-1:-1:-1;;;67654:78:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;70717:25:0;::::1;70709:34;;;::::0;::::1;;70754:10;:24:::0;;-1:-1:-1;;;;;;70754:24:0::1;-1:-1:-1::0;;;;;70754:24:0;::::1;;::::0;;70794:30:::1;::::0;::::1;::::0;::::1;::::0;70754:24;;70794:30:::1;:::i;90669:281::-:0;90758:5;;-1:-1:-1;;;;;90758:5:0;90736:10;:28;90728:37;;;;;;90822:5;;90784:34;;;-1:-1:-1;;;90784:34:0;;;;-1:-1:-1;;;;;90822:5:0;;;;90784:32;;;;;:34;;;;;;;;;;;;;;:32;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;90784:43:0;;90776:52;;;;;;90839:30;90856:12;90839:16;:30::i;:::-;90912:4;;:29;;-1:-1:-1;;;90912:29:0;;90880:62;;90898:12;;-1:-1:-1;;;;;90912:4:0;;;;:14;;:29;;90935:4;;90912:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;90880:4;;-1:-1:-1;;;;;90880:4:0;;:62;:17;:62::i;:::-;90669:281;:::o;115874:40::-;;;-1:-1:-1;;;;;115874:40:0;;:::o;71849:263::-;68078:10;;-1:-1:-1;;;;;68078:10:0;68064;:24;68056:48;;;;-1:-1:-1;;;68056:48:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;71930:22:0;::::1;71922:31;;;::::0;::::1;;71964:5;::::0;71978:7:::1;::::0;;71964:25:::1;::::0;-1:-1:-1;;;71964:25:0;;-1:-1:-1;;;;;71964:5:0;;::::1;::::0;:13:::1;::::0;:25:::1;::::0;71978:7;;::::1;::::0;71964:5:::1;::::0;:25:::1;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;72000:7:0::1;:18:::0;;-1:-1:-1;;;;;;72000:18:0::1;-1:-1:-1::0;;;;;72000:18:0;;::::1;::::0;;;::::1;::::0;;;72029:5:::1;::::0;:35:::1;::::0;-1:-1:-1;;;72029:35:0;;:5;;::::1;::::0;:13:::1;::::0;:35:::1;::::0;72043:7:::1;::::0;-1:-1:-1;;72060:2:0;72029:35:::1;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;72080:24;72095:8;72080:24;;;;;;:::i;121087:517::-:0;121277:23;;121200:4;;121277:23;;121273:67;;;-1:-1:-1;121324:4:0;121317:11;;121273:67;121491:10;:8;:10::i;:::-;121486:56;;-1:-1:-1;121525:5:0;121518:12;;121486:56;121561:35;121582:13;121561:20;:35::i;:::-;121554:42;121087:517;-1:-1:-1;;121087:517:0:o;122131:133::-;122193:7;122220:36;122240:15;:13;:15::i;:::-;122220;:13;:15::i;:::-;:19;;:36::i;73300:154::-;67676:10;;-1:-1:-1;;;;;67676:10:0;67662;:24;;:54;;;67704:12;:10;:12::i;:::-;-1:-1:-1;;;;;67690:26:0;:10;-1:-1:-1;;;;;67690:26:0;;67662:54;67654:78;;;;-1:-1:-1;;;67654:78:0;;;;;;;:::i;:::-;73378:14:::1;:23:::0;;;73417:29:::1;::::0;::::1;::::0;::::1;::::0;73395:6;;73417:29:::1;:::i;116013:48::-:0;116056:5;116013:48;:::o;66115:21::-;;;-1:-1:-1;;;;;66115:21:0;;:::o;91379:173::-;67842:10;;-1:-1:-1;;;;;67842:10:0;67828;:24;;:54;;;67870:12;:10;:12::i;:::-;-1:-1:-1;;;;;67856:26:0;:10;-1:-1:-1;;;;;67856:26:0;;67828:54;:88;;;;67900:5;;;;;;;;;-1:-1:-1;;;;;67900:5:0;-1:-1:-1;;;;;67900:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;67886:30:0;:10;-1:-1:-1;;;;;67886:30:0;;67828:88;:124;;;;67934:5;;;;;;;;;-1:-1:-1;;;;;67934:5:0;-1:-1:-1;;;;;67934:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;67920:32:0;:10;-1:-1:-1;;;;;67920:32:0;;67828:124;67806:185;;;;-1:-1:-1;;;67806:185:0;;;;;;;:::i;:::-;91451:13:::1;:20:::0;;-1:-1:-1;;91451:20:0::1;91467:4;91451:20;::::0;;91482:5:::1;::::0;:22:::1;::::0;;-1:-1:-1;;;91482:22:0;;;;-1:-1:-1;;;;;91482:5:0;;::::1;::::0;:20:::1;::::0;:22:::1;::::0;;::::1;::::0;91451:13:::1;::::0;91482:22;;;;;;;;91451:13;91482:5;:22;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;91522:22:0::1;::::0;::::1;::::0;-1:-1:-1;91522:22:0;;-1:-1:-1;91522:22:0::1;91379:173::o:0;117960:1062::-;118178:10;;118138:19;;118178:10;;;;;118170:29;;;;-1:-1:-1;;;118170:29:0;;;;;;;:::i;:::-;118350:4;118344:11;-1:-1:-1;;;118369:135:0;;118249:4;118233:22;;118541:4;118525:21;;118518:43;;;-1:-1:-1;;;118616:4:0;118600:21;;118575:146;118233:22;118772:4;118344:11;118210:20;118750:27;118800:177;;-1:-1:-1;;;118800:177:0;;118735:42;;-1:-1:-1;;;;;;118800:48:0;;;-1:-1:-1;118800:48:0;;:177;;118863:6;;118884:11;;118910:8;;118933:7;;118955:11;;118800:177;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;118995:19:0;;-1:-1:-1;;;;;118995:19:0;;;-1:-1:-1;118995:19:0;;-1:-1:-1;118995:19:0;;;117960:1062;;;;;;;;:::o;32178:622::-;32548:10;;;32547:62;;-1:-1:-1;32564:39:0;;-1:-1:-1;;;32564:39:0;;-1:-1:-1;;;;;32564:15:0;;;;;:39;;32588:4;;32595:7;;32564:39;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;32547:62;32539:152;;;;-1:-1:-1;;;32539:152:0;;;;;;;:::i;:::-;32702:90;32722:5;32752:22;;;32776:7;32785:5;32729:62;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;32729:62:0;;;;;;;;;;;;;;-1:-1:-1;;;;;32729:62:0;-1:-1:-1;;;;;;32729:62:0;;;;;;;;;;32702:19;:90::i;:::-;32178:622;;;:::o;3920:196::-;4023:12;4055:53;4078:6;4086:4;4092:1;4095:12;4055:22;:53::i;:::-;4048:60;3920:196;-1:-1:-1;;;;3920:196:0:o;75383:98::-;75455:5;;:18;;;-1:-1:-1;;;75455:18:0;;;;75428:7;;-1:-1:-1;;;;;75455:5:0;;:16;;:18;;;;;;;;;;;;;;:5;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;126916:120::-;127011:16;126916:120;:::o;31519:177::-;31602:86;31622:5;31652:23;;;31677:2;31681:5;31629:58;;;;;;;;;:::i;69413:727::-;69585:4;;-1:-1:-1;;;;;69585:4:0;69577:27;69569:68;;;;-1:-1:-1;;;69569:68:0;;;;;;;:::i;:::-;69650:5;:24;;-1:-1:-1;;;;;;69650:24:0;-1:-1:-1;;;;;69650:24:0;;;;;;;;;;;69699:13;;;-1:-1:-1;;;69699:13:0;;;;:5;;;;;:11;;:13;;;;;;;;;;;;;;;:5;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;69685:4;:28;;-1:-1:-1;;;;;;69685:28:0;-1:-1:-1;;;;;69685:28:0;;;;;;;;69724:37;;:4;69741:6;-1:-1:-1;;69724:16:0;:37::i;:::-;69820:10;:24;;-1:-1:-1;;;;;69820:24:0;;;-1:-1:-1;;;;;;69820:24:0;;;;;;;69855:7;:18;;;;;;;;;;;;69884:6;:16;;;;;;;;;;;;;;69820:10;69946:14;:18;;;69992:5;69975:14;:22;70023:3;70008:12;:18;70037:13;:17;70067:5;;:35;;-1:-1:-1;;;70067:35:0;;:5;;;;:13;;:35;;70081:7;;;-1:-1:-1;;;70067:35:0;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;117265:687::-;117335:10;:52;;-1:-1:-1;;;;;117335:52:0;;;;;-1:-1:-1;;;;;;117335:52:0;;;;;;;;;;117400:4;;:57;;:4;117375:11;-1:-1:-1;;117400:16:0;:57::i;:::-;117521:4;;117478:49;;-1:-1:-1;;;117478:49:0;;116382:42;;117478:34;;:49;;-1:-1:-1;;;;;117521:4:0;;117478:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;117470:5;:57;;-1:-1:-1;;;;;;117470:57:0;-1:-1:-1;;;;;117470:57:0;;;;;;;;117548:4;117538:7;:14;117594:28;;;-1:-1:-1;;;117594:28:0;;;;-1:-1:-1;;117601:5:0;;;;;117594:26;;:28;;;;;;;;;;;;;;;117601:5;117594:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;117565:57;;117738:9;117733:125;117757:18;117753:1;:22;117733:125;;;117822:5;;117815:30;;-1:-1:-1;;;117815:30:0;;117797:12;;-1:-1:-1;;;;;117822:5:0;;117815:27;;:30;;117843:1;;117815:30;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;117797:49;;;;;;;;-1:-1:-1;117797:49:0;;;;;;;;;;-1:-1:-1;;;;;;117797:49:0;-1:-1:-1;;;;;117797:49:0;;;;;;;;;;117777:3;117733:125;;;-1:-1:-1;;117868:11:0;:56;;-1:-1:-1;;;;;;117868:56:0;;;;;-1:-1:-1;117265:687:0:o;123846:975::-;123950:25;123977:13;124008:20;124031:15;:13;:15::i;:::-;124008:38;;124077:12;124061:13;:28;124057:757;;;124181:22;124206:15;:13;:15::i;:::-;124181:40;-1:-1:-1;124240:18:0;;124236:241;;124279:10;;124321:5;;124357:4;;-1:-1:-1;;;;;124279:10:0;;;;;;;:19;;124321:5;;;124357:4;124385:57;124394:14;124410:31;:13;124428:12;124410:17;:31::i;:::-;124385:8;:57::i;:::-;124279:182;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;124236:241;124491:25;124519:15;:13;:15::i;:::-;124491:43;;124569:42;124578:13;124593:17;124569:8;:42::i;:::-;124549:62;-1:-1:-1;124634:36:0;:13;124549:62;124634:17;:36::i;:::-;124626:44;;124057:757;;;;;124785:13;124800:1;124777:25;;;;;;;124057:757;123846:975;;;;;:::o;122872:966::-;122961:12;:19;:23;122957:86;;123001:10;;123025:5;;123001:30;;-1:-1:-1;;;123001:30:0;;-1:-1:-1;;;;;123001:10:0;;;;;;;:23;;:30;;123025:5;;;123001:30;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;122957:86;123079:22;123104:15;:13;:15::i;:::-;123079:40;-1:-1:-1;123134:18:0;;123130:701;;123204:28;;-1:-1:-1;;;123204:28:0;;123169:32;;116137:42;;123204:13;;:28;;123226:4;;123204:28;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;123247:10;;123267:5;;123247:26;;-1:-1:-1;;;123247:26:0;;123169:63;;-1:-1:-1;;;;;;123247:10:0;;;;;;;:19;;:26;;123267:5;;123247:26;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;123327:28:0;;-1:-1:-1;;;123327:28:0;;123288:19;;-1:-1:-1;123327:58:0;;-1:-1:-1;123360:24:0;;116137:42;;123327:13;;:28;;123349:4;;123327:28;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:32;;:58::i;:::-;123288:97;-1:-1:-1;123406:15:0;;123402:418;;123442:20;123486:46;116056:5;123486:24;123502:7;;123486:11;:15;;:24;;;;:::i;:::-;:28;;:46::i;:::-;123442:90;-1:-1:-1;123557:16:0;;123553:252;;123623:10;;123598:51;;116137:42;;123623:10;;;-1:-1:-1;;;;;123623:10:0;123636:12;123598:16;:51::i;:::-;123754:10;;;;;;;;;-1:-1:-1;;;;;123754:10:0;-1:-1:-1;;;;;123754:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;123553:252;123402:418;123130:701;;122872:966;:::o;122401:463::-;122484:13;;;;122480:52;;;122514:7;;122480:52;122633:17;122653:15;:13;:15::i;:::-;122633:35;-1:-1:-1;122683:13:0;;122679:150;;122739:10;;122713:4;;:49;;-1:-1:-1;;;;;122713:4:0;;;;122739:10;;;;;122752:9;122713:17;:49::i;:::-;122777:10;;122796:5;;122811:4;;122777:40;;-1:-1:-1;;;122777:40:0;;-1:-1:-1;;;;;122777:10:0;;;;;;;:18;;:40;;122796:5;;;;122811:4;;;122777:40;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;122679:150;122841:15;:13;:15::i;124867:325::-;124927:7;124947:22;124972:15;:13;:15::i;:::-;124947:40;-1:-1:-1;125002:18:0;;124998:154;;125083:10;;125103:5;;125118:4;;125083:57;;-1:-1:-1;;;125083:57:0;;-1:-1:-1;;;;;125083:10:0;;;;;;;:19;;:57;;125103:5;;;;125118:4;;;125125:14;;125083:57;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;124998:154;125169:15;:13;:15::i;:::-;125162:22;;;124867:325;:::o;16006:136::-;16064:7;16091:43;16095:1;16098;16091:43;;;;;;;;;;;;;;;;;:3;:43::i;:::-;16084:50;16006:136;-1:-1:-1;;;16006:136:0:o;125200:1457::-;125443:5;;:31;;-1:-1:-1;;;125443:31:0;;125317:15;;;;;;;;-1:-1:-1;;;;;125443:5:0;;;;:16;;:31;;125468:4;;125443:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;;125423:61;;125495:30;125528:22;:20;:22::i;:::-;125495:55;;125598:9;125573:22;:34;:104;;125676:1;125573:104;;;125623:37;:22;125650:9;125623:26;:37::i;:::-;125563:114;-1:-1:-1;125690:20:0;;125744:29;:16;125563:114;125744:20;:29::i;:::-;125721:52;-1:-1:-1;125788:16:0;;125784:104;;125845:31;125863:12;125845:17;:31::i;:::-;125821:55;-1:-1:-1;125821:55:0;-1:-1:-1;125784:104:0;125915:40;125924:16;125942:12;125915:8;:40::i;:::-;125900:55;;125980:7;125972:5;:15;125968:568;;;126195:18;:5;126205:7;126195:9;:18::i;:::-;126187:26;;126238:1;126228:11;;125968:568;;;126482:18;:7;126494:5;126482:11;:18::i;:::-;126472:28;;126523:1;126515:9;;125968:568;-1:-1:-1;;126618:23:0;:31;;-1:-1:-1;;126618:31:0;;;-1:-1:-1;125200:1457:0;;;;-1:-1:-1;125200:1457:0;-1:-1:-1;125200:1457:0:o;121612:277::-;121690:12;;121674:32;;116137:42;;-1:-1:-1;;;;;121690:12:0;;121674:15;:32::i;:::-;121722:9;121717:129;121741:12;:19;121737:23;;121717:129;;;121818:12;;121789;:15;;121782:52;;-1:-1:-1;;;;;121818:12:0;;;;121802:1;;121789:15;;;;;;;;;;;;;;;;-1:-1:-1;;;;;121789:15:0;;121782:52;:35;:52::i;:::-;121762:3;;121717:129;;;-1:-1:-1;121856:12:0;:25;;-1:-1:-1;;;;;;121856:25:0;;;121612:277::o;126665:243::-;126742:22;126767:15;:13;:15::i;:::-;126742:40;-1:-1:-1;126797:18:0;;126793:108;;126832:10;;126852:5;;126867:4;;126832:57;;-1:-1:-1;;;126832:57:0;;-1:-1:-1;;;;;126832:10:0;;;;;;;:19;;:57;;126852:5;;;;126867:4;;;126874:14;;126832:57;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;85016:1736::-;85092:4;85109:16;85128:24;85138:13;85128:9;:24::i;:::-;85109:43;;85163:28;;:::i;:::-;85194:5;;:31;;-1:-1:-1;;;85194:31:0;;-1:-1:-1;;;;;85194:5:0;;;;:16;;:31;;85219:4;;85194:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;85163:62;;85302:6;:17;;;85323:1;85302:22;85298:40;;;85333:5;85326:12;;;;;;85298:40;85483:14;;85462:17;;;;85442:38;;:15;;:19;:38::i;:::-;:55;85438:73;;;85506:5;85499:12;;;;;;85438:73;85630:14;;85608:17;;;;85588:38;;:15;;:19;:38::i;:::-;:56;85584:73;;85653:4;85646:11;;;;;;85584:73;86087:5;;:23;;;-1:-1:-1;;;86087:23:0;;;;86065:19;;-1:-1:-1;;;;;86087:5:0;;:21;;:23;;;;;;;;;;;;;;:5;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;86065:45;;86139:13;;86125:11;:27;86121:44;;;86161:4;86154:11;;;;;;;86121:44;86219:13;86235:22;:20;:22::i;:::-;86219:38;;86347:6;:16;;;86320:24;86330:13;;86320:5;:9;;:24;;;;:::i;:::-;:43;86316:60;;;86372:4;86365:11;;;;;;;;86316:60;86389:14;86430:6;:16;;;86422:5;:24;86418:66;;;86467:16;;;;86457:27;;:5;;:9;:27::i;:::-;86448:36;;86418:66;86654:5;;:23;;;-1:-1:-1;;;86654:23:0;;;;86637:14;;-1:-1:-1;;;;;86654:5:0;;:21;;:23;;;;;;;;;;;;;;:5;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;86637:40;-1:-1:-1;86725:18:0;86637:40;86736:6;86725:10;:18::i;:::-;86696:12;;:26;;86713:8;86696:16;:26::i;:::-;:47;;85016:1736;-1:-1:-1;;;;;;;;85016:1736:0:o;15542:181::-;15600:7;15632:5;;;15656:6;;;;15648:46;;;;-1:-1:-1;;;15648:46:0;;;;;;;:::i;33824:761::-;34248:23;34274:69;34302:4;34274:69;;;;;;;;;;;;;;;;;34282:5;-1:-1:-1;;;;;34274:27:0;;;:69;;;;;:::i;:::-;34358:17;;34248:95;;-1:-1:-1;34358:21:0;34354:224;;34500:10;34489:30;;;;;;;;;;;;:::i;:::-;34481:85;;;;-1:-1:-1;;;34481:85:0;;;;;;;:::i;5297:979::-;5427:12;5460:18;5471:6;5460:10;:18::i;:::-;5452:60;;;;-1:-1:-1;;;5452:60:0;;;;;;;:::i;:::-;5586:12;5600:23;5627:6;-1:-1:-1;;;;;5627:11:0;5647:8;5658:4;5627:36;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5585:78;;;;5678:7;5674:595;;;5709:10;-1:-1:-1;5702:17:0;;-1:-1:-1;5702:17:0;5674:595;5823:17;;:21;5819:439;;6086:10;6080:17;6147:15;6134:10;6130:2;6126:19;6119:44;6034:148;6229:12;6222:20;;-1:-1:-1;;;6222:20:0;;;;;;;;:::i;11623:106::-;11681:7;11712:1;11708;:5;:13;;11720:1;11708:13;;;-1:-1:-1;11716:1:0;;11623:106;-1:-1:-1;11623:106:0:o;16896:471::-;16954:7;17199:6;17195:47;;-1:-1:-1;17229:1:0;17222:8;;17195:47;17266:5;;;17270:1;17266;:5;:1;17290:5;;;;;:10;17282:56;;;;-1:-1:-1;;;17282:56:0;;;;;;;:::i;17843:132::-;17901:7;17928:39;17932:1;17935;17928:39;;;;;;;;;;;;;;;;;:3;:39::i;16445:192::-;16531:7;16567:12;16559:6;;;;16551:29;;;;-1:-1:-1;;;16551:29:0;;;;;;;;:::i;:::-;-1:-1:-1;;;16603:5:0;;;16445:192::o;805:619::-;865:4;1333:20;;1176:66;1373:23;;;;;;:42;;-1:-1:-1;;1400:15:0;;;1365:51;-1:-1:-1;;805:619:0:o;18471:278::-;18557:7;18592:12;18585:5;18577:28;;;;-1:-1:-1;;;18577:28:0;;;;;;;;:::i;:::-;;18616:9;18632:1;18628;:5;;;;;;;18471:278;-1:-1:-1;;;;;18471:278:0:o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;3521:241;;3625:2;3613:9;3604:7;3600:23;3596:32;3593:2;;;-1:-1;;3631:12;3593:2;85:6;72:20;97:33;124:5;97:33;:::i;3769:263::-;;3884:2;3872:9;3863:7;3859:23;3855:32;3852:2;;;-1:-1;;3890:12;3852:2;226:6;220:13;238:33;265:5;238:33;:::i;4039:743::-;;;;;;4211:3;4199:9;4190:7;4186:23;4182:33;4179:2;;;-1:-1;;4218:12;4179:2;85:6;72:20;97:33;124:5;97:33;:::i;:::-;4270:63;-1:-1;4370:2;4409:22;;72:20;97:33;72:20;97:33;:::i;:::-;4378:63;-1:-1;4478:2;4517:22;;72:20;97:33;72:20;97:33;:::i;:::-;4486:63;-1:-1;4586:2;4625:22;;72:20;97:33;72:20;97:33;:::i;:::-;4594:63;-1:-1;4694:3;4734:22;;72:20;97:33;72:20;97:33;:::i;:::-;4703:63;;;;4173:609;;;;;;;;:::o;4789:235::-;;4890:2;4878:9;4869:7;4865:23;4861:32;4858:2;;;-1:-1;;4896:12;4858:2;360:6;347:20;372:30;396:5;372:30;:::i;5031:257::-;;5143:2;5131:9;5122:7;5118:23;5114:32;5111:2;;;-1:-1;;5149:12;5111:2;495:6;489:13;507:30;531:5;507:30;:::i;5599:367::-;;;5723:2;5711:9;5702:7;5698:23;5694:32;5691:2;;;-1:-1;;5729:12;5691:2;5787:17;5774:31;5825:18;;5817:6;5814:30;5811:2;;;-1:-1;;5847:12;5811:2;5933:6;5922:9;5918:22;;;854:3;847:4;839:6;835:17;831:27;821:2;;-1:-1;;862:12;821:2;905:6;892:20;5825:18;924:6;921:30;918:2;;;-1:-1;;954:12;918:2;1049:3;5723:2;1029:17;990:6;1015:32;;1012:41;1009:2;;;-1:-1;;1056:12;1009:2;5723;986:17;;;;;5867:83;;-1:-1;5685:281;;-1:-1;;;;5685:281::o;5973:362::-;;6098:2;6086:9;6077:7;6073:23;6069:32;6066:2;;;-1:-1;;6104:12;6066:2;6155:17;6149:24;6193:18;;6185:6;6182:30;6179:2;;;-1:-1;;6215:12;6179:2;6302:6;6291:9;6287:22;;;1198:3;1191:4;1183:6;1179:17;1175:27;1165:2;;-1:-1;;1206:12;1165:2;1246:6;1240:13;6193:18;27865:6;27862:30;27859:2;;;-1:-1;;27895:12;27859:2;1268:65;27968:9;27949:17;;-1:-1;;27945:33;6098:2;28026:15;1268:65;:::i;:::-;1259:74;;1353:6;1346:5;1339:21;1457:3;6098:2;1448:6;1381;1439:16;;1436:25;1433:2;;;-1:-1;;1464:12;1433:2;1484:39;1516:6;6098:2;1415:5;1411:16;6098:2;1381:6;1377:17;1484:39;:::i;:::-;-1:-1;6235:84;6060:275;-1:-1;;;;6060:275::o;6342:328::-;;6489:3;;6477:9;6468:7;6464:23;6460:33;6457:2;;;-1:-1;;6496:12;6457:2;1735:22;6489:3;1735:22;:::i;:::-;1726:31;;1881:22;3458:13;1831:16;1824:86;1977:2;2046:9;2042:22;3458:13;1977:2;1996:5;1992:16;1985:86;2137:2;2206:9;2202:22;3458:13;2137:2;2156:5;2152:16;2145:86;2305:2;2374:9;2370:22;3458:13;2305:2;2324:5;2320:16;2313:86;2473:3;2543:9;2539:22;3458:13;2473:3;2493:5;2489:16;2482:86;2635:3;2705:9;2701:22;3458:13;2635:3;2655:5;2651:16;2644:86;2796:3;2866:9;2862:22;3458:13;2796:3;2816:5;2812:16;2805:86;2957:3;3027:9;3023:22;3458:13;2957:3;2977:5;2973:16;2966:86;3118:3;;3190:9;3186:22;3458:13;3118:3;3138:5;3134:18;3127:88;;6548:106;;;;6451:219;;;;:::o;6677:241::-;;6781:2;6769:9;6760:7;6756:23;6752:32;6749:2;;;-1:-1;;6787:12;6749:2;-1:-1;3310:20;;6743:175;-1:-1;6743:175::o;6925:263::-;;7040:2;7028:9;7019:7;7015:23;7011:32;7008:2;;;-1:-1;;7046:12;7008:2;-1:-1;3458:13;;7002:186;-1:-1;7002:186::o;14718:271::-;;7586:5;28145:12;7697:52;7742:6;7737:3;7730:4;7723:5;7719:16;7697:52;:::i;:::-;7761:16;;;;;14852:137;-1:-1;;14852:137::o;14996:542::-;;-1:-1;;;11097:11;11090:39;7586:5;28145:12;7697:52;7742:6;11074:2;11152:3;11148:12;7730:4;7723:5;7719:16;7697:52;:::i;:::-;7761:16;;;;11074:2;7761:16;;15233:305;-1:-1;;15233:305::o;15545:222::-;-1:-1;;;;;29161:54;;;;7266:37;;15672:2;15657:18;;15643:124::o;15774:333::-;-1:-1;;;;;29161:54;;;7266:37;;29161:54;;16093:2;16078:18;;7266:37;15929:2;15914:18;;15900:207::o;16114:668::-;-1:-1;;;;;29161:54;;;7266:37;;29161:54;;;16518:2;16503:18;;7266:37;29161:54;;;16601:2;16586:18;;7266:37;29161:54;;16684:2;16669:18;;7266:37;29161:54;;;16767:3;16752:19;;7266:37;16353:3;16338:19;;16324:458::o;16789:444::-;-1:-1;;;;;29161:54;;;7266:37;;29161:54;;;;17136:2;17121:18;;7266:37;17219:2;17204:18;;14669:37;;;;16972:2;16957:18;;16943:290::o;17240:349::-;-1:-1;;;;;29161:54;;;;7266:37;;17575:2;17560:18;;8399:58;17403:2;17388:18;;17374:215::o;17936:210::-;28958:13;;28951:21;7380:34;;18057:2;18042:18;;18028:118::o;18972:330::-;;19129:2;19150:17;19143:47;28584:6;19129:2;19118:9;19114:18;28572:19;30438:6;30433:3;28612:14;19118:9;28612:14;30415:30;30476:16;;;28612:14;30476:16;;;30469:27;;;;27968:9;30855:14;;;-1:-1;;30851:28;8749:39;;;19100:202;-1:-1;19100:202::o;19309:310::-;;19456:2;19477:17;19470:47;8947:5;28145:12;28584:6;19456:2;19445:9;19441:18;28572:19;9041:52;9086:6;28612:14;19445:9;28612:14;19456:2;9067:5;9063:16;9041:52;:::i;:::-;27968:9;30855:14;-1:-1;;30851:28;9105:39;;;;28612:14;9105:39;;19427:192;-1:-1;;19427:192::o;19626:416::-;19826:2;19840:47;;;9748:2;19811:18;;;28572:19;-1:-1;;;28612:14;;;9764:34;9817:12;;;19797:245::o;20049:416::-;20249:2;20263:47;;;10068:1;20234:18;;;28572:19;-1:-1;;;28612:14;;;10083:28;10130:12;;;20220:245::o;20472:416::-;20672:2;20686:47;;;10381:2;20657:18;;;28572:19;10417:29;28612:14;;;10397:50;10466:12;;;20643:245::o;20895:416::-;21095:2;21109:47;;;10717:2;21080:18;;;28572:19;-1:-1;;;28612:14;;;10733:35;10787:12;;;21066:245::o;21318:416::-;21518:2;21532:47;;;11399:2;21503:18;;;28572:19;11435:30;28612:14;;;11415:51;11485:12;;;21489:245::o;21741:416::-;21941:2;21955:47;;;11736:2;21926:18;;;28572:19;11772:34;28612:14;;;11752:55;-1:-1;;;11827:12;;;11820:25;11864:12;;;21912:245::o;22164:416::-;22364:2;22378:47;;;12115:1;22349:18;;;28572:19;-1:-1;;;28612:14;;;12130:29;12178:12;;;22335:245::o;22587:416::-;22787:2;22801:47;;;12429:1;22772:18;;;28572:19;-1:-1;;;28612:14;;;12444:30;12493:12;;;22758:245::o;23010:416::-;23210:2;23224:47;;;12744:1;23195:18;;;28572:19;-1:-1;;;28612:14;;;12759:29;12807:12;;;23181:245::o;23433:416::-;23633:2;23647:47;;;13058:2;23618:18;;;28572:19;13094:31;28612:14;;;13074:52;13145:12;;;23604:245::o;23856:416::-;24056:2;24070:47;;;13396:2;24041:18;;;28572:19;-1:-1;;;28612:14;;;13412:34;13465:12;;;24027:245::o;24279:416::-;24479:2;24493:47;;;13716:2;24464:18;;;28572:19;13752:34;28612:14;;;13732:55;-1:-1;;;13807:12;;;13800:34;13853:12;;;24450:245::o;24702:416::-;24902:2;24916:47;;;14104:2;24887:18;;;28572:19;-1:-1;;;28612:14;;;14120:33;14172:12;;;24873:245::o;25125:416::-;25325:2;25339:47;;;14423:2;25310:18;;;28572:19;14459:34;28612:14;;;14439:55;-1:-1;;;14514:12;;;14507:46;14572:12;;;25296:245::o;25548:222::-;14669:37;;;25675:2;25660:18;;25646:124::o;25777:444::-;14669:37;;;26124:2;26109:18;;14669:37;;;;26207:2;26192:18;;14669:37;25960:2;25945:18;;25931:290::o;26228:556::-;14669:37;;;26604:2;26589:18;;14669:37;;;;26687:2;26672:18;;14669:37;26770:2;26755:18;;14669:37;26439:3;26424:19;;26410:374::o;26791:668::-;14669:37;;;27195:2;27180:18;;14669:37;;;;27278:2;27263:18;;14669:37;;;;27361:2;27346:18;;14669:37;27444:3;27429:19;;14669:37;27030:3;27015:19;;27001:458::o;27466:256::-;27528:2;27522:9;27554:17;;;27629:18;27614:34;;27650:22;;;27611:62;27608:2;;;27686:1;;27676:12;27608:2;27528;27695:22;27506:216;;-1:-1;27506:216::o;30511:268::-;30576:1;30583:101;30597:6;30594:1;30591:13;30583:101;;;30664:11;;;30658:18;30645:11;;;30638:39;30619:2;30612:10;30583:101;;;30699:6;30696:1;30693:13;30690:2;;;-1:-1;;30576:1;30746:16;;30739:27;30560:219::o;30892:117::-;-1:-1;;;;;29161:54;;30951:35;;30941:2;;31000:1;;30990:12;31016:111;31097:5;28958:13;28951:21;31075:5;31072:32;31062:2;;31118:1;;31108:12

Swarm Source

ipfs://21c2dcc2013f1034d7e422e7a76a7c23314dd1d7026623fe02a62f3a8639a9c4
Loading...
Loading
Loading...
Loading
[ 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.