More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 19 from a total of 19 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Redeem | 22987539 | 195 days ago | IN | 0 ETH | 0.00062826 | ||||
| Report | 22831093 | 216 days ago | IN | 0 ETH | 0.00022349 | ||||
| Switch Lending P... | 22772356 | 225 days ago | IN | 0 ETH | 0.00073272 | ||||
| Switch Lending P... | 22766903 | 225 days ago | IN | 0 ETH | 0.00138145 | ||||
| Report | 22746102 | 228 days ago | IN | 0 ETH | 0.00067887 | ||||
| Tend | 22652108 | 241 days ago | IN | 0 ETH | 0.00079161 | ||||
| Tend | 22559644 | 254 days ago | IN | 0 ETH | 0.00053797 | ||||
| Deposit | 22559638 | 254 days ago | IN | 0 ETH | 0.0003238 | ||||
| Report | 22559005 | 255 days ago | IN | 0 ETH | 0.00022605 | ||||
| Report | 22402966 | 276 days ago | IN | 0 ETH | 0.00022288 | ||||
| Set Max Tend Bas... | 22389925 | 278 days ago | IN | 0 ETH | 0.00005929 | ||||
| Tend | 22389925 | 278 days ago | IN | 0 ETH | 0.00132952 | ||||
| Deposit | 22389865 | 278 days ago | IN | 0 ETH | 0.00100127 | ||||
| Report | 22389793 | 278 days ago | IN | 0 ETH | 0.00038497 | ||||
| Set Profit Max U... | 22389774 | 278 days ago | IN | 0 ETH | 0.00006549 | ||||
| Set Performance ... | 22389766 | 278 days ago | IN | 0 ETH | 0.00005662 | ||||
| Set Keeper | 22389695 | 278 days ago | IN | 0 ETH | 0.00003747 | ||||
| Report | 22352955 | 283 days ago | IN | 0 ETH | 0.00058419 | ||||
| Deposit | 22352938 | 283 days ago | IN | 0 ETH | 0.00042655 |
Latest 22 internal transactions
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Deposit | 22987557 | 195 days ago | 0.14031808 ETH | ||||
| Transfer | 22987557 | 195 days ago | 0.14031808 ETH | ||||
| Deposit | 22987539 | 195 days ago | 14.00692408 ETH | ||||
| Transfer | 22987539 | 195 days ago | 14.00692408 ETH | ||||
| Exchange | 22652108 | 241 days ago | 6.46718982 ETH | ||||
| Transfer | 22652108 | 241 days ago | 6.46718982 ETH | ||||
| Exchange | 22652076 | 242 days ago | 0.5 ETH | ||||
| Transfer | 22652076 | 242 days ago | 0.5 ETH | ||||
| Exchange | 22559644 | 254 days ago | 2.73867572 ETH | ||||
| Transfer | 22559644 | 254 days ago | 2.73867572 ETH | ||||
| Exchange | 22559638 | 254 days ago | 0.2 ETH | ||||
| Transfer | 22559638 | 254 days ago | 0.2 ETH | ||||
| Exchange | 22558967 | 255 days ago | 0.01 ETH | ||||
| Transfer | 22558967 | 255 days ago | 0.01 ETH | ||||
| Exchange | 22389925 | 278 days ago | 2.59334502 ETH | ||||
| Transfer | 22389925 | 278 days ago | 2.59334502 ETH | ||||
| Exchange | 22389865 | 278 days ago | 0.2 ETH | ||||
| Transfer | 22389865 | 278 days ago | 0.2 ETH | ||||
| Exchange | 22352955 | 283 days ago | 1.28982554 ETH | ||||
| Transfer | 22352955 | 283 days ago | 1.28982554 ETH | ||||
| Exchange | 22352938 | 283 days ago | 0.1 ETH | ||||
| Transfer | 22352938 | 283 days ago | 0.1 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Amplify
Compiler Version
v0.8.18+commit.87f61d96
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2025-04-26
*/
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.18;
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
// OpenZeppelin Contracts (last updated v4.9.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 (last updated v4.9.4) (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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
/**
* @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].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* 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}.
*
* 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 default value returned by this function, unless
* it's 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 {}
}
// TokenizedStrategy interface used for internal view delegateCalls.
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol)
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*
* _Available since v4.7._
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/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.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
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].
*
* CAUTION: See Security Considerations above.
*/
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);
}
// Interface that implements the 4626 standard and the implementation functions
interface ITokenizedStrategy is IERC4626, IERC20Permit {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event StrategyShutdown();
event NewTokenizedStrategy(
address indexed strategy,
address indexed asset,
string apiVersion
);
event Reported(
uint256 profit,
uint256 loss,
uint256 protocolFees,
uint256 performanceFees
);
event UpdatePerformanceFeeRecipient(
address indexed newPerformanceFeeRecipient
);
event UpdateKeeper(address indexed newKeeper);
event UpdatePerformanceFee(uint16 newPerformanceFee);
event UpdateManagement(address indexed newManagement);
event UpdateEmergencyAdmin(address indexed newEmergencyAdmin);
event UpdateProfitMaxUnlockTime(uint256 newProfitMaxUnlockTime);
event UpdatePendingManagement(address indexed newPendingManagement);
/*//////////////////////////////////////////////////////////////
INITIALIZATION
//////////////////////////////////////////////////////////////*/
function initialize(
address _asset,
string memory _name,
address _management,
address _performanceFeeRecipient,
address _keeper
) external;
/*//////////////////////////////////////////////////////////////
NON-STANDARD 4626 OPTIONS
//////////////////////////////////////////////////////////////*/
function withdraw(
uint256 assets,
address receiver,
address owner,
uint256 maxLoss
) external returns (uint256);
function redeem(
uint256 shares,
address receiver,
address owner,
uint256 maxLoss
) external returns (uint256);
function maxWithdraw(
address owner,
uint256 /*maxLoss*/
) external view returns (uint256);
function maxRedeem(
address owner,
uint256 /*maxLoss*/
) external view returns (uint256);
/*//////////////////////////////////////////////////////////////
MODIFIER HELPERS
//////////////////////////////////////////////////////////////*/
function requireManagement(address _sender) external view;
function requireKeeperOrManagement(address _sender) external view;
function requireEmergencyAuthorized(address _sender) external view;
/*//////////////////////////////////////////////////////////////
KEEPERS FUNCTIONS
//////////////////////////////////////////////////////////////*/
function tend() external;
function report() external returns (uint256 _profit, uint256 _loss);
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
function MAX_FEE() external view returns (uint16);
function FACTORY() external view returns (address);
/*//////////////////////////////////////////////////////////////
GETTERS
//////////////////////////////////////////////////////////////*/
function apiVersion() external view returns (string memory);
function pricePerShare() external view returns (uint256);
function management() external view returns (address);
function pendingManagement() external view returns (address);
function keeper() external view returns (address);
function emergencyAdmin() external view returns (address);
function performanceFee() external view returns (uint16);
function performanceFeeRecipient() external view returns (address);
function fullProfitUnlockDate() external view returns (uint256);
function profitUnlockingRate() external view returns (uint256);
function profitMaxUnlockTime() external view returns (uint256);
function lastReport() external view returns (uint256);
function isShutdown() external view returns (bool);
function unlockedShares() external view returns (uint256);
/*//////////////////////////////////////////////////////////////
SETTERS
//////////////////////////////////////////////////////////////*/
function setPendingManagement(address) external;
function acceptManagement() external;
function setKeeper(address _keeper) external;
function setEmergencyAdmin(address _emergencyAdmin) external;
function setPerformanceFee(uint16 _performanceFee) external;
function setPerformanceFeeRecipient(
address _performanceFeeRecipient
) external;
function setProfitMaxUnlockTime(uint256 _profitMaxUnlockTime) external;
function setName(string calldata _newName) external;
function shutdownStrategy() external;
function emergencyWithdraw(uint256 _amount) external;
}
/**
* @title YearnV3 Base Strategy
* @author yearn.finance
* @notice
* BaseStrategy implements all of the required functionality to
* seamlessly integrate with the `TokenizedStrategy` implementation contract
* allowing anyone to easily build a fully permissionless ERC-4626 compliant
* Vault by inheriting this contract and overriding three simple functions.
* It utilizes an immutable proxy pattern that allows the BaseStrategy
* to remain simple and small. All standard logic is held within the
* `TokenizedStrategy` and is reused over any n strategies all using the
* `fallback` function to delegatecall the implementation so that strategists
* can only be concerned with writing their strategy specific code.
*
* This contract should be inherited and the three main abstract methods
* `_deployFunds`, `_freeFunds` and `_harvestAndReport` implemented to adapt
* the Strategy to the particular needs it has to generate yield. There are
* other optional methods that can be implemented to further customize
* the strategy if desired.
*
* All default storage for the strategy is controlled and updated by the
* `TokenizedStrategy`. The implementation holds a storage struct that
* contains all needed global variables in a manual storage slot. This
* means strategists can feel free to implement their own custom storage
* variables as they need with no concern of collisions. All global variables
* can be viewed within the Strategy by a simple call using the
* `TokenizedStrategy` variable. IE: TokenizedStrategy.globalVariable();.
*/
abstract contract BaseStrategy {
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
/**
* @dev Used on TokenizedStrategy callback functions to make sure it is post
* a delegateCall from this address to the TokenizedStrategy.
*/
modifier onlySelf() {
_onlySelf();
_;
}
/**
* @dev Use to assure that the call is coming from the strategies management.
*/
modifier onlyManagement() {
TokenizedStrategy.requireManagement(msg.sender);
_;
}
/**
* @dev Use to assure that the call is coming from either the strategies
* management or the keeper.
*/
modifier onlyKeepers() {
TokenizedStrategy.requireKeeperOrManagement(msg.sender);
_;
}
/**
* @dev Use to assure that the call is coming from either the strategies
* management or the emergency admin.
*/
modifier onlyEmergencyAuthorized() {
TokenizedStrategy.requireEmergencyAuthorized(msg.sender);
_;
}
/**
* @dev Require that the msg.sender is this address.
*/
function _onlySelf() internal view {
require(msg.sender == address(this), "!self");
}
/*//////////////////////////////////////////////////////////////
CONSTANTS
//////////////////////////////////////////////////////////////*/
/**
* @dev This is the address of the TokenizedStrategy implementation
* contract that will be used by all strategies to handle the
* accounting, logic, storage etc.
*
* Any external calls to the that don't hit one of the functions
* defined in this base or the strategy will end up being forwarded
* through the fallback function, which will delegateCall this address.
*
* This address should be the same for every strategy, never be adjusted
* and always be checked before any integration with the Strategy.
*/
address public constant tokenizedStrategyAddress =
0xD377919FA87120584B21279a491F82D5265A139c;
/*//////////////////////////////////////////////////////////////
IMMUTABLES
//////////////////////////////////////////////////////////////*/
/**
* @dev Underlying asset the Strategy is earning yield on.
* Stored here for cheap retrievals within the strategy.
*/
ERC20 internal immutable asset;
/**
* @dev This variable is set to address(this) during initialization of each strategy.
*
* This can be used to retrieve storage data within the strategy
* contract as if it were a linked library.
*
* i.e. uint256 totalAssets = TokenizedStrategy.totalAssets()
*
* Using address(this) will mean any calls using this variable will lead
* to a call to itself. Which will hit the fallback function and
* delegateCall that to the actual TokenizedStrategy.
*/
ITokenizedStrategy internal immutable TokenizedStrategy;
/**
* @notice Used to initialize the strategy on deployment.
*
* This will set the `TokenizedStrategy` variable for easy
* internal view calls to the implementation. As well as
* initializing the default storage variables based on the
* parameters and using the deployer for the permissioned roles.
*
* @param _asset Address of the underlying asset.
* @param _name Name the strategy will use.
*/
constructor(address _asset, string memory _name) {
asset = ERC20(_asset);
// Set instance of the implementation for internal use.
TokenizedStrategy = ITokenizedStrategy(address(this));
// Initialize the strategy's storage variables.
_delegateCall(
abi.encodeCall(
ITokenizedStrategy.initialize,
(_asset, _name, msg.sender, msg.sender, msg.sender)
)
);
// Store the tokenizedStrategyAddress at the standard implementation
// address storage slot so etherscan picks up the interface. This gets
// stored on initialization and never updated.
assembly {
sstore(
// keccak256('eip1967.proxy.implementation' - 1)
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc,
tokenizedStrategyAddress
)
}
}
/*//////////////////////////////////////////////////////////////
NEEDED TO BE OVERRIDDEN BY STRATEGIST
//////////////////////////////////////////////////////////////*/
/**
* @dev Can deploy up to '_amount' of 'asset' in the yield source.
*
* This function is called at the end of a {deposit} or {mint}
* call. Meaning that unless a whitelist is implemented it will
* be entirely permissionless and thus can be sandwiched or otherwise
* manipulated.
*
* @param _amount The amount of 'asset' that the strategy can attempt
* to deposit in the yield source.
*/
function _deployFunds(uint256 _amount) internal virtual;
/**
* @dev Should attempt to free the '_amount' of 'asset'.
*
* NOTE: The amount of 'asset' that is already loose has already
* been accounted for.
*
* This function is called during {withdraw} and {redeem} calls.
* Meaning that unless a whitelist is implemented it will be
* entirely permissionless and thus can be sandwiched or otherwise
* manipulated.
*
* Should not rely on asset.balanceOf(address(this)) calls other than
* for diff accounting purposes.
*
* Any difference between `_amount` and what is actually freed will be
* counted as a loss and passed on to the withdrawer. This means
* care should be taken in times of illiquidity. It may be better to revert
* if withdraws are simply illiquid so not to realize incorrect losses.
*
* @param _amount, The amount of 'asset' to be freed.
*/
function _freeFunds(uint256 _amount) internal virtual;
/**
* @dev Internal function to harvest all rewards, redeploy any idle
* funds and return an accurate accounting of all funds currently
* held by the Strategy.
*
* This should do any needed harvesting, rewards selling, accrual,
* redepositing etc. to get the most accurate view of current assets.
*
* NOTE: All applicable assets including loose assets should be
* accounted for in this function.
*
* Care should be taken when relying on oracles or swap values rather
* than actual amounts as all Strategy profit/loss accounting will
* be done based on this returned value.
*
* This can still be called post a shutdown, a strategist can check
* `TokenizedStrategy.isShutdown()` to decide if funds should be
* redeployed or simply realize any profits/losses.
*
* @return _totalAssets A trusted and accurate account for the total
* amount of 'asset' the strategy currently holds including idle funds.
*/
function _harvestAndReport()
internal
virtual
returns (uint256 _totalAssets);
/*//////////////////////////////////////////////////////////////
OPTIONAL TO OVERRIDE BY STRATEGIST
//////////////////////////////////////////////////////////////*/
/**
* @dev Optional function for strategist to override that can
* be called in between reports.
*
* If '_tend' is used tendTrigger() will also need to be overridden.
*
* This call can only be called by a permissioned role so may be
* through protected relays.
*
* This can be used to harvest and compound rewards, deposit idle funds,
* perform needed position maintenance or anything else that doesn't need
* a full report for.
*
* EX: A strategy that can not deposit funds without getting
* sandwiched can use the tend when a certain threshold
* of idle to totalAssets has been reached.
*
* This will have no effect on PPS of the strategy till report() is called.
*
* @param _totalIdle The current amount of idle funds that are available to deploy.
*/
function _tend(uint256 _totalIdle) internal virtual {}
/**
* @dev Optional trigger to override if tend() will be used by the strategy.
* This must be implemented if the strategy hopes to invoke _tend().
*
* @return . Should return true if tend() should be called by keeper or false if not.
*/
function _tendTrigger() internal view virtual returns (bool) {
return false;
}
/**
* @notice Returns if tend() should be called by a keeper.
*
* @return . Should return true if tend() should be called by keeper or false if not.
* @return . Calldata for the tend call.
*/
function tendTrigger() external view virtual returns (bool, bytes memory) {
return (
// Return the status of the tend trigger.
_tendTrigger(),
// And the needed calldata either way.
abi.encodeWithSelector(ITokenizedStrategy.tend.selector)
);
}
/**
* @notice Gets the max amount of `asset` that an address can deposit.
* @dev Defaults to an unlimited amount for any address. But can
* be overridden by strategists.
*
* This function will be called before any deposit or mints to enforce
* any limits desired by the strategist. This can be used for either a
* traditional deposit limit or for implementing a whitelist etc.
*
* EX:
* if(isAllowed[_owner]) return super.availableDepositLimit(_owner);
*
* This does not need to take into account any conversion rates
* from shares to assets. But should know that any non max uint256
* amounts may be converted to shares. So it is recommended to keep
* custom amounts low enough as not to cause overflow when multiplied
* by `totalSupply`.
*
* @param . The address that is depositing into the strategy.
* @return . The available amount the `_owner` can deposit in terms of `asset`
*/
function availableDepositLimit(
address /*_owner*/
) public view virtual returns (uint256) {
return type(uint256).max;
}
/**
* @notice Gets the max amount of `asset` that can be withdrawn.
* @dev Defaults to an unlimited amount for any address. But can
* be overridden by strategists.
*
* This function will be called before any withdraw or redeem to enforce
* any limits desired by the strategist. This can be used for illiquid
* or sandwichable strategies. It should never be lower than `totalIdle`.
*
* EX:
* return TokenIzedStrategy.totalIdle();
*
* This does not need to take into account the `_owner`'s share balance
* or conversion rates from shares to assets.
*
* @param . The address that is withdrawing from the strategy.
* @return . The available amount that can be withdrawn in terms of `asset`
*/
function availableWithdrawLimit(
address /*_owner*/
) public view virtual returns (uint256) {
return type(uint256).max;
}
/**
* @dev Optional function for a strategist to override that will
* allow management to manually withdraw deployed funds from the
* yield source if a strategy is shutdown.
*
* This should attempt to free `_amount`, noting that `_amount` may
* be more than is currently deployed.
*
* NOTE: This will not realize any profits or losses. A separate
* {report} will be needed in order to record any profit/loss. If
* a report may need to be called after a shutdown it is important
* to check if the strategy is shutdown during {_harvestAndReport}
* so that it does not simply re-deploy all funds that had been freed.
*
* EX:
* if(freeAsset > 0 && !TokenizedStrategy.isShutdown()) {
* depositFunds...
* }
*
* @param _amount The amount of asset to attempt to free.
*/
function _emergencyWithdraw(uint256 _amount) internal virtual {}
/*//////////////////////////////////////////////////////////////
TokenizedStrategy HOOKS
//////////////////////////////////////////////////////////////*/
/**
* @notice Can deploy up to '_amount' of 'asset' in yield source.
* @dev Callback for the TokenizedStrategy to call during a {deposit}
* or {mint} to tell the strategy it can deploy funds.
*
* Since this can only be called after a {deposit} or {mint}
* delegateCall to the TokenizedStrategy msg.sender == address(this).
*
* Unless a whitelist is implemented this will be entirely permissionless
* and thus can be sandwiched or otherwise manipulated.
*
* @param _amount The amount of 'asset' that the strategy can
* attempt to deposit in the yield source.
*/
function deployFunds(uint256 _amount) external virtual onlySelf {
_deployFunds(_amount);
}
/**
* @notice Should attempt to free the '_amount' of 'asset'.
* @dev Callback for the TokenizedStrategy to call during a withdraw
* or redeem to free the needed funds to service the withdraw.
*
* This can only be called after a 'withdraw' or 'redeem' delegateCall
* to the TokenizedStrategy so msg.sender == address(this).
*
* @param _amount The amount of 'asset' that the strategy should attempt to free up.
*/
function freeFunds(uint256 _amount) external virtual onlySelf {
_freeFunds(_amount);
}
/**
* @notice Returns the accurate amount of all funds currently
* held by the Strategy.
* @dev Callback for the TokenizedStrategy to call during a report to
* get an accurate accounting of assets the strategy controls.
*
* This can only be called after a report() delegateCall to the
* TokenizedStrategy so msg.sender == address(this).
*
* @return . A trusted and accurate account for the total amount
* of 'asset' the strategy currently holds including idle funds.
*/
function harvestAndReport() external virtual onlySelf returns (uint256) {
return _harvestAndReport();
}
/**
* @notice Will call the internal '_tend' when a keeper tends the strategy.
* @dev Callback for the TokenizedStrategy to initiate a _tend call in the strategy.
*
* This can only be called after a tend() delegateCall to the TokenizedStrategy
* so msg.sender == address(this).
*
* We name the function `tendThis` so that `tend` calls are forwarded to
* the TokenizedStrategy.
* @param _totalIdle The amount of current idle funds that can be
* deployed during the tend
*/
function tendThis(uint256 _totalIdle) external virtual onlySelf {
_tend(_totalIdle);
}
/**
* @notice Will call the internal '_emergencyWithdraw' function.
* @dev Callback for the TokenizedStrategy during an emergency withdraw.
*
* This can only be called after a emergencyWithdraw() delegateCall to
* the TokenizedStrategy so msg.sender == address(this).
*
* We name the function `shutdownWithdraw` so that `emergencyWithdraw`
* calls are forwarded to the TokenizedStrategy.
*
* @param _amount The amount of asset to attempt to free.
*/
function shutdownWithdraw(uint256 _amount) external virtual onlySelf {
_emergencyWithdraw(_amount);
}
/**
* @dev Function used to delegate call the TokenizedStrategy with
* certain `_calldata` and return any return values.
*
* This is used to setup the initial storage of the strategy, and
* can be used by strategist to forward any other call to the
* TokenizedStrategy implementation.
*
* @param _calldata The abi encoded calldata to use in delegatecall.
* @return . The return value if the call was successful in bytes.
*/
function _delegateCall(
bytes memory _calldata
) internal returns (bytes memory) {
// Delegate call the tokenized strategy with provided calldata.
(bool success, bytes memory result) = tokenizedStrategyAddress
.delegatecall(_calldata);
// If the call reverted. Return the error.
if (!success) {
assembly {
let ptr := mload(0x40)
let size := returndatasize()
returndatacopy(ptr, 0, size)
revert(ptr, size)
}
}
// Return the result.
return result;
}
/**
* @dev Execute a function on the TokenizedStrategy and return any value.
*
* This fallback function will be executed when any of the standard functions
* defined in the TokenizedStrategy are called since they wont be defined in
* this contract.
*
* It will delegatecall the TokenizedStrategy implementation with the exact
* calldata and return any relevant values.
*
*/
fallback() external {
// load our target address
address _tokenizedStrategyAddress = tokenizedStrategyAddress;
// Execute external function using delegatecall and return any value.
assembly {
// Copy function selector and any arguments.
calldatacopy(0, 0, calldatasize())
// Execute function delegatecall.
let result := delegatecall(
gas(),
_tokenizedStrategyAddress,
0,
calldatasize(),
0,
0
)
// Get any return value
returndatacopy(0, 0, returndatasize())
// Return any return value or error back to the caller
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
}
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
// OpenZeppelin Contracts (last updated v4.9.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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [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://consensys.net/diligence/blog/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.8.0/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;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
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));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
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");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
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");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation 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).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// 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 cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
interface IBalancer {
struct SingleSwap {
bytes32 poolId;
uint8 kind;
address assetIn;
address assetOut;
uint256 amount;
bytes userData;
}
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
function swap(
SingleSwap memory singleSwap,
FundManagement memory funds,
uint256 limit,
uint256 deadline
) external payable returns (uint256);
function flashLoan(
address recipient,
address[] memory tokens,
uint256[] memory amounts,
bytes memory userData
) external;
}
interface IBalancerPool{
function getPoolId() external view returns (bytes32);
}
interface IMorpho {
function flashLoan(
address token,
uint256 amount,
bytes memory userData) external;
}
interface IPoolAddressesProvider {
function getPriceOracle() external view returns (address);
function getPoolDataProvider() external view returns (address);
}
interface IPool {
function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
function withdraw(address asset, uint256 amount, address to) external returns (uint256);
function borrow(
address asset,
uint256 amount,
uint256 interestRateMode,
uint16 referralCode,
address onBehalfOf
) external;
function repay(
address asset,
uint256 amount,
uint256 interestRateMode,
address onBehalfOf
) external returns (uint256);
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external;
function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider);
function setUserEMode(uint8 categoryId) external;
function getReserveAToken(address asset) external view returns (address);
function getReserveVariableDebtToken(address asset) external view returns (address);
}
interface IPoolDataProvider {
function getReserveCaps(
address asset
) external view returns (uint256 borrowCap, uint256 supplyCap);
}
interface IPriceOracle {
function getAssetsPrices(address[] calldata assets) external view returns (uint256[] memory);
}
interface IAToken {
function totalSupply() external view returns (uint256);
}
/// @title Callback for IUniswapV3PoolActions#swap
/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface
interface IUniswapV3SwapCallback {
/// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap.
/// @dev In the implementation you must pay the pool tokens owed for the swap.
/// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory.
/// amount0Delta and amount1Delta can both be 0 if no tokens were swapped.
/// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token0 to the pool.
/// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by
/// the end of the swap. If positive, the callback must send that amount of token1 to the pool.
/// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call
function uniswapV3SwapCallback(
int256 amount0Delta,
int256 amount1Delta,
bytes calldata data
) external;
}
/// @title Router token swapping functionality
/// @notice Functions for swapping tokens via Uniswap V3
interface ISwapRouter is IUniswapV3SwapCallback {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(
ExactInputSingleParams calldata params
) external payable returns (uint256 amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}
/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata
/// @return amountOut The amount of the received token
function exactInput(
ExactInputParams calldata params
) external payable returns (uint256 amountOut);
struct ExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another token
/// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata
/// @return amountIn The amount of the input token
function exactOutputSingle(
ExactOutputSingleParams calldata params
) external payable returns (uint256 amountIn);
struct ExactOutputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountOut;
uint256 amountInMaximum;
}
/// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed)
/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata
/// @return amountIn The amount of the input token
function exactOutput(
ExactOutputParams calldata params
) external payable returns (uint256 amountIn);
// Taken from https://soliditydeveloper.com/uniswap3
// Manually added to the interface
function refundETH() external payable;
}
/**
* @title UniswapV3Swapper
* @author Yearn.finance
* @dev This is a simple contract that can be inherited by any tokenized
* strategy that would like to use Uniswap V3 for swaps. It hold all needed
* logic to perform both exact input and exact output swaps.
*
* The global address variables default to the ETH mainnet addresses but
* remain settable by the inheriting contract to allow for customization
* based on needs or chain its used on.
*
* The only variables that are required to be set are the specific fees
* for each token pair. The inheriting contract can use the {_setUniFees}
* function to easily set this for any token pairs needed.
*/
contract UniswapV3Swapper {
using SafeERC20 for ERC20;
// Optional Variable to be set to not sell dust.
uint256 public minAmountToSell;
// Defaults to WETH on mainnet.
address public base = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
// Defaults to Uniswap V3 router on mainnet.
address public router = 0xE592427A0AEce92De3Edee1F18E0157C05861564;
// Fees for the Uni V3 pools. Each fee should get set each way in
// the mapping so no matter the direction the correct fee will get
// returned for any two tokens.
mapping(address => mapping(address => uint24)) public uniFees;
/**
* @dev All fess will default to 0 on creation. A strategist will need
* To set the mapping for the tokens expected to swap. This function
* is to help set the mapping. It can be called internally during
* initialization, through permissioned functions etc.
*/
function _setUniFees(
address _token0,
address _token1,
uint24 _fee
) internal virtual {
uniFees[_token0][_token1] = _fee;
uniFees[_token1][_token0] = _fee;
}
/**
* @dev Used to swap a specific amount of `_from` to `_to`.
* This will check and handle all allowances as well as not swapping
* unless `_amountIn` is greater than the set `_minAmountOut`
*
* If one of the tokens matches with the `base` token it will do only
* one jump, otherwise will do two jumps.
*
* The corresponding uniFees for each token pair will need to be set
* other wise this function will revert.
*
* @param _from The token we are swapping from.
* @param _to The token we are swapping to.
* @param _amountIn The amount of `_from` we will swap.
* @param _minAmountOut The min of `_to` to get out.
* @return _amountOut The actual amount of `_to` that was swapped to
*/
function _swapFrom(
address _from,
address _to,
uint256 _amountIn,
uint256 _minAmountOut
) internal virtual returns (uint256 _amountOut) {
if (_amountIn != 0 && _amountIn >= minAmountToSell) {
_checkAllowance(router, _from, _amountIn);
if (_from == base || _to == base) {
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
.ExactInputSingleParams(
_from, // tokenIn
_to, // tokenOut
uniFees[_from][_to], // from-to fee
address(this), // recipient
block.timestamp, // deadline
_amountIn, // amountIn
_minAmountOut, // amountOut
0 // sqrtPriceLimitX96
);
_amountOut = ISwapRouter(router).exactInputSingle(params);
} else {
bytes memory path = abi.encodePacked(
_from, // tokenIn
uniFees[_from][base], // from-base fee
base, // base token
uniFees[base][_to], // base-to fee
_to // tokenOut
);
_amountOut = ISwapRouter(router).exactInput(
ISwapRouter.ExactInputParams(
path,
address(this),
block.timestamp,
_amountIn,
_minAmountOut
)
);
}
}
}
/**
* @dev Used to swap a specific amount of `_to` from `_from` unless
* it takes more than `_maxAmountFrom`.
*
* This will check and handle all allowances as well as not swapping
* unless `_maxAmountFrom` is greater than the set `minAmountToSell`
*
* If one of the tokens matches with the `base` token it will do only
* one jump, otherwise will do two jumps.
*
* The corresponding uniFees for each token pair will need to be set
* other wise this function will revert.
*
* @param _from The token we are swapping from.
* @param _to The token we are swapping to.
* @param _amountTo The amount of `_to` we need out.
* @param _maxAmountFrom The max of `_from` we will swap.
* @return _amountIn The actual amount of `_from` swapped.
*/
function _swapTo(
address _from,
address _to,
uint256 _amountTo,
uint256 _maxAmountFrom
) internal virtual returns (uint256 _amountIn) {
if (_maxAmountFrom != 0 && _maxAmountFrom >= minAmountToSell) {
_checkAllowance(router, _from, _maxAmountFrom);
if (_from == base || _to == base) {
ISwapRouter.ExactOutputSingleParams memory params = ISwapRouter
.ExactOutputSingleParams(
_from, // tokenIn
_to, // tokenOut
uniFees[_from][_to], // from-to fee
address(this), // recipient
block.timestamp, // deadline
_amountTo, // amountOut
_maxAmountFrom, // maxAmountIn
0 // sqrtPriceLimitX96
);
_amountIn = ISwapRouter(router).exactOutputSingle(params);
} else {
bytes memory path = abi.encodePacked(
_to,
uniFees[base][_to], // base-to fee
base,
uniFees[_from][base], // from-base fee
_from
);
_amountIn = ISwapRouter(router).exactOutput(
ISwapRouter.ExactOutputParams(
path,
address(this),
block.timestamp,
_amountTo, // How much we want out
_maxAmountFrom
)
);
}
}
}
/**
* @dev Internal safe function to make sure the contract you want to
* interact with has enough allowance to pull the desired tokens.
*
* @param _contract The address of the contract that will move the token.
* @param _token The ERC-20 token that will be getting spent.
* @param _amount The amount of `_token` to be spent.
*/
function _checkAllowance(
address _contract,
address _token,
uint256 _amount
) internal virtual {
if (ERC20(_token).allowance(address(this), _contract) < _amount) {
ERC20(_token).safeApprove(_contract, 0);
ERC20(_token).safeApprove(_contract, _amount);
}
}
}
interface ICurve {
function exchange(
int128 from,
int128 to,
uint256 _from_amount,
uint256 _min_to_amount
) external payable returns(uint256);
function get_dy(
int128 from,
int128 to,
uint256 _from_amount
) external view returns (uint256);
}
interface IWETH {
function deposit() external payable;
function withdraw(uint256) external;
}
interface ISTETH is IERC20 {
function submit(address) external payable returns (uint256);
function isStakingPaused() external returns (bool);
}
interface IWSTETH {
function wrap(uint256 _stETHAmount) external returns (uint256);
function unwrap(uint256 _wstETHAmount) external returns (uint256);
}
contract Amplify is BaseStrategy, UniswapV3Swapper {
using SafeERC20 for ERC20;
enum Action {LEVERUP, LEVERDOWN, SWITCH}
enum Swapper {UNIV3, CURVE, BALANCER}
uint256 public LTVemergencyLeverDown = 9400 * WAD / 10000;
uint256 public LTVleverDown = 9350 * WAD / 10000;
uint256 public LTVtarget = 9280 * WAD / 10000;
uint256 public LTVleverUp = 9150 * WAD / 10000;
uint256 public swapSlippageBPS = 500; //default: 5%
uint256 public maxTendBasefee = 2e9; //default: 2 gwei
address internal constant LST = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0;
address internal constant STETH = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;
uint8 internal constant EMODE = 1;
// Swapper
address internal constant CURVE_POOL = 0xDC24316b9AE028F1497c275EB9192a3Ea0f67022;
int128 internal constant ASSETID = 0;
int128 internal constant LSTID = 1;
address internal constant BALANCER_POOL = 0x93d199263632a4EF4Bb438F1feB99e57b4b5f0BD;
Swapper public swapper = Swapper.CURVE;
// Flashloan
address internal constant BALANCER = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;
address internal constant MORPHO = 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb;
address public flashloanProvider = BALANCER;
// LendingPool
address internal constant AAVE_PRIME = 0x4e033931ad43597d96D6bcc25c280717730B58B1;
address internal constant AAVE_PRIME_ATOKEN = 0xC035a7cf15375cE2706766804551791aD035E0C2;
address internal constant AAVE_PRIME_DTOKEN = 0x91b7d78BF92db564221f6B5AeE744D1727d1Dd1e;
address internal constant AAVE_CORE = 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2;
address internal constant AAVE_CORE_ATOKEN = 0x0B925eD163218f6662a35e0f0371Ac234f9E9371;
address internal constant AAVE_CORE_DTOKEN = 0xeA51d7853EEFb32b6ee06b1C12E6dcCA88Be0fFE;
address public lendingPool = AAVE_PRIME;
address internal aToken = AAVE_PRIME_ATOKEN;
address internal debtToken = AAVE_PRIME_DTOKEN;
address internal protocolDataProvider;
address internal priceOracle;
bool public open = true;
mapping(address => bool) public allowed;
// Constants
uint256 internal constant COLLATERAL_DUST = 10;
uint256 internal constant DEBT_DUST = 5;
uint256 internal constant CEILING_DUST = 4e14;
uint256 internal constant MAX_BPS = 10000;
uint256 internal constant WAD = 1e18;
address public immutable MANAGEMENT;
bool internal flashloanActive;
constructor(address _asset, string memory _name)
BaseStrategy(_asset, _name)
{
MANAGEMENT = msg.sender;
_initializeLendingPool();
minAmountToSell = 1;
base = _asset;
_setUniFees(_asset, LST, 100);
//Staking approvals:
ERC20(STETH).safeApprove(LST, type(uint256).max);
//AAVE approvals:
ERC20(_asset).safeApprove(AAVE_PRIME, type(uint256).max);
ERC20(LST).safeApprove(AAVE_PRIME, type(uint256).max);
ERC20(_asset).safeApprove(AAVE_CORE, type(uint256).max);
ERC20(LST).safeApprove(AAVE_CORE, type(uint256).max);
//Swap approvals:
ERC20(STETH).safeApprove(CURVE_POOL, type(uint256).max);
ERC20(LST).safeApprove(BALANCER, type(uint256).max);
//Flashloan approvals:
ERC20(_asset).safeApprove(MORPHO, type(uint256).max);
}
function _initializeLendingPool() internal {
IPoolAddressesProvider addressProvider = IPoolAddressesProvider(IPool(lendingPool).ADDRESSES_PROVIDER());
priceOracle = addressProvider.getPriceOracle();
protocolDataProvider = addressProvider.getPoolDataProvider();
IPool(lendingPool).setUserEMode(EMODE);
}
receive() external payable {}
// ----------------- SWAPS: -----------------
function _swapAssetToLST(uint256 _amount) internal returns (uint256) {
_amount = _min(_amount, balanceOfAsset());
if (_amount == 0) return 0;
return _swapCurveAssetToLST(_amount);
}
function _swapLSTtoAsset(uint256 _amount, uint256 _swapSlippageBPS) internal {
_amount = _min(_amount, balanceOfLST());
if (_amount == 0) return;
if (swapper == Swapper.CURVE) {
_swapCurveLSTtoAsset(_amount, _swapSlippageBPS);
return;
}
if (swapper == Swapper.BALANCER) {
_swapBalancer(LST, address(asset), _amount, _minOutFromLST(_amount, _swapSlippageBPS));
return;
}
//else: Swapper.UNIV3
_swapFrom(LST, address(asset), _amount, _minOutFromLST(_amount, _swapSlippageBPS)); //minAmountOut in asset, account for swapping slippage
}
function _swapCurveAssetToLST(uint256 _amount) internal returns (uint256) {
IWETH(address(asset)).withdraw(_amount);
if ( ICurve(CURVE_POOL).get_dy(ASSETID, LSTID, _amount) < _amount){
ISTETH(STETH).submit{value: _amount}(MANAGEMENT);
return IWSTETH(LST).wrap(_amount);
} else {
return IWSTETH(LST).wrap(ICurve(CURVE_POOL).exchange{value: _amount}(ASSETID, LSTID, _amount, _amount)); //swap for at least 1:1
}
}
function _swapCurveLSTtoAsset(uint256 _amount, uint256 _swapSlippageBPS) internal {
_amount = IWSTETH(LST).unwrap(_amount);
IWETH(address(asset)).deposit{value: ICurve(CURVE_POOL).exchange(LSTID, ASSETID, _amount, _minOutFromAsset(_amount, _swapSlippageBPS))}();
}
function _swapBalancer(address _tokenIn, address _tokenOut, uint256 _amount, uint256 _minAmountOut) internal returns (uint256) {
IBalancer.SingleSwap memory singleSwap;
singleSwap.poolId = IBalancerPool(BALANCER_POOL).getPoolId();
singleSwap.kind = 0;
singleSwap.assetIn = _tokenIn;
singleSwap.assetOut = _tokenOut;
singleSwap.amount = _amount;
IBalancer.FundManagement memory funds;
funds.sender = address(this);
funds.fromInternalBalance = true;
funds.recipient = payable(this);
funds.toInternalBalance = false;
return IBalancer(BALANCER).swap(singleSwap, funds, _minAmountOut, block.timestamp);
}
function _minOutFromAsset(uint256 _amount, uint256 _swapSlippageBPS) internal pure returns (uint256) {
return _amount * (MAX_BPS - _swapSlippageBPS) / MAX_BPS;
}
function _minOutFromLST(uint256 _amount, uint256 _swapSlippageBPS) internal view returns (uint256) {
if (_swapSlippageBPS == MAX_BPS) return 0;
return _amount * _getLSTprice() * (MAX_BPS - _swapSlippageBPS) / WAD / MAX_BPS;
}
// ----------------- LENDING POOL -----------------
function _depositCollateral(uint256 _amount) internal {
if (_amount < COLLATERAL_DUST) return;
_amount = _min(balanceOfLST(), _amount);
if (_amount < COLLATERAL_DUST) return;
IPool(lendingPool).supply(LST, _amount, address(this), 0);
}
function _withdrawCollateral(uint256 _amount) internal {
if (_amount < COLLATERAL_DUST) return;
_amount = _min(balanceOfCollateral(), _amount);
if (_amount < COLLATERAL_DUST) return;
IPool(lendingPool).withdraw(LST, _amount, address(this));
}
function _borrowAsset(uint256 _amount) internal {
if (_amount == 0) return;
IPool pool = IPool(lendingPool);
pool.setUserUseReserveAsCollateral(LST, true);
pool.setUserEMode(EMODE);
pool.borrow(address(asset), _amount, 2, 0, address(this));
}
function _repayDebt(uint256 _amount) internal {
if (_amount == 0) return;
_amount = _min(_amount, balanceOfDebt());
if (_amount == 0) return;
IPool(lendingPool).repay(address(asset), _amount, 2, address(this));
}
function _maxDepositableCollateral() internal view returns (uint256) {
(, uint256 supplyCap) = IPoolDataProvider(protocolDataProvider).getReserveCaps(LST);
uint256 maximumAmount = supplyCap * WAD;
uint256 currentAmount = IAToken(aToken).totalSupply();
if (currentAmount + CEILING_DUST >= maximumAmount) {
return 0;
} else {
unchecked {
return maximumAmount - currentAmount - CEILING_DUST;
}
}
}
function _getLSTprice() internal view returns (uint256){
address[] memory assets = new address[](2);
assets[0] = LST;
assets[1] = address(asset);
uint[] memory prices = IPriceOracle(priceOracle).getAssetsPrices(assets);
return WAD * prices[0] / prices[1];
}
/*//////////////////////////////////////////////////////////////
INTERNAL OVERRIDE
//////////////////////////////////////////////////////////////*/
function _deployFunds(uint256 _amount) internal override {
_depositCollateral(_swapAssetToLST(_amount));
}
function availableDepositLimit(address _owner) public view override returns (uint256) {
if (!open && !allowed[_owner]) {
return 0;
}
uint256 maxDepositableInAsset = _maxDepositableCollateral() * WAD / _getLSTprice();
if (maxDepositableInAsset > WAD) {
unchecked {
return maxDepositableInAsset - WAD;
}
} else {
return 0;
}
}
function _freeFunds(uint256 _assetAmount) internal override {
uint256 totalAssets = TokenizedStrategy.totalAssets();
uint256 totalDebt = totalAssets - balanceOfAsset();
uint256 percentageOfSharesToRedeem;
if (totalDebt > 0) {
percentageOfSharesToRedeem = WAD * _assetAmount / totalDebt;
}
if (percentageOfSharesToRedeem > 0) {
_leverDown(percentageOfSharesToRedeem, MAX_BPS, balanceOfCollateral(), balanceOfDebt(), _getLSTprice(), LTVtarget);
}
uint256 assetBalance = balanceOfAsset();
if (assetBalance > _assetAmount) {
unchecked {
_repayDebt(assetBalance - _assetAmount);
}
}
if (balanceOfDebt() > DEBT_DUST) {
require(getLTV() < LTVemergencyLeverDown, "LTV is high, wait for keeper rebalance first");
}
}
function _harvestAndReport() internal override returns (uint256 _totalAssets) {
_rebalance();
_totalAssets = balanceOfAsset() + (balanceOfLST() + balanceOfCollateral()) * _getLSTprice() / WAD - balanceOfDebt();
}
function _tend(uint256 /*_totalIdle*/) internal override {
_rebalance();
}
function _tendTrigger() internal view override returns (bool) {
uint256 LTV = getLTV();
// Lever down if we need to repay debt and are above emergency limit, we do it regardless of the call cost
if (LTV >= LTVemergencyLeverDown) {
return true;
}
if (block.basefee >= maxTendBasefee) {
return false;
}
// Check if we need to lever down to reduce leverage
if (LTV >= LTVleverDown) {
return true;
}
// Check maximum depositable collateral once to avoid redundant calls
uint256 maxDepositable = _maxDepositableCollateral();
if (maxDepositable <= COLLATERAL_DUST) {
return false;
}
// Check for idle LST tokens that could be supplied
if (balanceOfLST() > COLLATERAL_DUST) {
return true;
}
// Also return early if the strategy is shutdown
if (TokenizedStrategy.isShutdown()) {
return false;
}
// Check if conditions are right for lever up (adding leverage)
if (LTV < LTVleverUp && balanceOfCollateral() > COLLATERAL_DUST) {
return maxDepositable >= WAD;
}
return false;
}
/*//////////////////////////////////////////////////////////////
LTV MANAGEMENT & LEVERAGE
//////////////////////////////////////////////////////////////*/
function _rebalance() internal {
uint256 balance = balanceOfAsset();
uint256 maxDepositable;
bool maxDepositableSet;
if (balance > 0) {
_swapCurveAssetToLST(balance);
}
balance = balanceOfLST();
if (balance > COLLATERAL_DUST) {
maxDepositable = _maxDepositableCollateral();
maxDepositableSet = true;
if (maxDepositable > COLLATERAL_DUST) {
balance = _min(balance, maxDepositable);
IPool(lendingPool).supply(LST, balance, address(this), 0);
unchecked {
maxDepositable -= balance;
}
}
}
uint256 currentCollateral = balanceOfCollateral();
uint256 currentDebt = balanceOfDebt();
uint256 LSTprice = _getLSTprice();
uint256 LTV = _getLTVwithParams(currentCollateral, currentDebt, LSTprice);
uint256 _LTVleverDown = LTVleverDown;
if (LTV >= _LTVleverDown) { // check if we need to lever down
_leverDown(0, swapSlippageBPS, currentCollateral, currentDebt, LSTprice, LTVtarget);
// Check that lever down improved the LTV:
if (balanceOfDebt() > DEBT_DUST) {
require(getLTV() < LTV, "lever down failure");
}
} else if (!TokenizedStrategy.isShutdown()) {
if (LTV < LTVleverUp) { // Check if we need to lever up
if (!maxDepositableSet) {
maxDepositable = _maxDepositableCollateral();
}
if (maxDepositable > COLLATERAL_DUST) {
_leverUp(LTVtarget, maxDepositable, currentCollateral, currentDebt, LSTprice);
// Check that lever up did not go above emergency LTV
if (balanceOfDebt() > DEBT_DUST) {
require(getLTV() < _LTVleverDown, "lever up failure");
}
}
}
}
}
function _leverUp(
uint256 _LTVtarget,
uint256 _maxDepositable,
uint256 _currentCollateral,
uint256 _currentDebt,
uint256 _LSTprice
) internal {
uint256 LTV = _getLTVwithParams(_currentCollateral, _currentDebt, _LSTprice);
uint256 _assetAmountInitial = balanceOfAsset();
uint256 collateralBalanceInAsset = _currentCollateral * _LSTprice / WAD;
uint256 targetCollateral = (_assetAmountInitial + collateralBalanceInAsset * (WAD - LTV) / WAD) * WAD / (WAD - _LTVtarget);
targetCollateral = _min(targetCollateral, collateralBalanceInAsset + _maxDepositable * _LSTprice / WAD);
if (targetCollateral < COLLATERAL_DUST) {
return;
}
uint256 flashloanAmount = targetCollateral * _LTVtarget / WAD - balanceOfDebt();
flashloanAmount = _min(flashloanAmount, asset.balanceOf(address(flashloanProvider)));
bytes memory data = abi.encode(Action.LEVERUP, _assetAmountInitial, 0);
_initFlashLoan(data, flashloanAmount);
}
function _leverDown(
uint256 _percentageOfSharesToRedeem,
uint256 _swapSlippageBPS,
uint256 _currentCollateral,
uint256 _currentDebt,
uint256 _LSTprice,
uint256 _LTVtarget
) internal {
if (_currentCollateral < COLLATERAL_DUST){
return;
}
uint256 LTV = _getLTVwithParams(_currentCollateral, _currentDebt, _LSTprice);
uint256 targetCollateral;
uint256 targetDebt;
if (_percentageOfSharesToRedeem == 0) {
targetCollateral = _currentCollateral * (WAD - LTV) / (WAD - _LTVtarget);
targetDebt = targetCollateral * _LSTprice * _LTVtarget / WAD / WAD;
} else {
_percentageOfSharesToRedeem = _min(WAD, _percentageOfSharesToRedeem);
targetCollateral = _currentCollateral * (WAD - _percentageOfSharesToRedeem) / WAD;
targetDebt = _currentDebt * (WAD - _percentageOfSharesToRedeem) / WAD;
}
uint256 collateralToSell = _currentCollateral - targetCollateral;
uint256 flashloanAmount = _currentDebt - targetDebt;
uint256 flashloanMaximum = asset.balanceOf(address(flashloanProvider));
if (flashloanMaximum < flashloanAmount) {
flashloanAmount = flashloanMaximum;
collateralToSell = _min(
_currentCollateral - (_currentDebt - flashloanAmount) * WAD * WAD / _LSTprice / _LTVtarget,
collateralToSell
);
}
bytes memory data = abi.encode(Action.LEVERDOWN, collateralToSell, _swapSlippageBPS);
_initFlashLoan(data, flashloanAmount);
}
// ----------------- FLASHLOAN -----------------
function _initFlashLoan(bytes memory _data, uint256 _amount)
internal
{
if (_amount == 0) return;
flashloanActive = true;
if (flashloanProvider == BALANCER) {
address[] memory tokens = new address[](1);
tokens[0] = address(asset);
uint256[] memory amounts = new uint256[](1);
amounts[0] = _amount;
IBalancer(flashloanProvider).flashLoan(address(this), tokens, amounts, _data);
} else {
IMorpho(flashloanProvider).flashLoan(address(asset), _amount, _data);
}
}
// ----------------- FLASHLOAN CALLBACK -----------------
function receiveFlashLoan(
ERC20[] calldata,
uint256[] calldata _amounts,
uint256[] calldata _fees,
bytes calldata _data
) external {
uint256 _amount = _amounts[0];
uint256 _fee = _fees[0];
require(_fee == 0, "flashloan fee");
_handleFlashLoan(_amount, _data);
}
function onMorphoFlashLoan(uint256 _amount, bytes memory _data) external {
_handleFlashLoan(_amount, _data);
}
function _handleFlashLoan(uint256 _amount, bytes memory _data) internal {
require(msg.sender == flashloanProvider && flashloanActive == true);
flashloanActive = false;
(Action action, uint256 _assetAmountInitialOrCollateralToSell, uint256 _swapSlippageBPS) = abi.decode(_data, (Action, uint256, uint256));
if (action == Action.LEVERUP) {
_callbackLeverUp(_amount, _assetAmountInitialOrCollateralToSell);
} else if (action == Action.LEVERDOWN) {
_callbackLeverDown(_amount, _assetAmountInitialOrCollateralToSell, _swapSlippageBPS);
} else if (action == Action.SWITCH) {
_callbackSwitch(_amount);
}
}
function _callbackLeverUp(uint256 _flashloanAmount, uint256 _assetAmountInitial) internal {
_depositCollateral(_swapAssetToLST(_assetAmountInitial + _flashloanAmount));
_borrowAsset(_flashloanAmount);
if (flashloanProvider == BALANCER) {
asset.transfer(address(flashloanProvider), _flashloanAmount);
}
}
function _callbackLeverDown(uint256 _flashloanAmount, uint256 _collateralToSell, uint256 _swapSlippageBPS) internal {
_repayDebt(_flashloanAmount);
_withdrawCollateral(_collateralToSell);
_swapLSTtoAsset(_collateralToSell, _swapSlippageBPS);
uint256 assetBalance = balanceOfAsset();
if (_flashloanAmount > assetBalance) {
unchecked {
_borrowAsset(_flashloanAmount - assetBalance);
}
}
if (flashloanProvider == BALANCER) {
asset.transfer(address(flashloanProvider), _flashloanAmount);
}
}
function _callbackSwitch(uint256 _flashloanAmount) internal {
_repayDebt(_flashloanAmount);
uint256 collateralBalance = balanceOfCollateral();
_withdrawCollateral(collateralBalance);
if (lendingPool == AAVE_PRIME) {
lendingPool = AAVE_CORE;
aToken = AAVE_CORE_ATOKEN;
debtToken = AAVE_CORE_DTOKEN;
} else {
lendingPool = AAVE_PRIME;
aToken = AAVE_PRIME_ATOKEN;
debtToken = AAVE_PRIME_DTOKEN;
}
_initializeLendingPool();
_depositCollateral(collateralBalance);
_borrowAsset(_flashloanAmount);
if (flashloanProvider == BALANCER && _flashloanAmount > 0) {
asset.transfer(address(flashloanProvider), _flashloanAmount);
}
}
function _min(uint256 _a, uint256 _b) internal pure returns (uint256) {
return _a < _b ? _a : _b;
}
// ----------------- BALANCES & LTV: -----------------
function balanceOfAsset() public view returns (uint256) {
return ERC20(asset).balanceOf(address(this));
}
function balanceOfLST() public view returns (uint256){
return ERC20(LST).balanceOf(address(this));
}
function balanceOfCollateral() public view returns (uint256) {
return ERC20(aToken).balanceOf(address(this));
}
function balanceOfDebt() public view returns (uint256) {
return ERC20(debtToken).balanceOf(address(this));
}
function getLTV() public view returns (uint256) {
uint256 currentCollateral = balanceOfCollateral();
if (currentCollateral < COLLATERAL_DUST) return 0;
uint256 currentDebt = balanceOfDebt();
if (currentDebt == 0) return 0;
return currentDebt * WAD * WAD / (currentCollateral * _getLSTprice());
}
function _getLTVwithParams(uint256 _currentCollateral, uint256 _currentDebt, uint256 _LSTprice) internal pure returns (uint256) {
if (_currentCollateral < COLLATERAL_DUST) return 0;
if (_currentDebt == 0) return 0;
return _currentDebt * WAD * WAD / (_currentCollateral * _LSTprice);
}
/*//////////////////////////////////////////////////////////////
MANAGEMENT:
//////////////////////////////////////////////////////////////*/
/// @notice Change if anyone can deposit in or only white listed addresses
function setOpen(bool _open) external onlyManagement {
open = _open;
}
/// @notice Set or update an addresses whitelist status.
function setAllowed(address _address, bool _allowed) external onlyManagement {
allowed[_address] = _allowed;
}
/// @notice Set the Loan-to-Value Targets of the strategy:
/// @param _LTVtarget the target Loan-to-Value the keeper tries to maintain.
/// @param _LTVemergencyLeverDown the Loan-to-Value at which the keeper levers down, ignoring gas.
/// @param _LTVleverDown the Loan-to-Value at which the keeper levers down, respecting gas.
/// @param _LTVleverUp the Loan-to-Value at which the keeper levers up, respecting gas.
function setLTVtargets(
uint256 _LTVtarget,
uint256 _LTVemergencyLeverDown,
uint256 _LTVleverDown,
uint256 _LTVleverUp
) external onlyManagement {
require(
_LTVemergencyLeverDown >= _LTVleverDown &&
_LTVleverDown >= _LTVtarget &&
_LTVtarget >= _LTVleverUp,
"invalid"
);
LTVtarget = _LTVtarget;
LTVemergencyLeverDown = _LTVemergencyLeverDown;
LTVleverDown = _LTVleverDown;
LTVleverUp = _LTVleverUp;
}
/// @notice Lever down the LTV.
/// @param _percentageOfSharesToRedeem The percentage of shares to redeem.
/// @param _swapSlippageBPS The slippage in basis points (BPS) to accept when swapping asset <-> staked asset in liquid staking token (LST).
function leverDown(
uint256 _percentageOfSharesToRedeem,
uint256 _swapSlippageBPS
) external onlyManagement {
_leverDown(_percentageOfSharesToRedeem, _swapSlippageBPS, balanceOfCollateral(), balanceOfDebt(), _getLSTprice(), LTVtarget);
}
/// @notice Set the max base fee for tending to occur at.
function setMaxTendBasefee(uint256 _maxTendBasefee) external onlyManagement {
maxTendBasefee = _maxTendBasefee;
}
/// @notice Set the Swapper through which all swaps are routed.
/// @param _swapper The Swapper to use.
function switchSwapper(Swapper _swapper) external onlyManagement {
swapper = _swapper;
}
/// @notice Set the maximum slippage in basis points (BPS) to accept when swapping asset <-> staked asset in liquid staking token (LST).
/// @param _swapSlippageBPS The slippage in basis points (BPS) to accept when swapping asset <-> staked asset in liquid staking token (LST).
function setSwapSlippageBPS(uint256 _swapSlippageBPS) external onlyManagement {
require(_swapSlippageBPS <= MAX_BPS);
swapSlippageBPS = _swapSlippageBPS;
}
/// @notice Set the UniswapV3 fee pools to choose for swapping between asset, borrowToken (BT) or base (intermediate token for better swaps).
/// @param _token0 The first token of the pair.
/// @param _token1 The second token of the pair.
/// @param _fee The fee for the pool.
function setUniFees(address _token0, address _token1, uint24 _fee) external onlyManagement {
_setUniFees(_token0, _token1, _fee);
}
/// @notice Set the UniswapV3 minimum amount to swap i.e. dust.
/// @param _minAmountToSell The minimum amount to swap.
function setMinAmountToSell(uint256 _minAmountToSell) external onlyManagement {
minAmountToSell = _minAmountToSell;
}
/// @notice Switch the flashloanProvider address.
function switchFlashloanProvider() external onlyManagement {
if (flashloanProvider == BALANCER) {
flashloanProvider = MORPHO;
} else {
flashloanProvider = BALANCER;
}
}
/// @notice Switch the lending pool between AAVE_PRIME and AAVE_CORE.
function switchLendingPool() external onlyManagement {
uint256 flashloanAmount = balanceOfDebt();
if (flashloanAmount == 0) {
_callbackSwitch(0);
return;
}
bytes memory data = abi.encode(Action.SWITCH, 0, 0);
_initFlashLoan(data, flashloanAmount);
}
/// @notice Adjust the LTV manually in an emergency situation.
/// @param _function Choose the function: 0 == deposit, 1 == repay, 2 == withdraw.
/// @param _token Choose the token to use with the selected function.
/// @param _amount Choose the amount of token to use with the selected function.
function emergencyAdjustLTV(uint8 _function, address _token, uint256 _amount) external onlyManagement {
if (_function == 0) {
IPool(lendingPool).supply(_token, _amount, address(this), 0);
} else if (_function == 1) {
IPool(lendingPool).repay(_token, _amount, 2, address(this));
} else if (_function == 2) {
IPool(lendingPool).withdraw(_token, _amount, address(this));
} else {
revert("!function");
}
}
/// @notice Sweep of non-asset ERC20 tokens to management.
/// @param _token The ERC20 token to sweep
function sweep(address _token) external onlyManagement {
require(_token != address(asset) && _token != aToken);
ERC20(_token).safeTransfer(MANAGEMENT, ERC20(_token).balanceOf(address(this)));
}
/*//////////////////////////////////////////////////////////////
EMERGENCY:
//////////////////////////////////////////////////////////////*/
// Emergency adjust LTV
function _emergencyWithdraw(uint256 _percentage) internal override {
_leverDown(_percentage, swapSlippageBPS, balanceOfCollateral(), balanceOfDebt(), _getLSTprice(), LTVtarget);
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"string","name":"_name","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"LTVemergencyLeverDown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LTVleverDown","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LTVleverUp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LTVtarget","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":"","type":"address"}],"name":"allowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"availableDepositLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"availableWithdrawLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"balanceOfLST","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"base","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deployFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_function","type":"uint8"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"emergencyAdjustLTV","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"flashloanProvider","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"freeFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getLTV","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvestAndReport","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lendingPool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_percentageOfSharesToRedeem","type":"uint256"},{"internalType":"uint256","name":"_swapSlippageBPS","type":"uint256"}],"name":"leverDown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxTendBasefee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minAmountToSell","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onMorphoFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"open","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract ERC20[]","name":"","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"_fees","type":"uint256[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"receiveFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bool","name":"_allowed","type":"bool"}],"name":"setAllowed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_LTVtarget","type":"uint256"},{"internalType":"uint256","name":"_LTVemergencyLeverDown","type":"uint256"},{"internalType":"uint256","name":"_LTVleverDown","type":"uint256"},{"internalType":"uint256","name":"_LTVleverUp","type":"uint256"}],"name":"setLTVtargets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxTendBasefee","type":"uint256"}],"name":"setMaxTendBasefee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minAmountToSell","type":"uint256"}],"name":"setMinAmountToSell","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_open","type":"bool"}],"name":"setOpen","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_swapSlippageBPS","type":"uint256"}],"name":"setSwapSlippageBPS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token0","type":"address"},{"internalType":"address","name":"_token1","type":"address"},{"internalType":"uint24","name":"_fee","type":"uint24"}],"name":"setUniFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"shutdownWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapSlippageBPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapper","outputs":[{"internalType":"enum Amplify.Swapper","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"switchFlashloanProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"switchLendingPool","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum Amplify.Swapper","name":"_swapper","type":"uint8"}],"name":"switchSwapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalIdle","type":"uint256"}],"name":"tendThis","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tendTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenizedStrategyAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"uniFees","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60e0604052600180546001600160a01b031990811673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2179091556002805490911673e592427a0aece92de3edee1f18e0157c0586156417905561271062000065670de0b6b3a76400006124b862000b40565b62000071919062000b6c565b6004556127106200008d670de0b6b3a764000061248662000b40565b62000099919062000b6c565b600555612710620000b5670de0b6b3a764000061244062000b40565b620000c1919062000b6c565b600655612710620000dd670de0b6b3a76400006123be62000b40565b620000e9919062000b6c565b6007556101f46008556377359400600955600a80546001600160a81b03191674ba12222222228d8ba445958a75a0704d566bf2c801179055600b80546001600160a01b0319908116734e033931ad43597d96d6bcc25c280717730b58b117909155600c8054821673c035a7cf15375ce2706766804551791ad035e0c2179055600d80549091167391b7d78bf92db564221f6b5aee744d1727d1dd1e179055600f805460ff60a01b1916600160a01b179055348015620001a757600080fd5b50604051620056fe380380620056fe833981016040819052620001ca9162000be4565b6001600160a01b0382166080523060a052604051829082906200023390620001ff908490849033908190819060240162000ce2565b60408051601f198184030181529190526020810180516001600160e01b03908116634b839d7360e11b17909152620004fb16565b505073d377919fa87120584b21279a491f82d5265a139c7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55503360c0526200027b6200058f565b6001600081815581546001600160a01b0319166001600160a01b038516908117909255818152600360209081526040808320600080516020620056de833981519152845282528083208054606462ffffff1991821681179092559484527f4e0c62681f87e6a48bb56176abcc4bb3a586d3ca16272e6059bc99151f41595b90925290912080549092161790556200034573ae7ab96520de3a18e5e111b5eaab095312d7fe84600080516020620056de83398151915260001962000768602090811b6200170f17901c565b62000380734e033931ad43597d96d6bcc25c280717730b58b1600019846001600160a01b03166200076860201b6200170f179092919060201c565b620003be600080516020620056de833981519152734e033931ad43597d96d6bcc25c280717730b58b160001962000768602090811b6200170f17901c565b620003f97387870bca3f3fd6335c3f4ce8392d69350b4fa4e2600019846001600160a01b03166200076860201b6200170f179092919060201c565b62000437600080516020620056de8339815191527387870bca3f3fd6335c3f4ce8392d69350b4fa4e260001962000768602090811b6200170f17901c565b6200047a73ae7ab96520de3a18e5e111b5eaab095312d7fe8473dc24316b9ae028f1497c275eb9192a3ea0f6702260001962000768602090811b6200170f17901c565b620004b8600080516020620056de83398151915273ba12222222228d8ba445958a75a0704d566bf2c860001962000768602090811b6200170f17901c565b620004f373bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb600019846001600160a01b03166200076860201b6200170f179092919060201c565b505062000db6565b606060008073d377919fa87120584b21279a491f82d5265a139c6001600160a01b0316846040516200052e919062000d25565b600060405180830381855af49150503d80600081146200056b576040519150601f19603f3d011682016040523d82523d6000602084013e62000570565b606091505b50915091508162000588576040513d806000833e8082fd5b9392505050565b600b5460408051630150a5d760e21b815290516000926001600160a01b031691630542975c9160048083019260209291908290030181865afa158015620005da573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000600919062000d43565b9050806001600160a01b031663fca513a86040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000641573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000667919062000d43565b600f60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663e860accb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620006cc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620006f2919062000d43565b600e80546001600160a01b0319166001600160a01b03928316179055600b546040516328530a4760e01b8152600160048201529116906328530a4790602401600060405180830381600087803b1580156200074c57600080fd5b505af115801562000761573d6000803e3d6000fd5b5050505050565b801580620007e65750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015620007be573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620007e4919062000d63565b155b6200085e5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b17909152620008b6918591620008bb16565b505050565b600062000917826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200099c60201b62001857179092919060201c565b90508051600014806200093b5750808060200190518101906200093b919062000d7d565b620008b65760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000855565b6060620009ad8484600085620009b5565b949350505050565b60608247101562000a185760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000855565b600080866001600160a01b0316858760405162000a36919062000d25565b60006040518083038185875af1925050503d806000811462000a75576040519150601f19603f3d011682016040523d82523d6000602084013e62000a7a565b606091505b50909250905062000a8e8783838762000a99565b979650505050505050565b6060831562000b0d57825160000362000b05576001600160a01b0385163b62000b055760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000855565b5081620009ad565b620009ad838381511562000b245781518083602001fd5b8060405162461bcd60e51b815260040162000855919062000da1565b808202811582820484141762000b6657634e487b7160e01b600052601160045260246000fd5b92915050565b60008262000b8a57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b038116811462000ba557600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000bdb57818101518382015260200162000bc1565b50506000910152565b6000806040838503121562000bf857600080fd5b825162000c058162000b8f565b60208401519092506001600160401b038082111562000c2357600080fd5b818501915085601f83011262000c3857600080fd5b81518181111562000c4d5762000c4d62000ba8565b604051601f8201601f19908116603f0116810190838211818310171562000c785762000c7862000ba8565b8160405282815288602084870101111562000c9257600080fd5b62000ca583602083016020880162000bbe565b80955050505050509250929050565b6000815180845262000cce81602086016020860162000bbe565b601f01601f19169290920160200192915050565b600060018060a01b03808816835260a0602084015262000d0660a084018862000cb4565b9581166040840152938416606083015250911660809091015292915050565b6000825162000d3981846020870162000bbe565b9190910192915050565b60006020828403121562000d5657600080fd5b8151620005888162000b8f565b60006020828403121562000d7657600080fd5b5051919050565b60006020828403121562000d9057600080fd5b815180151581146200058857600080fd5b60208152600062000588602083018462000cb4565b60805160a05160c05161481862000ec6600039600081816106640152818161095a01526133df015260008181610886015281816109f801528181610a9801528181610b1701528181610c7a01528181610e5801528181610f78015281816110740152818161116e0152818161128d0152818161133d015281816113bc0152818161144701528181611d73015281816121260152612c1e0152600081816108ea015281816112070152818161190f01528181611b58015281816123830152818161245b01528181612587015281816128920152818161295801528181612a08015281816131020152818161324901528181613292015281816132da015281816136df015261383801526148186000f3fe6080604052600436106102765760003560e01c80636687500e1161014f578063cc2d42b5116100c1578063f3ce280a1161007a578063f3ce280a14610784578063f60e8e4e146107d5578063f887ea40146107eb578063fcfff16f1461080b578063fdaff6811461082c578063fde813a8146108515761027d565b8063cc2d42b5146106a6578063cf683c70146106bc578063d19a3bb8146106dc578063d209f7f614610704578063d63a8e1114610724578063f04f2707146107645761027d565b806390cad3051161011357806390cad305146105dc5780639446058c146105fc5780639d7fb70c14610612578063a59a997314610632578063b53f0d0014610652578063c429d383146106865761027d565b80636687500e146105685780636889982c1461057d5780636fdca5e014610592578063797bf343146105b25780638b5ff1af146105c75761027d565b80633d6cb575116101e85780634ed2b8ac116101ac5780634ed2b8ac146104a35780635001f3b5146104b8578063503160d9146104f057806350398528146105105780635d265d3f14610530578063612cbc27146105535761027d565b80633d6cb57514610418578063410a9617146104385780634697f05d1461044e57806346aa2f121461046e57806349317f1d1461048e5761027d565b80631eab62a91161023a5780631eab62a9146103665780632b3297f91461037c5780632d49be91146103a35780632e3ecf2c146103c357806331f57072146103e3578063392f7a70146104035761027d565b806301681a62146102c557806304bd4629146102e557806309226cb91461031a5780631814436714610330578063199df725146103465761027d565b3661027d57005b34801561028957600080fd5b5073d377919fa87120584b21279a491f82d5265a139c3660008037600080366000845af43d6000803e8080156102be573d6000f35b3d6000fd5b005b3480156102d157600080fd5b506102c36102e0366004613e7a565b610871565b3480156102f157600080fd5b50610307610300366004613e7a565b5060001990565b6040519081526020015b60405180910390f35b34801561032657600080fd5b5061030760075481565b34801561033c57600080fd5b5061030760005481565b34801561035257600080fd5b506102c3610361366004613e97565b6109e3565b34801561037257600080fd5b5061030760085481565b34801561038857600080fd5b50600a546103969060ff1681565b6040516103119190613eed565b3480156103af57600080fd5b506102c36103be366004613f00565b610a83565b3480156103cf57600080fd5b506102c36103de366004613f19565b610b02565b3480156103ef57600080fd5b506102c36103fe366004613fb3565b610bd7565b34801561040f57600080fd5b50610307610be1565b34801561042457600080fd5b506102c3610433366004613f00565b610c54565b34801561044457600080fd5b5061030760045481565b34801561045a57600080fd5b506102c3610469366004614060565b610c65565b34801561047a57600080fd5b50610307610489366004613e7a565b610d07565b34801561049a57600080fd5b50610307610da5565b3480156104af57600080fd5b50610307610db7565b3480156104c457600080fd5b506001546104d8906001600160a01b031681565b6040516001600160a01b039091168152602001610311565b3480156104fc57600080fd5b506102c361050b366004613f00565b610e32565b34801561051c57600080fd5b506102c361052b366004614099565b610e43565b34801561053c57600080fd5b50610545610f25565b60405161031192919061411b565b34801561055f57600080fd5b506102c3610f63565b34801561057457600080fd5b5061030761102e565b34801561058957600080fd5b506102c361105f565b34801561059e57600080fd5b506102c36105ad366004614136565b611159565b3480156105be57600080fd5b506103076111ef565b3480156105d357600080fd5b5061030761123e565b3480156105e857600080fd5b506102c36105f7366004614160565b611278565b34801561060857600080fd5b5061030760065481565b34801561061e57600080fd5b506102c361062d366004613f00565b611317565b34801561063e57600080fd5b50600b546104d8906001600160a01b031681565b34801561065e57600080fd5b506104d87f000000000000000000000000000000000000000000000000000000000000000081565b34801561069257600080fd5b506102c36106a1366004613f00565b611328565b3480156106b257600080fd5b5061030760055481565b3480156106c857600080fd5b506102c36106d7366004613f00565b6113a7565b3480156106e857600080fd5b506104d873d377919fa87120584b21279a491f82d5265a139c81565b34801561071057600080fd5b506102c361071f36600461417d565b611432565b34801561073057600080fd5b5061075461073f366004613e7a565b60106020526000908152604090205460ff1681565b6040519015158152602001610311565b34801561077057600080fd5b506102c361077f366004614210565b611636565b34801561079057600080fd5b506107c161079f366004614301565b600360209081526000928352604080842090915290825290205462ffffff1681565b60405162ffffff9091168152602001610311565b3480156107e157600080fd5b5061030760095481565b3480156107f757600080fd5b506002546104d8906001600160a01b031681565b34801561081757600080fd5b50600f5461075490600160a01b900460ff1681565b34801561083857600080fd5b50600a546104d89061010090046001600160a01b031681565b34801561085d57600080fd5b506102c361086c366004613f00565b6116fe565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b1580156108d057600080fd5b505afa1580156108e4573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316141580156109385750600c546001600160a01b03828116911614155b61094157600080fd5b6040516370a0823160e01b81523060048201526109e0907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b038416906370a0823190602401602060405180830381865afa1580156109ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cf919061432f565b6001600160a01b0384169190611870565b50565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610a4257600080fd5b505afa158015610a56573d6000803e3d6000fd5b50505050610a7f8282610a6761102e565b610a6f610be1565b610a776118a0565b600654611a13565b5050565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610ae257600080fd5b505afa158015610af6573d6000803e3d6000fd5b50505060009190915550565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610b6157600080fd5b505afa158015610b75573d6000803e3d6000fd5b5050506001600160a01b0380851660008181526003602081815260408084209589168452948152848320805462ffffff1990811662ffffff8a16908117909255928252858420948452939052929020805490921617905550505050565b505050565b610a7f8282611c67565b600d546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a08231906024015b602060405180830381865afa158015610c2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4f919061432f565b905090565b610c5c611d38565b6109e081611d6f565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610cc457600080fd5b505afa158015610cd8573d6000803e3d6000fd5b505050506001600160a01b03919091166000908152601060205260409020805460ff1916911515919091179055565b600f54600090600160a01b900460ff16158015610d3d57506001600160a01b03821660009081526010602052604090205460ff16155b15610d4a57506000919050565b6000610d546118a0565b670de0b6b3a7640000610d65611ee4565b610d6f919061435e565b610d799190614375565b9050670de0b6b3a7640000811115610d9c57670de0b6b3a763ffff190192915050565b50600092915050565b6000610daf611d38565b610c4f612030565b600080610dc261102e565b9050600a811015610dd557600091505090565b6000610ddf610be1565b905080600003610df25760009250505090565b610dfa6118a0565b610e04908361435e565b670de0b6b3a7640000610e17818461435e565b610e21919061435e565b610e2b9190614375565b9250505090565b610e3a611d38565b6109e08161209d565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610ea257600080fd5b505afa158015610eb6573d6000803e3d6000fd5b50505050818310158015610eca5750838210155b8015610ed65750808410155b610f115760405162461bcd60e51b81526020600482015260076024820152661a5b9d985b1a5960ca1b60448201526064015b60405180910390fd5b600693909355600491909155600555600755565b60006060610f316120ae565b6040805160048152602481019091526020810180516001600160e01b031663440368a360e01b17905290939092509050565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610fc257600080fd5b505afa158015610fd6573d6000803e3d6000fd5b505050506000610fe4610be1565b905080600003610ff8576109e060006121eb565b6000600260008060405160200161101193929190614397565b6040516020818303038152906040529050610a7f81836123f1565b565b600c546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401610c0e565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b1580156110be57600080fd5b505afa1580156110d2573d6000803e3d6000fd5b5050600a5473ba12222222228d8ba445958a75a0704d566bf2c7196101009091046001600160a01b031601915061112f905057600a8054610100600160a81b03191674bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb00179055565b600a8054610100600160a81b03191674ba12222222228d8ba445958a75a0704d566bf2c800179055565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b1580156111b857600080fd5b505afa1580156111cc573d6000803e3d6000fd5b5050600f8054931515600160a01b0260ff60a01b19909416939093179092555050565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401610c0e565b6040516370a0823160e01b8152306004820152600090737f39c581f595b53c5cb19bd0b3f8da6c935e2ca0906370a0823190602401610c0e565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b1580156112d757600080fd5b505afa1580156112eb573d6000803e3d6000fd5b5050600a805484935090915060ff1916600183600281111561130f5761130f613eb9565b021790555050565b61131f611d38565b6109e0816125e1565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561138757600080fd5b505afa15801561139b573d6000803e3d6000fd5b50505060099190915550565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561140657600080fd5b505afa15801561141a573d6000803e3d6000fd5b5050505061271081111561142d57600080fd5b600855565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561149157600080fd5b505afa1580156114a5573d6000803e3d6000fd5b505050508260ff1660000361152257600b5460405163617ba03760e01b81526001600160a01b039091169063617ba037906114eb908590859030906000906004016143bc565b600060405180830381600087803b15801561150557600080fd5b505af1158015611519573d6000803e3d6000fd5b50505050505050565b8260ff166001036115b857600b5460405163573ade8160e01b81526001600160a01b03848116600483015260248201849052600260448301523060648301529091169063573ade81906084015b6020604051808303816000875af115801561158e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b2919061432f565b50505050565b8260ff1660020361160257600b54604051631a4ca37b60e21b81526001600160a01b03848116600483015260248201849052306044830152909116906369328dec9060640161156f565b60405162461bcd60e51b815260206004820152600960248201526810b33ab731ba34b7b760b91b6044820152606401610f08565b60008686600081811061164b5761164b6143e9565b905060200201359050600085856000818110611669576116696143e9565b905060200201359050806000146116b25760405162461bcd60e51b815260206004820152600d60248201526c666c6173686c6f616e2066656560981b6044820152606401610f08565b6116f28285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611c6792505050565b50505050505050505050565b611706611d38565b6109e0816125e9565b8015806117895750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611763573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611787919061432f565b155b6117f45760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610f08565b6040516001600160a01b038316602482015260448101829052610bd290849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526125f8565b606061186684846000856126cd565b90505b9392505050565b6040516001600160a01b038316602482015260448101829052610bd290849063a9059cbb60e01b90606401611820565b60408051600280825260608201835260009283929190602083019080368337019050509050737f39c581f595b53c5cb19bd0b3f8da6c935e2ca0816000815181106118ed576118ed6143e9565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000000000000000000000000000000000000000000081600181518110611941576119416143e9565b6001600160a01b039283166020918202929092010152600f54604051634e91ecf960e11b81526000929190911690639d23d9f290611983908590600401614443565b600060405180830381865afa1580156119a0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119c89190810190614456565b9050806001815181106119dd576119dd6143e9565b6020026020010151816000815181106119f8576119f86143e9565b6020026020010151670de0b6b3a7640000610e21919061435e565b600a8410611c5f576000611a288585856127aa565b905060008088600003611aa957611a4784670de0b6b3a76400006144fc565b611a5984670de0b6b3a76400006144fc565b611a63908961435e565b611a6d9190614375565b9150670de0b6b3a76400008085611a84888661435e565b611a8e919061435e565b611a989190614375565b611aa29190614375565b9050611b10565b611abb670de0b6b3a76400008a6127fe565b9850670de0b6b3a7640000611ad08a826144fc565b611ada908961435e565b611ae49190614375565b9150670de0b6b3a7640000611af98a826144fc565b611b03908861435e565b611b0d9190614375565b90505b6000611b1c83896144fc565b90506000611b2a83896144fc565b600a546040516370a0823160e01b81526101009091046001600160a01b0390811660048301529192506000917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611b9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc3919061432f565b905081811015611c2457905080611c218789670de0b6b3a764000080611be9868f6144fc565b611bf3919061435e565b611bfd919061435e565b611c079190614375565b611c119190614375565b611c1b908c6144fc565b846127fe565b92505b60006001848d604051602001611c3c9392919061450f565b6040516020818303038152906040529050611c5781846123f1565b505050505050505b505050505050565b600a5461010090046001600160a01b031633148015611c8d575060115460ff1615156001145b611c9657600080fd5b6011805460ff19169055805160009081908190611cbc9085016020908101908601614530565b919450925090506000836002811115611cd757611cd7613eb9565b03611ceb57611ce68583612818565b611d31565b6001836002811115611cff57611cff613eb9565b03611d0f57611ce68583836128c1565b6002836002811115611d2357611d23613eb9565b03611d3157611d31856121eb565b5050505050565b33301461102c5760405162461bcd60e51b815260206004820152600560248201526410b9b2b63360d91b6044820152606401610f08565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df3919061432f565b90506000611dff6111ef565b611e0990836144fc565b905060008115611e335781611e2685670de0b6b3a764000061435e565b611e309190614375565b90505b8015611e4857611e4881612710610a6761102e565b6000611e526111ef565b905084811115611e6757611e678582036129c5565b6005611e71610be1565b1115611d3157600454611e82610db7565b10611d315760405162461bcd60e51b815260206004820152602c60248201527f4c545620697320686967682c207761697420666f72206b65657065722072656260448201526b185b185b98d948199a5c9cdd60a21b6064820152608401610f08565b600e546040516308df7cab60e31b8152737f39c581f595b53c5cb19bd0b3f8da6c935e2ca0600482015260009182916001600160a01b03909116906346fbe558906024016040805180830381865afa158015611f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f689190614567565b915060009050611f80670de0b6b3a76400008361435e565b90506000600c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ffb919061432f565b90508161200f66016bcc41e900008361458b565b1061201e576000935050505090565b66016bcc41e8ffff1991030192915050565b600061203a612a93565b612042610be1565b670de0b6b3a76400006120536118a0565b61205b61102e565b61206361123e565b61206d919061458b565b612077919061435e565b6120819190614375565b6120896111ef565b612093919061458b565b610c4f91906144fc565b6109e06120a982612d2d565b612d56565b6000806120b9610db7565b905060045481106120cc57600191505090565b60095448106120dd57600091505090565b60055481106120ee57600191505090565b60006120f8611ee4565b9050600a811161210b5760009250505090565b600a61211561123e565b11156121245760019250505090565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa158015612182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121a6919061459e565b156121b45760009250505090565b600754821080156121cc5750600a6121ca61102e565b115b156121e257670de0b6b3a7640000111592915050565b60009250505090565b6121f4816129c5565b60006121fe61102e565b905061220981612dfa565b600b546001600160a01b0316734e033931ad43597d96d6bcc25c280717730b58b0190161229b57600b80546001600160a01b03199081167387870bca3f3fd6335c3f4ce8392d69350b4fa4e217909155600c80548216730b925ed163218f6662a35e0f0371ac234f9e9371179055600d805490911673ea51d7853eefb32b6ee06b1c12e6dcca88be0ffe179055612302565b600b80546001600160a01b0319908116734e033931ad43597d96d6bcc25c280717730b58b117909155600c8054821673c035a7cf15375ce2706766804551791ad035e0c2179055600d80549091167391b7d78bf92db564221f6b5aee744d1727d1dd1e1790555b61230a612e70565b61231381612d56565b61231c8261300e565b600a5461010090046001600160a01b031673ba12222222228d8ba445958a75a0704d566bf2c814801561234f5750600082115b15610a7f57600a5460405163a9059cbb60e01b81526101009091046001600160a01b039081166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044015b6020604051808303816000875af11580156123cd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd2919061459e565b806000036123fd575050565b6011805460ff19166001179055600a5473ba12222222228d8ba445958a75a0704d566bf2c7196101009091046001600160a01b03160161255b57604080516001808252818301909252600091602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061248d5761248d6143e9565b6001600160a01b03929092166020928302919091019091015260408051600180825281830190925260009181602001602082028036833701905050905082816000815181106124de576124de6143e9565b6020908102919091010152600a54604051632e1c224f60e11b81526101009091046001600160a01b031690635c38449e90612523903090869086908a906004016145bb565b600060405180830381600087803b15801561253d57600080fd5b505af1158015612551573d6000803e3d6000fd5b5050505050505050565b600a5460405163701195a160e11b81526101009091046001600160a01b03169063e0232b42906125b3907f00000000000000000000000000000000000000000000000000000000000000009085908790600401614634565b600060405180830381600087803b1580156125cd57600080fd5b505af1158015611c5f573d6000803e3d6000fd5b6109e0612a93565b6109e081600854610a6761102e565b600061264d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166118579092919063ffffffff16565b905080516000148061266e57508080602001905181019061266e919061459e565b610bd25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610f08565b60608247101561272e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610f08565b600080866001600160a01b0316858760405161274a9190614664565b60006040518083038185875af1925050503d8060008114612787576040519150601f19603f3d011682016040523d82523d6000602084013e61278c565b606091505b509150915061279d87838387613156565b925050505b949350505050565b6000600a8410156127bd57506000611869565b826000036127cd57506000611869565b6127d7828561435e565b670de0b6b3a76400006127ea818661435e565b6127f4919061435e565b6118669190614375565b600081831061280d578161280f565b825b90505b92915050565b61282d6120a9612828848461458b565b612d2d565b6128368261300e565b600a5473ba12222222228d8ba445958a75a0704d566bf2c7196101009091046001600160a01b031601610a7f57600a5460405163a9059cbb60e01b81526101009091046001600160a01b039081166004830152602482018490527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016123ae565b6128ca836129c5565b6128d382612dfa565b6128dd82826131cf565b60006128e76111ef565b9050808411156128fc576128fc81850361300e565b600a5473ba12222222228d8ba445958a75a0704d566bf2c7196101009091046001600160a01b0316016115b257600a5460405163a9059cbb60e01b81526101009091046001600160a01b039081166004830152602482018690527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af11580156129a1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d31919061459e565b806000036129d05750565b6129e1816129dc610be1565b6127fe565b9050806000036129ee5750565b600b5460405163573ade8160e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260248201849052600260448301523060648301529091169063573ade81906084015b6020604051808303816000875af1158015612a6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7f919061432f565b6000612a9d6111ef565b90506000808215612ab357612ab1836132c1565b505b612abb61123e565b9250600a831115612b6b57612ace611ee4565b915060019050600a821115612b6b57612ae783836127fe565b600b5460405163617ba03760e01b81529194506001600160a01b03169063617ba03790612b3390737f39c581f595b53c5cb19bd0b3f8da6c935e2ca090879030906000906004016143bc565b600060405180830381600087803b158015612b4d57600080fd5b505af1158015612b61573d6000803e3d6000fd5b5050505082820391505b6000612b7561102e565b90506000612b81610be1565b90506000612b8d6118a0565b90506000612b9c8484846127aa565b600554909150808210612c1c57612bbc6000600854878787600654611a13565b6005612bc6610be1565b1115612c175781612bd5610db7565b10612c175760405162461bcd60e51b81526020600482015260126024820152716c6576657220646f776e206661696c75726560701b6044820152606401610f08565b612551565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9e919061459e565b612551576007548210156125515785612cbc57612cb9611ee4565b96505b600a87111561255157612cd4600654888787876135a7565b6005612cde610be1565b11156125515780612ced610db7565b106125515760405162461bcd60e51b815260206004820152601060248201526f6c65766572207570206661696c75726560801b6044820152606401610f08565b6000612d3b826129dc6111ef565b915081600003612d4d57506000919050565b612812826132c1565b600a811015612d625750565b612d73612d6d61123e565b826127fe565b9050600a811015612d815750565b600b5460405163617ba03760e01b81526001600160a01b039091169063617ba03790612dcc90737f39c581f595b53c5cb19bd0b3f8da6c935e2ca090859030906000906004016143bc565b600060405180830381600087803b158015612de657600080fd5b505af1158015611d31573d6000803e3d6000fd5b600a811015612e065750565b612e11612d6d61102e565b9050600a811015612e1f5750565b600b54604051631a4ca37b60e21b8152737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06004820152602481018390523060448201526001600160a01b03909116906369328dec90606401612a50565b600b5460408051630150a5d760e21b815290516000926001600160a01b031691630542975c9160048083019260209291908290030181865afa158015612eba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ede9190614680565b9050806001600160a01b031663fca513a86040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f429190614680565b600f60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663e860accb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fca9190614680565b600e80546001600160a01b0319166001600160a01b03928316179055600b546040516328530a4760e01b8152600160048201529116906328530a4790602401612dcc565b806000036130195750565b600b54604051635a3b74b960e01b8152737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06004820152600160248201526001600160a01b03909116908190635a3b74b990604401600060405180830381600087803b15801561307b57600080fd5b505af115801561308f573d6000803e3d6000fd5b50506040516328530a4760e01b8152600160048201526001600160a01b03841692506328530a479150602401600060405180830381600087803b1580156130d557600080fd5b505af11580156130e9573d6000803e3d6000fd5b505060405163a415bcad60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301526024820186905260026044830152600060648301523060848301528416925063a415bcad915060a4016125b3565b606083156131c55782516000036131be576001600160a01b0385163b6131be5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610f08565b50816127a2565b6127a2838361378c565b6131db826129dc61123e565b9150816000036131e9575050565b6001600a5460ff16600281111561320257613202613eb9565b0361321157610a7f82826137b6565b6002600a5460ff16600281111561322a5761322a613eb9565b0361327857610bd2737f39c581f595b53c5cb19bd0b3f8da6c935e2ca07f000000000000000000000000000000000000000000000000000000000000000084613273868661392b565b613984565b610bd2737f39c581f595b53c5cb19bd0b3f8da6c935e2ca07f0000000000000000000000000000000000000000000000000000000000000000846132bc868661392b565b613afe565b604051632e1a7d4d60e01b8152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561332657600080fd5b505af115801561333a573d6000803e3d6000fd5b5050604051635e0d443f60e01b815260006004820152600160248201526044810185905284925073dc24316b9ae028f1497c275eb9192a3ea0f670229150635e0d443f90606401602060405180830381865afa15801561339e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133c2919061432f565b10156134e05760405163a1903eab60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016600482015273ae7ab96520de3a18e5e111b5eaab095312d7fe849063a1903eab90849060240160206040518083038185885af1158015613443573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613468919061432f565b50604051630ea598cb60e41b815260048101839052737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063ea598cb0906024015b6020604051808303816000875af11580156134bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612812919061432f565b604051630f7c084960e21b815260006004820152600160248201526044810183905260648101839052737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063ea598cb09073dc24316b9ae028f1497c275eb9192a3ea0f6702290633df0212490869060840160206040518083038185885af1158015613564573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613589919061432f565b6040518263ffffffff1660e01b815260040161349d91815260200190565b60006135b48484846127aa565b905060006135c06111ef565b90506000670de0b6b3a76400006135d7858861435e565b6135e19190614375565b905060006135f789670de0b6b3a76400006144fc565b670de0b6b3a76400008061360b87826144fc565b613615908661435e565b61361f9190614375565b613629908661458b565b613633919061435e565b61363d9190614375565b905061366a81670de0b6b3a7640000613656888c61435e565b6136609190614375565b6129dc908561458b565b9050600a81101561367e5750505050611d31565b6000613688610be1565b670de0b6b3a764000061369b8c8561435e565b6136a59190614375565b6136af91906144fc565b600a546040516370a0823160e01b81526001600160a01b036101009092048216600482015291925061374a9183917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015613726573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129dc919061432f565b90506000808560006040516020016137649392919061469d565b604051602081830303815290604052905061377f81836123f1565b5050505050505050505050565b81511561379c5781518083602001fd5b8060405162461bcd60e51b8152600401610f0891906146c1565b604051636f074d1f60e11b815260048101839052737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063de0e9a3e906024016020604051808303816000875af1158015613808573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061382c919061432f565b91506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d0e30db073dc24316b9ae028f1497c275eb9192a3ea0f67022633df0212460016000876138868189613daa565b6040516001600160e01b031960e087901b168152600f94850b60048201529290930b6024830152604482015260648101919091526084016020604051808303816000875af11580156138dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613900919061432f565b6040518263ffffffff1660e01b81526004016000604051808303818588803b15801561150557600080fd5b6000612710820361393e57506000612812565b612710670de0b6b3a764000061395484836144fc565b61395c6118a0565b613966908761435e565b613970919061435e565b61397a9190614375565b61280f9190614375565b6040805160c08101825260008082526020820181905291810182905260608082018390526080820183905260a08201527393d199263632a4ef4bb438f1feb99e57b4b5f0bd6001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a2a919061432f565b8152600060208083018290526001600160a01b03888116604080860191909152908816606080860191909152608080860189905282519081018352908101939093523080845260019284019290925282810191909152516352bbbe2960e01b815273ba12222222228d8ba445958a75a0704d566bf2c8906352bbbe2990613abb9085908590899042906004016146d4565b6020604051808303816000875af1158015613ada573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279d919061432f565b60008215801590613b1157506000548310155b156127a257600254613b2d906001600160a01b03168685613dc3565b6001546001600160a01b0386811691161480613b5657506001546001600160a01b038581169116145b15613c705760408051610100810182526001600160a01b0387811680835287821660208085018281526000938452600382528684209284529190528482205462ffffff9081168587019081523060608701908152426080880190815260a088018c815260c089018c815260e08a019788526002549a5163414bf38960e01b81528a518a16600482015296518916602488015293519094166044860152905186166064850152516084840152905160a48301525160c48201529051821660e48201529192169063414bf38990610104016020604051808303816000875af1158015613c44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c68919061432f565b9150506127a2565b6001600160a01b0385811660009081526003602081815260408084206001548087168652908352818520549383528185208a8716865283529381902054815160608c811b6bffffffffffffffffffffffff199081169583019590955260e895861b6001600160e81b0319908116603484015296811b851660378301529190941b909416604b8401529288901b16604e8201528151604281830301815260025461010283018452606283018281523060828501524260a285015260c2840189905260e2909301879052925163c04b8d5960e01b81529093929092169163c04b8d5991613d5d9160040161478a565b6020604051808303816000875af1158015613d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613da0919061432f565b9695505050505050565b6000612710613db983826144fc565b61397a908561435e565b604051636eb1769f60e11b81523060048201526001600160a01b03848116602483015282919084169063dd62ed3e90604401602060405180830381865afa158015613e12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e36919061432f565b1015610bd257613e516001600160a01b03831684600061170f565b610bd26001600160a01b038316848361170f565b6001600160a01b03811681146109e057600080fd5b600060208284031215613e8c57600080fd5b813561186981613e65565b60008060408385031215613eaa57600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b600381106109e057634e487b7160e01b600052602160045260246000fd5b60208101613efa83613ecf565b91905290565b600060208284031215613f1257600080fd5b5035919050565b600080600060608486031215613f2e57600080fd5b8335613f3981613e65565b92506020840135613f4981613e65565b9150604084013562ffffff81168114613f6157600080fd5b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613fab57613fab613f6c565b604052919050565b60008060408385031215613fc657600080fd5b8235915060208084013567ffffffffffffffff80821115613fe657600080fd5b818601915086601f830112613ffa57600080fd5b81358181111561400c5761400c613f6c565b61401e601f8201601f19168501613f82565b9150808252878482850101111561403457600080fd5b80848401858401376000848284010152508093505050509250929050565b80151581146109e057600080fd5b6000806040838503121561407357600080fd5b823561407e81613e65565b9150602083013561408e81614052565b809150509250929050565b600080600080608085870312156140af57600080fd5b5050823594602084013594506040840135936060013592509050565b60005b838110156140e65781810151838201526020016140ce565b50506000910152565b600081518084526141078160208601602086016140cb565b601f01601f19169290920160200192915050565b821515815260406020820152600061186660408301846140ef565b60006020828403121561414857600080fd5b813561186981614052565b600381106109e057600080fd5b60006020828403121561417257600080fd5b813561186981614153565b60008060006060848603121561419257600080fd5b833560ff811681146141a357600080fd5b925060208401356141b381613e65565b929592945050506040919091013590565b60008083601f8401126141d657600080fd5b50813567ffffffffffffffff8111156141ee57600080fd5b6020830191508360208260051b850101111561420957600080fd5b9250929050565b6000806000806000806000806080898b03121561422c57600080fd5b883567ffffffffffffffff8082111561424457600080fd5b6142508c838d016141c4565b909a50985060208b013591508082111561426957600080fd5b6142758c838d016141c4565b909850965060408b013591508082111561428e57600080fd5b61429a8c838d016141c4565b909650945060608b01359150808211156142b357600080fd5b818b0191508b601f8301126142c757600080fd5b8135818111156142d657600080fd5b8c60208285010111156142e857600080fd5b6020830194508093505050509295985092959890939650565b6000806040838503121561431457600080fd5b823561431f81613e65565b9150602083013561408e81613e65565b60006020828403121561434157600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761281257612812614348565b60008261439257634e487b7160e01b600052601260045260246000fd5b500490565b606081016143a485613ecf565b93815260ff9283166020820152911660409091015290565b6001600160a01b03948516815260208101939093529216604082015261ffff909116606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b838110156144385781516001600160a01b031687529582019590820190600101614413565b509495945050505050565b60208152600061280f60208301846143ff565b6000602080838503121561446957600080fd5b825167ffffffffffffffff8082111561448157600080fd5b818501915085601f83011261449557600080fd5b8151818111156144a7576144a7613f6c565b8060051b91506144b8848301613f82565b81815291830184019184810190888411156144d257600080fd5b938501935b838510156144f0578451825293850193908501906144d7565b98975050505050505050565b8181038181111561281257612812614348565b6060810161451c85613ecf565b938152602081019290925260409091015290565b60008060006060848603121561454557600080fd5b835161455081614153565b602085015160409095015190969495509392505050565b6000806040838503121561457a57600080fd5b505080516020909101519092909150565b8082018082111561281257612812614348565b6000602082840312156145b057600080fd5b815161186981614052565b6001600160a01b0385168152608060208083018290526000916145e0908401876143ff565b838103604085015285518082528287019183019060005b81811015614613578351835292840192918401916001016145f7565b5050848103606086015261462781876140ef565b9998505050505050505050565b60018060a01b038416815282602082015260606040820152600061465b60608301846140ef565b95945050505050565b600082516146768184602087016140cb565b9190910192915050565b60006020828403121561469257600080fd5b815161186981613e65565b606081016146aa85613ecf565b938152602081019290925260ff1660409091015290565b60208152600061280f60208301846140ef565b60e0808252855190820152602085015160ff1661010082015260408501516001600160a01b03908116610120830152606086015116610140820152608085015161016082015260a085015160c06101808301526000906147386101a08401826140ef565b915050614778602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b602081526000825160a060208401526147a660c08401826140ef565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a0840152809150509291505056fea264697066735822122071dc190579b21fc2848cf23e8a6392ea2156829e686aa2f6e69cac2d904b0e5264736f6c634300081200330000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000007416d706c69667900000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106102765760003560e01c80636687500e1161014f578063cc2d42b5116100c1578063f3ce280a1161007a578063f3ce280a14610784578063f60e8e4e146107d5578063f887ea40146107eb578063fcfff16f1461080b578063fdaff6811461082c578063fde813a8146108515761027d565b8063cc2d42b5146106a6578063cf683c70146106bc578063d19a3bb8146106dc578063d209f7f614610704578063d63a8e1114610724578063f04f2707146107645761027d565b806390cad3051161011357806390cad305146105dc5780639446058c146105fc5780639d7fb70c14610612578063a59a997314610632578063b53f0d0014610652578063c429d383146106865761027d565b80636687500e146105685780636889982c1461057d5780636fdca5e014610592578063797bf343146105b25780638b5ff1af146105c75761027d565b80633d6cb575116101e85780634ed2b8ac116101ac5780634ed2b8ac146104a35780635001f3b5146104b8578063503160d9146104f057806350398528146105105780635d265d3f14610530578063612cbc27146105535761027d565b80633d6cb57514610418578063410a9617146104385780634697f05d1461044e57806346aa2f121461046e57806349317f1d1461048e5761027d565b80631eab62a91161023a5780631eab62a9146103665780632b3297f91461037c5780632d49be91146103a35780632e3ecf2c146103c357806331f57072146103e3578063392f7a70146104035761027d565b806301681a62146102c557806304bd4629146102e557806309226cb91461031a5780631814436714610330578063199df725146103465761027d565b3661027d57005b34801561028957600080fd5b5073d377919fa87120584b21279a491f82d5265a139c3660008037600080366000845af43d6000803e8080156102be573d6000f35b3d6000fd5b005b3480156102d157600080fd5b506102c36102e0366004613e7a565b610871565b3480156102f157600080fd5b50610307610300366004613e7a565b5060001990565b6040519081526020015b60405180910390f35b34801561032657600080fd5b5061030760075481565b34801561033c57600080fd5b5061030760005481565b34801561035257600080fd5b506102c3610361366004613e97565b6109e3565b34801561037257600080fd5b5061030760085481565b34801561038857600080fd5b50600a546103969060ff1681565b6040516103119190613eed565b3480156103af57600080fd5b506102c36103be366004613f00565b610a83565b3480156103cf57600080fd5b506102c36103de366004613f19565b610b02565b3480156103ef57600080fd5b506102c36103fe366004613fb3565b610bd7565b34801561040f57600080fd5b50610307610be1565b34801561042457600080fd5b506102c3610433366004613f00565b610c54565b34801561044457600080fd5b5061030760045481565b34801561045a57600080fd5b506102c3610469366004614060565b610c65565b34801561047a57600080fd5b50610307610489366004613e7a565b610d07565b34801561049a57600080fd5b50610307610da5565b3480156104af57600080fd5b50610307610db7565b3480156104c457600080fd5b506001546104d8906001600160a01b031681565b6040516001600160a01b039091168152602001610311565b3480156104fc57600080fd5b506102c361050b366004613f00565b610e32565b34801561051c57600080fd5b506102c361052b366004614099565b610e43565b34801561053c57600080fd5b50610545610f25565b60405161031192919061411b565b34801561055f57600080fd5b506102c3610f63565b34801561057457600080fd5b5061030761102e565b34801561058957600080fd5b506102c361105f565b34801561059e57600080fd5b506102c36105ad366004614136565b611159565b3480156105be57600080fd5b506103076111ef565b3480156105d357600080fd5b5061030761123e565b3480156105e857600080fd5b506102c36105f7366004614160565b611278565b34801561060857600080fd5b5061030760065481565b34801561061e57600080fd5b506102c361062d366004613f00565b611317565b34801561063e57600080fd5b50600b546104d8906001600160a01b031681565b34801561065e57600080fd5b506104d87f000000000000000000000000a8592155fd1e5ac7e0c37b86ca541c467fc0c5a781565b34801561069257600080fd5b506102c36106a1366004613f00565b611328565b3480156106b257600080fd5b5061030760055481565b3480156106c857600080fd5b506102c36106d7366004613f00565b6113a7565b3480156106e857600080fd5b506104d873d377919fa87120584b21279a491f82d5265a139c81565b34801561071057600080fd5b506102c361071f36600461417d565b611432565b34801561073057600080fd5b5061075461073f366004613e7a565b60106020526000908152604090205460ff1681565b6040519015158152602001610311565b34801561077057600080fd5b506102c361077f366004614210565b611636565b34801561079057600080fd5b506107c161079f366004614301565b600360209081526000928352604080842090915290825290205462ffffff1681565b60405162ffffff9091168152602001610311565b3480156107e157600080fd5b5061030760095481565b3480156107f757600080fd5b506002546104d8906001600160a01b031681565b34801561081757600080fd5b50600f5461075490600160a01b900460ff1681565b34801561083857600080fd5b50600a546104d89061010090046001600160a01b031681565b34801561085d57600080fd5b506102c361086c366004613f00565b6116fe565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b1580156108d057600080fd5b505afa1580156108e4573d6000803e3d6000fd5b505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316816001600160a01b0316141580156109385750600c546001600160a01b03828116911614155b61094157600080fd5b6040516370a0823160e01b81523060048201526109e0907f000000000000000000000000a8592155fd1e5ac7e0c37b86ca541c467fc0c5a7906001600160a01b038416906370a0823190602401602060405180830381865afa1580156109ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cf919061432f565b6001600160a01b0384169190611870565b50565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b158015610a4257600080fd5b505afa158015610a56573d6000803e3d6000fd5b50505050610a7f8282610a6761102e565b610a6f610be1565b610a776118a0565b600654611a13565b5050565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b158015610ae257600080fd5b505afa158015610af6573d6000803e3d6000fd5b50505060009190915550565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b158015610b6157600080fd5b505afa158015610b75573d6000803e3d6000fd5b5050506001600160a01b0380851660008181526003602081815260408084209589168452948152848320805462ffffff1990811662ffffff8a16908117909255928252858420948452939052929020805490921617905550505050565b505050565b610a7f8282611c67565b600d546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a08231906024015b602060405180830381865afa158015610c2b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4f919061432f565b905090565b610c5c611d38565b6109e081611d6f565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b158015610cc457600080fd5b505afa158015610cd8573d6000803e3d6000fd5b505050506001600160a01b03919091166000908152601060205260409020805460ff1916911515919091179055565b600f54600090600160a01b900460ff16158015610d3d57506001600160a01b03821660009081526010602052604090205460ff16155b15610d4a57506000919050565b6000610d546118a0565b670de0b6b3a7640000610d65611ee4565b610d6f919061435e565b610d799190614375565b9050670de0b6b3a7640000811115610d9c57670de0b6b3a763ffff190192915050565b50600092915050565b6000610daf611d38565b610c4f612030565b600080610dc261102e565b9050600a811015610dd557600091505090565b6000610ddf610be1565b905080600003610df25760009250505090565b610dfa6118a0565b610e04908361435e565b670de0b6b3a7640000610e17818461435e565b610e21919061435e565b610e2b9190614375565b9250505090565b610e3a611d38565b6109e08161209d565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b158015610ea257600080fd5b505afa158015610eb6573d6000803e3d6000fd5b50505050818310158015610eca5750838210155b8015610ed65750808410155b610f115760405162461bcd60e51b81526020600482015260076024820152661a5b9d985b1a5960ca1b60448201526064015b60405180910390fd5b600693909355600491909155600555600755565b60006060610f316120ae565b6040805160048152602481019091526020810180516001600160e01b031663440368a360e01b17905290939092509050565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b158015610fc257600080fd5b505afa158015610fd6573d6000803e3d6000fd5b505050506000610fe4610be1565b905080600003610ff8576109e060006121eb565b6000600260008060405160200161101193929190614397565b6040516020818303038152906040529050610a7f81836123f1565b565b600c546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a0823190602401610c0e565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b1580156110be57600080fd5b505afa1580156110d2573d6000803e3d6000fd5b5050600a5473ba12222222228d8ba445958a75a0704d566bf2c7196101009091046001600160a01b031601915061112f905057600a8054610100600160a81b03191674bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb00179055565b600a8054610100600160a81b03191674ba12222222228d8ba445958a75a0704d566bf2c800179055565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b1580156111b857600080fd5b505afa1580156111cc573d6000803e3d6000fd5b5050600f8054931515600160a01b0260ff60a01b19909416939093179092555050565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316906370a0823190602401610c0e565b6040516370a0823160e01b8152306004820152600090737f39c581f595b53c5cb19bd0b3f8da6c935e2ca0906370a0823190602401610c0e565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b1580156112d757600080fd5b505afa1580156112eb573d6000803e3d6000fd5b5050600a805484935090915060ff1916600183600281111561130f5761130f613eb9565b021790555050565b61131f611d38565b6109e0816125e1565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b15801561138757600080fd5b505afa15801561139b573d6000803e3d6000fd5b50505060099190915550565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b15801561140657600080fd5b505afa15801561141a573d6000803e3d6000fd5b5050505061271081111561142d57600080fd5b600855565b6040516348e4a64960e01b81523360048201527f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b0316906348e4a6499060240160006040518083038186803b15801561149157600080fd5b505afa1580156114a5573d6000803e3d6000fd5b505050508260ff1660000361152257600b5460405163617ba03760e01b81526001600160a01b039091169063617ba037906114eb908590859030906000906004016143bc565b600060405180830381600087803b15801561150557600080fd5b505af1158015611519573d6000803e3d6000fd5b50505050505050565b8260ff166001036115b857600b5460405163573ade8160e01b81526001600160a01b03848116600483015260248201849052600260448301523060648301529091169063573ade81906084015b6020604051808303816000875af115801561158e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115b2919061432f565b50505050565b8260ff1660020361160257600b54604051631a4ca37b60e21b81526001600160a01b03848116600483015260248201849052306044830152909116906369328dec9060640161156f565b60405162461bcd60e51b815260206004820152600960248201526810b33ab731ba34b7b760b91b6044820152606401610f08565b60008686600081811061164b5761164b6143e9565b905060200201359050600085856000818110611669576116696143e9565b905060200201359050806000146116b25760405162461bcd60e51b815260206004820152600d60248201526c666c6173686c6f616e2066656560981b6044820152606401610f08565b6116f28285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611c6792505050565b50505050505050505050565b611706611d38565b6109e0816125e9565b8015806117895750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611763573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611787919061432f565b155b6117f45760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610f08565b6040516001600160a01b038316602482015260448101829052610bd290849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526125f8565b606061186684846000856126cd565b90505b9392505050565b6040516001600160a01b038316602482015260448101829052610bd290849063a9059cbb60e01b90606401611820565b60408051600280825260608201835260009283929190602083019080368337019050509050737f39c581f595b53c5cb19bd0b3f8da6c935e2ca0816000815181106118ed576118ed6143e9565b60200260200101906001600160a01b031690816001600160a01b0316815250507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281600181518110611941576119416143e9565b6001600160a01b039283166020918202929092010152600f54604051634e91ecf960e11b81526000929190911690639d23d9f290611983908590600401614443565b600060405180830381865afa1580156119a0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119c89190810190614456565b9050806001815181106119dd576119dd6143e9565b6020026020010151816000815181106119f8576119f86143e9565b6020026020010151670de0b6b3a7640000610e21919061435e565b600a8410611c5f576000611a288585856127aa565b905060008088600003611aa957611a4784670de0b6b3a76400006144fc565b611a5984670de0b6b3a76400006144fc565b611a63908961435e565b611a6d9190614375565b9150670de0b6b3a76400008085611a84888661435e565b611a8e919061435e565b611a989190614375565b611aa29190614375565b9050611b10565b611abb670de0b6b3a76400008a6127fe565b9850670de0b6b3a7640000611ad08a826144fc565b611ada908961435e565b611ae49190614375565b9150670de0b6b3a7640000611af98a826144fc565b611b03908861435e565b611b0d9190614375565b90505b6000611b1c83896144fc565b90506000611b2a83896144fc565b600a546040516370a0823160e01b81526101009091046001600160a01b0390811660048301529192506000917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906370a0823190602401602060405180830381865afa158015611b9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bc3919061432f565b905081811015611c2457905080611c218789670de0b6b3a764000080611be9868f6144fc565b611bf3919061435e565b611bfd919061435e565b611c079190614375565b611c119190614375565b611c1b908c6144fc565b846127fe565b92505b60006001848d604051602001611c3c9392919061450f565b6040516020818303038152906040529050611c5781846123f1565b505050505050505b505050505050565b600a5461010090046001600160a01b031633148015611c8d575060115460ff1615156001145b611c9657600080fd5b6011805460ff19169055805160009081908190611cbc9085016020908101908601614530565b919450925090506000836002811115611cd757611cd7613eb9565b03611ceb57611ce68583612818565b611d31565b6001836002811115611cff57611cff613eb9565b03611d0f57611ce68583836128c1565b6002836002811115611d2357611d23613eb9565b03611d3157611d31856121eb565b5050505050565b33301461102c5760405162461bcd60e51b815260206004820152600560248201526410b9b2b63360d91b6044820152606401610f08565b60007f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dcf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df3919061432f565b90506000611dff6111ef565b611e0990836144fc565b905060008115611e335781611e2685670de0b6b3a764000061435e565b611e309190614375565b90505b8015611e4857611e4881612710610a6761102e565b6000611e526111ef565b905084811115611e6757611e678582036129c5565b6005611e71610be1565b1115611d3157600454611e82610db7565b10611d315760405162461bcd60e51b815260206004820152602c60248201527f4c545620697320686967682c207761697420666f72206b65657065722072656260448201526b185b185b98d948199a5c9cdd60a21b6064820152608401610f08565b600e546040516308df7cab60e31b8152737f39c581f595b53c5cb19bd0b3f8da6c935e2ca0600482015260009182916001600160a01b03909116906346fbe558906024016040805180830381865afa158015611f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f689190614567565b915060009050611f80670de0b6b3a76400008361435e565b90506000600c60009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ffb919061432f565b90508161200f66016bcc41e900008361458b565b1061201e576000935050505090565b66016bcc41e8ffff1991030192915050565b600061203a612a93565b612042610be1565b670de0b6b3a76400006120536118a0565b61205b61102e565b61206361123e565b61206d919061458b565b612077919061435e565b6120819190614375565b6120896111ef565b612093919061458b565b610c4f91906144fc565b6109e06120a982612d2d565b612d56565b6000806120b9610db7565b905060045481106120cc57600191505090565b60095448106120dd57600091505090565b60055481106120ee57600191505090565b60006120f8611ee4565b9050600a811161210b5760009250505090565b600a61211561123e565b11156121245760019250505090565b7f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa158015612182573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121a6919061459e565b156121b45760009250505090565b600754821080156121cc5750600a6121ca61102e565b115b156121e257670de0b6b3a7640000111592915050565b60009250505090565b6121f4816129c5565b60006121fe61102e565b905061220981612dfa565b600b546001600160a01b0316734e033931ad43597d96d6bcc25c280717730b58b0190161229b57600b80546001600160a01b03199081167387870bca3f3fd6335c3f4ce8392d69350b4fa4e217909155600c80548216730b925ed163218f6662a35e0f0371ac234f9e9371179055600d805490911673ea51d7853eefb32b6ee06b1c12e6dcca88be0ffe179055612302565b600b80546001600160a01b0319908116734e033931ad43597d96d6bcc25c280717730b58b117909155600c8054821673c035a7cf15375ce2706766804551791ad035e0c2179055600d80549091167391b7d78bf92db564221f6b5aee744d1727d1dd1e1790555b61230a612e70565b61231381612d56565b61231c8261300e565b600a5461010090046001600160a01b031673ba12222222228d8ba445958a75a0704d566bf2c814801561234f5750600082115b15610a7f57600a5460405163a9059cbb60e01b81526101009091046001600160a01b039081166004830152602482018490527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169063a9059cbb906044015b6020604051808303816000875af11580156123cd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd2919061459e565b806000036123fd575050565b6011805460ff19166001179055600a5473ba12222222228d8ba445958a75a0704d566bf2c7196101009091046001600160a01b03160161255b57604080516001808252818301909252600091602080830190803683370190505090507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28160008151811061248d5761248d6143e9565b6001600160a01b03929092166020928302919091019091015260408051600180825281830190925260009181602001602082028036833701905050905082816000815181106124de576124de6143e9565b6020908102919091010152600a54604051632e1c224f60e11b81526101009091046001600160a01b031690635c38449e90612523903090869086908a906004016145bb565b600060405180830381600087803b15801561253d57600080fd5b505af1158015612551573d6000803e3d6000fd5b5050505050505050565b600a5460405163701195a160e11b81526101009091046001600160a01b03169063e0232b42906125b3907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29085908790600401614634565b600060405180830381600087803b1580156125cd57600080fd5b505af1158015611c5f573d6000803e3d6000fd5b6109e0612a93565b6109e081600854610a6761102e565b600061264d826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166118579092919063ffffffff16565b905080516000148061266e57508080602001905181019061266e919061459e565b610bd25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610f08565b60608247101561272e5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610f08565b600080866001600160a01b0316858760405161274a9190614664565b60006040518083038185875af1925050503d8060008114612787576040519150601f19603f3d011682016040523d82523d6000602084013e61278c565b606091505b509150915061279d87838387613156565b925050505b949350505050565b6000600a8410156127bd57506000611869565b826000036127cd57506000611869565b6127d7828561435e565b670de0b6b3a76400006127ea818661435e565b6127f4919061435e565b6118669190614375565b600081831061280d578161280f565b825b90505b92915050565b61282d6120a9612828848461458b565b612d2d565b6128368261300e565b600a5473ba12222222228d8ba445958a75a0704d566bf2c7196101009091046001600160a01b031601610a7f57600a5460405163a9059cbb60e01b81526101009091046001600160a01b039081166004830152602482018490527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169063a9059cbb906044016123ae565b6128ca836129c5565b6128d382612dfa565b6128dd82826131cf565b60006128e76111ef565b9050808411156128fc576128fc81850361300e565b600a5473ba12222222228d8ba445958a75a0704d566bf2c7196101009091046001600160a01b0316016115b257600a5460405163a9059cbb60e01b81526101009091046001600160a01b039081166004830152602482018690527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2169063a9059cbb906044016020604051808303816000875af11580156129a1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d31919061459e565b806000036129d05750565b6129e1816129dc610be1565b6127fe565b9050806000036129ee5750565b600b5460405163573ade8160e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc28116600483015260248201849052600260448301523060648301529091169063573ade81906084015b6020604051808303816000875af1158015612a6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a7f919061432f565b6000612a9d6111ef565b90506000808215612ab357612ab1836132c1565b505b612abb61123e565b9250600a831115612b6b57612ace611ee4565b915060019050600a821115612b6b57612ae783836127fe565b600b5460405163617ba03760e01b81529194506001600160a01b03169063617ba03790612b3390737f39c581f595b53c5cb19bd0b3f8da6c935e2ca090879030906000906004016143bc565b600060405180830381600087803b158015612b4d57600080fd5b505af1158015612b61573d6000803e3d6000fd5b5050505082820391505b6000612b7561102e565b90506000612b81610be1565b90506000612b8d6118a0565b90506000612b9c8484846127aa565b600554909150808210612c1c57612bbc6000600854878787600654611a13565b6005612bc6610be1565b1115612c175781612bd5610db7565b10612c175760405162461bcd60e51b81526020600482015260126024820152716c6576657220646f776e206661696c75726560701b6044820152606401610f08565b612551565b7f000000000000000000000000aae409b376882467e517c473ff63ef67db7a60cf6001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9e919061459e565b612551576007548210156125515785612cbc57612cb9611ee4565b96505b600a87111561255157612cd4600654888787876135a7565b6005612cde610be1565b11156125515780612ced610db7565b106125515760405162461bcd60e51b815260206004820152601060248201526f6c65766572207570206661696c75726560801b6044820152606401610f08565b6000612d3b826129dc6111ef565b915081600003612d4d57506000919050565b612812826132c1565b600a811015612d625750565b612d73612d6d61123e565b826127fe565b9050600a811015612d815750565b600b5460405163617ba03760e01b81526001600160a01b039091169063617ba03790612dcc90737f39c581f595b53c5cb19bd0b3f8da6c935e2ca090859030906000906004016143bc565b600060405180830381600087803b158015612de657600080fd5b505af1158015611d31573d6000803e3d6000fd5b600a811015612e065750565b612e11612d6d61102e565b9050600a811015612e1f5750565b600b54604051631a4ca37b60e21b8152737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06004820152602481018390523060448201526001600160a01b03909116906369328dec90606401612a50565b600b5460408051630150a5d760e21b815290516000926001600160a01b031691630542975c9160048083019260209291908290030181865afa158015612eba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ede9190614680565b9050806001600160a01b031663fca513a86040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f429190614680565b600f60006101000a8154816001600160a01b0302191690836001600160a01b03160217905550806001600160a01b031663e860accb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612fa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fca9190614680565b600e80546001600160a01b0319166001600160a01b03928316179055600b546040516328530a4760e01b8152600160048201529116906328530a4790602401612dcc565b806000036130195750565b600b54604051635a3b74b960e01b8152737f39c581f595b53c5cb19bd0b3f8da6c935e2ca06004820152600160248201526001600160a01b03909116908190635a3b74b990604401600060405180830381600087803b15801561307b57600080fd5b505af115801561308f573d6000803e3d6000fd5b50506040516328530a4760e01b8152600160048201526001600160a01b03841692506328530a479150602401600060405180830381600087803b1580156130d557600080fd5b505af11580156130e9573d6000803e3d6000fd5b505060405163a415bcad60e01b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2811660048301526024820186905260026044830152600060648301523060848301528416925063a415bcad915060a4016125b3565b606083156131c55782516000036131be576001600160a01b0385163b6131be5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610f08565b50816127a2565b6127a2838361378c565b6131db826129dc61123e565b9150816000036131e9575050565b6001600a5460ff16600281111561320257613202613eb9565b0361321157610a7f82826137b6565b6002600a5460ff16600281111561322a5761322a613eb9565b0361327857610bd2737f39c581f595b53c5cb19bd0b3f8da6c935e2ca07f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc284613273868661392b565b613984565b610bd2737f39c581f595b53c5cb19bd0b3f8da6c935e2ca07f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2846132bc868661392b565b613afe565b604051632e1a7d4d60e01b8152600481018290526000907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561332657600080fd5b505af115801561333a573d6000803e3d6000fd5b5050604051635e0d443f60e01b815260006004820152600160248201526044810185905284925073dc24316b9ae028f1497c275eb9192a3ea0f670229150635e0d443f90606401602060405180830381865afa15801561339e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133c2919061432f565b10156134e05760405163a1903eab60e01b81526001600160a01b037f000000000000000000000000a8592155fd1e5ac7e0c37b86ca541c467fc0c5a716600482015273ae7ab96520de3a18e5e111b5eaab095312d7fe849063a1903eab90849060240160206040518083038185885af1158015613443573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613468919061432f565b50604051630ea598cb60e41b815260048101839052737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063ea598cb0906024015b6020604051808303816000875af11580156134bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612812919061432f565b604051630f7c084960e21b815260006004820152600160248201526044810183905260648101839052737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063ea598cb09073dc24316b9ae028f1497c275eb9192a3ea0f6702290633df0212490869060840160206040518083038185885af1158015613564573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190613589919061432f565b6040518263ffffffff1660e01b815260040161349d91815260200190565b60006135b48484846127aa565b905060006135c06111ef565b90506000670de0b6b3a76400006135d7858861435e565b6135e19190614375565b905060006135f789670de0b6b3a76400006144fc565b670de0b6b3a76400008061360b87826144fc565b613615908661435e565b61361f9190614375565b613629908661458b565b613633919061435e565b61363d9190614375565b905061366a81670de0b6b3a7640000613656888c61435e565b6136609190614375565b6129dc908561458b565b9050600a81101561367e5750505050611d31565b6000613688610be1565b670de0b6b3a764000061369b8c8561435e565b6136a59190614375565b6136af91906144fc565b600a546040516370a0823160e01b81526001600160a01b036101009092048216600482015291925061374a9183917f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906370a0823190602401602060405180830381865afa158015613726573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129dc919061432f565b90506000808560006040516020016137649392919061469d565b604051602081830303815290604052905061377f81836123f1565b5050505050505050505050565b81511561379c5781518083602001fd5b8060405162461bcd60e51b8152600401610f0891906146c1565b604051636f074d1f60e11b815260048101839052737f39c581f595b53c5cb19bd0b3f8da6c935e2ca09063de0e9a3e906024016020604051808303816000875af1158015613808573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061382c919061432f565b91506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21663d0e30db073dc24316b9ae028f1497c275eb9192a3ea0f67022633df0212460016000876138868189613daa565b6040516001600160e01b031960e087901b168152600f94850b60048201529290930b6024830152604482015260648101919091526084016020604051808303816000875af11580156138dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613900919061432f565b6040518263ffffffff1660e01b81526004016000604051808303818588803b15801561150557600080fd5b6000612710820361393e57506000612812565b612710670de0b6b3a764000061395484836144fc565b61395c6118a0565b613966908761435e565b613970919061435e565b61397a9190614375565b61280f9190614375565b6040805160c08101825260008082526020820181905291810182905260608082018390526080820183905260a08201527393d199263632a4ef4bb438f1feb99e57b4b5f0bd6001600160a01b03166338fff2d06040518163ffffffff1660e01b8152600401602060405180830381865afa158015613a06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a2a919061432f565b8152600060208083018290526001600160a01b03888116604080860191909152908816606080860191909152608080860189905282519081018352908101939093523080845260019284019290925282810191909152516352bbbe2960e01b815273ba12222222228d8ba445958a75a0704d566bf2c8906352bbbe2990613abb9085908590899042906004016146d4565b6020604051808303816000875af1158015613ada573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061279d919061432f565b60008215801590613b1157506000548310155b156127a257600254613b2d906001600160a01b03168685613dc3565b6001546001600160a01b0386811691161480613b5657506001546001600160a01b038581169116145b15613c705760408051610100810182526001600160a01b0387811680835287821660208085018281526000938452600382528684209284529190528482205462ffffff9081168587019081523060608701908152426080880190815260a088018c815260c089018c815260e08a019788526002549a5163414bf38960e01b81528a518a16600482015296518916602488015293519094166044860152905186166064850152516084840152905160a48301525160c48201529051821660e48201529192169063414bf38990610104016020604051808303816000875af1158015613c44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c68919061432f565b9150506127a2565b6001600160a01b0385811660009081526003602081815260408084206001548087168652908352818520549383528185208a8716865283529381902054815160608c811b6bffffffffffffffffffffffff199081169583019590955260e895861b6001600160e81b0319908116603484015296811b851660378301529190941b909416604b8401529288901b16604e8201528151604281830301815260025461010283018452606283018281523060828501524260a285015260c2840189905260e2909301879052925163c04b8d5960e01b81529093929092169163c04b8d5991613d5d9160040161478a565b6020604051808303816000875af1158015613d7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613da0919061432f565b9695505050505050565b6000612710613db983826144fc565b61397a908561435e565b604051636eb1769f60e11b81523060048201526001600160a01b03848116602483015282919084169063dd62ed3e90604401602060405180830381865afa158015613e12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e36919061432f565b1015610bd257613e516001600160a01b03831684600061170f565b610bd26001600160a01b038316848361170f565b6001600160a01b03811681146109e057600080fd5b600060208284031215613e8c57600080fd5b813561186981613e65565b60008060408385031215613eaa57600080fd5b50508035926020909101359150565b634e487b7160e01b600052602160045260246000fd5b600381106109e057634e487b7160e01b600052602160045260246000fd5b60208101613efa83613ecf565b91905290565b600060208284031215613f1257600080fd5b5035919050565b600080600060608486031215613f2e57600080fd5b8335613f3981613e65565b92506020840135613f4981613e65565b9150604084013562ffffff81168114613f6157600080fd5b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613fab57613fab613f6c565b604052919050565b60008060408385031215613fc657600080fd5b8235915060208084013567ffffffffffffffff80821115613fe657600080fd5b818601915086601f830112613ffa57600080fd5b81358181111561400c5761400c613f6c565b61401e601f8201601f19168501613f82565b9150808252878482850101111561403457600080fd5b80848401858401376000848284010152508093505050509250929050565b80151581146109e057600080fd5b6000806040838503121561407357600080fd5b823561407e81613e65565b9150602083013561408e81614052565b809150509250929050565b600080600080608085870312156140af57600080fd5b5050823594602084013594506040840135936060013592509050565b60005b838110156140e65781810151838201526020016140ce565b50506000910152565b600081518084526141078160208601602086016140cb565b601f01601f19169290920160200192915050565b821515815260406020820152600061186660408301846140ef565b60006020828403121561414857600080fd5b813561186981614052565b600381106109e057600080fd5b60006020828403121561417257600080fd5b813561186981614153565b60008060006060848603121561419257600080fd5b833560ff811681146141a357600080fd5b925060208401356141b381613e65565b929592945050506040919091013590565b60008083601f8401126141d657600080fd5b50813567ffffffffffffffff8111156141ee57600080fd5b6020830191508360208260051b850101111561420957600080fd5b9250929050565b6000806000806000806000806080898b03121561422c57600080fd5b883567ffffffffffffffff8082111561424457600080fd5b6142508c838d016141c4565b909a50985060208b013591508082111561426957600080fd5b6142758c838d016141c4565b909850965060408b013591508082111561428e57600080fd5b61429a8c838d016141c4565b909650945060608b01359150808211156142b357600080fd5b818b0191508b601f8301126142c757600080fd5b8135818111156142d657600080fd5b8c60208285010111156142e857600080fd5b6020830194508093505050509295985092959890939650565b6000806040838503121561431457600080fd5b823561431f81613e65565b9150602083013561408e81613e65565b60006020828403121561434157600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141761281257612812614348565b60008261439257634e487b7160e01b600052601260045260246000fd5b500490565b606081016143a485613ecf565b93815260ff9283166020820152911660409091015290565b6001600160a01b03948516815260208101939093529216604082015261ffff909116606082015260800190565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b838110156144385781516001600160a01b031687529582019590820190600101614413565b509495945050505050565b60208152600061280f60208301846143ff565b6000602080838503121561446957600080fd5b825167ffffffffffffffff8082111561448157600080fd5b818501915085601f83011261449557600080fd5b8151818111156144a7576144a7613f6c565b8060051b91506144b8848301613f82565b81815291830184019184810190888411156144d257600080fd5b938501935b838510156144f0578451825293850193908501906144d7565b98975050505050505050565b8181038181111561281257612812614348565b6060810161451c85613ecf565b938152602081019290925260409091015290565b60008060006060848603121561454557600080fd5b835161455081614153565b602085015160409095015190969495509392505050565b6000806040838503121561457a57600080fd5b505080516020909101519092909150565b8082018082111561281257612812614348565b6000602082840312156145b057600080fd5b815161186981614052565b6001600160a01b0385168152608060208083018290526000916145e0908401876143ff565b838103604085015285518082528287019183019060005b81811015614613578351835292840192918401916001016145f7565b5050848103606086015261462781876140ef565b9998505050505050505050565b60018060a01b038416815282602082015260606040820152600061465b60608301846140ef565b95945050505050565b600082516146768184602087016140cb565b9190910192915050565b60006020828403121561469257600080fd5b815161186981613e65565b606081016146aa85613ecf565b938152602081019290925260ff1660409091015290565b60208152600061280f60208301846140ef565b60e0808252855190820152602085015160ff1661010082015260408501516001600160a01b03908116610120830152606086015116610140820152608085015161016082015260a085015160c06101808301526000906147386101a08401826140ef565b915050614778602083018680516001600160a01b039081168352602080830151151590840152604080830151909116908301526060908101511515910152565b60a082019390935260c0015292915050565b602081526000825160a060208401526147a660c08401826140ef565b905060018060a01b0360208501511660408401526040840151606084015260608401516080840152608084015160a0840152809150509291505056fea264697066735822122071dc190579b21fc2848cf23e8a6392ea2156829e686aa2f6e69cac2d904b0e5264736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000007416d706c69667900000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _asset (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [1] : _name (string): Amplify
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [3] : 416d706c69667900000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
90388:28261:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;42581:42:0;58426:14;58175:33;;58407:34;58688:1;58668;58635:14;58615:1;58571:25;58547:5;58516:188;58776:16;58773:1;58770;58755:38;58882:6;58902:68;;;;59021:16;59018:1;59011:27;58902:68;58938:16;58935:1;58928:27;58875:178;;118034:212;;;;;;;;;;-1:-1:-1;118034:212:0;;;;;:::i;:::-;;:::i;51914:149::-;;;;;;;;;;-1:-1:-1;51914:149:0;;;;;:::i;:::-;-1:-1:-1;;;52038:17:0;51914:149;;;;548:25:1;;;536:2;521:18;51914:149:0;;;;;;;;90740:46;;;;;;;;;;;;;;;;82837:30;;;;;;;;;;;;;;;;114494:274;;;;;;;;;;-1:-1:-1;114494:274:0;;;;;:::i;:::-;;:::i;90795:36::-;;;;;;;;;;;;;;;;91407:38;;;;;;;;;;-1:-1:-1;91407:38:0;;;;;;;;;;;;;;;:::i;116252:131::-;;;;;;;;;;-1:-1:-1;116252:131:0;;;;;:::i;:::-;;:::i;115969:145::-;;;;;;;;;;-1:-1:-1;115969:145:0;;;;;:::i;:::-;;:::i;108653:124::-;;;;;;;;;;-1:-1:-1;108653:124:0;;;;;:::i;:::-;;:::i;111888:122::-;;;;;;;;;;;;;:::i;54461:100::-;;;;;;;;;;-1:-1:-1;54461:100:0;;;;;:::i;:::-;;:::i;90569:57::-;;;;;;;;;;;;;;;;113100:124;;;;;;;;;;-1:-1:-1;113100:124:0;;;;;:::i;:::-;;:::i;99471:452::-;;;;;;;;;;-1:-1:-1;99471:452:0;;;;;:::i;:::-;;:::i;55110:117::-;;;;;;;;;;;;;:::i;112018:345::-;;;;;;;;;;;;;:::i;82911:64::-;;;;;;;;;;-1:-1:-1;82911:64:0;;;;-1:-1:-1;;;;;82911:64:0;;;;;;-1:-1:-1;;;;;4091:32:1;;;4073:51;;4061:2;4046:18;82911:64:0;3927:203:1;53877:104:0;;;;;;;;;;-1:-1:-1;53877:104:0;;;;;:::i;:::-;;:::i;113672:551::-;;;;;;;;;;-1:-1:-1;113672:551:0;;;;;:::i;:::-;;:::i;49612:318::-;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;116755:331::-;;;;;;;;;;;;;:::i;111755:125::-;;;;;;;;;;;;;:::i;116446:226::-;;;;;;;;;;;;;:::i;112946:84::-;;;;;;;;;;-1:-1:-1;112946:84:0;;;;;:::i;:::-;;:::i;111506:119::-;;;;;;;;;;;;;:::i;111633:114::-;;;;;;;;;;;;;:::i;115088:102::-;;;;;;;;;;-1:-1:-1;115088:102:0;;;;;:::i;:::-;;:::i;90688:45::-;;;;;;;;;;;;;;;;55780:100;;;;;;;;;;-1:-1:-1;55780:100:0;;;;;:::i;:::-;;:::i;92275:39::-;;;;;;;;;;-1:-1:-1;92275:39:0;;;;-1:-1:-1;;;;;92275:39:0;;;92847:35;;;;;;;;;;;;;;;114839:127;;;;;;;;;;-1:-1:-1;114839:127:0;;;;;:::i;:::-;;:::i;90633:48::-;;;;;;;;;;;;;;;;115486:178;;;;;;;;;;-1:-1:-1;115486:178:0;;;;;:::i;:::-;;:::i;42521:102::-;;;;;;;;;;;;42581:42;42521:102;;117411:503;;;;;;;;;;-1:-1:-1;117411:503:0;;;;;:::i;:::-;;:::i;92537:39::-;;;;;;;;;;-1:-1:-1;92537:39:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;6632:14:1;;6625:22;6607:41;;6595:2;6580:18;92537:39:0;6467:187:1;108301:344:0;;;;;;;;;;-1:-1:-1;108301:344:0;;;;;:::i;:::-;;:::i;83289:61::-;;;;;;;;;;-1:-1:-1;83289:61:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9181:8:1;9169:21;;;9151:40;;9139:2;9124:18;83289:61:0;9007:190:1;90852:35:0;;;;;;;;;;;;;;;;83034:66;;;;;;;;;;-1:-1:-1;83034:66:0;;;;-1:-1:-1;;;;;83034:66:0;;;92507:23;;;;;;;;;;-1:-1:-1;92507:23:0;;;;-1:-1:-1;;;92507:23:0;;;;;;91642:43;;;;;;;;;;-1:-1:-1;91642:43:0;;;;;;;-1:-1:-1;;;;;91642:43:0;;;56409:115;;;;;;;;;;-1:-1:-1;56409:115:0;;;;;:::i;:::-;;:::i;118034:212::-;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;118122:5:::1;-1:-1:-1::0;;;;;118104:24:0::1;:6;-1:-1:-1::0;;;;;118104:24:0::1;;;:44;;;;-1:-1:-1::0;118142:6:0::1;::::0;-1:-1:-1;;;;;118132:16:0;;::::1;118142:6:::0;::::1;118132:16;;118104:44;118096:53;;;::::0;::::1;;118199:38;::::0;-1:-1:-1;;;118199:38:0;;118231:4:::1;118199:38;::::0;::::1;4073:51:1::0;118160:78:0::1;::::0;118187:10:::1;::::0;-1:-1:-1;;;;;118199:23:0;::::1;::::0;::::1;::::0;4046:18:1;;118199:38:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;118160:26:0;::::1;::::0;:78;:26:::1;:78::i;:::-;118034:212:::0;:::o;114494:274::-;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;114636:124:::1;114647:27;114676:16;114694:21;:19;:21::i;:::-;114717:15;:13;:15::i;:::-;114734:14;:12;:14::i;:::-;114750:9;;114636:10;:124::i;:::-;114494:274:::0;;:::o;116252:131::-;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;116341:15:0::1;:34:::0;;;;-1:-1:-1;116252:131:0:o;115969:145::-;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;83788:16:0;;;;;;;:7;:16;;;;;;;;:25;;;;;;;;;;;:32;;-1:-1:-1;;83788:32:0;;;;;;;;;;;;83831:16;;;;;;:25;;;;;;;;;:32;;;;;;;;-1:-1:-1;115969:145:0;;;:::o;116071:35::-:1;115969:145:::0;;;:::o;108653:124::-;108737:32;108754:7;108763:5;108737:16;:32::i;111888:122::-;111967:9;;111961:41;;-1:-1:-1;;;111961:41:0;;111996:4;111961:41;;;4073:51:1;111934:7:0;;-1:-1:-1;;;;;111967:9:0;;111961:26;;4046:18:1;;111961:41:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;111954:48;;111888:122;:::o;54461:100::-;40805:11;:9;:11::i;:::-;54534:19:::1;54545:7;54534:10;:19::i;113100:124::-:0;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;;;;113188:17:0;;;::::1;;::::0;;;:7:::1;:17;::::0;;;;:28;;-1:-1:-1;;113188:28:0::1;::::0;::::1;;::::0;;;::::1;::::0;;113100:124::o;99471:452::-;99573:4;;99548:7;;-1:-1:-1;;;99573:4:0;;;;99572:5;:25;;;;-1:-1:-1;;;;;;99582:15:0;;;;;;:7;:15;;;;;;;;99581:16;99572:25;99568:66;;;-1:-1:-1;99621:1:0;;99471:452;-1:-1:-1;99471:452:0:o;99568:66::-;99644:29;99712:14;:12;:14::i;:::-;92834:4;99676:27;:25;:27::i;:::-;:33;;;;:::i;:::-;:50;;;;:::i;:::-;99644:82;;92834:4;99741:21;:27;99737:179;;;-1:-1:-1;;99821:27:0;;99471:452;-1:-1:-1;;99471:452:0:o;99737:179::-;-1:-1:-1;99903:1:0;;99471:452;-1:-1:-1;;99471:452:0:o;55110:117::-;55173:7;40805:11;:9;:11::i;:::-;55200:19:::1;:17;:19::i;112018:345::-:0;112057:7;112077:25;112105:21;:19;:21::i;:::-;112077:49;;92647:2;112141:17;:35;112137:49;;;112185:1;112178:8;;;112018:345;:::o;112137:49::-;112197:19;112219:15;:13;:15::i;:::-;112197:37;;112249:11;112264:1;112249:16;112245:30;;112274:1;112267:8;;;;112018:345;:::o;112245:30::-;112340:14;:12;:14::i;:::-;112320:34;;:17;:34;:::i;:::-;92834:4;112293:17;92834:4;112293:11;:17;:::i;:::-;:23;;;;:::i;:::-;:62;;;;:::i;:::-;112286:69;;;;112018:345;:::o;53877:104::-;40805:11;:9;:11::i;:::-;53952:21:::1;53965:7;53952:12;:21::i;113672:551::-:0;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;113917:13:::1;113891:22;:39;;:83;;;;;113964:10;113947:13;:27;;113891:83;:125;;;;;114005:11;113991:10;:25;;113891:125;113869:182;;;::::0;-1:-1:-1;;;113869:182:0;;10120:2:1;113869:182:0::1;::::0;::::1;10102:21:1::0;10159:1;10139:18;;;10132:29;-1:-1:-1;;;10177:18:1;;;10170:37;10224:18;;113869:182:0::1;;;;;;;;;114062:9;:22:::0;;;;114095:21:::1;:46:::0;;;;114152:12:::1;:28:::0;114191:10:::1;:24:::0;113672:551::o;49612:318::-;49666:4;49672:12;49774:14;:12;:14::i;:::-;49855:56;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;49855:56:0;-1:-1:-1;;;49855:56:0;;;49697:225;;49855:56;;-1:-1:-1;49612:318:0;-1:-1:-1;49612:318:0:o;116755:331::-;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;116819:23:::1;116845:15;:13;:15::i;:::-;116819:41;;116875:15;116894:1;116875:20:::0;116871:98:::1;;116912:18;116928:1;116912:15;:18::i;116871:98::-;116979:17;117010:13;117025:1;117028::::0;116999:31:::1;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;116979:51;;117041:37;117056:4;117062:15;117041:14;:37::i;41040:1::-;116755:331::o:0;111755:125::-;111840:6;;111834:38;;-1:-1:-1;;;111834:38:0;;111866:4;111834:38;;;4073:51:1;111807:7:0;;-1:-1:-1;;;;;111840:6:0;;111834:23;;4046:18:1;;111834:38:0;3927:203:1;116446:226:0;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;116520:17:0::1;::::0;-1:-1:-1;;116520:17:0::1;::::0;;::::1;-1:-1:-1::0;;;;;116520:17:0::1;:29:::0;;-1:-1:-1;116516:149:0::1;::::0;-1:-1:-1;116516:149:0::1;116566:17;:26:::0;;-1:-1:-1;;;;;;116566:26:0::1;::::0;::::1;::::0;;116755:331::o;116516:149::-:1;116625:17;:28:::0;;-1:-1:-1;;;;;;116625:28:0::1;::::0;::::1;::::0;;116446:226::o;112946:84::-;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;113010:4:0::1;:12:::0;;;::::1;;-1:-1:-1::0;;;113010:12:0::1;-1:-1:-1::0;;;;113010:12:0;;::::1;::::0;;;::::1;::::0;;;-1:-1:-1;;112946:84:0:o;111506:119::-;111580:37;;-1:-1:-1;;;111580:37:0;;111611:4;111580:37;;;4073:51:1;111553:7:0;;111586:5;-1:-1:-1;;;;;111580:22:0;;;;4046:18:1;;111580:37:0;3927:203:1;111633:114:0;111704:35;;-1:-1:-1;;;111704:35:0;;111733:4;111704:35;;;4073:51:1;111678:7:0;;90946:42;;111704:20;;4046:18:1;;111704:35:0;3927:203:1;115088:102:0;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;115164:7:0::1;:18:::0;;115174:8;;-1:-1:-1;115164:7:0;;-1:-1:-1;;;115164:18:0::1;::::0;115174:8;115164:18:::1;::::0;::::1;;;;;;:::i;:::-;;;;;;115088:102:::0;:::o;55780:100::-;40805:11;:9;:11::i;:::-;55855:17:::1;55861:10;55855:5;:17::i;114839:127::-:0;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;114926:14:0::1;:32:::0;;;;-1:-1:-1;114839:127:0:o;115486:178::-;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;92790:5:::1;115583:16;:27;;115575:36;;;::::0;::::1;;115622:15;:34:::0;115486:178::o;117411:503::-;40982:47;;-1:-1:-1;;;40982:47:0;;41018:10;40982:47;;;4073:51:1;40982:17:0;-1:-1:-1;;;;;40982:35:0;;;;4046:18:1;;40982:47:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;117528:9:::1;:14;;117541:1;117528:14:::0;117524:383:::1;;117565:11;::::0;117559:60:::1;::::0;-1:-1:-1;;;117559:60:0;;-1:-1:-1;;;;;117565:11:0;;::::1;::::0;117559:25:::1;::::0;:60:::1;::::0;117585:6;;117593:7;;117610:4:::1;::::0;117565:11:::1;::::0;117559:60:::1;;;:::i;:::-;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;115969:145:::0;;;:::o;117524:383::-:1;117641:9;:14;;117654:1;117641:14:::0;117637:270:::1;;117678:11;::::0;117672:59:::1;::::0;-1:-1:-1;;;117672:59:0;;-1:-1:-1;;;;;11433:15:1;;;117672:59:0::1;::::0;::::1;11415:34:1::0;11465:18;;;11458:34;;;117714:1:0::1;11508:18:1::0;;;11501:34;117725:4:0::1;11551:18:1::0;;;11544:43;117678:11:0;;::::1;::::0;117672:24:::1;::::0;11349:19:1;;117672:59:0::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;115969:145:::0;;;:::o;117637:270::-:1;117753:9;:14;;117766:1;117753:14:::0;117749:158:::1;;117790:11;::::0;117784:59:::1;::::0;-1:-1:-1;;;117784:59:0;;-1:-1:-1;;;;;11856:15:1;;;117784:59:0::1;::::0;::::1;11838:34:1::0;11888:18;;;11881:34;;;117837:4:0::1;11931:18:1::0;;;11924:43;117790:11:0;;::::1;::::0;117784:27:::1;::::0;11773:18:1;;117784:59:0::1;11598:375:1::0;117749:158:0::1;117876:19;::::0;-1:-1:-1;;;117876:19:0;;12180:2:1;117876:19:0::1;::::0;::::1;12162:21:1::0;12219:1;12199:18;;;12192:29;-1:-1:-1;;;12237:18:1;;;12230:39;12286:18;;117876:19:0::1;11978:332:1::0;108301:344:0;108485:15;108503:8;;108512:1;108503:11;;;;;;;:::i;:::-;;;;;;;108485:29;;108525:12;108540:5;;108546:1;108540:8;;;;;;;:::i;:::-;;;;;;;108525:23;;108567:4;108575:1;108567:9;108559:35;;;;-1:-1:-1;;;108559:35:0;;12649:2:1;108559:35:0;;;12631:21:1;12688:2;12668:18;;;12661:30;-1:-1:-1;;;12707:18:1;;;12700:43;12760:18;;108559:35:0;12447:337:1;108559:35:0;108605:32;108622:7;108631:5;;108605:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;108605:16:0;;-1:-1:-1;;;108605:32:0:i;:::-;108474:171;;108301:344;;;;;;;;:::o;56409:115::-;40805:11;:9;:11::i;:::-;56489:27:::1;56508:7;56489:18;:27::i;70323:582::-:0;70653:10;;;70652:62;;-1:-1:-1;70669:39:0;;-1:-1:-1;;;70669:39:0;;70693:4;70669:39;;;13001:34:1;-1:-1:-1;;;;;13071:15:1;;;13051:18;;;13044:43;70669:15:0;;;;;12936:18:1;;70669:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;70652:62;70630:166;;;;-1:-1:-1;;;70630:166:0;;13300:2:1;70630:166:0;;;13282:21:1;13339:2;13319:18;;;13312:30;13378:34;13358:18;;;13351:62;-1:-1:-1;;;13429:18:1;;;13422:52;13491:19;;70630:166:0;13098:418:1;70630:166:0;70834:62;;-1:-1:-1;;;;;13713:32:1;;70834:62:0;;;13695:51:1;13762:18;;;13755:34;;;70807:90:0;;70827:5;;-1:-1:-1;;;70857:22:0;13668:18:1;;70834:62:0;;;;-1:-1:-1;;70834:62:0;;;;;;;;;;;;;;-1:-1:-1;;;;;70834:62:0;-1:-1:-1;;;;;;70834:62:0;;;;;;;;;;70807:19;:90::i;63309:229::-;63446:12;63478:52;63500:6;63508:4;63514:1;63517:12;63478:21;:52::i;:::-;63471:59;;63309:229;;;;;;:::o;69427:177::-;69537:58;;-1:-1:-1;;;;;13713:32:1;;69537:58:0;;;13695:51:1;13762:18;;;13755:34;;;69510:86:0;;69530:5;;-1:-1:-1;;;69560:23:0;13668:18:1;;69537:58:0;13521:274:1;98851:307:0;98943:16;;;98957:1;98943:16;;;;;;;;98898:7;;;;98943:16;98957:1;98943:16;;;;;;;;;;-1:-1:-1;98943:16:0;98917:42;;90946;98970:6;98977:1;98970:9;;;;;;;;:::i;:::-;;;;;;:15;-1:-1:-1;;;;;98970:15:0;;;-1:-1:-1;;;;;98970:15:0;;;;;99016:5;98996:6;99003:1;98996:9;;;;;;;;:::i;:::-;-1:-1:-1;;;;;98996:26:0;;;:9;;;;;;;;;:26;99069:11;;99056:49;;-1:-1:-1;;;99056:49:0;;99033:20;;99069:11;;;;;99056:41;;:49;;99098:6;;99056:49;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;99056:49:0;;;;;;;;;;;;:::i;:::-;99033:72;;99141:6;99148:1;99141:9;;;;;;;;:::i;:::-;;;;;;;99129:6;99136:1;99129:9;;;;;;;;:::i;:::-;;;;;;;92834:4;99123:15;;;;:::i;105851:1716::-;92647:2;106108:18;:36;106160:7;106104:74;106198:11;106212:62;106230:18;106250:12;106264:9;106212:17;:62::i;:::-;106198:76;;106287:24;106322:18;106365:27;106396:1;106365:32;106361:499;;106469:16;106475:10;92834:4;106469:16;:::i;:::-;106455:9;106461:3;92834:4;106455:9;:::i;:::-;106433:32;;:18;:32;:::i;:::-;:53;;;;:::i;:::-;106414:72;-1:-1:-1;92834:4:0;;106545:10;106514:28;106533:9;106414:72;106514:28;:::i;:::-;:41;;;;:::i;:::-;:47;;;;:::i;:::-;:53;;;;:::i;:::-;106501:66;;106361:499;;;106630:38;92834:4;106640:27;106630:4;:38::i;:::-;106600:68;-1:-1:-1;92834:4:0;106724:33;106600:68;92834:4;106724:33;:::i;:::-;106702:56;;:18;:56;:::i;:::-;:62;;;;:::i;:::-;106683:81;-1:-1:-1;92834:4:0;106808:33;106814:27;92834:4;106808:33;:::i;:::-;106792:50;;:12;:50;:::i;:::-;:56;;;;:::i;:::-;106779:69;;106361:499;106880:24;106907:37;106928:16;106907:18;:37;:::i;:::-;106880:64;-1:-1:-1;106955:23:0;106981:25;106996:10;106981:12;:25;:::i;:::-;107078:17;;107054:43;;-1:-1:-1;;;107054:43:0;;107078:17;;;;-1:-1:-1;;;;;107078:17:0;;;107054:43;;;4073:51:1;106955::0;;-1:-1:-1;107027:24:0;;107054:5;:15;;;;4046:18:1;;107054:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;107027:70;;107131:15;107112:16;:34;107108:299;;;107181:16;-1:-1:-1;107181:16:0;107231:164;107334:10;107322:9;92834:4;;107276:30;107181:16;107276:12;:30;:::i;:::-;107275:38;;;;:::i;:::-;:44;;;;:::i;:::-;:56;;;;:::i;:::-;:69;;;;:::i;:::-;107254:90;;:18;:90;:::i;:::-;107364:16;107231:4;:164::i;:::-;107212:183;;107108:299;107427:17;107458:16;107476;107494;107447:64;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;107427:84;;107522:37;107537:4;107543:15;107522:14;:37::i;:::-;106093:1474;;;;;;;105851:1716;;;;;;;:::o;108785:705::-;108890:17;;;;;-1:-1:-1;;;;;108890:17:0;108876:10;:31;:58;;;;-1:-1:-1;108911:15:0;;;;:23;;:15;:23;108876:58;108868:67;;;;;;108946:15;:23;;-1:-1:-1;;108946:23:0;;;109071:45;;108964:5;;;;;;109071:45;;;;;;;;;;;;:::i;:::-;108980:136;;-1:-1:-1;108980:136:0;-1:-1:-1;108980:136:0;-1:-1:-1;109141:14:0;109131:6;:24;;;;;;;;:::i;:::-;;109127:356;;109172:64;109189:7;109198:37;109172:16;:64::i;:::-;109127:356;;;109268:16;109258:6;:26;;;;;;;;:::i;:::-;;109254:229;;109301:84;109320:7;109329:37;109368:16;109301:18;:84::i;109254:229::-;109417:13;109407:6;:23;;;;;;;;:::i;:::-;;109403:80;;109447:24;109463:7;109447:15;:24::i;:::-;108857:633;;;108785:705;;:::o;41649:99::-;41703:10;41725:4;41703:27;41695:45;;;;-1:-1:-1;;;41695:45:0;;16581:2:1;41695:45:0;;;16563:21:1;16620:1;16600:18;;;16593:29;-1:-1:-1;;;16638:18:1;;;16631:35;16683:18;;41695:45:0;16379:328:1;99931:924:0;100002:19;100024:17;-1:-1:-1;;;;;100024:29:0;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;100002:53;;100066:17;100100:16;:14;:16::i;:::-;100086:30;;:11;:30;:::i;:::-;100066:50;-1:-1:-1;100137:34:0;100186:13;;100182:105;;100266:9;100245:18;100251:12;92834:4;100245:18;:::i;:::-;:30;;;;:::i;:::-;100216:59;;100182:105;100311:30;;100307:177;;100358:114;100369:26;92790:5;100406:21;:19;:21::i;100358:114::-;100494:20;100517:16;:14;:16::i;:::-;100494:39;;100563:12;100548;:27;100544:143;;;100621:39;100647:12;100632;:27;100621:10;:39::i;:::-;92694:1;100703:15;:13;:15::i;:::-;:27;100699:149;;;100766:21;;100755:8;:6;:8::i;:::-;:32;100747:89;;;;-1:-1:-1;;;100747:89:0;;16914:2:1;100747:89:0;;;16896:21:1;16953:2;16933:18;;;16926:30;16992:34;16972:18;;;16965:62;-1:-1:-1;;;17043:18:1;;;17036:42;17095:19;;100747:89:0;16712:408:1;98334:509:0;98456:20;;98438:59;;-1:-1:-1;;;98438:59:0;;90946:42;98438:59;;;4073:51:1;98394:7:0;;;;-1:-1:-1;;;;;98456:20:0;;;;98438:54;;4046:18:1;;98438:59:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;98414:83;-1:-1:-1;98508:21:0;;-1:-1:-1;98532:15:0;92834:4;98414:83;98532:15;:::i;:::-;98508:39;;98558:21;98590:6;;;;;;;;;-1:-1:-1;;;;;98590:6:0;-1:-1:-1;;;;;98582:27:0;;:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;98558:53;-1:-1:-1;98658:13:0;98626:28;92743:4;98558:53;98626:28;:::i;:::-;:45;98622:214;;98695:1;98688:8;;;;;98334:509;:::o;98622:214::-;-1:-1:-1;;98765:29:0;;:44;;98334:509;-1:-1:-1;;98334:509:0:o;100863:235::-;100919:20;100952:12;:10;:12::i;:::-;101075:15;:13;:15::i;:::-;92834:4;101052:14;:12;:14::i;:::-;101027:21;:19;:21::i;:::-;101010:14;:12;:14::i;:::-;:38;;;;:::i;:::-;101009:57;;;;:::i;:::-;:63;;;;:::i;:::-;100990:16;:14;:16::i;:::-;:82;;;;:::i;:::-;:100;;;;:::i;99343:120::-;99411:44;99430:24;99446:7;99430:15;:24::i;:::-;99411:18;:44::i;101202:1316::-;101258:4;101275:11;101289:8;:6;:8::i;:::-;101275:22;;101445:21;;101438:3;:28;101434:72;;101490:4;101483:11;;;101202:1316;:::o;101434:72::-;101539:14;;101522:13;:31;101518:76;;101577:5;101570:12;;;101202:1316;:::o;101518:76::-;101679:12;;101672:3;:19;101668:63;;101715:4;101708:11;;;101202:1316;:::o;101668:63::-;101830:22;101855:27;:25;:27::i;:::-;101830:52;;92647:2;101897:14;:33;101893:78;;101954:5;101947:12;;;;101202:1316;:::o;101893:78::-;92647:2;102056:14;:12;:14::i;:::-;:32;102052:76;;;102112:4;102105:11;;;;101202:1316;:::o;102052:76::-;102202:17;-1:-1:-1;;;;;102202:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;102198:75;;;102256:5;102249:12;;;;101202:1316;:::o;102198:75::-;102376:10;;102370:3;:16;:59;;;;;92647:2;102390:21;:19;:21::i;:::-;:39;102370:59;102366:120;;;92834:4;-1:-1:-1;102453:21:0;;101202:1316;-1:-1:-1;;101202:1316:0:o;102366:120::-;102505:5;102498:12;;;;101202:1316;:::o;110497:818::-;110568:28;110579:16;110568:10;:28::i;:::-;110607:25;110635:21;:19;:21::i;:::-;110607:49;;110667:38;110687:17;110667:19;:38::i;:::-;110722:11;;-1:-1:-1;;;;;110722:11:0;-1:-1:-1;;110722:25:0;110718:306;;110764:11;:23;;-1:-1:-1;;;;;;110764:23:0;;;92032:42;110764:23;;;;110802:6;:25;;;;92126:42;110802:25;;;110842:9;:28;;;;;92220:42;110842:28;;;110718:306;;;110903:11;:24;;-1:-1:-1;;;;;;110903:24:0;;;91753:42;110903:24;;;;110942:6;:26;;;;91848:42;110942:26;;;110983:9;:29;;;;;91943:42;110983:29;;;110718:306;111036:24;:22;:24::i;:::-;111071:37;111090:17;111071:18;:37::i;:::-;111119:30;111132:16;111119:12;:30::i;:::-;111166:17;;;;;-1:-1:-1;;;;;111166:17:0;91509:42;111166:29;:53;;;;;111218:1;111199:16;:20;111166:53;111162:146;;;111259:17;;111236:60;;-1:-1:-1;;;111236:60:0;;111259:17;;;;-1:-1:-1;;;;;111259:17:0;;;111236:60;;;13695:51:1;13762:18;;;13755:34;;;111236:5:0;:14;;;;13668:18:1;;111236:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;107629:601::-;107728:7;107739:1;107728:12;107724:25;;107629:601;;:::o;107724:25::-;107759:15;:22;;-1:-1:-1;;107759:22:0;107777:4;107759:22;;;107796:17;;-1:-1:-1;;107759:22:0;107796:17;;;-1:-1:-1;;;;;107796:17:0;:29;107792:431;;107868:16;;;107882:1;107868:16;;;;;;;;;107842:23;;107868:16;;;;;;;;;;;-1:-1:-1;107868:16:0;107842:42;;107919:5;107899:6;107906:1;107899:9;;;;;;;;:::i;:::-;-1:-1:-1;;;;;107899:26:0;;;;:9;;;;;;;;;;;:26;107967:16;;;107981:1;107967:16;;;;;;;;;107940:24;;107967:16;;;;;;;;;;;;-1:-1:-1;107967:16:0;107940:43;;108011:7;107998;108006:1;107998:10;;;;;;;;:::i;:::-;;;;;;;;;;:20;108043:17;;108033:77;;-1:-1:-1;;;108033:77:0;;108043:17;;;;-1:-1:-1;;;;;108043:17:0;;108033:38;;:77;;108080:4;;108087:6;;108095:7;;108104:5;;108033:77;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;107827:295;;114494:274;;:::o;107792:431::-;108151:17;;108143:68;;-1:-1:-1;;;108143:68:0;;108151:17;;;;-1:-1:-1;;;;;108151:17:0;;108143:36;;:68;;108188:5;;108196:7;;108205:5;;108143:68;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;101106:88;101174:12;:10;:12::i;118453:193::-;118531:107;118542:11;118555:15;;118572:21;:19;:21::i;73773:649::-;74197:23;74223:69;74251:4;74223:69;;;;;;;;;;;;;;;;;74231:5;-1:-1:-1;;;;;74223:27:0;;;:69;;;;;:::i;:::-;74197:95;;74311:10;:17;74332:1;74311:22;:56;;;;74348:10;74337:30;;;;;;;;;;;;:::i;:::-;74303:111;;;;-1:-1:-1;;;74303:111:0;;19383:2:1;74303:111:0;;;19365:21:1;19422:2;19402:18;;;19395:30;19461:34;19441:18;;;19434:62;-1:-1:-1;;;19512:18:1;;;19505:40;19562:19;;74303:111:0;19181:406:1;64395:455:0;64565:12;64623:5;64598:21;:30;;64590:81;;;;-1:-1:-1;;;64590:81:0;;19794:2:1;64590:81:0;;;19776:21:1;19833:2;19813:18;;;19806:30;19872:34;19852:18;;;19845:62;-1:-1:-1;;;19923:18:1;;;19916:36;19969:19;;64590:81:0;19592:402:1;64590:81:0;64683:12;64697:23;64724:6;-1:-1:-1;;;;;64724:11:0;64743:5;64750:4;64724:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;64682:73;;;;64773:69;64800:6;64808:7;64817:10;64829:12;64773:26;:69::i;:::-;64766:76;;;;64395:455;;;;;;;:::o;112371:316::-;112490:7;92647:2;112514:18;:36;112510:50;;;-1:-1:-1;112559:1:0;112552:8;;112510:50;112575:12;112591:1;112575:17;112571:31;;-1:-1:-1;112601:1:0;112594:8;;112571:31;112648:30;112669:9;112648:18;:30;:::i;:::-;92834:4;112620:18;92834:4;112620:12;:18;:::i;:::-;:24;;;;:::i;:::-;:59;;;;:::i;111323:113::-;111384:7;111416:2;111411;:7;:17;;111426:2;111411:17;;;111421:2;111411:17;111404:24;;111323:113;;;;;:::o;109498:359::-;109599:75;109618:55;109634:38;109656:16;109634:19;:38;:::i;:::-;109618:15;:55::i;109599:75::-;109685:30;109698:16;109685:12;:30::i;:::-;109732:17;;-1:-1:-1;;109732:17:0;;;;-1:-1:-1;;;;;109732:17:0;:29;109728:122;;109801:17;;109778:60;;-1:-1:-1;;;109778:60:0;;109801:17;;;;-1:-1:-1;;;;;109801:17:0;;;109778:60;;;13695:51:1;13762:18;;;13755:34;;;109778:5:0;:14;;;;13668:18:1;;109778:60:0;13521:274:1;109865:624:0;109992:28;110003:16;109992:10;:28::i;:::-;110031:38;110051:17;110031:19;:38::i;:::-;110080:52;110096:17;110115:16;110080:15;:52::i;:::-;110145:20;110168:16;:14;:16::i;:::-;110145:39;;110218:12;110199:16;:31;110195:153;;;110276:45;110308:12;110289:16;:31;110276:12;:45::i;:::-;110364:17;;-1:-1:-1;;110364:17:0;;;;-1:-1:-1;;;;;110364:17:0;:29;110360:122;;110433:17;;110410:60;;-1:-1:-1;;;110410:60:0;;110433:17;;;;-1:-1:-1;;;;;110433:17:0;;;110410:60;;;13695:51:1;13762:18;;;13755:34;;;110410:5:0;:14;;;;13668:18:1;;110410:60:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;98073:253::-;98134:7;98145:1;98134:12;98130:25;;98073:253;:::o;98130:25::-;98175:30;98180:7;98189:15;:13;:15::i;:::-;98175:4;:30::i;:::-;98165:40;;98220:7;98231:1;98220:12;98216:25;;98073:253;:::o;98216:25::-;98257:11;;98251:67;;-1:-1:-1;;;98251:67:0;;-1:-1:-1;;;;;98284:5:0;11433:15:1;;98251:67:0;;;11415:34:1;11465:18;;;11458:34;;;98301:1:0;11508:18:1;;;11501:34;98312:4:0;11551:18:1;;;11544:43;98257:11:0;;;;98251:24;;11349:19:1;;98251:67:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;102710:2050::-;102752:15;102770:16;:14;:16::i;:::-;102752:34;-1:-1:-1;102797:22:0;;102869:11;;102865:73;;102897:29;102918:7;102897:20;:29::i;:::-;;102865:73;102960:14;:12;:14::i;:::-;102950:24;;92647:2;102991:7;:25;102987:439;;;103050:27;:25;:27::i;:::-;103033:44;;103112:4;103092:24;;92647:2;103135:14;:32;103131:284;;;103198:29;103203:7;103212:14;103198:4;:29::i;:::-;103252:11;;103246:57;;-1:-1:-1;;;103246:57:0;;103188:39;;-1:-1:-1;;;;;;103252:11:0;;103246:25;;:57;;90946:42;;103188:39;;103294:4;;103252:11;;103246:57;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;103373:7;103355:25;;;;103131:284;103438:25;103466:21;:19;:21::i;:::-;103438:49;;103498:19;103520:15;:13;:15::i;:::-;103498:37;;103546:16;103565:14;:12;:14::i;:::-;103546:33;;103590:11;103604:59;103622:17;103641:11;103654:8;103604:17;:59::i;:::-;103698:12;;103590:73;;-1:-1:-1;103727:20:0;;;103723:1030;;103798:83;103809:1;103812:15;;103829:17;103848:11;103861:8;103871:9;;103798:10;:83::i;:::-;92694:1;103956:15;:13;:15::i;:::-;:27;103952:113;;;104023:3;104012:8;:6;:8::i;:::-;:14;104004:45;;;;-1:-1:-1;;;104004:45:0;;20493:2:1;104004:45:0;;;20475:21:1;20532:2;20512:18;;;20505:30;-1:-1:-1;;;20551:18:1;;;20544:48;20609:18;;104004:45:0;20291:342:1;104004:45:0;103723:1030;;;104087:17;-1:-1:-1;;;;;104087:28:0;;:30;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;104082:671;;104144:10;;104138:3;:16;104134:608;;;104212:17;104207:111;;104271:27;:25;:27::i;:::-;104254:44;;104207:111;92647:2;104340:14;:32;104336:391;;;104397:77;104406:9;;104417:14;104433:17;104452:11;104465:8;104397;:77::i;:::-;92694:1;104576:15;:13;:15::i;:::-;:27;104572:136;;;104650:13;104639:8;:6;:8::i;:::-;:24;104631:53;;;;-1:-1:-1;;;104631:53:0;;20840:2:1;104631:53:0;;;20822:21:1;20879:2;20859:18;;;20852:30;-1:-1:-1;;;20898:18:1;;;20891:46;20954:18;;104631:53:0;20638:340:1;94292:213:0;94352:7;94382:31;94387:7;94396:16;:14;:16::i;94382:31::-;94372:41;;94428:7;94439:1;94428:12;94424:26;;-1:-1:-1;94449:1:0;;94292:213;-1:-1:-1;94292:213:0:o;94424:26::-;94468:29;94489:7;94468:20;:29::i;97198:276::-;92647:2;97267:7;:25;97263:38;;;97198:276;:::o;97263:38::-;97321:29;97326:14;:12;:14::i;:::-;97342:7;97321:4;:29::i;:::-;97311:39;;92647:2;97365:7;:25;97361:38;;;97198:276;:::o;97361:38::-;97415:11;;97409:57;;-1:-1:-1;;;97409:57:0;;-1:-1:-1;;;;;97415:11:0;;;;97409:25;;:57;;90946:42;;97440:7;;97457:4;;97415:11;;97409:57;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;97482:283;92647:2;97552:7;:25;97548:38;;;97482:283;:::o;97548:38::-;97606:36;97611:21;:19;:21::i;97606:36::-;97596:46;;92647:2;97657:7;:25;97653:38;;;97482:283;:::o;97653:38::-;97707:11;;97701:56;;-1:-1:-1;;;97701:56:0;;90946:42;97701:56;;;11838:34:1;11888:18;;;11881:34;;;97751:4:0;11931:18:1;;;11924:43;-1:-1:-1;;;;;97707:11:0;;;;97701:27;;11773:18:1;;97701:56:0;11598:375:1;93853:343:0;93977:11;;93971:39;;;-1:-1:-1;;;93971:39:0;;;;93907:38;;-1:-1:-1;;;;;93977:11:0;;93971:37;;:39;;;;;;;;;;;;;;93977:11;93971:39;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;93907:104;;94036:15;-1:-1:-1;;;;;94036:30:0;;:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;94022:11;;:46;;;;;-1:-1:-1;;;;;94022:46:0;;;;;-1:-1:-1;;;;;94022:46:0;;;;;;94102:15;-1:-1:-1;;;;;94102:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;94079:20;:60;;-1:-1:-1;;;;;;94079:60:0;-1:-1:-1;;;;;94079:60:0;;;;;;94156:11;;94150:38;;-1:-1:-1;;;94150:38:0;;-1:-1:-1;94150:38:0;;;21668:36:1;94156:11:0;;;94150:31;;21641:18:1;;94150:38:0;21526:184:1;97773:292:0;97836:7;97847:1;97836:12;97832:25;;97773:292;:::o;97832:25::-;97886:11;;97909:45;;-1:-1:-1;;;97909:45:0;;90946:42;97909:45;;;21883:51:1;97886:11:0;21950:18:1;;;21943:50;-1:-1:-1;;;;;97886:11:0;;;;;;97909:34;;21856:18:1;;97909:45:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;97965:24:0;;-1:-1:-1;;;97965:24:0;;91110:1;97965:24;;;21668:36:1;-1:-1:-1;;;;;97965:17:0;;;-1:-1:-1;97965:17:0;;-1:-1:-1;21641:18:1;;97965:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;98000:57:0;;-1:-1:-1;;;98000:57:0;;-1:-1:-1;;;;;98020:5:0;22334:15:1;;98000:57:0;;;22316:34:1;22366:18;;;22359:34;;;98037:1:0;22409:18:1;;;22402:34;-1:-1:-1;22452:18:1;;;22445:47;98051:4:0;22508:19:1;;;22501:44;98000:11:0;;;-1:-1:-1;98000:11:0;;-1:-1:-1;22250:19:1;;98000:57:0;22004:547:1;66968:644:0;67153:12;67182:7;67178:427;;;67210:10;:17;67231:1;67210:22;67206:290;;-1:-1:-1;;;;;60849:19:0;;;67420:60;;;;-1:-1:-1;;;67420:60:0;;22758:2:1;67420:60:0;;;22740:21:1;22797:2;22777:18;;;22770:30;22836:31;22816:18;;;22809:59;22885:18;;67420:60:0;22556:353:1;67420:60:0;-1:-1:-1;67517:10:0;67510:17;;67178:427;67560:33;67568:10;67580:12;67560:7;:33::i;94513:667::-;94611:29;94616:7;94625:14;:12;:14::i;94611:29::-;94601:39;;94655:7;94666:1;94655:12;94651:25;;94513:667;;:::o;94651:25::-;94703:13;94692:7;;;;:24;;;;;;;;:::i;:::-;;94688:125;;94733:47;94754:7;94763:16;94733:20;:47::i;94688:125::-;94840:16;94829:7;;;;:27;;;;;;;;:::i;:::-;;94825:167;;94873:86;90946:42;94900:5;94908:7;94917:41;94932:7;94941:16;94917:14;:41::i;:::-;94873:13;:86::i;94825:167::-;95035:82;90946:42;95058:5;95066:7;95075:41;95090:7;95099:16;95075:14;:41::i;:::-;95035:9;:82::i;95188:491::-;95273:39;;-1:-1:-1;;;95273:39:0;;;;;548:25:1;;;95253:7:0;;95287:5;-1:-1:-1;;;;;95273:30:0;;;;521:18:1;;95273:39:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;95328:50:0;;-1:-1:-1;;;95328:50:0;;91267:1;95328:50;;;23112:41:1;91308:1:0;23169:18:1;;;23162:50;23228:18;;;23221:34;;;95381:7:0;;-1:-1:-1;91183:42:0;;-1:-1:-1;95328:25:0;;23085:18:1;;95328:50:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:60;95323:349;;;95404:48;;-1:-1:-1;;;95404:48:0;;-1:-1:-1;;;;;95441:10:0;4091:32:1;95404:48:0;;;4073:51:1;91029:42:0;;95404:20;;95432:7;;4046:18:1;;95404:48:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;95474:26:0;;-1:-1:-1;;;95474:26:0;;;;;548:25:1;;;90946:42:0;;95474:17;;521:18:1;;95474:26:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;95323:349::-;95558:77;;-1:-1:-1;;;95558:77:0;;91267:1;95558:77;;;23493:41:1;91308:1:0;23550:18:1;;;23543:50;23609:18;;;23602:34;;;23652:18;;;23645:34;;;90946:42:0;;95540:17;;91183:42;;95558:27;;95593:7;;23465:19:1;;95558:77:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;95540:96;;;;;;;;;;;;;548:25:1;;536:2;521:18;;402:177;104768:1071:0;104972:11;104986:62;105004:18;105024:12;105038:9;104986:17;:62::i;:::-;104972:76;;105059:27;105089:16;:14;:16::i;:::-;105059:46;-1:-1:-1;105116:32:0;92834:4;105151:30;105172:9;105151:18;:30;:::i;:::-;:36;;;;:::i;:::-;105116:71;-1:-1:-1;105198:24:0;105303:16;105309:10;92834:4;105303:16;:::i;:::-;92834:4;;105276:9;105282:3;92834:4;105276:9;:::i;:::-;105248:38;;:24;:38;:::i;:::-;:44;;;;:::i;:::-;105226:66;;:19;:66;:::i;:::-;105225:74;;;;:::i;:::-;:95;;;;:::i;:::-;105198:122;-1:-1:-1;105350:84:0;105198:122;92834:4;105400:27;105418:9;105400:15;:27;:::i;:::-;:33;;;;:::i;:::-;105373:60;;:24;:60;:::i;105350:84::-;105331:103;;92647:2;105449:16;:34;105445:73;;;105500:7;;;;;;105445:73;105528:23;105592:15;:13;:15::i;:::-;92834:4;105554:29;105573:10;105554:16;:29;:::i;:::-;:35;;;;:::i;:::-;:53;;;;:::i;:::-;105682:17;;105658:43;;-1:-1:-1;;;105658:43:0;;-1:-1:-1;;;;;105682:17:0;;;;;;105658:43;;;4073:51:1;105528:79:0;;-1:-1:-1;105636:66:0;;105528:79;;105658:5;:15;;;;4046:18:1;;105658:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;105636:66::-;105618:84;;105713:17;105744:14;105760:19;105781:1;105733:50;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;105713:70;;105794:37;105809:4;105815:15;105794:14;:37::i;:::-;104961:878;;;;;;104768:1071;;;;;:::o;68154:552::-;68315:17;;:21;68311:388;;68547:10;68541:17;68604:15;68591:10;68587:2;68583:19;68576:44;68311:388;68674:12;68667:20;;-1:-1:-1;;;68667:20:0;;;;;;;;:::i;95687:287::-;95790:28;;-1:-1:-1;;;95790:28:0;;;;;548:25:1;;;90946:42:0;;95790:19;;521:18:1;;95790:28:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;95780:38;-1:-1:-1;;;;;;95843:5:0;95829:29;;91183:42;95866:27;91308:1;91267;95780:38;95919:43;95780:38;95945:16;95919;:43::i;:::-;95866:97;;-1:-1:-1;;;;;;95866:97:0;;;;;;;23522:2:1;23511:22;;;95866:97:0;;;23493:41:1;23570:22;;;;23550:18;;;23543:50;23609:18;;;23602:34;23652:18;;;23645:34;;;;23465:19;;95866:97:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;95829:137;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;96885:248;96975:7;92790:5;96999:16;:27;96995:41;;-1:-1:-1;97035:1:0;97028:8;;96995:41;92790:5;92834:4;97082:26;97092:16;92790:5;97082:26;:::i;:::-;97064:14;:12;:14::i;:::-;97054:24;;:7;:24;:::i;:::-;:55;;;;:::i;:::-;:61;;;;:::i;:::-;:71;;;;:::i;95982:712::-;-1:-1:-1;;;;;;;;96100:7:0;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;91358:42:0;-1:-1:-1;;;;;96189:38:0;;:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;96169:60;;:17;96240:15;;;;:19;;;-1:-1:-1;;;;;96270:29:0;;;:18;;;;:29;;;;96310:31;;;:19;;;;:31;;;;96352:17;;;;:27;;;-1:-1:-1;;;;;;;;;;;;;;96461:4:0;96438:28;;;96505:4;-1:-1:-1;;;96477:32:0;;;;-1:-1:-1;;;96520:31:0;;;;96611:75;-1:-1:-1;;;96611:75:0;;91509:42;;96611:24;;:75;;96169:60;;-1:-1:-1;;96655:13:0;;96670:15;;96611:75;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;84664:1686::-;84822:18;84857:14;;;;;:46;;;84888:15;;84875:9;:28;;84857:46;84853:1490;;;84936:6;;84920:41;;-1:-1:-1;;;;;84936:6:0;84944:5;84951:9;84920:15;:41::i;:::-;84989:4;;-1:-1:-1;;;;;84980:13:0;;;84989:4;;84980:13;;:28;;-1:-1:-1;85004:4:0;;-1:-1:-1;;;;;84997:11:0;;;85004:4;;84997:11;84980:28;84976:1356;;;85080:482;;;;;;;;-1:-1:-1;;;;;85080:482:0;;;;;;;;;;;;;;;;-1:-1:-1;85248:14:0;;;:7;:14;;;;;:19;;;;;;;;;;;;;;85080:482;;;;;;85317:4;85080:482;;;;;;85362:15;85080:482;;;;;;;;;;;;;;;;;;;;;;;;85608:6;;85596:44;;-1:-1:-1;;;85596:44:0;;26229:13:1;;26225:22;;85596:44:0;;;26207:41:1;26290:24;;26286:33;;26264:20;;;26257:63;26362:24;;26358:39;;;26336:20;;;26329:69;26440:24;;26436:33;;26414:20;;;26407:63;26508:24;26486:20;;;26479:54;26571:24;;26549:20;;;26542:54;26634:24;26612:20;;;26605:54;26701:24;;26697:33;;26675:20;;;26668:63;85080:482:0;;85608:6;;85596:36;;26141:19:1;;85596:44:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;85583:57;;85010:646;84976:1356;;;-1:-1:-1;;;;;85779:14:0;;;85681:17;85779:14;;;:7;:14;;;;;;;;85794:4;;;;;85779:20;;;;;;;;;85880:13;;;;;;:18;;;;;;;;;;;;85701:269;;27049:2:1;27045:15;;;-1:-1:-1;;27041:24:1;;;85701:269:0;;;27029:37:1;;;;27089:3;27137:16;;;-1:-1:-1;;;;;;27137:16:1;;;27119:12;;;27112:47;27193:15;;;;;27175:12;;;27168:46;27248:16;;;;;;;27230:12;;;27223:47;27304:15;;;;27300:24;27286:12;;;27279:46;85701:269:0;;;;;;;;;86016:6;;86057:240;;;;;27341:12:1;;;86057:240:0;;;86151:4;86057:240;;;;86183:15;86057:240;;;;;;;;;;;;;;;;;86004:312;;-1:-1:-1;;;86004:312:0;;85701:269;;86016:6;;;;;86004:30;;:312;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;85991:325;84664:1686;-1:-1:-1;;;;;;84664:1686:0:o;96702:175::-;96794:7;92790:5;96832:26;96842:16;92790:5;96832:26;:::i;:::-;96821:38;;:7;:38;:::i;89281:337::-;89424:49;;-1:-1:-1;;;89424:49:0;;89456:4;89424:49;;;13001:34:1;-1:-1:-1;;;;;13071:15:1;;;13051:18;;;13044:43;89476:7:0;;89424:23;;;;;;12936:18:1;;89424:49:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:59;89420:191;;;89500:39;-1:-1:-1;;;;;89500:25:0;;89526:9;89537:1;89500:25;:39::i;:::-;89554:45;-1:-1:-1;;;;;89554:25:0;;89580:9;89591:7;89554:25;:45::i;14:131:1:-;-1:-1:-1;;;;;89:31:1;;79:42;;69:70;;135:1;132;125:12;150:247;209:6;262:2;250:9;241:7;237:23;233:32;230:52;;;278:1;275;268:12;230:52;317:9;304:23;336:31;361:5;336:31;:::i;584:248::-;652:6;660;713:2;701:9;692:7;688:23;684:32;681:52;;;729:1;726;719:12;681:52;-1:-1:-1;;752:23:1;;;822:2;807:18;;;794:32;;-1:-1:-1;584:248:1:o;837:127::-;898:10;893:3;889:20;886:1;879:31;929:4;926:1;919:15;953:4;950:1;943:15;969:209;1049:1;1042:5;1039:12;1029:143;;1094:10;1089:3;1085:20;1082:1;1075:31;1129:4;1126:1;1119:15;1157:4;1154:1;1147:15;1183:233;1327:2;1312:18;;1339:37;1369:6;1339:37;:::i;:::-;1385:25;;;1183:233;:::o;1421:180::-;1480:6;1533:2;1521:9;1512:7;1508:23;1504:32;1501:52;;;1549:1;1546;1539:12;1501:52;-1:-1:-1;1572:23:1;;1421:180;-1:-1:-1;1421:180:1:o;1606:558::-;1682:6;1690;1698;1751:2;1739:9;1730:7;1726:23;1722:32;1719:52;;;1767:1;1764;1757:12;1719:52;1806:9;1793:23;1825:31;1850:5;1825:31;:::i;:::-;1875:5;-1:-1:-1;1932:2:1;1917:18;;1904:32;1945:33;1904:32;1945:33;:::i;:::-;1997:7;-1:-1:-1;2056:2:1;2041:18;;2028:32;2104:8;2091:22;;2079:35;;2069:63;;2128:1;2125;2118:12;2069:63;2151:7;2141:17;;;1606:558;;;;;:::o;2169:127::-;2230:10;2225:3;2221:20;2218:1;2211:31;2261:4;2258:1;2251:15;2285:4;2282:1;2275:15;2301:275;2372:2;2366:9;2437:2;2418:13;;-1:-1:-1;;2414:27:1;2402:40;;2472:18;2457:34;;2493:22;;;2454:62;2451:88;;;2519:18;;:::i;:::-;2555:2;2548:22;2301:275;;-1:-1:-1;2301:275:1:o;2581:831::-;2658:6;2666;2719:2;2707:9;2698:7;2694:23;2690:32;2687:52;;;2735:1;2732;2725:12;2687:52;2771:9;2758:23;2748:33;;2800:2;2853;2842:9;2838:18;2825:32;2876:18;2917:2;2909:6;2906:14;2903:34;;;2933:1;2930;2923:12;2903:34;2971:6;2960:9;2956:22;2946:32;;3016:7;3009:4;3005:2;3001:13;2997:27;2987:55;;3038:1;3035;3028:12;2987:55;3074:2;3061:16;3096:2;3092;3089:10;3086:36;;;3102:18;;:::i;:::-;3144:53;3187:2;3168:13;;-1:-1:-1;;3164:27:1;3160:36;;3144:53;:::i;:::-;3131:66;;3220:2;3213:5;3206:17;3260:7;3255:2;3250;3246;3242:11;3238:20;3235:33;3232:53;;;3281:1;3278;3271:12;3232:53;3336:2;3331;3327;3323:11;3318:2;3311:5;3307:14;3294:45;3380:1;3375:2;3370;3363:5;3359:14;3355:23;3348:34;;3401:5;3391:15;;;;;2581:831;;;;;:::o;3417:118::-;3503:5;3496:13;3489:21;3482:5;3479:32;3469:60;;3525:1;3522;3515:12;3540:382;3605:6;3613;3666:2;3654:9;3645:7;3641:23;3637:32;3634:52;;;3682:1;3679;3672:12;3634:52;3721:9;3708:23;3740:31;3765:5;3740:31;:::i;:::-;3790:5;-1:-1:-1;3847:2:1;3832:18;;3819:32;3860:30;3819:32;3860:30;:::i;:::-;3909:7;3899:17;;;3540:382;;;;;:::o;4135:385::-;4221:6;4229;4237;4245;4298:3;4286:9;4277:7;4273:23;4269:33;4266:53;;;4315:1;4312;4305:12;4266:53;-1:-1:-1;;4338:23:1;;;4408:2;4393:18;;4380:32;;-1:-1:-1;4459:2:1;4444:18;;4431:32;;4510:2;4495:18;4482:32;;-1:-1:-1;4135:385:1;-1:-1:-1;4135:385:1:o;4525:250::-;4610:1;4620:113;4634:6;4631:1;4628:13;4620:113;;;4710:11;;;4704:18;4691:11;;;4684:39;4656:2;4649:10;4620:113;;;-1:-1:-1;;4767:1:1;4749:16;;4742:27;4525:250::o;4780:270::-;4821:3;4859:5;4853:12;4886:6;4881:3;4874:19;4902:76;4971:6;4964:4;4959:3;4955:14;4948:4;4941:5;4937:16;4902:76;:::i;:::-;5032:2;5011:15;-1:-1:-1;;5007:29:1;4998:39;;;;5039:4;4994:50;;4780:270;-1:-1:-1;;4780:270:1:o;5055:298::-;5238:6;5231:14;5224:22;5213:9;5206:41;5283:2;5278;5267:9;5263:18;5256:30;5187:4;5303:44;5343:2;5332:9;5328:18;5320:6;5303:44;:::i;5358:241::-;5414:6;5467:2;5455:9;5446:7;5442:23;5438:32;5435:52;;;5483:1;5480;5473:12;5435:52;5522:9;5509:23;5541:28;5563:5;5541:28;:::i;5604:106::-;5684:1;5677:5;5674:12;5664:40;;5700:1;5697;5690:12;5715:264;5786:6;5839:2;5827:9;5818:7;5814:23;5810:32;5807:52;;;5855:1;5852;5845:12;5807:52;5894:9;5881:23;5913:36;5943:5;5913:36;:::i;5984:478::-;6059:6;6067;6075;6128:2;6116:9;6107:7;6103:23;6099:32;6096:52;;;6144:1;6141;6134:12;6096:52;6183:9;6170:23;6233:4;6226:5;6222:16;6215:5;6212:27;6202:55;;6253:1;6250;6243:12;6202:55;6276:5;-1:-1:-1;6333:2:1;6318:18;;6305:32;6346:33;6305:32;6346:33;:::i;:::-;5984:478;;6398:7;;-1:-1:-1;;;6452:2:1;6437:18;;;;6424:32;;5984:478::o;6659:374::-;6729:8;6739:6;6793:3;6786:4;6778:6;6774:17;6770:27;6760:55;;6811:1;6808;6801:12;6760:55;-1:-1:-1;6834:20:1;;6877:18;6866:30;;6863:50;;;6909:1;6906;6899:12;6863:50;6946:4;6938:6;6934:17;6922:29;;7006:3;6999:4;6989:6;6986:1;6982:14;6974:6;6970:27;6966:38;6963:47;6960:67;;;7023:1;7020;7013:12;6960:67;6659:374;;;;;:::o;7038:1571::-;7229:6;7237;7245;7253;7261;7269;7277;7285;7338:3;7326:9;7317:7;7313:23;7309:33;7306:53;;;7355:1;7352;7345:12;7306:53;7395:9;7382:23;7424:18;7465:2;7457:6;7454:14;7451:34;;;7481:1;7478;7471:12;7451:34;7520:77;7589:7;7580:6;7569:9;7565:22;7520:77;:::i;:::-;7616:8;;-1:-1:-1;7494:103:1;-1:-1:-1;7704:2:1;7689:18;;7676:32;;-1:-1:-1;7720:16:1;;;7717:36;;;7749:1;7746;7739:12;7717:36;7788:79;7859:7;7848:8;7837:9;7833:24;7788:79;:::i;:::-;7886:8;;-1:-1:-1;7762:105:1;-1:-1:-1;7974:2:1;7959:18;;7946:32;;-1:-1:-1;7990:16:1;;;7987:36;;;8019:1;8016;8009:12;7987:36;8058:79;8129:7;8118:8;8107:9;8103:24;8058:79;:::i;:::-;8156:8;;-1:-1:-1;8032:105:1;-1:-1:-1;8244:2:1;8229:18;;8216:32;;-1:-1:-1;8260:16:1;;;8257:36;;;8289:1;8286;8279:12;8257:36;8327:8;8316:9;8312:24;8302:34;;8374:7;8367:4;8363:2;8359:13;8355:27;8345:55;;8396:1;8393;8386:12;8345:55;8436:2;8423:16;8462:2;8454:6;8451:14;8448:34;;;8478:1;8475;8468:12;8448:34;8523:7;8518:2;8509:6;8505:2;8501:15;8497:24;8494:37;8491:57;;;8544:1;8541;8534:12;8491:57;8575:2;8571;8567:11;8557:21;;8597:6;8587:16;;;;;7038:1571;;;;;;;;;;;:::o;8614:388::-;8682:6;8690;8743:2;8731:9;8722:7;8718:23;8714:32;8711:52;;;8759:1;8756;8749:12;8711:52;8798:9;8785:23;8817:31;8842:5;8817:31;:::i;:::-;8867:5;-1:-1:-1;8924:2:1;8909:18;;8896:32;8937:33;8896:32;8937:33;:::i;9202:184::-;9272:6;9325:2;9313:9;9304:7;9300:23;9296:32;9293:52;;;9341:1;9338;9331:12;9293:52;-1:-1:-1;9364:16:1;;9202:184;-1:-1:-1;9202:184:1:o;9391:127::-;9452:10;9447:3;9443:20;9440:1;9433:31;9483:4;9480:1;9473:15;9507:4;9504:1;9497:15;9523:168;9596:9;;;9627;;9644:15;;;9638:22;;9624:37;9614:71;;9665:18;;:::i;9696:217::-;9736:1;9762;9752:132;;9806:10;9801:3;9797:20;9794:1;9787:31;9841:4;9838:1;9831:15;9869:4;9866:1;9859:15;9752:132;-1:-1:-1;9898:9:1;;9696:217::o;10253:408::-;10464:2;10449:18;;10476:37;10506:6;10476:37;:::i;:::-;10522:25;;;10595:4;10583:17;;;10578:2;10563:18;;10556:45;10637:17;;10632:2;10617:18;;;10610:45;10253:408;:::o;10666:467::-;-1:-1:-1;;;;;10960:15:1;;;10942:34;;11007:2;10992:18;;10985:34;;;;11055:15;;11050:2;11035:18;;11028:43;11119:6;11107:19;;;11102:2;11087:18;;11080:47;10891:3;10876:19;;10666:467::o;12315:127::-;12376:10;12371:3;12367:20;12364:1;12357:31;12407:4;12404:1;12397:15;12431:4;12428:1;12421:15;13800:461;13853:3;13891:5;13885:12;13918:6;13913:3;13906:19;13944:4;13973:2;13968:3;13964:12;13957:19;;14010:2;14003:5;13999:14;14031:1;14041:195;14055:6;14052:1;14049:13;14041:195;;;14120:13;;-1:-1:-1;;;;;14116:39:1;14104:52;;14176:12;;;;14211:15;;;;14152:1;14070:9;14041:195;;;-1:-1:-1;14252:3:1;;13800:461;-1:-1:-1;;;;;13800:461:1:o;14266:261::-;14445:2;14434:9;14427:21;14408:4;14465:56;14517:2;14506:9;14502:18;14494:6;14465:56;:::i;14532:936::-;14627:6;14658:2;14701;14689:9;14680:7;14676:23;14672:32;14669:52;;;14717:1;14714;14707:12;14669:52;14750:9;14744:16;14779:18;14820:2;14812:6;14809:14;14806:34;;;14836:1;14833;14826:12;14806:34;14874:6;14863:9;14859:22;14849:32;;14919:7;14912:4;14908:2;14904:13;14900:27;14890:55;;14941:1;14938;14931:12;14890:55;14970:2;14964:9;14992:2;14988;14985:10;14982:36;;;14998:18;;:::i;:::-;15044:2;15041:1;15037:10;15027:20;;15067:28;15091:2;15087;15083:11;15067:28;:::i;:::-;15129:15;;;15199:11;;;15195:20;;;15160:12;;;;15227:19;;;15224:39;;;15259:1;15256;15249:12;15224:39;15283:11;;;;15303:135;15319:6;15314:3;15311:15;15303:135;;;15385:10;;15373:23;;15336:12;;;;15416;;;;15303:135;;;15457:5;14532:936;-1:-1:-1;;;;;;;;14532:936:1:o;15473:128::-;15540:9;;;15561:11;;;15558:37;;;15575:18;;:::i;15606:374::-;15805:2;15790:18;;15817:37;15847:6;15817:37;:::i;:::-;15863:25;;;15919:2;15904:18;;15897:34;;;;15962:2;15947:18;;;15940:34;15606:374;:::o;15985:389::-;16084:6;16092;16100;16153:2;16141:9;16132:7;16128:23;16124:32;16121:52;;;16169:1;16166;16159:12;16121:52;16201:9;16195:16;16220:36;16250:5;16220:36;:::i;:::-;16320:2;16305:18;;16299:25;16364:2;16349:18;;;16343:25;16275:5;;16299:25;;-1:-1:-1;16343:25:1;15985:389;-1:-1:-1;;;15985:389:1:o;17125:245::-;17204:6;17212;17265:2;17253:9;17244:7;17240:23;17236:32;17233:52;;;17281:1;17278;17271:12;17233:52;-1:-1:-1;;17304:16:1;;17360:2;17345:18;;;17339:25;17304:16;;17339:25;;-1:-1:-1;17125:245:1:o;17375:125::-;17440:9;;;17461:10;;;17458:36;;;17474:18;;:::i;17505:245::-;17572:6;17625:2;17613:9;17604:7;17600:23;17596:32;17593:52;;;17641:1;17638;17631:12;17593:52;17673:9;17667:16;17692:28;17714:5;17692:28;:::i;17755:1031::-;-1:-1:-1;;;;;18086:32:1;;18068:51;;18176:3;18138:2;18156:18;;;18149:31;;;18049:4;;18203:57;;18240:19;;18232:6;18203:57;:::i;:::-;18296:22;;;18291:2;18276:18;;18269:50;18368:13;;18390:22;;;18466:15;;;;18428;;;18499:1;18509:169;18523:6;18520:1;18517:13;18509:169;;;18584:13;;18572:26;;18653:15;;;;18618:12;;;;18545:1;18538:9;18509:169;;;18513:3;;18723:9;18718:3;18714:19;18709:2;18698:9;18694:18;18687:47;18751:29;18776:3;18768:6;18751:29;:::i;:::-;18743:37;17755:1031;-1:-1:-1;;;;;;;;;17755:1031:1:o;18791:385::-;19023:1;19019;19014:3;19010:11;19006:19;18998:6;18994:32;18983:9;18976:51;19063:6;19058:2;19047:9;19043:18;19036:34;19106:2;19101;19090:9;19086:18;19079:30;18957:4;19126:44;19166:2;19155:9;19151:18;19143:6;19126:44;:::i;:::-;19118:52;18791:385;-1:-1:-1;;;;;18791:385:1:o;19999:287::-;20128:3;20166:6;20160:13;20182:66;20241:6;20236:3;20229:4;20221:6;20217:17;20182:66;:::i;:::-;20264:16;;;;;19999:287;-1:-1:-1;;19999:287:1:o;20983:282::-;21084:6;21137:2;21125:9;21116:7;21112:23;21108:32;21105:52;;;21153:1;21150;21143:12;21105:52;21185:9;21179:16;21204:31;21229:5;21204:31;:::i;23690:391::-;23895:2;23880:18;;23907:37;23937:6;23907:37;:::i;:::-;23953:25;;;24009:2;23994:18;;23987:34;;;;24069:4;24057:17;24052:2;24037:18;;;24030:45;23690:391;:::o;24086:219::-;24235:2;24224:9;24217:21;24198:4;24255:44;24295:2;24284:9;24280:18;24272:6;24255:44;:::i;24859:1078::-;25192:3;25174:22;;;25233:13;;25212:19;;;25205:42;25306:4;25294:17;;25288:24;25314:4;25284:35;25278:3;25263:19;;25256:64;25367:4;25355:17;;25349:24;-1:-1:-1;;;;;25448:21:1;;;25442:3;25427:19;;25420:50;25529:4;25517:17;;25511:24;25507:33;25501:3;25486:19;;25479:62;25596:4;25584:17;;25578:24;25572:3;25557:19;;25550:53;25400:3;25640:17;;25634:24;25695:4;25689:3;25674:19;;25667:33;-1:-1:-1;;25717:53:1;25765:3;25750:19;;25634:24;25717:53;:::i;:::-;25709:61;;;25779:62;25835:4;25824:9;25820:20;25812:6;24621:12;;-1:-1:-1;;;;;24617:21:1;;;24605:34;;24702:4;24691:16;;;24685:23;24678:31;24671:39;24655:14;;;24648:63;24764:4;24753:16;;;24747:23;24743:32;;;24727:14;;;24720:56;24839:4;24828:16;;;24822:23;24815:31;24808:39;24792:14;;24785:63;24499:355;25779:62;25872:4;25857:20;;25850:36;;;;25917:4;25902:20;25895:36;24859:1078;;-1:-1:-1;;24859:1078:1:o;27364:652::-;27561:2;27550:9;27543:21;27524:4;27599:6;27593:13;27642:4;27637:2;27626:9;27622:18;27615:32;27670:51;27716:3;27705:9;27701:19;27687:12;27670:51;:::i;:::-;27656:65;;27802:1;27798;27793:3;27789:11;27785:19;27779:2;27771:6;27767:15;27761:22;27757:48;27752:2;27741:9;27737:18;27730:76;27860:2;27852:6;27848:15;27842:22;27837:2;27826:9;27822:18;27815:50;27920:2;27912:6;27908:15;27902:22;27896:3;27885:9;27881:19;27874:51;27981:3;27973:6;27969:16;27963:23;27956:4;27945:9;27941:20;27934:53;28004:6;27996:14;;;27364:652;;;;:::o
Swarm Source
ipfs://71dc190579b21fc2848cf23e8a6392ea2156829e686aa2f6e69cac2d904b0e52
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
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.