Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
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
Loading...
Loading
Cross-Chain Transactions
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
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_voterProxy","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"}],"name":"Cloned","type":"event"},{"anonymous":false,"inputs":[],"name":"EmergencyExitEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loss","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtPayment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtOutstanding","type":"uint256"}],"name":"Harvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"debtThreshold","type":"uint256"}],"name":"UpdatedDebtThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newKeeper","type":"address"}],"name":"UpdatedKeeper","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"UpdatedMaxReportDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"metadataURI","type":"string"}],"name":"UpdatedMetadataURI","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"UpdatedMinReportDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"profitFactor","type":"uint256"}],"name":"UpdatedProfitFactor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rewards","type":"address"}],"name":"UpdatedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newStrategist","type":"address"}],"name":"UpdatedStrategist","type":"event"},{"inputs":[],"name":"BIPS_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"apiVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"balanceOfWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_strategist","type":"address"},{"internalType":"address","name":"_rewards","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_voterProxy","type":"address"}],"name":"clone","outputs":[{"internalType":"address","name":"newStrategy","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"debtThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegatedAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"doHealthCheck","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyExit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"estimatedTotalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ethAmount","type":"uint256"}],"name":"ethToWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gauge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCostinEth","type":"uint256"}],"name":"harvestTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"healthCheck","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_strategist","type":"address"},{"internalType":"address","name":"_rewards","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_voterProxy","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOriginal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keepBAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxReportDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newStrategy","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minReportDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"profitFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"removeTradeFactoryPermissions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewardTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debtThreshold","type":"uint256"}],"name":"setDebtThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_doHealthCheck","type":"bool"}],"name":"setDoHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setEmergencyExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_forceHarvestTriggerOnce","type":"bool"}],"name":"setForceHarvestTriggerOnce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_healthCheck","type":"address"}],"name":"setHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_keepBAL","type":"uint256"}],"name":"setKeepBAL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"setKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setMaxReportDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_metadataURI","type":"string"}],"name":"setMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setMinReportDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_profitFactor","type":"uint256"}],"name":"setProfitFactor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewards","type":"address"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategist","type":"address"}],"name":"setStrategist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tradeFactory","type":"address"}],"name":"setTradeFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_voterProxy","type":"address"}],"name":"setVoterProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stakedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategist","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCostInWei","type":"uint256"}],"name":"tendTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tradeFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract VaultAPI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voterProxy","outputs":[{"internalType":"contract BalancerStrategyVoterProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"want","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountNeeded","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"_loss","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]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
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.