Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
BaseLibrary
Compiler Version
v0.8.18+commit.87f61d96
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2023-03-28
*/
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.18;
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @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 == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from,
address to,
uint256 amount
) external returns (bool);
}
// 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.openzeppelin.com/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:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, 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}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, 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}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, 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) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, 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) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* 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:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, 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;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_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;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_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 Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - 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 {}
}
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
// OpenZeppelin Contracts (last updated v4.8.0) (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
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 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 functionCallWithValue(target, data, 0, "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");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, 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) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or 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 {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// 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
/// @solidity memory-safe-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));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @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");
}
}
}
interface IDiamond {
enum FacetCutAction {
Add,
Replace,
Remove
}
// Add=0, Replace=1, Remove=2
struct FacetCut {
address facetAddress;
FacetCutAction action;
bytes4[] functionSelectors;
}
event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
/// @notice Add/replace/remove any number of functions and optionally execute
/// a function with delegatecall
/// @param _diamondCut Contains the facet addresses and function selectors
/// @param _init The address of the contract or facet to execute _calldata
/// @param _calldata A function call, including function selector and arguments
/// _calldata is executed with delegatecall on _init
function diamondCut(
FacetCut[] calldata _diamondCut,
address _init,
bytes calldata _calldata
) external;
}
// A loupe is a small magnifying glass used to look at diamonds.
// These functions look at diamonds
interface IDiamondLoupe {
struct Facet {
address facetAddress;
bytes4[] functionSelectors;
}
/// @notice Gets all facet addresses and their four byte function selectors.
/// @return facets_ Facet
function facets() external view returns (Facet[] memory facets_);
/// @notice Gets all the function selectors supported by a specific facet.
/// @param _facet The facet address.
/// @return facetFunctionSelectors_
function facetFunctionSelectors(
address _facet
) external view returns (bytes4[] memory facetFunctionSelectors_);
/// @notice Get all the facet addresses used by a diamond.
/// @return facetAddresses_
function facetAddresses()
external
view
returns (address[] memory facetAddresses_);
/// @notice Gets the facet that supports the given selector.
/// @dev If facet is not found return address(0).
/// @param _functionSelector The function selector.
/// @return facetAddress_ The facet address.
function facetAddress(
bytes4 _functionSelector
) external view returns (address facetAddress_);
}
interface IBaseLibrary {
function apiVersion() external view returns (string memory);
}
/**
* @title YearnV3 Diamond Helper
* @author yearn.finance
* @notice
* This contract is meant to be a helper contract for the `BaseLibrary`
* for any ERC-2535 view functions needed. This will hold all the needed
* structs and event for the library to access upon a new strategy being
* created or post creation for the "Diamond" functions.
*/
contract DiamondHelper {
address public baseLibrary;
bytes4[] private selectors;
IDiamond.FacetCut[] private cuts;
constructor(bytes4[] memory _selectors) {
selectors = _selectors;
}
/**
* @notice Get the api version for this helper.
*/
function apiVersion() external view returns (string memory) {
return IBaseLibrary(baseLibrary).apiVersion();
}
/**
* @notice Set the address of the BaseLibrary and store the
* FacetCut for events
* @dev This contract needs to be deployed first since the
* address must be hardcoded in the library.
*
* This can only be set up once and then the contract can
* never be adjusted.
*
* @param _library, The address of the BaseLibrary for the
* strategies to forward calls to.
*/
function setLibrary(address _library) external {
require(baseLibrary == address(0), "already set");
baseLibrary = _library;
//set up diamond cut struct
cuts.push(
IDiamond.FacetCut(_library, IDiamond.FacetCutAction.Add, selectors)
);
}
/**
* @notice Returns the Struct to emit in the needed DiamondCut
* event on initilization of a new strategy.
*
* Contatins the address of the library, the enum singaling we
* are adding and the array of all its external function selectors.
*/
function diamondCut()
external
view
returns (IDiamond.FacetCut[] memory _cuts)
{
_cuts = new IDiamond.FacetCut[](cuts.length);
_cuts = cuts;
}
/**
* @notice Returns the fully array of function selectors the BaseLibrary contains.
*/
function functionSelectors()
external
view
returns (bytes4[] memory _selectors)
{
_selectors = new bytes4[](selectors.length);
_selectors = selectors;
}
/**
* @notice Gets all facet addresses and their four byte function selectors.
* @return facets_ Facet
*/
function facets()
external
view
returns (IDiamondLoupe.Facet[] memory facets_)
{
facets_ = new IDiamondLoupe.Facet[](1);
// we forward all calls to the base library
facets_[0] = IDiamondLoupe.Facet(baseLibrary, selectors);
}
/**
* @notice Gets all the function selectors supported by a specific facet.
* @param _facet The facet address.
* @return facetFunctionSelectors_
*/
function facetFunctionSelectors(
address _facet
) external view returns (bytes4[] memory facetFunctionSelectors_) {
if (_facet == baseLibrary) {
facetFunctionSelectors_ = selectors;
}
}
/**
* @notice Get all the facet addresses used by a diamond.
* @return facetAddresses_
*/
function facetAddresses()
external
view
returns (address[] memory facetAddresses_)
{
facetAddresses_ = new address[](1);
// we only use one facet
facetAddresses_[0] = baseLibrary;
}
/**
* @notice Gets the facet that supports the given selector.
* @dev If facet is not found return address(0).
* @param _functionSelector The function selector.
* @return facetAddress_ The facet address.
*/
function facetAddress(
bytes4 _functionSelector
) external view returns (address facetAddress_) {
bytes4[] memory facetFunctionSelectors_ = selectors;
for (uint256 i; i < facetFunctionSelectors_.length; ++i) {
if (facetFunctionSelectors_[i] == _functionSelector)
return baseLibrary;
}
}
}
interface IBaseStrategy {
/*//////////////////////////////////////////////////////////////
IMMUTABLE FUNCTIONS
//////////////////////////////////////////////////////////////*/
function isOriginal() external view returns (bool);
function initialize(
address _asset,
string memory name_,
address _management,
address _performanceFeeRecipient,
address _keeper
) external;
function availableDepositLimit(
address _owner
) external view returns (uint256);
function availableWithdrawLimit(
address _owner
) external view returns (uint256);
function invest(uint256 _assets) external;
function freeFunds(uint256 _amount) external;
function totalInvested() external returns (uint256);
function tendThis(uint256 _totalIdle) external;
function tendTrigger() external view returns (bool);
}
interface IFactory {
function protocol_fee_config()
external
view
returns (uint16, uint32, address);
}
interface IRegistry {
function newStrategy(address _strategy, address _asset) external;
}
/**
* @title YearnV3 Base Library
* @author yearn.finance
* @notice
* This library can be used by anyone wishing to easily build and deploy
* their own custom ERC4626 compiant one strategy Vault. This library
* would be used to hanle all logic, storage and mangement for the custom
* strategy. Any ERC4626, ERC20 or ERC2535 function calls to the implemenation
* would be forwarded throug a delegateCall to this library and so the
* implementation would only need to override a few simple functions that
* are focused entirely on the strategy specific needs to easily and cheaply
* deploy their own permisionless vault.
*/
library BaseLibrary {
using Math for uint256;
using SafeERC20 for ERC20;
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
/**
* @notice Emitted whent the 'mangement' address is updtaed to 'newManagement'.
*/
event UpdateManagement(address indexed newManagement);
/**
* @notice Emitted whent the 'keeper' address is updtaed to 'newKeeper'.
*/
event UpdateKeeper(address indexed newKeeper);
/**
* @notice Emitted whent the 'performaneFee' is updtaed to 'newPerformanceFee'.
*/
event UpdatePerformanceFee(uint16 newPerformanceFee);
/**
* @notice Emitted whent the 'performanceFeeRecipient' address is
* updtaed to 'newPerformanceFeeRecipient'.
*/
event UpdatePerformanceFeeRecipient(
address indexed newPerformanceFeeRecipient
);
/**
* @notice Emitted whent the 'profitMaxUnlockTime' is updtaed to 'newProfitMaxUnlockTime'.
*/
event UpdateProfitMaxUnlockTime(uint256 newProfitMaxUnlockTime);
/**
* @notice Emitted when a strategy is shutdown.
*/
event StrategyShutdown();
/**
* @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
);
/**
* @dev Emitted when the `caller` has exchanged `assets` for `shares`,
* and transferred those `shares` to `owner`.
*/
event Deposit(
address indexed caller,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Emitted when the `caller` has exchanged `owner`s `shares` for `assets`,
* and transferred those `assets` to `receiver`.
*/
event Withdraw(
address indexed caller,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Emitted when the strategy reports `profit` or `loss` and
* `performanceFees` and `protocolFees` are paid out.
*/
event Reported(
uint256 profit,
uint256 loss,
uint256 performanceFees,
uint256 protocolFees
);
/**
* @dev Emitted on the initialization of a new strategy.
*/
event DiamondCut(
IDiamond.FacetCut[] _diamondCut,
address _init,
bytes _calldata
);
/**
* @dev Emitted when a new `clone` is created from an `original`.
*/
event Cloned(address indexed clone, address indexed original);
/*//////////////////////////////////////////////////////////////
STORAGE STRUCT
//////////////////////////////////////////////////////////////*/
/**
* @dev The struct that will hold all the data for each implementation
* strategy that uses this library.
*
* This replaces all state variables for a traditional contract. This
* full struct will be initiliazed on the createion of the implemenation
* contract and continually updated and read from for the life of the contract.
*
* We combine all the variables into one struct to limit the amount of times
* custom storage slots need to be loaded during complex functions.
*
* Loading the corresponding storage slot for the struct does not
* load any of the contents of the struct into memory. So the size
* has no effect on gas usage.
*/
// prettier-ignore
struct BaseStrategyData {
// The ERC20 compliant underlying asset that will be
// used by the implementation contract. We can keep this
// as and ERC20 instance because the implementation holds the
// addres of `asset` as a immutable variable to be 4626 compliant.
ERC20 asset;
// These are the corresponding ERC20 variables needed for the
// strategies token that is issued and burned on each deposit or withdraw.
uint8 decimals; // The amount of decimals that `asset` and strategy use
bytes10 symbol; // The symbol of the token for the strategy.
string name; // The name of the token for the strategy.
uint256 totalSupply; // The total amount of shares currently issued
uint256 INITIAL_CHAIN_ID; // The intitial chain id when the strategy was created.
bytes32 INITIAL_DOMAIN_SEPARATOR; // The domain seperator used for permits on the intitial chain.
mapping(address => uint256) nonces; // Mapping of nonces used for permit functions.
mapping(address => uint256) balances; // Mapping to track current balances for each account that holds shares.
mapping(address => mapping(address => uint256)) allowances; // Mapping to track the allowances for the strategies shares.
// Assets data to track totals the strategy holds.
// We manually track idle instead of relying on asset.balanceOf(address(this))
// to prevent PPS manipulation through airdrops.
uint256 totalIdle; // The total amount of loose `asset` the strategy holds.
uint256 totalDebt; // The total amount `asset` that is currently deployed by the strategy
// Variables for profit reporting and locking
// We use uint128 for time stamps which is 1,025 years in the future.
uint256 profitUnlockingRate; // The rate at which locked profit is unlocking.
uint128 fullProfitUnlockDate; // The timestamp at which all locked shares will unlock.
uint128 lastReport; // The last time a {report} was called.
uint32 profitMaxUnlockTime; // The amount of seconds that the reported profit unlocks over.
uint16 performanceFee; // The percent in basis points of profit that is charged as a fee.
address performanceFeeRecipient; // The address to pay the `performanceFee` to.
// Access management variables.
address management; // Main address that can set all configurable variables.
address keeper; // Address given permission to call {report} and {tend}.
bool entered; // Bool to prevent reentrancy.
bool shutdown; // Bool that can be used to stop deposits into the strategy.
}
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
/**
* @dev Require that the call is coming from the strategies mangement.
*/
modifier onlyManagement() {
isManagement(msg.sender);
_;
}
/**
* @dev Require that the call is coming from either the strategies
* management or the keeper.
*/
modifier onlyKeepers() {
isKeeperOrManagement(msg.sender);
_;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Placed over all state changing functions for increased safety.
*/
modifier nonReentrant() {
BaseStrategyData storage S = _baseStrategyStorgage();
// On the first call to nonReentrant, `entered` will be false
require(!S.entered, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
S.entered = true;
_;
// Reset to false once call has finished
S.entered = false;
}
/**
* @dev Will stop new deposits if the strategy has been shutdown.
* This will not effect withdraws which can never be paused or stopped.
*/
modifier notShutdown() {
require(!isShutdown(), "shutdown");
_;
}
/**
* @notice To check if a sender is the management for a specific strategy.
* @dev Is left public so that it can be used by the implementation.
*
* When the implementations calls this the msg.sender would be the
* address of the strategy so we need to specify the sender.
*/
function isManagement(address _sender) public view {
require(_sender == _baseStrategyStorgage().management, "!Authorized");
}
/**
* @notice To check if a sender is the keeper or management
* for a specific strategy.
* @dev Is left public so that it can be used by the implementation.
*
* When the implementations calls this the msg.sender would be the
* address of the strategy so we need to specify the sender.
*/
function isKeeperOrManagement(address _sender) public view {
BaseStrategyData storage S = _baseStrategyStorgage();
require(_sender == S.keeper || _sender == S.management, "!Authorized");
}
/**
* @notice To check if the strategy has been shutdown.
* @dev Is left public so that it can be used by the implementation.
*
* We don't revert here so this can be used for the external getter
* for the `shutdown` variable as well.
*/
function isShutdown() public view returns (bool) {
return _baseStrategyStorgage().shutdown;
}
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
// Api version this library implements.
string private constant API_VERSION = "3.1.0";
address private constant diamondHelper =
0x9bcC5F7560B243E37e0Adf8379FA6D9AB49a425b;
// Used for fee calculations.
uint256 private constant MAX_BPS = 10_000;
// Used for profit unlocking rate calculations.
uint256 private constant MAX_BPS_EXTENDED = 1_000_000_000_000;
address private constant FACTORY =
0xa8f46C3f5A89fbC3c80B3EE333a1dAF8FA719061;
// Address of the registry used to track all deployed vaults and strategies
address private constant REGISTRY =
0x1DBcECb8E3fED0151C2B2Bcec288Cf8E42022669;
/**
* @dev Custom storgage slot that will be used to store the
* `BaseStrategyData` struct that holds each strategies
* specific storage variables.
*
* Any storage updates done by the library actually update
* the storage of the calling contract. This variable points
* to the specic location that will be used to store the
* struct that holds all that data.
*
* We intentionally use a large string in order to get a high
* storage slot that will allow for stratgists to use any
* amount of storage in the implementations without worrying
* about collisions. This storage slot sits at roughly 1e77.
*/
bytes32 private constant BASE_STRATEGY_STORAGE =
bytes32(uint256(keccak256("yearn.base.strategy.storage")) - 1);
/*//////////////////////////////////////////////////////////////
STORAGE GETTER FUNCTION
//////////////////////////////////////////////////////////////*/
/**
* @dev will return the actaul storage slot where the strategy
* sepcific `BaseStrategyData` struct is stored for both read
* and write operations.
*
* This loads just the slot location, not the full struct
* so it can be used in a gas effecient manner.
*/
function _baseStrategyStorgage()
private
pure
returns (BaseStrategyData storage S)
{
// Since STORAGE_SLOT is a constant, we have to put a variable
// on the stack to access it from an inline assembly block.
bytes32 slot = BASE_STRATEGY_STORAGE;
assembly {
S.slot := slot
}
}
/*//////////////////////////////////////////////////////////////
INITILIZATION OF DEFAULT STORAGE
//////////////////////////////////////////////////////////////*/
/**
* @notice Used to initialize storage for a newly deployed strategy.
* @dev This should be called atomically whenever a new strategy is
* deployed or cloned, and can only be called once for each strategy.
*
* This will set all the default storage that must be set for a
* strategy to function. Any changes can be made post deployment
* through external calls from `management`.
*
* The function will also emit the `DiamondCut` event that will be
* emitted through the calling strategy as well as telling the
* registry a new strategy has been deployed for easy tracking
* purposes.
*
* This is called through a lowelevel call in the BaseStrategy so
* any reverts will return the "init failed" string.
*
* @param _asset Address of the underlying asset.
* @param _name Name the strategy will use.
* @param _management Address to set as the strategies `management`.
* @param _performanceFeeRecipient Address to receive performance fees.
* @param _keeper Address to set as strategies `keeper`.
*/
function init(
address _asset,
string memory _name,
address _management,
address _performanceFeeRecipient,
address _keeper
) external {
// Cache storage pointer
BaseStrategyData storage S = _baseStrategyStorgage();
// Make sure we aren't initiliazed.
require(address(S.asset) == address(0));
// Set the strategys underlying asset
S.asset = ERC20(_asset);
// Set the Tokens name.
S.name = _name;
// Set the symbol and decimals based off the `asset`.
IERC20Metadata a = IERC20Metadata(_asset);
// This stores the symbol as bytes10 so it can be
// packed in the struct with `asset` and `decimals`
S.symbol = bytes10(abi.encodePacked("ys", a.symbol()));
S.decimals = a.decimals();
// Set initial chain id for permit replay protection
S.INITIAL_CHAIN_ID = block.chainid;
// Set the inital domain seperator for permit functions
S.INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
// Default to a 10 day profit unlock period
S.profitMaxUnlockTime = 10 days;
// Set address to receive performance fees.
// Can't be address(0) or we will be burning fees.
require(_performanceFeeRecipient != address(0));
S.performanceFeeRecipient = _performanceFeeRecipient;
// Default to a 10% performance fee?
S.performanceFee = 1_000;
// Set last report to this block
S.lastReport = uint128(block.timestamp);
// Set the default management address. Can't be 0.
require(_management != address(0));
S.management = _management;
// Set the keeper address
S.keeper = _keeper;
// Emit the standard DiamondCut event with the values from our helper contract
emit DiamondCut(
// Struct containing the address of the library,
// the add enum and array of all function selectors.
DiamondHelper(diamondHelper).diamondCut(),
// Init address to call if applicable.
address(0),
// Call data to send the init address if applicable.
new bytes(0)
);
// Tell the registry we have a new strategy deployed.
IRegistry(REGISTRY).newStrategy(address(this), _asset);
}
/*//////////////////////////////////////////////////////////////
ERC4626 FUNCIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Mints `shares` of strategy shares to `receiver` by
* depositing exactly `assets` of underlying tokens.
* @param assets The amount of underlying to deposit in.
* @param receiver The address to receive the `shares`.
* @return shares The actual amount of shares issued.
*/
function deposit(
uint256 assets,
address receiver
) external notShutdown nonReentrant returns (uint256 shares) {
// Check for rounding error.
require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES");
_deposit(receiver, assets, shares);
}
/**
* @notice Mints exactly `shares` of strategy shares to
* `receiver` by depositing `assets` of underlying tokens.
* @param shares The amount of strategy shares mint.
* @param receiver The address to receive the `shares`.
* @return assets The actual amount of asset deposited.
*/
function mint(
uint256 shares,
address receiver
) external notShutdown nonReentrant returns (uint256 assets) {
// Check for rounding error.
require((assets = previewMint(shares)) != 0, "ZERO_ASSETS");
_deposit(receiver, assets, shares);
}
/**
* @notice Redeems `shares` from `owner` and sends `assets`
* of underlying tokens to `receiver`.
* @param assets The amount of underlying to withdraw.
* @param receiver The address to receive `assets`.
* @param owner The address whose shares are burnt.
* @return shares The actual amount of shares burnt.
*/
function withdraw(
uint256 assets,
address receiver,
address owner
) external nonReentrant returns (uint256 shares) {
// Check for rounding error.
require((shares = previewWithdraw(assets)) != 0, "ZERO_SHARES");
_withdraw(receiver, owner, assets, shares);
}
/**
* @notice Redeems exactly `shares` from `owner` and
* sends `assets` of underlying tokens to `receiver`.
* @param shares The amount of shares burnt.
* @param receiver The address to receive `assets`.
* @param owner The address whose shares are burnt.
* @return assets The actual amount of underlying withdrawn.
*/
function redeem(
uint256 shares,
address receiver,
address owner
) external nonReentrant returns (uint256 assets) {
// Check for rounding error.
require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS");
_withdraw(receiver, owner, assets, shares);
}
/**
* @notice The amount of shares that the strategy would
* exchange for the amount of assets provided, in an
* ideal scenario where all the conditions are met.
*
* @param assets The amount of underlying.
* @return . Expected shares that `assets` repersents.
*/
function convertToShares(uint256 assets) public view returns (uint256) {
// Saves an extra SLOAD if totalAssets() is non-zero.
uint256 _totalAssets = totalAssets();
return
_totalAssets == 0
? assets
: assets.mulDiv(
totalSupply(),
_totalAssets,
Math.Rounding.Down
);
}
/**
* @notice The amount of assets that the strategy would
* exchange for the amount of shares provided, in an
* ideal scenario where all the conditions are met.
*
* @param shares The amount of the strategies shares.
* @return . Expected amount of `asset` the shares repersent.
*/
function convertToAssets(uint256 shares) public view returns (uint256) {
// Saves an extra SLOAD if totalSupply() is non-zero.
uint256 supply = totalSupply();
return
supply == 0
? shares
: shares.mulDiv(totalAssets(), supply, Math.Rounding.Down);
}
/**
* @notice Allows an on-chain or off-chain user to simulate
* the effects of their deposit at the current block, given
* current on-chain conditions.
* @dev This will round down.
*/
function previewDeposit(uint256 assets) public view returns (uint256) {
return convertToShares(assets);
}
/**
* @notice Allows an on-chain or off-chain user to simulate
* the effects of their mint at the current block, given
* current on-chain conditions.
* @dev This is used instead of convertToAssets so that it can
* round up for safer mints.
*/
function previewMint(uint256 shares) public view returns (uint256) {
// Saves an extra SLOAD if totalSupply() is non-zero.
uint256 supply = totalSupply();
return
supply == 0
? shares
: shares.mulDiv(totalAssets(), supply, Math.Rounding.Up);
}
/**
* @notice Allows an on-chain or off-chain user to simulate
* the effects of their withdrawal at the current block,
* given current on-chain conditions.
* @dev This is used instead of convertToShares so that it can
* round up for safer withdraws.
*/
function previewWithdraw(uint256 assets) public view returns (uint256) {
// Saves an extra SLOAD if totalAssets() is non-zero.
uint256 _totalAssets = totalAssets();
return
_totalAssets == 0
? assets
: assets.mulDiv(totalSupply(), _totalAssets, Math.Rounding.Up);
}
/**
* @notice Allows an on-chain or off-chain user to simulate
* the effects of their redeemption at the current block,
* given current on-chain conditions.
* @dev This will round down.
*/
function previewRedeem(uint256 shares) public view returns (uint256) {
return convertToAssets(shares);
}
/**
* @notice Total number of underlying assets that can
* be deposited by `_owner` into the strategy, where `_owner`
* corresponds to the msg.sender of a {deposit} call.
*/
function maxDeposit(address _owner) public view returns (uint256) {
return IBaseStrategy(address(this)).availableDepositLimit(_owner);
}
/**
* @notice Total number of shares that can be minted by `_owner`
* into the strategy, where `_owner` corresponds to the msg.sender
* of a {mint} call.
*/
function maxMint(address _owner) public view returns (uint256 _maxMint) {
_maxMint = IBaseStrategy(address(this)).availableDepositLimit(_owner);
if (_maxMint != type(uint256).max) {
_maxMint = convertToShares(_maxMint);
}
}
/**
* @notice Total number of underlying assets that can be
* withdrawn from the strategy by `owner`, where `owner`
* corresponds to the msg.sender of a {redeem} call.
*/
function maxWithdraw(
address _owner
) public view returns (uint256 _maxWithdraw) {
_maxWithdraw = IBaseStrategy(address(this)).availableWithdrawLimit(
_owner
);
if (_maxWithdraw == type(uint256).max) {
// Saves a min check if there is no withdrawal limit.
_maxWithdraw = convertToAssets(balanceOf(_owner));
} else {
_maxWithdraw = Math.min(
convertToAssets(balanceOf(_owner)),
_maxWithdraw
);
}
}
/**
* @notice Total number of strategy shares that can be
* redeemed from the strategy by `owner`, where `owner`
* corresponds to the msg.sender of a {redeem} call.
*/
function maxRedeem(
address _owner
) public view returns (uint256 _maxRedeem) {
_maxRedeem = IBaseStrategy(address(this)).availableWithdrawLimit(
_owner
);
// Conversion would overflow and saves a min check if there is no withdrawal limit.
if (_maxRedeem == type(uint256).max) {
_maxRedeem = balanceOf(_owner);
} else {
_maxRedeem = Math.min(
// Use preview withdraw to round up
previewWithdraw(_maxRedeem),
balanceOf(_owner)
);
}
}
/*//////////////////////////////////////////////////////////////
ACCOUNTING LOGIC
//////////////////////////////////////////////////////////////*/
function totalAssets() public view returns (uint256) {
BaseStrategyData storage S = _baseStrategyStorgage();
unchecked {
return S.totalIdle + S.totalDebt;
}
}
function totalSupply() public view returns (uint256) {
return _baseStrategyStorgage().totalSupply - _unlockedShares();
}
/**
* @dev Function to be called during {deposit} and {mint}.
*
* This function handles all logic including transfers,
* minting and accounting.
*
* We do all external calls before updating any internal
* values to prevent view re-entrancy issues from the token
* transfers or the _invest() calls.
*/
function _deposit(
address receiver,
uint256 assets,
uint256 shares
) private {
require(receiver != address(this), "ERC4626: mint to self");
require(
assets <= maxDeposit(msg.sender),
"ERC4626: deposit more than max"
);
// Cache storage variables used more than once.
BaseStrategyData storage S = _baseStrategyStorgage();
ERC20 _asset = S.asset;
// Need to transfer before minting or ERC777s could reenter.
_asset.safeTransferFrom(msg.sender, address(this), assets);
// We will deposit up to current idle plus the new amount added
uint256 toInvest = S.totalIdle + assets;
// Cache for post {invest} checks.
uint256 beforeBalance = _asset.balanceOf(address(this));
// Invest up to all loose funds.
IBaseStrategy(address(this)).invest(toInvest);
// Always get the actual amount invested. We double check the
// diff agianst toInvest for complete accuracy.
uint256 invested = Math.min(
beforeBalance - _asset.balanceOf(address(this)),
toInvest
);
// Adjust total Assets.
S.totalDebt += invested;
unchecked {
// Cant't underflow due to previous min check.
S.totalIdle = toInvest - invested;
}
// mint shares
_mint(receiver, shares);
emit Deposit(msg.sender, receiver, assets, shares);
}
/**
* @dev To be called during {redeem} and {withdraw}.
*
* This will handle all logic, transfers and accounting
* in order to service the withdraw request.
*
* If we are not able to withdraw the full amount needed, it will
* be counted as a loss and passed on to the user.
*/
function _withdraw(
address receiver,
address owner,
uint256 assets,
uint256 shares
) private {
require(shares <= maxRedeem(owner), "ERC4626: withdraw more than max");
if (msg.sender != owner) {
_spendAllowance(owner, msg.sender, shares);
}
BaseStrategyData storage S = _baseStrategyStorgage();
// Expected beharvior is to need to free funds so we cache `_asset`.
ERC20 _asset = S.asset;
uint256 idle = S.totalIdle;
// Check if we need to withdraw funds.
if (idle < assets) {
// Cache before balance for diff checks.
uint256 before = _asset.balanceOf(address(this));
// Tell implementation to free what we need.
unchecked {
IBaseStrategy(address(this)).freeFunds(assets - idle);
}
// Return the actual amount withdrawn. Adjust for potential overwithdraws.
uint256 withdrawn = Math.min(
_asset.balanceOf(address(this)) - before,
S.totalDebt
);
unchecked {
idle += withdrawn;
}
uint256 loss;
// If we didn't get enough out then we have a loss.
if (idle < assets) {
unchecked {
loss = assets - idle;
}
// Lower the amount to be withdrawn.
assets = idle;
}
// Update debt storage.
S.totalDebt -= (withdrawn + loss);
}
// Update idle based on how much we took.
S.totalIdle = idle - assets;
_burn(owner, shares);
_asset.safeTransfer(receiver, assets);
emit Withdraw(msg.sender, receiver, owner, assets, shares);
}
/*//////////////////////////////////////////////////////////////
PROFIT LOCKING
//////////////////////////////////////////////////////////////*/
/**
* @notice Function for keepers to call to harvest and record all
* profits accrued.
*
* @dev This should be called through protected relays if swaps
* are likely occur.
*
* This will account for any gains/losses since the last report
* and charge fees accordingly.
*
* Any profit over the fees charged will be immediatly locked
* so there is no change in PricePerShare. Then slowly unlocked
* over the `maxProfitUnlockTime` each second based on the
* calculated `profitUnlockingRate`.
*
* Any 'loss' or fees greater than 'profit' will attempted to be
* offset with any remaining locked shares from the last report
* in order to reduce any negative impact to PPS.
*
* Will then recalculate the new time to unlock profits over and the
* rate based on a weighted average of any remaining time from the
* last report and the new amount of shares to be locked.
*
* @return profit The notional amount of gain if any since the last
* report in terms of `asset`.
* @return loss The notional amount of loss if any since the last
* report in terms of `asset`.
*/
function report()
external
nonReentrant
onlyKeepers
returns (uint256 profit, uint256 loss)
{
// Cache storage pointer since its used repeatedly.
BaseStrategyData storage S = _baseStrategyStorgage();
uint256 oldTotalAssets;
unchecked {
// Manuaully calculate totalAssets to save a SLOAD.
oldTotalAssets = S.totalIdle + S.totalDebt;
}
// Calculate protocol fees before we burn shares and
// potentially update lastReport.
(
uint256 totalFees,
address protocolFeesRecipient
) = _assessProtocolFees(oldTotalAssets);
// Burn unlocked shares.
_burnUnlockedShares();
// Tell the strategy to report the real total assets it has.
// It should do all reward selling and reinvesting now and
// account for invested and loose `asset` so we can accuratly
// account for all funds including those potentially airdropped
// by a trade factory. It is safe here to use asset.balanceOf()
// instead of totalIdle because any profits are immediatly locked.
uint256 invested = IBaseStrategy(address(this)).totalInvested();
uint256 performanceFees;
unchecked {
// Calculate profit/loss.
if (invested > oldTotalAssets) {
// We have a profit
profit = invested - oldTotalAssets;
// Asses performance fees.
performanceFees = (profit * S.performanceFee) / MAX_BPS;
totalFees += performanceFees;
} else {
// We have a loss.
loss = oldTotalAssets - invested;
}
}
// We need to get the shares to issue for the fees at
// current PPS before any minting or burning.
uint256 performanceFeeShares = convertToShares(performanceFees);
uint256 protocolFeeShares;
unchecked {
protocolFeeShares = convertToShares(totalFees - performanceFees);
}
uint256 sharesToLock;
if (loss + totalFees >= profit) {
// We have a net loss.
// Will try and unlock the difference between between the gain and the loss
// to prevent any PPS decline post report.
uint256 sharesToBurn = Math.min(
convertToShares((loss + totalFees) - profit),
S.balances[address(this)]
);
if (sharesToBurn > 0) {
_burn(address(this), sharesToBurn);
}
} else {
// we have a net profit
// lock (profit - fees)
unchecked {
sharesToLock = convertToShares(profit - totalFees);
}
_mint(address(this), sharesToLock);
}
// Mint fees shares.
if (performanceFeeShares > 0) {
_mint(S.performanceFeeRecipient, performanceFeeShares);
}
if (protocolFeeShares > 0) {
_mint(protocolFeesRecipient, protocolFeeShares);
}
// Update unlocking rate and time to fully unlocked
{
// Scoped to avoid stack to deep errors
uint256 totalLockedShares = S.balances[address(this)];
uint32 _profitMaxUnlockTime = S.profitMaxUnlockTime;
if (totalLockedShares > 0 && _profitMaxUnlockTime > 0) {
uint256 remainingTime;
uint128 _fullProfitUnlockDate = S.fullProfitUnlockDate;
if (_fullProfitUnlockDate > block.timestamp) {
unchecked {
remainingTime = _fullProfitUnlockDate - block.timestamp;
}
}
uint256 previouslyLockedShares = totalLockedShares -
sharesToLock;
// new_profit_locking_period is a weighted average between the remaining
// time of the previously locked shares and the PROFIT_MAX_UNLOCK_TIME
uint256 newProfitLockingPeriod = (previouslyLockedShares *
remainingTime +
sharesToLock *
_profitMaxUnlockTime) / totalLockedShares;
S.profitUnlockingRate =
(totalLockedShares * MAX_BPS_EXTENDED) /
newProfitLockingPeriod;
S.fullProfitUnlockDate = uint128(
block.timestamp + newProfitLockingPeriod
);
} else {
// Only setting this to 0 will turn in the desired effect,
// no need to update fullProfitUnlockDate
S.profitUnlockingRate = 0;
}
}
// Update storage we use the actual loose here since it should have
// been accounted for in `totalInvested` and any airdropped amounts
// would have been locked to prevent PPS manipulation.
uint256 newIdle = S.asset.balanceOf(address(this));
S.totalIdle = newIdle;
S.totalDebt = invested - newIdle;
S.lastReport = uint128(block.timestamp);
// Emit event with info
emit Reported(
profit,
loss,
performanceFees,
totalFees - performanceFees // Protocol fees
);
}
function _assessProtocolFees(
uint256 _oldTotalAssets
)
private
view
returns (uint256 protocolFees, address protocolFeesRecipient)
{
(
uint16 protocolFeeBps,
uint32 protocolFeeLastChange,
address _protocolFeesRecipient
) = IFactory(FACTORY).protocol_fee_config();
if (protocolFeeBps > 0) {
protocolFeesRecipient = _protocolFeesRecipient;
// Charge fees since last report OR last fee change
// (this will mean less fees are charged after a change
// in protocol_fees, but fees should not change frequently).
uint256 secondsSinceLastReport = Math.min(
block.timestamp - _baseStrategyStorgage().lastReport,
block.timestamp - uint256(protocolFeeLastChange)
);
protocolFees =
(_oldTotalAssets *
uint256(protocolFeeBps) *
secondsSinceLastReport) /
31_556_952 / // Seconds per year
MAX_BPS;
}
}
function _burnUnlockedShares() private {
uint256 unlcokdedShares = _unlockedShares();
if (unlcokdedShares == 0) {
return;
}
// update variables (done here to keep _unlcokdedShares() as a view function)
if (_baseStrategyStorgage().fullProfitUnlockDate > block.timestamp) {
_baseStrategyStorgage().lastReport = uint128(block.timestamp);
}
_burn(address(this), unlcokdedShares);
}
function _unlockedShares() private view returns (uint256 unlockedShares) {
// should save 2 extra calls for most scenarios.
BaseStrategyData storage S = _baseStrategyStorgage();
uint128 _fullProfitUnlockDate = S.fullProfitUnlockDate;
if (_fullProfitUnlockDate > block.timestamp) {
unchecked {
unlockedShares =
(S.profitUnlockingRate * (block.timestamp - S.lastReport)) /
MAX_BPS_EXTENDED;
}
} else if (_fullProfitUnlockDate != 0) {
// All shares have been unlocked.
unlockedShares = S.balances[address(this)];
}
}
/*//////////////////////////////////////////////////////////////
TENDING LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice For a 'keeper' to 'tend' the strategy if a custom
* tendTrigger() is implemented.
*
* @dev Both 'tendTrigger' and '_tend' will need to be overridden
* for this to be used.
*
* This will callback the internal '_tend' call in the BaseStrategy
* with the total current amount available to the strategy to invest.
*
* Keepers are expected to use protected relays in tend calls so this
* can be used for illiquid or manipulatable strategies to compound
* rewards, perform maintence or invest/withdraw funds.
*
* All accounting for totalDebt and totalIdle updates will be done
* here post '_tend'.
*
* This should never cause an increase in PPS. Total assets should
* be the same before and after
*
* A report() call will be needed to record the profit.
*/
function tend() external nonReentrant onlyKeepers {
BaseStrategyData storage S = _baseStrategyStorgage();
// Expected Behavior is this will get used twice so we cache it
uint256 _totalIdle = S.totalIdle;
ERC20 _asset = S.asset;
uint256 beforeBalance = _asset.balanceOf(address(this));
IBaseStrategy(address(this)).tendThis(_totalIdle);
uint256 afterBalance = _asset.balanceOf(address(this));
// Adjust storage according to the changes without adjusting totalAssets().
if (beforeBalance > afterBalance) {
// Idle funds were deposited.
uint256 invested = Math.min(
beforeBalance - afterBalance,
_totalIdle
);
unchecked {
S.totalIdle -= invested;
S.totalDebt += invested;
}
} else if (afterBalance > beforeBalance) {
// We default to use any funds freed as idle for cheaper withdraw/redeems.
uint256 harvested = Math.min(
afterBalance - beforeBalance,
S.totalDebt
);
unchecked {
S.totalIdle += harvested;
S.totalDebt -= harvested;
}
}
}
/*//////////////////////////////////////////////////////////////
Getter FUNCIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Get the api version for this Library.
* @return . The api version for this library
*/
function apiVersion() external pure returns (string memory) {
return API_VERSION;
}
/**
* @notice Get the current total idle for a strategy.
* @return . The current amount of idle funds.
*/
function totalIdle() external view returns (uint256) {
return _baseStrategyStorgage().totalIdle;
}
/**
* @notice Get the current total debt for a strategy.
* @return . The current amount of debt.
*/
function totalDebt() external view returns (uint256) {
return _baseStrategyStorgage().totalDebt;
}
/**
* @notice Get the current address that controls the strategy.
* @return . Address of management
*/
function management() external view returns (address) {
return _baseStrategyStorgage().management;
}
/**
* @notice Get the current address that can call tend and report.
* @return . Address of the keeper
*/
function keeper() external view returns (address) {
return _baseStrategyStorgage().keeper;
}
function performanceFee() external view returns (uint16) {
return _baseStrategyStorgage().performanceFee;
}
/**
* @notice Get the current address that receives the performance fees.
* @return . Address of performanceFeeRecipient
*/
function performanceFeeRecipient() external view returns (address) {
return _baseStrategyStorgage().performanceFeeRecipient;
}
/**
* @notice Gets the timestamp at which all profits will be unlocked.
* @return . The full profit unlocking timestamp
*/
function fullProfitUnlockDate() external view returns (uint256) {
return uint256(_baseStrategyStorgage().fullProfitUnlockDate);
}
/**
* @notice The per second rate at which profits are unlocking.
* @dev This is denominated in EXTENDED_BPS decimals.
* @return . The current profit unlocking rate.
*/
function profitUnlockingRate() external view returns (uint256) {
return _baseStrategyStorgage().profitUnlockingRate;
}
/**
* @notice Gets the current time profits are set to unlock over.
* @return . The current profit max unlock time.
*/
function profitMaxUnlockTime() external view returns (uint256) {
return _baseStrategyStorgage().profitMaxUnlockTime;
}
/**
* @notice The timestamp of the last time protocol fees were charged.
* @return . The last report.
*/
function lastReport() external view returns (uint256) {
return uint256(_baseStrategyStorgage().lastReport);
}
/**
* @notice Get the price per share.
* @dev This value offers limited precision. Integrations that require
* exact precision should use convertToAssets or convertToShares instead.
*
* @return . The price per share.
*/
function pricePerShare() external view returns (uint256) {
return convertToAssets(10 ** _baseStrategyStorgage().decimals);
}
/*//////////////////////////////////////////////////////////////
SETTER FUNCIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Sets a new address to be in charge of the stategy.
* @dev Can only be called by the current `management`.
*
* Cannot set `management` to address(0).
*
* @param _management New address to set `management` to.
*/
function setManagement(address _management) external onlyManagement {
require(_management != address(0), "ZERO ADDRESS");
_baseStrategyStorgage().management = _management;
emit UpdateManagement(_management);
}
/**
* @notice Sets a new address to be in charge of tend and reports.
* @dev Can only be called by the current `management`.
*
* @param _keeper New address to set `keeper` to.
*/
function setKeeper(address _keeper) external onlyManagement {
_baseStrategyStorgage().keeper = _keeper;
emit UpdateKeeper(_keeper);
}
/**
* @notice Sets the performance fee to be charged on a reported gains.
* @dev Can only be called by the current `management`.
*
* Denominated in Baseis Points. So 100% == 10_000.
* Cannot set greateer or equal to 10_000.
*
* @param _performanceFee New performance fee.
*/
function setPerformanceFee(uint16 _performanceFee) external onlyManagement {
require(_performanceFee < MAX_BPS, "MAX BPS");
_baseStrategyStorgage().performanceFee = _performanceFee;
emit UpdatePerformanceFee(_performanceFee);
}
/**
* @notice Sets a new address to recieve performance fees.
* @dev Can only be called by the current `management`.
*
* Cannot set to address(0).
*
* @param _performanceFeeRecipient New address to set `management` to.
*/
function setPerformanceFeeRecipient(
address _performanceFeeRecipient
) external onlyManagement {
require(_performanceFeeRecipient != address(0), "ZERO ADDRESS");
_baseStrategyStorgage()
.performanceFeeRecipient = _performanceFeeRecipient;
emit UpdatePerformanceFeeRecipient(_performanceFeeRecipient);
}
/**
* @notice Sets the time for profits to be unlocked over.
* @dev Can only be called by the current `management`.
*
* Denominated in seconds and cannot be greater than 1 year.
*
* `profitMaxUnlockTime` is stored as a uint32 for packing but can
* be passed in as uint256 for simplicity.
*
* @param _profitMaxUnlockTime New `profitMaxUnlockTime`.
*/
function setProfitMaxUnlockTime(
uint256 _profitMaxUnlockTime
) external onlyManagement {
require(_profitMaxUnlockTime <= 31_556_952, "to long");
_baseStrategyStorgage().profitMaxUnlockTime = uint32(
_profitMaxUnlockTime
);
emit UpdateProfitMaxUnlockTime(_profitMaxUnlockTime);
}
/**
* @notice Used to shutdown the strategy preventing any further deposits.
* @dev Can only be called by the current `management`.
*
* This will stop any new {deposit} or {mint} calls but will
* not prevent {withdraw} or {redeem}. It will also still allow for
* {tend} and {report} so that management can report any last losses
* in an emergency as well as provide any maintence to allow for full
* withdraw.
*
* This is a one way switch and can never be set back once shutdown.
*/
function shutdownStrategy() external onlyManagement {
_baseStrategyStorgage().shutdown = true;
emit StrategyShutdown();
}
/*//////////////////////////////////////////////////////////////
EXTERNAL ERC-2535 VIEW FUNCTIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Gets all facet addresses and their four byte function selectors.
* @return facets_ Facet
*/
function facets() external view returns (IDiamondLoupe.Facet[] memory) {
return DiamondHelper(diamondHelper).facets();
}
/**
* @notice Gets all the function selectors supported by a specific facet.
* @param _facet The facet address.
* @return facetFunctionSelectors_
*/
function facetFunctionSelectors(
address _facet
) external view returns (bytes4[] memory) {
return DiamondHelper(diamondHelper).facetFunctionSelectors(_facet);
}
/**
* @notice Get all the facet addresses used by a diamond.
* @return facetAddresses_
*/
function facetAddresses() external view returns (address[] memory) {
return DiamondHelper(diamondHelper).facetAddresses();
}
/**
* @notice Gets the facet that supports the given selector.
* @dev If facet is not found return address(0).
* @param _functionSelector The function selector.
* @return facetAddress_ The facet address.
*/
function facetAddress(
bytes4 _functionSelector
) external view returns (address) {
return DiamondHelper(diamondHelper).facetAddress(_functionSelector);
}
/*//////////////////////////////////////////////////////////////
ERC20 FUNCIONS
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns the name of the token.
* @return . The name the strategy is using for its token.
*/
function name() public view returns (string memory) {
return _baseStrategyStorgage().name;
}
/**
* @notice Returns the symbol of the token.
* @dev Should be some iteration of 'ys + asset symbol'
* @return . The symbol the strategy is using for its tokens.
*/
function symbol() public view returns (string memory) {
return string(abi.encodePacked((_baseStrategyStorgage().symbol)));
}
/**
* @notice Returns the number of decimals used to get its user representation.
* @return . The decimals used for the strategy and `asset`.
*/
function decimals() public view returns (uint8) {
return _baseStrategyStorgage().decimals;
}
/**
* @notice Returns the current balance for a given '_account'.
* @dev If the '_account` is the strategy then this will subtract
* the amount of shares that have been unlocked since the last profit first.
* @param account the address to return the balance for.
* @return . The current balance in y shares of the '_account'.
*/
function balanceOf(address account) public view returns (uint256) {
if (account == address(this)) {
return
_baseStrategyStorgage().balances[account] - _unlockedShares();
}
return _baseStrategyStorgage().balances[account];
}
/**
* @notice Transfer '_amount` of shares from `msg.sender` to `to`.
* @dev
* Requirements:
*
* - `to` cannot be the zero address.
* - `to` cannot be the address of the strategy.
* - the caller must have a balance of at least `_amount`.
*
* @param to The address shares will be transferred to.
* @param amount The amount of shares to be transferred from sender.
* @return . a boolean value indicating whether the operation succeeded.
*/
function transfer(address to, uint256 amount) public returns (bool) {
_transfer(msg.sender, to, amount);
return true;
}
/**
* @notice 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.
* @param owner The address who owns the shares.
* @param spender The address who would be moving the owners shares.
* @return . The remaining amount of shares of `owner` that could be moved by `spender`.
*/
function allowance(
address owner,
address spender
) public view returns (uint256) {
return _baseStrategyStorgage().allowances[owner][spender];
}
/**
* @notice Sets `amount` as the allowance of `spender` over the caller's tokens.
* @dev
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*
* 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.
*
* @param spender the address to allow the shares to be moved by.
* @param amount the amount of shares to allow `spender` to move.
* @return . a boolean value indicating whether the operation succeeded.
*/
function approve(address spender, uint256 amount) public returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
/**
* @notice `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* @dev
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `to` cannot be the address of the strategy.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*
* Emits a {Transfer} event.
*
* @param from the address to be moving shares from.
* @param to the address to be moving shares to.
* @param amount the quantity of shares to move.
* @return . a boolean value indicating whether the operation succeeded.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public returns (bool) {
_spendAllowance(from, msg.sender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @notice Atomically increases the allowance granted to `spender` by the caller.
*
* @dev 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.
* - cannot give spender over uint256.max allowance
*
* @param spender the account that will be able to move the senders shares.
* @param addedValue the extra amount to add to the current allowance.
* @return . a boolean value indicating whether the operation succeeded.
*/
function increaseAllowance(
address spender,
uint256 addedValue
) public returns (bool) {
address owner = msg.sender;
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @notice Atomically decreases the allowance granted to `spender` by the caller.
*
* @dev 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`.
*
* @param spender the account that will be able to move less of the senders shares.
* @param subtractedValue the amount to decrease the current allowance by.
* @return . a boolean value indicating whether the operation succeeded.
*/
function decreaseAllowance(
address spender,
uint256 subtractedValue
) public returns (bool) {
address owner = msg.sender;
_approve(owner, spender, allowance(owner, spender) - subtractedValue);
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* 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:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `to` cannot be the strategies address
* - `from` must have a balance of at least `amount`.
*
*/
function _transfer(address from, address to, uint256 amount) private {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
require(to != address(this), "ERC20 transfer to strategy");
BaseStrategyData storage S = _baseStrategyStorgage();
S.balances[from] -= amount;
unchecked {
S.balances[to] += amount;
}
emit Transfer(from, to, 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) private {
require(account != address(0), "ERC20: mint to the zero address");
BaseStrategyData storage S = _baseStrategyStorgage();
S.totalSupply += amount;
unchecked {
S.balances[account] += amount;
}
emit Transfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) private {
require(account != address(0), "ERC20: burn from the zero address");
BaseStrategyData storage S = _baseStrategyStorgage();
S.balances[account] -= amount;
unchecked {
S.totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) private {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_baseStrategyStorgage().allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) private {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(
currentAllowance >= amount,
"ERC20: insufficient allowance"
);
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
/**
* @notice Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* @dev Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*
* @param _owner the address of the account to return the nonce for.
* @return . the current nonce for the account.
*/
function nonces(address _owner) external view returns (uint256) {
return _baseStrategyStorgage().nonces[_owner];
}
/**
* @notice Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* @dev IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public {
require(deadline >= block.timestamp, "ERC20: PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
_baseStrategyStorgage().nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(
recoveredAddress != address(0) && recoveredAddress == owner,
"ERC20: INVALID_SIGNER"
);
_approve(recoveredAddress, spender, value);
}
}
/**
* @notice Returns the domain separator used in the encoding of the signature
* for {permit}, as defined by {EIP712}.
*
* @dev This checks that the current chain id is the same as when the contract was deployed to
* prevent replay attacks. If false it will calculate a new domain seperator based on the new chain id.
*
* @return . The domain seperator that will be used for any {permit} calls.
*/
function DOMAIN_SEPARATOR() public view returns (bytes32) {
BaseStrategyData storage S = _baseStrategyStorgage();
return
block.chainid == S.INITIAL_CHAIN_ID
? S.INITIAL_DOMAIN_SEPARATOR
: _computeDomainSeparator();
}
/**
* @dev Calculates and returns the domain seperator to be used in any
* permit functions for the strategies {permit} calls.
*
* This will be used at the initilization of each new strategies storage.
* It would then be used in the future in the case of any forks in which
* the current chain id is not the same as the origin al.
*
*/
function _computeDomainSeparator() internal view returns (bytes32) {
return
keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
),
keccak256(bytes(_baseStrategyStorgage().name)),
keccak256(bytes(API_VERSION)),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
CLONING
//////////////////////////////////////////////////////////////*/
/**
* @notice Used to create a new clone of the calling stategy.
* @dev This can be called through a normal delegate call directly
* to the library however that will leave all implementation
* sepcific setup uncompleted.
*
* The recommended use for strategies that wish to utilize cloning
* is to declare a implemtation specific {clone} that will then call
* `BaseLibrary.clone(data)` so it can implement its own initiliaztion.
*
* This can't be called through a strategy that is a clone. All
* cloning must come through the original contract that can be
* viewed by the `isOriginal` variable in all strategies.
*
* @param _asset Address of the underlying asset.
* @param _name Name the strategy will use.
* @param _management Address to set as the strategies `management`.
* @param _performanceFeeRecipient Address to receive performance fees.
* @param _keeper Address to set as strategies `keeper`.
* @return newStrategy The address of the new clone.
*/
function clone(
address _asset,
string memory _name,
address _management,
address _performanceFeeRecipient,
address _keeper
) external returns (address newStrategy) {
require(IBaseStrategy(address(this)).isOriginal(), "!clone");
// 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)
}
IBaseStrategy(newStrategy).initialize(
_asset,
_name,
_management,
_performanceFeeRecipient,
_keeper
);
emit Cloned(newStrategy, address(this));
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"clone","type":"address"},{"indexed":true,"internalType":"address","name":"original","type":"address"}],"name":"Cloned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"facetAddress","type":"address"},{"internalType":"enum IDiamond.FacetCutAction","name":"action","type":"uint8"},{"internalType":"bytes4[]","name":"functionSelectors","type":"bytes4[]"}],"indexed":false,"internalType":"struct IDiamond.FacetCut[]","name":"_diamondCut","type":"tuple[]"},{"indexed":false,"internalType":"address","name":"_init","type":"address"},{"indexed":false,"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"DiamondCut","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":"performanceFees","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFees","type":"uint256"}],"name":"Reported","type":"event"},{"anonymous":false,"inputs":[],"name":"StrategyShutdown","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newKeeper","type":"address"}],"name":"UpdateKeeper","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newManagement","type":"address"}],"name":"UpdateManagement","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"newPerformanceFee","type":"uint16"}],"name":"UpdatePerformanceFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newPerformanceFeeRecipient","type":"address"}],"name":"UpdatePerformanceFeeRecipient","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newProfitMaxUnlockTime","type":"uint256"}],"name":"UpdateProfitMaxUnlockTime","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"apiVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_functionSelector","type":"bytes4"}],"name":"facetAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"facetAddresses","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_facet","type":"address"}],"name":"facetFunctionSelectors","outputs":[{"internalType":"bytes4[]","name":"","type":"bytes4[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"facets","outputs":[{"components":[{"internalType":"address","name":"facetAddress","type":"address"},{"internalType":"bytes4[]","name":"functionSelectors","type":"bytes4[]"}],"internalType":"struct IDiamondLoupe.Facet[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fullProfitUnlockDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"}],"name":"isKeeperOrManagement","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"}],"name":"isManagement","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isShutdown","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":"lastReport","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"management","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"_maxMint","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"_maxRedeem","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"_maxWithdraw","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"performanceFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"performanceFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"profitMaxUnlockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"profitUnlockingRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalIdle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
61466a61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106103985760003560e01c806388a8d602116101e8578063bf86d69011610119578063d505accf116100b7578063ec0c7e2811610086578063ec0c7e2814610875578063ed27f7c914610888578063ef8b30f714610890578063fc7b9c18146108a357600080fd5b8063d505accf1461080f578063d905777e1461082f578063dd62ed3e14610842578063df69b22a1461085557600080fd5b8063c6e6f592116100f3578063c6e6f592146107b6578063cdffacc6146107c9578063ce96cb77146107dc578063d4a22bde146107ef57600080fd5b8063bf86d69014610793578063c3535b521461079b578063c63d75b6146107a357600080fd5b8063aa290e6d11610186578063b3d7f6b911610160578063b3d7f6b91461072b578063b460af941461073e578063ba0876521461075e578063be8f16681461077e57600080fd5b8063aa290e6d146106e3578063aced166114610703578063adfca15e1461070b57600080fd5b806399530b06116101c257806399530b06146106935780639aa7df941461069b578063a457c2d7146106a3578063a9059cbb146106c357600080fd5b806388a8d6021461066357806394bf804d1461066b57806395d89b411461068b57600080fd5b80633644e515116102cd5780635e04a4d61161026b578063748747e61161023a578063748747e6146106005780637a0ed627146106205780637ecebe0014610635578063877887821461064857600080fd5b80635e04a4d6146105755780636a5f1aa2146105ad5780636e553f65146105cd57806370a08231146105ed57600080fd5b8063440368a3116102a7578063440368a3146105305780634cdad506146105455780635141eebb1461055857806352ef6b2c1461056057600080fd5b80633644e515146104f557806339509351146104fd578063402d267d1461051d57600080fd5b80631d3b72271161033a5780632606a10b116103145780632606a10b146104895780632d632692146104b35780632ecfe315146104bb578063313ce567146104db57600080fd5b80631d3b72271461043357806323b872dd14610448578063258294101461046857600080fd5b80630952864e116103765780630952864e146103e0578063095ea7b3146103e85780630a28a4771461041857806318160ddd1461042b57600080fd5b806301e1d1141461039d57806306fdde03146103b857806307a2d13a146103cd575b600080fd5b6103a56108ab565b6040519081526020015b60405180910390f35b6103c06108c8565b6040516103af919061376c565b6103a56103db36600461377f565b610963565b6103a5610999565b8180156103f457600080fd5b506104086104033660046137b8565b6109b2565b60405190151581526020016103af565b6103a561042636600461377f565b6109c9565b6103a56109f1565b6104466104413660046137e4565b610a16565b005b81801561045457600080fd5b50610408610463366004613801565b610a93565b6040805180820190915260058152640332e312e360dc1b60208201526103c0565b81801561049557600080fd5b5061049e610ab5565b604080519283526020830191909152016103af565b6103a5610ec1565b8180156104c757600080fd5b506104466104d63660046138fd565b610edd565b6104e3611270565b60405160ff90911681526020016103af565b6103a561128a565b81801561050957600080fd5b506104086105183660046137b8565b6112bb565b6103a561052b3660046137e4565b6112dd565b81801561053c57600080fd5b50610446611348565b6103a561055336600461377f565b61156d565b6103a5611578565b61056861158b565b6040516103af91906139c2565b81801561058157600080fd5b506105956105903660046138fd565b611607565b6040516001600160a01b0390911681526020016103af565b8180156105b957600080fd5b506104466105c83660046137e4565b611791565b8180156105d957600080fd5b506103a56105e8366004613a0f565b611841565b6103a56105fb3660046137e4565b611939565b81801561060c57600080fd5b5061044661061b3660046137e4565b6119ac565b610628611a0b565b6040516103af9190613a84565b6103a56106433660046137e4565b611a87565b610650611ab3565b60405161ffff90911681526020016103af565b610595611ad2565b81801561067757600080fd5b506103a5610686366004613a0f565b611aee565b6103c0611bd2565b6103a5611c11565b6103a5611c34565b8180156106af57600080fd5b506104086106be3660046137b8565b611c47565b8180156106cf57600080fd5b506104086106de3660046137b8565b611c64565b8180156106ef57600080fd5b506104466106fe366004613b11565b611c71565b610595611d19565b61071e6107193660046137e4565b611d35565b6040516103af9190613b2e565b6103a561073936600461377f565b611db8565b81801561074a57600080fd5b506103a5610759366004613b41565b611dd6565b81801561076a57600080fd5b506103a5610779366004613b41565b611e8f565b81801561078a57600080fd5b50610446611f33565b610408611f8e565b6103a5611fab565b6103a56107b13660046137e4565b611fce565b6103a56107c436600461377f565b612052565b6105956107d7366004613b99565b612070565b6103a56107ea3660046137e4565b6120f0565b8180156107fb57600080fd5b5061044661080a3660046137e4565b612187565b81801561081b57600080fd5b5061044661082a366004613bc5565b61222b565b6103a561083d3660046137e4565b612431565b6103a5610850366004613c36565b6124ca565b81801561086157600080fd5b5061044661087036600461377f565b612504565b6104466108833660046137e4565b61259f565b6105956125f6565b6103a561089e36600461377f565b612619565b6103a5612624565b6000806108b6612637565b60098101546008909101540192915050565b60606108d2612637565b60010180546108e090613c64565b80601f016020809104026020016040519081016040528092919081815260200182805461090c90613c64565b80156109595780601f1061092e57610100808354040283529160200191610959565b820191906000526020600020905b81548152906001019060200180831161093c57829003601f168201915b5050505050905090565b60008061096e6109f1565b905080156109905761098b6109816108ab565b8490836000612665565b610992565b825b9392505050565b60006109a3612637565b600c015463ffffffff16919050565b60006109bf3384846126c4565b5060015b92915050565b6000806109d46108ab565b905080156109905761098b6109e76109f1565b8490836001612665565b60006109fb6127f9565b610a03612637565b60020154610a119190613cb4565b905090565b6000610a20612637565b600e8101549091506001600160a01b0383811691161480610a505750600d8101546001600160a01b038381169116145b610a8f5760405162461bcd60e51b815260206004820152600b60248201526a08505d5d1a1bdc9a5e995960aa1b60448201526064015b60405180910390fd5b5050565b6000610aa0843384612872565b610aab8484846128ec565b5060019392505050565b6000806000610ac2612637565b600e810154909150600160a01b900460ff1615610af15760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b179055610b0f33610a16565b6000610b19612637565b6009810154600882015491925001600080610b3383612aae565b91509150610b3f612bbe565b6000306001600160a01b0316635216aeec6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610b81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba59190613cfe565b9050600084821115610bd957600c860154858303995061271090640100000000900461ffff168a0204938401939050610bdf565b81850397505b6000610bea82612052565b90506000610bf9838703612052565b905060008b610c08888d613d2d565b10610c5b576000610c43610c2c8e8a8f610c229190613d2d565b6107c49190613cb4565b30600090815260068d016020526040902054612c23565b90508015610c5557610c553082612c32565b50610c72565b610c66878d03612052565b9050610c723082612d19565b8215610c9757600c890154610c9790600160301b90046001600160a01b031684612d19565b8115610ca757610ca78683612d19565b30600090815260068a016020526040902054600c8a015463ffffffff168115801590610cd9575060008163ffffffff16115b15610da657600b8b01546000906001600160801b031642811115610d065742816001600160801b03160391505b6000610d128686613cb4565b9050600085610d2763ffffffff871689613d40565b610d318685613d40565b610d3b9190613d2d565b610d459190613d57565b905080610d5764e8d4a5100088613d40565b610d619190613d57565b8f600a01819055508042610d759190613d2d565b8f600b0160006101000a8154816001600160801b0302191690836001600160801b0316021790555050505050610dae565b6000600a8c01555b505088546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610df8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1c9190613cfe565b60088b018190559050610e2f8187613cb4565b60098b0155600b8a0180546001600160801b03428116600160801b0291161790557fecdd072e4d5bd913a75a37f02daedcea7e2dc0281f9942c0063cfd1cfe5c4c4f8d8d87610e7e818d613cb4565b60408051948552602085019390935291830152606082015260800160405180910390a1505050600e909701805460ff60a01b191690555096979596505050505050565b6000610ecb612637565b600b01546001600160801b0316919050565b6000610ee7612637565b80549091506001600160a01b031615610eff57600080fd5b80546001600160a01b0319166001600160a01b03871617815560018101610f268682613dc7565b506000869050806001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610f6a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f929190810190613e87565b604051602001610fa29190613efe565b604051602081830303815290604052610fba90613f28565b8260000160156101000a81548169ffffffffffffffffffff021916908360b01c0217905550806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561101d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110419190613f5f565b825460ff91909116600160a01b0260ff60a01b19909116178255466003830155611069612de3565b6004830155600c8201805463ffffffff1916620d2f001790556001600160a01b03841661109557600080fd5b600c820180546503e80000000065ffff00000000196001600160a01b03808916600160301b0291909116640100000000600160d01b03199093169290921717909155600b830180546001600160801b03428116600160801b02911617905585166110fe57600080fd5b600d820180546001600160a01b038088166001600160a01b031992831617909255600e840180549286169290911691909117905560408051630d8e30e760e41b815290517f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb67391739bcc5f7560b243e37e0adf8379fa6d9ab49a425b9163d8e30e70916004808201926000929091908290030181865afa1580156111a5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111cd919081019061400f565b604080516000808252602082019092526040516111ec93929190614135565b60405180910390a160405163065b719960e51b81523060048201526001600160a01b0388166024820152731dbcecb8e3fed0151c2b2bcec288cf8e420226699063cb6e332090604401600060405180830381600087803b15801561124f57600080fd5b505af1158015611263573d6000803e3d6000fd5b5050505050505050505050565b600061127a612637565b54600160a01b900460ff16919050565b600080611295612637565b9050806003015446146112af576112aa612de3565b6112b5565b80600401545b91505090565b600033610aab8185856112ce83836124ca565b6112d89190613d2d565b6126c4565b604051632355178960e11b81526001600160a01b038216600482015260009030906346aa2f1290602401602060405180830381865afa158015611324573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c39190613cfe565b6000611352612637565b600e810154909150600160a01b900460ff16156113815760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b17905561139f33610a16565b60006113a9612637565b600881015481546040516370a0823160e01b815230600482015292935090916001600160a01b039091169060009082906370a0823190602401602060405180830381865afa1580156113ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114239190613cfe565b60405163275fedc360e21b8152600481018590529091503090639d7fb70c90602401600060405180830381600087803b15801561145f57600080fd5b505af1158015611473573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03851691506370a0823190602401602060405180830381865afa1580156114be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e29190613cfe565b90508082111561151d5760006115016114fb8385613cb4565b86612c23565b6008870180548290039055600987018054909101905550611556565b8181111561155657600061153e6115348484613cb4565b8760090154612c23565b60088701805482019055600987018054919091039055505b505050600e909201805460ff60a01b191690555050565b60006109c382610963565b6000611582612637565b600a0154905090565b6060739bcc5f7560b243e37e0adf8379fa6d9ab49a425b6001600160a01b03166352ef6b2c6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156115df573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a119190810190614235565b6000306001600160a01b0316636f392ce76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611647573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166b91906142c4565b6116a05760405162461bcd60e51b815260206004820152600660248201526521636c6f6e6560d01b6044820152606401610a86565b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81523060601b601482018190526e5af43d82803e903d91602b57fd5bf360881b6028830152906037816000f0604051634b839d7360e11b81529093506001600160a01b03841691506397073ae69061171f908a908a908a908a908a906004016142e6565b600060405180830381600087803b15801561173957600080fd5b505af115801561174d573d6000803e3d6000fd5b50506040513092506001600160a01b03851691507fae93c8e84b9065113a0230417359f283712a933bdab9abc10fcb1179edc6b1c890600090a35095945050505050565b61179a3361259f565b6001600160a01b0381166117df5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204144445245535360a01b6044820152606401610a86565b806117e8612637565b600c0180546601000000000000600160d01b031916600160301b6001600160a01b0393841602179055604051908216907f9ebbf695dd251e855d9d15a146a72f5f654dc6f8630fbc11212f27e0c88ba11a90600090a250565b600061184b611f8e565b156118835760405162461bcd60e51b815260206004820152600860248201526739b43aba3237bbb760c11b6044820152606401610a86565b600061188d612637565b600e810154909150600160a01b900460ff16156118bc5760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b1790556118da84612619565b91508160000361191a5760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f53484152455360a81b6044820152606401610a86565b611925838584612e9f565b600e01805460ff60a01b1916905592915050565b6000306001600160a01b03831603611982576119536127f9565b61195b612637565b6001600160a01b038416600090815260069190910160205260409020546109c39190613cb4565b61198a612637565b6001600160a01b03909216600090815260069290920160205250604090205490565b6119b53361259f565b806119be612637565b600e0180546001600160a01b0319166001600160a01b03928316179055604051908216907fd7f49e282c36d417b290d4181a56943f6d670aaa2987c0d40e60d39919c6888290600090a250565b6060739bcc5f7560b243e37e0adf8379fa6d9ab49a425b6001600160a01b0316637a0ed6276040518163ffffffff1660e01b8152600401600060405180830381865afa158015611a5f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a119190810190614327565b6000611a91612637565b6001600160a01b03909216600090815260059290920160205250604090205490565b6000611abd612637565b600c0154640100000000900461ffff16919050565b6000611adc612637565b600d01546001600160a01b0316919050565b6000611af8611f8e565b15611b305760405162461bcd60e51b815260206004820152600860248201526739b43aba3237bbb760c11b6044820152606401610a86565b6000611b3a612637565b600e810154909150600160a01b900460ff1615611b695760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b179055611b8784611db8565b915081600003611bc75760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f41535345545360a81b6044820152606401610a86565b611925838386612e9f565b6060611bdc612637565b54604051600160a81b90910460b01b6001600160b01b0319166020820152602a01604051602081830303815290604052905090565b6000610a11611c1e612637565b546103db90600160a01b900460ff16600a6144f6565b6000611c3e612637565b60080154905090565b600033610aab818585611c5a83836124ca565b6112d89190613cb4565b60006109bf3384846128ec565b611c7a3361259f565b6127108161ffff1610611cb95760405162461bcd60e51b81526020600482015260076024820152664d41582042505360c81b6044820152606401610a86565b80611cc2612637565b600c01805465ffff00000000191664010000000061ffff9384160217905560405190821681527fdc843735e683348ec21c302ffff45462399c5c46f75f67b0a1a5395c53599753906020015b60405180910390a150565b6000611d23612637565b600e01546001600160a01b0316919050565b6040516356fe50af60e11b81526001600160a01b0382166004820152606090739bcc5f7560b243e37e0adf8379fa6d9ab49a425b9063adfca15e90602401600060405180830381865afa158015611d90573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109c39190810190614505565b600080611dc36109f1565b905080156109905761098b6109e76108ab565b600080611de1612637565b600e810154909150600160a01b900460ff1615611e105760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b179055611e2e856109c9565b915081600003611e6e5760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f53484152455360a81b6044820152606401610a86565b611e7a8484878561313a565b600e01805460ff60a01b191690559392505050565b600080611e9a612637565b600e810154909150600160a01b900460ff1615611ec95760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b179055611ee78561156d565b915081600003611f275760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f41535345545360a81b6044820152606401610a86565b611e7a8484848861313a565b611f3c3361259f565b6001611f46612637565b600e018054911515600160a81b0260ff60a81b199092169190911790556040517ffc1249757a7f27c510c8173c55d03ba442e0d33d9223e06ceb416feac8c7693f90600090a1565b6000611f98612637565b600e0154600160a81b900460ff16919050565b6000611fb5612637565b600b0154600160801b90046001600160801b0316919050565b604051632355178960e11b81526001600160a01b038216600482015260009030906346aa2f1290602401602060405180830381865afa158015612015573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120399190613cfe565b9050600019811461204d576109c381612052565b919050565b60008061205d6108ab565b905080156109905761098b6109816109f1565b6040516366ffd66360e11b81526001600160e01b031982166004820152600090739bcc5f7560b243e37e0adf8379fa6d9ab49a425b9063cdffacc690602401602060405180830381865afa1580156120cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c3919061453a565b6040516304bd462960e01b81526001600160a01b038216600482015260009030906304bd462990602401602060405180830381865afa158015612137573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215b9190613cfe565b90506000198103612172576109c36103db83611939565b6109c36121816103db84611939565b82612c23565b6121903361259f565b6001600160a01b0381166121d55760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204144445245535360a01b6044820152606401610a86565b806121de612637565b600d0180546001600160a01b0319166001600160a01b03928316179055604051908216907fff54978127edd34aec0f9061fb3b155fbe0ededdfa881ee3e0d541d3a1eef43890600090a250565b4284101561227b5760405162461bcd60e51b815260206004820152601e60248201527f45524332303a205045524d49545f444541444c494e455f4558504952454400006044820152606401610a86565b6000600161228761128a565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98a8a8a6122b3612637565b6001600160a01b038f8116600090815260059290920160209081526040928390208054600181019091558351808301989098529582168784015293166060860152608085019190915260a084019290925260c08084018b90528251808503909101815260e08401909252815191012061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156123a2573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906123d85750876001600160a01b0316816001600160a01b0316145b61241c5760405162461bcd60e51b815260206004820152601560248201527422a92199181d1024a72b20a624a22fa9a4a3a722a960591b6044820152606401610a86565b6124278188886126c4565b5050505050505050565b6040516304bd462960e01b81526001600160a01b038216600482015260009030906304bd462990602401602060405180830381865afa158015612478573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249c9190613cfe565b905060001981036124b0576109c382611939565b6109c36124bc826109c9565b6124c584611939565b612c23565b60006124d4612637565b6001600160a01b039384166000908152600791909101602090815260408083209490951682529290925250205490565b61250d3361259f565b6301e1855881111561254b5760405162461bcd60e51b8152602060048201526007602482015266746f206c6f6e6760c81b6044820152606401610a86565b80612554612637565b600c01805463ffffffff191663ffffffff929092169190911790556040518181527ff361aed463da6fa20358e45c6209f1d3e16d4eca706e6eab0b0aeb338729c77a90602001611d0e565b6125a7612637565b600d01546001600160a01b038281169116146125f35760405162461bcd60e51b815260206004820152600b60248201526a08505d5d1a1bdc9a5e995960aa1b6044820152606401610a86565b50565b6000612600612637565b600c0154600160301b90046001600160a01b0316919050565b60006109c382612052565b600061262e612637565b60090154905090565b6000806109c360017fd2841a5d2692465040bd5e06a6f3b37483952c866e0f304dc0e03f76a1f8a0b1613cb4565b6000806126738686866133d8565b905060018360028111156126895761268961411f565b1480156126a65750600084806126a1576126a1613d17565b868809115b156126b9576126b6600182613d2d565b90505b90505b949350505050565b6001600160a01b0383166127265760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610a86565b6001600160a01b0382166127875760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a86565b80612790612637565b6001600160a01b038581166000818152600793909301602090815260408085209388168086529382529384902094909455915184815290927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b600080612804612637565b600b8101549091506001600160801b03164281111561284957600b820154600a83015464e8d4a5100091600160801b90046001600160801b0316420302049250505090565b6001600160801b0381161561286d5730600090815260068301602052604090205492505b505090565b600061287e84846124ca565b905060001981146128e657818110156128d95760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a86565b6128e684848484036126c4565b50505050565b6001600160a01b0383166129505760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610a86565b6001600160a01b0382166129b25760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610a86565b306001600160a01b03831603612a0a5760405162461bcd60e51b815260206004820152601a60248201527f4552433230207472616e7366657220746f2073747261746567790000000000006044820152606401610a86565b6000612a14612637565b6001600160a01b0385166000908152600682016020526040812080549293508492909190612a43908490613cb4565b90915550506001600160a01b038084166000818152600684016020526040908190208054860190555190918616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612aa09086815260200190565b60405180910390a350505050565b600080600080600073a8f46c3f5a89fbc3c80b3ee333a1daf8fa7190616001600160a01b0316635153b1996040518163ffffffff1660e01b8152600401606060405180830381865afa158015612b08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b2c9190614557565b9194509250905061ffff831615612bb6578093506000612b7b612b4d612637565b600b0154612b6b90600160801b90046001600160801b031642613cb4565b6124c563ffffffff861642613cb4565b90506127106301e1855882612b9461ffff88168b613d40565b612b9e9190613d40565b612ba89190613d57565b612bb29190613d57565b9550505b505050915091565b6000612bc86127f9565b905080600003612bd55750565b42612bde612637565b600b01546001600160801b03161115612c195742612bfa612637565b600b0180546001600160801b03928316600160801b0292169190911790555b6125f33082612c32565b60008183106109905781610992565b6001600160a01b038216612c925760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610a86565b6000612c9c612637565b6001600160a01b0384166000908152600682016020526040812080549293508492909190612ccb908490613cb4565b909155505060028101805483900390556040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016127ec565b6001600160a01b038216612d6f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a86565b6000612d79612637565b905081816002016000828254612d8f9190613d2d565b90915550506001600160a01b03831660008181526006830160209081526040808320805487019055518581527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91016127ec565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f612e0e612637565b600101604051612e1e91906145a2565b60408051918290038220828201825260058352640332e312e360dc1b6020938401528151928301939093528101919091527f0e23d0b508e2034d01a5c31f12e9d9bbb31708c5518057dde31201ab93b17cef60608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b306001600160a01b03841603612eef5760405162461bcd60e51b815260206004820152601560248201527422a9219a1b191b1d1036b4b73a103a379039b2b63360591b6044820152606401610a86565b612ef8336112dd565b821115612f475760405162461bcd60e51b815260206004820152601e60248201527f455243343632363a206465706f736974206d6f7265207468616e206d617800006044820152606401610a86565b6000612f51612637565b80549091506001600160a01b0316612f6b81333087613487565b6000848360080154612f7d9190613d2d565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038416906370a0823190602401602060405180830381865afa158015612fc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612feb9190613cfe565b6040516255f9e960e71b8152600481018490529091503090632afcf48090602401600060405180830381600087803b15801561302657600080fd5b505af115801561303a573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506130bd91506001600160a01b038616906370a0823190602401602060405180830381865afa158015613089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ad9190613cfe565b6130b79084613cb4565b84612c23565b9050808560090160008282546130d39190613d2d565b909155505080830360088601556130ea8887612d19565b60408051888152602081018890526001600160a01b038a169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a35050505050505050565b61314383612431565b8111156131925760405162461bcd60e51b815260206004820152601f60248201527f455243343632363a207769746864726177206d6f7265207468616e206d6178006044820152606401610a86565b336001600160a01b038416146131ad576131ad833383612872565b60006131b7612637565b805460088201549192506001600160a01b03169084811015613357576040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa15801561321a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061323e9190613cfe565b604051633d6cb57560e01b815283880360048201529091503090633d6cb57590602401600060405180830381600087803b15801561327b57600080fd5b505af115801561328f573d6000803e3d6000fd5b50506040516370a0823160e01b815230600482015260009250613318915083906001600160a01b038716906370a0823190602401602060405180830381865afa1580156132e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133049190613cfe565b61330e9190613cb4565b8660090154612c23565b9283019290506000878410156133315783880390508397505b61333b8183613d2d565b86600901600082825461334e9190613cb4565b90915550505050505b6133618582613cb4565b60088401556133708685612c32565b6133846001600160a01b03831688876134f2565b60408051868152602081018690526001600160a01b0380891692908a169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a450505050505050565b60008080600019858709858702925082811083820303915050806000036134125783828161340857613408613d17565b0492505050610992565b80841161341e57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040516001600160a01b03808516602483015283166044820152606481018290526128e69085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613527565b6040516001600160a01b03831660248201526044810182905261352290849063a9059cbb60e01b906064016134bb565b505050565b600061357c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135f99092919063ffffffff16565b805190915015613522578080602001905181019061359a91906142c4565b6135225760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a86565b60606126bc848460008585600080866001600160a01b031685876040516136209190614618565b60006040518083038185875af1925050503d806000811461365d576040519150601f19603f3d011682016040523d82523d6000602084013e613662565b606091505b50915091506136738783838761367e565b979650505050505050565b606083156136ed5782516000036136e6576001600160a01b0385163b6136e65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a86565b50816126bc565b6126bc83838151156137025781518083602001fd5b8060405162461bcd60e51b8152600401610a86919061376c565b60005b8381101561373757818101518382015260200161371f565b50506000910152565b6000815180845261375881602086016020860161371c565b601f01601f19169290920160200192915050565b6020815260006109926020830184613740565b60006020828403121561379157600080fd5b5035919050565b6001600160a01b03811681146125f357600080fd5b803561204d81613798565b600080604083850312156137cb57600080fd5b82356137d681613798565b946020939093013593505050565b6000602082840312156137f657600080fd5b813561099281613798565b60008060006060848603121561381657600080fd5b833561382181613798565b9250602084013561383181613798565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561387b5761387b613842565b60405290565b6040805190810167ffffffffffffffff8111828210171561387b5761387b613842565b604051601f8201601f1916810167ffffffffffffffff811182821017156138cd576138cd613842565b604052919050565b600067ffffffffffffffff8211156138ef576138ef613842565b50601f01601f191660200190565b600080600080600060a0868803121561391557600080fd5b853561392081613798565b9450602086013567ffffffffffffffff81111561393c57600080fd5b8601601f8101881361394d57600080fd5b803561396061395b826138d5565b6138a4565b81815289602083850101111561397557600080fd5b8160208401602083013760006020838301015280965050505061399a604087016137ad565b92506139a8606087016137ad565b91506139b6608087016137ad565b90509295509295909350565b6020808252825182820181905260009190848201906040850190845b81811015613a035783516001600160a01b0316835292840192918401916001016139de565b50909695505050505050565b60008060408385031215613a2257600080fd5b823591506020830135613a3481613798565b809150509250929050565b600081518084526020808501945080840160005b83811015613a795781516001600160e01b03191687529582019590820190600101613a53565b509495945050505050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015613af357888303603f19018552815180516001600160a01b03168452870151878401879052613ae087850182613a3f565b9588019593505090860190600101613aab565b509098975050505050505050565b61ffff811681146125f357600080fd5b600060208284031215613b2357600080fd5b813561099281613b01565b6020815260006109926020830184613a3f565b600080600060608486031215613b5657600080fd5b833592506020840135613b6881613798565b91506040840135613b7881613798565b809150509250925092565b6001600160e01b0319811681146125f357600080fd5b600060208284031215613bab57600080fd5b813561099281613b83565b60ff811681146125f357600080fd5b600080600080600080600060e0888a031215613be057600080fd5b8735613beb81613798565b96506020880135613bfb81613798565b955060408801359450606088013593506080880135613c1981613bb6565b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215613c4957600080fd5b8235613c5481613798565b91506020830135613a3481613798565b600181811c90821680613c7857607f821691505b602082108103613c9857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156109c3576109c3613c9e565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600060208284031215613d1057600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b808201808211156109c3576109c3613c9e565b80820281158282048414176109c3576109c3613c9e565b600082613d7457634e487b7160e01b600052601260045260246000fd5b500490565b601f82111561352257600081815260208120601f850160051c81016020861015613da05750805b601f850160051c820191505b81811015613dbf57828155600101613dac565b505050505050565b815167ffffffffffffffff811115613de157613de1613842565b613df581613def8454613c64565b84613d79565b602080601f831160018114613e2a5760008415613e125750858301515b600019600386901b1c1916600185901b178555613dbf565b600085815260208120601f198616915b82811015613e5957888601518255948401946001909101908401613e3a565b5085821015613e775787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215613e9957600080fd5b815167ffffffffffffffff811115613eb057600080fd5b8201601f81018413613ec157600080fd5b8051613ecf61395b826138d5565b818152856020838501011115613ee457600080fd5b613ef582602083016020860161371c565b95945050505050565b61797360f01b815260008251613f1b81600285016020870161371c565b9190910160020192915050565b805160208201516001600160b01b0319808216929190600a831015613f5757808184600a0360031b1b83161693505b505050919050565b600060208284031215613f7157600080fd5b815161099281613bb6565b600067ffffffffffffffff821115613f9657613f96613842565b5060051b60200190565b600082601f830112613fb157600080fd5b81516020613fc161395b83613f7c565b82815260059290921b84018101918181019086841115613fe057600080fd5b8286015b84811015614004578051613ff781613b83565b8352918301918301613fe4565b509695505050505050565b6000602080838503121561402257600080fd5b825167ffffffffffffffff8082111561403a57600080fd5b818501915085601f83011261404e57600080fd5b815161405c61395b82613f7c565b81815260059190911b8301840190848101908883111561407b57600080fd5b8585015b83811015614112578051858111156140975760008081fd5b86016060818c03601f19018113156140af5760008081fd5b6140b7613858565b898301516140c481613798565b8152604083810151600381106140da5760008081fd5b828c01529183015191888311156140f15760008081fd5b6140ff8e8c85870101613fa0565b908201528552505091860191860161407f565b5098975050505050505050565b634e487b7160e01b600052602160045260246000fd5b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b8481101561420557898403607f19018652815180516001600160a01b031685528381015189860190600381106141a457634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b808310156141f05783516001600160e01b03191682529286019260019290920191908601906141c6565b5097850197955050509082019060010161415e565b50506001600160a01b038a169088015286810360408801526142278189613740565b9a9950505050505050505050565b6000602080838503121561424857600080fd5b825167ffffffffffffffff81111561425f57600080fd5b8301601f8101851361427057600080fd5b805161427e61395b82613f7c565b81815260059190911b8201830190838101908783111561429d57600080fd5b928401925b828410156136735783516142b581613798565b825292840192908401906142a2565b6000602082840312156142d657600080fd5b8151801515811461099257600080fd5b600060018060a01b03808816835260a0602084015261430860a0840188613740565b9581166040840152938416606083015250911660809091015292915050565b6000602080838503121561433a57600080fd5b825167ffffffffffffffff8082111561435257600080fd5b818501915085601f83011261436657600080fd5b815161437461395b82613f7c565b81815260059190911b8301840190848101908883111561439357600080fd5b8585015b83811015614112578051858111156143af5760008081fd5b86016040818c03601f19018113156143c75760008081fd5b6143cf613881565b898301516143dc81613798565b81529082015190878211156143f15760008081fd5b6143ff8d8b84860101613fa0565b818b015285525050918601918601614397565b600181815b8085111561444d57816000190482111561443357614433613c9e565b8085161561444057918102915b93841c9390800290614417565b509250929050565b600082614464575060016109c3565b81614471575060006109c3565b81600181146144875760028114614491576144ad565b60019150506109c3565b60ff8411156144a2576144a2613c9e565b50506001821b6109c3565b5060208310610133831016604e8410600b84101617156144d0575081810a6109c3565b6144da8383614412565b80600019048211156144ee576144ee613c9e565b029392505050565b600061099260ff841683614455565b60006020828403121561451757600080fd5b815167ffffffffffffffff81111561452e57600080fd5b6126bc84828501613fa0565b60006020828403121561454c57600080fd5b815161099281613798565b60008060006060848603121561456c57600080fd5b835161457781613b01565b602085015190935063ffffffff8116811461459157600080fd5b6040850151909250613b7881613798565b60008083546145b081613c64565b600182811680156145c857600181146145dd5761460c565b60ff198416875282151583028701945061460c565b8760005260208060002060005b858110156146035781548a8201529084019082016145ea565b50505082870194505b50929695505050505050565b6000825161462a81846020870161371c565b919091019291505056fea264697066735822122055c25ed18b35da0a6d2cadb63741ca302103cc5dd2aa1c4e4c8d55a41610380264736f6c63430008120033
Deployed Bytecode
0x733c79d158b508564e5a20211eec948242fb556eff30146080604052600436106103985760003560e01c806388a8d602116101e8578063bf86d69011610119578063d505accf116100b7578063ec0c7e2811610086578063ec0c7e2814610875578063ed27f7c914610888578063ef8b30f714610890578063fc7b9c18146108a357600080fd5b8063d505accf1461080f578063d905777e1461082f578063dd62ed3e14610842578063df69b22a1461085557600080fd5b8063c6e6f592116100f3578063c6e6f592146107b6578063cdffacc6146107c9578063ce96cb77146107dc578063d4a22bde146107ef57600080fd5b8063bf86d69014610793578063c3535b521461079b578063c63d75b6146107a357600080fd5b8063aa290e6d11610186578063b3d7f6b911610160578063b3d7f6b91461072b578063b460af941461073e578063ba0876521461075e578063be8f16681461077e57600080fd5b8063aa290e6d146106e3578063aced166114610703578063adfca15e1461070b57600080fd5b806399530b06116101c257806399530b06146106935780639aa7df941461069b578063a457c2d7146106a3578063a9059cbb146106c357600080fd5b806388a8d6021461066357806394bf804d1461066b57806395d89b411461068b57600080fd5b80633644e515116102cd5780635e04a4d61161026b578063748747e61161023a578063748747e6146106005780637a0ed627146106205780637ecebe0014610635578063877887821461064857600080fd5b80635e04a4d6146105755780636a5f1aa2146105ad5780636e553f65146105cd57806370a08231146105ed57600080fd5b8063440368a3116102a7578063440368a3146105305780634cdad506146105455780635141eebb1461055857806352ef6b2c1461056057600080fd5b80633644e515146104f557806339509351146104fd578063402d267d1461051d57600080fd5b80631d3b72271161033a5780632606a10b116103145780632606a10b146104895780632d632692146104b35780632ecfe315146104bb578063313ce567146104db57600080fd5b80631d3b72271461043357806323b872dd14610448578063258294101461046857600080fd5b80630952864e116103765780630952864e146103e0578063095ea7b3146103e85780630a28a4771461041857806318160ddd1461042b57600080fd5b806301e1d1141461039d57806306fdde03146103b857806307a2d13a146103cd575b600080fd5b6103a56108ab565b6040519081526020015b60405180910390f35b6103c06108c8565b6040516103af919061376c565b6103a56103db36600461377f565b610963565b6103a5610999565b8180156103f457600080fd5b506104086104033660046137b8565b6109b2565b60405190151581526020016103af565b6103a561042636600461377f565b6109c9565b6103a56109f1565b6104466104413660046137e4565b610a16565b005b81801561045457600080fd5b50610408610463366004613801565b610a93565b6040805180820190915260058152640332e312e360dc1b60208201526103c0565b81801561049557600080fd5b5061049e610ab5565b604080519283526020830191909152016103af565b6103a5610ec1565b8180156104c757600080fd5b506104466104d63660046138fd565b610edd565b6104e3611270565b60405160ff90911681526020016103af565b6103a561128a565b81801561050957600080fd5b506104086105183660046137b8565b6112bb565b6103a561052b3660046137e4565b6112dd565b81801561053c57600080fd5b50610446611348565b6103a561055336600461377f565b61156d565b6103a5611578565b61056861158b565b6040516103af91906139c2565b81801561058157600080fd5b506105956105903660046138fd565b611607565b6040516001600160a01b0390911681526020016103af565b8180156105b957600080fd5b506104466105c83660046137e4565b611791565b8180156105d957600080fd5b506103a56105e8366004613a0f565b611841565b6103a56105fb3660046137e4565b611939565b81801561060c57600080fd5b5061044661061b3660046137e4565b6119ac565b610628611a0b565b6040516103af9190613a84565b6103a56106433660046137e4565b611a87565b610650611ab3565b60405161ffff90911681526020016103af565b610595611ad2565b81801561067757600080fd5b506103a5610686366004613a0f565b611aee565b6103c0611bd2565b6103a5611c11565b6103a5611c34565b8180156106af57600080fd5b506104086106be3660046137b8565b611c47565b8180156106cf57600080fd5b506104086106de3660046137b8565b611c64565b8180156106ef57600080fd5b506104466106fe366004613b11565b611c71565b610595611d19565b61071e6107193660046137e4565b611d35565b6040516103af9190613b2e565b6103a561073936600461377f565b611db8565b81801561074a57600080fd5b506103a5610759366004613b41565b611dd6565b81801561076a57600080fd5b506103a5610779366004613b41565b611e8f565b81801561078a57600080fd5b50610446611f33565b610408611f8e565b6103a5611fab565b6103a56107b13660046137e4565b611fce565b6103a56107c436600461377f565b612052565b6105956107d7366004613b99565b612070565b6103a56107ea3660046137e4565b6120f0565b8180156107fb57600080fd5b5061044661080a3660046137e4565b612187565b81801561081b57600080fd5b5061044661082a366004613bc5565b61222b565b6103a561083d3660046137e4565b612431565b6103a5610850366004613c36565b6124ca565b81801561086157600080fd5b5061044661087036600461377f565b612504565b6104466108833660046137e4565b61259f565b6105956125f6565b6103a561089e36600461377f565b612619565b6103a5612624565b6000806108b6612637565b60098101546008909101540192915050565b60606108d2612637565b60010180546108e090613c64565b80601f016020809104026020016040519081016040528092919081815260200182805461090c90613c64565b80156109595780601f1061092e57610100808354040283529160200191610959565b820191906000526020600020905b81548152906001019060200180831161093c57829003601f168201915b5050505050905090565b60008061096e6109f1565b905080156109905761098b6109816108ab565b8490836000612665565b610992565b825b9392505050565b60006109a3612637565b600c015463ffffffff16919050565b60006109bf3384846126c4565b5060015b92915050565b6000806109d46108ab565b905080156109905761098b6109e76109f1565b8490836001612665565b60006109fb6127f9565b610a03612637565b60020154610a119190613cb4565b905090565b6000610a20612637565b600e8101549091506001600160a01b0383811691161480610a505750600d8101546001600160a01b038381169116145b610a8f5760405162461bcd60e51b815260206004820152600b60248201526a08505d5d1a1bdc9a5e995960aa1b60448201526064015b60405180910390fd5b5050565b6000610aa0843384612872565b610aab8484846128ec565b5060019392505050565b6000806000610ac2612637565b600e810154909150600160a01b900460ff1615610af15760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b179055610b0f33610a16565b6000610b19612637565b6009810154600882015491925001600080610b3383612aae565b91509150610b3f612bbe565b6000306001600160a01b0316635216aeec6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015610b81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ba59190613cfe565b9050600084821115610bd957600c860154858303995061271090640100000000900461ffff168a0204938401939050610bdf565b81850397505b6000610bea82612052565b90506000610bf9838703612052565b905060008b610c08888d613d2d565b10610c5b576000610c43610c2c8e8a8f610c229190613d2d565b6107c49190613cb4565b30600090815260068d016020526040902054612c23565b90508015610c5557610c553082612c32565b50610c72565b610c66878d03612052565b9050610c723082612d19565b8215610c9757600c890154610c9790600160301b90046001600160a01b031684612d19565b8115610ca757610ca78683612d19565b30600090815260068a016020526040902054600c8a015463ffffffff168115801590610cd9575060008163ffffffff16115b15610da657600b8b01546000906001600160801b031642811115610d065742816001600160801b03160391505b6000610d128686613cb4565b9050600085610d2763ffffffff871689613d40565b610d318685613d40565b610d3b9190613d2d565b610d459190613d57565b905080610d5764e8d4a5100088613d40565b610d619190613d57565b8f600a01819055508042610d759190613d2d565b8f600b0160006101000a8154816001600160801b0302191690836001600160801b0316021790555050505050610dae565b6000600a8c01555b505088546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401602060405180830381865afa158015610df8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e1c9190613cfe565b60088b018190559050610e2f8187613cb4565b60098b0155600b8a0180546001600160801b03428116600160801b0291161790557fecdd072e4d5bd913a75a37f02daedcea7e2dc0281f9942c0063cfd1cfe5c4c4f8d8d87610e7e818d613cb4565b60408051948552602085019390935291830152606082015260800160405180910390a1505050600e909701805460ff60a01b191690555096979596505050505050565b6000610ecb612637565b600b01546001600160801b0316919050565b6000610ee7612637565b80549091506001600160a01b031615610eff57600080fd5b80546001600160a01b0319166001600160a01b03871617815560018101610f268682613dc7565b506000869050806001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610f6a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610f929190810190613e87565b604051602001610fa29190613efe565b604051602081830303815290604052610fba90613f28565b8260000160156101000a81548169ffffffffffffffffffff021916908360b01c0217905550806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561101d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110419190613f5f565b825460ff91909116600160a01b0260ff60a01b19909116178255466003830155611069612de3565b6004830155600c8201805463ffffffff1916620d2f001790556001600160a01b03841661109557600080fd5b600c820180546503e80000000065ffff00000000196001600160a01b03808916600160301b0291909116640100000000600160d01b03199093169290921717909155600b830180546001600160801b03428116600160801b02911617905585166110fe57600080fd5b600d820180546001600160a01b038088166001600160a01b031992831617909255600e840180549286169290911691909117905560408051630d8e30e760e41b815290517f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb67391739bcc5f7560b243e37e0adf8379fa6d9ab49a425b9163d8e30e70916004808201926000929091908290030181865afa1580156111a5573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526111cd919081019061400f565b604080516000808252602082019092526040516111ec93929190614135565b60405180910390a160405163065b719960e51b81523060048201526001600160a01b0388166024820152731dbcecb8e3fed0151c2b2bcec288cf8e420226699063cb6e332090604401600060405180830381600087803b15801561124f57600080fd5b505af1158015611263573d6000803e3d6000fd5b5050505050505050505050565b600061127a612637565b54600160a01b900460ff16919050565b600080611295612637565b9050806003015446146112af576112aa612de3565b6112b5565b80600401545b91505090565b600033610aab8185856112ce83836124ca565b6112d89190613d2d565b6126c4565b604051632355178960e11b81526001600160a01b038216600482015260009030906346aa2f1290602401602060405180830381865afa158015611324573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c39190613cfe565b6000611352612637565b600e810154909150600160a01b900460ff16156113815760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b17905561139f33610a16565b60006113a9612637565b600881015481546040516370a0823160e01b815230600482015292935090916001600160a01b039091169060009082906370a0823190602401602060405180830381865afa1580156113ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114239190613cfe565b60405163275fedc360e21b8152600481018590529091503090639d7fb70c90602401600060405180830381600087803b15801561145f57600080fd5b505af1158015611473573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506001600160a01b03851691506370a0823190602401602060405180830381865afa1580156114be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e29190613cfe565b90508082111561151d5760006115016114fb8385613cb4565b86612c23565b6008870180548290039055600987018054909101905550611556565b8181111561155657600061153e6115348484613cb4565b8760090154612c23565b60088701805482019055600987018054919091039055505b505050600e909201805460ff60a01b191690555050565b60006109c382610963565b6000611582612637565b600a0154905090565b6060739bcc5f7560b243e37e0adf8379fa6d9ab49a425b6001600160a01b03166352ef6b2c6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156115df573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a119190810190614235565b6000306001600160a01b0316636f392ce76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611647573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061166b91906142c4565b6116a05760405162461bcd60e51b815260206004820152600660248201526521636c6f6e6560d01b6044820152606401610a86565b604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81523060601b601482018190526e5af43d82803e903d91602b57fd5bf360881b6028830152906037816000f0604051634b839d7360e11b81529093506001600160a01b03841691506397073ae69061171f908a908a908a908a908a906004016142e6565b600060405180830381600087803b15801561173957600080fd5b505af115801561174d573d6000803e3d6000fd5b50506040513092506001600160a01b03851691507fae93c8e84b9065113a0230417359f283712a933bdab9abc10fcb1179edc6b1c890600090a35095945050505050565b61179a3361259f565b6001600160a01b0381166117df5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204144445245535360a01b6044820152606401610a86565b806117e8612637565b600c0180546601000000000000600160d01b031916600160301b6001600160a01b0393841602179055604051908216907f9ebbf695dd251e855d9d15a146a72f5f654dc6f8630fbc11212f27e0c88ba11a90600090a250565b600061184b611f8e565b156118835760405162461bcd60e51b815260206004820152600860248201526739b43aba3237bbb760c11b6044820152606401610a86565b600061188d612637565b600e810154909150600160a01b900460ff16156118bc5760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b1790556118da84612619565b91508160000361191a5760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f53484152455360a81b6044820152606401610a86565b611925838584612e9f565b600e01805460ff60a01b1916905592915050565b6000306001600160a01b03831603611982576119536127f9565b61195b612637565b6001600160a01b038416600090815260069190910160205260409020546109c39190613cb4565b61198a612637565b6001600160a01b03909216600090815260069290920160205250604090205490565b6119b53361259f565b806119be612637565b600e0180546001600160a01b0319166001600160a01b03928316179055604051908216907fd7f49e282c36d417b290d4181a56943f6d670aaa2987c0d40e60d39919c6888290600090a250565b6060739bcc5f7560b243e37e0adf8379fa6d9ab49a425b6001600160a01b0316637a0ed6276040518163ffffffff1660e01b8152600401600060405180830381865afa158015611a5f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a119190810190614327565b6000611a91612637565b6001600160a01b03909216600090815260059290920160205250604090205490565b6000611abd612637565b600c0154640100000000900461ffff16919050565b6000611adc612637565b600d01546001600160a01b0316919050565b6000611af8611f8e565b15611b305760405162461bcd60e51b815260206004820152600860248201526739b43aba3237bbb760c11b6044820152606401610a86565b6000611b3a612637565b600e810154909150600160a01b900460ff1615611b695760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b179055611b8784611db8565b915081600003611bc75760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f41535345545360a81b6044820152606401610a86565b611925838386612e9f565b6060611bdc612637565b54604051600160a81b90910460b01b6001600160b01b0319166020820152602a01604051602081830303815290604052905090565b6000610a11611c1e612637565b546103db90600160a01b900460ff16600a6144f6565b6000611c3e612637565b60080154905090565b600033610aab818585611c5a83836124ca565b6112d89190613cb4565b60006109bf3384846128ec565b611c7a3361259f565b6127108161ffff1610611cb95760405162461bcd60e51b81526020600482015260076024820152664d41582042505360c81b6044820152606401610a86565b80611cc2612637565b600c01805465ffff00000000191664010000000061ffff9384160217905560405190821681527fdc843735e683348ec21c302ffff45462399c5c46f75f67b0a1a5395c53599753906020015b60405180910390a150565b6000611d23612637565b600e01546001600160a01b0316919050565b6040516356fe50af60e11b81526001600160a01b0382166004820152606090739bcc5f7560b243e37e0adf8379fa6d9ab49a425b9063adfca15e90602401600060405180830381865afa158015611d90573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109c39190810190614505565b600080611dc36109f1565b905080156109905761098b6109e76108ab565b600080611de1612637565b600e810154909150600160a01b900460ff1615611e105760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b179055611e2e856109c9565b915081600003611e6e5760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f53484152455360a81b6044820152606401610a86565b611e7a8484878561313a565b600e01805460ff60a01b191690559392505050565b600080611e9a612637565b600e810154909150600160a01b900460ff1615611ec95760405162461bcd60e51b8152600401610a8690613cc7565b600e8101805460ff60a01b1916600160a01b179055611ee78561156d565b915081600003611f275760405162461bcd60e51b815260206004820152600b60248201526a5a45524f5f41535345545360a81b6044820152606401610a86565b611e7a8484848861313a565b611f3c3361259f565b6001611f46612637565b600e018054911515600160a81b0260ff60a81b199092169190911790556040517ffc1249757a7f27c510c8173c55d03ba442e0d33d9223e06ceb416feac8c7693f90600090a1565b6000611f98612637565b600e0154600160a81b900460ff16919050565b6000611fb5612637565b600b0154600160801b90046001600160801b0316919050565b604051632355178960e11b81526001600160a01b038216600482015260009030906346aa2f1290602401602060405180830381865afa158015612015573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120399190613cfe565b9050600019811461204d576109c381612052565b919050565b60008061205d6108ab565b905080156109905761098b6109816109f1565b6040516366ffd66360e11b81526001600160e01b031982166004820152600090739bcc5f7560b243e37e0adf8379fa6d9ab49a425b9063cdffacc690602401602060405180830381865afa1580156120cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c3919061453a565b6040516304bd462960e01b81526001600160a01b038216600482015260009030906304bd462990602401602060405180830381865afa158015612137573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061215b9190613cfe565b90506000198103612172576109c36103db83611939565b6109c36121816103db84611939565b82612c23565b6121903361259f565b6001600160a01b0381166121d55760405162461bcd60e51b815260206004820152600c60248201526b5a45524f204144445245535360a01b6044820152606401610a86565b806121de612637565b600d0180546001600160a01b0319166001600160a01b03928316179055604051908216907fff54978127edd34aec0f9061fb3b155fbe0ededdfa881ee3e0d541d3a1eef43890600090a250565b4284101561227b5760405162461bcd60e51b815260206004820152601e60248201527f45524332303a205045524d49545f444541444c494e455f4558504952454400006044820152606401610a86565b6000600161228761128a565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98a8a8a6122b3612637565b6001600160a01b038f8116600090815260059290920160209081526040928390208054600181019091558351808301989098529582168784015293166060860152608085019190915260a084019290925260c08084018b90528251808503909101815260e08401909252815191012061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156123a2573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116158015906123d85750876001600160a01b0316816001600160a01b0316145b61241c5760405162461bcd60e51b815260206004820152601560248201527422a92199181d1024a72b20a624a22fa9a4a3a722a960591b6044820152606401610a86565b6124278188886126c4565b5050505050505050565b6040516304bd462960e01b81526001600160a01b038216600482015260009030906304bd462990602401602060405180830381865afa158015612478573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061249c9190613cfe565b905060001981036124b0576109c382611939565b6109c36124bc826109c9565b6124c584611939565b612c23565b60006124d4612637565b6001600160a01b039384166000908152600791909101602090815260408083209490951682529290925250205490565b61250d3361259f565b6301e1855881111561254b5760405162461bcd60e51b8152602060048201526007602482015266746f206c6f6e6760c81b6044820152606401610a86565b80612554612637565b600c01805463ffffffff191663ffffffff929092169190911790556040518181527ff361aed463da6fa20358e45c6209f1d3e16d4eca706e6eab0b0aeb338729c77a90602001611d0e565b6125a7612637565b600d01546001600160a01b038281169116146125f35760405162461bcd60e51b815260206004820152600b60248201526a08505d5d1a1bdc9a5e995960aa1b6044820152606401610a86565b50565b6000612600612637565b600c0154600160301b90046001600160a01b0316919050565b60006109c382612052565b600061262e612637565b60090154905090565b6000806109c360017fd2841a5d2692465040bd5e06a6f3b37483952c866e0f304dc0e03f76a1f8a0b1613cb4565b6000806126738686866133d8565b905060018360028111156126895761268961411f565b1480156126a65750600084806126a1576126a1613d17565b868809115b156126b9576126b6600182613d2d565b90505b90505b949350505050565b6001600160a01b0383166127265760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610a86565b6001600160a01b0382166127875760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a86565b80612790612637565b6001600160a01b038581166000818152600793909301602090815260408085209388168086529382529384902094909455915184815290927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b600080612804612637565b600b8101549091506001600160801b03164281111561284957600b820154600a83015464e8d4a5100091600160801b90046001600160801b0316420302049250505090565b6001600160801b0381161561286d5730600090815260068301602052604090205492505b505090565b600061287e84846124ca565b905060001981146128e657818110156128d95760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a86565b6128e684848484036126c4565b50505050565b6001600160a01b0383166129505760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610a86565b6001600160a01b0382166129b25760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610a86565b306001600160a01b03831603612a0a5760405162461bcd60e51b815260206004820152601a60248201527f4552433230207472616e7366657220746f2073747261746567790000000000006044820152606401610a86565b6000612a14612637565b6001600160a01b0385166000908152600682016020526040812080549293508492909190612a43908490613cb4565b90915550506001600160a01b038084166000818152600684016020526040908190208054860190555190918616907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90612aa09086815260200190565b60405180910390a350505050565b600080600080600073a8f46c3f5a89fbc3c80b3ee333a1daf8fa7190616001600160a01b0316635153b1996040518163ffffffff1660e01b8152600401606060405180830381865afa158015612b08573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b2c9190614557565b9194509250905061ffff831615612bb6578093506000612b7b612b4d612637565b600b0154612b6b90600160801b90046001600160801b031642613cb4565b6124c563ffffffff861642613cb4565b90506127106301e1855882612b9461ffff88168b613d40565b612b9e9190613d40565b612ba89190613d57565b612bb29190613d57565b9550505b505050915091565b6000612bc86127f9565b905080600003612bd55750565b42612bde612637565b600b01546001600160801b03161115612c195742612bfa612637565b600b0180546001600160801b03928316600160801b0292169190911790555b6125f33082612c32565b60008183106109905781610992565b6001600160a01b038216612c925760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610a86565b6000612c9c612637565b6001600160a01b0384166000908152600682016020526040812080549293508492909190612ccb908490613cb4565b909155505060028101805483900390556040518281526000906001600160a01b038516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016127ec565b6001600160a01b038216612d6f5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a86565b6000612d79612637565b905081816002016000828254612d8f9190613d2d565b90915550506001600160a01b03831660008181526006830160209081526040808320805487019055518581527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91016127ec565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f612e0e612637565b600101604051612e1e91906145a2565b60408051918290038220828201825260058352640332e312e360dc1b6020938401528151928301939093528101919091527f0e23d0b508e2034d01a5c31f12e9d9bbb31708c5518057dde31201ab93b17cef60608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b306001600160a01b03841603612eef5760405162461bcd60e51b815260206004820152601560248201527422a9219a1b191b1d1036b4b73a103a379039b2b63360591b6044820152606401610a86565b612ef8336112dd565b821115612f475760405162461bcd60e51b815260206004820152601e60248201527f455243343632363a206465706f736974206d6f7265207468616e206d617800006044820152606401610a86565b6000612f51612637565b80549091506001600160a01b0316612f6b81333087613487565b6000848360080154612f7d9190613d2d565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038416906370a0823190602401602060405180830381865afa158015612fc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612feb9190613cfe565b6040516255f9e960e71b8152600481018490529091503090632afcf48090602401600060405180830381600087803b15801561302657600080fd5b505af115801561303a573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092506130bd91506001600160a01b038616906370a0823190602401602060405180830381865afa158015613089573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ad9190613cfe565b6130b79084613cb4565b84612c23565b9050808560090160008282546130d39190613d2d565b909155505080830360088601556130ea8887612d19565b60408051888152602081018890526001600160a01b038a169133917fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7910160405180910390a35050505050505050565b61314383612431565b8111156131925760405162461bcd60e51b815260206004820152601f60248201527f455243343632363a207769746864726177206d6f7265207468616e206d6178006044820152606401610a86565b336001600160a01b038416146131ad576131ad833383612872565b60006131b7612637565b805460088201549192506001600160a01b03169084811015613357576040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa15801561321a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061323e9190613cfe565b604051633d6cb57560e01b815283880360048201529091503090633d6cb57590602401600060405180830381600087803b15801561327b57600080fd5b505af115801561328f573d6000803e3d6000fd5b50506040516370a0823160e01b815230600482015260009250613318915083906001600160a01b038716906370a0823190602401602060405180830381865afa1580156132e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133049190613cfe565b61330e9190613cb4565b8660090154612c23565b9283019290506000878410156133315783880390508397505b61333b8183613d2d565b86600901600082825461334e9190613cb4565b90915550505050505b6133618582613cb4565b60088401556133708685612c32565b6133846001600160a01b03831688876134f2565b60408051868152602081018690526001600160a01b0380891692908a169133917ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db910160405180910390a450505050505050565b60008080600019858709858702925082811083820303915050806000036134125783828161340857613408613d17565b0492505050610992565b80841161341e57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6040516001600160a01b03808516602483015283166044820152606481018290526128e69085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613527565b6040516001600160a01b03831660248201526044810182905261352290849063a9059cbb60e01b906064016134bb565b505050565b600061357c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135f99092919063ffffffff16565b805190915015613522578080602001905181019061359a91906142c4565b6135225760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610a86565b60606126bc848460008585600080866001600160a01b031685876040516136209190614618565b60006040518083038185875af1925050503d806000811461365d576040519150601f19603f3d011682016040523d82523d6000602084013e613662565b606091505b50915091506136738783838761367e565b979650505050505050565b606083156136ed5782516000036136e6576001600160a01b0385163b6136e65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a86565b50816126bc565b6126bc83838151156137025781518083602001fd5b8060405162461bcd60e51b8152600401610a86919061376c565b60005b8381101561373757818101518382015260200161371f565b50506000910152565b6000815180845261375881602086016020860161371c565b601f01601f19169290920160200192915050565b6020815260006109926020830184613740565b60006020828403121561379157600080fd5b5035919050565b6001600160a01b03811681146125f357600080fd5b803561204d81613798565b600080604083850312156137cb57600080fd5b82356137d681613798565b946020939093013593505050565b6000602082840312156137f657600080fd5b813561099281613798565b60008060006060848603121561381657600080fd5b833561382181613798565b9250602084013561383181613798565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b6040516060810167ffffffffffffffff8111828210171561387b5761387b613842565b60405290565b6040805190810167ffffffffffffffff8111828210171561387b5761387b613842565b604051601f8201601f1916810167ffffffffffffffff811182821017156138cd576138cd613842565b604052919050565b600067ffffffffffffffff8211156138ef576138ef613842565b50601f01601f191660200190565b600080600080600060a0868803121561391557600080fd5b853561392081613798565b9450602086013567ffffffffffffffff81111561393c57600080fd5b8601601f8101881361394d57600080fd5b803561396061395b826138d5565b6138a4565b81815289602083850101111561397557600080fd5b8160208401602083013760006020838301015280965050505061399a604087016137ad565b92506139a8606087016137ad565b91506139b6608087016137ad565b90509295509295909350565b6020808252825182820181905260009190848201906040850190845b81811015613a035783516001600160a01b0316835292840192918401916001016139de565b50909695505050505050565b60008060408385031215613a2257600080fd5b823591506020830135613a3481613798565b809150509250929050565b600081518084526020808501945080840160005b83811015613a795781516001600160e01b03191687529582019590820190600101613a53565b509495945050505050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015613af357888303603f19018552815180516001600160a01b03168452870151878401879052613ae087850182613a3f565b9588019593505090860190600101613aab565b509098975050505050505050565b61ffff811681146125f357600080fd5b600060208284031215613b2357600080fd5b813561099281613b01565b6020815260006109926020830184613a3f565b600080600060608486031215613b5657600080fd5b833592506020840135613b6881613798565b91506040840135613b7881613798565b809150509250925092565b6001600160e01b0319811681146125f357600080fd5b600060208284031215613bab57600080fd5b813561099281613b83565b60ff811681146125f357600080fd5b600080600080600080600060e0888a031215613be057600080fd5b8735613beb81613798565b96506020880135613bfb81613798565b955060408801359450606088013593506080880135613c1981613bb6565b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215613c4957600080fd5b8235613c5481613798565b91506020830135613a3481613798565b600181811c90821680613c7857607f821691505b602082108103613c9857634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b818103818111156109c3576109c3613c9e565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b600060208284031215613d1057600080fd5b5051919050565b634e487b7160e01b600052601260045260246000fd5b808201808211156109c3576109c3613c9e565b80820281158282048414176109c3576109c3613c9e565b600082613d7457634e487b7160e01b600052601260045260246000fd5b500490565b601f82111561352257600081815260208120601f850160051c81016020861015613da05750805b601f850160051c820191505b81811015613dbf57828155600101613dac565b505050505050565b815167ffffffffffffffff811115613de157613de1613842565b613df581613def8454613c64565b84613d79565b602080601f831160018114613e2a5760008415613e125750858301515b600019600386901b1c1916600185901b178555613dbf565b600085815260208120601f198616915b82811015613e5957888601518255948401946001909101908401613e3a565b5085821015613e775787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215613e9957600080fd5b815167ffffffffffffffff811115613eb057600080fd5b8201601f81018413613ec157600080fd5b8051613ecf61395b826138d5565b818152856020838501011115613ee457600080fd5b613ef582602083016020860161371c565b95945050505050565b61797360f01b815260008251613f1b81600285016020870161371c565b9190910160020192915050565b805160208201516001600160b01b0319808216929190600a831015613f5757808184600a0360031b1b83161693505b505050919050565b600060208284031215613f7157600080fd5b815161099281613bb6565b600067ffffffffffffffff821115613f9657613f96613842565b5060051b60200190565b600082601f830112613fb157600080fd5b81516020613fc161395b83613f7c565b82815260059290921b84018101918181019086841115613fe057600080fd5b8286015b84811015614004578051613ff781613b83565b8352918301918301613fe4565b509695505050505050565b6000602080838503121561402257600080fd5b825167ffffffffffffffff8082111561403a57600080fd5b818501915085601f83011261404e57600080fd5b815161405c61395b82613f7c565b81815260059190911b8301840190848101908883111561407b57600080fd5b8585015b83811015614112578051858111156140975760008081fd5b86016060818c03601f19018113156140af5760008081fd5b6140b7613858565b898301516140c481613798565b8152604083810151600381106140da5760008081fd5b828c01529183015191888311156140f15760008081fd5b6140ff8e8c85870101613fa0565b908201528552505091860191860161407f565b5098975050505050505050565b634e487b7160e01b600052602160045260246000fd5b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b8481101561420557898403607f19018652815180516001600160a01b031685528381015189860190600381106141a457634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b808310156141f05783516001600160e01b03191682529286019260019290920191908601906141c6565b5097850197955050509082019060010161415e565b50506001600160a01b038a169088015286810360408801526142278189613740565b9a9950505050505050505050565b6000602080838503121561424857600080fd5b825167ffffffffffffffff81111561425f57600080fd5b8301601f8101851361427057600080fd5b805161427e61395b82613f7c565b81815260059190911b8201830190838101908783111561429d57600080fd5b928401925b828410156136735783516142b581613798565b825292840192908401906142a2565b6000602082840312156142d657600080fd5b8151801515811461099257600080fd5b600060018060a01b03808816835260a0602084015261430860a0840188613740565b9581166040840152938416606083015250911660809091015292915050565b6000602080838503121561433a57600080fd5b825167ffffffffffffffff8082111561435257600080fd5b818501915085601f83011261436657600080fd5b815161437461395b82613f7c565b81815260059190911b8301840190848101908883111561439357600080fd5b8585015b83811015614112578051858111156143af5760008081fd5b86016040818c03601f19018113156143c75760008081fd5b6143cf613881565b898301516143dc81613798565b81529082015190878211156143f15760008081fd5b6143ff8d8b84860101613fa0565b818b015285525050918601918601614397565b600181815b8085111561444d57816000190482111561443357614433613c9e565b8085161561444057918102915b93841c9390800290614417565b509250929050565b600082614464575060016109c3565b81614471575060006109c3565b81600181146144875760028114614491576144ad565b60019150506109c3565b60ff8411156144a2576144a2613c9e565b50506001821b6109c3565b5060208310610133831016604e8410600b84101617156144d0575081810a6109c3565b6144da8383614412565b80600019048211156144ee576144ee613c9e565b029392505050565b600061099260ff841683614455565b60006020828403121561451757600080fd5b815167ffffffffffffffff81111561452e57600080fd5b6126bc84828501613fa0565b60006020828403121561454c57600080fd5b815161099281613798565b60008060006060848603121561456c57600080fd5b835161457781613b01565b602085015190935063ffffffff8116811461459157600080fd5b6040850151909250613b7881613798565b60008083546145b081613c64565b600182811680156145c857600181146145dd5761460c565b60ff198416875282151583028701945061460c565b8760005260208060002060005b858110156146035781548a8201529084019082016145ea565b50505082870194505b50929695505050505050565b6000825161462a81846020870161371c565b919091019291505056fea264697066735822122055c25ed18b35da0a6d2cadb63741ca302103cc5dd2aa1c4e4c8d55a41610380264736f6c63430008120033
Deployed Bytecode Sourcemap
54679:68481:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;79433:203;;;:::i;:::-;;;168:25:1;;;156:2;141:18;79433:203:0;;;;;;;;104587:106;;;:::i;:::-;;;;;;;:::i;74545:329::-;;;;;;:::i;:::-;;:::i;98133:132::-;;;:::i;108423:150::-;;;;;;;;;;-1:-1:-1;108423:150:0;;;;;:::i;:::-;;:::i;:::-;;;1921:14:1;;1914:22;1896:41;;1884:2;1869:18;108423:150:0;1748:195:1;76138:345:0;;;;;;:::i;:::-;;:::i;79644:134::-;;;:::i;63723:211::-;;;;;;:::i;:::-;;:::i;:::-;;109586:240;;;;;;;;;;-1:-1:-1;109586:240:0;;;;;:::i;:::-;;:::i;95844:97::-;95922:11;;;;;;;;;;;;-1:-1:-1;;;95922:11:0;;;;95844:97;;85330:5487;;;;;;;;;;;;;:::i;:::-;;;;2843:25:1;;;2899:2;2884:18;;2877:34;;;;2816:18;85330:5487:0;2661:256:1;97502:143:0;;;:::i;68214:2421::-;;;;;;;;;;-1:-1:-1;68214:2421:0;;;;;:::i;:::-;;:::i;105210:106::-;;;:::i;:::-;;;5263:4:1;5251:17;;;5233:36;;5221:2;5206:18;105210:106:0;5083:192:1;119438:286:0;;;:::i;110543:253::-;;;;;;;;;;-1:-1:-1;110543:253:0;;;;;:::i;:::-;;:::i;77044:150::-;;;;;;:::i;:::-;;:::i;94219:1311::-;;;;;;;;;;;;;:::i;76715:118::-;;;;;;:::i;:::-;;:::i;97851:132::-;;;:::i;103698:138::-;;;:::i;:::-;;;;;;;:::i;121926:1231::-;;;;;;;;;;-1:-1:-1;121926:1231:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;6422:32:1;;;6404:51;;6392:2;6377:18;121926:1231:0;6250:211:1;100891:364:0;;;;;;;;;;-1:-1:-1;100891:364:0;;;;;:::i;:::-;;:::i;71152:301::-;;;;;;;;;;-1:-1:-1;71152:301:0;;;;;:::i;:::-;;:::i;105694:285::-;;;;;;:::i;:::-;;:::i;99859:158::-;;;;;;;;;;-1:-1:-1;99859:158:0;;;;;:::i;:::-;;:::i;103068:134::-;;;:::i;:::-;;;;;;;:::i;116460:128::-;;;;;;:::i;:::-;;:::i;96932:121::-;;;:::i;:::-;;;8506:6:1;8494:19;;;8476:38;;8464:2;8449:18;96932:121:0;8324:196:1;96567:114:0;;;:::i;71784:295::-;;;;;;;;;;-1:-1:-1;71784:295:0;;;;;:::i;:::-;;:::i;104896:138::-;;;:::i;98793:::-;;;:::i;96078:112::-;;;:::i;111562:263::-;;;;;;;;;;-1:-1:-1;111562:263:0;;;;;:::i;:::-;;:::i;106502:142::-;;;;;;;;;;-1:-1:-1;106502:142:0;;;;;:::i;:::-;;:::i;100353:261::-;;;;;;;;;;-1:-1:-1;100353:261:0;;;;;:::i;:::-;;:::i;96818:106::-;;;:::i;103388:189::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;75513:323::-;;;;;;:::i;:::-;;:::i;72446:::-;;;;;;;;;;-1:-1:-1;72446:323:0;;;;;:::i;:::-;;:::i;73142:319::-;;;;;;;;;;-1:-1:-1;73142:319:0;;;;;:::i;:::-;;:::i;102589:146::-;;;;;;;;;;;;;:::i;64220:107::-;;;:::i;98401:123::-;;;:::i;77388:268::-;;;;;;:::i;:::-;;:::i;73780:429::-;;;;;;:::i;:::-;;:::i;104086:182::-;;;;;;:::i;:::-;;:::i;77864:560::-;;;;;;:::i;:::-;;:::i;99394:243::-;;;;;;;;;;-1:-1:-1;99394:243:0;;;;;:::i;:::-;;:::i;117422:1555::-;;;;;;;;;;-1:-1:-1;117422:1555:0;;;;;:::i;:::-;;:::i;78629:608::-;;;;;;:::i;:::-;;:::i;107153:182::-;;;;;;:::i;:::-;;:::i;101678:349::-;;;;;;;;;;-1:-1:-1;101678:349:0;;;;;:::i;:::-;;:::i;63240:139::-;;;;;;:::i;:::-;;:::i;97208:140::-;;;:::i;75102:119::-;;;;;;:::i;:::-;;:::i;96321:112::-;;;:::i;79433:203::-;79477:7;79497:26;79526:23;:21;:23::i;:::-;79606:11;;;;79592;;;;;:25;;79433:203;-1:-1:-1;;79433:203:0:o;104587:106::-;104624:13;104657:23;:21;:23::i;:::-;:28;;104650:35;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;104587:106;:::o;74545:329::-;74607:7;74690:14;74707:13;:11;:13::i;:::-;74690:30;-1:-1:-1;74753:11:0;;:113;;74810:56;74824:13;:11;:13::i;:::-;74810:6;;74839;74847:18;74810:13;:56::i;:::-;74753:113;;;74784:6;74753:113;74733:133;74545:329;-1:-1:-1;;;74545:329:0:o;98133:132::-;98187:7;98214:23;:21;:23::i;:::-;:43;;;;;;98133:132;-1:-1:-1;98133:132:0:o;108423:150::-;108489:4;108506:37;108515:10;108527:7;108536:6;108506:8;:37::i;:::-;-1:-1:-1;108561:4:0;108423:150;;;;;:::o;76138:345::-;76200:7;76283:20;76306:13;:11;:13::i;:::-;76283:36;-1:-1:-1;76352:17:0;;:123;;76415:60;76429:13;:11;:13::i;:::-;76415:6;;76444:12;76458:16;76415:13;:60::i;79644:134::-;79688:7;79753:17;:15;:17::i;:::-;79715:23;:21;:23::i;:::-;:35;;;:55;;;;:::i;:::-;79708:62;;79644:134;:::o;63723:211::-;63793:26;63822:23;:21;:23::i;:::-;63875:8;;;;63793:52;;-1:-1:-1;;;;;;63864:19:0;;;63875:8;;63864:19;;:46;;-1:-1:-1;63898:12:0;;;;-1:-1:-1;;;;;63887:23:0;;;63898:12;;63887:23;63864:46;63856:70;;;;-1:-1:-1;;;63856:70:0;;12185:2:1;63856:70:0;;;12167:21:1;12224:2;12204:18;;;12197:30;-1:-1:-1;;;12243:18:1;;;12236:41;12294:18;;63856:70:0;;;;;;;;;63782:152;63723:211;:::o;109586:240::-;109700:4;109717:41;109733:4;109739:10;109751:6;109717:15;:41::i;:::-;109769:27;109779:4;109785:2;109789:6;109769:9;:27::i;:::-;-1:-1:-1;109814:4:0;109586:240;;;;;:::o;85330:5487::-;85427:14;85443:12;62268:26;62297:23;:21;:23::i;:::-;62411:9;;;;;;-1:-1:-1;;;;62411:9:0;;;;62410:10;62402:54;;;;-1:-1:-1;;;62402:54:0;;;;;;;:::i;:::-;62534:9;;;:16;;-1:-1:-1;;;;62534:16:0;-1:-1:-1;;;62534:16:0;;;62005:32:::1;62026:10;62005:20;:32::i;:::-;85534:26:::2;85563:23;:21;:23::i;:::-;85753:11;::::0;::::2;::::0;85739::::2;::::0;::::2;::::0;85534:52;;-1:-1:-1;85739:25:0::2;85599:22;::::0;85983:35:::2;85739:25:::0;85983:19:::2;:35::i;:::-;85893:125;;;;86065:21;:19;:21::i;:::-;86530:16;86571:4;-1:-1:-1::0;;;;;86549:42:0::2;;:44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;86530:63;;86606:23;86719:14;86708:8;:25;86704:413;;;86918:16;::::0;::::2;::::0;86800:25;;::::2;::::0;-1:-1:-1;64789:6:0::2;::::0;86918:16;;::::2;;;86909:25:::0;::::2;86908:37;86964:28:::0;;::::2;::::0;86908:37;-1:-1:-1;86704:413:0::2;;;87093:8;87076:14;:25;87069:32;;86704:413;87258:28;87289:32;87305:15;87289;:32::i;:::-;87258:63;;87332:25;87413:44;87441:15;87429:9;:27;87413:15;:44::i;:::-;87393:64:::0;-1:-1:-1;87479:20:0::2;87534:6:::0;87514:16:::2;87521:9:::0;87514:4;:16:::2;:::i;:::-;:26;87510:750;;87738:20;87761:130;87788:44;87825:6;87812:9;87805:4;:16;;;;:::i;:::-;87804:27;;;;:::i;87788:44::-;87870:4;87851:25;::::0;;;:10:::2;::::0;::::2;:25;::::0;;;;;87761:8:::2;:130::i;:::-;87738:153:::0;-1:-1:-1;87912:16:0;;87908:91:::2;;87949:34;87963:4;87970:12;87949:5;:34::i;:::-;87542:468;87510:750;;;88149:35;88174:9;88165:6;:18;88149:15;:35::i;:::-;88134:50;;88214:34;88228:4;88235:12;88214:5;:34::i;:::-;88306:24:::0;;88302:111:::2;;88353:25;::::0;::::2;::::0;88347:54:::2;::::0;-1:-1:-1;;;88353:25:0;::::2;-1:-1:-1::0;;;;;88353:25:0::2;88380:20:::0;88347:5:::2;:54::i;:::-;88429:21:::0;;88425:101:::2;;88467:47;88473:21;88496:17;88467:5;:47::i;:::-;88714:4;88667:25;88695::::0;;;:10:::2;::::0;::::2;:25;::::0;;;;;88765:21:::2;::::0;::::2;::::0;::::2;;88805::::0;;;;;:49:::2;;;88853:1;88830:20;:24;;;88805:49;88801:1391;;;88947:22;::::0;::::2;::::0;88875:21:::2;::::0;-1:-1:-1;;;;;88947:22:0::2;89016:15;88992:39:::0;::::2;88988:203;;;89133:15;89109:21;-1:-1:-1::0;;;;;89109:39:0::2;;89093:55;;88988:203;89211:30;89244:53;89285:12:::0;89244:17;:53:::2;:::i;:::-;89211:86:::0;-1:-1:-1;89496:30:0::2;89673:17:::0;89613:56:::2;;::::0;::::2;:12:::0;:56:::2;:::i;:::-;89530:59;89576:13:::0;89530:22;:59:::2;:::i;:::-;:139;;;;:::i;:::-;89529:161;;;;:::i;:::-;89496:194:::0;-1:-1:-1;89496:194:0;89757:36:::2;64899:17;89757::::0;:36:::2;:::i;:::-;89756:84;;;;:::i;:::-;89711:1;:21;;:129;;;;89934:22;89916:15;:40;;;;:::i;:::-;89861:1;:22;;;:114;;;;;-1:-1:-1::0;;;;;89861:114:0::2;;;;;-1:-1:-1::0;;;;;89861:114:0::2;;;;;;88856:1135;;;;88801:1391;;;90175:1;90151:21;::::0;::::2;:25:::0;88801:1391:::2;-1:-1:-1::0;;90451:7:0;;:32:::2;::::0;-1:-1:-1;;;90451:32:0;;90477:4:::2;90451:32;::::0;::::2;6404:51:1::0;90433:15:0::2;::::0;-1:-1:-1;;;;;90451:7:0::2;::::0;:17:::2;::::0;6377:18:1;;90451:32:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;90494:11;::::0;::::2;:21:::0;;;90433:50;-1:-1:-1;90540:18:0::2;90433:50:::0;90540:8;:18:::2;:::i;:::-;90526:11;::::0;::::2;:32:::0;90571:12:::2;::::0;::::2;:39:::0;;-1:-1:-1;;;;;90594:15:0::2;90571:39:::0;::::2;-1:-1:-1::0;;;90571:39:0::2;::::0;::::2;;::::0;;90661:148:::2;90684:6:::0;90705:4;90724:15;90754:27:::2;90724:15:::0;90754:9;:27:::2;:::i;:::-;90661:148;::::0;;13968:25:1;;;14024:2;14009:18;;14002:34;;;;14052:18;;;14045:34;14110:2;14095:18;;14088:34;13955:3;13940:19;90661:148:0::2;;;;;;;-1:-1:-1::0;;;62627:9:0;;;;:17;;-1:-1:-1;;;;62627:17:0;;;-1:-1:-1;85330:5487:0;;;;-1:-1:-1;;;;;;85330:5487:0:o;97502:143::-;97557:7;97592:23;:21;:23::i;:::-;:44;;;-1:-1:-1;;;;;97592:44:0;;97502:143;-1:-1:-1;97502:143:0:o;68214:2421::-;68443:26;68472:23;:21;:23::i;:::-;68569:7;;68443:52;;-1:-1:-1;;;;;;68569:7:0;68561:30;68553:39;;;;;;68650:23;;-1:-1:-1;;;;;;68650:23:0;-1:-1:-1;;;;;68650:23:0;;;;;-1:-1:-1;68717:6:0;;:14;68726:5;68717:6;:14;:::i;:::-;;68805:16;68839:6;68805:41;;69019:1;-1:-1:-1;;;;;69019:8:0;;:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;69019:10:0;;;;;;;;;;;;:::i;:::-;68996:34;;;;;;;;:::i;:::-;;;;;;;;;;;;;68988:43;;;:::i;:::-;68977:1;:8;;;:54;;;;;;;;;;;;;;;;;;69055:1;-1:-1:-1;;;;;69055:10:0;;:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;69042:25;;;;;;;-1:-1:-1;;;69042:25:0;-1:-1:-1;;;;69042:25:0;;;;;;69161:13;69140:18;;;:34;69279:25;:23;:25::i;:::-;69250:26;;;:54;69370:21;;;:31;;-1:-1:-1;;69370:31:0;69394:7;69370:31;;;-1:-1:-1;;;;;69533:38:0;;69525:47;;;;;;69583:25;;;:52;;69692:24;-1:-1:-1;;;;;;;69583:52:0;;;-1:-1:-1;;;69583:52:0;69692:24;;;;-1:-1:-1;;;;;;69692:24:0;;;;;;;;;;;69769:12;;;:39;;-1:-1:-1;;;;;69792:15:0;69769:39;;-1:-1:-1;;;69769:39:0;;;;;;69889:25;;69881:34;;;;;;69926:12;;;:26;;-1:-1:-1;;;;;69926:26:0;;;-1:-1:-1;;;;;;69926:26:0;;;;;;;69998:8;;;:18;;;;;;;;;;;;;;;70275:41;;;-1:-1:-1;;;70275:41:0;;;;70122:375;;64668:42;;70275:39;;:41;;;;;69926:12;;70275:41;;;;;;;;64668:42;70275:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;70275:41:0;;;;;;;;;;;;:::i;:::-;70474:12;;;70391:1;70474:12;;;;;;;;;70122:375;;;;;;;;:::i;:::-;;;;;;;;70573:54;;-1:-1:-1;;;70573:54:0;;70613:4;70573:54;;;23453:34:1;-1:-1:-1;;;;;23523:15:1;;23503:18;;;23496:43;65146:42:0;;70573:31;;23388:18:1;;70573:54:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;68398:2237;;68214:2421;;;;;:::o;105210:106::-;105251:5;105276:23;:21;:23::i;:::-;:32;-1:-1:-1;;;105276:32:0;;;;;;-1:-1:-1;105210:106:0:o;119438:286::-;119487:7;119507:26;119536:23;:21;:23::i;:::-;119507:52;;119607:1;:18;;;119590:13;:35;:126;;119691:25;:23;:25::i;:::-;119590:126;;;119645:1;:26;;;119590:126;119570:146;;;119438:286;:::o;110543:253::-;110648:4;110681:10;110702:64;110681:10;110718:7;110755:10;110727:25;110681:10;110718:7;110727:9;:25::i;:::-;:38;;;;:::i;:::-;110702:8;:64::i;77044:150::-;77128:58;;-1:-1:-1;;;77128:58:0;;-1:-1:-1;;;;;6422:32:1;;77128:58:0;;;6404:51:1;77101:7:0;;77150:4;;77128:50;;6377:18:1;;77128:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;94219:1311::-;62268:26;62297:23;:21;:23::i;:::-;62411:9;;;;;;-1:-1:-1;;;;62411:9:0;;;;62410:10;62402:54;;;;-1:-1:-1;;;62402:54:0;;;;;;;:::i;:::-;62534:9;;;:16;;-1:-1:-1;;;;62534:16:0;-1:-1:-1;;;62534:16:0;;;62005:32:::1;62026:10;62005:20;:32::i;:::-;94280:26:::2;94309:23;:21;:23::i;:::-;94437:11;::::0;::::2;::::0;94474:7;;94518:31:::2;::::0;-1:-1:-1;;;94518:31:0;;94543:4:::2;94518:31;::::0;::::2;6404:51:1::0;94437:11:0;;-1:-1:-1;94437:11:0;;-1:-1:-1;;;;;94474:7:0;;::::2;::::0;94416:18:::2;::::0;94474:7;;94518:16:::2;::::0;6377:18:1;;94518:31:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;94560:49;::::0;-1:-1:-1;;;94560:49:0;;::::2;::::0;::::2;168:25:1::0;;;94494:55:0;;-1:-1:-1;94582:4:0::2;::::0;94560:37:::2;::::0;141:18:1;;94560:49:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;::::0;::::2;;;;;-1:-1:-1::0;;94643:31:0::2;::::0;-1:-1:-1;;;94643:31:0;;94668:4:::2;94643:31;::::0;::::2;6404:51:1::0;94620:20:0::2;::::0;-1:-1:-1;;;;;;94643:16:0;::::2;::::0;-1:-1:-1;94643:16:0::2;::::0;6377:18:1;;94643:31:0::2;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;94620:54;;94792:12;94776:13;:28;94772:751;;;94864:16;94883:99;94910:28;94926:12:::0;94910:13;:28:::2;:::i;:::-;94957:10;94883:8;:99::i;:::-;95028:11;::::0;::::2;:23:::0;;;;::::2;::::0;;95070:11:::2;::::0;::::2;:23:::0;;;;::::2;::::0;;-1:-1:-1;94772:751:0::2;;;95145:13;95130:12;:28;95126:397;;;95263:17;95283:100;95310:28;95325:13:::0;95310:12;:28:::2;:::i;:::-;95357:1;:11;;;95283:8;:100::i;:::-;95429:11;::::0;::::2;:24:::0;;;::::2;::::0;;95472:11:::2;::::0;::::2;:24:::0;;;;;::::2;::::0;;-1:-1:-1;95126:397:0::2;-1:-1:-1::0;;;62627:9:0;;;;:17;;-1:-1:-1;;;;62627:17:0;;;-1:-1:-1;;94219:1311:0:o;76715:118::-;76775:7;76802:23;76818:6;76802:15;:23::i;97851:132::-;97905:7;97932:23;:21;:23::i;:::-;:43;;;97925:50;;97851:132;:::o;103698:138::-;103747:16;64668:42;-1:-1:-1;;;;;103783:43:0;;:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;103783:45:0;;;;;;;;;;;;:::i;121926:1231::-;122120:19;122182:4;-1:-1:-1;;;;;122160:39:0;;:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;122152:60;;;;-1:-1:-1;;;122152:60:0;;25185:2:1;122152:60:0;;;25167:21:1;25224:1;25204:18;;;25197:29;-1:-1:-1;;;25242:18:1;;;25235:36;25288:18;;122152:60:0;24983:329:1;122152:60:0;122471:4;122465:11;-1:-1:-1;;;122490:135:0;;122370:4;122354:22;;122662:4;122646:21;;122639:43;;;-1:-1:-1;;;122737:4:0;122721:21;;122696:146;122354:22;122893:4;122465:11;122331:20;122871:27;122921:176;;-1:-1:-1;;;122921:176:0;;122856:42;;-1:-1:-1;;;;;;122921:37:0;;;-1:-1:-1;122921:37:0;;:176;;122973:6;;122994:5;;123014:11;;123040:24;;123079:7;;122921:176;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;123115:34:0;;123143:4;;-1:-1:-1;;;;;;123115:34:0;;;-1:-1:-1;123115:34:0;;;;;122141:1016;121926:1231;;;;;;;:::o;100891:364::-;61795:24;61808:10;61795:12;:24::i;:::-;-1:-1:-1;;;;;101020:38:0;::::1;101012:63;;;::::0;-1:-1:-1;;;101012:63:0;;26105:2:1;101012:63:0::1;::::0;::::1;26087:21:1::0;26144:2;26124:18;;;26117:30;-1:-1:-1;;;26163:18:1;;;26156:42;26215:18;;101012:63:0::1;25903:336:1::0;101012:63:0::1;101150:24;101086:23;:21;:23::i;:::-;:61;;:88:::0;;-1:-1:-1;;;;;;101086:88:0::1;-1:-1:-1::0;;;;;;;;101086:88:0;;::::1;;;::::0;;101192:55:::1;::::0;;;::::1;::::0;::::1;::::0;-1:-1:-1;;101192:55:0::1;100891:364:::0;:::o;71152:301::-;71271:14;62869:12;:10;:12::i;:::-;62868:13;62860:34;;;;-1:-1:-1;;;62860:34:0;;26446:2:1;62860:34:0;;;26428:21:1;26485:1;26465:18;;;26458:29;-1:-1:-1;;;26503:18:1;;;26496:38;26551:18;;62860:34:0;26244:331:1;62860:34:0;62268:26:::1;62297:23;:21;:23::i;:::-;62411:9;::::0;::::1;::::0;;;-1:-1:-1;;;;62411:9:0;::::1;;;62410:10;62402:54;;;;-1:-1:-1::0;;;62402:54:0::1;;;;;;;:::i;:::-;62534:9;::::0;::::1;:16:::0;;-1:-1:-1;;;;62534:16:0::1;-1:-1:-1::0;;;62534:16:0::1;::::0;;71354:22:::2;71369:6:::0;71354:14:::2;:22::i;:::-;71345:31;;;71381:1;71344:38:::0;71336:62:::2;;;::::0;-1:-1:-1;;;71336:62:0;;26782:2:1;71336:62:0::2;::::0;::::2;26764:21:1::0;26821:2;26801:18;;;26794:30;-1:-1:-1;;;26840:18:1;;;26833:41;26891:18;;71336:62:0::2;26580:335:1::0;71336:62:0::2;71411:34;71420:8;71430:6;71438;71411:8;:34::i;:::-;62627:9:::1;;:17:::0;;-1:-1:-1;;;;62627:17:0::1;::::0;;71152:301;;-1:-1:-1;;71152:301:0:o;105694:285::-;105751:7;105794:4;-1:-1:-1;;;;;105775:24:0;;;105771:142;;105884:17;:15;:17::i;:::-;105840:23;:21;:23::i;:::-;-1:-1:-1;;;;;105840:41:0;;;;;;:32;;;;;:41;;;;;;:61;;;;:::i;105771:142::-;105930:23;:21;:23::i;:::-;-1:-1:-1;;;;;105930:41:0;;;;;;;:32;;;;;:41;;-1:-1:-1;105930:41:0;;;;;105694:285::o;99859:158::-;61795:24;61808:10;61795:12;:24::i;:::-;99963:7:::1;99930:23;:21;:23::i;:::-;:30;;:40:::0;;-1:-1:-1;;;;;;99930:40:0::1;-1:-1:-1::0;;;;;99930:40:0;;::::1;;::::0;;99988:21:::1;::::0;;;::::1;::::0;::::1;::::0;-1:-1:-1;;99988:21:0::1;99859:158:::0;:::o;103068:134::-;103109:28;64668:42;-1:-1:-1;;;;;103157:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;103157:37:0;;;;;;;;;;;;:::i;116460:128::-;116515:7;116542:23;:21;:23::i;:::-;-1:-1:-1;;;;;116542:38:0;;;;;;;:30;;;;;:38;;-1:-1:-1;116542:38:0;;;;;116460:128::o;96932:121::-;96981:6;97007:23;:21;:23::i;:::-;:38;;;;;;;;;;-1:-1:-1;96932:121:0:o;96567:114::-;96612:7;96639:23;:21;:23::i;:::-;:34;;;-1:-1:-1;;;;;96639:34:0;;96567:114;-1:-1:-1;96567:114:0:o;71784:295::-;71900:14;62869:12;:10;:12::i;:::-;62868:13;62860:34;;;;-1:-1:-1;;;62860:34:0;;26446:2:1;62860:34:0;;;26428:21:1;26485:1;26465:18;;;26458:29;-1:-1:-1;;;26503:18:1;;;26496:38;26551:18;;62860:34:0;26244:331:1;62860:34:0;62268:26:::1;62297:23;:21;:23::i;:::-;62411:9;::::0;::::1;::::0;;;-1:-1:-1;;;;62411:9:0;::::1;;;62410:10;62402:54;;;;-1:-1:-1::0;;;62402:54:0::1;;;;;;;:::i;:::-;62534:9;::::0;::::1;:16:::0;;-1:-1:-1;;;;62534:16:0::1;-1:-1:-1::0;;;62534:16:0::1;::::0;;71983:19:::2;71995:6:::0;71983:11:::2;:19::i;:::-;71974:28;;;72007:1;71973:35:::0;71965:59:::2;;;::::0;-1:-1:-1;;;71965:59:0;;28884:2:1;71965:59:0::2;::::0;::::2;28866:21:1::0;28923:2;28903:18;;;28896:30;-1:-1:-1;;;28942:18:1;;;28935:41;28993:18;;71965:59:0::2;28682:335:1::0;71965:59:0::2;72037:34;72046:8;72056:6;72064;72037:8;:34::i;104896:138::-:0;104935:13;104993:23;:21;:23::i;:::-;:30;104975:50;;-1:-1:-1;;;104993:30:0;;;;;-1:-1:-1;;;;;;29163:45:1;104975:50:0;;;29151:58:1;29225:12;;104975:50:0;;;;;;;;;;;;104961:65;;104896:138;:::o;98793:::-;98841:7;98868:55;98890:23;:21;:23::i;:::-;:32;98884:38;;-1:-1:-1;;;98890:32:0;;;;98884:2;:38;:::i;96078:112::-;96122:7;96149:23;:21;:23::i;:::-;:33;;;96142:40;;96078:112;:::o;111562:263::-;111672:4;111705:10;111726:69;111705:10;111742:7;111779:15;111751:25;111705:10;111742:7;111751:9;:25::i;:::-;:43;;;;:::i;106502:142::-;106564:4;106581:33;106591:10;106603:2;106607:6;106581:9;:33::i;100353:261::-;61795:24;61808:10;61795:12;:24::i;:::-;64789:6:::1;100447:15;:25;;;100439:45;;;::::0;-1:-1:-1;;;100439:45:0;;30833:2:1;100439:45:0::1;::::0;::::1;30815:21:1::0;30872:1;30852:18;;;30845:29;-1:-1:-1;;;30890:18:1;;;30883:37;30937:18;;100439:45:0::1;30631:330:1::0;100439:45:0::1;100536:15;100495:23;:21;:23::i;:::-;:38;;:56:::0;;-1:-1:-1;;100495:56:0::1;::::0;::::1;::::0;;::::1;;;::::0;;100569:37:::1;::::0;8494:19:1;;;8476:38;;100569:37:0::1;::::0;8464:2:1;8449:18;100569:37:0::1;;;;;;;;100353:261:::0;:::o;96818:106::-;96859:7;96886:23;:21;:23::i;:::-;:30;;;-1:-1:-1;;;;;96886:30:0;;96818:106;-1:-1:-1;96818:106:0:o;103388:189::-;103510:59;;-1:-1:-1;;;103510:59:0;;-1:-1:-1;;;;;6422:32:1;;103510:59:0;;;6404:51:1;103475:15:0;;64668:42;;103510:51;;6377:18:1;;103510:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;103510:59:0;;;;;;;;;;;;:::i;75513:323::-;75571:7;75654:14;75671:13;:11;:13::i;:::-;75654:30;-1:-1:-1;75717:11:0;;:111;;75774:54;75788:13;:11;:13::i;72446:323::-;72578:14;62268:26;62297:23;:21;:23::i;:::-;62411:9;;;;;;-1:-1:-1;;;;62411:9:0;;;;62410:10;62402:54;;;;-1:-1:-1;;;62402:54:0;;;;;;;:::i;:::-;62534:9;;;:16;;-1:-1:-1;;;;62534:16:0;-1:-1:-1;;;62534:16:0;;;72661:23:::1;72677:6:::0;72661:15:::1;:23::i;:::-;72652:32;;;72689:1;72651:39:::0;72643:63:::1;;;::::0;-1:-1:-1;;;72643:63:0;;26782:2:1;72643:63:0::1;::::0;::::1;26764:21:1::0;26821:2;26801:18;;;26794:30;-1:-1:-1;;;26840:18:1;;;26833:41;26891:18;;72643:63:0::1;26580:335:1::0;72643:63:0::1;72719:42;72729:8;72739:5;72746:6;72754;72719:9;:42::i;:::-;62627:9:::0;;:17;;-1:-1:-1;;;;62627:17:0;;;72446:323;;-1:-1:-1;;;72446:323:0:o;73142:319::-;73272:14;62268:26;62297:23;:21;:23::i;:::-;62411:9;;;;;;-1:-1:-1;;;;62411:9:0;;;;62410:10;62402:54;;;;-1:-1:-1;;;62402:54:0;;;;;;;:::i;:::-;62534:9;;;:16;;-1:-1:-1;;;;62534:16:0;-1:-1:-1;;;62534:16:0;;;73355:21:::1;73369:6:::0;73355:13:::1;:21::i;:::-;73346:30;;;73381:1;73345:37:::0;73337:61:::1;;;::::0;-1:-1:-1;;;73337:61:0;;28884:2:1;73337:61:0::1;::::0;::::1;28866:21:1::0;28923:2;28903:18;;;28896:30;-1:-1:-1;;;28942:18:1;;;28935:41;28993:18;;73337:61:0::1;28682:335:1::0;73337:61:0::1;73411:42;73421:8;73431:5;73438:6;73446;73411:9;:42::i;102589:146::-:0;61795:24;61808:10;61795:12;:24::i;:::-;102687:4:::1;102652:23;:21;:23::i;:::-;:32;;:39:::0;;;::::1;;-1:-1:-1::0;;;102652:39:0::1;-1:-1:-1::0;;;;102652:39:0;;::::1;::::0;;;::::1;::::0;;102709:18:::1;::::0;::::1;::::0;-1:-1:-1;;102709:18:0::1;102589:146::o:0;64220:107::-;64263:4;64287:23;:21;:23::i;:::-;:32;;;-1:-1:-1;;;64287:32:0;;;;;;-1:-1:-1;64220:107:0:o;98401:123::-;98446:7;98481:23;:21;:23::i;:::-;:34;;;-1:-1:-1;;;98481:34:0;;-1:-1:-1;;;;;98481:34:0;;;-1:-1:-1;98401:123:0:o;77388:268::-;77482:58;;-1:-1:-1;;;77482:58:0;;-1:-1:-1;;;;;6422:32:1;;77482:58:0;;;6404:51:1;77442:16:0;;77504:4;;77482:50;;6377:18:1;;77482:58:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;77471:69;;-1:-1:-1;;77555:8:0;:29;77551:98;;77612:25;77628:8;77612:15;:25::i;77551:98::-;77388:268;;;:::o;73780:429::-;73842:7;73925:20;73948:13;:11;:13::i;:::-;73925:36;-1:-1:-1;73994:17:0;;:207;;74057:144;74093:13;:11;:13::i;104086:182::-;104200:60;;-1:-1:-1;;;104200:60:0;;-1:-1:-1;;;;;;31687:33:1;;104200:60:0;;;31669:52:1;104173:7:0;;64668:42;;104200:41;;31642:18:1;;104200:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;77864:560::-;77986:83;;-1:-1:-1;;;77986:83:0;;-1:-1:-1;;;;;6422:32:1;;77986:83:0;;;6404:51:1;77938:20:0;;78008:4;;77986:51;;6377:18:1;;77986:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;77971:98;;-1:-1:-1;;78084:12:0;:33;78080:337;;78216:34;78232:17;78242:6;78232:9;:17::i;78080:337::-;78298:107;78325:34;78341:17;78351:6;78341:9;:17::i;78325:34::-;78378:12;78298:8;:107::i;99394:243::-;61795:24;61808:10;61795:12;:24::i;:::-;-1:-1:-1;;;;;99481:25:0;::::1;99473:50;;;::::0;-1:-1:-1;;;99473:50:0;;26105:2:1;99473:50:0::1;::::0;::::1;26087:21:1::0;26144:2;26124:18;;;26117:30;-1:-1:-1;;;26163:18:1;;;26156:42;26215:18;;99473:50:0::1;25903:336:1::0;99473:50:0::1;99571:11;99534:23;:21;:23::i;:::-;:34;;:48:::0;;-1:-1:-1;;;;;;99534:48:0::1;-1:-1:-1::0;;;;;99534:48:0;;::::1;;::::0;;99600:29:::1;::::0;;;::::1;::::0;::::1;::::0;-1:-1:-1;;99600:29:0::1;99394:243:::0;:::o;117422:1555::-;117642:15;117630:8;:27;;117622:70;;;;-1:-1:-1;;;117622:70:0;;32190:2:1;117622:70:0;;;32172:21:1;32229:2;32209:18;;;32202:30;32268:32;32248:18;;;32241:60;32318:18;;117622:70:0;31988:354:1;117622:70:0;117862:24;117889:851;118029:18;:16;:18::i;:::-;118159:167;118361:5;118401:7;118443:5;118483:23;:21;:23::i;:::-;-1:-1:-1;;;;;118483:37:0;;;;;;;:30;;;;;:37;;;;;;;;;:39;;;;;;;;118114:482;;;;;32634:25:1;;;;32733:15;;;32713:18;;;32706:43;32785:15;;32765:18;;;32758:43;32817:18;;;32810:34;;;;32860:19;;;32853:35;;;;32904:19;;;;32897:35;;;118114:482:0;;;;;;;;;;32606:19:1;;;118114:482:0;;;118074:549;;;;;-1:-1:-1;;;117949:697:0;;;33201:27:1;33244:11;;;33237:27;;;;33280:12;;;33273:28;;;;33317:12;;117949:697:0;;;-1:-1:-1;;117949:697:0;;;;;;;;;117917:748;;117949:697;117917:748;;;;117889:851;;;;;;;;;33567:25:1;33640:4;33628:17;;33608:18;;;33601:45;33662:18;;;33655:34;;;33705:18;;;33698:34;;;33539:19;;117889:851:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;117889:851:0;;-1:-1:-1;;117889:851:0;;;-1:-1:-1;;;;;;;118783:30:0;;;;;;:59;;;118837:5;-1:-1:-1;;;;;118817:25:0;:16;-1:-1:-1;;;;;118817:25:0;;118783:59;118757:142;;;;-1:-1:-1;;;118757:142:0;;33945:2:1;118757:142:0;;;33927:21:1;33984:2;33964:18;;;33957:30;-1:-1:-1;;;34003:18:1;;;33996:51;34064:18;;118757:142:0;33743:345:1;118757:142:0;118916:42;118925:16;118943:7;118952:5;118916:8;:42::i;:::-;117837:1133;117422:1555;;;;;;;:::o;78629:608::-;78745:83;;-1:-1:-1;;;78745:83:0;;-1:-1:-1;;;;;6422:32:1;;78745:83:0;;;6404:51:1;78701:18:0;;78767:4;;78745:51;;6377:18:1;;78745:83:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;78732:96;;-1:-1:-1;;78936:10:0;:31;78932:298;;78997:17;79007:6;78997:9;:17::i;78932:298::-;79060:158;79140:27;79156:10;79140:15;:27::i;:::-;79186:17;79196:6;79186:9;:17::i;:::-;79060:8;:158::i;107153:182::-;107250:7;107277:23;:21;:23::i;:::-;-1:-1:-1;;;;;107277:41:0;;;;;;;:34;;;;;:41;;;;;;;;:50;;;;;;;;;;-1:-1:-1;107277:50:0;;;107153:182::o;101678:349::-;61795:24;61808:10;61795:12;:24::i;:::-;101823:10:::1;101799:20;:34;;101791:54;;;::::0;-1:-1:-1;;;101791:54:0;;34295:2:1;101791:54:0::1;::::0;::::1;34277:21:1::0;34334:1;34314:18;;;34307:29;-1:-1:-1;;;34352:18:1;;;34345:37;34399:18;;101791:54:0::1;34093:330:1::0;101791:54:0::1;101923:20;101856:23;:21;:23::i;:::-;:43;;:98:::0;;-1:-1:-1;;101856:98:0::1;;::::0;;;::::1;::::0;;;::::1;::::0;;101972:47:::1;::::0;168:25:1;;;101972:47:0::1;::::0;156:2:1;141:18;101972:47:0::1;14:185:1::0;63240:139:0;63321:23;:21;:23::i;:::-;:34;;;-1:-1:-1;;;;;63310:45:0;;;63321:34;;63310:45;63302:69;;;;-1:-1:-1;;;63302:69:0;;12185:2:1;63302:69:0;;;12167:21:1;12224:2;12204:18;;;12197:30;-1:-1:-1;;;12243:18:1;;;12236:41;12294:18;;63302:69:0;11983:335:1;63302:69:0;63240:139;:::o;97208:140::-;97266:7;97293:23;:21;:23::i;:::-;:47;;;-1:-1:-1;;;97293:47:0;;-1:-1:-1;;;;;97293:47:0;;;-1:-1:-1;97208:140:0:o;75102:119::-;75163:7;75190:23;75206:6;75190:15;:23::i;96321:112::-;96365:7;96392:23;:21;:23::i;:::-;:33;;;96385:40;;96321:112;:::o;66511:370::-;66593:26;;65954:53;66006:1;65962:40;65954:53;:::i;5868:348::-;6012:7;6032:14;6049:25;6056:1;6059;6062:11;6049:6;:25::i;:::-;6032:42;-1:-1:-1;6101:11:0;6089:8;:23;;;;;;;;:::i;:::-;;:56;;;;;6144:1;6129:11;6116:25;;;;;:::i;:::-;6126:1;6123;6116:25;:29;6089:56;6085:100;;;6162:11;6172:1;6162:11;;:::i;:::-;;;6085:100;6202:6;-1:-1:-1;5868:348:0;;;;;;;:::o;114672:360::-;-1:-1:-1;;;;;114765:19:0;;114757:68;;;;-1:-1:-1;;;114757:68:0;;34630:2:1;114757:68:0;;;34612:21:1;34669:2;34649:18;;;34642:30;34708:34;34688:18;;;34681:62;-1:-1:-1;;;34759:18:1;;;34752:34;34803:19;;114757:68:0;34428:400:1;114757:68:0;-1:-1:-1;;;;;114844:21:0;;114836:68;;;;-1:-1:-1;;;114836:68:0;;35035:2:1;114836:68:0;;;35017:21:1;35074:2;35054:18;;;35047:30;35113:34;35093:18;;;35086:62;-1:-1:-1;;;35164:18:1;;;35157:32;35206:19;;114836:68:0;34833:398:1;114836:68:0;114970:6;114917:23;:21;:23::i;:::-;-1:-1:-1;;;;;114917:41:0;;;;;;;:34;;;;;:41;;;;;;;;:50;;;;;;;;;;;;;:59;;;;114992:32;;168:25:1;;;114917:50:0;;114992:32;;141:18:1;114992:32:0;;;;;;;;114672:360;;;:::o;92451:683::-;92500:22;92593:26;92622:23;:21;:23::i;:::-;92688:22;;;;92593:52;;-1:-1:-1;;;;;;92688:22:0;92749:15;92725:39;;92721:406;;;92892:12;;;;92849:21;;;;64899:17;;-1:-1:-1;;;92892:12:0;;-1:-1:-1;;;;;92892:12:0;92874:15;:30;92849:56;92848:98;92810:136;;92524:610;;92451:683;:::o;92721:406::-;-1:-1:-1;;;;;92983:26:0;;;92979:148;;93109:4;93090:25;;;;:10;;;:25;;;;;;;-1:-1:-1;92979:148:0;92524:610;;92451:683;:::o;115323:493::-;115449:24;115476:25;115486:5;115493:7;115476:9;:25::i;:::-;115449:52;;-1:-1:-1;;115516:16:0;:37;115512:297;;115616:6;115596:16;:26;;115570:117;;;;-1:-1:-1;;;115570:117:0;;35438:2:1;115570:117:0;;;35420:21:1;35477:2;35457:18;;;35450:30;35516:31;35496:18;;;35489:59;35565:18;;115570:117:0;35236:353:1;115570:117:0;115731:51;115740:5;115747:7;115775:6;115756:16;:25;115731:8;:51::i;:::-;115438:378;115323:493;;;:::o;112351:517::-;-1:-1:-1;;;;;112439:18:0;;112431:68;;;;-1:-1:-1;;;112431:68:0;;35796:2:1;112431:68:0;;;35778:21:1;35835:2;35815:18;;;35808:30;35874:34;35854:18;;;35847:62;-1:-1:-1;;;35925:18:1;;;35918:35;35970:19;;112431:68:0;35594:401:1;112431:68:0;-1:-1:-1;;;;;112518:16:0;;112510:64;;;;-1:-1:-1;;;112510:64:0;;36202:2:1;112510:64:0;;;36184:21:1;36241:2;36221:18;;;36214:30;36280:34;36260:18;;;36253:62;-1:-1:-1;;;36331:18:1;;;36324:33;36374:19;;112510:64:0;36000:399:1;112510:64:0;112607:4;-1:-1:-1;;;;;112593:19:0;;;112585:58;;;;-1:-1:-1;;;112585:58:0;;36606:2:1;112585:58:0;;;36588:21:1;36645:2;36625:18;;;36618:30;36684:28;36664:18;;;36657:56;36730:18;;112585:58:0;36404:350:1;112585:58:0;112654:26;112683:23;:21;:23::i;:::-;-1:-1:-1;;;;;112719:16:0;;;;;;:10;;;:16;;;;;:26;;112654:52;;-1:-1:-1;112739:6:0;;112719:16;;;:26;;112739:6;;112719:26;:::i;:::-;;;;-1:-1:-1;;;;;;;112781:14:0;;;;;;;:10;;;:14;;;;;;;:24;;;;;;112834:26;112781:14;;112834:26;;;;;;;112799:6;168:25:1;;156:2;141:18;;14:185;112834:26:0;;;;;;;;112420:448;112351:517;;;:::o;90825:1135::-;90944:20;90966:29;91028:21;91064:28;91107:30;64969:42;-1:-1:-1;;;;;91151:37:0;;:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;91013:177;;-1:-1:-1;91013:177:0;-1:-1:-1;91013:177:0;-1:-1:-1;91207:18:0;;;;91203:750;;91266:22;91242:46;;91511:30;91544:161;91589:23;:21;:23::i;:::-;:34;;;91571:52;;-1:-1:-1;;;91589:34:0;;-1:-1:-1;;;;;91589:34:0;91571:15;:52;:::i;:::-;91642:48;91660:30;;;91642:15;:48;:::i;91544:161::-;91511:194;-1:-1:-1;64789:6:0;91884:10;91511:194;91755:62;91794:23;;;91755:15;:62;:::i;:::-;:108;;;;:::i;:::-;91754:140;;;;:::i;:::-;:187;;;;:::i;:::-;91722:219;;91227:726;91203:750;91002:958;;;90825:1135;;;:::o;91968:475::-;92018:23;92044:17;:15;:17::i;:::-;92018:43;;92076:15;92095:1;92076:20;92072:59;;92113:7;91968:475::o;92072:59::-;92281:15;92234:23;:21;:23::i;:::-;:44;;;-1:-1:-1;;;;;92234:44:0;:62;92230:156;;;92358:15;92313:23;:21;:23::i;:::-;:34;;:61;;-1:-1:-1;;;;;92313:61:0;;;-1:-1:-1;;;92313:61:0;;;;;;;;;92230:156;92398:37;92412:4;92419:15;92398:5;:37::i;618:106::-;676:7;707:1;703;:5;:13;;715:1;703:13;;113864:370;-1:-1:-1;;;;;113939:21:0;;113931:67;;;;-1:-1:-1;;;113931:67:0;;37514:2:1;113931:67:0;;;37496:21:1;37553:2;37533:18;;;37526:30;37592:34;37572:18;;;37565:62;-1:-1:-1;;;37643:18:1;;;37636:31;37684:19;;113931:67:0;37312:397:1;113931:67:0;114009:26;114038:23;:21;:23::i;:::-;-1:-1:-1;;;;;114074:19:0;;;;;;:10;;;:19;;;;;:29;;114009:52;;-1:-1:-1;114097:6:0;;114074:19;;;:29;;114097:6;;114074:29;:::i;:::-;;;;-1:-1:-1;;114139:13:0;;;:23;;;;;;;114189:37;;168:25:1;;;-1:-1:-1;;;;;;;114189:37:0;;;;;156:2:1;141:18;114189:37:0;14:185:1;113163:368:0;-1:-1:-1;;;;;113238:21:0;;113230:65;;;;-1:-1:-1;;;113230:65:0;;37916:2:1;113230:65:0;;;37898:21:1;37955:2;37935:18;;;37928:30;37994:33;37974:18;;;37967:61;38045:18;;113230:65:0;37714:355:1;113230:65:0;113306:26;113335:23;:21;:23::i;:::-;113306:52;;113388:6;113371:1;:13;;;:23;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;;;113430:19:0;;;;;;:10;;;:19;;;;;;;;:29;;;;;;113486:37;168:25:1;;;113486:37:0;;141:18:1;113486:37:0;14:185:1;120121:537:0;120179:7;120280:143;120462:23;:21;:23::i;:::-;:28;;120446:46;;;;;;:::i;:::-;;;;;;;;;;120531:11;;;;;;;;-1:-1:-1;;;120531:11:0;;;;;120247:388;;;;;39182:25:1;;;;39223:18;;39216:34;;;;120515:29:0;39266:18:1;;;39259:34;120567:13:0;39309:18:1;;;39302:34;120611:4:0;39352:19:1;;;39345:61;39154:19;;120247:388:0;;;;;;;;;;;;120219:431;;;;;;120199:451;;120121:537;:::o;80146:1540::-;80295:4;-1:-1:-1;;;;;80275:25:0;;;80267:59;;;;-1:-1:-1;;;80267:59:0;;39619:2:1;80267:59:0;;;39601:21:1;39658:2;39638:18;;;39631:30;-1:-1:-1;;;39677:18:1;;;39670:51;39738:18;;80267:59:0;39417:345:1;80267:59:0;80369:22;80380:10;80369;:22::i;:::-;80359:6;:32;;80337:112;;;;-1:-1:-1;;;80337:112:0;;39969:2:1;80337:112:0;;;39951:21:1;40008:2;39988:18;;;39981:30;40047:32;40027:18;;;40020:60;40097:18;;80337:112:0;39767:354:1;80337:112:0;80519:26;80548:23;:21;:23::i;:::-;80597:7;;80519:52;;-1:-1:-1;;;;;;80597:7:0;80687:58;80597:7;80711:10;80731:4;80738:6;80687:23;:58::i;:::-;80831:16;80864:6;80850:1;:11;;;:20;;;;:::i;:::-;80951:31;;-1:-1:-1;;;80951:31:0;;80976:4;80951:31;;;6404:51:1;80831:39:0;;-1:-1:-1;80927:21:0;;-1:-1:-1;;;;;80951:16:0;;;;;6377:18:1;;80951:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;81037:45;;-1:-1:-1;;;81037:45:0;;;;;168:25:1;;;80927:55:0;;-1:-1:-1;81059:4:0;;81037:35;;141:18:1;;81037:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;81281:31:0;;-1:-1:-1;;;81281:31:0;;81306:4;81281:31;;;6404:51:1;81223:16:0;;-1:-1:-1;81242:104:0;;-1:-1:-1;;;;;;81281:16:0;;;;;6377:18:1;;81281:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;81265:47;;:13;:47;:::i;:::-;81327:8;81242;:104::i;:::-;81223:123;;81407:8;81392:1;:11;;;:23;;;;;;;:::i;:::-;;;;-1:-1:-1;;81525:19:0;;;81511:11;;;:33;81592:23;81598:8;81608:6;81592:5;:23::i;:::-;81633:45;;;2843:25:1;;;2899:2;2884:18;;2877:34;;;-1:-1:-1;;;;;81633:45:0;;;81641:10;;81633:45;;2816:18:1;81633:45:0;;;;;;;80256:1430;;;;;80146:1540;;;:::o;82024:1892::-;82188:16;82198:5;82188:9;:16::i;:::-;82178:6;:26;;82170:70;;;;-1:-1:-1;;;82170:70:0;;40581:2:1;82170:70:0;;;40563:21:1;40620:2;40600:18;;;40593:30;40659:33;40639:18;;;40632:61;40710:18;;82170:70:0;40379:355:1;82170:70:0;82257:10;-1:-1:-1;;;;;82257:19:0;;;82253:94;;82293:42;82309:5;82316:10;82328:6;82293:15;:42::i;:::-;82359:26;82388:23;:21;:23::i;:::-;82515:7;;82550:11;;;;82359:52;;-1:-1:-1;;;;;;82515:7:0;;82626:13;;;82622:1042;;;82727:31;;-1:-1:-1;;;82727:31:0;;82752:4;82727:31;;;6404:51:1;82710:14:0;;-1:-1:-1;;;;;82727:16:0;;;;;6377:18:1;;82727:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;82862:53;;-1:-1:-1;;;82862:53:0;;82901:13;;;82862:53;;;168:25:1;82710:48:0;;-1:-1:-1;82884:4:0;;82862:38;;141:18:1;;82862:53:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;83082:31:0;;-1:-1:-1;;;83082:31:0;;83107:4;83082:31;;;6404:51:1;83035:17:0;;-1:-1:-1;83055:112:0;;-1:-1:-1;83116:6:0;;-1:-1:-1;;;;;83082:16:0;;;;;6377:18:1;;83082:31:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:40;;;;:::i;:::-;83141:1;:11;;;83055:8;:112::i;:::-;83213:17;;;;83035:132;-1:-1:-1;83262:12:0;83358:13;;;83354:212;;;83441:4;83432:6;:13;83425:20;;83546:4;83537:13;;83354:212;83635:16;83647:4;83635:9;:16;:::i;:::-;83619:1;:11;;;:33;;;;;;;:::i;:::-;;;;-1:-1:-1;;;;;82622:1042:0;83741:13;83748:6;83741:4;:13;:::i;:::-;83727:11;;;:27;83767:20;83773:5;83780:6;83767:5;:20::i;:::-;83800:37;-1:-1:-1;;;;;83800:19:0;;83820:8;83830:6;83800:19;:37::i;:::-;83855:53;;;2843:25:1;;;2899:2;2884:18;;2877:34;;;-1:-1:-1;;;;;83855:53:0;;;;;;;;83864:10;;83855:53;;2816:18:1;83855:53:0;;;;;;;82159:1757;;;82024:1892;;;;:::o;1726:4005::-;1842:14;;;-1:-1:-1;;2387:1:0;2384;2377:20;2431:1;2428;2424:9;2415:18;;2487:5;2483:2;2480:13;2472:5;2468:2;2464:14;2460:34;2451:43;;;2593:5;2602:1;2593:10;2589:77;;2639:11;2631:5;:19;;;;;:::i;:::-;;2624:26;;;;;;2589:77;2793:5;2779:11;:19;2771:28;;;;;;3062:17;3200:11;3197:1;3194;3187:25;4607:1;3759;3744:12;;:16;;3729:32;;3867:22;;;;4588:1;:15;;4587:21;;4844;;;4840:25;;4829:36;4914:21;;;4910:25;;4899:36;4985:21;;;4981:25;;4970:36;5056:21;;;5052:25;;5041:36;5127:21;;;5123:25;;5112:36;5199:21;;;5195:25;;;5184:36;;;3714:12;4118;;;4114:23;;;4110:31;;;3317:20;;;3306:32;;;4234:12;;;;3365:21;;3968:16;;;;4225:21;;;;5669:15;;;-1:-1:-1;;;;1726:4005:0:o;42752:248::-;42923:68;;-1:-1:-1;;;;;40997:15:1;;;42923:68:0;;;40979:34:1;41049:15;;41029:18;;;41022:43;41081:18;;;41074:34;;;42896:96:0;;42916:5;;-1:-1:-1;;;42946:27:0;40914:18:1;;42923:68:0;;;;-1:-1:-1;;42923:68:0;;;;;;;;;;;;;;-1:-1:-1;;;;;42923:68:0;-1:-1:-1;;;;;;42923:68:0;;;;;;;;;;42896:19;:96::i;42533:211::-;42677:58;;-1:-1:-1;;;;;41311:32:1;;42677:58:0;;;41293:51:1;41360:18;;;41353:34;;;42650:86:0;;42670:5;;-1:-1:-1;;;42700:23:0;41266:18:1;;42677:58:0;41119:274:1;42650:86:0;42533:211;;;:::o;45600:716::-;46024:23;46050:69;46078:4;46050:69;;;;;;;;;;;;;;;;;46058:5;-1:-1:-1;;;;;46050:27:0;;;:69;;;;;:::i;:::-;46134:17;;46024:95;;-1:-1:-1;46134:21:0;46130:179;;46231:10;46220:30;;;;;;;;;;;;:::i;:::-;46212:85;;;;-1:-1:-1;;;46212:85:0;;41600:2:1;46212:85:0;;;41582:21:1;41639:2;41619:18;;;41612:30;41678:34;41658:18;;;41651:62;-1:-1:-1;;;41729:18:1;;;41722:40;41779:19;;46212:85:0;41398:406:1;36569:229:0;36706:12;36738:52;36760:6;36768:4;36774:1;36777:12;36706;37977;37991:23;38018:6;-1:-1:-1;;;;;38018:11:0;38037:5;38044:4;38018:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;37976:73;;;;38067:69;38094:6;38102:7;38111:10;38123:12;38067:26;:69::i;:::-;38060:76;37689:455;-1:-1:-1;;;;;;;37689:455:0:o;40262:644::-;40447:12;40476:7;40472:427;;;40504:10;:17;40525:1;40504:22;40500:290;;-1:-1:-1;;;;;34107:19:0;;;40714:60;;;;-1:-1:-1;;;40714:60:0;;42710:2:1;40714:60:0;;;42692:21:1;42749:2;42729:18;;;42722:30;42788:31;42768:18;;;42761:59;42837:18;;40714:60:0;42508:353:1;40714:60:0;-1:-1:-1;40811:10:0;40804:17;;40472:427;40854:33;40862:10;40874:12;41609:17;;:21;41605:388;;41841:10;41835:17;41898:15;41885:10;41881:2;41877:19;41870:44;41605:388;41968:12;41961:20;;-1:-1:-1;;;41961:20:0;;;;;;;;:::i;204:250:1:-;289:1;299:113;313:6;310:1;307:13;299:113;;;389:11;;;383:18;370:11;;;363:39;335:2;328:10;299:113;;;-1:-1:-1;;446:1:1;428:16;;421:27;204:250::o;459:271::-;501:3;539:5;533:12;566:6;561:3;554:19;582:76;651:6;644:4;639:3;635:14;628:4;621:5;617:16;582:76;:::i;:::-;712:2;691:15;-1:-1:-1;;687:29:1;678:39;;;;719:4;674:50;;459:271;-1:-1:-1;;459:271:1:o;735:228::-;892:2;881:9;874:21;855:4;912:45;953:2;942:9;938:18;930:6;912:45;:::i;968:180::-;1027:6;1080:2;1068:9;1059:7;1055:23;1051:32;1048:52;;;1096:1;1093;1086:12;1048:52;-1:-1:-1;1119:23:1;;968:180;-1:-1:-1;968:180:1:o;1153:131::-;-1:-1:-1;;;;;1228:31:1;;1218:42;;1208:70;;1274:1;1271;1264:12;1289:134;1357:20;;1386:31;1357:20;1386:31;:::i;1428:315::-;1496:6;1504;1557:2;1545:9;1536:7;1532:23;1528:32;1525:52;;;1573:1;1570;1563:12;1525:52;1612:9;1599:23;1631:31;1656:5;1631:31;:::i;:::-;1681:5;1733:2;1718:18;;;;1705:32;;-1:-1:-1;;;1428:315:1:o;1948:247::-;2007:6;2060:2;2048:9;2039:7;2035:23;2031:32;2028:52;;;2076:1;2073;2066:12;2028:52;2115:9;2102:23;2134:31;2159:5;2134:31;:::i;2200:456::-;2277:6;2285;2293;2346:2;2334:9;2325:7;2321:23;2317:32;2314:52;;;2362:1;2359;2352:12;2314:52;2401:9;2388:23;2420:31;2445:5;2420:31;:::i;:::-;2470:5;-1:-1:-1;2527:2:1;2512:18;;2499:32;2540:33;2499:32;2540:33;:::i;:::-;2200:456;;2592:7;;-1:-1:-1;;;2646:2:1;2631:18;;;;2618:32;;2200:456::o;2922:127::-;2983:10;2978:3;2974:20;2971:1;2964:31;3014:4;3011:1;3004:15;3038:4;3035:1;3028:15;3054:253;3126:2;3120:9;3168:4;3156:17;;3203:18;3188:34;;3224:22;;;3185:62;3182:88;;;3250:18;;:::i;:::-;3286:2;3279:22;3054:253;:::o;3312:257::-;3384:4;3378:11;;;3416:17;;3463:18;3448:34;;3484:22;;;3445:62;3442:88;;;3510:18;;:::i;3574:275::-;3645:2;3639:9;3710:2;3691:13;;-1:-1:-1;;3687:27:1;3675:40;;3745:18;3730:34;;3766:22;;;3727:62;3724:88;;;3792:18;;:::i;:::-;3828:2;3821:22;3574:275;;-1:-1:-1;3574:275:1:o;3854:187::-;3903:4;3936:18;3928:6;3925:30;3922:56;;;3958:18;;:::i;:::-;-1:-1:-1;4024:2:1;4003:15;-1:-1:-1;;3999:29:1;4030:4;3995:40;;3854:187::o;4046:1032::-;4151:6;4159;4167;4175;4183;4236:3;4224:9;4215:7;4211:23;4207:33;4204:53;;;4253:1;4250;4243:12;4204:53;4292:9;4279:23;4311:31;4336:5;4311:31;:::i;:::-;4361:5;-1:-1:-1;4417:2:1;4402:18;;4389:32;4444:18;4433:30;;4430:50;;;4476:1;4473;4466:12;4430:50;4499:22;;4552:4;4544:13;;4540:27;-1:-1:-1;4530:55:1;;4581:1;4578;4571:12;4530:55;4617:2;4604:16;4642:49;4658:32;4687:2;4658:32;:::i;:::-;4642:49;:::i;:::-;4714:2;4707:5;4700:17;4754:7;4749:2;4744;4740;4736:11;4732:20;4729:33;4726:53;;;4775:1;4772;4765:12;4726:53;4830:2;4825;4821;4817:11;4812:2;4805:5;4801:14;4788:45;4874:1;4869:2;4864;4857:5;4853:14;4849:23;4842:34;4895:5;4885:15;;;;;4919:38;4953:2;4942:9;4938:18;4919:38;:::i;:::-;4909:48;;4976:38;5010:2;4999:9;4995:18;4976:38;:::i;:::-;4966:48;;5033:39;5067:3;5056:9;5052:19;5033:39;:::i;:::-;5023:49;;4046:1032;;;;;;;;:::o;5579:666::-;5758:2;5810:21;;;5880:13;;5783:18;;;5902:22;;;5729:4;;5758:2;5981:15;;;;5955:2;5940:18;;;5729:4;6024:195;6038:6;6035:1;6032:13;6024:195;;;6103:13;;-1:-1:-1;;;;;6099:39:1;6087:52;;6194:15;;;;6159:12;;;;6135:1;6053:9;6024:195;;;-1:-1:-1;6236:3:1;;5579:666;-1:-1:-1;;;;;;5579:666:1:o;6466:315::-;6534:6;6542;6595:2;6583:9;6574:7;6570:23;6566:32;6563:52;;;6611:1;6608;6601:12;6563:52;6647:9;6634:23;6624:33;;6707:2;6696:9;6692:18;6679:32;6720:31;6745:5;6720:31;:::i;:::-;6770:5;6760:15;;;6466:315;;;;;:::o;6786:461::-;6838:3;6876:5;6870:12;6903:6;6898:3;6891:19;6929:4;6958:2;6953:3;6949:12;6942:19;;6995:2;6988:5;6984:14;7016:1;7026:196;7040:6;7037:1;7034:13;7026:196;;;7105:13;;-1:-1:-1;;;;;;7101:40:1;7089:53;;7162:12;;;;7197:15;;;;7062:1;7055:9;7026:196;;;-1:-1:-1;7238:3:1;;6786:461;-1:-1:-1;;;;;6786:461:1:o;7252:1067::-;7448:4;7477:2;7517;7506:9;7502:18;7547:2;7536:9;7529:21;7570:6;7605;7599:13;7636:6;7628;7621:22;7662:2;7652:12;;7695:2;7684:9;7680:18;7673:25;;7757:2;7747:6;7744:1;7740:14;7729:9;7725:30;7721:39;7795:2;7787:6;7783:15;7816:1;7826:464;7840:6;7837:1;7834:13;7826:464;;;7905:22;;;-1:-1:-1;;7901:36:1;7889:49;;7961:13;;8006:9;;-1:-1:-1;;;;;8002:35:1;7987:51;;8077:11;;8071:18;8109:15;;;8102:27;;;8152:58;8194:15;;;8071:18;8152:58;:::i;:::-;8268:12;;;;8142:68;-1:-1:-1;;8233:15:1;;;;7862:1;7855:9;7826:464;;;-1:-1:-1;8307:6:1;;7252:1067;-1:-1:-1;;;;;;;;7252:1067:1:o;8525:117::-;8610:6;8603:5;8599:18;8592:5;8589:29;8579:57;;8632:1;8629;8622:12;8647:245;8705:6;8758:2;8746:9;8737:7;8733:23;8729:32;8726:52;;;8774:1;8771;8764:12;8726:52;8813:9;8800:23;8832:30;8856:5;8832:30;:::i;8897:266::-;9082:2;9071:9;9064:21;9045:4;9102:55;9153:2;9142:9;9138:18;9130:6;9102:55;:::i;9168:456::-;9245:6;9253;9261;9314:2;9302:9;9293:7;9289:23;9285:32;9282:52;;;9330:1;9327;9320:12;9282:52;9366:9;9353:23;9343:33;;9426:2;9415:9;9411:18;9398:32;9439:31;9464:5;9439:31;:::i;:::-;9489:5;-1:-1:-1;9546:2:1;9531:18;;9518:32;9559:33;9518:32;9559:33;:::i;:::-;9611:7;9601:17;;;9168:456;;;;;:::o;9629:131::-;-1:-1:-1;;;;;;9703:32:1;;9693:43;;9683:71;;9750:1;9747;9740:12;9765:245;9823:6;9876:2;9864:9;9855:7;9851:23;9847:32;9844:52;;;9892:1;9889;9882:12;9844:52;9931:9;9918:23;9950:30;9974:5;9950:30;:::i;10015:114::-;10099:4;10092:5;10088:16;10081:5;10078:27;10068:55;;10119:1;10116;10109:12;10134:801;10245:6;10253;10261;10269;10277;10285;10293;10346:3;10334:9;10325:7;10321:23;10317:33;10314:53;;;10363:1;10360;10353:12;10314:53;10402:9;10389:23;10421:31;10446:5;10421:31;:::i;:::-;10471:5;-1:-1:-1;10528:2:1;10513:18;;10500:32;10541:33;10500:32;10541:33;:::i;:::-;10593:7;-1:-1:-1;10647:2:1;10632:18;;10619:32;;-1:-1:-1;10698:2:1;10683:18;;10670:32;;-1:-1:-1;10754:3:1;10739:19;;10726:33;10768:31;10726:33;10768:31;:::i;:::-;10134:801;;;;-1:-1:-1;10134:801:1;;;;10818:7;10872:3;10857:19;;10844:33;;-1:-1:-1;10924:3:1;10909:19;;;10896:33;;10134:801;-1:-1:-1;;10134:801:1:o;10940:388::-;11008:6;11016;11069:2;11057:9;11048:7;11044:23;11040:32;11037:52;;;11085:1;11082;11075:12;11037:52;11124:9;11111:23;11143:31;11168:5;11143:31;:::i;:::-;11193:5;-1:-1:-1;11250:2:1;11235:18;;11222:32;11263:33;11222:32;11263:33;:::i;11333:380::-;11412:1;11408:12;;;;11455;;;11476:61;;11530:4;11522:6;11518:17;11508:27;;11476:61;11583:2;11575:6;11572:14;11552:18;11549:38;11546:161;;11629:10;11624:3;11620:20;11617:1;11610:31;11664:4;11661:1;11654:15;11692:4;11689:1;11682:15;11546:161;;11333:380;;;:::o;11718:127::-;11779:10;11774:3;11770:20;11767:1;11760:31;11810:4;11807:1;11800:15;11834:4;11831:1;11824:15;11850:128;11917:9;;;11938:11;;;11935:37;;;11952:18;;:::i;12323:355::-;12525:2;12507:21;;;12564:2;12544:18;;;12537:30;12603:33;12598:2;12583:18;;12576:61;12669:2;12654:18;;12323:355::o;12683:184::-;12753:6;12806:2;12794:9;12785:7;12781:23;12777:32;12774:52;;;12822:1;12819;12812:12;12774:52;-1:-1:-1;12845:16:1;;12683:184;-1:-1:-1;12683:184:1:o;12872:127::-;12933:10;12928:3;12924:20;12921:1;12914:31;12964:4;12961:1;12954:15;12988:4;12985:1;12978:15;13004:125;13069:9;;;13090:10;;;13087:36;;;13103:18;;:::i;13134:168::-;13207:9;;;13238;;13255:15;;;13249:22;;13235:37;13225:71;;13276:18;;:::i;13307:217::-;13347:1;13373;13363:132;;13417:10;13412:3;13408:20;13405:1;13398:31;13452:4;13449:1;13442:15;13480:4;13477:1;13470:15;13363:132;-1:-1:-1;13509:9:1;;13307:217::o;14259:545::-;14361:2;14356:3;14353:11;14350:448;;;14397:1;14422:5;14418:2;14411:17;14467:4;14463:2;14453:19;14537:2;14525:10;14521:19;14518:1;14514:27;14508:4;14504:38;14573:4;14561:10;14558:20;14555:47;;;-1:-1:-1;14596:4:1;14555:47;14651:2;14646:3;14642:12;14639:1;14635:20;14629:4;14625:31;14615:41;;14706:82;14724:2;14717:5;14714:13;14706:82;;;14769:17;;;14750:1;14739:13;14706:82;;;14710:3;;;14259:545;;;:::o;14980:1352::-;15106:3;15100:10;15133:18;15125:6;15122:30;15119:56;;;15155:18;;:::i;:::-;15184:97;15274:6;15234:38;15266:4;15260:11;15234:38;:::i;:::-;15228:4;15184:97;:::i;:::-;15336:4;;15400:2;15389:14;;15417:1;15412:663;;;;16119:1;16136:6;16133:89;;;-1:-1:-1;16188:19:1;;;16182:26;16133:89;-1:-1:-1;;14937:1:1;14933:11;;;14929:24;14925:29;14915:40;14961:1;14957:11;;;14912:57;16235:81;;15382:944;;15412:663;14206:1;14199:14;;;14243:4;14230:18;;-1:-1:-1;;15448:20:1;;;15566:236;15580:7;15577:1;15574:14;15566:236;;;15669:19;;;15663:26;15648:42;;15761:27;;;;15729:1;15717:14;;;;15596:19;;15566:236;;;15570:3;15830:6;15821:7;15818:19;15815:201;;;15891:19;;;15885:26;-1:-1:-1;;15974:1:1;15970:14;;;15986:3;15966:24;15962:37;15958:42;15943:58;15928:74;;15815:201;-1:-1:-1;;;;;16062:1:1;16046:14;;;16042:22;16029:36;;-1:-1:-1;14980:1352:1:o;16337:649::-;16417:6;16470:2;16458:9;16449:7;16445:23;16441:32;16438:52;;;16486:1;16483;16476:12;16438:52;16519:9;16513:16;16552:18;16544:6;16541:30;16538:50;;;16584:1;16581;16574:12;16538:50;16607:22;;16660:4;16652:13;;16648:27;-1:-1:-1;16638:55:1;;16689:1;16686;16679:12;16638:55;16718:2;16712:9;16743:49;16759:32;16788:2;16759:32;:::i;16743:49::-;16815:2;16808:5;16801:17;16855:7;16850:2;16845;16841;16837:11;16833:20;16830:33;16827:53;;;16876:1;16873;16866:12;16827:53;16889:67;16953:2;16948;16941:5;16937:14;16932:2;16928;16924:11;16889:67;:::i;:::-;16975:5;16337:649;-1:-1:-1;;;;;16337:649:1:o;16991:432::-;-1:-1:-1;;;17248:3:1;17241:17;17223:3;17287:6;17281:13;17303:74;17370:6;17366:1;17361:3;17357:11;17350:4;17342:6;17338:17;17303:74;:::i;:::-;17397:16;;;;17415:1;17393:24;;16991:432;-1:-1:-1;;16991:432:1:o;17428:376::-;17546:12;;17594:4;17583:16;;17577:23;-1:-1:-1;;;;;;17669:11:1;;;;17546:12;17577:23;17703:2;17692:14;;17689:109;;;17785:2;17779;17769:6;17765:2;17761:15;17758:1;17754:23;17750:32;17746:2;17742:41;17738:50;17729:59;;17689:109;;;;17428:376;;;:::o;17809:247::-;17877:6;17930:2;17918:9;17909:7;17905:23;17901:32;17898:52;;;17946:1;17943;17936:12;17898:52;17978:9;17972:16;17997:29;18020:5;17997:29;:::i;18061:191::-;18129:4;18162:18;18154:6;18151:30;18148:56;;;18184:18;;:::i;:::-;-1:-1:-1;18229:1:1;18225:14;18241:4;18221:25;;18061:191::o;18257:740::-;18321:5;18374:3;18367:4;18359:6;18355:17;18351:27;18341:55;;18392:1;18389;18382:12;18341:55;18421:6;18415:13;18447:4;18471:68;18487:51;18535:2;18487:51;:::i;18471:68::-;18573:15;;;18659:1;18655:10;;;;18643:23;;18639:32;;;18604:12;;;;18683:15;;;18680:35;;;18711:1;18708;18701:12;18680:35;18747:2;18739:6;18735:15;18759:209;18775:6;18770:3;18767:15;18759:209;;;18848:3;18842:10;18865:30;18889:5;18865:30;:::i;:::-;18908:18;;18946:12;;;;18792;;18759:209;;;-1:-1:-1;18986:5:1;18257:740;-1:-1:-1;;;;;;18257:740:1:o;19002:2006::-;19123:6;19154:2;19197;19185:9;19176:7;19172:23;19168:32;19165:52;;;19213:1;19210;19203:12;19165:52;19246:9;19240:16;19275:18;19316:2;19308:6;19305:14;19302:34;;;19332:1;19329;19322:12;19302:34;19370:6;19359:9;19355:22;19345:32;;19415:7;19408:4;19404:2;19400:13;19396:27;19386:55;;19437:1;19434;19427:12;19386:55;19466:2;19460:9;19489:68;19505:51;19553:2;19505:51;:::i;19489:68::-;19591:15;;;19673:1;19669:10;;;;19661:19;;19657:28;;;19622:12;;;;19697:19;;;19694:39;;;19729:1;19726;19719:12;19694:39;19761:2;19757;19753:11;19773:1205;19789:6;19784:3;19781:15;19773:1205;;;19868:3;19862:10;19904:2;19891:11;19888:19;19885:109;;;19948:1;19977:2;19973;19966:14;19885:109;20017:20;;20060:4;20088:16;;;-1:-1:-1;;20084:30:1;20080:39;-1:-1:-1;20077:129:1;;;20160:1;20189:2;20185;20178:14;20077:129;20232:22;;:::i;:::-;20296:2;20292;20288:11;20282:18;20313:33;20338:7;20313:33;:::i;:::-;20359:22;;20404:2;20440:11;;;20434:18;20487:1;20475:14;;20465:115;;20532:1;20562:3;20557;20550:16;20465:115;20600:14;;;20593:31;20659:11;;;20653:18;;20687:16;;;20684:109;;;20745:1;20775:3;20770;20763:16;20684:109;20829:75;20896:7;20891:2;20880:8;20876:2;20872:17;20868:26;20829:75;:::i;:::-;20813:14;;;20806:99;20918:18;;-1:-1:-1;;20956:12:1;;;;19806;;19773:1205;;;-1:-1:-1;20997:5:1;19002:2006;-1:-1:-1;;;;;;;;19002:2006:1:o;21013:127::-;21074:10;21069:3;21065:20;21062:1;21055:31;21105:4;21102:1;21095:15;21129:4;21126:1;21119:15;21145:2091;21413:4;21442:2;21482;21471:9;21467:18;21512:2;21501:9;21494:21;21535:6;21570;21564:13;21601:6;21593;21586:22;21627:3;21617:13;;21661:2;21650:9;21646:18;21639:25;;21723:2;21713:6;21710:1;21706:14;21695:9;21691:30;21687:39;21745:4;21784:2;21776:6;21772:15;21805:1;21815:1249;21829:6;21826:1;21823:13;21815:1249;;;21894:22;;;-1:-1:-1;;21890:37:1;21878:50;;21951:13;;22038:9;;-1:-1:-1;;;;;22034:35:1;22019:51;;22109:11;;;22103:18;21991:15;;;;22161:1;22144:19;;22134:170;;22214:10;22209:3;22205:20;22202:1;22195:31;22253:4;22250:1;22243:15;22285:4;22282:1;22275:15;22134:170;22324:15;;;22317:37;22377:4;22422:11;;;22416:18;22454:15;;;22447:27;;;22535:21;;22569:24;;;;22659:23;;;;-1:-1:-1;;22615:15:1;;;;22720:236;22736:8;22731:3;22728:17;22720:236;;;22817:15;;-1:-1:-1;;;;;;22813:42:1;22799:57;;22925:17;;;;22764:1;22755:11;;;;;22882:14;;;;22720:236;;;-1:-1:-1;23042:12:1;;;;22979:5;-1:-1:-1;;;23007:15:1;;;;21851:1;21844:9;21815:1249;;;-1:-1:-1;;;;;;;5536:31:1;;23100:18;;;5524:44;23157:22;;;23150:4;23135:20;;23128:52;23197:33;23161:6;23215;23197:33;:::i;:::-;23189:41;21145:2091;-1:-1:-1;;;;;;;;;;21145:2091:1:o;23732:964::-;23827:6;23858:2;23901;23889:9;23880:7;23876:23;23872:32;23869:52;;;23917:1;23914;23907:12;23869:52;23950:9;23944:16;23983:18;23975:6;23972:30;23969:50;;;24015:1;24012;24005:12;23969:50;24038:22;;24091:4;24083:13;;24079:27;-1:-1:-1;24069:55:1;;24120:1;24117;24110:12;24069:55;24149:2;24143:9;24172:68;24188:51;24236:2;24188:51;:::i;24172:68::-;24274:15;;;24356:1;24352:10;;;;24344:19;;24340:28;;;24305:12;;;;24380:19;;;24377:39;;;24412:1;24409;24402:12;24377:39;24436:11;;;;24456:210;24472:6;24467:3;24464:15;24456:210;;;24545:3;24539:10;24562:31;24587:5;24562:31;:::i;:::-;24606:18;;24489:12;;;;24644;;;;24456:210;;24701:277;24768:6;24821:2;24809:9;24800:7;24796:23;24792:32;24789:52;;;24837:1;24834;24827:12;24789:52;24869:9;24863:16;24922:5;24915:13;24908:21;24901:5;24898:32;24888:60;;24944:1;24941;24934:12;25317:581;25541:4;25587:1;25583;25578:3;25574:11;25570:19;25628:2;25620:6;25616:15;25605:9;25598:34;25668:3;25663:2;25652:9;25648:18;25641:31;25689:46;25730:3;25719:9;25715:19;25707:6;25689:46;:::i;:::-;25771:15;;;25766:2;25751:18;;25744:43;25823:15;;;25818:2;25803:18;;25796:43;-1:-1:-1;25876:15:1;;25870:3;25855:19;;;25848:44;25681:54;25317:581;-1:-1:-1;;25317:581:1:o;26920:1757::-;27038:6;27069:2;27112;27100:9;27091:7;27087:23;27083:32;27080:52;;;27128:1;27125;27118:12;27080:52;27161:9;27155:16;27190:18;27231:2;27223:6;27220:14;27217:34;;;27247:1;27244;27237:12;27217:34;27285:6;27274:9;27270:22;27260:32;;27330:7;27323:4;27319:2;27315:13;27311:27;27301:55;;27352:1;27349;27342:12;27301:55;27381:2;27375:9;27404:68;27420:51;27468:2;27420:51;:::i;27404:68::-;27506:15;;;27588:1;27584:10;;;;27576:19;;27572:28;;;27537:12;;;;27612:19;;;27609:39;;;27644:1;27641;27634:12;27609:39;27676:2;27672;27668:11;27688:959;27704:6;27699:3;27696:15;27688:959;;;27783:3;27777:10;27819:2;27806:11;27803:19;27800:109;;;27863:1;27892:2;27888;27881:14;27800:109;27932:20;;27975:4;28003:16;;;-1:-1:-1;;27999:30:1;27995:39;-1:-1:-1;27992:129:1;;;28075:1;28104:2;28100;28093:14;27992:129;28147:22;;:::i;:::-;28211:2;28207;28203:11;28197:18;28228:33;28253:7;28228:33;:::i;:::-;28274:22;;28331:11;;;28325:18;;28359:16;;;28356:106;;;28416:1;28445:2;28441;28434:14;28356:106;28498:75;28565:7;28560:2;28549:8;28545:2;28541:17;28537:26;28498:75;:::i;:::-;28482:14;;;28475:99;28587:18;;-1:-1:-1;;28625:12:1;;;;27721;;27688:959;;29248:422;29337:1;29380:5;29337:1;29394:270;29415:7;29405:8;29402:21;29394:270;;;29474:4;29470:1;29466:6;29462:17;29456:4;29453:27;29450:53;;;29483:18;;:::i;:::-;29533:7;29523:8;29519:22;29516:55;;;29553:16;;;;29516:55;29632:22;;;;29592:15;;;;29394:270;;;29398:3;29248:422;;;;;:::o;29675:806::-;29724:5;29754:8;29744:80;;-1:-1:-1;29795:1:1;29809:5;;29744:80;29843:4;29833:76;;-1:-1:-1;29880:1:1;29894:5;;29833:76;29925:4;29943:1;29938:59;;;;30011:1;30006:130;;;;29918:218;;29938:59;29968:1;29959:10;;29982:5;;;30006:130;30043:3;30033:8;30030:17;30027:43;;;30050:18;;:::i;:::-;-1:-1:-1;;30106:1:1;30092:16;;30121:5;;29918:218;;30220:2;30210:8;30207:16;30201:3;30195:4;30192:13;30188:36;30182:2;30172:8;30169:16;30164:2;30158:4;30155:12;30151:35;30148:77;30145:159;;;-1:-1:-1;30257:19:1;;;30289:5;;30145:159;30336:34;30361:8;30355:4;30336:34;:::i;:::-;30406:6;30402:1;30398:6;30394:19;30385:7;30382:32;30379:58;;;30417:18;;:::i;:::-;30455:20;;29675:806;-1:-1:-1;;;29675:806:1:o;30486:140::-;30544:5;30573:47;30614:4;30604:8;30600:19;30594:4;30573:47;:::i;31159:361::-;31253:6;31306:2;31294:9;31285:7;31281:23;31277:32;31274:52;;;31322:1;31319;31312:12;31274:52;31355:9;31349:16;31388:18;31380:6;31377:30;31374:50;;;31420:1;31417;31410:12;31374:50;31443:71;31506:7;31497:6;31486:9;31482:22;31443:71;:::i;31732:251::-;31802:6;31855:2;31843:9;31834:7;31830:23;31826:32;31823:52;;;31871:1;31868;31861:12;31823:52;31903:9;31897:16;31922:31;31947:5;31922:31;:::i;36759:548::-;36845:6;36853;36861;36914:2;36902:9;36893:7;36889:23;36885:32;36882:52;;;36930:1;36927;36920:12;36882:52;36962:9;36956:16;36981:30;37005:5;36981:30;:::i;:::-;37080:2;37065:18;;37059:25;37030:5;;-1:-1:-1;37128:10:1;37115:24;;37103:37;;37093:65;;37154:1;37151;37144:12;37093:65;37229:2;37214:18;;37208:25;37177:7;;-1:-1:-1;37242:33:1;37208:25;37242:33;:::i;38074:844::-;38204:3;38233:1;38266:6;38260:13;38296:36;38322:9;38296:36;:::i;:::-;38351:1;38368:18;;;38395:133;;;;38542:1;38537:356;;;;38361:532;;38395:133;-1:-1:-1;;38428:24:1;;38416:37;;38501:14;;38494:22;38482:35;;38473:45;;;-1:-1:-1;38395:133:1;;38537:356;38568:6;38565:1;38558:17;38598:4;38643:2;38640:1;38630:16;38668:1;38682:165;38696:6;38693:1;38690:13;38682:165;;;38774:14;;38761:11;;;38754:35;38817:16;;;;38711:10;;38682:165;;;38686:3;;;38876:6;38871:3;38867:16;38860:23;;38361:532;-1:-1:-1;38909:3:1;;38074:844;-1:-1:-1;;;;;;38074:844:1:o;42216:287::-;42345:3;42383:6;42377:13;42399:66;42458:6;42453:3;42446:4;42438:6;42434:17;42399:66;:::i;:::-;42481:16;;;;;42216:287;-1:-1:-1;;42216:287:1:o
Swarm Source
ipfs://55c25ed18b35da0a6d2cadb63741ca302103cc5dd2aa1c4e4c8d55a416103802
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.