Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
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 Name:
StrategyBalancerClonable
Compiler Version
v0.6.12+commit.27d51765
Contract Source Code (Solidity)
/** *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
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}]
Contract Creation Code
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
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.