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
Latest 2 internal transactions
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x3d602d80 | 15576537 | 1289 days ago | Contract Creation | 0 ETH | |||
| 0x3d602d80 | 15576483 | 1289 days ago | Contract Creation | 0 ETH |
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:
Strategy
Compiler Version
v0.8.12+commit.f00d7308
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2022-09-20
*/
// SPDX-License-Identifier: MIT
pragma experimental ABIEncoderV2;
pragma solidity ^0.8.12;
// OpenZeppelin Contracts v4.4.1 (utils/math/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.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a / b + (a % b == 0 ? 0 : 1);
}
}
// OpenZeppelin Contracts v4.4.1 (token/ERC20/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);
}
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)
// OpenZeppelin Contracts v4.4.1 (utils/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) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
// OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol)
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
// OpenZeppelin Contracts v4.4.1 (utils/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 meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
/**
* @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 Contracts guidelines: functions revert
* instead 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, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the 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 this function is
* overridden;
*
* 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 virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* Requirements:
*
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
uint256 currentAllowance = _allowances[sender][_msgSender()];
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
unchecked {
_approve(sender, _msgSender(), currentAllowance - amount);
}
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] + 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) {
uint256 currentAllowance = _allowances[_msgSender()][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(_msgSender(), spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `sender` to `recipient`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[sender] = senderBalance - amount;
}
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
_afterTokenTransfer(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:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be 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 {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been 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 _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}
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 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);
event SetHealthCheck(address);
event SetDoHealthCheck(bool);
// 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) {
_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, type(uint256).max); // 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, type(uint256).max); // Allow rewards to be pulled
}
function setHealthCheck(address _healthCheck) external onlyVaultManagers {
emit SetHealthCheck(_healthCheck);
healthCheck = _healthCheck;
}
function setDoHealthCheck(bool _doHealthCheck) external onlyVaultManagers {
emit SetDoHealthCheck(_doHealthCheck);
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, type(uint256).max);
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 - params.lastReport < minReportDelay) return false;
// Should trigger if hasn't been called in a while
if (block.timestamp - 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 + debtThreshold < params.totalDebt) return true;
uint256 profit = 0;
if (total > params.totalDebt) profit = total - 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 * callCost < credit + 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 - amountFreed;
} else if (amountFreed > debtOutstanding) {
profit = amountFreed - debtOutstanding;
}
debtPayment = debtOutstanding - 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) 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);
}
}
// OpenZeppelin Contracts v4.4.1 (security/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].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making 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;
}
}
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 Router
* @author yearn.finance
* @notice
* BaseRouter 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 Router.
* A good starting point to build a router is https://github.com/yearn/brownie-router-mix
*
*/
abstract contract BaseRouter {
using Math for uint256;
// Reduce number of external calls (SLOADs stay the same)
mapping(address => 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;
constructor(address _registry) {
// 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 router 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(address token) public view virtual returns (VaultAPI) {
return VaultAPI(registry.latestVault(token));
}
/**
* @notice
* Used to get all vaults from the registery for the token
* @return An array containing instances of VaultAPI
*/
function allVaults(address token) public view virtual returns (VaultAPI[] memory) {
uint256 cache_length = _cachedVaults[token].length;
uint256 num_vaults = registry.numVaults(token);
// Use cached
if (cache_length == num_vaults) {
return _cachedVaults[token];
}
VaultAPI[] memory vaults = new VaultAPI[](num_vaults);
for (uint256 vault_id = 0; vault_id < cache_length; vault_id++) {
vaults[vault_id] = _cachedVaults[token][vault_id];
}
for (uint256 vault_id = cache_length; vault_id < num_vaults; vault_id++) {
vaults[vault_id] = VaultAPI(registry.vaults(token, vault_id));
}
return vaults;
}
function _updateVaultCache(address token, 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[token].length) {
_cachedVaults[token] = vaults;
}
}
/**
* @notice
* Used to get the balance of an account accross all the vaults for a token.
* @dev will be used to get the router 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 token, address account) public view returns (uint256 balance) {
VaultAPI[] memory vaults = allVaults(token);
for (uint256 id = 0; id < vaults.length; id++) {
balance = balance + ((vaults[id].balanceOf(account) * vaults[id].pricePerShare()) / (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(address token) public view returns (uint256 assets) {
VaultAPI[] memory vaults = allVaults(token);
for (uint256 id = 0; id < vaults.length; id++) {
assets = assets + vaults[id].totalAssets();
}
}
function _deposit(
IERC20 token,
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(address(token));
if (pullFunds) {
if (amount == DEPOSIT_EVERYTHING) {
amount = token.balanceOf(depositor);
}
SafeERC20.safeTransferFrom(token, depositor, address(this), amount);
}
if (token.allowance(address(this), address(_bestVault)) < amount) {
SafeERC20.safeApprove(token, address(_bestVault), 0); // Avoid issues with some tokens requiring 0
SafeERC20.safeApprove(token, 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 - 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) SafeERC20.safeTransfer(token, depositor, afterBal);
}
function _withdraw(
IERC20 token,
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(address(token));
VaultAPI[] memory vaults = allVaults(address(token));
_updateVaultCache(address(token), 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 router 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 (amount != WITHDRAW_EVERYTHING) {
// Compute amount to withdraw fully to satisfy the request
uint256 estimatedShares = ((amount - withdrawn) * (10**uint256(vaults[id].decimals()))) / vaults[id].pricePerShare();
// NOTE: Changes every iteration
// 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) {
if (sender != address(this)) vaults[id].transferFrom(sender, address(this), estimatedShares);
withdrawn = withdrawn + vaults[id].withdraw(estimatedShares);
} else {
if (sender != address(this)) vaults[id].transferFrom(sender, address(this), availableShares);
withdrawn = withdrawn + vaults[id].withdraw(availableShares);
}
} else {
if (sender != address(this)) vaults[id].transferFrom(sender, address(this), availableShares);
withdrawn = withdrawn + 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 - amount) > _bestVault.pricePerShare() / 10**_bestVault.decimals())) {
// Don't forget to approve the deposit
if (token.allowance(address(this), address(_bestVault)) < withdrawn - amount) {
SafeERC20.safeApprove(token, address(_bestVault), UNLIMITED_APPROVAL); // Vaults are trusted
}
_bestVault.deposit(withdrawn - amount, sender);
withdrawn = amount;
}
// `receiver` now has `withdrawn` tokens as balance
if (receiver != address(this)) SafeERC20.safeTransfer(token, receiver, withdrawn);
}
}
/**
* @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 is BaseRouter {
using Math for uint256;
IERC20 public token;
uint256 constant MIGRATE_EVERYTHING = type(uint256).max;
// VaultsAPI.depositLimit is unlimited
uint256 constant UNCAPPED_DEPOSITS = type(uint256).max;
constructor(address _token, address _registry) BaseRouter(_registry) {
// Recommended to use a token with a `Registry.latestVault(_token) != address(0)`
token = IERC20(_token);
}
/**
* @notice
* Used to get the most recent vault for the token using the registry.
* @return An instance of a VaultAPI
*/
function bestVault() public view virtual returns (VaultAPI) {
return bestVault(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) {
return allVaults(address(token));
}
/**
* @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) {
return totalVaultBalance(address(token), account);
}
/**
* @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) {
return totalAssets(address(token));
}
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) {
return _deposit(token, depositor, receiver, amount, pullFunds);
}
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) {
return _withdraw(token, sender, receiver, amount, withdrawFromBest);
}
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 - _totalAssets;
if (_amount > _depositLeft) _amount = _depositLeft;
}
if (_amount > 0) {
// NOTE: `false` = don't withdraw from `_bestVault`
uint256 withdrawn = _withdraw(token, 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(token, 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 - migrated) <= maxMigrationLoss);
} // else: nothing to migrate! (not a failure)
}
}
contract yToken is IERC20, BaseWrapper {
mapping(address => mapping(address => uint256)) public override allowance;
constructor(address _token, address _registry) 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] - amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(msg.sender, spender, allowance[msg.sender][spender] + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(msg.sender, spender, allowance[msg.sender][spender] - 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), type(uint256).max, 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) 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
payable(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)
}
}
// Struct to handle all the parameters to manage the fees
// related to a given collateral pool (associated to the stablecoin)
struct MintBurnData {
// Values of the thresholds to compute the minting fees
// depending on HA hedge (scaled by `BASE_PARAMS`)
uint64[] xFeeMint;
// Values of the fees at thresholds (scaled by `BASE_PARAMS`)
uint64[] yFeeMint;
// Values of the thresholds to compute the burning fees
// depending on HA hedge (scaled by `BASE_PARAMS`)
uint64[] xFeeBurn;
// Values of the fees at thresholds (scaled by `BASE_PARAMS`)
uint64[] yFeeBurn;
// Max proportion of collateral from users that can be covered by HAs
// It is exactly the same as the parameter of the same name in `PerpetualManager`, whenever one is updated
// the other changes accordingly
uint64 targetHAHedge;
// Minting fees correction set by the `FeeManager` contract: they are going to be multiplied
// to the value of the fees computed using the hedge curve
// Scaled by `BASE_PARAMS`
uint64 bonusMalusMint;
// Burning fees correction set by the `FeeManager` contract: they are going to be multiplied
// to the value of the fees computed using the hedge curve
// Scaled by `BASE_PARAMS`
uint64 bonusMalusBurn;
// Parameter used to limit the number of stablecoins that can be issued using the concerned collateral
uint256 capOnStableMinted;
}
// Struct to handle all the variables and parameters to handle SLPs in the protocol
// including the fraction of interests they receive or the fees to be distributed to
// them
struct SLPData {
// Last timestamp at which the `sanRate` has been updated for SLPs
uint256 lastBlockUpdated;
// Fees accumulated from previous blocks and to be distributed to SLPs
uint256 lockedInterests;
// Max interests used to update the `sanRate` in a single block
// Should be in collateral token base
uint256 maxInterestsDistributed;
// Amount of fees left aside for SLPs and that will be distributed
// when the protocol is collateralized back again
uint256 feesAside;
// Part of the fees normally going to SLPs that is left aside
// before the protocol is collateralized back again (depends on collateral ratio)
// Updated by keepers and scaled by `BASE_PARAMS`
uint64 slippageFee;
// Portion of the fees from users minting and burning
// that goes to SLPs (the rest goes to surplus)
uint64 feesForSLPs;
// Slippage factor that's applied to SLPs exiting (depends on collateral ratio)
// If `slippage = BASE_PARAMS`, SLPs can get nothing, if `slippage = 0` they get their full claim
// Updated by keepers and scaled by `BASE_PARAMS`
uint64 slippage;
// Portion of the interests from lending
// that goes to SLPs (the rest goes to surplus)
uint64 interestsForSLPs;
}
/// @title IStableMasterFunctions
/// @author Angle Core Team
/// @notice Interface for the `StableMaster` contract
interface IStableMasterFunctions {
// ============================== Lending ======================================
function accumulateInterest(uint256 gain) external;
function signalLoss(uint256 loss) external;
// ============================== HAs ==========================================
function getStocksUsers() external view returns (uint256 maxCAmountInStable);
function convertToSLP(uint256 amount, address user) external;
// ============================== Keepers ======================================
function getCollateralRatio() external returns (uint256);
function setFeeKeeper(
uint64 feeMint,
uint64 feeBurn,
uint64 _slippage,
uint64 _slippageFee
) external;
// ============================== AgToken ======================================
function updateStocksUsers(uint256 amount, address poolManager) external;
}
/// @title IStableMaster
/// @author Angle Core Team
/// @notice Previous interface with additionnal getters for public variables and mappings
interface IStableMaster is IStableMasterFunctions {
function agToken() external view returns (address);
function collateralMap(address poolManager)
external
view
returns (
address token,
address sanToken,
address perpetualManager,
address oracle,
uint256 stocksUsers,
uint256 sanRate,
uint256 collatBase,
SLPData memory slpData,
MintBurnData memory feeData
);
/// @notice Lets a SLP enter the protocol by sending collateral to the system in exchange of sanTokens
/// @param user Address of the SLP to send sanTokens to
/// @param amount Amount of collateral sent
/// @param poolManager Address of the `PoolManager` of the required collateral
function deposit(
uint256 amount,
address user,
address poolManager
) external;
/// @notice Lets a SLP burn of sanTokens and receive the corresponding collateral back in exchange at the
/// current exchange rate between sanTokens and collateral
/// @param amount Amount of sanTokens burnt by the SLP
/// @param burner Address that will burn its sanTokens
/// @param dest Address that will receive the collateral
/// @param poolManager Address of the `PoolManager` of the required collateral
/// @dev The `msg.sender` should have approval to burn from the `burner` or the `msg.sender` should be the `burner`
/// @dev This transaction will fail if the `PoolManager` does not have enough reserves, the front will however be here
/// to notify them that they cannot withdraw
/// @dev In case there are not enough reserves, strategies should be harvested or their debt ratios should be adjusted
/// by governance to make sure that users, HAs or SLPs withdrawing always have free collateral they can use
function withdraw(
uint256 amount,
address burner,
address dest,
address poolManager
) external;
}
interface IAngleGauge {
//it stakes.
function deposit(uint256 amount) external;
//gimme profit
function claim_rewards() external;
//gimme principal
function withdraw(uint256 amount) external;
//getReward and Withdraw in same go
function exit() external;
//basically a sweep in case things get weird
function recoverERC20(address tokenAddress, address to, uint256 amount) external;
function balanceOf(address account) external view returns(uint256);
function claimable_reward(address _user, address _reward_token) external view returns (uint256);
}
struct AsyncTradeExecutionDetails {
address _strategy;
address _tokenIn;
address _tokenOut;
uint256 _amount;
uint256 _minAmountOut;
}
interface ITradeFactory {
function enable(address rewards, address want) external;
function grantRole(bytes32 role, address account) external;
function STRATEGY() external view returns (bytes32);
function execute(
AsyncTradeExecutionDetails calldata _tradeExecutionDetails,
address _swapper,
bytes calldata _data
) external returns (uint256 _receivedAmount);
}
interface IUniV2 {
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapExactTokensForTokens(
uint256,
uint256,
address[] calldata,
address,
uint256
) external;
function getAmountsOut(uint256 amountIn, address[] memory path)
external
view
returns (uint256[] memory amounts);
}
interface IVoteEscrow {
function create_lock(uint256, uint256) external;
function increase_amount(uint256) external;
function withdraw() external;
}
contract YearnAngleVoter {
using SafeERC20 for IERC20;
address constant public angle = address(0x31429d1856aD1377A8A0079410B297e1a9e214c2);
address constant public veAngle = address(0x0C462Dbb9EC8cD1630f1728B2CFD2769d09f0dd5);
address public governance;
address public pendingGovernance;
address public proxy;
constructor() public {
governance = address(0x16388463d60FFE0661Cf7F1f31a7D658aC790ff7);
}
function getName() external pure returns (string memory) {
return "YearnAngleVoter";
}
function setProxy(address _proxy) external {
require(msg.sender == governance, "!governance");
proxy = _proxy;
}
function createLock(uint256 _value, uint256 _unlockTime) external {
require(msg.sender == proxy || msg.sender == governance, "!authorized");
IERC20(angle).approve(veAngle, _value);
IVoteEscrow(veAngle).create_lock(_value, _unlockTime);
}
function increaseAmount(uint _value) external {
require(msg.sender == proxy || msg.sender == governance, "!authorized");
IERC20(angle).approve(veAngle, _value);
IVoteEscrow(veAngle).increase_amount(_value);
}
function release() external {
require(msg.sender == proxy || msg.sender == governance, "!authorized");
IVoteEscrow(veAngle).withdraw();
}
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);
}
function execute(address to, uint value, bytes calldata data) external returns (bool, bytes memory) {
require(msg.sender == proxy || msg.sender == governance, "!governance");
(bool success, bytes memory result) = to.call{value: value}(data);
return (success, result);
}
}
interface ICurveFi {
function get_virtual_price() external view returns (uint256);
function add_liquidity(
// sBTC pool
uint256[3] calldata amounts,
uint256 min_mint_amount
) external;
function add_liquidity(
// bUSD pool
uint256[4] calldata amounts,
uint256 min_mint_amount
) external;
function add_liquidity(
// stETH pool
uint256[2] calldata amounts,
uint256 min_mint_amount
) external payable;
function coins(uint256) external returns (address);
function remove_liquidity_imbalance(uint256[2] calldata amounts, uint256 max_burn_amount) external;
function remove_liquidity(uint256 _amount, uint256[2] calldata amounts) external;
function calc_withdraw_one_coin(uint256 _amount, int128 i) external view returns (uint256);
function remove_liquidity_one_coin(
uint256 _token_amount,
int128 i,
uint256 min_amount
) external;
function exchange(
int128 from,
int128 to,
uint256 _from_amount,
uint256 _min_to_amount
) external payable;
function exchange_underlying(
int128 from,
int128 to,
uint256 _from_amount,
uint256 _min_to_amount
) external payable;
function balances(int128) external view returns (uint256);
function get_dy(
int128 from,
int128 to,
uint256 _from_amount
) external view returns (uint256);
function calc_token_amount( uint256[2] calldata amounts, bool is_deposit) external view returns (uint256);
}
interface Zap {
function remove_liquidity_one_coin(
uint256,
int128,
uint256
) external;
}
library SafeVoter {
function safeExecute(
YearnAngleVoter voter,
address to,
uint256 value,
bytes memory data
) internal {
(bool success, bytes memory result) = voter.execute(to, value, data);
require(success, string(result));
}
}
contract AngleStrategyVoterProxy {
using SafeVoter for YearnAngleVoter;
using SafeERC20 for IERC20;
using Address for address;
YearnAngleVoter public yearnAngleVoter;
address public constant angleToken = address(0x31429d1856aD1377A8A0079410B297e1a9e214c2);
uint256 public constant UNLOCK_TIME = 4 * 365 * 24 * 60 * 60;
// gauge => strategies
mapping(address => address) public strategies;
mapping(address => bool) public voters;
address public governance;
constructor(address _voter) public {
governance = address(0x16388463d60FFE0661Cf7F1f31a7D658aC790ff7);
yearnAngleVoter = YearnAngleVoter(_voter);
}
function setGovernance(address _governance) external {
require(msg.sender == governance, "!governance");
governance = _governance;
}
function approveStrategy(address _gauge, address _strategy) external {
require(msg.sender == governance, "!governance");
strategies[_gauge] = _strategy;
}
function revokeStrategy(address _gauge) external {
require(msg.sender == governance, "!governance");
strategies[_gauge] = address(0);
}
function approveVoter(address _voter) external {
require(msg.sender == governance, "!governance");
voters[_voter] = true;
}
function revokeVoter(address _voter) external {
require(msg.sender == governance, "!governance");
voters[_voter] = false;
}
function lock(uint256 amount) external {
if (amount > 0 && amount <= IERC20(angleToken).balanceOf(address(yearnAngleVoter))) {
yearnAngleVoter.createLock(amount, block.timestamp + UNLOCK_TIME);
}
}
function increaseAmount(uint256 amount) external {
if (amount > 0 && amount <= IERC20(angleToken).balanceOf(address(yearnAngleVoter))) {
yearnAngleVoter.increaseAmount(amount);
}
}
function vote(address _gauge, uint256 _amount) public {
require(voters[msg.sender], "!voter");
yearnAngleVoter.safeExecute(_gauge, 0, abi.encodeWithSignature("vote_for_gauge_weights(address,uint256)", _gauge, _amount));
}
function withdraw(
address _gauge,
address _token,
uint256 _amount
) public returns (uint256) {
require(strategies[_gauge] == msg.sender, "!strategy");
uint256 _balance = IERC20(_token).balanceOf(address(yearnAngleVoter));
yearnAngleVoter.safeExecute(_gauge, 0, abi.encodeWithSignature("withdraw(uint256)", _amount));
_balance = IERC20(_token).balanceOf(address(yearnAngleVoter)) - _balance;
yearnAngleVoter.safeExecute(_token, 0, abi.encodeWithSignature("transfer(address,uint256)", msg.sender, _balance));
return _balance;
}
function withdrawFromStableMaster(address stableMaster, uint256 amount,
address poolManager, address token, address gauge) external {
require(strategies[gauge] == msg.sender, "!strategy");
IERC20(token).safeTransfer(address(yearnAngleVoter), amount);
yearnAngleVoter.safeExecute(stableMaster, 0, abi.encodeWithSignature(
"withdraw(uint256,address,address,address)",
amount,
address(yearnAngleVoter),
msg.sender,
poolManager
));
}
function balanceOfStakedSanToken(address _gauge) public view returns (uint256) {
return IERC20(_gauge).balanceOf(address(yearnAngleVoter));
}
function withdrawAll(address _gauge, address _token) external returns (uint256) {
require(strategies[_gauge] == msg.sender, "!strategy");
return withdraw(_gauge, _token, balanceOfStakedSanToken(_gauge));
}
function stake(address gauge, uint256 amount, address token) external {
require(strategies[gauge] == msg.sender, "!strategy");
_checkAllowance(token, gauge, amount);
yearnAngleVoter.safeExecute(gauge, 0, abi.encodeWithSignature(
"deposit(uint256)",
amount
));
}
function depositToStableMaster(address stableMaster, uint256 amount,
address poolManager, address token, address gauge) external {
require(strategies[gauge] == msg.sender, "!strategy");
IERC20(token).safeTransfer(address(yearnAngleVoter), amount);
_checkAllowance(token, stableMaster, amount);
yearnAngleVoter.safeExecute(stableMaster, 0, abi.encodeWithSignature(
"deposit(uint256,address,address)",
amount,
address(yearnAngleVoter),
poolManager
));
}
function claimRewards(address _gauge) external {
require(strategies[_gauge] == msg.sender, "!strategy");
yearnAngleVoter.safeExecute(
_gauge,
0,
abi.encodeWithSelector(
IAngleGauge.claim_rewards.selector
)
);
address _token = address(angleToken);
yearnAngleVoter.safeExecute(_token, 0, abi.encodeWithSignature("transfer(address,uint256)", msg.sender, IERC20(_token).balanceOf(address(yearnAngleVoter))));
}
function balanceOfSanToken(address sanToken) public view returns (uint256) {
return IERC20(sanToken).balanceOf(address(yearnAngleVoter));
}
function _checkAllowance(
address _token,
address _contract,
uint256 _amount
) internal {
if (IERC20(_token).allowance(address(yearnAngleVoter), _contract) < _amount) {
yearnAngleVoter.safeExecute(_token, 0, abi.encodeWithSignature("approve(address,uint256)", _contract, 0));
yearnAngleVoter.safeExecute(_token, 0, abi.encodeWithSignature("approve(address,uint256)", _contract, _amount));
}
}
}
interface IBaseFee {
function isCurrentBaseFeeAcceptable() external view returns (bool);
}
contract Strategy is BaseStrategy {
using SafeERC20 for IERC20;
using Address for address;
event Cloned(address indexed clone);
bool public isOriginal = true;
IERC20 public constant angleToken = IERC20(0x31429d1856aD1377A8A0079410B297e1a9e214c2);
IStableMaster public constant angleStableMaster = IStableMaster(0x5adDc89785D75C86aB939E9e15bfBBb7Fc086A87);
AngleStrategyVoterProxy public strategyProxy;
uint256 public constant MAX_BPS = 10000;
// variable for determining how much governance token to hold for voting rights
uint256 public percentKeep;
IERC20 public sanToken;
IAngleGauge public sanTokenGauge;
address public constant treasury = 0x93A62dA5a14C80f265DAbC077fCEE437B1a0Efde; // To change this, migrate
address public constant unirouter = 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F; // SushiSwap
address public constant usdt = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
address public constant weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public poolManager;
address public tradeFactory = address(0);
// keeper stuff
uint256 public harvestProfitMin; // minimum size in USD (6 decimals) that we want to harvest
uint256 public harvestProfitMax; // maximum size in USD (6 decimals) that we want to harvest
uint256 public creditThreshold; // amount of credit in underlying tokens that will automatically trigger a harvest
bool internal forceHarvestTriggerOnce; // only set this to true when we want to trigger our keepers to harvest for us
constructor(
address _vault,
address _sanToken,
address _sanTokenGauge,
address _poolManager,
address _strategyProxy
) public BaseStrategy(_vault) {
// Constructor should initialize local variables
_initializeStrategy(
_sanToken,
_sanTokenGauge,
_poolManager,
_strategyProxy
);
}
// Cloning & initialization code adapted from https://github.com/yearn/yearn-vaults/blob/43a0673ab89742388369bc0c9d1f321aa7ea73f6/contracts/BaseStrategy.sol#L866
function _initializeStrategy(
address _sanToken,
address _sanTokenGauge,
address _poolManager,
address _strategyProxy
) internal {
sanToken = IERC20(_sanToken);
sanTokenGauge = IAngleGauge(_sanTokenGauge);
poolManager = _poolManager;
strategyProxy = AngleStrategyVoterProxy(_strategyProxy);
percentKeep = 1000;
healthCheck = 0xDDCea799fF1699e98EDF118e0629A974Df7DF012;
doHealthCheck = true;
maxReportDelay = 21 days; // 21 days in seconds, if we hit this then harvestTrigger = True
harvestProfitMin = 2_000e6;
harvestProfitMax = 10_000e6;
creditThreshold = 1e6 * 1e18;
}
function initialize(
address _vault,
address _strategist,
address _rewards,
address _keeper,
address _sanToken,
address _sanTokenGauge,
address _poolManager,
address _strategyProxy
) external {
_initialize(_vault, _strategist, _rewards, _keeper);
_initializeStrategy(
_sanToken,
_sanTokenGauge,
_poolManager,
_strategyProxy
);
}
function cloneAngle(
address _vault,
address _strategist,
address _rewards,
address _keeper,
address _sanToken,
address _sanTokenGauge,
address _poolManager,
address _strategyProxy
) 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)
}
Strategy(newStrategy).initialize(
_vault,
_strategist,
_rewards,
_keeper,
_sanToken,
_sanTokenGauge,
_poolManager,
_strategyProxy
);
emit Cloned(newStrategy);
}
function name() external view override returns (string memory) {
return
string(
abi.encodePacked(
"StrategyAngle",
IERC20Metadata(address(want)).symbol()
)
);
}
// returns sum of all assets, realized and unrealized
function estimatedTotalAssets() public view override returns (uint256) {
return balanceOfWant() + valueOfStakedSanToken() + valueOfSanToken();
}
function prepareReturn(uint256 _debtOutstanding)
internal
override
returns (
uint256 _profit,
uint256 _loss,
uint256 _debtPayment
)
{
// Run initial profit + loss calculations.
uint256 _totalAssets = estimatedTotalAssets();
uint256 _totalDebt = vault.strategies(address(this)).totalDebt;
if (_totalAssets >= _totalDebt) {
// Implicitly, _profit & _loss are 0 before we change them.
_profit = _totalAssets - _totalDebt;
} else {
_loss = _totalDebt - _totalAssets;
}
// Free up _debtOutstanding + our profit, and make any necessary adjustments to the accounting.
(uint256 _amountFreed, uint256 _liquidationLoss) =
liquidatePosition(_debtOutstanding + _profit);
_loss = _loss + _liquidationLoss;
_debtPayment = Math.min(_debtOutstanding, _amountFreed);
if (_loss > _profit) {
_loss = _loss - _profit;
_profit = 0;
} else {
_profit = _profit - _loss;
_loss = 0;
}
// we're done harvesting, so reset our trigger if we used it
forceHarvestTriggerOnce = false;
}
// Deposit value & stake
function adjustPosition(uint256 _debtOutstanding) internal override {
if (emergencyExit) {
return;
}
// Claim rewards here so that we can chain tend() -> yswap sell -> harvest() in a single transaction
strategyProxy.claimRewards(address(sanTokenGauge));
uint256 _tokensAvailable = balanceOfAngleToken();
if (_tokensAvailable > 0) {
uint256 _tokensToKeep =
(_tokensAvailable * percentKeep) / MAX_BPS;
if (_tokensToKeep > 0) {
IERC20(angleToken).transfer(address(strategyProxy.yearnAngleVoter()), _tokensToKeep);
}
}
uint256 _balanceOfWant = balanceOfWant();
// do not invest if we have more debt than want
if (_debtOutstanding > _balanceOfWant) {
return;
}
// Invest the rest of the want
uint256 _wantAvailable = _balanceOfWant - _debtOutstanding;
if (_wantAvailable > 0) {
// deposit for sanToken
want.safeTransfer(address(strategyProxy), _wantAvailable);
depositToStableMaster(_wantAvailable);
}
// Stake any san tokens, whether they originated through the above deposit or some other means (e.g. migration)
uint256 _sanTokenBalance = balanceOfSanToken();
if (_sanTokenBalance > 0) {
strategyProxy.stake(address(sanTokenGauge), _sanTokenBalance, address(sanToken));
}
}
function liquidateAllPositions()
internal
override
returns (uint256 _amountFreed)
{
(_amountFreed, ) = liquidatePosition(estimatedTotalAssets());
}
function liquidatePosition(uint256 _amountNeeded)
internal
override
returns (uint256 _liquidatedAmount, uint256 _loss)
{
// NOTE: Maintain invariant `_liquidatedAmount + _loss <= _amountNeeded`
_amountNeeded = Math.min(_amountNeeded, estimatedTotalAssets()); // This makes it safe to request to liquidate more than we have
uint256 _balanceOfWant = balanceOfWant();
if (_balanceOfWant < _amountNeeded) {
// We need to withdraw to get back more want
_withdrawSome(_amountNeeded - _balanceOfWant);
// reload balance of want after side effect
_balanceOfWant = balanceOfWant();
}
if (_balanceOfWant >= _amountNeeded) {
_liquidatedAmount = _amountNeeded;
} else {
_liquidatedAmount = _balanceOfWant;
_loss = _amountNeeded - _balanceOfWant;
}
}
// withdraw some want from Angle
function _withdrawSome(uint256 _amount) internal {
uint256 _amountInSanToken = wantToSanToken(_amount);
uint256 _sanTokenBalance = balanceOfSanToken();
if (_amountInSanToken > _sanTokenBalance) {
_amountInSanToken = Math.min(_amountInSanToken - _sanTokenBalance, balanceOfStakedSanToken());
strategyProxy.withdraw(
address(sanTokenGauge),
address(sanToken),
_amountInSanToken
);
IERC20(sanToken).safeTransfer(address(strategyProxy), _amountInSanToken);
}
withdrawFromStableMaster(_amountInSanToken);
}
// can be used in conjunction with migration if this function is still working
function claimRewards() external onlyVaultManagers {
strategyProxy.claimRewards(address(sanTokenGauge));
}
// transfers all tokens to new strategy
function prepareMigration(address _newStrategy) internal override {
// Claim rewards is called externally + sweep by governance
// Governance can then revoke this strategy and approve the new one so the
// funds assigned to this gauge in the proxy are available
}
function protectedTokens()
internal
view
override
returns (address[] memory)
{}
function ethToWant(uint256 _amtInWei)
public
view
override
returns (uint256)
{
return _amtInWei;
}
/* ========== KEEP3RS ========== */
// use this to determine when to harvest
function harvestTrigger(uint256 callCostinEth)
public
view
override
returns (bool)
{
// 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;
}
// harvest if we have a profit to claim at our upper limit without considering gas price
uint256 claimableProfit = claimableProfitInUsdt();
if (claimableProfit > harvestProfitMax) {
return true;
}
// check if the base fee gas price is higher than we allow. if it is, block harvests.
if (!isBaseFeeAcceptable()) {
return false;
}
// trigger if we want to manually harvest, but only if our gas price is acceptable
if (forceHarvestTriggerOnce) {
return true;
}
// harvest if we have a sufficient profit to claim, but only if our gas price is acceptable
if (claimableProfit > harvestProfitMin) {
return true;
}
StrategyParams memory params = vault.strategies(address(this));
// harvest no matter what once we reach our maxDelay
if (block.timestamp - params.lastReport > maxReportDelay) {
return true;
}
// harvest our credit if it's above our threshold
if (vault.creditAvailable() > creditThreshold) {
return true;
}
// otherwise, we don't harvest
return false;
}
/// @notice The value in dollars that our claimable rewards are worth (in USDT, 6 decimals).
function claimableProfitInUsdt() public view returns (uint256) {
address[] memory path = new address[](3);
path[0] = address(angleToken);
path[1] = weth;
path[2] = address(usdt);
uint256 _claimableRewards = sanTokenGauge.claimable_reward(address(this), address(angleToken));
if (_claimableRewards < 1e18) { // Dust check
return 0;
}
uint256[] memory amounts = IUniV2(unirouter).getAmountsOut(
_claimableRewards,
path
);
return amounts[amounts.length - 1];
}
// check if the current baseFee is below our external target
function isBaseFeeAcceptable() internal view returns (bool) {
return
IBaseFee(0xb5e1CAcB567d98faaDB60a1fD4820720141f064F)
.isCurrentBaseFeeAcceptable();
}
// ---------------------- SETTERS -----------------------
// This allows us to manually harvest with our keeper as needed
function setForceHarvestTriggerOnce(bool _forceHarvestTriggerOnce)
external
onlyVaultManagers
{
forceHarvestTriggerOnce = _forceHarvestTriggerOnce;
}
// Min profit to start checking for harvests if gas is good, max will harvest no matter gas (both in USDT, 6 decimals). Credit threshold is in want token, and will trigger a harvest if credit is large enough. check earmark to look at convex's booster.
function setHarvestTriggerParams(
uint256 _harvestProfitMin,
uint256 _harvestProfitMax,
uint256 _creditThreshold
) external onlyVaultManagers {
harvestProfitMin = _harvestProfitMin;
harvestProfitMax = _harvestProfitMax;
creditThreshold = _creditThreshold;
}
function setKeepInBips(uint256 _percentKeep) external onlyVaultManagers {
require(
_percentKeep <= MAX_BPS,
"_percentKeep can't be larger than 10,000"
);
percentKeep = _percentKeep;
}
// ----------------- SUPPORT & UTILITY FUNCTIONS ----------
function balanceOfWant() public view returns (uint256) {
return want.balanceOf(address(this));
}
function balanceOfStakedSanToken() public view returns (uint256) {
return strategyProxy.balanceOfStakedSanToken(address(sanTokenGauge));
}
function balanceOfSanToken() public view returns (uint256) {
return strategyProxy.balanceOfSanToken(address(sanToken));
}
function balanceOfAngleToken() public view returns (uint256) {
return angleToken.balanceOf(address(this));
}
function valueOfSanToken() public view returns (uint256) {
return sanTokenToWant(balanceOfSanToken());
}
function valueOfStakedSanToken() public view returns (uint256) {
return sanTokenToWant(balanceOfStakedSanToken());
}
function sanTokenToWant(uint256 _sanTokenAmount)
public
view
returns (uint256)
{
return (_sanTokenAmount * getSanRate()) / 1e18;
}
function wantToSanToken(uint256 _wantAmount) public view returns (uint256) {
return ((_wantAmount * 1e18) / getSanRate()) + 1;
}
// Get rate of conversion between sanTokens and want
function getSanRate() public view returns (uint256) {
(, , , , , uint256 _sanRate, , , ) =
IStableMaster(angleStableMaster).collateralMap(poolManager);
return _sanRate;
}
function depositToStableMaster(uint256 _amount) internal {
strategyProxy.depositToStableMaster(
address(angleStableMaster),
_amount,
poolManager,
address(want),
address(sanTokenGauge)
);
}
function withdrawFromStableMaster(uint256 _amountInSanToken) internal {
strategyProxy.withdrawFromStableMaster(
address(angleStableMaster),
_amountInSanToken,
poolManager,
address(sanToken),
address(sanTokenGauge)
);
}
// ---------------------- YSWAPS FUNCTIONS ----------------------
function setTradeFactory(address _tradeFactory) external onlyGovernance {
if (tradeFactory != address(0)) {
_removeTradeFactoryPermissions();
}
angleToken.safeApprove(_tradeFactory, type(uint256).max);
ITradeFactory tf = ITradeFactory(_tradeFactory);
tf.enable(address(angleToken), address(want));
tradeFactory = _tradeFactory;
}
function removeTradeFactoryPermissions() external onlyEmergencyAuthorized {
_removeTradeFactoryPermissions();
}
function _removeTradeFactoryPermissions() internal {
angleToken.safeApprove(tradeFactory, 0);
tradeFactory = address(0);
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_sanToken","type":"address"},{"internalType":"address","name":"_sanTokenGauge","type":"address"},{"internalType":"address","name":"_poolManager","type":"address"},{"internalType":"address","name":"_strategyProxy","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":"bool","name":"","type":"bool"}],"name":"SetDoHealthCheck","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"","type":"address"}],"name":"SetHealthCheck","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":"MAX_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"angleStableMaster","outputs":[{"internalType":"contract IStableMaster","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"angleToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"apiVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"balanceOfAngleToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfSanToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfStakedSanToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimableProfitInUsdt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"_sanToken","type":"address"},{"internalType":"address","name":"_sanTokenGauge","type":"address"},{"internalType":"address","name":"_poolManager","type":"address"},{"internalType":"address","name":"_strategyProxy","type":"address"}],"name":"cloneAngle","outputs":[{"internalType":"address","name":"newStrategy","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"creditThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"_amtInWei","type":"uint256"}],"name":"ethToWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSanRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"harvestProfitMax","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvestProfitMin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"_sanToken","type":"address"},{"internalType":"address","name":"_sanTokenGauge","type":"address"},{"internalType":"address","name":"_poolManager","type":"address"},{"internalType":"address","name":"_strategyProxy","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":"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":"percentKeep","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolManager","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[],"name":"rewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sanToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sanTokenGauge","outputs":[{"internalType":"contract IAngleGauge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sanTokenAmount","type":"uint256"}],"name":"sanTokenToWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"uint256","name":"_harvestProfitMin","type":"uint256"},{"internalType":"uint256","name":"_harvestProfitMax","type":"uint256"},{"internalType":"uint256","name":"_creditThreshold","type":"uint256"}],"name":"setHarvestTriggerParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_healthCheck","type":"address"}],"name":"setHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_percentKeep","type":"uint256"}],"name":"setKeepInBips","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":[],"name":"strategist","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategyProxy","outputs":[{"internalType":"contract AngleStrategyVoterProxy","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":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unirouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usdt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"valueOfSanToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"valueOfStakedSanToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract VaultAPI","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":"_wantAmount","type":"uint256"}],"name":"wantToSanToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","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
6080604052600b805461ff001916610100179055601080546001600160a01b03191690553480156200003057600080fd5b5060405162004d3038038062004d308339810160408190526200005391620006d7565b8462000062813380806200011d565b50600d80546001600160a01b03199081166001600160a01b0380881691909117909255600e80548216838716179055600f8054909116828516179055600b805462010000600160b01b03191662010000928416929092029190911790556103e8600c55600180546001600160a81b03191674ddcea799ff1699e98edf118e0629a974df7df01201179055621baf8060085563773594006011556402540be40060125569d3c21bcecceda1000000601355505050505062000829565b6006546001600160a01b0316156200017c5760405162461bcd60e51b815260206004820152601c60248201527f537472617465677920616c726561647920696e697469616c697a65640000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a916004808201926020929091908290030181865afa158015620001d6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001fc919062000747565b600680546001600160a01b0319166001600160a01b0392909216918217905562000236908560001962000301602090811b62002dbb17901c565b600380546001600160a01b038581166001600160a01b03199283161790925560048054858416908316811782556005805486861694169390931790925560006007819055620151806008556064600955600a5560025460405163095ea7b360e01b815291820192909252600019602482015291169063095ea7b3906044016020604051808303816000875af1158015620002d4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002fa919062000765565b5050505050565b8015806200037f5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801562000357573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200037d919062000789565b155b620003f35760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e636500000000000000000000606482015260840162000173565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b179091526200044b9185916200045016565b505050565b6000620004ac826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200052e60201b62002f08179092919060201c565b8051909150156200044b5780806020019051810190620004cd919062000765565b6200044b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000173565b60606200053f848460008562000549565b90505b9392505050565b606082471015620005ac5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000173565b843b620005fc5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000173565b600080866001600160a01b031685876040516200061a9190620007d6565b60006040518083038185875af1925050503d806000811462000659576040519150601f19603f3d011682016040523d82523d6000602084013e6200065e565b606091505b509092509050620006718282866200067c565b979650505050505050565b606083156200068d57508162000542565b8251156200069e5782518084602001fd5b8160405162461bcd60e51b8152600401620001739190620007f4565b80516001600160a01b0381168114620006d257600080fd5b919050565b600080600080600060a08688031215620006f057600080fd5b620006fb86620006ba565b94506200070b60208701620006ba565b93506200071b60408701620006ba565b92506200072b60608701620006ba565b91506200073b60808701620006ba565b90509295509295909350565b6000602082840312156200075a57600080fd5b6200054282620006ba565b6000602082840312156200077857600080fd5b815180151581146200054257600080fd5b6000602082840312156200079c57600080fd5b5051919050565b60005b83811015620007c0578181015183820152602001620007a6565b83811115620007d0576000848401525b50505050565b60008251620007ea818460208701620007a3565b9190910192915050565b602081526000825180602084015262000815816040850160208701620007a3565b601f01601f19169190910160400192915050565b6144f780620008396000396000f3fe608060405234801561001057600080fd5b50600436106104285760003560e01c80636d51a20f1161022b578063b69af17211610130578063e5e19b4a116100b8578063efbb5cb011610087578063efbb5cb0146108ae578063f017c92f146108b6578063fbfa77cf146108c9578063fcf2d0ad146108dc578063fd967f47146108e457600080fd5b8063e5e19b4a1461086d578063eace9f2614610880578063ec38a86214610888578063ed882c2b1461089b57600080fd5b8063ce5494bb116100ff578063ce5494bb1461081c578063d96db2c21461082f578063dc4c90d31461084a578063e1cc58441461085d578063e300aff41461086557600080fd5b8063b69af172146107d5578063c1a3d44c146107e8578063c7b9d530146107f0578063cb14cd0a1461080357600080fd5b806391397ab4116101b3578063aa5480cf11610182578063aa5480cf1461077b578063ac00ff2614610784578063aced166114610797578063b18925af146107aa578063b252720b146107bd57600080fd5b806391397ab41461073157806395e80c50146107445780639ec5a8941461074d578063a6be02cb1461076057600080fd5b8063780022a0116101fa578063780022a0146106f55780638a29e2de146107065780638cdfe166146107195780638dddbe17146107225780638e6350e21461072a57600080fd5b80636d51a20f146106b55780636f392ce7146106bd578063748747e6146106cf578063750521f5146106e257600080fd5b80633569cb791161033157806346f6bbb7116102b9578063613ba8e711610288578063613ba8e71461065e57806361d027b314610666578063650d18801461068157806365210942146106955780636718835f146106a857600080fd5b806346f6bbb7146106225780635641ec03146106355780635e007a09146106425780635fbeb25f1461065557600080fd5b80633b7c6e2f116103005780633b7c6e2f146105e65780633fc8cef3146105ef5780634262f98e1461060a578063440368a3146106125780634641257d1461061a57600080fd5b80633569cb79146105af578063372500ab146105b857806339a172a8146105c057806339e24173146105d357600080fd5b80631d12f28b116103b4578063257ae0de11610383578063257ae0de1461053c578063258294101461055757806328b7ccf7146105785780632e1a7d4d146105815780632f48ab7d1461059457600080fd5b80631d12f28b146104dd5780631f1fcd51146104e65780631fe4a6861461051157806322f3e2d41461052457600080fd5b80630ada4dab116103fb5780630ada4dab1461047e5780630eed6485146104915780630f969b87146104a457806311bc8245146104b7578063146b8de0146104ca57600080fd5b806301681a621461042d57806303ee438c1461044257806306cfb3c01461046057806306fdde0314610476575b600080fd5b61044061043b366004613b6e565b6108ed565b005b61044a610acd565b6040516104579190613bb7565b60405180910390f35b610468610b5b565b604051908152602001610457565b61044a610d9e565b61044061048c366004613bf8565b610e34565b61044061049f366004613c15565b610f11565b6104406104b2366004613c41565b610fe9565b6104406104c5366004613b6e565b611072565b6104686104d8366004613c41565b6111a0565b610468600a5481565b6006546104f9906001600160a01b031681565b6040516001600160a01b039091168152602001610457565b6003546104f9906001600160a01b031681565b61052c6111d7565b6040519015158152602001610457565b6104f973d9e1ce17f2641f24ae83637ab66a2cca9c378b9f81565b604080518082019091526005815264302e342e3360d81b602082015261044a565b61046860085481565b61046861058f366004613c41565b611265565b6104f973dac17f958d2ee523a2206206994597c13d831ec781565b610468600c5481565b6104406112d9565b6104406105ce366004613c41565b61140c565b6104686105e1366004613c41565b61148e565b61046860125481565b6104f973c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6104686114b5565b61044061154d565b610440611749565b600e546104f9906001600160a01b031681565b600b5461052c9060ff1681565b610440610650366004613c41565b611c03565b61046860115481565b610468611d35565b6104f97393a62da5a14c80f265dabc077fcee437b1a0efde81565b61052c61068f366004613c41565b50600090565b6104406106a3366004613b6e565b611d42565b60015461052c9060ff1681565b610440611e52565b600b5461052c90610100900460ff1681565b6104406106dd366004613b6e565b611fcb565b6104406106f0366004613c5a565b612079565b610468610703366004613c41565b90565b610440610714366004613ccc565b612110565b61046860095481565b6104686121d5565b6000610468565b61044061073f366004613c41565b612250565b61046860075481565b6004546104f9906001600160a01b031681565b6104f97331429d1856ad1377a8a0079410b297e1a9e214c281565b61046860135481565b610440610792366004613bf8565b6122d2565b6005546104f9906001600160a01b031681565b600d546104f9906001600160a01b031681565b6001546104f99061010090046001600160a01b031681565b6104f96107e3366004613ccc565b6123e4565b610468612548565b6104406107fe366004613b6e565b612579565b600b546104f9906201000090046001600160a01b031681565b61044061082a366004613b6e565b612627565b6104f9735addc89785d75c86ab939e9e15bfbbb7fc086a8781565b600f546104f9906001600160a01b031681565b610468612749565b610468612783565b6010546104f9906001600160a01b031681565b6104686127c1565b610440610896366004613b6e565b6127ce565b61052c6108a9366004613c41565b61296c565b610468612b04565b6104406108c4366004613c41565b612b32565b6002546104f9906001600160a01b031681565b610440612bb4565b61046861271081565b6108f5612f21565b6001600160a01b0316336001600160a01b03161461092e5760405162461bcd60e51b815260040161092590613d75565b60405180910390fd5b6006546001600160a01b03828116911614156109745760405162461bcd60e51b8152602060048201526005602482015264085dd85b9d60da1b6044820152606401610925565b6002546001600160a01b03828116911614156109bc5760405162461bcd60e51b81526020600482015260076024820152662173686172657360c81b6044820152606401610925565b606060005b8151811015610a44578181815181106109dc576109dc613d9a565b60200260200101516001600160a01b0316836001600160a01b03161415610a325760405162461bcd60e51b815260206004820152600a602482015269085c1c9bdd1958dd195960b21b6044820152606401610925565b80610a3c81613dc6565b9150506109c1565b50610ac9610a50612f21565b6040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa158015610a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab89190613de1565b6001600160a01b0385169190612f8f565b5050565b60008054610ada90613dfa565b80601f0160208091040260200160405190810160405280929190818152602001828054610b0690613dfa565b8015610b535780601f10610b2857610100808354040283529160200191610b53565b820191906000526020600020905b815481529060010190602001808311610b3657829003601f168201915b505050505081565b60408051600380825260808201909252600091829190602082016060803683370190505090507331429d1856ad1377a8a0079410b297e1a9e214c281600081518110610ba957610ba9613d9a565b60200260200101906001600160a01b031690816001600160a01b03168152505073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110610bf157610bf1613d9a565b60200260200101906001600160a01b031690816001600160a01b03168152505073dac17f958d2ee523a2206206994597c13d831ec781600281518110610c3957610c39613d9a565b6001600160a01b039283166020918202929092010152600e54604051630cff5bdd60e21b81523060048201527331429d1856ad1377a8a0079410b297e1a9e214c2602482015260009291909116906333fd6f7490604401602060405180830381865afa158015610cad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd19190613de1565b9050670de0b6b3a7640000811015610cec5760009250505090565b60405163d06ca61f60e01b815260009073d9e1ce17f2641f24ae83637ab66a2cca9c378b9f9063d06ca61f90610d289085908790600401613e45565b600060405180830381865afa158015610d45573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d6d9190810190613f3f565b90508060018251610d7e9190613fca565b81518110610d8e57610d8e613d9a565b6020026020010151935050505090565b600654604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b419160048083019260009291908290030181865afa158015610de8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e109190810190613fe1565b604051602001610e209190614075565b604051602081830303815290604052905090565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eab91906140aa565b6001600160a01b0316336001600160a01b03161480610ee25750610ecd612f21565b6001600160a01b0316336001600160a01b0316145b610efe5760405162461bcd60e51b815260040161092590613d75565b6014805460ff1916911515919091179055565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8891906140aa565b6001600160a01b0316336001600160a01b03161480610fbf5750610faa612f21565b6001600160a01b0316336001600160a01b0316145b610fdb5760405162461bcd60e51b815260040161092590613d75565b601192909255601255601355565b6003546001600160a01b031633148061101a5750611005612f21565b6001600160a01b0316336001600160a01b0316145b6110365760405162461bcd60e51b815260040161092590613d75565b600a8190556040518181527fa68ba126373d04c004c5748c300c9fca12bd444b3d4332e261f3bd2bac4a8600906020015b60405180910390a150565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e991906140aa565b6001600160a01b0316336001600160a01b03161480611120575061110b612f21565b6001600160a01b0316336001600160a01b0316145b61113c5760405162461bcd60e51b815260040161092590613d75565b6040516001600160a01b03821681527fc8db9c35f716b87af1fbb83f03c78646061931269301fd7ba6dcf189b4cdc2fc9060200160405180910390a1600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60006111aa6114b5565b6111bc83670de0b6b3a76400006140c7565b6111c691906140e6565b6111d1906001614108565b92915050565b6002546040516339ebf82360e01b815230600482015260009182916001600160a01b03909116906339ebf8239060240161012060405180830381865afa158015611225573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112499190614120565b6040015111806112605750600061125e612b04565b115b905090565b6002546000906001600160a01b031633146112ab5760405162461bcd60e51b8152602060048201526006602482015265085d985d5b1d60d21b6044820152606401610925565b60006112b683612fbf565b6006549093509091506112d3906001600160a01b03163383612f8f565b50919050565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561132c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135091906140aa565b6001600160a01b0316336001600160a01b031614806113875750611372612f21565b6001600160a01b0316336001600160a01b0316145b6113a35760405162461bcd60e51b815260040161092590613d75565b600b54600e54604051633bd73ee360e21b81526001600160a01b03918216600482015262010000909204169063ef5cfb8c90602401600060405180830381600087803b1580156113f257600080fd5b505af1158015611406573d6000803e3d6000fd5b50505050565b6003546001600160a01b031633148061143d5750611428612f21565b6001600160a01b0316336001600160a01b0316145b6114595760405162461bcd60e51b815260040161092590613d75565b60078190556040518181527fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b190602001611067565b6000670de0b6b3a76400006114a16114b5565b6114ab90846140c7565b6111d191906140e6565b600f5460405163ba8b722360e01b81526001600160a01b0390911660048201526000908190735addc89785d75c86ab939e9e15bfbbb7fc086a879063ba8b722390602401600060405180830381865afa158015611516573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261153e919081019061431c565b50919998505050505050505050565b6005546001600160a01b031633148061157057506003546001600160a01b031633145b80611593575061157e612f21565b6001600160a01b0316336001600160a01b0316145b806116255750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161091906140aa565b6001600160a01b0316336001600160a01b0316145b806116b75750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561167e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a291906140aa565b6001600160a01b0316336001600160a01b0316145b6116d35760405162461bcd60e51b815260040161092590613d75565b6002546040805163bf3759b560e01b81529051611747926001600160a01b03169163bf3759b59160048083019260209291908290030181865afa15801561171e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117429190613de1565b61302b565b565b6005546001600160a01b031633148061176c57506003546001600160a01b031633145b8061178f575061177a612f21565b6001600160a01b0316336001600160a01b0316145b806118215750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061180c91906140aa565b6001600160a01b0316336001600160a01b0316145b806118b35750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561187a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189e91906140aa565b6001600160a01b0316336001600160a01b0316145b6118cf5760405162461bcd60e51b815260040161092590613d75565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611927573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194b9190613de1565b600b5490915060009060ff16156119a85760006119666132d3565b9050828110156119815761197a8184613fca565b9350611996565b82811115611996576119938382613fca565b94505b6119a08484613fca565b9150506119b9565b6119b1826132e5565b919550935090505b6002546040516339ebf82360e01b81523060048201526000916001600160a01b0316906339ebf8239060240161012060405180830381865afa158015611a03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a279190614120565b60c001516002546040516328766ebf60e21b81526004810188905260248101879052604481018590529192506001600160a01b03169063a1d9bafc906064016020604051808303816000875af1158015611a85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa99190613de1565b9250611ab48361302b565b60015460ff168015611ad5575060015461010090046001600160a01b031615155b15611ba75760015460405163c70fa00b60e01b815260048101879052602481018690526044810184905260648101859052608481018390526101009091046001600160a01b03169063c70fa00b9060a401602060405180830381865afa158015611b43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b679190614459565b611ba25760405162461bcd60e51b815260206004820152600c60248201526b216865616c7468636865636b60a01b6044820152606401610925565b611bb4565b6001805460ff1916811790555b6040805186815260208101869052908101839052606081018490527f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d5099060800160405180910390a15050505050565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7a91906140aa565b6001600160a01b0316336001600160a01b03161480611cb15750611c9c612f21565b6001600160a01b0316336001600160a01b0316145b611ccd5760405162461bcd60e51b815260040161092590613d75565b612710811115611d305760405162461bcd60e51b815260206004820152602860248201527f5f70657263656e744b6565702063616e2774206265206c61726765722074686160448201526706e2031302c3030360c41b6064820152608401610925565b600c55565b60006112606105e1612783565b611d4a612f21565b6001600160a01b0316336001600160a01b031614611d7a5760405162461bcd60e51b815260040161092590613d75565b6010546001600160a01b031615611d9357611d93613402565b611db47331429d1856ad1377a8a0079410b297e1a9e214c282600019612dbb565b600654604051632642a09360e11b81527331429d1856ad1377a8a0079410b297e1a9e214c260048201526001600160a01b0391821660248201528291821690634c85412690604401600060405180830381600087803b158015611e1657600080fd5b505af1158015611e2a573d6000803e3d6000fd5b5050601080546001600160a01b0319166001600160a01b039590951694909417909355505050565b6003546001600160a01b0316331480611e835750611e6e612f21565b6001600160a01b0316336001600160a01b0316145b80611f155750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa158015611edc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0091906140aa565b6001600160a01b0316336001600160a01b0316145b80611fa75750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9291906140aa565b6001600160a01b0316336001600160a01b0316145b611fc35760405162461bcd60e51b815260040161092590613d75565b611747613402565b6003546001600160a01b0316331480611ffc5750611fe7612f21565b6001600160a01b0316336001600160a01b0316145b6120185760405162461bcd60e51b815260040161092590613d75565b6001600160a01b03811661202b57600080fd5b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe715490602001611067565b6003546001600160a01b03163314806120aa5750612095612f21565b6001600160a01b0316336001600160a01b0316145b6120c65760405162461bcd60e51b815260040161092590613d75565b6120d260008383613ac0565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda68282604051612104929190614476565b60405180910390a15050565b61211c88888888613441565b600d80546001600160a01b03199081166001600160a01b0380881691909117909255600e80548216838716179055600f8054909116828516179055600b805462010000600160b01b03191662010000928416929092029190911790556103e8600c55600180546001600160a81b03191674ddcea799ff1699e98edf118e0629a974df7df01201179055621baf8060085563773594006011556402540be40060125569d3c21bcecceda10000006013555050505050505050565b600b54600e5460405163682ee1e560e01b81526001600160a01b0391821660048201526000926201000090049091169063682ee1e5906024015b602060405180830381865afa15801561222c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112609190613de1565b6003546001600160a01b0316331480612281575061226c612f21565b6001600160a01b0316336001600160a01b0316145b61229d5760405162461bcd60e51b815260040161092590613d75565b60098190556040518181527fd94596337df4c2f0f44d30a7fc5db1c7bb60d9aca4185ed77c6fd96eb45ec29890602001611067565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015612325573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234991906140aa565b6001600160a01b0316336001600160a01b03161480612380575061236b612f21565b6001600160a01b0316336001600160a01b0316145b61239c5760405162461bcd60e51b815260040161092590613d75565b60405181151581527ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b9060200160405180910390a16001805460ff1916911515919091179055565b600b54600090610100900460ff166124275760405162461bcd60e51b815260206004820152600660248201526521636c6f6e6560d01b6044820152606401610925565b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81523060601b601482018190526e5af43d82803e903d91602b57fd5bf360881b6028830152906037816000f0604051634514f16f60e11b81526001600160a01b038d811660048301528c811660248301528b811660448301528a81166064830152898116608483015288811660a483015287811660c483015286811660e48301529194509084169150638a29e2de9061010401600060405180830381600087803b1580156124ef57600080fd5b505af1158015612503573d6000803e3d6000fd5b50506040516001600160a01b03851692507f783540fb4221a3238720dc7038937d0d79982bcf895274aa6ad179f82cf0d53c9150600090a25098975050505050505050565b6006546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240161220f565b6003546001600160a01b03163314806125aa5750612595612f21565b6001600160a01b0316336001600160a01b0316145b6125c65760405162461bcd60e51b815260040161092590613d75565b6001600160a01b0381166125d957600080fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b490602001611067565b6002546001600160a01b0316331461263e57600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf9160048083019260209291908290030181865afa15801561268a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ae91906140aa565b6001600160a01b0316146126c157600080fd5b6006546040516370a0823160e01b81523060048201526127469183916001600160a01b03909116906370a0823190602401602060405180830381865afa15801561270f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127339190613de1565b6006546001600160a01b03169190612f8f565b50565b6040516370a0823160e01b81523060048201526000907331429d1856ad1377a8a0079410b297e1a9e214c2906370a082319060240161220f565b600b54600d546040516305df477360e51b81526001600160a01b0391821660048201526000926201000090049091169063bbe8ee609060240161220f565b60006112606105e16121d5565b6003546001600160a01b031633146128165760405162461bcd60e51b815260206004820152600b60248201526a085cdd1c985d1959da5cdd60aa1b6044820152606401610925565b6001600160a01b03811661282957600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b0391821692810192909252600060248301529091169063095ea7b3906044016020604051808303816000875af1158015612882573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a69190614459565b50600480546001600160a01b0319166001600160a01b03838116918217835560025460405163095ea7b360e01b8152938401929092526000196024840152169063095ea7b3906044016020604051808303816000875af115801561290e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129329190614459565b506040516001600160a01b03821681527fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a06990602001611067565b60006129766111d7565b61298257506000919050565b600061298c610b5b565b90506012548111156129a15750600192915050565b6129a9613604565b6129b65750600092915050565b60145460ff16156129ca5750600192915050565b6011548111156129dd5750600192915050565b6002546040516339ebf82360e01b81523060048201526000916001600160a01b0316906339ebf8239060240161012060405180830381865afa158015612a27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a4b9190614120565b90506008548160a0015142612a609190613fca565b1115612a70575060019392505050565b601354600260009054906101000a90046001600160a01b03166001600160a01b031663112c1f9b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aea9190613de1565b1115612afa575060019392505050565b5060009392505050565b6000612b0e611d35565b612b166127c1565b612b1e612548565b612b289190614108565b6112609190614108565b6003546001600160a01b0316331480612b635750612b4e612f21565b6001600160a01b0316336001600160a01b0316145b612b7f5760405162461bcd60e51b815260040161092590613d75565b60088190556040518181527f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c590602001611067565b6003546001600160a01b0316331480612be55750612bd0612f21565b6001600160a01b0316336001600160a01b0316145b80612c775750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c6291906140aa565b6001600160a01b0316336001600160a01b0316145b80612d095750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf491906140aa565b6001600160a01b0316336001600160a01b0316145b612d255760405162461bcd60e51b815260040161092590613d75565b600b805460ff191660011790556002546040805163507257cd60e11b815290516001600160a01b039092169163a0e4af9a9160048082019260009290919082900301818387803b158015612d7857600080fd5b505af1158015612d8c573d6000803e3d6000fd5b50506040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b925060009150a1565b801580612e355750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612e0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e339190613de1565b155b612ea05760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610925565b6040516001600160a01b038316602482015260448101829052612f0390849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261367c565b505050565b6060612f17848460008561374e565b90505b9392505050565b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e6759160048083019260209291908290030181865afa158015612f6b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126091906140aa565b6040516001600160a01b038316602482015260448101829052612f0390849063a9059cbb60e01b90606401612ecc565b600080612fd383612fce612b04565b613876565b92506000612fdf612548565b90508381101561300657612ffb612ff68286613fca565b61388c565b613003612548565b90505b83811061301557839250613025565b9150816130228185613fca565b91505b50915091565b600b5460ff16156130395750565b600b54600e54604051633bd73ee360e21b81526001600160a01b03918216600482015262010000909204169063ef5cfb8c90602401600060405180830381600087803b15801561308857600080fd5b505af115801561309c573d6000803e3d6000fd5b5050505060006130aa612749565b905080156131e6576000612710600c54836130c591906140c7565b6130cf91906140e6565b905080156131e4577331429d1856ad1377a8a0079410b297e1a9e214c26001600160a01b031663a9059cbb600b60029054906101000a90046001600160a01b03166001600160a01b031663e6b59dc06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561314d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061317191906140aa565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af11580156131be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e29190614459565b505b505b60006131f0612548565b9050808311156131ff57505050565b600061320b8483613fca565b9050801561324057600b54600654613237916001600160a01b0391821691620100009091041683612f8f565b6132408161397d565b600061324a612783565b905080156132cc57600b54600e54600d5460405163294091cd60e01b81526001600160a01b03928316600482015260248101859052908216604482015262010000909204169063294091cd90606401600060405180830381600087803b1580156132b357600080fd5b505af11580156132c7573d6000803e3d6000fd5b505050505b5050505050565b60006112d36132e0612b04565b612fbf565b6000806000806132f3612b04565b6002546040516339ebf82360e01b81523060048201529192506000916001600160a01b03909116906339ebf8239060240161012060405180830381865afa158015613342573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133669190614120565b60c0015190508082106133845761337d8183613fca565b9450613391565b61338e8282613fca565b93505b6000806133a16132e0888a614108565b90925090506133b08187614108565b95506133bc8883613876565b9450868611156133db576133d08787613fca565b9550600096506133ec565b6133e58688613fca565b9650600095505b50506014805460ff191690555092949193509150565b60105461342f907331429d1856ad1377a8a0079410b297e1a9e214c2906001600160a01b03166000612dbb565b601080546001600160a01b0319169055565b6006546001600160a01b03161561349a5760405162461bcd60e51b815260206004820152601c60248201527f537472617465677920616c726561647920696e697469616c697a6564000000006044820152606401610925565b600280546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a916004808201926020929091908290030181865afa1580156134f3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061351791906140aa565b600680546001600160a01b0319166001600160a01b039290921691821790556135439085600019612dbb565b600380546001600160a01b038581166001600160a01b03199283161790925560048054858416908316811782556005805486861694169390931790925560006007819055620151806008556064600955600a5560025460405163095ea7b360e01b815291820192909252600019602482015291169063095ea7b3906044016020604051808303816000875af11580156135e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132cc9190614459565b600073b5e1cacb567d98faadb60a1fd4820720141f064f6001600160a01b03166334a9e75c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613658573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112609190614459565b60006136d1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612f089092919063ffffffff16565b805190915015612f0357808060200190518101906136ef9190614459565b612f035760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610925565b6060824710156137af5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610925565b843b6137fd5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610925565b600080866001600160a01b0316858760405161381991906144a5565b60006040518083038185875af1925050503d8060008114613856576040519150601f19603f3d011682016040523d82523d6000602084013e61385b565b606091505b509150915061386b828286613a17565b979650505050505050565b60008183106138855781612f1a565b5090919050565b6000613897826111a0565b905060006138a3612783565b905080821115613974576138c26138ba8284613fca565b612fce6121d5565b600b54600e54600d54604051636ce5768960e11b81526001600160a01b03928316600482015290821660248201526044810184905292945062010000909104169063d9caed12906064016020604051808303816000875af115801561392b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061394f9190613de1565b50600b54600d54613974916001600160a01b0391821691620100009091041684612f8f565b612f0382613a50565b600b54600f54600654600e54604051631cf68e9f60e01b8152735addc89785d75c86ab939e9e15bfbbb7fc086a876004820152602481018690526001600160a01b039384166044820152918316606483015282166084820152620100009092041690631cf68e9f9060a4015b600060405180830381600087803b158015613a0357600080fd5b505af11580156132cc573d6000803e3d6000fd5b60608315613a26575081612f1a565b825115613a365782518084602001fd5b8160405162461bcd60e51b81526004016109259190613bb7565b600b54600f54600d54600e5460405163d471370560e01b8152735addc89785d75c86ab939e9e15bfbbb7fc086a876004820152602481018690526001600160a01b03938416604482015291831660648301528216608482015262010000909204169063d47137059060a4016139e9565b828054613acc90613dfa565b90600052602060002090601f016020900481019282613aee5760008555613b34565b82601f10613b075782800160ff19823516178555613b34565b82800160010185558215613b34579182015b82811115613b34578235825591602001919060010190613b19565b50613b40929150613b44565b5090565b5b80821115613b405760008155600101613b45565b6001600160a01b038116811461274657600080fd5b600060208284031215613b8057600080fd5b8135612f1a81613b59565b60005b83811015613ba6578181015183820152602001613b8e565b838111156114065750506000910152565b6020815260008251806020840152613bd6816040850160208701613b8b565b601f01601f19169190910160400192915050565b801515811461274657600080fd5b600060208284031215613c0a57600080fd5b8135612f1a81613bea565b600080600060608486031215613c2a57600080fd5b505081359360208301359350604090920135919050565b600060208284031215613c5357600080fd5b5035919050565b60008060208385031215613c6d57600080fd5b823567ffffffffffffffff80821115613c8557600080fd5b818501915085601f830112613c9957600080fd5b813581811115613ca857600080fd5b866020828501011115613cba57600080fd5b60209290920196919550909350505050565b600080600080600080600080610100898b031215613ce957600080fd5b8835613cf481613b59565b97506020890135613d0481613b59565b96506040890135613d1481613b59565b95506060890135613d2481613b59565b94506080890135613d3481613b59565b935060a0890135613d4481613b59565b925060c0890135613d5481613b59565b915060e0890135613d6481613b59565b809150509295985092959890939650565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415613dda57613dda613db0565b5060010190565b600060208284031215613df357600080fd5b5051919050565b600181811c90821680613e0e57607f821691505b602082108114156112d357634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6000604082018483526020604081850152818551808452606086019150828701935060005b81811015613e8f5784516001600160a01b031683529383019391830191600101613e6a565b5090979650505050505050565b604051610120810167ffffffffffffffff81118282101715613ec057613ec0613e2f565b60405290565b604051610100810167ffffffffffffffff81118282101715613ec057613ec0613e2f565b604051601f8201601f1916810167ffffffffffffffff81118282101715613f1357613f13613e2f565b604052919050565b600067ffffffffffffffff821115613f3557613f35613e2f565b5060051b60200190565b60006020808385031215613f5257600080fd5b825167ffffffffffffffff811115613f6957600080fd5b8301601f81018513613f7a57600080fd5b8051613f8d613f8882613f1b565b613eea565b81815260059190911b82018301908381019087831115613fac57600080fd5b928401925b8284101561386b57835182529284019290840190613fb1565b600082821015613fdc57613fdc613db0565b500390565b600060208284031215613ff357600080fd5b815167ffffffffffffffff8082111561400b57600080fd5b818401915084601f83011261401f57600080fd5b81518181111561403157614031613e2f565b614044601f8201601f1916602001613eea565b915080825285602082850101111561405b57600080fd5b61406c816020840160208601613b8b565b50949350505050565b6c5374726174656779416e676c6560981b81526000825161409d81600d850160208701613b8b565b91909101600d0192915050565b6000602082840312156140bc57600080fd5b8151612f1a81613b59565b60008160001904831182151516156140e1576140e1613db0565b500290565b60008261410357634e487b7160e01b600052601260045260246000fd5b500490565b6000821982111561411b5761411b613db0565b500190565b6000610120828403121561413357600080fd5b61413b613e9c565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b805167ffffffffffffffff811681146141b357600080fd5b919050565b600082601f8301126141c957600080fd5b815160206141d9613f8883613f1b565b82815260059290921b840181019181810190868411156141f857600080fd5b8286015b8481101561421a5761420d8161419b565b83529183019183016141fc565b509695505050505050565b6000610100828403121561423857600080fd5b614240613ec6565b9050815167ffffffffffffffff8082111561425a57600080fd5b614266858386016141b8565b8352602084015191508082111561427c57600080fd5b614288858386016141b8565b602084015260408401519150808211156142a157600080fd5b6142ad858386016141b8565b604084015260608401519150808211156142c657600080fd5b506142d3848285016141b8565b6060830152506142e56080830161419b565b60808201526142f660a0830161419b565b60a082015261430760c0830161419b565b60c082015260e082015160e082015292915050565b6000806000806000806000806000898b0361020081121561433c57600080fd5b8a5161434781613b59565b60208c0151909a5061435881613b59565b60408c015190995061436981613b59565b60608c015190985061437a81613b59565b8097505060808b0151955060a08b0151945060c08b015193506101008060df19830112156143a757600080fd5b6143af613ec6565b60e08d01518152908c015160208201526101208c015160408201526101408c0151606082015290506143e46101608c0161419b565b60808201526143f66101808c0161419b565b60a08201526144086101a08c0161419b565b60c082015261441a6101c08c0161419b565b60e08201526101e08b015190925067ffffffffffffffff81111561443d57600080fd5b6144498c828d01614225565b9150509295985092959850929598565b60006020828403121561446b57600080fd5b8151612f1a81613bea565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600082516144b7818460208701613b8b565b919091019291505056fea264697066735822122038ade064d40806c4f767c679d4faf67ab3ef3befc52c80566e1c19df83080acc64736f6c634300080c0033000000000000000000000000a354f35829ae975e850e23e9615b11da1b3dc4de0000000000000000000000009c215206da4bf108ae5aeef9da7cad3352a36dad00000000000000000000000051fe22abaf4a26631b2913e417c0560d547797a7000000000000000000000000e9f183fc656656f1f17af1f2b0df79b8ff9ad8ed0000000000000000000000007a93f294898385f1df93cd8d081e94525fdd2e50
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106104285760003560e01c80636d51a20f1161022b578063b69af17211610130578063e5e19b4a116100b8578063efbb5cb011610087578063efbb5cb0146108ae578063f017c92f146108b6578063fbfa77cf146108c9578063fcf2d0ad146108dc578063fd967f47146108e457600080fd5b8063e5e19b4a1461086d578063eace9f2614610880578063ec38a86214610888578063ed882c2b1461089b57600080fd5b8063ce5494bb116100ff578063ce5494bb1461081c578063d96db2c21461082f578063dc4c90d31461084a578063e1cc58441461085d578063e300aff41461086557600080fd5b8063b69af172146107d5578063c1a3d44c146107e8578063c7b9d530146107f0578063cb14cd0a1461080357600080fd5b806391397ab4116101b3578063aa5480cf11610182578063aa5480cf1461077b578063ac00ff2614610784578063aced166114610797578063b18925af146107aa578063b252720b146107bd57600080fd5b806391397ab41461073157806395e80c50146107445780639ec5a8941461074d578063a6be02cb1461076057600080fd5b8063780022a0116101fa578063780022a0146106f55780638a29e2de146107065780638cdfe166146107195780638dddbe17146107225780638e6350e21461072a57600080fd5b80636d51a20f146106b55780636f392ce7146106bd578063748747e6146106cf578063750521f5146106e257600080fd5b80633569cb791161033157806346f6bbb7116102b9578063613ba8e711610288578063613ba8e71461065e57806361d027b314610666578063650d18801461068157806365210942146106955780636718835f146106a857600080fd5b806346f6bbb7146106225780635641ec03146106355780635e007a09146106425780635fbeb25f1461065557600080fd5b80633b7c6e2f116103005780633b7c6e2f146105e65780633fc8cef3146105ef5780634262f98e1461060a578063440368a3146106125780634641257d1461061a57600080fd5b80633569cb79146105af578063372500ab146105b857806339a172a8146105c057806339e24173146105d357600080fd5b80631d12f28b116103b4578063257ae0de11610383578063257ae0de1461053c578063258294101461055757806328b7ccf7146105785780632e1a7d4d146105815780632f48ab7d1461059457600080fd5b80631d12f28b146104dd5780631f1fcd51146104e65780631fe4a6861461051157806322f3e2d41461052457600080fd5b80630ada4dab116103fb5780630ada4dab1461047e5780630eed6485146104915780630f969b87146104a457806311bc8245146104b7578063146b8de0146104ca57600080fd5b806301681a621461042d57806303ee438c1461044257806306cfb3c01461046057806306fdde0314610476575b600080fd5b61044061043b366004613b6e565b6108ed565b005b61044a610acd565b6040516104579190613bb7565b60405180910390f35b610468610b5b565b604051908152602001610457565b61044a610d9e565b61044061048c366004613bf8565b610e34565b61044061049f366004613c15565b610f11565b6104406104b2366004613c41565b610fe9565b6104406104c5366004613b6e565b611072565b6104686104d8366004613c41565b6111a0565b610468600a5481565b6006546104f9906001600160a01b031681565b6040516001600160a01b039091168152602001610457565b6003546104f9906001600160a01b031681565b61052c6111d7565b6040519015158152602001610457565b6104f973d9e1ce17f2641f24ae83637ab66a2cca9c378b9f81565b604080518082019091526005815264302e342e3360d81b602082015261044a565b61046860085481565b61046861058f366004613c41565b611265565b6104f973dac17f958d2ee523a2206206994597c13d831ec781565b610468600c5481565b6104406112d9565b6104406105ce366004613c41565b61140c565b6104686105e1366004613c41565b61148e565b61046860125481565b6104f973c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6104686114b5565b61044061154d565b610440611749565b600e546104f9906001600160a01b031681565b600b5461052c9060ff1681565b610440610650366004613c41565b611c03565b61046860115481565b610468611d35565b6104f97393a62da5a14c80f265dabc077fcee437b1a0efde81565b61052c61068f366004613c41565b50600090565b6104406106a3366004613b6e565b611d42565b60015461052c9060ff1681565b610440611e52565b600b5461052c90610100900460ff1681565b6104406106dd366004613b6e565b611fcb565b6104406106f0366004613c5a565b612079565b610468610703366004613c41565b90565b610440610714366004613ccc565b612110565b61046860095481565b6104686121d5565b6000610468565b61044061073f366004613c41565b612250565b61046860075481565b6004546104f9906001600160a01b031681565b6104f97331429d1856ad1377a8a0079410b297e1a9e214c281565b61046860135481565b610440610792366004613bf8565b6122d2565b6005546104f9906001600160a01b031681565b600d546104f9906001600160a01b031681565b6001546104f99061010090046001600160a01b031681565b6104f96107e3366004613ccc565b6123e4565b610468612548565b6104406107fe366004613b6e565b612579565b600b546104f9906201000090046001600160a01b031681565b61044061082a366004613b6e565b612627565b6104f9735addc89785d75c86ab939e9e15bfbbb7fc086a8781565b600f546104f9906001600160a01b031681565b610468612749565b610468612783565b6010546104f9906001600160a01b031681565b6104686127c1565b610440610896366004613b6e565b6127ce565b61052c6108a9366004613c41565b61296c565b610468612b04565b6104406108c4366004613c41565b612b32565b6002546104f9906001600160a01b031681565b610440612bb4565b61046861271081565b6108f5612f21565b6001600160a01b0316336001600160a01b03161461092e5760405162461bcd60e51b815260040161092590613d75565b60405180910390fd5b6006546001600160a01b03828116911614156109745760405162461bcd60e51b8152602060048201526005602482015264085dd85b9d60da1b6044820152606401610925565b6002546001600160a01b03828116911614156109bc5760405162461bcd60e51b81526020600482015260076024820152662173686172657360c81b6044820152606401610925565b606060005b8151811015610a44578181815181106109dc576109dc613d9a565b60200260200101516001600160a01b0316836001600160a01b03161415610a325760405162461bcd60e51b815260206004820152600a602482015269085c1c9bdd1958dd195960b21b6044820152606401610925565b80610a3c81613dc6565b9150506109c1565b50610ac9610a50612f21565b6040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa158015610a94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab89190613de1565b6001600160a01b0385169190612f8f565b5050565b60008054610ada90613dfa565b80601f0160208091040260200160405190810160405280929190818152602001828054610b0690613dfa565b8015610b535780601f10610b2857610100808354040283529160200191610b53565b820191906000526020600020905b815481529060010190602001808311610b3657829003601f168201915b505050505081565b60408051600380825260808201909252600091829190602082016060803683370190505090507331429d1856ad1377a8a0079410b297e1a9e214c281600081518110610ba957610ba9613d9a565b60200260200101906001600160a01b031690816001600160a01b03168152505073c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110610bf157610bf1613d9a565b60200260200101906001600160a01b031690816001600160a01b03168152505073dac17f958d2ee523a2206206994597c13d831ec781600281518110610c3957610c39613d9a565b6001600160a01b039283166020918202929092010152600e54604051630cff5bdd60e21b81523060048201527331429d1856ad1377a8a0079410b297e1a9e214c2602482015260009291909116906333fd6f7490604401602060405180830381865afa158015610cad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd19190613de1565b9050670de0b6b3a7640000811015610cec5760009250505090565b60405163d06ca61f60e01b815260009073d9e1ce17f2641f24ae83637ab66a2cca9c378b9f9063d06ca61f90610d289085908790600401613e45565b600060405180830381865afa158015610d45573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d6d9190810190613f3f565b90508060018251610d7e9190613fca565b81518110610d8e57610d8e613d9a565b6020026020010151935050505090565b600654604080516395d89b4160e01b815290516060926001600160a01b0316916395d89b419160048083019260009291908290030181865afa158015610de8573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610e109190810190613fe1565b604051602001610e209190614075565b604051602081830303815290604052905090565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eab91906140aa565b6001600160a01b0316336001600160a01b03161480610ee25750610ecd612f21565b6001600160a01b0316336001600160a01b0316145b610efe5760405162461bcd60e51b815260040161092590613d75565b6014805460ff1916911515919091179055565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8891906140aa565b6001600160a01b0316336001600160a01b03161480610fbf5750610faa612f21565b6001600160a01b0316336001600160a01b0316145b610fdb5760405162461bcd60e51b815260040161092590613d75565b601192909255601255601355565b6003546001600160a01b031633148061101a5750611005612f21565b6001600160a01b0316336001600160a01b0316145b6110365760405162461bcd60e51b815260040161092590613d75565b600a8190556040518181527fa68ba126373d04c004c5748c300c9fca12bd444b3d4332e261f3bd2bac4a8600906020015b60405180910390a150565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110e991906140aa565b6001600160a01b0316336001600160a01b03161480611120575061110b612f21565b6001600160a01b0316336001600160a01b0316145b61113c5760405162461bcd60e51b815260040161092590613d75565b6040516001600160a01b03821681527fc8db9c35f716b87af1fbb83f03c78646061931269301fd7ba6dcf189b4cdc2fc9060200160405180910390a1600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b60006111aa6114b5565b6111bc83670de0b6b3a76400006140c7565b6111c691906140e6565b6111d1906001614108565b92915050565b6002546040516339ebf82360e01b815230600482015260009182916001600160a01b03909116906339ebf8239060240161012060405180830381865afa158015611225573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112499190614120565b6040015111806112605750600061125e612b04565b115b905090565b6002546000906001600160a01b031633146112ab5760405162461bcd60e51b8152602060048201526006602482015265085d985d5b1d60d21b6044820152606401610925565b60006112b683612fbf565b6006549093509091506112d3906001600160a01b03163383612f8f565b50919050565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561132c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061135091906140aa565b6001600160a01b0316336001600160a01b031614806113875750611372612f21565b6001600160a01b0316336001600160a01b0316145b6113a35760405162461bcd60e51b815260040161092590613d75565b600b54600e54604051633bd73ee360e21b81526001600160a01b03918216600482015262010000909204169063ef5cfb8c90602401600060405180830381600087803b1580156113f257600080fd5b505af1158015611406573d6000803e3d6000fd5b50505050565b6003546001600160a01b031633148061143d5750611428612f21565b6001600160a01b0316336001600160a01b0316145b6114595760405162461bcd60e51b815260040161092590613d75565b60078190556040518181527fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b190602001611067565b6000670de0b6b3a76400006114a16114b5565b6114ab90846140c7565b6111d191906140e6565b600f5460405163ba8b722360e01b81526001600160a01b0390911660048201526000908190735addc89785d75c86ab939e9e15bfbbb7fc086a879063ba8b722390602401600060405180830381865afa158015611516573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261153e919081019061431c565b50919998505050505050505050565b6005546001600160a01b031633148061157057506003546001600160a01b031633145b80611593575061157e612f21565b6001600160a01b0316336001600160a01b0316145b806116255750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161091906140aa565b6001600160a01b0316336001600160a01b0316145b806116b75750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561167e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116a291906140aa565b6001600160a01b0316336001600160a01b0316145b6116d35760405162461bcd60e51b815260040161092590613d75565b6002546040805163bf3759b560e01b81529051611747926001600160a01b03169163bf3759b59160048083019260209291908290030181865afa15801561171e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117429190613de1565b61302b565b565b6005546001600160a01b031633148061176c57506003546001600160a01b031633145b8061178f575061177a612f21565b6001600160a01b0316336001600160a01b0316145b806118215750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117e8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061180c91906140aa565b6001600160a01b0316336001600160a01b0316145b806118b35750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561187a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061189e91906140aa565b6001600160a01b0316336001600160a01b0316145b6118cf5760405162461bcd60e51b815260040161092590613d75565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611927573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061194b9190613de1565b600b5490915060009060ff16156119a85760006119666132d3565b9050828110156119815761197a8184613fca565b9350611996565b82811115611996576119938382613fca565b94505b6119a08484613fca565b9150506119b9565b6119b1826132e5565b919550935090505b6002546040516339ebf82360e01b81523060048201526000916001600160a01b0316906339ebf8239060240161012060405180830381865afa158015611a03573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a279190614120565b60c001516002546040516328766ebf60e21b81526004810188905260248101879052604481018590529192506001600160a01b03169063a1d9bafc906064016020604051808303816000875af1158015611a85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aa99190613de1565b9250611ab48361302b565b60015460ff168015611ad5575060015461010090046001600160a01b031615155b15611ba75760015460405163c70fa00b60e01b815260048101879052602481018690526044810184905260648101859052608481018390526101009091046001600160a01b03169063c70fa00b9060a401602060405180830381865afa158015611b43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b679190614459565b611ba25760405162461bcd60e51b815260206004820152600c60248201526b216865616c7468636865636b60a01b6044820152606401610925565b611bb4565b6001805460ff1916811790555b6040805186815260208101869052908101839052606081018490527f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d5099060800160405180910390a15050505050565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c7a91906140aa565b6001600160a01b0316336001600160a01b03161480611cb15750611c9c612f21565b6001600160a01b0316336001600160a01b0316145b611ccd5760405162461bcd60e51b815260040161092590613d75565b612710811115611d305760405162461bcd60e51b815260206004820152602860248201527f5f70657263656e744b6565702063616e2774206265206c61726765722074686160448201526706e2031302c3030360c41b6064820152608401610925565b600c55565b60006112606105e1612783565b611d4a612f21565b6001600160a01b0316336001600160a01b031614611d7a5760405162461bcd60e51b815260040161092590613d75565b6010546001600160a01b031615611d9357611d93613402565b611db47331429d1856ad1377a8a0079410b297e1a9e214c282600019612dbb565b600654604051632642a09360e11b81527331429d1856ad1377a8a0079410b297e1a9e214c260048201526001600160a01b0391821660248201528291821690634c85412690604401600060405180830381600087803b158015611e1657600080fd5b505af1158015611e2a573d6000803e3d6000fd5b5050601080546001600160a01b0319166001600160a01b039590951694909417909355505050565b6003546001600160a01b0316331480611e835750611e6e612f21565b6001600160a01b0316336001600160a01b0316145b80611f155750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa158015611edc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f0091906140aa565b6001600160a01b0316336001600160a01b0316145b80611fa75750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f6e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f9291906140aa565b6001600160a01b0316336001600160a01b0316145b611fc35760405162461bcd60e51b815260040161092590613d75565b611747613402565b6003546001600160a01b0316331480611ffc5750611fe7612f21565b6001600160a01b0316336001600160a01b0316145b6120185760405162461bcd60e51b815260040161092590613d75565b6001600160a01b03811661202b57600080fd5b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe715490602001611067565b6003546001600160a01b03163314806120aa5750612095612f21565b6001600160a01b0316336001600160a01b0316145b6120c65760405162461bcd60e51b815260040161092590613d75565b6120d260008383613ac0565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda68282604051612104929190614476565b60405180910390a15050565b61211c88888888613441565b600d80546001600160a01b03199081166001600160a01b0380881691909117909255600e80548216838716179055600f8054909116828516179055600b805462010000600160b01b03191662010000928416929092029190911790556103e8600c55600180546001600160a81b03191674ddcea799ff1699e98edf118e0629a974df7df01201179055621baf8060085563773594006011556402540be40060125569d3c21bcecceda10000006013555050505050505050565b600b54600e5460405163682ee1e560e01b81526001600160a01b0391821660048201526000926201000090049091169063682ee1e5906024015b602060405180830381865afa15801561222c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112609190613de1565b6003546001600160a01b0316331480612281575061226c612f21565b6001600160a01b0316336001600160a01b0316145b61229d5760405162461bcd60e51b815260040161092590613d75565b60098190556040518181527fd94596337df4c2f0f44d30a7fc5db1c7bb60d9aca4185ed77c6fd96eb45ec29890602001611067565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015612325573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061234991906140aa565b6001600160a01b0316336001600160a01b03161480612380575061236b612f21565b6001600160a01b0316336001600160a01b0316145b61239c5760405162461bcd60e51b815260040161092590613d75565b60405181151581527ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b9060200160405180910390a16001805460ff1916911515919091179055565b600b54600090610100900460ff166124275760405162461bcd60e51b815260206004820152600660248201526521636c6f6e6560d01b6044820152606401610925565b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81523060601b601482018190526e5af43d82803e903d91602b57fd5bf360881b6028830152906037816000f0604051634514f16f60e11b81526001600160a01b038d811660048301528c811660248301528b811660448301528a81166064830152898116608483015288811660a483015287811660c483015286811660e48301529194509084169150638a29e2de9061010401600060405180830381600087803b1580156124ef57600080fd5b505af1158015612503573d6000803e3d6000fd5b50506040516001600160a01b03851692507f783540fb4221a3238720dc7038937d0d79982bcf895274aa6ad179f82cf0d53c9150600090a25098975050505050505050565b6006546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a082319060240161220f565b6003546001600160a01b03163314806125aa5750612595612f21565b6001600160a01b0316336001600160a01b0316145b6125c65760405162461bcd60e51b815260040161092590613d75565b6001600160a01b0381166125d957600080fd5b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b490602001611067565b6002546001600160a01b0316331461263e57600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf9160048083019260209291908290030181865afa15801561268a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ae91906140aa565b6001600160a01b0316146126c157600080fd5b6006546040516370a0823160e01b81523060048201526127469183916001600160a01b03909116906370a0823190602401602060405180830381865afa15801561270f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127339190613de1565b6006546001600160a01b03169190612f8f565b50565b6040516370a0823160e01b81523060048201526000907331429d1856ad1377a8a0079410b297e1a9e214c2906370a082319060240161220f565b600b54600d546040516305df477360e51b81526001600160a01b0391821660048201526000926201000090049091169063bbe8ee609060240161220f565b60006112606105e16121d5565b6003546001600160a01b031633146128165760405162461bcd60e51b815260206004820152600b60248201526a085cdd1c985d1959da5cdd60aa1b6044820152606401610925565b6001600160a01b03811661282957600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b0391821692810192909252600060248301529091169063095ea7b3906044016020604051808303816000875af1158015612882573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128a69190614459565b50600480546001600160a01b0319166001600160a01b03838116918217835560025460405163095ea7b360e01b8152938401929092526000196024840152169063095ea7b3906044016020604051808303816000875af115801561290e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129329190614459565b506040516001600160a01b03821681527fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a06990602001611067565b60006129766111d7565b61298257506000919050565b600061298c610b5b565b90506012548111156129a15750600192915050565b6129a9613604565b6129b65750600092915050565b60145460ff16156129ca5750600192915050565b6011548111156129dd5750600192915050565b6002546040516339ebf82360e01b81523060048201526000916001600160a01b0316906339ebf8239060240161012060405180830381865afa158015612a27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a4b9190614120565b90506008548160a0015142612a609190613fca565b1115612a70575060019392505050565b601354600260009054906101000a90046001600160a01b03166001600160a01b031663112c1f9b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ac6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612aea9190613de1565b1115612afa575060019392505050565b5060009392505050565b6000612b0e611d35565b612b166127c1565b612b1e612548565b612b289190614108565b6112609190614108565b6003546001600160a01b0316331480612b635750612b4e612f21565b6001600160a01b0316336001600160a01b0316145b612b7f5760405162461bcd60e51b815260040161092590613d75565b60088190556040518181527f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c590602001611067565b6003546001600160a01b0316331480612be55750612bd0612f21565b6001600160a01b0316336001600160a01b0316145b80612c775750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c6291906140aa565b6001600160a01b0316336001600160a01b0316145b80612d095750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015612cd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cf491906140aa565b6001600160a01b0316336001600160a01b0316145b612d255760405162461bcd60e51b815260040161092590613d75565b600b805460ff191660011790556002546040805163507257cd60e11b815290516001600160a01b039092169163a0e4af9a9160048082019260009290919082900301818387803b158015612d7857600080fd5b505af1158015612d8c573d6000803e3d6000fd5b50506040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b925060009150a1565b801580612e355750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612e0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e339190613de1565b155b612ea05760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610925565b6040516001600160a01b038316602482015260448101829052612f0390849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261367c565b505050565b6060612f17848460008561374e565b90505b9392505050565b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e6759160048083019260209291908290030181865afa158015612f6b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061126091906140aa565b6040516001600160a01b038316602482015260448101829052612f0390849063a9059cbb60e01b90606401612ecc565b600080612fd383612fce612b04565b613876565b92506000612fdf612548565b90508381101561300657612ffb612ff68286613fca565b61388c565b613003612548565b90505b83811061301557839250613025565b9150816130228185613fca565b91505b50915091565b600b5460ff16156130395750565b600b54600e54604051633bd73ee360e21b81526001600160a01b03918216600482015262010000909204169063ef5cfb8c90602401600060405180830381600087803b15801561308857600080fd5b505af115801561309c573d6000803e3d6000fd5b5050505060006130aa612749565b905080156131e6576000612710600c54836130c591906140c7565b6130cf91906140e6565b905080156131e4577331429d1856ad1377a8a0079410b297e1a9e214c26001600160a01b031663a9059cbb600b60029054906101000a90046001600160a01b03166001600160a01b031663e6b59dc06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561314d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061317191906140aa565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602481018490526044016020604051808303816000875af11580156131be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131e29190614459565b505b505b60006131f0612548565b9050808311156131ff57505050565b600061320b8483613fca565b9050801561324057600b54600654613237916001600160a01b0391821691620100009091041683612f8f565b6132408161397d565b600061324a612783565b905080156132cc57600b54600e54600d5460405163294091cd60e01b81526001600160a01b03928316600482015260248101859052908216604482015262010000909204169063294091cd90606401600060405180830381600087803b1580156132b357600080fd5b505af11580156132c7573d6000803e3d6000fd5b505050505b5050505050565b60006112d36132e0612b04565b612fbf565b6000806000806132f3612b04565b6002546040516339ebf82360e01b81523060048201529192506000916001600160a01b03909116906339ebf8239060240161012060405180830381865afa158015613342573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133669190614120565b60c0015190508082106133845761337d8183613fca565b9450613391565b61338e8282613fca565b93505b6000806133a16132e0888a614108565b90925090506133b08187614108565b95506133bc8883613876565b9450868611156133db576133d08787613fca565b9550600096506133ec565b6133e58688613fca565b9650600095505b50506014805460ff191690555092949193509150565b60105461342f907331429d1856ad1377a8a0079410b297e1a9e214c2906001600160a01b03166000612dbb565b601080546001600160a01b0319169055565b6006546001600160a01b03161561349a5760405162461bcd60e51b815260206004820152601c60248201527f537472617465677920616c726561647920696e697469616c697a6564000000006044820152606401610925565b600280546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a916004808201926020929091908290030181865afa1580156134f3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061351791906140aa565b600680546001600160a01b0319166001600160a01b039290921691821790556135439085600019612dbb565b600380546001600160a01b038581166001600160a01b03199283161790925560048054858416908316811782556005805486861694169390931790925560006007819055620151806008556064600955600a5560025460405163095ea7b360e01b815291820192909252600019602482015291169063095ea7b3906044016020604051808303816000875af11580156135e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132cc9190614459565b600073b5e1cacb567d98faadb60a1fd4820720141f064f6001600160a01b03166334a9e75c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613658573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112609190614459565b60006136d1826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316612f089092919063ffffffff16565b805190915015612f0357808060200190518101906136ef9190614459565b612f035760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610925565b6060824710156137af5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610925565b843b6137fd5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610925565b600080866001600160a01b0316858760405161381991906144a5565b60006040518083038185875af1925050503d8060008114613856576040519150601f19603f3d011682016040523d82523d6000602084013e61385b565b606091505b509150915061386b828286613a17565b979650505050505050565b60008183106138855781612f1a565b5090919050565b6000613897826111a0565b905060006138a3612783565b905080821115613974576138c26138ba8284613fca565b612fce6121d5565b600b54600e54600d54604051636ce5768960e11b81526001600160a01b03928316600482015290821660248201526044810184905292945062010000909104169063d9caed12906064016020604051808303816000875af115801561392b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061394f9190613de1565b50600b54600d54613974916001600160a01b0391821691620100009091041684612f8f565b612f0382613a50565b600b54600f54600654600e54604051631cf68e9f60e01b8152735addc89785d75c86ab939e9e15bfbbb7fc086a876004820152602481018690526001600160a01b039384166044820152918316606483015282166084820152620100009092041690631cf68e9f9060a4015b600060405180830381600087803b158015613a0357600080fd5b505af11580156132cc573d6000803e3d6000fd5b60608315613a26575081612f1a565b825115613a365782518084602001fd5b8160405162461bcd60e51b81526004016109259190613bb7565b600b54600f54600d54600e5460405163d471370560e01b8152735addc89785d75c86ab939e9e15bfbbb7fc086a876004820152602481018690526001600160a01b03938416604482015291831660648301528216608482015262010000909204169063d47137059060a4016139e9565b828054613acc90613dfa565b90600052602060002090601f016020900481019282613aee5760008555613b34565b82601f10613b075782800160ff19823516178555613b34565b82800160010185558215613b34579182015b82811115613b34578235825591602001919060010190613b19565b50613b40929150613b44565b5090565b5b80821115613b405760008155600101613b45565b6001600160a01b038116811461274657600080fd5b600060208284031215613b8057600080fd5b8135612f1a81613b59565b60005b83811015613ba6578181015183820152602001613b8e565b838111156114065750506000910152565b6020815260008251806020840152613bd6816040850160208701613b8b565b601f01601f19169190910160400192915050565b801515811461274657600080fd5b600060208284031215613c0a57600080fd5b8135612f1a81613bea565b600080600060608486031215613c2a57600080fd5b505081359360208301359350604090920135919050565b600060208284031215613c5357600080fd5b5035919050565b60008060208385031215613c6d57600080fd5b823567ffffffffffffffff80821115613c8557600080fd5b818501915085601f830112613c9957600080fd5b813581811115613ca857600080fd5b866020828501011115613cba57600080fd5b60209290920196919550909350505050565b600080600080600080600080610100898b031215613ce957600080fd5b8835613cf481613b59565b97506020890135613d0481613b59565b96506040890135613d1481613b59565b95506060890135613d2481613b59565b94506080890135613d3481613b59565b935060a0890135613d4481613b59565b925060c0890135613d5481613b59565b915060e0890135613d6481613b59565b809150509295985092959890939650565b6020808252600b908201526a08585d5d1a1bdc9a5e995960aa1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415613dda57613dda613db0565b5060010190565b600060208284031215613df357600080fd5b5051919050565b600181811c90821680613e0e57607f821691505b602082108114156112d357634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6000604082018483526020604081850152818551808452606086019150828701935060005b81811015613e8f5784516001600160a01b031683529383019391830191600101613e6a565b5090979650505050505050565b604051610120810167ffffffffffffffff81118282101715613ec057613ec0613e2f565b60405290565b604051610100810167ffffffffffffffff81118282101715613ec057613ec0613e2f565b604051601f8201601f1916810167ffffffffffffffff81118282101715613f1357613f13613e2f565b604052919050565b600067ffffffffffffffff821115613f3557613f35613e2f565b5060051b60200190565b60006020808385031215613f5257600080fd5b825167ffffffffffffffff811115613f6957600080fd5b8301601f81018513613f7a57600080fd5b8051613f8d613f8882613f1b565b613eea565b81815260059190911b82018301908381019087831115613fac57600080fd5b928401925b8284101561386b57835182529284019290840190613fb1565b600082821015613fdc57613fdc613db0565b500390565b600060208284031215613ff357600080fd5b815167ffffffffffffffff8082111561400b57600080fd5b818401915084601f83011261401f57600080fd5b81518181111561403157614031613e2f565b614044601f8201601f1916602001613eea565b915080825285602082850101111561405b57600080fd5b61406c816020840160208601613b8b565b50949350505050565b6c5374726174656779416e676c6560981b81526000825161409d81600d850160208701613b8b565b91909101600d0192915050565b6000602082840312156140bc57600080fd5b8151612f1a81613b59565b60008160001904831182151516156140e1576140e1613db0565b500290565b60008261410357634e487b7160e01b600052601260045260246000fd5b500490565b6000821982111561411b5761411b613db0565b500190565b6000610120828403121561413357600080fd5b61413b613e9c565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b805167ffffffffffffffff811681146141b357600080fd5b919050565b600082601f8301126141c957600080fd5b815160206141d9613f8883613f1b565b82815260059290921b840181019181810190868411156141f857600080fd5b8286015b8481101561421a5761420d8161419b565b83529183019183016141fc565b509695505050505050565b6000610100828403121561423857600080fd5b614240613ec6565b9050815167ffffffffffffffff8082111561425a57600080fd5b614266858386016141b8565b8352602084015191508082111561427c57600080fd5b614288858386016141b8565b602084015260408401519150808211156142a157600080fd5b6142ad858386016141b8565b604084015260608401519150808211156142c657600080fd5b506142d3848285016141b8565b6060830152506142e56080830161419b565b60808201526142f660a0830161419b565b60a082015261430760c0830161419b565b60c082015260e082015160e082015292915050565b6000806000806000806000806000898b0361020081121561433c57600080fd5b8a5161434781613b59565b60208c0151909a5061435881613b59565b60408c015190995061436981613b59565b60608c015190985061437a81613b59565b8097505060808b0151955060a08b0151945060c08b015193506101008060df19830112156143a757600080fd5b6143af613ec6565b60e08d01518152908c015160208201526101208c015160408201526101408c0151606082015290506143e46101608c0161419b565b60808201526143f66101808c0161419b565b60a08201526144086101a08c0161419b565b60c082015261441a6101c08c0161419b565b60e08201526101e08b015190925067ffffffffffffffff81111561443d57600080fd5b6144498c828d01614225565b9150509295985092959850929598565b60006020828403121561446b57600080fd5b8151612f1a81613bea565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b600082516144b7818460208701613b8b565b919091019291505056fea264697066735822122038ade064d40806c4f767c679d4faf67ab3ef3befc52c80566e1c19df83080acc64736f6c634300080c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a354f35829ae975e850e23e9615b11da1b3dc4de0000000000000000000000009c215206da4bf108ae5aeef9da7cad3352a36dad00000000000000000000000051fe22abaf4a26631b2913e417c0560d547797a7000000000000000000000000e9f183fc656656f1f17af1f2b0df79b8ff9ad8ed0000000000000000000000007a93f294898385f1df93cd8d081e94525fdd2e50
-----Decoded View---------------
Arg [0] : _vault (address): 0xa354F35829Ae975e850e23e9615b11Da1B3dC4DE
Arg [1] : _sanToken (address): 0x9C215206Da4bf108aE5aEEf9dA7caD3352A36Dad
Arg [2] : _sanTokenGauge (address): 0x51fE22abAF4a26631b2913E417c0560D547797a7
Arg [3] : _poolManager (address): 0xe9f183FC656656f1F17af1F2b0dF79b8fF9ad8eD
Arg [4] : _strategyProxy (address): 0x7A93f294898385F1dF93cd8D081e94525fdd2e50
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000a354f35829ae975e850e23e9615b11da1b3dc4de
Arg [1] : 0000000000000000000000009c215206da4bf108ae5aeef9da7cad3352a36dad
Arg [2] : 00000000000000000000000051fe22abaf4a26631b2913e417c0560d547797a7
Arg [3] : 000000000000000000000000e9f183fc656656f1f17af1f2b0df79b8ff9ad8ed
Arg [4] : 0000000000000000000000007a93f294898385f1df93cd8d081e94525fdd2e50
Deployed Bytecode Sourcemap
111021:17387:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;65033:444;;;;;;:::i;:::-;;:::i;:::-;;36113:25;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;123515:599;;;:::i;:::-;;;1199:25:1;;;1187:2;1172:18;123515:599:0;1053:177:1;115679:276:0;;;:::i;124528:186::-;;;;;;:::i;:::-;;:::i;124979:321::-;;;;;;:::i;:::-;;:::i;46662:175::-;;;;;;:::i;:::-;;:::i;42132:162::-;;;;;;:::i;:::-;;:::i;126623:142::-;;;;;;:::i;:::-;;:::i;39465:28::-;;;;;;38140:18;;;;;-1:-1:-1;;;;;38140:18:0;;;;;;-1:-1:-1;;;;;2288:32:1;;;2270:51;;2258:2;2243:18;38140::0;2110:217:1;38049:25:0;;;;;-1:-1:-1;;;;;38049:25:0;;;50064:148;;;:::i;:::-;;;2705:14:1;;2698:22;2680:41;;2668:2;2653:18;50064:148:0;2540:187:1;111816:78:0;;111852:42;111816:78;;36512:91;36581:14;;;;;;;;;;;;-1:-1:-1;;;36581:14:0;;;;36512:91;;39101:29;;;;;;61437:515;;;;;;:::i;:::-;;:::i;111914:73::-;;111945:42;111914:73;;111604:26;;;;;;120976:120;;;:::i;44711:154::-;;;;;;:::i;:::-;;:::i;126439:176::-;;;;;;:::i;:::-;;:::i;112275:31::-;;;;;;111994:73;;112025:42;111994:73;;126831:208;;;:::i;55161:170::-;;;:::i;59622:1571::-;;;:::i;111666:32::-;;;;;-1:-1:-1;;;;;111666:32:0;;;39544:25;;;;;;;;;125308:241;;;;;;:::i;:::-;;:::i;112177:31::-;;;;;;126175:118;;;:::i;111705:77::-;;111740:42;111705:77;;54400:432;;;;;;:::i;:::-;-1:-1:-1;54473:4:0;;54400:432;127718:401;;;;;;:::i;:::-;;:::i;36169:25::-;;;;;;;;;128127:125;;;:::i;111173:29::-;;;;;;;;;;;;43462:174;;;;;;:::i;:::-;;:::i;47140:171::-;;;;;;:::i;:::-;;:::i;121581:153::-;;;;;;:::i;:::-;121717:9;121581:153;113945:489;;;;;;:::i;:::-;;:::i;39287:27::-;;;;;;125742:152;;;:::i;37919:94::-;37977:7;37919:94;;45936:169;;;;;;:::i;:::-;;:::i;38950:29::-;;;;;;38081:22;;;;;-1:-1:-1;;;;;38081:22:0;;;111211:86;;111254:42;111211:86;;112373:30;;;;;;42302:171;;;;;;:::i;:::-;;:::i;38110:21::-;;;;;-1:-1:-1;;;;;38110:21:0;;;111637:22;;;;;-1:-1:-1;;;;;111637:22:0;;;36201:26;;;;;;;;-1:-1:-1;;;;;36201:26:0;;;114442:1229;;;;;;:::i;:::-;;:::i;125624:110::-;;;:::i;42706:202::-;;;;;;:::i;:::-;;:::i;111418:44::-;;;;;;;;-1:-1:-1;;;;;111418:44:0;;;62724:281;;;;;;:::i;:::-;;:::i;111304:107::-;;111368:42;111304:107;;112074:26;;;;;-1:-1:-1;;;;;112074:26:0;;;126045:122;;;:::i;125902:135::-;;;:::i;112107:40::-;;;;;-1:-1:-1;;;;;112107:40:0;;;126301:130;;;:::i;43925:269::-;;;;;;:::i;:::-;;:::i;121829:1580::-;;;;;;:::i;:::-;;:::i;116022:158::-;;;:::i;45382:154::-;;;;;;:::i;:::-;;:::i;38021:21::-;;;;;-1:-1:-1;;;;;38021:21:0;;;63434:173;;;:::i;111471:39::-;;111505:5;111471:39;;65033:444;40170:12;:10;:12::i;:::-;-1:-1:-1;;;;;40156:26:0;:10;-1:-1:-1;;;;;40156:26:0;;40148:50;;;;-1:-1:-1;;;40148:50:0;;;;;;;:::i;:::-;;;;;;;;;65125:4:::1;::::0;-1:-1:-1;;;;;65107:23:0;;::::1;65125:4:::0;::::1;65107:23;;65099:41;;;::::0;-1:-1:-1;;;65099:41:0;;6038:2:1;65099:41:0::1;::::0;::::1;6020:21:1::0;6077:1;6057:18;;;6050:29;-1:-1:-1;;;6095:18:1;;;6088:35;6140:18;;65099:41:0::1;5836:328:1::0;65099:41:0::1;65177:5;::::0;-1:-1:-1;;;;;65159:24:0;;::::1;65177:5:::0;::::1;65159:24;;65151:44;;;::::0;-1:-1:-1;;;65151:44:0;;6371:2:1;65151:44:0::1;::::0;::::1;6353:21:1::0;6410:1;6390:18;;;6383:29;-1:-1:-1;;;6428:18:1;;;6421:37;6475:18;;65151:44:0::1;6169:330:1::0;65151:44:0::1;121548:16:::0;65208:33:::1;65272:102;65292:16;:23;65288:1;:27;65272:102;;;65340:16;65357:1;65340:19;;;;;;;;:::i;:::-;;;;;;;-1:-1:-1::0;;;;;65330:29:0::1;:6;-1:-1:-1::0;;;;;65330:29:0::1;;;65322:52;;;::::0;-1:-1:-1;;;65322:52:0;;6838:2:1;65322:52:0::1;::::0;::::1;6820:21:1::0;6877:2;6857:18;;;6850:30;-1:-1:-1;;;6896:18:1;;;6889:40;6946:18;;65322:52:0::1;6636:334:1::0;65322:52:0::1;65317:3:::0;::::1;::::0;::::1;:::i;:::-;;;;65272:102;;;;65387:82;65415:12;:10;:12::i;:::-;65429:39;::::0;-1:-1:-1;;;65429:39:0;;65462:4:::1;65429:39;::::0;::::1;2270:51:1::0;-1:-1:-1;;;;;65429:24:0;::::1;::::0;::::1;::::0;2243:18:1;;65429:39:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;65387:27:0;::::1;::::0;:82;:27:::1;:82::i;:::-;65088:389;65033:444:::0;:::o;36113:25::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;123515:599::-;123613:16;;;123627:1;123613:16;;;;;;;;;123569:7;;;;123613:16;;;;;;;;;;;-1:-1:-1;123613:16:0;123589:40;;111254:42;123640:4;123645:1;123640:7;;;;;;;;:::i;:::-;;;;;;:29;-1:-1:-1;;;;;123640:29:0;;;-1:-1:-1;;;;;123640:29:0;;;;;112025:42;123680:4;123685:1;123680:7;;;;;;;;:::i;:::-;;;;;;:14;-1:-1:-1;;;;;123680:14:0;;;-1:-1:-1;;;;;123680:14:0;;;;;111945:42;123705:4;123710:1;123705:7;;;;;;;;:::i;:::-;-1:-1:-1;;;;;123705:23:0;;;:7;;;;;;;;;:23;123769:13;;:66;;-1:-1:-1;;;123769:66:0;;123808:4;123769:66;;;8165:34:1;111254:42:0;8215:18:1;;;8208:43;123741:25:0;;123769:13;;;;;:30;;8100:18:1;;123769:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;123741:94;;123872:4;123852:17;:24;123848:79;;;123914:1;123907:8;;;;123515:599;:::o;123848:79::-;123966:93;;-1:-1:-1;;;123966:93:0;;123939:24;;111852:42;;123966:31;;:93;;124012:17;;124044:4;;123966:93;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;123966:93:0;;;;;;;;;;;;:::i;:::-;123939:120;;124079:7;124104:1;124087:7;:14;:18;;;;:::i;:::-;124079:27;;;;;;;;:::i;:::-;;;;;;;124072:34;;;;;123515:599;:::o;115679:276::-;115898:4;;115875:38;;;-1:-1:-1;;;115875:38:0;;;;115727:13;;-1:-1:-1;;;;;115898:4:0;;115875:36;;:38;;;;;115898:4;;115875:38;;;;;;;115898:4;115875:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;115875:38:0;;;;;;;;;;;;:::i;:::-;115798:134;;;;;;;;:::i;:::-;;;;;;;;;;;;;115753:194;;115679:276;:::o;124528:186::-;40627:5;;;;;;;;;-1:-1:-1;;;;;40627:5:0;-1:-1:-1;;;;;40627:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;40613:32:0;:10;-1:-1:-1;;;;;40613:32:0;;:62;;;;40663:12;:10;:12::i;:::-;-1:-1:-1;;;;;40649:26:0;:10;-1:-1:-1;;;;;40649:26:0;;40613:62;40605:86;;;;-1:-1:-1;;;40605:86:0;;;;;;;:::i;:::-;124656:23:::1;:50:::0;;-1:-1:-1;;124656:50:0::1;::::0;::::1;;::::0;;;::::1;::::0;;124528:186::o;124979:321::-;40627:5;;;;;;;;;-1:-1:-1;;;;;40627:5:0;-1:-1:-1;;;;;40627:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;40613:32:0;:10;-1:-1:-1;;;;;40613:32:0;;:62;;;;40663:12;:10;:12::i;:::-;-1:-1:-1;;;;;40649:26:0;:10;-1:-1:-1;;;;;40649:26:0;;40613:62;40605:86;;;;-1:-1:-1;;;40605:86:0;;;;;;;:::i;:::-;125164:16:::1;:36:::0;;;;125211:16:::1;:36:::0;125258:15:::1;:34:::0;124979:321::o;46662:175::-;39655:10;;-1:-1:-1;;;;;39655:10:0;39641;:24;;:54;;;39683:12;:10;:12::i;:::-;-1:-1:-1;;;;;39669:26:0;:10;-1:-1:-1;;;;;39669:26:0;;39641:54;39633:78;;;;-1:-1:-1;;;39633:78:0;;;;;;;:::i;:::-;46747:13:::1;:30:::0;;;46793:36:::1;::::0;1199:25:1;;;46793:36:0::1;::::0;1187:2:1;1172:18;46793:36:0::1;;;;;;;;46662:175:::0;:::o;42132:162::-;40627:5;;;;;;;;;-1:-1:-1;;;;;40627:5:0;-1:-1:-1;;;;;40627:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;40613:32:0;:10;-1:-1:-1;;;;;40613:32:0;;:62;;;;40663:12;:10;:12::i;:::-;-1:-1:-1;;;;;40649:26:0;:10;-1:-1:-1;;;;;40649:26:0;;40613:62;40605:86;;;;-1:-1:-1;;;40605:86:0;;;;;;;:::i;:::-;42221:28:::1;::::0;-1:-1:-1;;;;;2288:32:1;;2270:51;;42221:28:0::1;::::0;2258:2:1;2243:18;42221:28:0::1;;;;;;;42260:11;:26:::0;;-1:-1:-1;;;;;42260:26:0;;::::1;;;-1:-1:-1::0;;;;;;42260:26:0;;::::1;::::0;;;::::1;::::0;;42132:162::o;126623:142::-;126689:7;126740:12;:10;:12::i;:::-;126718:18;:11;126732:4;126718:18;:::i;:::-;126717:35;;;;:::i;:::-;126716:41;;126756:1;126716:41;:::i;:::-;126709:48;126623:142;-1:-1:-1;;126623:142:0:o;50064:148::-;50129:5;;:31;;-1:-1:-1;;;50129:31:0;;50154:4;50129:31;;;2270:51:1;50105:4:0;;;;-1:-1:-1;;;;;50129:5:0;;;;:16;;2243:18:1;;50129:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;;:45;:75;;;;50203:1;50178:22;:20;:22::i;:::-;:26;50129:75;50122:82;;50064:148;:::o;61437:515::-;61552:5;;61496:13;;-1:-1:-1;;;;;61552:5:0;61530:10;:28;61522:47;;;;-1:-1:-1;;;61522:47:0;;13920:2:1;61522:47:0;;;13902:21:1;13959:1;13939:18;;;13932:29;-1:-1:-1;;;13977:18:1;;;13970:36;14023:18;;61522:47:0;13718:329:1;61522:47:0;61655:19;61708:32;61726:13;61708:17;:32::i;:::-;61832:4;;61685:55;;-1:-1:-1;61685:55:0;;-1:-1:-1;61832:42:0;;-1:-1:-1;;;;;61832:4:0;61850:10;61685:55;61832:17;:42::i;:::-;61511:441;61437:515;;;:::o;120976:120::-;40627:5;;;;;;;;;-1:-1:-1;;;;;40627:5:0;-1:-1:-1;;;;;40627:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;40613:32:0;:10;-1:-1:-1;;;;;40613:32:0;;:62;;;;40663:12;:10;:12::i;:::-;-1:-1:-1;;;;;40649:26:0;:10;-1:-1:-1;;;;;40649:26:0;;40613:62;40605:86;;;;-1:-1:-1;;;40605:86:0;;;;;;;:::i;:::-;121038:13:::1;::::0;121073::::1;::::0;121038:50:::1;::::0;-1:-1:-1;;;121038:50:0;;-1:-1:-1;;;;;121073:13:0;;::::1;121038:50;::::0;::::1;2270:51:1::0;121038:13:0;;;::::1;;::::0;:26:::1;::::0;2243:18:1;;121038:50:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;120976:120::o:0;44711:154::-;39655:10;;-1:-1:-1;;;;;39655:10:0;39641;:24;;:54;;;39683:12;:10;:12::i;:::-;-1:-1:-1;;;;;39669:26:0;:10;-1:-1:-1;;;;;39669:26:0;;39641:54;39633:78;;;;-1:-1:-1;;;39633:78:0;;;;;;;:::i;:::-;44789:14:::1;:23:::0;;;44828:29:::1;::::0;1199:25:1;;;44828:29:0::1;::::0;1187:2:1;1172:18;44828:29:0::1;1053:177:1::0;126439:176:0;126536:7;126603:4;126587:12;:10;:12::i;:::-;126569:30;;:15;:30;:::i;:::-;126568:39;;;;:::i;126831:208::-;126991:11;;126944:59;;-1:-1:-1;;;126944:59:0;;-1:-1:-1;;;;;126991:11:0;;;126944:59;;;2270:51:1;126874:7:0;;;;111368:42;;126944:46;;2243:18:1;;126944:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;126944:59:0;;;;;;;;;;;;:::i;:::-;-1:-1:-1;126894:109:0;;126831:208;-1:-1:-1;;;;;;;;;126831:208:0:o;55161:170::-;40296:6;;-1:-1:-1;;;;;40296:6:0;40282:10;:20;;:65;;-1:-1:-1;40337:10:0;;-1:-1:-1;;;;;40337:10:0;40323;:24;40282:65;:112;;;;40382:12;:10;:12::i;:::-;-1:-1:-1;;;;;40368:26:0;:10;-1:-1:-1;;;;;40368:26:0;;40282:112;:163;;;;40429:5;;;;;;;;;-1:-1:-1;;;;;40429:5:0;-1:-1:-1;;;;;40429:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;40415:30:0;:10;-1:-1:-1;;;;;40415:30:0;;40282:163;:216;;;;40480:5;;;;;;;;;-1:-1:-1;;;;;40480:5:0;-1:-1:-1;;;;;40480:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;40466:32:0;:10;-1:-1:-1;;;;;40466:32:0;;40282:216;40260:277;;;;-1:-1:-1;;;40260:277:0;;;;;;;:::i;:::-;55299:5:::1;::::0;:23:::1;::::0;;-1:-1:-1;;;55299:23:0;;;;55284:39:::1;::::0;-1:-1:-1;;;;;55299:5:0::1;::::0;:21:::1;::::0;:23:::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;:5;:23:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;55284:14;:39::i;:::-;55161:170::o:0;59622:1571::-;40296:6;;-1:-1:-1;;;;;40296:6:0;40282:10;:20;;:65;;-1:-1:-1;40337:10:0;;-1:-1:-1;;;;;40337:10:0;40323;:24;40282:65;:112;;;;40382:12;:10;:12::i;:::-;-1:-1:-1;;;;;40368:26:0;:10;-1:-1:-1;;;;;40368:26:0;;40282:112;:163;;;;40429:5;;;;;;;;;-1:-1:-1;;;;;40429:5:0;-1:-1:-1;;;;;40429:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;40415:30:0;:10;-1:-1:-1;;;;;40415:30:0;;40282:163;:216;;;;40480:5;;;;;;;;;-1:-1:-1;;;;;40480:5:0;-1:-1:-1;;;;;40480:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;40466:32:0;:10;-1:-1:-1;;;;;40466:32:0;;40282:216;40260:277;;;;-1:-1:-1;;;40260:277:0;;;;;;;:::i;:::-;59673:14:::1;59702:12:::0;59729:23:::1;59755:5;;;;;;;;;-1:-1:-1::0;;;;;59755:5:0::1;-1:-1:-1::0;;;;;59755:21:0::1;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;59827:13;::::0;59729:49;;-1:-1:-1;59789:19:0::1;::::0;59827:13:::1;;59823:571;;;59909:19;59931:23;:21;:23::i;:::-;59909:45;;59987:15;59973:11;:29;59969:220;;;60030:29;60048:11:::0;60030:15;:29:::1;:::i;:::-;60023:36;;59969:220;;;60099:15;60085:11;:29;60081:108;;;60144:29;60158:15:::0;60144:11;:29:::1;:::i;:::-;60135:38;;60081:108;60217:22;60235:4:::0;60217:15;:22:::1;:::i;:::-;60203:36;;59842:409;59823:571;;;60352:30;60366:15;60352:13;:30::i;:::-;60322:60:::0;;-1:-1:-1;60322:60:0;-1:-1:-1;60322:60:0;-1:-1:-1;59823:571:0::1;60610:5;::::0;:31:::1;::::0;-1:-1:-1;;;60610:31:0;;60635:4:::1;60610:31;::::0;::::1;2270:51:1::0;60590:17:0::1;::::0;-1:-1:-1;;;;;60610:5:0::1;::::0;:16:::1;::::0;2243:18:1;;60610:31:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;::::0;60680:5:::1;::::0;:39:::1;::::0;-1:-1:-1;;;60680:39:0;;::::1;::::0;::::1;18305:25:1::0;;;18346:18;;;18339:34;;;18389:18;;;18382:34;;;60610:41:0;;-1:-1:-1;;;;;;60680:5:0::1;::::0;:12:::1;::::0;18278:18:1;;60680:39:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;60662:57;;60795:31;60810:15;60795:14;:31::i;:::-;60881:13;::::0;::::1;;:42:::0;::::1;;;-1:-1:-1::0;60898:11:0::1;::::0;::::1;::::0;::::1;-1:-1:-1::0;;;;;60898:11:0::1;:25:::0;::::1;60881:42;60877:238;;;60960:11;::::0;60948:85:::1;::::0;-1:-1:-1;;;60948:85:0;;::::1;::::0;::::1;18686:25:1::0;;;18727:18;;;18720:34;;;18770:18;;;18763:34;;;18813:18;;;18806:34;;;18856:19;;;18849:35;;;60960:11:0::1;::::0;;::::1;-1:-1:-1::0;;;;;60960:11:0::1;::::0;60948:30:::1;::::0;18658:19:1;;60948:85:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;60940:110;;;::::0;-1:-1:-1;;;60940:110:0;;19347:2:1;60940:110:0::1;::::0;::::1;19329:21:1::0;19386:2;19366:18;;;19359:30;-1:-1:-1;;;19405:18:1;;;19398:42;19457:18;;60940:110:0::1;19145:336:1::0;60940:110:0::1;60877:238;;;61099:4;61083:20:::0;;-1:-1:-1;;61083:20:0::1;::::0;::::1;::::0;;60877:238:::1;61132:53;::::0;;19717:25:1;;;19773:2;19758:18;;19751:34;;;19801:18;;;19794:34;;;19859:2;19844:18;;19837:34;;;61132:53:0::1;::::0;19704:3:1;19689:19;61132:53:0::1;;;;;;;59662:1531;;;;;59622:1571::o:0;125308:241::-;40627:5;;;;;;;;;-1:-1:-1;;;;;40627:5:0;-1:-1:-1;;;;;40627:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;40613:32:0;:10;-1:-1:-1;;;;;40613:32:0;;:62;;;;40663:12;:10;:12::i;:::-;-1:-1:-1;;;;;40649:26:0;:10;-1:-1:-1;;;;;40649:26:0;;40613:62;40605:86;;;;-1:-1:-1;;;40605:86:0;;;;;;;:::i;:::-;111505:5:::1;125413:12;:23;;125391:113;;;::::0;-1:-1:-1;;;125391:113:0;;20084:2:1;125391:113:0::1;::::0;::::1;20066:21:1::0;20123:2;20103:18;;;20096:30;20162:34;20142:18;;;20135:62;-1:-1:-1;;;20213:18:1;;;20206:38;20261:19;;125391:113:0::1;19882:404:1::0;125391:113:0::1;125515:11;:26:::0;125308:241::o;126175:118::-;126223:7;126250:35;126265:19;:17;:19::i;127718:401::-;40170:12;:10;:12::i;:::-;-1:-1:-1;;;;;40156:26:0;:10;-1:-1:-1;;;;;40156:26:0;;40148:50;;;;-1:-1:-1;;;40148:50:0;;;;;;;:::i;:::-;127805:12:::1;::::0;-1:-1:-1;;;;;127805:12:0::1;:26:::0;127801:91:::1;;127848:32;:30;:32::i;:::-;127902:56;111254:42;127925:13:::0;-1:-1:-1;;127902:22:0::1;:56::i;:::-;128066:4;::::0;128027:45:::1;::::0;-1:-1:-1;;;128027:45:0;;111254:42:::1;128027:45;::::0;::::1;8165:34:1::0;-1:-1:-1;;;;;128066:4:0;;::::1;8215:18:1::0;;;8208:43;128002:13:0;;128027:9;::::1;::::0;::::1;::::0;8100:18:1;;128027:45:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;128083:12:0::1;:28:::0;;-1:-1:-1;;;;;;128083:28:0::1;-1:-1:-1::0;;;;;128083:28:0;;;::::1;::::0;;;::::1;::::0;;;-1:-1:-1;;;127718:401:0:o;128127:125::-;39821:10;;-1:-1:-1;;;;;39821:10:0;39807;:24;;:54;;;39849:12;:10;:12::i;:::-;-1:-1:-1;;;;;39835:26:0;:10;-1:-1:-1;;;;;39835:26:0;;39807:54;:88;;;;39879:5;;;;;;;;;-1:-1:-1;;;;;39879:5:0;-1:-1:-1;;;;;39879:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;39865:30:0;:10;-1:-1:-1;;;;;39865:30:0;;39807:88;:124;;;;39913:5;;;;;;;;;-1:-1:-1;;;;;39913:5:0;-1:-1:-1;;;;;39913:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;39899:32:0;:10;-1:-1:-1;;;;;39899:32:0;;39807:124;39785:185;;;;-1:-1:-1;;;39785:185:0;;;;;;;:::i;:::-;128212:32:::1;:30;:32::i;43462:174::-:0;39655:10;;-1:-1:-1;;;;;39655:10:0;39641;:24;;:54;;;39683:12;:10;:12::i;:::-;-1:-1:-1;;;;;39669:26:0;:10;-1:-1:-1;;;;;39669:26:0;;39641:54;39633:78;;;;-1:-1:-1;;;39633:78:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;43541:21:0;::::1;43533:30;;;::::0;::::1;;43574:6;:16:::0;;-1:-1:-1;;;;;;43574:16:0::1;-1:-1:-1::0;;;;;43574:16:0;::::1;::::0;;::::1;::::0;;;43606:22:::1;::::0;2270:51:1;;;43606:22:0::1;::::0;2258:2:1;2243:18;43606:22:0::1;2110:217:1::0;47140:171:0;39655:10;;-1:-1:-1;;;;;39655:10:0;39641;:24;;:54;;;39683:12;:10;:12::i;:::-;-1:-1:-1;;;;;39669:26:0;:10;-1:-1:-1;;;;;39669:26:0;;39641:54;39633:78;;;;-1:-1:-1;;;39633:78:0;;;;;;;:::i;:::-;47229:26:::1;:11;47243:12:::0;;47229:26:::1;:::i;:::-;;47271:32;47290:12;;47271:32;;;;;;;:::i;:::-;;;;;;;;47140:171:::0;;:::o;113945:489::-;114225:51;114237:6;114245:11;114258:8;114268:7;114225:11;:51::i;:::-;113389:8;:28;;-1:-1:-1;;;;;;113389:28:0;;;-1:-1:-1;;;;;113389:28:0;;;;;;;;;;113428:13;:43;;;;;;;;;;113482:11;:26;;;;;;;;;;;113519:13;:55;;-1:-1:-1;;;;;;113519:55:0;;;;;;;;;;;;;;;113601:4;113587:11;:18;-1:-1:-1;113616:56:0;;-1:-1:-1;;;;;;113683:20:0;;;;;113733:7;113716:14;:24;113835:7;113816:16;:26;113872:8;113853:16;:27;113909:10;113891:15;:28;113945:489;;;;;;;;:::o;125742:152::-;125825:13;;125871;;125825:61;;-1:-1:-1;;;125825:61:0;;-1:-1:-1;;;;;125871:13:0;;;125825:61;;;2270:51:1;125798:7:0;;125825:13;;;;;;;:37;;2243:18:1;;125825:61:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;45936:169::-;39655:10;;-1:-1:-1;;;;;39655:10:0;39641;:24;;:54;;;39683:12;:10;:12::i;:::-;-1:-1:-1;;;;;39669:26:0;:10;-1:-1:-1;;;;;39669:26:0;;39641:54;39633:78;;;;-1:-1:-1;;;39633:78:0;;;;;;;:::i;:::-;46019:12:::1;:28:::0;;;46063:34:::1;::::0;1199:25:1;;;46063:34:0::1;::::0;1187:2:1;1172:18;46063:34:0::1;1053:177:1::0;42302:171:0;40627:5;;;;;;;;;-1:-1:-1;;;;;40627:5:0;-1:-1:-1;;;;;40627:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;40613:32:0;:10;-1:-1:-1;;;;;40613:32:0;;:62;;;;40663:12;:10;:12::i;:::-;-1:-1:-1;;;;;40649:26:0;:10;-1:-1:-1;;;;;40649:26:0;;40613:62;40605:86;;;;-1:-1:-1;;;40605:86:0;;;;;;;:::i;:::-;42392:32:::1;::::0;2705:14:1;;2698:22;2680:41;;42392:32:0::1;::::0;2668:2:1;2653:18;42392:32:0::1;;;;;;;42435:13;:30:::0;;-1:-1:-1;;42435:30:0::1;::::0;::::1;;::::0;;;::::1;::::0;;42302:171::o;114442:1229::-;114760:10;;114720:19;;114760:10;;;;;114752:29;;;;-1:-1:-1;;;114752:29:0;;20888:2:1;114752:29:0;;;20870:21:1;20927:1;20907:18;;;20900:29;-1:-1:-1;;;20945:18:1;;;20938:36;20991:18;;114752:29:0;20686:329:1;114752:29:0;114932:4;114926:11;-1:-1:-1;;;114951:135:0;;114831:4;114815:22;;115123:4;115107:21;;115100:43;;;-1:-1:-1;;;115198:4:0;115182:21;;115157:146;114815:22;115354:4;114926:11;114792:20;115332:27;115382:244;;-1:-1:-1;;;115382:244:0;;-1:-1:-1;;;;;21419:15:1;;;115382:244:0;;;21401:34:1;21471:15;;;21451:18;;;21444:43;21523:15;;;21503:18;;;21496:43;21575:15;;;21555:18;;;21548:43;21628:15;;;21607:19;;;21600:44;21681:15;;;21660:19;;;21653:44;21734:15;;;21713:19;;;21706:44;21787:15;;;21766:19;;;21759:44;115317:42:0;;-1:-1:-1;115382:32:0;;;;-1:-1:-1;115382:32:0;;21335:19:1;;115382:244:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;115644:19:0;;-1:-1:-1;;;;;115644:19:0;;;-1:-1:-1;115644:19:0;;-1:-1:-1;115644:19:0;;;114741:930;114442:1229;;;;;;;;;;:::o;125624:110::-;125697:4;;:29;;-1:-1:-1;;;125697:29:0;;125720:4;125697:29;;;2270:51:1;125670:7:0;;-1:-1:-1;;;;;125697:4:0;;:14;;2243:18:1;;125697:29:0;2110:217:1;42706:202:0;39655:10;;-1:-1:-1;;;;;39655:10:0;39641;:24;;:54;;;39683:12;:10;:12::i;:::-;-1:-1:-1;;;;;39669:26:0;:10;-1:-1:-1;;;;;39669:26:0;;39641:54;39633:78;;;;-1:-1:-1;;;39633:78:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;42793:25:0;::::1;42785:34;;;::::0;::::1;;42830:10;:24:::0;;-1:-1:-1;;;;;;42830:24:0::1;-1:-1:-1::0;;;;;42830:24:0;::::1;::::0;;::::1;::::0;;;42870:30:::1;::::0;2270:51:1;;;42870:30:0::1;::::0;2258:2:1;2243:18;42870:30:0::1;2110:217:1::0;62724:281:0;62813:5;;-1:-1:-1;;;;;62813:5:0;62791:10;:28;62783:37;;;;;;62877:5;;62839:34;;;-1:-1:-1;;;62839:34:0;;;;-1:-1:-1;;;;;62877:5:0;;;;62839:32;;;;;:34;;;;;;;;;;;;;;:32;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;62839:43:0;;62831:52;;;;;;62967:4;;:29;;-1:-1:-1;;;62967:29:0;;62990:4;62967:29;;;2270:51:1;62935:62:0;;62953:12;;-1:-1:-1;;;;;62967:4:0;;;;:14;;2243:18:1;;62967:29:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;62935:4;;-1:-1:-1;;;;;62935:4:0;;:62;:17;:62::i;:::-;62724:281;:::o;126045:122::-;126124:35;;-1:-1:-1;;;126124:35:0;;126153:4;126124:35;;;2270:51:1;126097:7:0;;111254:42;;126124:20;;2243:18:1;;126124:35:0;2110:217:1;125902:135:0;125979:13;;126019:8;;125979:50;;-1:-1:-1;;;125979:50:0;;-1:-1:-1;;;;;126019:8:0;;;125979:50;;;2270:51:1;125952:7:0;;125979:13;;;;;;;:31;;2243:18:1;;125979:50:0;2110:217:1;126301:130:0;126355:7;126382:41;126397:25;:23;:25::i;43925:269::-;40057:10;;-1:-1:-1;;;;;40057:10:0;40043;:24;40035:48;;;;-1:-1:-1;;;40035:48:0;;22289:2:1;40035:48:0;;;22271:21:1;22328:2;22308:18;;;22301:30;-1:-1:-1;;;22347:18:1;;;22340:41;22398:18;;40035:48:0;22087:335:1;40035:48:0;-1:-1:-1;;;;;44006:22:0;::::1;43998:31;;;::::0;::::1;;44040:5;::::0;44054:7:::1;::::0;;44040:25:::1;::::0;-1:-1:-1;;;44040:25:0;;-1:-1:-1;;;;;44054:7:0;;::::1;44040:25:::0;;::::1;22609:51:1::0;;;;44040:5:0::1;22676:18:1::0;;;22669:34;44040:5:0;;::::1;::::0;:13:::1;::::0;22582:18:1;;44040:25:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;44076:7:0::1;:18:::0;;-1:-1:-1;;;;;;44076:18:0::1;-1:-1:-1::0;;;;;44076:18:0;;::::1;::::0;;::::1;::::0;;44105:5:::1;::::0;:41:::1;::::0;-1:-1:-1;;;44105:41:0;;;;::::1;22609:51:1::0;;;;-1:-1:-1;;22676:18:1;;;22669:34;44105:5:0::1;::::0;:13:::1;::::0;22582:18:1;;44105:41:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;44162:24:0::1;::::0;-1:-1:-1;;;;;2288:32:1;;2270:51;;44162:24:0::1;::::0;2258:2:1;2243:18;44162:24:0::1;2110:217:1::0;121829:1580:0;121942:4;122103:10;:8;:10::i;:::-;122098:56;;-1:-1:-1;122137:5:0;;121829:1580;-1:-1:-1;121829:1580:0:o;122098:56::-;122264:23;122290;:21;:23::i;:::-;122264:49;;122346:16;;122328:15;:34;122324:78;;;-1:-1:-1;122386:4:0;;121829:1580;-1:-1:-1;;121829:1580:0:o;122324:78::-;122514:21;:19;:21::i;:::-;122509:67;;-1:-1:-1;122559:5:0;;121829:1580;-1:-1:-1;;121829:1580:0:o;122509:67::-;122684:23;;;;122680:67;;;-1:-1:-1;122731:4:0;;121829:1580;-1:-1:-1;;121829:1580:0:o;122680:67::-;122882:16;;122864:15;:34;122860:78;;;-1:-1:-1;122922:4:0;;121829:1580;-1:-1:-1;;121829:1580:0:o;122860:78::-;122981:5;;:31;;-1:-1:-1;;;122981:31:0;;123006:4;122981:31;;;2270:51:1;122950:28:0;;-1:-1:-1;;;;;122981:5:0;;:16;;2243:18:1;;122981:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;122950:62;;123127:14;;123107:6;:17;;;123089:15;:35;;;;:::i;:::-;:52;123085:96;;;-1:-1:-1;123165:4:0;;121829:1580;-1:-1:-1;;;121829:1580:0:o;123085:96::-;123282:15;;123256:5;;;;;;;;;-1:-1:-1;;;;;123256:5:0;-1:-1:-1;;;;;123256:21:0;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;123252:85;;;-1:-1:-1;123321:4:0;;121829:1580;-1:-1:-1;;;121829:1580:0:o;123252:85::-;-1:-1:-1;123396:5:0;;121829:1580;-1:-1:-1;;;121829:1580:0:o;116022:158::-;116084:7;116155:17;:15;:17::i;:::-;116129:23;:21;:23::i;:::-;116111:15;:13;:15::i;:::-;:41;;;;:::i;:::-;:61;;;;:::i;45382:154::-;39655:10;;-1:-1:-1;;;;;39655:10:0;39641;:24;;:54;;;39683:12;:10;:12::i;:::-;-1:-1:-1;;;;;39669:26:0;:10;-1:-1:-1;;;;;39669:26:0;;39641:54;39633:78;;;;-1:-1:-1;;;39633:78:0;;;;;;;:::i;:::-;45460:14:::1;:23:::0;;;45499:29:::1;::::0;1199:25:1;;;45499:29:0::1;::::0;1187:2:1;1172:18;45499:29:0::1;1053:177:1::0;63434:173:0;39821:10;;-1:-1:-1;;;;;39821:10:0;39807;:24;;:54;;;39849:12;:10;:12::i;:::-;-1:-1:-1;;;;;39835:26:0;:10;-1:-1:-1;;;;;39835:26:0;;39807:54;:88;;;;39879:5;;;;;;;;;-1:-1:-1;;;;;39879:5:0;-1:-1:-1;;;;;39879:14:0;;:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;39865:30:0;:10;-1:-1:-1;;;;;39865:30:0;;39807:88;:124;;;;39913:5;;;;;;;;;-1:-1:-1;;;;;39913:5:0;-1:-1:-1;;;;;39913:16:0;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;39899:32:0;:10;-1:-1:-1;;;;;39899:32:0;;39807:124;39785:185;;;;-1:-1:-1;;;39785:185:0;;;;;;;:::i;:::-;63506:13:::1;:20:::0;;-1:-1:-1;;63506:20:0::1;63522:4;63506:20;::::0;;63537:5:::1;::::0;:22:::1;::::0;;-1:-1:-1;;;63537:22:0;;;;-1:-1:-1;;;;;63537:5:0;;::::1;::::0;:20:::1;::::0;:22:::1;::::0;;::::1;::::0;63506:13:::1;::::0;63537:22;;;;;;;;63506:13;63537:5;:22;::::1;;::::0;::::1;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;63577:22:0::1;::::0;::::1;::::0;-1:-1:-1;63577:22:0;;-1:-1:-1;63577:22:0::1;63434:173::o:0;13503:616::-;13867:10;;;13866:62;;-1:-1:-1;13883:39:0;;-1:-1:-1;;;13883:39:0;;13907:4;13883:39;;;8165:34:1;-1:-1:-1;;;;;8235:15:1;;;8215:18;;;8208:43;13883:15:0;;;;;8100:18:1;;13883:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;13866:62;13844:166;;;;-1:-1:-1;;;13844:166:0;;23195:2:1;13844:166:0;;;23177:21:1;23234:2;23214:18;;;23207:30;23273:34;23253:18;;;23246:62;-1:-1:-1;;;23324:18:1;;;23317:52;23386:19;;13844:166:0;22993:418:1;13844:166:0;14048:62;;-1:-1:-1;;;;;22627:32:1;;14048:62:0;;;22609:51:1;22676:18;;;22669:34;;;14021:90:0;;14041:5;;-1:-1:-1;;;14071:22:0;22582:18:1;;14048:62:0;;;;-1:-1:-1;;14048:62:0;;;;;;;;;;;;;;-1:-1:-1;;;;;14048:62:0;-1:-1:-1;;;;;;14048:62:0;;;;;;;;;;14021:19;:90::i;:::-;13503:616;;;:::o;7716:229::-;7853:12;7885:52;7907:6;7915:4;7921:1;7924:12;7885:21;:52::i;:::-;7878:59;;7716:229;;;;;;:::o;47465:98::-;47537:5;;:18;;;-1:-1:-1;;;47537:18:0;;;;47510:7;;-1:-1:-1;;;;;47537:5:0;;:16;;:18;;;;;;;;;;;;;;:5;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;12767:211::-;12911:58;;-1:-1:-1;;;;;22627:32:1;;12911:58:0;;;22609:51:1;22676:18;;;22669:34;;;12884:86:0;;12904:5;;-1:-1:-1;;;12934:23:0;22582:18:1;;12911:58:0;22427:282:1;119239:941:0;119343:25;119370:13;119499:47;119508:13;119523:22;:20;:22::i;:::-;119499:8;:47::i;:::-;119483:63;;119623:22;119648:15;:13;:15::i;:::-;119623:40;;119695:13;119678:14;:30;119674:270;;;119783:45;119797:30;119813:14;119797:13;:30;:::i;:::-;119783:13;:45::i;:::-;119917:15;:13;:15::i;:::-;119900:32;;119674:270;119978:13;119960:14;:31;119956:217;;120028:13;120008:33;;119956:217;;;120094:14;-1:-1:-1;120094:14:0;120131:30;120094:14;120131:13;:30;:::i;:::-;120123:38;;119956:217;119390:790;119239:941;;;:::o;117521:1509::-;117604:13;;;;117600:52;;;117521:1509;:::o;117600:52::-;117774:13;;117809;;117774:50;;-1:-1:-1;;;117774:50:0;;-1:-1:-1;;;;;117809:13:0;;;117774:50;;;2270:51:1;117774:13:0;;;;;;:26;;2243:18:1;;117774:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;117837:24;117864:21;:19;:21::i;:::-;117837:48;-1:-1:-1;117900:20:0;;117896:292;;117937:21;111505:5;117998:11;;117979:16;:30;;;;:::i;:::-;117978:42;;;;:::i;:::-;117937:83;-1:-1:-1;118039:17:0;;118035:142;;111254:42;-1:-1:-1;;;;;118077:27:0;;118113:13;;;;;;;;;-1:-1:-1;;;;;118113:13:0;-1:-1:-1;;;;;118113:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;118077:84;;-1:-1:-1;;;;;;118077:84:0;;;;;;;-1:-1:-1;;;;;22627:32:1;;;118077:84:0;;;22609:51:1;22676:18;;;22669:34;;;22582:18;;118077:84:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;118035:142;117922:266;117896:292;118200:22;118225:15;:13;:15::i;:::-;118200:40;;118333:14;118314:16;:33;118310:72;;;118364:7;;117521:1509;:::o;118310:72::-;118434:22;118459:33;118476:16;118459:14;:33;:::i;:::-;118434:58;-1:-1:-1;118507:18:0;;118503:197;;118605:13;;118579:4;;:57;;-1:-1:-1;;;;;118579:4:0;;;;118605:13;;;;;118621:14;118579:17;:57::i;:::-;118651:37;118673:14;118651:21;:37::i;:::-;118833:24;118860:19;:17;:19::i;:::-;118833:46;-1:-1:-1;118894:20:0;;118890:133;;118931:13;;118959;;119001:8;;118931:80;;-1:-1:-1;;;118931:80:0;;-1:-1:-1;;;;;118959:13:0;;;118931:80;;;23936:34:1;23986:18;;;23979:34;;;119001:8:0;;;24029:18:1;;;24022:43;118931:13:0;;;;;;:19;;23871:18:1;;118931:80:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;118890:133;117589:1441;;;;117521:1509;:::o;119038:193::-;119125:20;119182:41;119200:22;:20;:22::i;:::-;119182:17;:41::i;116188:1295::-;116305:15;116335:13;116363:20;116465;116488:22;:20;:22::i;:::-;116542:5;;:31;;-1:-1:-1;;;116542:31:0;;116567:4;116542:31;;;2270:51:1;116465:45:0;;-1:-1:-1;116521:18:0;;-1:-1:-1;;;;;116542:5:0;;;;:16;;2243:18:1;;116542:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:41;;;116521:62;;116616:10;116600:12;:26;116596:233;;116726:25;116741:10;116726:12;:25;:::i;:::-;116716:35;;116596:233;;;116792:25;116805:12;116792:10;:25;:::i;:::-;116784:33;;116596:233;116949:20;;117012:45;117030:26;117049:7;117030:16;:26;:::i;117012:45::-;116948:109;;-1:-1:-1;116948:109:0;-1:-1:-1;117078:24:0;116948:109;117078:5;:24;:::i;:::-;117070:32;;117130:40;117139:16;117157:12;117130:8;:40::i;:::-;117115:55;;117195:7;117187:5;:15;117183:179;;;117227:15;117235:7;117227:5;:15;:::i;:::-;117219:23;;117267:1;117257:11;;117183:179;;;117311:15;117321:5;117311:7;:15;:::i;:::-;117301:25;;117349:1;117341:9;;117183:179;-1:-1:-1;;117444:23:0;:31;;-1:-1:-1;;117444:31:0;;;-1:-1:-1;116188:1295:0;;;;-1:-1:-1;116188:1295:0;-1:-1:-1;116188:1295:0:o;128260:145::-;128345:12;;128322:39;;111254:42;;-1:-1:-1;;;;;128345:12:0;;128322:22;:39::i;:::-;128372:12;:25;;-1:-1:-1;;;;;;128372:25:0;;;128260:145::o;41385:739::-;41557:4;;-1:-1:-1;;;;;41557:4:0;41549:27;41541:68;;;;-1:-1:-1;;;41541:68:0;;24278:2:1;41541:68:0;;;24260:21:1;24317:2;24297:18;;;24290:30;24356;24336:18;;;24329:58;24404:18;;41541:68:0;24076:352:1;41541:68:0;41622:5;:24;;-1:-1:-1;;;;;;41622:24:0;-1:-1:-1;;;;;41622:24:0;;;;;;;;41671:13;;;-1:-1:-1;;;41671:13:0;;;;:11;;:13;;;;;;;;;;;;;;;41622:24;41671:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;41657:4;:28;;-1:-1:-1;;;;;;41657:28:0;-1:-1:-1;;;;;41657:28:0;;;;;;;;;41696:43;;41713:6;-1:-1:-1;;41696:16:0;:43::i;:::-;41798:10;:24;;-1:-1:-1;;;;;41798:24:0;;;-1:-1:-1;;;;;;41798:24:0;;;;;;;41833:7;:18;;;;;;;;;;;;41862:6;:16;;;;;;;;;;;;;;-1:-1:-1;41924:14:0;:18;;;41970:5;41953:14;:22;42001:3;41986:12;:18;42015:13;:17;42045:5;;:41;;-1:-1:-1;;;42045:41:0;;;;;22609:51:1;;;;-1:-1:-1;;22676:18:1;;;22669:34;42045:5:0;;;:13;;22582:18:1;;42045:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;124188:198::-;124242:4;124288:42;-1:-1:-1;;;;;124279:97:0;;:99;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;15340:716::-;15764:23;15790:69;15818:4;15790:69;;;;;;;;;;;;;;;;;15798:5;-1:-1:-1;;;;;15790:27:0;;;:69;;;;;:::i;:::-;15874:17;;15764:95;;-1:-1:-1;15874:21:0;15870:179;;15971:10;15960:30;;;;;;;;;;;;:::i;:::-;15952:85;;;;-1:-1:-1;;;15952:85:0;;24635:2:1;15952:85:0;;;24617:21:1;24674:2;24654:18;;;24647:30;24713:34;24693:18;;;24686:62;-1:-1:-1;;;24764:18:1;;;24757:40;24814:19;;15952:85:0;24433:406:1;8836:510:0;9006:12;9064:5;9039:21;:30;;9031:81;;;;-1:-1:-1;;;9031:81:0;;25046:2:1;9031:81:0;;;25028:21:1;25085:2;25065:18;;;25058:30;25124:34;25104:18;;;25097:62;-1:-1:-1;;;25175:18:1;;;25168:36;25221:19;;9031:81:0;24844:402:1;9031:81:0;5233:20;;9123:60;;;;-1:-1:-1;;;9123:60:0;;25453:2:1;9123:60:0;;;25435:21:1;25492:2;25472:18;;;25465:30;25531:31;25511:18;;;25504:59;25580:18;;9123:60:0;25251:353:1;9123:60:0;9197:12;9211:23;9238:6;-1:-1:-1;;;;;9238:11:0;9257:5;9264:4;9238:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9196:73;;;;9287:51;9304:7;9313:10;9325:12;9287:16;:51::i;:::-;9280:58;8836:510;-1:-1:-1;;;;;;;8836:510:0:o;503:106::-;561:7;592:1;588;:5;:13;;600:1;588:13;;;-1:-1:-1;596:1:0;;581:20;-1:-1:-1;503:106:0:o;120226:658::-;120286:25;120314:23;120329:7;120314:14;:23::i;:::-;120286:51;;120350:24;120377:19;:17;:19::i;:::-;120350:46;;120431:16;120411:17;:36;120407:414;;;120484:73;120493:36;120513:16;120493:17;:36;:::i;:::-;120531:25;:23;:25::i;120484:73::-;120572:13;;120621;;120662:8;;120572:150;;-1:-1:-1;;;120572:150:0;;-1:-1:-1;;;;;120621:13:0;;;120572:150;;;26128:34:1;120662:8:0;;;26178:18:1;;;26171:43;26230:18;;;26223:34;;;120464:93:0;;-1:-1:-1;120572:13:0;;;;;;:22;;26063:18:1;;120572:150:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;120775:13:0;;120744:8;;120737:72;;-1:-1:-1;;;;;120744:8:0;;;;120775:13;;;;;120791:17;120737:29;:72::i;:::-;120833:43;120858:17;120833:24;:43::i;127047:276::-;127115:13;;127228:11;;127262:4;;127290:13;;127115:200;;-1:-1:-1;;;127115:200:0;;111368:42;127115:200;;;26565:34:1;26615:18;;;26608:34;;;-1:-1:-1;;;;;127228:11:0;;;26658:18:1;;;26651:43;127262:4:0;;;26710:18:1;;;26703:43;127290:13:0;;26762:19:1;;;26755:44;127115:13:0;;;;;;:35;;26499:19:1;;127115:200:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11522:712;11672:12;11701:7;11697:530;;;-1:-1:-1;11732:10:0;11725:17;;11697:530;11846:17;;:21;11842:374;;12044:10;12038:17;12105:15;12092:10;12088:2;12084:19;12077:44;11842:374;12187:12;12180:20;;-1:-1:-1;;;12180:20:0;;;;;;;;:::i;127331:306::-;127412:13;;127538:11;;127572:8;;127604:13;;127412:217;;-1:-1:-1;;;127412:217:0;;111368:42;127412:217;;;26565:34:1;26615:18;;;26608:34;;;-1:-1:-1;;;;;127538:11:0;;;26658:18:1;;;26651:43;127572:8:0;;;26710:18:1;;;26703:43;127604:13:0;;26762:19:1;;;26755:44;127412:13:0;;;;;;:38;;26499:19:1;;127412:217:0;26268:537:1;-1:-1:-1;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;14:131:1;-1:-1:-1;;;;;89:31:1;;79:42;;69:70;;135:1;132;125:12;150:247;209:6;262:2;250:9;241:7;237:23;233:32;230:52;;;278:1;275;268:12;230:52;317:9;304:23;336:31;361:5;336:31;:::i;402:258::-;474:1;484:113;498:6;495:1;492:13;484:113;;;574:11;;;568:18;555:11;;;548:39;520:2;513:10;484:113;;;615:6;612:1;609:13;606:48;;;-1:-1:-1;;650:1:1;632:16;;625:27;402:258::o;665:383::-;814:2;803:9;796:21;777:4;846:6;840:13;889:6;884:2;873:9;869:18;862:34;905:66;964:6;959:2;948:9;944:18;939:2;931:6;927:15;905:66;:::i;:::-;1032:2;1011:15;-1:-1:-1;;1007:29:1;992:45;;;;1039:2;988:54;;665:383;-1:-1:-1;;665:383:1:o;1235:118::-;1321:5;1314:13;1307:21;1300:5;1297:32;1287:60;;1343:1;1340;1333:12;1358:241;1414:6;1467:2;1455:9;1446:7;1442:23;1438:32;1435:52;;;1483:1;1480;1473:12;1435:52;1522:9;1509:23;1541:28;1563:5;1541:28;:::i;1604:316::-;1681:6;1689;1697;1750:2;1738:9;1729:7;1725:23;1721:32;1718:52;;;1766:1;1763;1756:12;1718:52;-1:-1:-1;;1789:23:1;;;1859:2;1844:18;;1831:32;;-1:-1:-1;1910:2:1;1895:18;;;1882:32;;1604:316;-1:-1:-1;1604:316:1:o;1925:180::-;1984:6;2037:2;2025:9;2016:7;2012:23;2008:32;2005:52;;;2053:1;2050;2043:12;2005:52;-1:-1:-1;2076:23:1;;1925:180;-1:-1:-1;1925:180:1:o;2960:592::-;3031:6;3039;3092:2;3080:9;3071:7;3067:23;3063:32;3060:52;;;3108:1;3105;3098:12;3060:52;3148:9;3135:23;3177:18;3218:2;3210:6;3207:14;3204:34;;;3234:1;3231;3224:12;3204:34;3272:6;3261:9;3257:22;3247:32;;3317:7;3310:4;3306:2;3302:13;3298:27;3288:55;;3339:1;3336;3329:12;3288:55;3379:2;3366:16;3405:2;3397:6;3394:14;3391:34;;;3421:1;3418;3411:12;3391:34;3466:7;3461:2;3452:6;3448:2;3444:15;3440:24;3437:37;3434:57;;;3487:1;3484;3477:12;3434:57;3518:2;3510:11;;;;;3540:6;;-1:-1:-1;2960:592:1;;-1:-1:-1;;;;2960:592:1:o;3557:1239::-;3679:6;3687;3695;3703;3711;3719;3727;3735;3788:3;3776:9;3767:7;3763:23;3759:33;3756:53;;;3805:1;3802;3795:12;3756:53;3844:9;3831:23;3863:31;3888:5;3863:31;:::i;:::-;3913:5;-1:-1:-1;3970:2:1;3955:18;;3942:32;3983:33;3942:32;3983:33;:::i;:::-;4035:7;-1:-1:-1;4094:2:1;4079:18;;4066:32;4107:33;4066:32;4107:33;:::i;:::-;4159:7;-1:-1:-1;4218:2:1;4203:18;;4190:32;4231:33;4190:32;4231:33;:::i;:::-;4283:7;-1:-1:-1;4342:3:1;4327:19;;4314:33;4356;4314;4356;:::i;:::-;4408:7;-1:-1:-1;4467:3:1;4452:19;;4439:33;4481;4439;4481;:::i;:::-;4533:7;-1:-1:-1;4592:3:1;4577:19;;4564:33;4606;4564;4606;:::i;:::-;4658:7;-1:-1:-1;4717:3:1;4702:19;;4689:33;4731;4689;4731;:::i;:::-;4783:7;4773:17;;;3557:1239;;;;;;;;;;;:::o;5496:335::-;5698:2;5680:21;;;5737:2;5717:18;;;5710:30;-1:-1:-1;;;5771:2:1;5756:18;;5749:41;5822:2;5807:18;;5496:335::o;6504:127::-;6565:10;6560:3;6556:20;6553:1;6546:31;6596:4;6593:1;6586:15;6620:4;6617:1;6610:15;6975:127;7036:10;7031:3;7027:20;7024:1;7017:31;7067:4;7064:1;7057:15;7091:4;7088:1;7081:15;7107:135;7146:3;-1:-1:-1;;7167:17:1;;7164:43;;;7187:18;;:::i;:::-;-1:-1:-1;7234:1:1;7223:13;;7107:135::o;7247:184::-;7317:6;7370:2;7358:9;7349:7;7345:23;7341:32;7338:52;;;7386:1;7383;7376:12;7338:52;-1:-1:-1;7409:16:1;;7247:184;-1:-1:-1;7247:184:1:o;7436:380::-;7515:1;7511:12;;;;7558;;;7579:61;;7633:4;7625:6;7621:17;7611:27;;7579:61;7686:2;7678:6;7675:14;7655:18;7652:38;7649:161;;;7732:10;7727:3;7723:20;7720:1;7713:31;7767:4;7764:1;7757:15;7795:4;7792:1;7785:15;7821:127;7882:10;7877:3;7873:20;7870:1;7863:31;7913:4;7910:1;7903:15;7937:4;7934:1;7927:15;8262:729;8432:4;8480:2;8469:9;8465:18;8510:6;8499:9;8492:25;8536:2;8574;8569;8558:9;8554:18;8547:30;8597:6;8632;8626:13;8663:6;8655;8648:22;8701:2;8690:9;8686:18;8679:25;;8739:2;8731:6;8727:15;8713:29;;8760:1;8770:195;8784:6;8781:1;8778:13;8770:195;;;8849:13;;-1:-1:-1;;;;;8845:39:1;8833:52;;8940:15;;;;8905:12;;;;8881:1;8799:9;8770:195;;;-1:-1:-1;8982:3:1;;8262:729;-1:-1:-1;;;;;;;8262:729:1:o;8996:252::-;9068:2;9062:9;9110:3;9098:16;;9144:18;9129:34;;9165:22;;;9126:62;9123:88;;;9191:18;;:::i;:::-;9227:2;9220:22;8996:252;:::o;9253:255::-;9325:2;9319:9;9367:6;9355:19;;9404:18;9389:34;;9425:22;;;9386:62;9383:88;;;9451:18;;:::i;9513:275::-;9584:2;9578:9;9649:2;9630:13;;-1:-1:-1;;9626:27:1;9614:40;;9684:18;9669:34;;9705:22;;;9666:62;9663:88;;;9731:18;;:::i;:::-;9767:2;9760:22;9513:275;;-1:-1:-1;9513:275:1:o;9793:183::-;9853:4;9886:18;9878:6;9875:30;9872:56;;;9908:18;;:::i;:::-;-1:-1:-1;9953:1:1;9949:14;9965:4;9945:25;;9793:183::o;9981:881::-;10076:6;10107:2;10150;10138:9;10129:7;10125:23;10121:32;10118:52;;;10166:1;10163;10156:12;10118:52;10199:9;10193:16;10232:18;10224:6;10221:30;10218:50;;;10264:1;10261;10254:12;10218:50;10287:22;;10340:4;10332:13;;10328:27;-1:-1:-1;10318:55:1;;10369:1;10366;10359:12;10318:55;10398:2;10392:9;10421:60;10437:43;10477:2;10437:43;:::i;:::-;10421:60;:::i;:::-;10515:15;;;10597:1;10593:10;;;;10585:19;;10581:28;;;10546:12;;;;10621:19;;;10618:39;;;10653:1;10650;10643:12;10618:39;10677:11;;;;10697:135;10713:6;10708:3;10705:15;10697:135;;;10779:10;;10767:23;;10730:12;;;;10810;;;;10697:135;;10867:125;10907:4;10935:1;10932;10929:8;10926:34;;;10940:18;;:::i;:::-;-1:-1:-1;10977:9:1;;10867:125::o;10997:706::-;11077:6;11130:2;11118:9;11109:7;11105:23;11101:32;11098:52;;;11146:1;11143;11136:12;11098:52;11179:9;11173:16;11208:18;11249:2;11241:6;11238:14;11235:34;;;11265:1;11262;11255:12;11235:34;11303:6;11292:9;11288:22;11278:32;;11348:7;11341:4;11337:2;11333:13;11329:27;11319:55;;11370:1;11367;11360:12;11319:55;11399:2;11393:9;11421:2;11417;11414:10;11411:36;;;11427:18;;:::i;:::-;11469:53;11512:2;11493:13;;-1:-1:-1;;11489:27:1;11518:2;11485:36;11469:53;:::i;:::-;11456:66;;11545:2;11538:5;11531:17;11585:7;11580:2;11575;11571;11567:11;11563:20;11560:33;11557:53;;;11606:1;11603;11596:12;11557:53;11619:54;11670:2;11665;11658:5;11654:14;11649:2;11645;11641:11;11619:54;:::i;:::-;-1:-1:-1;11692:5:1;10997:706;-1:-1:-1;;;;10997:706:1:o;11708:432::-;-1:-1:-1;;;11965:3:1;11958:28;11940:3;12015:6;12009:13;12031:62;12086:6;12081:2;12076:3;12072:12;12065:4;12057:6;12053:17;12031:62;:::i;:::-;12113:16;;;;12131:2;12109:25;;11708:432;-1:-1:-1;;11708:432:1:o;12145:251::-;12215:6;12268:2;12256:9;12247:7;12243:23;12239:32;12236:52;;;12284:1;12281;12274:12;12236:52;12316:9;12310:16;12335:31;12360:5;12335:31;:::i;12401:168::-;12441:7;12507:1;12503;12499:6;12495:14;12492:1;12489:21;12484:1;12477:9;12470:17;12466:45;12463:71;;;12514:18;;:::i;:::-;-1:-1:-1;12554:9:1;;12401:168::o;12574:217::-;12614:1;12640;12630:132;;12684:10;12679:3;12675:20;12672:1;12665:31;12719:4;12716:1;12709:15;12747:4;12744:1;12737:15;12630:132;-1:-1:-1;12776:9:1;;12574:217::o;12796:128::-;12836:3;12867:1;12863:6;12860:1;12857:13;12854:39;;;12873:18;;:::i;:::-;-1:-1:-1;12909:9:1;;12796:128::o;12929:784::-;13031:6;13084:3;13072:9;13063:7;13059:23;13055:33;13052:53;;;13101:1;13098;13091:12;13052:53;13127:22;;:::i;:::-;13178:9;13172:16;13165:5;13158:31;13242:2;13231:9;13227:18;13221:25;13216:2;13209:5;13205:14;13198:49;13300:2;13289:9;13285:18;13279:25;13274:2;13267:5;13263:14;13256:49;13358:2;13347:9;13343:18;13337:25;13332:2;13325:5;13321:14;13314:49;13417:3;13406:9;13402:19;13396:26;13390:3;13383:5;13379:15;13372:51;13477:3;13466:9;13462:19;13456:26;13450:3;13443:5;13439:15;13432:51;13537:3;13526:9;13522:19;13516:26;13510:3;13503:5;13499:15;13492:51;13597:3;13586:9;13582:19;13576:26;13570:3;13563:5;13559:15;13552:51;13622:3;13678:2;13667:9;13663:18;13657:25;13652:2;13645:5;13641:14;13634:49;;13702:5;13692:15;;;12929:784;;;;:::o;14052:175::-;14130:13;;14183:18;14172:30;;14162:41;;14152:69;;14217:1;14214;14207:12;14152:69;14052:175;;;:::o;14232:681::-;14296:5;14349:3;14342:4;14334:6;14330:17;14326:27;14316:55;;14367:1;14364;14357:12;14316:55;14396:6;14390:13;14422:4;14446:60;14462:43;14502:2;14462:43;:::i;14446:60::-;14540:15;;;14626:1;14622:10;;;;14610:23;;14606:32;;;14571:12;;;;14650:15;;;14647:35;;;14678:1;14675;14668:12;14647:35;14714:2;14706:6;14702:15;14726:158;14742:6;14737:3;14734:15;14726:158;;;14808:33;14837:3;14808:33;:::i;:::-;14796:46;;14862:12;;;;14759;;14726:158;;;-1:-1:-1;14902:5:1;14232:681;-1:-1:-1;;;;;;14232:681:1:o;14918:1298::-;14988:5;15036:6;15024:9;15019:3;15015:19;15011:32;15008:52;;;15056:1;15053;15046:12;15008:52;15078:22;;:::i;:::-;15069:31;;15129:9;15123:16;15158:18;15199:2;15191:6;15188:14;15185:34;;;15215:1;15212;15205:12;15185:34;15242:67;15305:3;15296:6;15285:9;15281:22;15242:67;:::i;:::-;15235:5;15228:82;15356:2;15345:9;15341:18;15335:25;15319:41;;15385:2;15375:8;15372:16;15369:36;;;15401:1;15398;15391:12;15369:36;15437:69;15502:3;15491:8;15480:9;15476:24;15437:69;:::i;:::-;15432:2;15425:5;15421:14;15414:93;15553:2;15542:9;15538:18;15532:25;15516:41;;15582:2;15572:8;15569:16;15566:36;;;15598:1;15595;15588:12;15566:36;15634:69;15699:3;15688:8;15677:9;15673:24;15634:69;:::i;:::-;15629:2;15622:5;15618:14;15611:93;15750:2;15739:9;15735:18;15729:25;15713:41;;15779:2;15769:8;15766:16;15763:36;;;15795:1;15792;15785:12;15763:36;;15831:69;15896:3;15885:8;15874:9;15870:24;15831:69;:::i;:::-;15826:2;15819:5;15815:14;15808:93;;15934:49;15978:3;15967:9;15963:19;15934:49;:::i;:::-;15928:3;15921:5;15917:15;15910:74;16017:49;16061:3;16050:9;16046:19;16017:49;:::i;:::-;16011:3;16004:5;16000:15;15993:74;16100:49;16144:3;16133:9;16129:19;16100:49;:::i;:::-;16094:3;16087:5;16083:15;16076:74;16204:3;16193:9;16189:19;16183:26;16177:3;16170:5;16166:15;16159:51;14918:1298;;;;:::o;16221:1877::-;16418:6;16426;16434;16442;16450;16458;16466;16474;16482;16526:9;16517:7;16513:23;16556:3;16552:2;16548:12;16545:32;;;16573:1;16570;16563:12;16545:32;16605:9;16599:16;16624:31;16649:5;16624:31;:::i;:::-;16724:2;16709:18;;16703:25;16674:5;;-1:-1:-1;16737:33:1;16703:25;16737:33;:::i;:::-;16841:2;16826:18;;16820:25;16789:7;;-1:-1:-1;16854:33:1;16820:25;16854:33;:::i;:::-;16958:2;16943:18;;16937:25;16906:7;;-1:-1:-1;16971:33:1;16937:25;16971:33;:::i;:::-;17023:7;17013:17;;;17070:3;17059:9;17055:19;17049:26;17039:36;;17115:3;17104:9;17100:19;17094:26;17084:36;;17160:3;17149:9;17145:19;17139:26;17129:36;;17184:6;17225:2;17218:3;17214:8;17210:2;17206:17;17202:26;17199:46;;;17241:1;17238;17231:12;17199:46;17269:22;;:::i;:::-;17337:3;17322:19;;17316:26;17300:43;;17383:18;;;17377:25;17372:2;17359:16;;17352:51;17458:3;17443:19;;17437:26;17432:2;17419:16;;17412:52;17519:3;17504:19;;17498:26;17493:2;17480:16;;17473:52;17254:37;-1:-1:-1;17560:49:1;17604:3;17589:19;;17560:49;:::i;:::-;17554:3;17545:7;17541:17;17534:76;17645:49;17689:3;17678:9;17674:19;17645:49;:::i;:::-;17639:3;17630:7;17626:17;17619:76;17730:49;17774:3;17763:9;17759:19;17730:49;:::i;:::-;17724:3;17715:7;17711:17;17704:76;17815:49;17859:3;17848:9;17844:19;17815:49;:::i;:::-;17809:3;17796:17;;17789:76;17935:3;17920:19;;17914:26;17800:7;;-1:-1:-1;17963:18:1;17952:30;;17949:50;;;17995:1;17992;17985:12;17949:50;18018:74;18084:7;18075:6;18064:9;18060:22;18018:74;:::i;:::-;18008:84;;;16221:1877;;;;;;;;;;;:::o;18895:245::-;18962:6;19015:2;19003:9;18994:7;18990:23;18986:32;18983:52;;;19031:1;19028;19021:12;18983:52;19063:9;19057:16;19082:28;19104:5;19082:28;:::i;20291:390::-;20450:2;20439:9;20432:21;20489:6;20484:2;20473:9;20469:18;20462:34;20546:6;20538;20533:2;20522:9;20518:18;20505:48;20602:1;20573:22;;;20597:2;20569:31;;;20562:42;;;;20665:2;20644:15;;;-1:-1:-1;;20640:29:1;20625:45;20621:54;;20291:390;-1:-1:-1;20291:390:1:o;25609:274::-;25738:3;25776:6;25770:13;25792:53;25838:6;25833:3;25826:4;25818:6;25814:17;25792:53;:::i;:::-;25861:16;;;;;25609:274;-1:-1:-1;;25609:274:1:o
Swarm Source
ipfs://38ade064d40806c4f767c679d4faf67ab3ef3befc52c80566e1c19df83080acc
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 ]
[ 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.