Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 5 from a total of 5 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
New Single Sided... | 20134552 | 104 days ago | IN | 0 ETH | 0.02698471 | ||||
New Single Sided... | 20133790 | 104 days ago | IN | 0 ETH | 0.03322993 | ||||
New Single Sided... | 20125671 | 105 days ago | IN | 0 ETH | 0.02353819 | ||||
New Single Sided... | 20125559 | 105 days ago | IN | 0 ETH | 0.019129 | ||||
0x60e06040 | 20125353 | 105 days ago | IN | 0 ETH | 0.01729046 |
Latest 4 internal transactions
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
20134552 | 104 days ago | Contract Creation | 0 ETH | |||
20133790 | 104 days ago | Contract Creation | 0 ETH | |||
20125671 | 105 days ago | Contract Creation | 0 ETH | |||
20125559 | 105 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
SingleSidedPTcoreFactory
Compiler Version
v0.8.18+commit.87f61d96
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2024-06-19 */ // 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); /*////////////////////////////////////////////////////////////// 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 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 = 0xBB51273D6c746910C7C06fe718f30c936170feD0; /*////////////////////////////////////////////////////////////// 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()) } } } } /** * @title Base Health Check * @author Yearn.finance * @notice This contract can be inherited by any Yearn * V3 strategy wishing to implement a health check during * the `report` function in order to prevent any unexpected * behavior from being permanently recorded as well as the * `checkHealth` modifier. * * A strategist simply needs to inherit this contract. Set * the limit ratios to the desired amounts and then * override `_harvestAndReport()` just as they otherwise * would. If the profit or loss that would be recorded is * outside the acceptable bounds the tx will revert. * * The healthcheck does not prevent a strategy from reporting * losses, but rather can make sure manual intervention is * needed before reporting an unexpected loss or profit. */ abstract contract BaseHealthCheck is BaseStrategy { // Can be used to determine if a healthcheck should be called. // Defaults to true; bool public doHealthCheck = true; uint256 internal constant MAX_BPS = 10_000; // Default profit limit to 100%. uint16 private _profitLimitRatio = uint16(MAX_BPS); // Defaults loss limit to 0. uint16 private _lossLimitRatio; constructor( address _asset, string memory _name ) BaseStrategy(_asset, _name) {} /** * @notice Returns the current profit limit ratio. * @dev Use a getter function to keep the variable private. * @return . The current profit limit ratio. */ function profitLimitRatio() public view returns (uint256) { return _profitLimitRatio; } /** * @notice Returns the current loss limit ratio. * @dev Use a getter function to keep the variable private. * @return . The current loss limit ratio. */ function lossLimitRatio() public view returns (uint256) { return _lossLimitRatio; } /** * @notice Set the `profitLimitRatio`. * @dev Denominated in basis points. I.E. 1_000 == 10%. * @param _newProfitLimitRatio The mew profit limit ratio. */ function setProfitLimitRatio( uint256 _newProfitLimitRatio ) external onlyManagement { _setProfitLimitRatio(_newProfitLimitRatio); } /** * @dev Internally set the profit limit ratio. Denominated * in basis points. I.E. 1_000 == 10%. * @param _newProfitLimitRatio The mew profit limit ratio. */ function _setProfitLimitRatio(uint256 _newProfitLimitRatio) internal { require(_newProfitLimitRatio > 0, "!zero profit"); require(_newProfitLimitRatio <= type(uint16).max, "!too high"); _profitLimitRatio = uint16(_newProfitLimitRatio); } /** * @notice Set the `lossLimitRatio`. * @dev Denominated in basis points. I.E. 1_000 == 10%. * @param _newLossLimitRatio The new loss limit ratio. */ function setLossLimitRatio( uint256 _newLossLimitRatio ) external onlyManagement { _setLossLimitRatio(_newLossLimitRatio); } /** * @dev Internally set the loss limit ratio. Denominated * in basis points. I.E. 1_000 == 10%. * @param _newLossLimitRatio The new loss limit ratio. */ function _setLossLimitRatio(uint256 _newLossLimitRatio) internal { require(_newLossLimitRatio < MAX_BPS, "!loss limit"); _lossLimitRatio = uint16(_newLossLimitRatio); } /** * @notice Turns the healthcheck on and off. * @dev If turned off the next report will auto turn it back on. * @param _doHealthCheck Bool if healthCheck should be done. */ function setDoHealthCheck(bool _doHealthCheck) public onlyManagement { doHealthCheck = _doHealthCheck; } /** * @notice OVerrides the default {harvestAndReport} to include a healthcheck. * @return _totalAssets New totalAssets post report. */ function harvestAndReport() external override onlySelf returns (uint256 _totalAssets) { // Let the strategy report. _totalAssets = _harvestAndReport(); // Run the healthcheck on the amount returned. _executeHealthCheck(_totalAssets); } /** * @dev To be called during a report to make sure the profit * or loss being recorded is within the acceptable bound. * * @param _newTotalAssets The amount that will be reported. */ function _executeHealthCheck(uint256 _newTotalAssets) internal virtual { if (!doHealthCheck) { doHealthCheck = true; return; } // Get the current total assets from the implementation. uint256 currentTotalAssets = TokenizedStrategy.totalAssets(); if (_newTotalAssets > currentTotalAssets) { require( ((_newTotalAssets - currentTotalAssets) <= (currentTotalAssets * uint256(_profitLimitRatio)) / MAX_BPS), "healthCheck" ); } else if (currentTotalAssets > _newTotalAssets) { require( (currentTotalAssets - _newTotalAssets <= ((currentTotalAssets * uint256(_lossLimitRatio)) / MAX_BPS)), "healthCheck" ); } } } // 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 IPendleMarket { function readTokens() external view returns (address _SY, address _PT, address _YT); function isExpired() external view returns (bool); } interface ISY { function deposit( address receiver, address tokenIn, uint256 amountTokenToDeposit, uint256 minSharesOut ) external payable returns (uint256 amountSharesOut); function redeem( address receiver, uint256 amountSharesToRedeem, address tokenOut, uint256 minTokenOut, bool burnFromInternalBalance ) external payable returns (uint256 amountTokenOut); function isValidTokenIn(address) external view returns (bool); function isValidTokenOut(address) external view returns (bool); function previewRedeem( address tokenOut, uint256 amountSharesToRedeem ) external view returns (uint256 amountTokenOut); } interface IPendleRouter { struct ApproxParams { uint256 guessMin; uint256 guessMax; uint256 guessOffchain; // pass 0 in to skip this variable uint256 maxIteration; // every iteration, the diff between guessMin and guessMax will be divided by 2 uint256 eps; // the max eps between the returned result & the correct result, base 1e18. Normally this number will be set // to 1e15 (1e18/1000 = 0.1%) } struct LimitOrderData { address limitRouter; uint256 epsSkipMarket; // only used for swap operations, will be ignored otherwise FillOrderParams[] normalFills; FillOrderParams[] flashFills; bytes optData; } struct FillOrderParams { Order order; bytes signature; uint256 makingAmount; } struct Order { uint256 salt; uint256 expiry; uint256 nonce; OrderType orderType; address token; address YT; address maker; address receiver; uint256 makingAmount; uint256 lnImpliedRate; uint256 failSafeRate; bytes permit; } enum OrderType { SY_FOR_PT, PT_FOR_SY, SY_FOR_YT, YT_FOR_SY } function swapExactSyForPt( address receiver, address market, uint256 exactSyIn, uint256 minPtOut, ApproxParams calldata guessPtOut, LimitOrderData calldata limit ) external returns (uint256 netPtOut, uint256 netSyFee); function swapExactPtForSy( address receiver, address market, uint256 exactPtIn, uint256 minSyOut, LimitOrderData calldata limit ) external returns (uint256 netSyOut, uint256 netSyFee); function redeemPyToSy( address receiver, address YT, uint256 netPyIn, uint256 minSyOut ) external returns (uint256 netSyOut); } interface IPendleOracle { function getPtToSyRate( address market, uint32 oracleDuration ) external view returns (uint256 rate); function getOracleState( address market, uint32 oracleDuration ) external view returns ( bool increaseCardinalityRequired, uint16 cardinalityRequired, bool oldestObservationSatisfied ); } /// @title yearn-v3-SingleSidedPTcore /// @author mil0x /// @notice yearn-v3 Strategy that invests into Pendle PT positions. contract SingleSidedPTcore is BaseHealthCheck { using SafeERC20 for ERC20; ///@notice Address of our Pendle market. address public market; address internal immutable oracle; ///@notice Oracle TWAP duration, in seconds. uint32 public oracleDuration; ///@notice Bool if the strategy is open for any depositors. Default = true. bool public open = true; ///@notice Mapping of addresses allowed to deposit. mapping(address => bool) public allowed; struct TradeParams { ///@notice Set the minimum asset amount to be converted to PT. Set to max to prevent PT buying. uint128 minAssetAmountToPT; ///@notice The max in asset will be invested by the keeper at a time. uint128 maxSingleTrade; } ///@notice Parameters used to contrin size of strategy investing into PT. TradeParams public tradeParams; ///@notice The total deposit limit for the strategy. Use in case we want to cap a given strategy. uint256 public depositLimit = type(uint256).max; address internal constant pendleRouter = 0x888888888889758F76e7103c6CbF23ABbF58F946; ///@notice Parameters passed to Pendle's router for swaps in using binary search. IPendleRouter.ApproxParams public routerParams; ///@notice Address of this market's SY token. address public immutable SY; ///@notice Address of this market's PT token. address public PT; address internal YT; ///@notice Amount in Basis Points to allow for slippage when reporting. uint256 public swapSlippageBPS; ///@notice Amount in Basis Points to account for as buffer when reporting. Can also manually account for bigger depeg scenarios. uint256 public bufferSlippageBPS; // Struct for all variables involved in tendTrigger struct TendTriggerParams { ///@notice The amount in asset that will trigger a tend if idle. uint128 depositTrigger; ///@notice The max amount the base fee can be for a tend to happen. uint48 maxTendBaseFee; ///@notice Minimum time between deposits to wait. uint40 minDepositInterval; ///@notice Time stamp of the last deployment of funds. uint40 lastDeposit; } ///@notice Contains adjustable variables that govern when to tend this strategy. TendTriggerParams public tendTriggerParams; ///@notice Yearn governance address public immutable GOV; uint256 internal constant WAD = 1e18; constructor( address _asset, address _market, address _oracle, address _GOV, string memory _name ) BaseHealthCheck(_asset, _name) { market = _market; require(!_isExpired(), "expired"); oracle = _oracle; //Default oracle duration to 1 hour price smoothing recommendation by Pendle Finance oracleDuration = 3600; //Default maxSingleTrade to 15 ETH as a majority of markets are ETH based. Change this for non-ETH. tradeParams.maxSingleTrade = 15e18; (SY, PT, YT) = IPendleMarket(_market).readTokens(); require(ISY(SY).isValidTokenOut(_asset), "!valid out"); require(ISY(SY).isValidTokenIn(_asset), "!valid in"); // Default slippage to 0.5%. swapSlippageBPS = 50; bufferSlippageBPS = 50; routerParams.guessMax = type(uint256).max; routerParams.maxIteration = 256; routerParams.eps = 1e15; // max 0.1% unused TendTriggerParams memory _tendTriggerParams; _tendTriggerParams.depositTrigger = 5e18; // The amount in asset that will trigger a tend if idle. Default to 5 ETH; update for non-ETH. _tendTriggerParams.maxTendBaseFee = 20e9; // The max amount the base fee can be for a tend to happen. Default max tend fee to 20 gwei. _tendTriggerParams.minDepositInterval = 43200; // Minimum time between deposits to wait. Default min deposit interval to 12 hours. tendTriggerParams = _tendTriggerParams; // Allow a 500% gain. _setProfitLimitRatio(500_00); GOV = _GOV; //approvals: ERC20(_asset).forceApprove(SY, type(uint256).max); ERC20(SY).forceApprove(pendleRouter, type(uint256).max); ERC20(PT).forceApprove(pendleRouter, type(uint256).max); } /*////////////////////////////////////////////////////////////// INTERNAL //////////////////////////////////////////////////////////////*/ function _deployFunds(uint256 _amount) internal override { //do nothing, we want to only have the keeper swap funds } function _invest(uint256 _amount) internal { //asset --> SY ISY(SY).deposit(address(this), address(asset), _amount, 0); _amount = ERC20(SY).balanceOf(address(this)); //SY --> PT IPendleRouter.LimitOrderData memory limit; //skip limit order by passing zero address uint256 minPTout = (_SYtoPT(_amount) * (MAX_BPS - swapSlippageBPS)) / MAX_BPS; //calculate minimum expected PT out IPendleRouter(pendleRouter).swapExactSyForPt( address(this), market, _amount, minPTout, routerParams, limit ); // Update the last time that we deposited. tendTriggerParams.lastDeposit = uint40(block.timestamp); } function _freeFunds(uint256 _amount) internal override { //Redeem PT shares proportional to the SSPT shares redeemed: uint256 totalAssets = TokenizedStrategy.totalAssets(); uint256 totalDebt = totalAssets - _balanceOfAsset(); uint256 PTtoUninvest = (_balanceOfPT() * _amount) / totalDebt; _uninvest(PTtoUninvest); } function _uninvest(uint256 currentBalance) internal returns (uint256) { if (currentBalance == 0) return 0; //PT --> SY if (_isExpired()) { //if expired, redeem PY to SY currentBalance = IPendleRouter(pendleRouter).redeemPyToSy( address(this), YT, currentBalance, 0 ); } else { IPendleRouter.LimitOrderData memory limit; //skip limit order by passing zero address // We don't enforce any min amount out since withdrawer's can use 'maxLoss' (currentBalance, ) = IPendleRouter(pendleRouter).swapExactPtForSy( address(this), market, currentBalance, 0, limit ); if (currentBalance == 0) return 0; } //SY --> asset // We don't enforce any min amount out since withdrawers can use 'maxLoss' return ISY(SY).redeem( address(this), currentBalance, address(asset), 0, false ); } function _harvestAndReport() internal override returns (uint256 _totalAssets) { if (!_isExpired() && !TokenizedStrategy.isShutdown()) { uint256 assetBalance = _balanceOfAsset(); TradeParams memory _tradeParams = tradeParams; if (assetBalance > _tradeParams.minAssetAmountToPT) { _invest(_min(assetBalance, _tradeParams.maxSingleTrade)); } } _totalAssets = _balanceOfAsset() + (_PTtoAsset(_balanceOfPT()) * (MAX_BPS - bufferSlippageBPS)) / MAX_BPS; //reduce PT balance by bufferSlippageBPS to account for the fact that it will need to be swapped back to asset } function _SYtoPT(uint256 _amount) internal view returns (uint256) { return (_amount * WAD) / IPendleOracle(oracle).getPtToSyRate(market, oracleDuration); } function _PTtoSY(uint256 _amount) internal view returns (uint256) { return (_amount * IPendleOracle(oracle).getPtToSyRate(market, oracleDuration)) / WAD; } function _PTtoAsset(uint256 _amount) internal view returns (uint256) { return ISY(SY).previewRedeem(address(asset), _PTtoSY(_amount)); } function _tend(uint256) internal override { _invest(_min(_balanceOfAsset(), tradeParams.maxSingleTrade)); } function _tendTrigger() internal view override returns (bool _shouldTend) { TendTriggerParams memory _tendTriggerParams = tendTriggerParams; if ( !_isExpired() && block.timestamp - _tendTriggerParams.lastDeposit > _tendTriggerParams.minDepositInterval && _balanceOfAsset() > _tendTriggerParams.depositTrigger && tradeParams.maxSingleTrade > 0 && !TokenizedStrategy.isShutdown() ) { _shouldTend = block.basefee < _tendTriggerParams.maxTendBaseFee; } } function availableDepositLimit( address _owner ) public view override returns (uint256) { // If the owner is whitelisted or the strategy is open. if (allowed[_owner] || open) { uint256 totalDeposits = TokenizedStrategy.totalAssets(); if (depositLimit > totalDeposits) { return depositLimit - totalDeposits; } else { return 0; } } else { return 0; } } function _balanceOfAsset() internal view returns (uint256) { return asset.balanceOf(address(this)); } function _balanceOfPT() internal view returns (uint256) { return ERC20(PT).balanceOf(address(this)); } function _isExpired() internal view returns (bool) { return IPendleMarket(market).isExpired(); } function _checkOracle( address _market, uint32 _oracleDuration ) internal view { ( bool increaseCardinalityRequired, , bool oldestObservationSatisfied ) = IPendleOracle(oracle).getOracleState(_market, _oracleDuration); if (increaseCardinalityRequired || !oldestObservationSatisfied) { revert("oracle not ready"); } } function _min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /*////////////////////////////////////////////////////////////// EXTERNAL: //////////////////////////////////////////////////////////////*/ function balanceOfAsset() external view returns (uint256) { return _balanceOfAsset(); } function balanceOfPT() external view returns (uint256) { return _balanceOfPT(); } function isExpired() external view returns (bool) { return _isExpired(); } /** * @notice Set oracle duration price smoothing * @param _oracleDuration twap duration in seconds */ function setOracleDuration( uint32 _oracleDuration ) external onlyEmergencyAuthorized { require(_oracleDuration >= 900, "duration too low"); _checkOracle(market, _oracleDuration); oracleDuration = _oracleDuration; } /** * @notice Set the tradeParams for the strategy to decide on minimum investment and maximum single investments for the keeper. * @param _minAssetAmountToPT Set the minimum amount in asset that should be converted to PT. Set this to max in order to not trigger any PT buying. * @param _maxSingleTrade Set the max in asset amount that will be invested by the keeper at a time. Can also be used to pause keeper investments. */ function setTradeParams( uint128 _minAssetAmountToPT, uint128 _maxSingleTrade ) external onlyManagement { require( _maxSingleTrade <= type(uint128).max && _minAssetAmountToPT <= type(uint128).max, "too large" ); require(_maxSingleTrade >= _minAssetAmountToPT, "wrong order"); require(tendTriggerParams.depositTrigger >= _minAssetAmountToPT, "minAsset too large"); TradeParams memory _tradeParams; _tradeParams.minAssetAmountToPT = _minAssetAmountToPT; _tradeParams.maxSingleTrade = _maxSingleTrade; tradeParams = _tradeParams; } /** * @notice Set the routerParams for the pendleRouter. Pendle's AMM only supports the built-in swapSyForExactPt. To execute a swapExactSyForPt, the * router will conduct a binary search to determine the amount of PT to swap. * @param _guessMin The minimum value for binary search. Default: 0. * @param _guessMax The maximum value for binary search. Default: type(uint256).max. * @param _maxIteration The maximum number of times binary search will be performed. Default: 256. * @param _eps The precision of binary search - the maximum proportion of the input that can be unused. Default: 1e15 == max 0.1% unused. * Alternatively: 1e14 implies that no more than 0.01% unused. */ function setRouterParams( uint256 _guessMin, uint256 _guessMax, uint256 _maxIteration, uint256 _eps ) external onlyManagement { routerParams.guessMin = _guessMin; // default: 0 routerParams.guessMax = _guessMax; // default: type(uint256).max routerParams.maxIteration = _maxIteration; // default: 256 routerParams.eps = _eps; // default: 1e15 == max 0.1% unused. Alternatively: 1e14 implies that no more than 0.01% unused. } /** * @notice Set the tendTriggerParams for all variables involved in tendTrigger. * @param _depositTrigger The amount in asset that will trigger a tend if idle. * @param _maxTendBaseFee The max amount the base fee can be for a tend to happen in wei. * @param _minDepositInterval Minimum time between deposits to wait in seconds. */ function setTendTriggerParams( uint128 _depositTrigger, uint48 _maxTendBaseFee, uint40 _minDepositInterval ) external onlyManagement { require(_minDepositInterval > 0, "interval too low"); require(_depositTrigger <= type(uint128).max, "too large"); require(_depositTrigger >= tradeParams.minAssetAmountToPT, "trigger too small"); tendTriggerParams.depositTrigger = _depositTrigger; tendTriggerParams.maxTendBaseFee = _maxTendBaseFee; tendTriggerParams.minDepositInterval = _minDepositInterval; } /** * @notice Set the deposit limit in asset amount. Set this to 0 to disallow deposits. * @param _depositLimit the deposit limit in asset units */ function setDepositLimit(uint256 _depositLimit) external onlyManagement { depositLimit = _depositLimit; } /** * @notice Set the slippage for keeper investments in basis points. * @param _swapSlippageBPS the maximum slippage in basis points (BPS) */ function setSwapSlippageBPS( uint256 _swapSlippageBPS ) external onlyManagement { require(_swapSlippageBPS <= MAX_BPS); swapSlippageBPS = _swapSlippageBPS; } /** * @notice Set the buffer for reports in basis points. Can also be used to manually account for bigger depeg scenarios * @param _bufferSlippageBPS the buffer slippage in basis points (BPS) */ function setBufferSlippageBPS( uint256 _bufferSlippageBPS ) external onlyManagement { require(_bufferSlippageBPS <= MAX_BPS); bufferSlippageBPS = _bufferSlippageBPS; } /** * @notice Change if anyone can deposit in or only white listed addresses * @param _open the bool deciding if anyone can deposit (true) or only whitelisted addresses (false) */ function setOpen(bool _open) external onlyManagement { open = _open; } /** * @notice Set or update an addresses whitelist status. * @param _address the address for which to change the whitelist status * @param _allowed the bool to set as whitelisted (true) or not (false) */ function setAllowed( address _address, bool _allowed ) external onlyManagement { allowed[_address] = _allowed; } /*////////////////////////////////////////////////////////////// EMERGENCY & GOVERNANCE: //////////////////////////////////////////////////////////////*/ /** * @notice Manually pull funds out from the PT stack without shuting down. This will also stop keeper investments. * @param _amount the PT amount to uninvest into asset * @param _expectedAssetAmountOut the minimum acceptable asset amount as a result of uninvestment */ function manualWithdraw( uint256 _amount, uint256 _expectedAssetAmountOut ) external onlyEmergencyAuthorized { tradeParams.maxSingleTrade = 0; uint256 currentBalance = _balanceOfPT(); if (_amount > currentBalance) { _amount = currentBalance; } uint256 _amountOut = _uninvest(_amount); require(_amountOut >= _expectedAssetAmountOut, "too little amountOut"); } /** * @notice Manually pull funds out from the PT stack after the strategy has been shutdown. * @param _amount the PT amount to uninvest into asset */ function _emergencyWithdraw(uint256 _amount) internal override { uint256 currentBalance = _balanceOfPT(); if (_amount > currentBalance) { _amount = currentBalance; } uint256 expectedAssetAmountOut = _PTtoAsset(_amount); uint256 _amountOut = _uninvest(_amount); require( _amountOut >= (expectedAssetAmountOut * (MAX_BPS - swapSlippageBPS)) / MAX_BPS, "too little amountOut" ); } /** * @notice Redeem all PT into asset and rollover the market into a new maturity. Only callable by governance. * @param _market the market address (not PT address) for the new maturity to rollover into * @param _minAssetAmountOut the acceptable minimum amount of asset out for the PT amount currently held by the strategy */ function rolloverMaturity( address _market, uint256 _minAssetAmountOut ) external onlyGovernance { require(_isExpired(), "not expired"); require(_market != address(0), "!market"); require(market != _market, "same market"); //check new market exists long enough for preset oracleDuration _checkOracle(_market, oracleDuration); //redeem all PT to SY uint256 currentBalance = _balanceOfPT(); if (currentBalance > 0) { currentBalance = IPendleRouter(pendleRouter).redeemPyToSy( address(this), YT, currentBalance, 0 ); } //set addresses to new maturity market = _market; require(!_isExpired(), "expired"); (address _SY, address _PT, address _YT) = IPendleMarket(_market) .readTokens(); require(_SY == SY, "wrong SY"); PT = _PT; YT = _YT; ERC20(_PT).forceApprove(pendleRouter, type(uint256).max); //redeem all SY into asset (let keeper move asset to new PT over time) if (currentBalance == 0 && _minAssetAmountOut == 0) return; ISY(SY).redeem( address(this), currentBalance, address(asset), _minAssetAmountOut, false ); } /** * @notice Sweep of non-asset ERC20 tokens to governance (onlyGovernance) * @param _token The ERC20 token to sweep */ function sweep(address _token) external onlyGovernance { require(_token != address(asset), "!asset"); require(_token != PT, "!PT"); ERC20(_token).safeTransfer(GOV, ERC20(_token).balanceOf(address(this))); } modifier onlyGovernance() { require(msg.sender == GOV, "!gov"); _; } } interface IBaseStrategy { function tokenizedStrategyAddress() external view returns (address); /*////////////////////////////////////////////////////////////// IMMUTABLE FUNCTIONS //////////////////////////////////////////////////////////////*/ function availableDepositLimit( address _owner ) external view returns (uint256); function availableWithdrawLimit( address _owner ) external view returns (uint256); function deployFunds(uint256 _assets) external; function freeFunds(uint256 _amount) external; function harvestAndReport() external returns (uint256); function tendThis(uint256 _totalIdle) external; function shutdownWithdraw(uint256 _amount) external; function tendTrigger() external view returns (bool, bytes memory); } interface IStrategy is IBaseStrategy, ITokenizedStrategy {} interface IStrategyInterface is IStrategy { function reportTrigger( address _strategy ) external view returns (bool, bytes memory); function sweep(address _token) external; function balanceOfAsset() external view returns (uint256); function balanceOfPT() external view returns (uint256); function setProfitLimitRatio(uint256) external; function setLossLimitRatio(uint256) external; function setDoHealthCheck(bool) external; function setRouterParams( uint256 _guessMin, uint256 _guessMax, uint256 _maxIteration, uint256 _eps ) external; function isExpired() external view returns (bool); function setTradeParams( uint128 _minAssetAmountToPT, uint128 _maxSingleTrade ) external; function setTendTriggerParams( uint128 _depositTrigger, uint48 _maxTendBaseFee, uint40 _minDepositInterval ) external; function setDepositLimit(uint256) external; function setDepositTrigger(uint256) external; function market() external view returns (address); function setSwapSlippageBPS(uint256) external; function setOracleDuration(uint32) external; function rolloverMaturity(address market, uint256 _slippageBPS) external; function PT() external view returns (address); function SY() external view returns (address); function YT() external view returns (address); } contract SingleSidedPTcoreFactory { event NewSingleSidedPTcore(address indexed strategy, address indexed asset); address public management; address public performanceFeeRecipient; address public keeper; address public immutable oracle; address public immutable emergencyAdmin; address public immutable GOV; mapping(address => address) public assetToStrategy; constructor( address _management, address _peformanceFeeRecipient, address _keeper, address _oracle, address _emergencyAdmin, address _GOV ) { management = _management; performanceFeeRecipient = _peformanceFeeRecipient; keeper = _keeper; oracle = _oracle; emergencyAdmin = _emergencyAdmin; GOV = _GOV; } modifier onlyManagement() { require(msg.sender == management, "!management"); _; } /** * @notice Deploy a new Single Sided Pendle PT Core Strategy. * @return . The address of the new strategy. */ function newSingleSidedPTcore( address _asset, address _market, string memory _name ) external onlyManagement returns (address) { IStrategyInterface newStrategy = IStrategyInterface( address(new SingleSidedPTcore(_asset, _market, oracle, GOV, _name)) ); newStrategy.setPerformanceFeeRecipient(performanceFeeRecipient); newStrategy.setKeeper(keeper); newStrategy.setPendingManagement(management); newStrategy.setEmergencyAdmin(emergencyAdmin); emit NewSingleSidedPTcore(address(newStrategy), _asset); assetToStrategy[_asset] = address(newStrategy); return address(newStrategy); } /** * @notice Deploy a new Single Sided Pendle PT Strategy. * @return . The address of the new strategy. */ function newSingleSidedPTcore( address _asset, address _market, uint128 _minAssetAmountToPT, uint128 _maxSingleTrade, uint256 _depositLimit, uint128 _depositTrigger, uint48 _maxTendBaseFee, uint40 _minDepositInterval, string memory _name ) external onlyManagement returns (address) { IStrategyInterface newStrategy = IStrategyInterface( address(new SingleSidedPTcore(_asset, _market, oracle, GOV, _name)) ); newStrategy.setPerformanceFeeRecipient(performanceFeeRecipient); newStrategy.setKeeper(keeper); newStrategy.setPendingManagement(management); newStrategy.setEmergencyAdmin(emergencyAdmin); newStrategy.setTendTriggerParams( _depositTrigger, _maxTendBaseFee, _minDepositInterval ); newStrategy.setTradeParams(_minAssetAmountToPT, _maxSingleTrade); if (_depositLimit != type(uint256).max) { newStrategy.setDepositLimit(_depositLimit); } emit NewSingleSidedPTcore(address(newStrategy), _asset); assetToStrategy[_asset] = address(newStrategy); return address(newStrategy); } /** * @notice Retrieve the address of a strategy by asset address * @param _asset asset address * @return strategy address */ function getStrategyByAsset( address _asset ) external view returns (address) { return assetToStrategy[_asset]; } /** * @notice Check if a strategy has been deployed by this Factory * @param _strategy strategy address */ function isDeployedStrategy( address _strategy ) external view returns (bool) { address _asset = IStrategyInterface(_strategy).asset(); return assetToStrategy[_asset] == _strategy; } function setStrategyByAsset( address _asset, address _strategy ) external onlyManagement { assetToStrategy[_asset] = _strategy; } /** * @notice Set the management address. * @dev This is the address that can call the management functions. * @param _management The address to set as the management address. */ function setManagement(address _management) external onlyManagement { require(_management != address(0), "ZERO_ADDRESS"); management = _management; } /** * @notice Set the performance fee recipient address. * @dev This is the address that will receive the performance fee. * @param _performanceFeeRecipient The address to set as the performance fee recipient address. */ function setPerformanceFeeRecipient( address _performanceFeeRecipient ) external onlyManagement { require(_performanceFeeRecipient != address(0), "ZERO_ADDRESS"); performanceFeeRecipient = _performanceFeeRecipient; } /** * @notice Set the keeper address. * @dev This is the address that will be able to call the keeper functions. * @param _keeper The address to set as the keeper address. */ function setKeeper(address _keeper) external onlyManagement { keeper = _keeper; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_management","type":"address"},{"internalType":"address","name":"_peformanceFeeRecipient","type":"address"},{"internalType":"address","name":"_keeper","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"address","name":"_emergencyAdmin","type":"address"},{"internalType":"address","name":"_GOV","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"strategy","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"}],"name":"NewSingleSidedPTcore","type":"event"},{"inputs":[],"name":"GOV","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetToStrategy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"}],"name":"getStrategyByAsset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_strategy","type":"address"}],"name":"isDeployedStrategy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"management","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_market","type":"address"},{"internalType":"uint128","name":"_minAssetAmountToPT","type":"uint128"},{"internalType":"uint128","name":"_maxSingleTrade","type":"uint128"},{"internalType":"uint256","name":"_depositLimit","type":"uint256"},{"internalType":"uint128","name":"_depositTrigger","type":"uint128"},{"internalType":"uint48","name":"_maxTendBaseFee","type":"uint48"},{"internalType":"uint40","name":"_minDepositInterval","type":"uint40"},{"internalType":"string","name":"_name","type":"string"}],"name":"newSingleSidedPTcore","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_market","type":"address"},{"internalType":"string","name":"_name","type":"string"}],"name":"newSingleSidedPTcore","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"performanceFeeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"setKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_management","type":"address"}],"name":"setManagement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_performanceFeeRecipient","type":"address"}],"name":"setPerformanceFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"address","name":"_strategy","type":"address"}],"name":"setStrategyByAsset","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60e06040523480156200001157600080fd5b5060405162005352380380620053528339810160408190526200003491620000a6565b600080546001600160a01b03199081166001600160a01b0398891617909155600180548216968816969096179095556002805490951693861693909317909355831660805290821660a0521660c05262000127565b80516001600160a01b0381168114620000a157600080fd5b919050565b60008060008060008060c08789031215620000c057600080fd5b620000cb8762000089565b9550620000db6020880162000089565b9450620000eb6040880162000089565b9350620000fb6060880162000089565b92506200010b6080880162000089565b91506200011b60a0880162000089565b90509295509295509295565b60805160a05160c0516151d162000181600039600081816101400152818161051c01526109d40152600081816101c6015281816106b20152610b6a015260008181610205015281816104fb01526109b301526151d16000f3fe60806040523480156200001157600080fd5b5060043610620001095760003560e01c806388a8d60211620000a3578063d4a22bde116200006e578063d4a22bde146200027d578063db90b1e01462000294578063ed27f7c914620002c3578063f987e55d14620002d757600080fd5b806388a8d602146200022757806397256094146200023b578063a22d7f631462000252578063aced1661146200026957600080fd5b80636a5f1aa211620000e45780636a5f1aa214620001a757806370905dce14620001c0578063748747e614620001e85780637dc0d1d014620001ff57600080fd5b80630d004424146200010e578063180cb47f146200013a5780634a3e6544146200017b575b600080fd5b620001256200011f36600462000c68565b620002ee565b60405190151581526020015b60405180910390f35b620001627f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200162000131565b620001626200018c36600462000c68565b6003602052600090815260409020546001600160a01b031681565b620001be620001b836600462000c68565b6200037e565b005b620001627f000000000000000000000000000000000000000000000000000000000000000081565b620001be620001f936600462000c68565b6200041d565b620001627f000000000000000000000000000000000000000000000000000000000000000081565b60005462000162906001600160a01b031681565b620001be6200024c36600462000c8f565b6200046c565b620001626200026336600462000dab565b620004c7565b60025462000162906001600160a01b031681565b620001be6200028e36600462000c68565b620008e9565b62000162620002a536600462000c68565b6001600160a01b039081166000908152600360205260409020541690565b60015462000162906001600160a01b031681565b62000162620002e836600462000e89565b6200097f565b600080826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000330573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000356919062000ef3565b6001600160a01b03908116600090815260036020526040902054811693169290921492915050565b6000546001600160a01b03163314620003b45760405162461bcd60e51b8152600401620003ab9062000f13565b60405180910390fd5b6001600160a01b038116620003fb5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401620003ab565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146200044a5760405162461bcd60e51b8152600401620003ab9062000f13565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314620004995760405162461bcd60e51b8152600401620003ab9062000f13565b6001600160a01b03918216600090815260036020526040902080546001600160a01b03191691909216179055565b600080546001600160a01b03163314620004f55760405162461bcd60e51b8152600401620003ab9062000f13565b60008a8a7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000866040516200054a9062000c41565b6200055a95949392919062000f38565b604051809103906000f08015801562000577573d6000803e3d6000fd5b5060015460405163352f8d5160e11b81526001600160a01b039182166004820152919250821690636a5f1aa290602401600060405180830381600087803b158015620005c257600080fd5b505af1158015620005d7573d6000803e3d6000fd5b5050600254604051633a43a3f360e11b81526001600160a01b039182166004820152908416925063748747e69150602401600060405180830381600087803b1580156200062357600080fd5b505af115801562000638573d6000803e3d6000fd5b5050600054604051630f629b7960e41b81526001600160a01b039182166004820152908416925063f629b7909150602401600060405180830381600087803b1580156200068457600080fd5b505af115801562000699573d6000803e3d6000fd5b5050604051630d768ce560e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152841692506335da33949150602401600060405180830381600087803b1580156200070157600080fd5b505af115801562000716573d6000803e3d6000fd5b5050604051633ba24f8160e01b81526001600160801b038916600482015265ffffffffffff8816602482015264ffffffffff871660448201526001600160a01b0384169250633ba24f819150606401600060405180830381600087803b1580156200078057600080fd5b505af115801562000795573d6000803e3d6000fd5b505060405163f462bbff60e01b81526001600160801b03808d1660048301528b1660248201526001600160a01b038416925063f462bbff9150604401600060405180830381600087803b158015620007ec57600080fd5b505af115801562000801573d6000803e3d6000fd5b5050505060001987146200086c5760405163bdc8144b60e01b8152600481018890526001600160a01b0382169063bdc8144b90602401600060405180830381600087803b1580156200085257600080fd5b505af115801562000867573d6000803e3d6000fd5b505050505b8a6001600160a01b0316816001600160a01b03167f4e26313b1dea133965fe2d5a105476115b8bbaf3300e207b839d078fb334266060405160405180910390a36001600160a01b039a8b16600090815260036020526040902080546001600160a01b0319169b82169b909b17909a55509798975050505050505050565b6000546001600160a01b03163314620009165760405162461bcd60e51b8152600401620003ab9062000f13565b6001600160a01b0381166200095d5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401620003ab565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b600080546001600160a01b03163314620009ad5760405162461bcd60e51b8152600401620003ab9062000f13565b600084847f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008660405162000a029062000c41565b62000a1295949392919062000f38565b604051809103906000f08015801562000a2f573d6000803e3d6000fd5b5060015460405163352f8d5160e11b81526001600160a01b039182166004820152919250821690636a5f1aa290602401600060405180830381600087803b15801562000a7a57600080fd5b505af115801562000a8f573d6000803e3d6000fd5b5050600254604051633a43a3f360e11b81526001600160a01b039182166004820152908416925063748747e69150602401600060405180830381600087803b15801562000adb57600080fd5b505af115801562000af0573d6000803e3d6000fd5b5050600054604051630f629b7960e41b81526001600160a01b039182166004820152908416925063f629b7909150602401600060405180830381600087803b15801562000b3c57600080fd5b505af115801562000b51573d6000803e3d6000fd5b5050604051630d768ce560e21b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152841692506335da33949150602401600060405180830381600087803b15801562000bb957600080fd5b505af115801562000bce573d6000803e3d6000fd5b50506040516001600160a01b038089169350841691507f4e26313b1dea133965fe2d5a105476115b8bbaf3300e207b839d078fb334266090600090a36001600160a01b03948516600090815260036020526040902080546001600160a01b03191695821695909517909455509192915050565b6141e58062000fb783390190565b6001600160a01b038116811462000c6557600080fd5b50565b60006020828403121562000c7b57600080fd5b813562000c888162000c4f565b9392505050565b6000806040838503121562000ca357600080fd5b823562000cb08162000c4f565b9150602083013562000cc28162000c4f565b809150509250929050565b80356001600160801b038116811462000ce557600080fd5b919050565b803564ffffffffff8116811462000ce557600080fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011262000d2857600080fd5b813567ffffffffffffffff8082111562000d465762000d4662000d00565b604051601f8301601f19908116603f0116810190828211818310171562000d715762000d7162000d00565b8160405283815286602085880101111562000d8b57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060008060006101208a8c03121562000dcb57600080fd5b893562000dd88162000c4f565b985060208a013562000dea8162000c4f565b975062000dfa60408b0162000ccd565b965062000e0a60608b0162000ccd565b955060808a0135945062000e2160a08b0162000ccd565b935060c08a013565ffffffffffff8116811462000e3d57600080fd5b925062000e4d60e08b0162000cea565b91506101008a013567ffffffffffffffff81111562000e6b57600080fd5b62000e798c828d0162000d16565b9150509295985092959850929598565b60008060006060848603121562000e9f57600080fd5b833562000eac8162000c4f565b9250602084013562000ebe8162000c4f565b9150604084013567ffffffffffffffff81111562000edb57600080fd5b62000ee98682870162000d16565b9150509250925092565b60006020828403121562000f0657600080fd5b815162000c888162000c4f565b6020808252600b908201526a085b585b9859d95b595b9d60aa1b604082015260600190565b600060018060a01b0380881683526020818816818501528187166040850152818616606085015260a06080850152845191508160a085015260005b8281101562000f915785810182015185820160c00152810162000f73565b5050600060c0828501015260c0601f19601f830116840101915050969550505050505056fe6101206040526000805462ffffff60ff60e81b01191662271001600160e81b011790556000196003553480156200003557600080fd5b50604051620041e5380380620041e5833981016040819052620000589162000af4565b6001600160a01b0385166080523060a0526040518590829082908290620000c59062000091908490849033908190819060240162000c28565b60408051601f198184030181529190526020810180516001600160e01b03908116634b839d7360e11b17909152620004c116565b505073bb51273d6c746910c7c06fe718f30c936170fed07f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55505060008054600160281b600160c81b031916650100000000006001600160a01b03881602179055506200013162000555565b156200016e5760405162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b60448201526064015b60405180910390fd5b6001600160a01b0383811660c0526000805463ffffffff60c81b191660e160cc1b179055600280546001600160801b031665340aad21b3b760921b17905560408051630b2339af60e21b8152905191861691632c8ce6bc916004808201926060929091908290030181865afa158015620001ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000212919062000c6b565b600a80546001600160a01b03199081166001600160a01b0393841617909155600980549091169282169290921790915590811660e0819052604051633c21b3eb60e11b815291871660048301529063784367d690602401602060405180830381865afa15801562000287573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ad919062000cb5565b620002e85760405162461bcd60e51b815260206004820152600a602482015269085d985b1a59081bdd5d60b21b604482015260640162000165565b60e051604051637d2d278360e11b81526001600160a01b0387811660048301529091169063fa5a4f0690602401602060405180830381865afa15801562000333573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000359919062000cb5565b620003935760405162461bcd60e51b815260206004820152600960248201526810bb30b634b21034b760b91b604482015260640162000165565b6032600b819055600c5560001960055561010060075566038d7ea4c680006008556040805160808101825260006060820152674563918244f4000081526404a817c800602082015261a8c09181019190915277a8c00004a817c80000000000000000004563918244f40000600d556200040e61c350620005d5565b6001600160a01b038381166101005260e0516200043d9188169060001962000674602090811b620018ee17901c565b6200047a73888888888889758f76e7103c6cbf23abbf58f94660001960e0516001600160a01b03166200067460201b620018ee179092919060201c565b600954620004b5906001600160a01b031673888888888889758f76e7103c6cbf23abbf58f94660001962000674602090811b620018ee17901c565b50505050505062000d0c565b606060008073bb51273d6c746910c7c06fe718f30c936170fed06001600160a01b031684604051620004f4919062000cd9565b600060405180830381855af49150503d806000811462000531576040519150601f19603f3d011682016040523d82523d6000602084013e62000536565b606091505b5091509150816200054e576040513d806000833e8082fd5b9392505050565b60008060059054906101000a90046001600160a01b03166001600160a01b0316632f13b60c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620005aa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005d0919062000cb5565b905090565b60008111620006165760405162461bcd60e51b815260206004820152600c60248201526b085e995c9bc81c1c9bd99a5d60a21b604482015260640162000165565b61ffff811115620006565760405162461bcd60e51b8152602060048201526009602482015268042e8dede40d0d2ced60bb1b604482015260640162000165565b6000805461ffff9092166101000262ffff0019909216919091179055565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b17909152620006ce90859083906200074a16565b62000744576040516001600160a01b0384166024820152600060448201526200073890859063095ea7b360e01b9060640160408051808303601f190181529190526020810180516001600160e01b0319939093166001600160e01b03938416179052906200080216565b62000744848262000802565b50505050565b6000806000846001600160a01b03168460405162000769919062000cd9565b6000604051808303816000865af19150503d8060008114620007a8576040519150601f19603f3d011682016040523d82523d6000602084013e620007ad565b606091505b5091509150818015620007db575080511580620007db575080806020019051810190620007db919062000cb5565b8015620007f95750620007f985620008e860201b620019b01760201c565b95945050505050565b60006200085e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620008f760201b620019bf179092919060201c565b90508051600014806200088257508080602001905181019062000882919062000cb5565b620008e35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000165565b505050565b6001600160a01b03163b151590565b606062000908848460008562000910565b949350505050565b606082471015620009735760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000165565b600080866001600160a01b0316858760405162000991919062000cd9565b60006040518083038185875af1925050503d8060008114620009d0576040519150601f19603f3d011682016040523d82523d6000602084013e620009d5565b606091505b509092509050620009e987838387620009f4565b979650505050505050565b6060831562000a6857825160000362000a60576001600160a01b0385163b62000a605760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000165565b508162000908565b62000908838381511562000a7f5781518083602001fd5b8060405162461bcd60e51b815260040162000165919062000cf7565b80516001600160a01b038116811462000ab357600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000aeb57818101518382015260200162000ad1565b50506000910152565b600080600080600060a0868803121562000b0d57600080fd5b62000b188662000a9b565b945062000b286020870162000a9b565b935062000b386040870162000a9b565b925062000b486060870162000a9b565b60808701519092506001600160401b038082111562000b6657600080fd5b818801915088601f83011262000b7b57600080fd5b81518181111562000b905762000b9062000ab8565b604051601f8201601f19908116603f0116810190838211818310171562000bbb5762000bbb62000ab8565b816040528281528b602084870101111562000bd557600080fd5b62000be883602083016020880162000ace565b80955050505050509295509295909350565b6000815180845262000c1481602086016020860162000ace565b601f01601f19169290920160200192915050565b600060018060a01b03808816835260a0602084015262000c4c60a084018862000bfa565b9581166040840152938416606083015250911660809091015292915050565b60008060006060848603121562000c8157600080fd5b62000c8c8462000a9b565b925062000c9c6020850162000a9b565b915062000cac6040850162000a9b565b90509250925092565b60006020828403121562000cc857600080fd5b815180151581146200054e57600080fd5b6000825162000ced81846020870162000ace565b9190910192915050565b6020815260006200054e602083018462000bfa565b60805160a05160c05160e051610100516133ad62000e386000396000818161032b015281816106f1015281816108170152610f330152600081816105a5015281816111ef0152818161131b015281816122bf0152818161279f0152818161285401526129c401526000818161236101528181612b1a0152612bea0152600081816108ce01528181610a9001528181610b1b01528181610be101528181610d1301528181610db301528181610e44015281816113a701528181611432015281816114bd0152818161153c01528181611641015281816116cc0152818161174c01528181611b2e01528181611c0c01528181611d5a0152611f52015260008181610752015281816112e50152818161200701528181612289015281816127ce01526129f301526133ad6000f3fe608060405234801561001057600080fd5b50600436106102695760003560e01c80637d96993211610151578063c05bd92d116100c3578063d696860111610087578063d69686011461067d578063d94073d414610690578063ecf70858146106a3578063f462bbff146106ac578063fcfff16f146106bf578063fde813a8146106d357610269565b8063c05bd92d146105ed578063cefba47414610600578063cf683c701461062c578063d19a3bb81461063f578063d63a8e111461065a57610269565b8063a4a7799511610115578063a4a77995146104ff578063ab1c99941461057a578063ac00ff261461058d578063afd27bf5146105a0578063bc06b529146105c7578063bdc8144b146105da57610269565b80637d9699321461049957806380f55605146104ac578063950b3d73146104c65780639d7fb70c146104d9578063a0ef795b146104ec57610269565b80633d6cb575116101ea5780634a5d0943116101ae5780634a5d094314610437578063503160d9146104485780635d265d3f1461045b5780636718835f146104715780636fdca5e01461047e578063797bf3431461049157610269565b80633d6cb575146103e357806345b1993f146103f65780634697f05d1461040957806346aa2f121461041c57806349317f1d1461042f57610269565b80631eab62a9116102315780631eab62a914610365578063256d8a231461036e5780632b24a878146103b05780632f13b60c146103b85780633ba24f81146103d057610269565b806301681a62146102a457806304bd4629146102b757806309b2c8a8146102df5780631809bca51461031d578063180cb47f14610326575b73bb51273d6c746910c7c06fe718f30c936170fed03660008037600080366000845af43d6000803e80801561029d573d6000f35b3d6000fd5b005b6102a26102b2366004612cd6565b6106e6565b6102cc6102c5366004612cd6565b5060001990565b6040519081526020015b60405180910390f35b6002546102fd906001600160801b0380821691600160801b90041682565b604080516001600160801b039384168152929091166020830152016102d6565b6102cc600c5481565b61034d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102d6565b6102cc600b5481565b600454600554600654600754600854610388949392919085565b604080519586526020860194909452928401919091526060830152608082015260a0016102d6565b6102cc6108a0565b6103c06108af565b60405190151581526020016102d6565b6102a26103de366004612d0a565b6108b9565b6102a26103f1366004612d68565b610a6a565b6102a2610404366004612d81565b610a7b565b6102a2610417366004612dc1565b610b06565b6102cc61042a366004612cd6565b610ba8565b6102cc610c98565b600054610100900461ffff166102cc565b6102a2610456366004612d68565b610cb8565b610463610cc0565b6040516102d6929190612e4a565b6000546103c09060ff1681565b6102a261048c366004612e65565b610cfe565b6102cc610d94565b6000546301000000900461ffff166102cc565b60005461034d90600160281b90046001600160a01b031681565b6102a26104d4366004612d68565b610d9e565b6102a26104e7366004612d68565b610e1e565b6102a26104fa366004612e82565b610e2f565b600d5461053c906001600160801b0381169065ffffffffffff600160801b8204169064ffffffffff600160b01b8204811691600160d81b90041684565b604080516001600160801b03909516855265ffffffffffff909316602085015264ffffffffff918216928401929092521660608201526080016102d6565b6102a2610588366004612ea4565b610f28565b6102a261059b366004612e65565b611392565b61034d7f000000000000000000000000000000000000000000000000000000000000000081565b6102a26105d5366004612d68565b61141d565b6102a26105e8366004612d68565b6114a8565b6102a26105fb366004612ed0565b611527565b60005461061790600160c81b900463ffffffff1681565b60405163ffffffff90911681526020016102d6565b6102a261063a366004612d68565b61162c565b61034d73bb51273d6c746910c7c06fe718f30c936170fed081565b6103c0610668366004612cd6565b60016020526000908152604090205460ff1681565b6102a261068b366004612d68565b6116b7565b60095461034d906001600160a01b031681565b6102cc60035481565b6102a26106ba366004612ef6565b611737565b6000546103c090600160e81b900460ff1681565b6102a26106e1366004612d68565b6118dd565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107505760405162461bcd60e51b81526004016107479060208082526004908201526310b3b7bb60e11b604082015260600190565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036107ba5760405162461bcd60e51b815260206004820152600660248201526508585cdcd95d60d21b6044820152606401610747565b6009546001600160a01b03908116908216036107fe5760405162461bcd60e51b815260206004820152600360248201526208541560ea1b6044820152606401610747565b6040516370a0823160e01b815230600482015261089d907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b038416906370a0823190602401602060405180830381865afa158015610868573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088c9190612f29565b6001600160a01b03841691906119d6565b50565b60006108aa611a0b565b905090565b60006108aa611a79565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561091857600080fd5b505afa15801561092c573d6000803e3d6000fd5b5050505060008164ffffffffff161161097a5760405162461bcd60e51b815260206004820152601060248201526f696e74657276616c20746f6f206c6f7760801b6044820152606401610747565b6001600160801b0383811611156109bf5760405162461bcd60e51b8152602060048201526009602482015268746f6f206c6172676560b81b6044820152606401610747565b6002546001600160801b039081169084161015610a125760405162461bcd60e51b81526020600482015260116024820152701d1c9a59d9d95c881d1bdbc81cdb585b1b607a1b6044820152606401610747565b600d805464ffffffffff909216600160b01b0264ffffffffff60b01b1965ffffffffffff909416600160801b026001600160b01b03199093166001600160801b03909516949094179190911791909116919091179055565b610a72611af1565b61089d81611b2a565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610ada57600080fd5b505afa158015610aee573d6000803e3d6000fd5b50505060049490945560059290925560075560085550565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610b6557600080fd5b505afa158015610b79573d6000803e3d6000fd5b505050506001600160a01b03919091166000908152600160205260409020805460ff1916911515919091179055565b6001600160a01b03811660009081526001602052604081205460ff1680610bd85750600054600160e81b900460ff165b15610c8b5760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c619190612f29565b9050806003541115610c825780600354610c7b9190612f58565b9392505050565b50600092915050565b506000919050565b919050565b6000610ca2611af1565b610caa611bf8565b9050610cb581611d3c565b90565b61089d611af1565b60006060610ccc611e86565b6040805160048152602481019091526020810180516001600160e01b031663440368a360e01b17905290939092509050565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610d5d57600080fd5b505afa158015610d71573d6000803e3d6000fd5b505060008054931515600160e81b0260ff60e81b19909416939093179092555050565b60006108aa611fef565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610dfd57600080fd5b505afa158015610e11573d6000803e3d6000fd5b5050505061089d8161203e565b610e26611af1565b61089d816120d9565b6040516320b8029160e21b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906382e00a449060240160006040518083038186803b158015610e8e57600080fd5b505afa158015610ea2573d6000803e3d6000fd5b5050600280546001600160801b031690555060009050610ec0611a0b565b905080831115610ece578092505b6000610ed9846120ff565b905082811015610f225760405162461bcd60e51b81526020600482015260146024820152731d1bdbc81b1a5d1d1b1948185b5bdd5b9d13dd5d60621b6044820152606401610747565b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f895760405162461bcd60e51b81526004016107479060208082526004908201526310b3b7bb60e11b604082015260600190565b610f91611a79565b610fcb5760405162461bcd60e51b815260206004820152600b60248201526a1b9bdd08195e1c1a5c995960aa1b6044820152606401610747565b6001600160a01b03821661100b5760405162461bcd60e51b8152602060048201526007602482015266085b585c9ad95d60ca1b6044820152606401610747565b6000546001600160a01b03808416600160281b909204160361105d5760405162461bcd60e51b815260206004820152600b60248201526a1cd85b59481b585c9ad95d60aa1b6044820152606401610747565b600054611078908390600160c81b900463ffffffff16612332565b6000611082611a0b565b9050801561111b57600a5460405163339748cb60e01b815273888888888889758f76e7103c6cbf23abbf58f9469163339748cb916110d59130916001600160a01b03909116908690600090600401612f6b565b6020604051808303816000875af11580156110f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111189190612f29565b90505b6000805465010000000000600160c81b031916600160281b6001600160a01b03861602179055611149611a79565b156111805760405162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b6044820152606401610747565b6000806000856001600160a01b0316632c8ce6bc6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156111c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e79190612f94565b9250925092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316146112595760405162461bcd60e51b815260206004820152600860248201526777726f6e6720535960c01b6044820152606401610747565b600980546001600160a01b038085166001600160a01b03199283168117909355600a8054918516919092161790556112a89073888888888889758f76e7103c6cbf23abbf58f9466000196118ee565b831580156112b4575084155b156112c157505050505050565b60405163769f8e5d60e01b8152306004820152602481018590526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116604483015260648201879052600060848301527f0000000000000000000000000000000000000000000000000000000000000000169063769f8e5d9060a4016020604051808303816000875af1158015611364573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113889190612f29565b50505050505b5050565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b1580156113f157600080fd5b505afa158015611405573d6000803e3d6000fd5b50506000805460ff1916931515939093179092555050565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561147c57600080fd5b505afa158015611490573d6000803e3d6000fd5b505050506127108111156114a357600080fd5b600c55565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561150757600080fd5b505afa15801561151b573d6000803e3d6000fd5b50505060039190915550565b6040516320b8029160e21b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906382e00a449060240160006040518083038186803b15801561158657600080fd5b505afa15801561159a573d6000803e3d6000fd5b505050506103848163ffffffff1610156115e95760405162461bcd60e51b815260206004820152601060248201526f6475726174696f6e20746f6f206c6f7760801b6044820152606401610747565b60005461160690600160281b90046001600160a01b031682612332565b6000805463ffffffff909216600160c81b0263ffffffff60c81b19909216919091179055565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561168b57600080fd5b505afa15801561169f573d6000803e3d6000fd5b505050506127108111156116b257600080fd5b600b55565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561171657600080fd5b505afa15801561172a573d6000803e3d6000fd5b5050505061089d8161241b565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561179657600080fd5b505afa1580156117aa573d6000803e3d6000fd5b5050506001600160801b0382811611801591506117d057506001600160801b0382811611155b6118085760405162461bcd60e51b8152602060048201526009602482015268746f6f206c6172676560b81b6044820152606401610747565b816001600160801b0316816001600160801b031610156118585760405162461bcd60e51b815260206004820152600b60248201526a3bb937b7339037b93232b960a91b6044820152606401610747565b600d546001600160801b03808416911610156118ab5760405162461bcd60e51b81526020600482015260126024820152716d696e417373657420746f6f206c6172676560701b6044820152606401610747565b604080518082019091526001600160801b03928316808252919092166020909201829052600160801b90910217600255565b6118e5611af1565b61089d8161247c565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b17905261193f848261251b565b610f22576040516001600160a01b0384166024820152600060448201526119a690859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526125c2565b610f2284826125c2565b6001600160a01b03163b151590565b60606119ce8484600085612697565b949350505050565b6040516001600160a01b038316602482015260448101829052611a0690849063a9059cbb60e01b9060640161196f565b505050565b6009546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a08231906024015b602060405180830381865afa158015611a55573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108aa9190612f29565b60008060059054906101000a90046001600160a01b03166001600160a01b0316632f13b60c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611acd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108aa9190612fd6565b333014611b285760405162461bcd60e51b815260206004820152600560248201526410b9b2b63360d91b6044820152606401610747565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bae9190612f29565b90506000611bba611fef565b611bc49083612f58565b905060008184611bd2611a0b565b611bdc9190612ff3565b611be6919061300a565b9050611bf1816120ff565b5050505050565b6000611c02611a79565b158015611c8e57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c8c9190612fd6565b155b15611cf3576000611c9d611fef565b604080518082019091526002546001600160801b03808216808452600160801b90920416602083015291925090821115611cf057611cf0611ceb8383602001516001600160801b0316612772565b612788565b50505b612710600c54612710611d069190612f58565b611d16611d11611a0b565b6129c0565b611d209190612ff3565b611d2a919061300a565b611d32611fef565b6108aa919061302c565b60005460ff16611d5657506000805460ff19166001179055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611db6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dda9190612f29565b905080821115611e4e5760005461271090611dfe90610100900461ffff1683612ff3565b611e08919061300a565b611e128284612f58565b111561138e5760405162461bcd60e51b815260206004820152600b60248201526a6865616c7468436865636b60a81b6044820152606401610747565b8181111561138e5760005461271090611e72906301000000900461ffff1683612ff3565b611e7c919061300a565b611e128383612f58565b60408051608081018252600d546001600160801b038116825265ffffffffffff600160801b820416602083015264ffffffffff600160b01b8204811693830193909352600160d81b90049091166060820152600090611ee3611a79565b158015611f105750806040015164ffffffffff16816060015164ffffffffff1642611f0e9190612f58565b115b8015611f2c575080516001600160801b0316611f2a611fef565b115b8015611f495750600254600160801b90046001600160801b031615155b8015611fd457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd29190612fd6565b155b15611feb57806020015165ffffffffffff16481091505b5090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401611a38565b6000811161207d5760405162461bcd60e51b815260206004820152600c60248201526b085e995c9bc81c1c9bd99a5d60a21b6044820152606401610747565b61ffff8111156120bb5760405162461bcd60e51b8152602060048201526009602482015268042e8dede40d0d2ced60bb1b6044820152606401610747565b6000805461ffff9092166101000262ffff0019909216919091179055565b61089d611ceb6120e7611fef565b600254600160801b90046001600160801b0316612772565b60008160000361211157506000919050565b612119611a79565b156121b357600a5460405163339748cb60e01b815273888888888889758f76e7103c6cbf23abbf58f9469163339748cb916121699130916001600160a01b03909116908790600090600401612f6b565b6020604051808303816000875af1158015612188573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ac9190612f29565b9150612265565b6121bb612c89565b60008054604051633346d3a360e01b815273888888888889758f76e7103c6cbf23abbf58f94692633346d3a39261220c923092600160281b9092046001600160a01b03169189918890600401613228565b60408051808303816000875af115801561222a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224e9190613262565b50925060008390036122635750600092915050565b505b60405163769f8e5d60e01b8152306004820152602481018390526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116604483015260006064830181905260848301527f0000000000000000000000000000000000000000000000000000000000000000169063769f8e5d9060a4016020604051808303816000875af1158015612308573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061232c9190612f29565b92915050565b60405162439f4b60e91b81526001600160a01b03838116600483015263ffffffff8316602483015260009182917f0000000000000000000000000000000000000000000000000000000000000000169063873e960090604401606060405180830381865afa1580156123a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123cc9190613286565b925050915081806123db575080155b15610f225760405162461bcd60e51b815260206004820152601060248201526f6f7261636c65206e6f7420726561647960801b6044820152606401610747565b612710811061245a5760405162461bcd60e51b815260206004820152600b60248201526a085b1bdcdcc81b1a5b5a5d60aa1b6044820152606401610747565b6000805461ffff90921663010000000264ffff00000019909216919091179055565b6000612486611a0b565b905080821115612494578091505b600061249f836129c0565b905060006124ac846120ff565b9050612710600b546127106124c19190612f58565b6124cb9084612ff3565b6124d5919061300a565b811015610f225760405162461bcd60e51b81526020600482015260146024820152731d1bdbc81b1a5d1d1b1948185b5bdd5b9d13dd5d60621b6044820152606401610747565b6000806000846001600160a01b03168460405161253891906132cf565b6000604051808303816000865af19150503d8060008114612575576040519150601f19603f3d011682016040523d82523d6000602084013e61257a565b606091505b50915091508180156125a45750805115806125a45750808060200190518101906125a49190612fd6565b80156125b957506001600160a01b0385163b15155b95945050505050565b6000612617826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166119bf9092919063ffffffff16565b90508051600014806126385750808060200190518101906126389190612fd6565b611a065760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610747565b6060824710156126f85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610747565b600080866001600160a01b0316858760405161271491906132cf565b60006040518083038185875af1925050503d8060008114612751576040519150601f19603f3d011682016040523d82523d6000602084013e612756565b606091505b509150915061276787838387612a64565b979650505050505050565b60008183106127815781610c7b565b5090919050565b6040516320e8c56560e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906320e8c565906127fb9030907f0000000000000000000000000000000000000000000000000000000000000000908690600090600401612f6b565b6020604051808303816000875af115801561281a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061283e9190612f29565b506040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156128a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c79190612f29565b90506128d1612c89565b6000612710600b546127106128e69190612f58565b6128ef85612add565b6128f99190612ff3565b612903919061300a565b600054604051630a94245f60e21b815291925073888888888889758f76e7103c6cbf23abbf58f94691632a50917c91612959913091600160281b90046001600160a01b031690889087906004908a9082016132eb565b60408051808303816000875af1158015612977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299b9190613262565b5050600d80546001600160d81b0316600160d81b4264ffffffffff1602179055505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cbe52ae37f0000000000000000000000000000000000000000000000000000000000000000612a1b85612ba3565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015612308573d6000803e3d6000fd5b60608315612ad3578251600003612acc576001600160a01b0385163b612acc5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610747565b50816119ce565b6119ce8383612c5f565b6000805460405163a31426d160e01b8152600160281b82046001600160a01b039081166004830152600160c81b90920463ffffffff1660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063a31426d190604401602060405180830381865afa158015612b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b879190612f29565b612b99670de0b6b3a764000084612ff3565b61232c919061300a565b6000805460405163a31426d160e01b8152600160281b82046001600160a01b039081166004830152600160c81b90920463ffffffff166024820152670de0b6b3a7640000917f0000000000000000000000000000000000000000000000000000000000000000169063a31426d190604401602060405180830381865afa158015612c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c559190612f29565b612b999084612ff3565b815115612c6f5781518083602001fd5b8060405162461bcd60e51b81526004016107479190613364565b6040518060a0016040528060006001600160a01b03168152602001600081526020016060815260200160608152602001606081525090565b6001600160a01b038116811461089d57600080fd5b600060208284031215612ce857600080fd5b8135610c7b81612cc1565b80356001600160801b0381168114610c9357600080fd5b600080600060608486031215612d1f57600080fd5b612d2884612cf3565b9250602084013565ffffffffffff81168114612d4357600080fd5b9150604084013564ffffffffff81168114612d5d57600080fd5b809150509250925092565b600060208284031215612d7a57600080fd5b5035919050565b60008060008060808587031215612d9757600080fd5b5050823594602084013594506040840135936060013592509050565b801515811461089d57600080fd5b60008060408385031215612dd457600080fd5b8235612ddf81612cc1565b91506020830135612def81612db3565b809150509250929050565b60005b83811015612e15578181015183820152602001612dfd565b50506000910152565b60008151808452612e36816020860160208601612dfa565b601f01601f19169290920160200192915050565b82151581526040602082015260006119ce6040830184612e1e565b600060208284031215612e7757600080fd5b8135610c7b81612db3565b60008060408385031215612e9557600080fd5b50508035926020909101359150565b60008060408385031215612eb757600080fd5b8235612ec281612cc1565b946020939093013593505050565b600060208284031215612ee257600080fd5b813563ffffffff81168114610c7b57600080fd5b60008060408385031215612f0957600080fd5b612f1283612cf3565b9150612f2060208401612cf3565b90509250929050565b600060208284031215612f3b57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561232c5761232c612f42565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b600080600060608486031215612fa957600080fd5b8351612fb481612cc1565b6020850151909350612fc581612cc1565b6040850151909250612d5d81612cc1565b600060208284031215612fe857600080fd5b8151610c7b81612db3565b808202811582820484141761232c5761232c612f42565b60008261302757634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111561232c5761232c612f42565b6004811061305d57634e487b7160e01b600052602160045260246000fd5b9052565b600081518084526020808501808196508360051b8101915082860160005b858110156131b757828403895281516060815181875280518288015287810151608081818a0152604091508183015160a081818c015285850151955060c091506130cb828c018761303f565b91840151945060e0916130e88b8401876001600160a01b03169052565b84015194506101006131048b8201876001600160a01b03169052565b908401519450610120906131228b8301876001600160a01b03169052565b918401519450610140916131408b8401876001600160a01b03169052565b8401516101608b81019190915290840151610180808c0191909152918401516101a08b01528301516101c08a019190915292506131816101e0890184612e1e565b92508884015191508783038989015261319a8383612e1e565b93810151970196909652509885019893509084019060010161307f565b5091979650505050505050565b60018060a01b038151168252602081015160208301526000604082015160a060408501526131f560a0850182613061565b90506060830151848203606086015261320e8282613061565b915050608083015184820360808601526125b98282612e1e565b6001600160a01b03868116825285166020820152604081018490526060810183905260a060808201819052600090612767908301846131c4565b6000806040838503121561327557600080fd5b505080516020909101519092909150565b60008060006060848603121561329b57600080fd5b83516132a681612db3565b602085015190935061ffff811681146132be57600080fd5b6040850151909250612d5d81612db3565b600082516132e1818460208701612dfa565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905282546080820152600183015460a0820152600283015460c0820152600383015460e082015260048301546101008201526101406101208201819052600090613357838201856131c4565b9998505050505050505050565b602081526000610c7b6020830184612e1e56fea264697066735822122080aa6f66d3610913017e3c5a184bde24093d96e2dfe9bd5e62ab7b7ce4dbbc9664736f6c63430008120033a2646970667358221220b51a462e32e4cfad9298aff78f080ace9af6f1ba5ed9397c6648bb8a1eabfb4a64736f6c634300081200330000000000000000000000006ba1734209a53a6e63c39d4e36612cc856a34d560000000000000000000000006ba1734209a53a6e63c39d4e36612cc856a34d56000000000000000000000000604e586f17ce106b64185a7a0d2c1da5bace711e00000000000000000000000066a1096c6366b2529274df4f5d8247827fe4cea800000000000000000000000016388463d60ffe0661cf7f1f31a7d658ac790ff7000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff52
Deployed Bytecode
0x60806040523480156200001157600080fd5b5060043610620001095760003560e01c806388a8d60211620000a3578063d4a22bde116200006e578063d4a22bde146200027d578063db90b1e01462000294578063ed27f7c914620002c3578063f987e55d14620002d757600080fd5b806388a8d602146200022757806397256094146200023b578063a22d7f631462000252578063aced1661146200026957600080fd5b80636a5f1aa211620000e45780636a5f1aa214620001a757806370905dce14620001c0578063748747e614620001e85780637dc0d1d014620001ff57600080fd5b80630d004424146200010e578063180cb47f146200013a5780634a3e6544146200017b575b600080fd5b620001256200011f36600462000c68565b620002ee565b60405190151581526020015b60405180910390f35b620001627f000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff5281565b6040516001600160a01b03909116815260200162000131565b620001626200018c36600462000c68565b6003602052600090815260409020546001600160a01b031681565b620001be620001b836600462000c68565b6200037e565b005b620001627f00000000000000000000000016388463d60ffe0661cf7f1f31a7d658ac790ff781565b620001be620001f936600462000c68565b6200041d565b620001627f00000000000000000000000066a1096c6366b2529274df4f5d8247827fe4cea881565b60005462000162906001600160a01b031681565b620001be6200024c36600462000c8f565b6200046c565b620001626200026336600462000dab565b620004c7565b60025462000162906001600160a01b031681565b620001be6200028e36600462000c68565b620008e9565b62000162620002a536600462000c68565b6001600160a01b039081166000908152600360205260409020541690565b60015462000162906001600160a01b031681565b62000162620002e836600462000e89565b6200097f565b600080826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000330573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000356919062000ef3565b6001600160a01b03908116600090815260036020526040902054811693169290921492915050565b6000546001600160a01b03163314620003b45760405162461bcd60e51b8152600401620003ab9062000f13565b60405180910390fd5b6001600160a01b038116620003fb5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401620003ab565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146200044a5760405162461bcd60e51b8152600401620003ab9062000f13565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314620004995760405162461bcd60e51b8152600401620003ab9062000f13565b6001600160a01b03918216600090815260036020526040902080546001600160a01b03191691909216179055565b600080546001600160a01b03163314620004f55760405162461bcd60e51b8152600401620003ab9062000f13565b60008a8a7f00000000000000000000000066a1096c6366b2529274df4f5d8247827fe4cea87f000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff52866040516200054a9062000c41565b6200055a95949392919062000f38565b604051809103906000f08015801562000577573d6000803e3d6000fd5b5060015460405163352f8d5160e11b81526001600160a01b039182166004820152919250821690636a5f1aa290602401600060405180830381600087803b158015620005c257600080fd5b505af1158015620005d7573d6000803e3d6000fd5b5050600254604051633a43a3f360e11b81526001600160a01b039182166004820152908416925063748747e69150602401600060405180830381600087803b1580156200062357600080fd5b505af115801562000638573d6000803e3d6000fd5b5050600054604051630f629b7960e41b81526001600160a01b039182166004820152908416925063f629b7909150602401600060405180830381600087803b1580156200068457600080fd5b505af115801562000699573d6000803e3d6000fd5b5050604051630d768ce560e21b81526001600160a01b037f00000000000000000000000016388463d60ffe0661cf7f1f31a7d658ac790ff781166004830152841692506335da33949150602401600060405180830381600087803b1580156200070157600080fd5b505af115801562000716573d6000803e3d6000fd5b5050604051633ba24f8160e01b81526001600160801b038916600482015265ffffffffffff8816602482015264ffffffffff871660448201526001600160a01b0384169250633ba24f819150606401600060405180830381600087803b1580156200078057600080fd5b505af115801562000795573d6000803e3d6000fd5b505060405163f462bbff60e01b81526001600160801b03808d1660048301528b1660248201526001600160a01b038416925063f462bbff9150604401600060405180830381600087803b158015620007ec57600080fd5b505af115801562000801573d6000803e3d6000fd5b5050505060001987146200086c5760405163bdc8144b60e01b8152600481018890526001600160a01b0382169063bdc8144b90602401600060405180830381600087803b1580156200085257600080fd5b505af115801562000867573d6000803e3d6000fd5b505050505b8a6001600160a01b0316816001600160a01b03167f4e26313b1dea133965fe2d5a105476115b8bbaf3300e207b839d078fb334266060405160405180910390a36001600160a01b039a8b16600090815260036020526040902080546001600160a01b0319169b82169b909b17909a55509798975050505050505050565b6000546001600160a01b03163314620009165760405162461bcd60e51b8152600401620003ab9062000f13565b6001600160a01b0381166200095d5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401620003ab565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b600080546001600160a01b03163314620009ad5760405162461bcd60e51b8152600401620003ab9062000f13565b600084847f00000000000000000000000066a1096c6366b2529274df4f5d8247827fe4cea87f000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff528660405162000a029062000c41565b62000a1295949392919062000f38565b604051809103906000f08015801562000a2f573d6000803e3d6000fd5b5060015460405163352f8d5160e11b81526001600160a01b039182166004820152919250821690636a5f1aa290602401600060405180830381600087803b15801562000a7a57600080fd5b505af115801562000a8f573d6000803e3d6000fd5b5050600254604051633a43a3f360e11b81526001600160a01b039182166004820152908416925063748747e69150602401600060405180830381600087803b15801562000adb57600080fd5b505af115801562000af0573d6000803e3d6000fd5b5050600054604051630f629b7960e41b81526001600160a01b039182166004820152908416925063f629b7909150602401600060405180830381600087803b15801562000b3c57600080fd5b505af115801562000b51573d6000803e3d6000fd5b5050604051630d768ce560e21b81526001600160a01b037f00000000000000000000000016388463d60ffe0661cf7f1f31a7d658ac790ff781166004830152841692506335da33949150602401600060405180830381600087803b15801562000bb957600080fd5b505af115801562000bce573d6000803e3d6000fd5b50506040516001600160a01b038089169350841691507f4e26313b1dea133965fe2d5a105476115b8bbaf3300e207b839d078fb334266090600090a36001600160a01b03948516600090815260036020526040902080546001600160a01b03191695821695909517909455509192915050565b6141e58062000fb783390190565b6001600160a01b038116811462000c6557600080fd5b50565b60006020828403121562000c7b57600080fd5b813562000c888162000c4f565b9392505050565b6000806040838503121562000ca357600080fd5b823562000cb08162000c4f565b9150602083013562000cc28162000c4f565b809150509250929050565b80356001600160801b038116811462000ce557600080fd5b919050565b803564ffffffffff8116811462000ce557600080fd5b634e487b7160e01b600052604160045260246000fd5b600082601f83011262000d2857600080fd5b813567ffffffffffffffff8082111562000d465762000d4662000d00565b604051601f8301601f19908116603f0116810190828211818310171562000d715762000d7162000d00565b8160405283815286602085880101111562000d8b57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060008060008060008060006101208a8c03121562000dcb57600080fd5b893562000dd88162000c4f565b985060208a013562000dea8162000c4f565b975062000dfa60408b0162000ccd565b965062000e0a60608b0162000ccd565b955060808a0135945062000e2160a08b0162000ccd565b935060c08a013565ffffffffffff8116811462000e3d57600080fd5b925062000e4d60e08b0162000cea565b91506101008a013567ffffffffffffffff81111562000e6b57600080fd5b62000e798c828d0162000d16565b9150509295985092959850929598565b60008060006060848603121562000e9f57600080fd5b833562000eac8162000c4f565b9250602084013562000ebe8162000c4f565b9150604084013567ffffffffffffffff81111562000edb57600080fd5b62000ee98682870162000d16565b9150509250925092565b60006020828403121562000f0657600080fd5b815162000c888162000c4f565b6020808252600b908201526a085b585b9859d95b595b9d60aa1b604082015260600190565b600060018060a01b0380881683526020818816818501528187166040850152818616606085015260a06080850152845191508160a085015260005b8281101562000f915785810182015185820160c00152810162000f73565b5050600060c0828501015260c0601f19601f830116840101915050969550505050505056fe6101206040526000805462ffffff60ff60e81b01191662271001600160e81b011790556000196003553480156200003557600080fd5b50604051620041e5380380620041e5833981016040819052620000589162000af4565b6001600160a01b0385166080523060a0526040518590829082908290620000c59062000091908490849033908190819060240162000c28565b60408051601f198184030181529190526020810180516001600160e01b03908116634b839d7360e11b17909152620004c116565b505073bb51273d6c746910c7c06fe718f30c936170fed07f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc55505060008054600160281b600160c81b031916650100000000006001600160a01b03881602179055506200013162000555565b156200016e5760405162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b60448201526064015b60405180910390fd5b6001600160a01b0383811660c0526000805463ffffffff60c81b191660e160cc1b179055600280546001600160801b031665340aad21b3b760921b17905560408051630b2339af60e21b8152905191861691632c8ce6bc916004808201926060929091908290030181865afa158015620001ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000212919062000c6b565b600a80546001600160a01b03199081166001600160a01b0393841617909155600980549091169282169290921790915590811660e0819052604051633c21b3eb60e11b815291871660048301529063784367d690602401602060405180830381865afa15801562000287573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002ad919062000cb5565b620002e85760405162461bcd60e51b815260206004820152600a602482015269085d985b1a59081bdd5d60b21b604482015260640162000165565b60e051604051637d2d278360e11b81526001600160a01b0387811660048301529091169063fa5a4f0690602401602060405180830381865afa15801562000333573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000359919062000cb5565b620003935760405162461bcd60e51b815260206004820152600960248201526810bb30b634b21034b760b91b604482015260640162000165565b6032600b819055600c5560001960055561010060075566038d7ea4c680006008556040805160808101825260006060820152674563918244f4000081526404a817c800602082015261a8c09181019190915277a8c00004a817c80000000000000000004563918244f40000600d556200040e61c350620005d5565b6001600160a01b038381166101005260e0516200043d9188169060001962000674602090811b620018ee17901c565b6200047a73888888888889758f76e7103c6cbf23abbf58f94660001960e0516001600160a01b03166200067460201b620018ee179092919060201c565b600954620004b5906001600160a01b031673888888888889758f76e7103c6cbf23abbf58f94660001962000674602090811b620018ee17901c565b50505050505062000d0c565b606060008073bb51273d6c746910c7c06fe718f30c936170fed06001600160a01b031684604051620004f4919062000cd9565b600060405180830381855af49150503d806000811462000531576040519150601f19603f3d011682016040523d82523d6000602084013e62000536565b606091505b5091509150816200054e576040513d806000833e8082fd5b9392505050565b60008060059054906101000a90046001600160a01b03166001600160a01b0316632f13b60c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620005aa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620005d0919062000cb5565b905090565b60008111620006165760405162461bcd60e51b815260206004820152600c60248201526b085e995c9bc81c1c9bd99a5d60a21b604482015260640162000165565b61ffff811115620006565760405162461bcd60e51b8152602060048201526009602482015268042e8dede40d0d2ced60bb1b604482015260640162000165565b6000805461ffff9092166101000262ffff0019909216919091179055565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b17909152620006ce90859083906200074a16565b62000744576040516001600160a01b0384166024820152600060448201526200073890859063095ea7b360e01b9060640160408051808303601f190181529190526020810180516001600160e01b0319939093166001600160e01b03938416179052906200080216565b62000744848262000802565b50505050565b6000806000846001600160a01b03168460405162000769919062000cd9565b6000604051808303816000865af19150503d8060008114620007a8576040519150601f19603f3d011682016040523d82523d6000602084013e620007ad565b606091505b5091509150818015620007db575080511580620007db575080806020019051810190620007db919062000cb5565b8015620007f95750620007f985620008e860201b620019b01760201c565b95945050505050565b60006200085e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316620008f760201b620019bf179092919060201c565b90508051600014806200088257508080602001905181019062000882919062000cb5565b620008e35760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000165565b505050565b6001600160a01b03163b151590565b606062000908848460008562000910565b949350505050565b606082471015620009735760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000165565b600080866001600160a01b0316858760405162000991919062000cd9565b60006040518083038185875af1925050503d8060008114620009d0576040519150601f19603f3d011682016040523d82523d6000602084013e620009d5565b606091505b509092509050620009e987838387620009f4565b979650505050505050565b6060831562000a6857825160000362000a60576001600160a01b0385163b62000a605760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000165565b508162000908565b62000908838381511562000a7f5781518083602001fd5b8060405162461bcd60e51b815260040162000165919062000cf7565b80516001600160a01b038116811462000ab357600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000aeb57818101518382015260200162000ad1565b50506000910152565b600080600080600060a0868803121562000b0d57600080fd5b62000b188662000a9b565b945062000b286020870162000a9b565b935062000b386040870162000a9b565b925062000b486060870162000a9b565b60808701519092506001600160401b038082111562000b6657600080fd5b818801915088601f83011262000b7b57600080fd5b81518181111562000b905762000b9062000ab8565b604051601f8201601f19908116603f0116810190838211818310171562000bbb5762000bbb62000ab8565b816040528281528b602084870101111562000bd557600080fd5b62000be883602083016020880162000ace565b80955050505050509295509295909350565b6000815180845262000c1481602086016020860162000ace565b601f01601f19169290920160200192915050565b600060018060a01b03808816835260a0602084015262000c4c60a084018862000bfa565b9581166040840152938416606083015250911660809091015292915050565b60008060006060848603121562000c8157600080fd5b62000c8c8462000a9b565b925062000c9c6020850162000a9b565b915062000cac6040850162000a9b565b90509250925092565b60006020828403121562000cc857600080fd5b815180151581146200054e57600080fd5b6000825162000ced81846020870162000ace565b9190910192915050565b6020815260006200054e602083018462000bfa565b60805160a05160c05160e051610100516133ad62000e386000396000818161032b015281816106f1015281816108170152610f330152600081816105a5015281816111ef0152818161131b015281816122bf0152818161279f0152818161285401526129c401526000818161236101528181612b1a0152612bea0152600081816108ce01528181610a9001528181610b1b01528181610be101528181610d1301528181610db301528181610e44015281816113a701528181611432015281816114bd0152818161153c01528181611641015281816116cc0152818161174c01528181611b2e01528181611c0c01528181611d5a0152611f52015260008181610752015281816112e50152818161200701528181612289015281816127ce01526129f301526133ad6000f3fe608060405234801561001057600080fd5b50600436106102695760003560e01c80637d96993211610151578063c05bd92d116100c3578063d696860111610087578063d69686011461067d578063d94073d414610690578063ecf70858146106a3578063f462bbff146106ac578063fcfff16f146106bf578063fde813a8146106d357610269565b8063c05bd92d146105ed578063cefba47414610600578063cf683c701461062c578063d19a3bb81461063f578063d63a8e111461065a57610269565b8063a4a7799511610115578063a4a77995146104ff578063ab1c99941461057a578063ac00ff261461058d578063afd27bf5146105a0578063bc06b529146105c7578063bdc8144b146105da57610269565b80637d9699321461049957806380f55605146104ac578063950b3d73146104c65780639d7fb70c146104d9578063a0ef795b146104ec57610269565b80633d6cb575116101ea5780634a5d0943116101ae5780634a5d094314610437578063503160d9146104485780635d265d3f1461045b5780636718835f146104715780636fdca5e01461047e578063797bf3431461049157610269565b80633d6cb575146103e357806345b1993f146103f65780634697f05d1461040957806346aa2f121461041c57806349317f1d1461042f57610269565b80631eab62a9116102315780631eab62a914610365578063256d8a231461036e5780632b24a878146103b05780632f13b60c146103b85780633ba24f81146103d057610269565b806301681a62146102a457806304bd4629146102b757806309b2c8a8146102df5780631809bca51461031d578063180cb47f14610326575b73bb51273d6c746910c7c06fe718f30c936170fed03660008037600080366000845af43d6000803e80801561029d573d6000f35b3d6000fd5b005b6102a26102b2366004612cd6565b6106e6565b6102cc6102c5366004612cd6565b5060001990565b6040519081526020015b60405180910390f35b6002546102fd906001600160801b0380821691600160801b90041682565b604080516001600160801b039384168152929091166020830152016102d6565b6102cc600c5481565b61034d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016102d6565b6102cc600b5481565b600454600554600654600754600854610388949392919085565b604080519586526020860194909452928401919091526060830152608082015260a0016102d6565b6102cc6108a0565b6103c06108af565b60405190151581526020016102d6565b6102a26103de366004612d0a565b6108b9565b6102a26103f1366004612d68565b610a6a565b6102a2610404366004612d81565b610a7b565b6102a2610417366004612dc1565b610b06565b6102cc61042a366004612cd6565b610ba8565b6102cc610c98565b600054610100900461ffff166102cc565b6102a2610456366004612d68565b610cb8565b610463610cc0565b6040516102d6929190612e4a565b6000546103c09060ff1681565b6102a261048c366004612e65565b610cfe565b6102cc610d94565b6000546301000000900461ffff166102cc565b60005461034d90600160281b90046001600160a01b031681565b6102a26104d4366004612d68565b610d9e565b6102a26104e7366004612d68565b610e1e565b6102a26104fa366004612e82565b610e2f565b600d5461053c906001600160801b0381169065ffffffffffff600160801b8204169064ffffffffff600160b01b8204811691600160d81b90041684565b604080516001600160801b03909516855265ffffffffffff909316602085015264ffffffffff918216928401929092521660608201526080016102d6565b6102a2610588366004612ea4565b610f28565b6102a261059b366004612e65565b611392565b61034d7f000000000000000000000000000000000000000000000000000000000000000081565b6102a26105d5366004612d68565b61141d565b6102a26105e8366004612d68565b6114a8565b6102a26105fb366004612ed0565b611527565b60005461061790600160c81b900463ffffffff1681565b60405163ffffffff90911681526020016102d6565b6102a261063a366004612d68565b61162c565b61034d73bb51273d6c746910c7c06fe718f30c936170fed081565b6103c0610668366004612cd6565b60016020526000908152604090205460ff1681565b6102a261068b366004612d68565b6116b7565b60095461034d906001600160a01b031681565b6102cc60035481565b6102a26106ba366004612ef6565b611737565b6000546103c090600160e81b900460ff1681565b6102a26106e1366004612d68565b6118dd565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146107505760405162461bcd60e51b81526004016107479060208082526004908201526310b3b7bb60e11b604082015260600190565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036107ba5760405162461bcd60e51b815260206004820152600660248201526508585cdcd95d60d21b6044820152606401610747565b6009546001600160a01b03908116908216036107fe5760405162461bcd60e51b815260206004820152600360248201526208541560ea1b6044820152606401610747565b6040516370a0823160e01b815230600482015261089d907f0000000000000000000000000000000000000000000000000000000000000000906001600160a01b038416906370a0823190602401602060405180830381865afa158015610868573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088c9190612f29565b6001600160a01b03841691906119d6565b50565b60006108aa611a0b565b905090565b60006108aa611a79565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561091857600080fd5b505afa15801561092c573d6000803e3d6000fd5b5050505060008164ffffffffff161161097a5760405162461bcd60e51b815260206004820152601060248201526f696e74657276616c20746f6f206c6f7760801b6044820152606401610747565b6001600160801b0383811611156109bf5760405162461bcd60e51b8152602060048201526009602482015268746f6f206c6172676560b81b6044820152606401610747565b6002546001600160801b039081169084161015610a125760405162461bcd60e51b81526020600482015260116024820152701d1c9a59d9d95c881d1bdbc81cdb585b1b607a1b6044820152606401610747565b600d805464ffffffffff909216600160b01b0264ffffffffff60b01b1965ffffffffffff909416600160801b026001600160b01b03199093166001600160801b03909516949094179190911791909116919091179055565b610a72611af1565b61089d81611b2a565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610ada57600080fd5b505afa158015610aee573d6000803e3d6000fd5b50505060049490945560059290925560075560085550565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610b6557600080fd5b505afa158015610b79573d6000803e3d6000fd5b505050506001600160a01b03919091166000908152600160205260409020805460ff1916911515919091179055565b6001600160a01b03811660009081526001602052604081205460ff1680610bd85750600054600160e81b900460ff165b15610c8b5760007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c619190612f29565b9050806003541115610c825780600354610c7b9190612f58565b9392505050565b50600092915050565b506000919050565b919050565b6000610ca2611af1565b610caa611bf8565b9050610cb581611d3c565b90565b61089d611af1565b60006060610ccc611e86565b6040805160048152602481019091526020810180516001600160e01b031663440368a360e01b17905290939092509050565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610d5d57600080fd5b505afa158015610d71573d6000803e3d6000fd5b505060008054931515600160e81b0260ff60e81b19909416939093179092555050565b60006108aa611fef565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b158015610dfd57600080fd5b505afa158015610e11573d6000803e3d6000fd5b5050505061089d8161203e565b610e26611af1565b61089d816120d9565b6040516320b8029160e21b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906382e00a449060240160006040518083038186803b158015610e8e57600080fd5b505afa158015610ea2573d6000803e3d6000fd5b5050600280546001600160801b031690555060009050610ec0611a0b565b905080831115610ece578092505b6000610ed9846120ff565b905082811015610f225760405162461bcd60e51b81526020600482015260146024820152731d1bdbc81b1a5d1d1b1948185b5bdd5b9d13dd5d60621b6044820152606401610747565b50505050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f895760405162461bcd60e51b81526004016107479060208082526004908201526310b3b7bb60e11b604082015260600190565b610f91611a79565b610fcb5760405162461bcd60e51b815260206004820152600b60248201526a1b9bdd08195e1c1a5c995960aa1b6044820152606401610747565b6001600160a01b03821661100b5760405162461bcd60e51b8152602060048201526007602482015266085b585c9ad95d60ca1b6044820152606401610747565b6000546001600160a01b03808416600160281b909204160361105d5760405162461bcd60e51b815260206004820152600b60248201526a1cd85b59481b585c9ad95d60aa1b6044820152606401610747565b600054611078908390600160c81b900463ffffffff16612332565b6000611082611a0b565b9050801561111b57600a5460405163339748cb60e01b815273888888888889758f76e7103c6cbf23abbf58f9469163339748cb916110d59130916001600160a01b03909116908690600090600401612f6b565b6020604051808303816000875af11580156110f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111189190612f29565b90505b6000805465010000000000600160c81b031916600160281b6001600160a01b03861602179055611149611a79565b156111805760405162461bcd60e51b8152602060048201526007602482015266195e1c1a5c995960ca1b6044820152606401610747565b6000806000856001600160a01b0316632c8ce6bc6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156111c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e79190612f94565b9250925092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316146112595760405162461bcd60e51b815260206004820152600860248201526777726f6e6720535960c01b6044820152606401610747565b600980546001600160a01b038085166001600160a01b03199283168117909355600a8054918516919092161790556112a89073888888888889758f76e7103c6cbf23abbf58f9466000196118ee565b831580156112b4575084155b156112c157505050505050565b60405163769f8e5d60e01b8152306004820152602481018590526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116604483015260648201879052600060848301527f0000000000000000000000000000000000000000000000000000000000000000169063769f8e5d9060a4016020604051808303816000875af1158015611364573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113889190612f29565b50505050505b5050565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b1580156113f157600080fd5b505afa158015611405573d6000803e3d6000fd5b50506000805460ff1916931515939093179092555050565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561147c57600080fd5b505afa158015611490573d6000803e3d6000fd5b505050506127108111156114a357600080fd5b600c55565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561150757600080fd5b505afa15801561151b573d6000803e3d6000fd5b50505060039190915550565b6040516320b8029160e21b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906382e00a449060240160006040518083038186803b15801561158657600080fd5b505afa15801561159a573d6000803e3d6000fd5b505050506103848163ffffffff1610156115e95760405162461bcd60e51b815260206004820152601060248201526f6475726174696f6e20746f6f206c6f7760801b6044820152606401610747565b60005461160690600160281b90046001600160a01b031682612332565b6000805463ffffffff909216600160c81b0263ffffffff60c81b19909216919091179055565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561168b57600080fd5b505afa15801561169f573d6000803e3d6000fd5b505050506127108111156116b257600080fd5b600b55565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561171657600080fd5b505afa15801561172a573d6000803e3d6000fd5b5050505061089d8161241b565b6040516348e4a64960e01b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906348e4a6499060240160006040518083038186803b15801561179657600080fd5b505afa1580156117aa573d6000803e3d6000fd5b5050506001600160801b0382811611801591506117d057506001600160801b0382811611155b6118085760405162461bcd60e51b8152602060048201526009602482015268746f6f206c6172676560b81b6044820152606401610747565b816001600160801b0316816001600160801b031610156118585760405162461bcd60e51b815260206004820152600b60248201526a3bb937b7339037b93232b960a91b6044820152606401610747565b600d546001600160801b03808416911610156118ab5760405162461bcd60e51b81526020600482015260126024820152716d696e417373657420746f6f206c6172676560701b6044820152606401610747565b604080518082019091526001600160801b03928316808252919092166020909201829052600160801b90910217600255565b6118e5611af1565b61089d8161247c565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b17905261193f848261251b565b610f22576040516001600160a01b0384166024820152600060448201526119a690859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526125c2565b610f2284826125c2565b6001600160a01b03163b151590565b60606119ce8484600085612697565b949350505050565b6040516001600160a01b038316602482015260448101829052611a0690849063a9059cbb60e01b9060640161196f565b505050565b6009546040516370a0823160e01b81523060048201526000916001600160a01b0316906370a08231906024015b602060405180830381865afa158015611a55573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108aa9190612f29565b60008060059054906101000a90046001600160a01b03166001600160a01b0316632f13b60c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611acd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108aa9190612fd6565b333014611b285760405162461bcd60e51b815260206004820152600560248201526410b9b2b63360d91b6044820152606401610747565b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bae9190612f29565b90506000611bba611fef565b611bc49083612f58565b905060008184611bd2611a0b565b611bdc9190612ff3565b611be6919061300a565b9050611bf1816120ff565b5050505050565b6000611c02611a79565b158015611c8e57507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c68573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c8c9190612fd6565b155b15611cf3576000611c9d611fef565b604080518082019091526002546001600160801b03808216808452600160801b90920416602083015291925090821115611cf057611cf0611ceb8383602001516001600160801b0316612772565b612788565b50505b612710600c54612710611d069190612f58565b611d16611d11611a0b565b6129c0565b611d209190612ff3565b611d2a919061300a565b611d32611fef565b6108aa919061302c565b60005460ff16611d5657506000805460ff19166001179055565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166301e1d1146040518163ffffffff1660e01b8152600401602060405180830381865afa158015611db6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dda9190612f29565b905080821115611e4e5760005461271090611dfe90610100900461ffff1683612ff3565b611e08919061300a565b611e128284612f58565b111561138e5760405162461bcd60e51b815260206004820152600b60248201526a6865616c7468436865636b60a81b6044820152606401610747565b8181111561138e5760005461271090611e72906301000000900461ffff1683612ff3565b611e7c919061300a565b611e128383612f58565b60408051608081018252600d546001600160801b038116825265ffffffffffff600160801b820416602083015264ffffffffff600160b01b8204811693830193909352600160d81b90049091166060820152600090611ee3611a79565b158015611f105750806040015164ffffffffff16816060015164ffffffffff1642611f0e9190612f58565b115b8015611f2c575080516001600160801b0316611f2a611fef565b115b8015611f495750600254600160801b90046001600160801b031615155b8015611fd457507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663bf86d6906040518163ffffffff1660e01b8152600401602060405180830381865afa158015611fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd29190612fd6565b155b15611feb57806020015165ffffffffffff16481091505b5090565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401611a38565b6000811161207d5760405162461bcd60e51b815260206004820152600c60248201526b085e995c9bc81c1c9bd99a5d60a21b6044820152606401610747565b61ffff8111156120bb5760405162461bcd60e51b8152602060048201526009602482015268042e8dede40d0d2ced60bb1b6044820152606401610747565b6000805461ffff9092166101000262ffff0019909216919091179055565b61089d611ceb6120e7611fef565b600254600160801b90046001600160801b0316612772565b60008160000361211157506000919050565b612119611a79565b156121b357600a5460405163339748cb60e01b815273888888888889758f76e7103c6cbf23abbf58f9469163339748cb916121699130916001600160a01b03909116908790600090600401612f6b565b6020604051808303816000875af1158015612188573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121ac9190612f29565b9150612265565b6121bb612c89565b60008054604051633346d3a360e01b815273888888888889758f76e7103c6cbf23abbf58f94692633346d3a39261220c923092600160281b9092046001600160a01b03169189918890600401613228565b60408051808303816000875af115801561222a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224e9190613262565b50925060008390036122635750600092915050565b505b60405163769f8e5d60e01b8152306004820152602481018390526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116604483015260006064830181905260848301527f0000000000000000000000000000000000000000000000000000000000000000169063769f8e5d9060a4016020604051808303816000875af1158015612308573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061232c9190612f29565b92915050565b60405162439f4b60e91b81526001600160a01b03838116600483015263ffffffff8316602483015260009182917f0000000000000000000000000000000000000000000000000000000000000000169063873e960090604401606060405180830381865afa1580156123a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123cc9190613286565b925050915081806123db575080155b15610f225760405162461bcd60e51b815260206004820152601060248201526f6f7261636c65206e6f7420726561647960801b6044820152606401610747565b612710811061245a5760405162461bcd60e51b815260206004820152600b60248201526a085b1bdcdcc81b1a5b5a5d60aa1b6044820152606401610747565b6000805461ffff90921663010000000264ffff00000019909216919091179055565b6000612486611a0b565b905080821115612494578091505b600061249f836129c0565b905060006124ac846120ff565b9050612710600b546127106124c19190612f58565b6124cb9084612ff3565b6124d5919061300a565b811015610f225760405162461bcd60e51b81526020600482015260146024820152731d1bdbc81b1a5d1d1b1948185b5bdd5b9d13dd5d60621b6044820152606401610747565b6000806000846001600160a01b03168460405161253891906132cf565b6000604051808303816000865af19150503d8060008114612575576040519150601f19603f3d011682016040523d82523d6000602084013e61257a565b606091505b50915091508180156125a45750805115806125a45750808060200190518101906125a49190612fd6565b80156125b957506001600160a01b0385163b15155b95945050505050565b6000612617826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166119bf9092919063ffffffff16565b90508051600014806126385750808060200190518101906126389190612fd6565b611a065760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610747565b6060824710156126f85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610747565b600080866001600160a01b0316858760405161271491906132cf565b60006040518083038185875af1925050503d8060008114612751576040519150601f19603f3d011682016040523d82523d6000602084013e612756565b606091505b509150915061276787838387612a64565b979650505050505050565b60008183106127815781610c7b565b5090919050565b6040516320e8c56560e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906320e8c565906127fb9030907f0000000000000000000000000000000000000000000000000000000000000000908690600090600401612f6b565b6020604051808303816000875af115801561281a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061283e9190612f29565b506040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156128a3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c79190612f29565b90506128d1612c89565b6000612710600b546127106128e69190612f58565b6128ef85612add565b6128f99190612ff3565b612903919061300a565b600054604051630a94245f60e21b815291925073888888888889758f76e7103c6cbf23abbf58f94691632a50917c91612959913091600160281b90046001600160a01b031690889087906004908a9082016132eb565b60408051808303816000875af1158015612977573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061299b9190613262565b5050600d80546001600160d81b0316600160d81b4264ffffffffff1602179055505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cbe52ae37f0000000000000000000000000000000000000000000000000000000000000000612a1b85612ba3565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381865afa158015612308573d6000803e3d6000fd5b60608315612ad3578251600003612acc576001600160a01b0385163b612acc5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610747565b50816119ce565b6119ce8383612c5f565b6000805460405163a31426d160e01b8152600160281b82046001600160a01b039081166004830152600160c81b90920463ffffffff1660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063a31426d190604401602060405180830381865afa158015612b63573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b879190612f29565b612b99670de0b6b3a764000084612ff3565b61232c919061300a565b6000805460405163a31426d160e01b8152600160281b82046001600160a01b039081166004830152600160c81b90920463ffffffff166024820152670de0b6b3a7640000917f0000000000000000000000000000000000000000000000000000000000000000169063a31426d190604401602060405180830381865afa158015612c31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c559190612f29565b612b999084612ff3565b815115612c6f5781518083602001fd5b8060405162461bcd60e51b81526004016107479190613364565b6040518060a0016040528060006001600160a01b03168152602001600081526020016060815260200160608152602001606081525090565b6001600160a01b038116811461089d57600080fd5b600060208284031215612ce857600080fd5b8135610c7b81612cc1565b80356001600160801b0381168114610c9357600080fd5b600080600060608486031215612d1f57600080fd5b612d2884612cf3565b9250602084013565ffffffffffff81168114612d4357600080fd5b9150604084013564ffffffffff81168114612d5d57600080fd5b809150509250925092565b600060208284031215612d7a57600080fd5b5035919050565b60008060008060808587031215612d9757600080fd5b5050823594602084013594506040840135936060013592509050565b801515811461089d57600080fd5b60008060408385031215612dd457600080fd5b8235612ddf81612cc1565b91506020830135612def81612db3565b809150509250929050565b60005b83811015612e15578181015183820152602001612dfd565b50506000910152565b60008151808452612e36816020860160208601612dfa565b601f01601f19169290920160200192915050565b82151581526040602082015260006119ce6040830184612e1e565b600060208284031215612e7757600080fd5b8135610c7b81612db3565b60008060408385031215612e9557600080fd5b50508035926020909101359150565b60008060408385031215612eb757600080fd5b8235612ec281612cc1565b946020939093013593505050565b600060208284031215612ee257600080fd5b813563ffffffff81168114610c7b57600080fd5b60008060408385031215612f0957600080fd5b612f1283612cf3565b9150612f2060208401612cf3565b90509250929050565b600060208284031215612f3b57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561232c5761232c612f42565b6001600160a01b0394851681529290931660208301526040820152606081019190915260800190565b600080600060608486031215612fa957600080fd5b8351612fb481612cc1565b6020850151909350612fc581612cc1565b6040850151909250612d5d81612cc1565b600060208284031215612fe857600080fd5b8151610c7b81612db3565b808202811582820484141761232c5761232c612f42565b60008261302757634e487b7160e01b600052601260045260246000fd5b500490565b8082018082111561232c5761232c612f42565b6004811061305d57634e487b7160e01b600052602160045260246000fd5b9052565b600081518084526020808501808196508360051b8101915082860160005b858110156131b757828403895281516060815181875280518288015287810151608081818a0152604091508183015160a081818c015285850151955060c091506130cb828c018761303f565b91840151945060e0916130e88b8401876001600160a01b03169052565b84015194506101006131048b8201876001600160a01b03169052565b908401519450610120906131228b8301876001600160a01b03169052565b918401519450610140916131408b8401876001600160a01b03169052565b8401516101608b81019190915290840151610180808c0191909152918401516101a08b01528301516101c08a019190915292506131816101e0890184612e1e565b92508884015191508783038989015261319a8383612e1e565b93810151970196909652509885019893509084019060010161307f565b5091979650505050505050565b60018060a01b038151168252602081015160208301526000604082015160a060408501526131f560a0850182613061565b90506060830151848203606086015261320e8282613061565b915050608083015184820360808601526125b98282612e1e565b6001600160a01b03868116825285166020820152604081018490526060810183905260a060808201819052600090612767908301846131c4565b6000806040838503121561327557600080fd5b505080516020909101519092909150565b60008060006060848603121561329b57600080fd5b83516132a681612db3565b602085015190935061ffff811681146132be57600080fd5b6040850151909250612d5d81612db3565b600082516132e1818460208701612dfa565b9190910192915050565b6001600160a01b03878116825286166020820152604081018590526060810184905282546080820152600183015460a0820152600283015460c0820152600383015460e082015260048301546101008201526101406101208201819052600090613357838201856131c4565b9998505050505050505050565b602081526000610c7b6020830184612e1e56fea264697066735822122080aa6f66d3610913017e3c5a184bde24093d96e2dfe9bd5e62ab7b7ce4dbbc9664736f6c63430008120033a2646970667358221220b51a462e32e4cfad9298aff78f080ace9af6f1ba5ed9397c6648bb8a1eabfb4a64736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006ba1734209a53a6e63c39d4e36612cc856a34d560000000000000000000000006ba1734209a53a6e63c39d4e36612cc856a34d56000000000000000000000000604e586f17ce106b64185a7a0d2c1da5bace711e00000000000000000000000066a1096c6366b2529274df4f5d8247827fe4cea800000000000000000000000016388463d60ffe0661cf7f1f31a7d658ac790ff7000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff52
-----Decoded View---------------
Arg [0] : _management (address): 0x6Ba1734209a53a6E63C39D4e36612cc856A34D56
Arg [1] : _peformanceFeeRecipient (address): 0x6Ba1734209a53a6E63C39D4e36612cc856A34D56
Arg [2] : _keeper (address): 0x604e586F17cE106B64185A7a0d2c1Da5bAce711E
Arg [3] : _oracle (address): 0x66a1096C6366b2529274dF4f5D8247827fe4CEA8
Arg [4] : _emergencyAdmin (address): 0x16388463d60FFE0661Cf7F1f31a7D658aC790ff7
Arg [5] : _GOV (address): 0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000006ba1734209a53a6e63c39d4e36612cc856a34d56
Arg [1] : 0000000000000000000000006ba1734209a53a6e63c39d4e36612cc856a34d56
Arg [2] : 000000000000000000000000604e586f17ce106b64185a7a0d2c1da5bace711e
Arg [3] : 00000000000000000000000066a1096c6366b2529274df4f5d8247827fe4cea8
Arg [4] : 00000000000000000000000016388463d60ffe0661cf7f1f31a7d658ac790ff7
Arg [5] : 000000000000000000000000feb4acf3df3cdea7399794d0869ef76a6efaff52
Deployed Bytecode Sourcemap
107118:5275:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;110791:219;;;;;;:::i;:::-;;:::i;:::-;;;567:14:1;;560:22;542:41;;530:2;515:18;110791:219:0;;;;;;;;107434:28;;;;;;;;-1:-1:-1;;;;;758:32:1;;;740:51;;728:2;713:18;107434:28:0;594:203:1;107471:50:0;;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;107471:50:0;;;111830:253;;;;;;:::i;:::-;;:::i;:::-;;107388:39;;;;;112295:95;;;;;;:::i;:::-;;:::i;107350:31::-;;;;;107243:25;;;;;-1:-1:-1;;;;;107243:25:0;;;111018:166;;;;;;:::i;:::-;;:::i;109070:1279::-;;;;;;:::i;:::-;;:::i;107320:21::-;;;;;-1:-1:-1;;;;;107320:21:0;;;111400:172;;;;;;:::i;:::-;;:::i;110512:141::-;;;;;;:::i;:::-;-1:-1:-1;;;;;110622:23:0;;;110595:7;110622:23;;;:15;:23;;;;;;;;110512:141;107275:38;;;;;-1:-1:-1;;;;;107275:38:0;;;108208:723;;;;;;:::i;:::-;;:::i;110791:219::-;110877:4;110894:14;110930:9;-1:-1:-1;;;;;110911:35:0;;:37;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;110966:23:0;;;;;;;:15;:23;;;;;;;;:36;;;;;;;110791:219;-1:-1:-1;;110791:219:0:o;111830:253::-;108018:10;;-1:-1:-1;;;;;108018:10:0;108004;:24;107996:48;;;;-1:-1:-1;;;107996:48:0;;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;;;111959:38:0;::::1;111951:63;;;::::0;-1:-1:-1;;;111951:63:0;;4962:2:1;111951:63:0::1;::::0;::::1;4944:21:1::0;5001:2;4981:18;;;4974:30;-1:-1:-1;;;5020:18:1;;;5013:42;5072:18;;111951:63:0::1;4760:336:1::0;111951:63:0::1;112025:23;:50:::0;;-1:-1:-1;;;;;;112025:50:0::1;-1:-1:-1::0;;;;;112025:50:0;;;::::1;::::0;;;::::1;::::0;;111830:253::o;112295:95::-;108018:10;;-1:-1:-1;;;;;108018:10:0;108004;:24;107996:48;;;;-1:-1:-1;;;107996:48:0;;;;;;;:::i;:::-;112366:6:::1;:16:::0;;-1:-1:-1;;;;;;112366:16:0::1;-1:-1:-1::0;;;;;112366:16:0;;;::::1;::::0;;;::::1;::::0;;112295:95::o;111018:166::-;108018:10;;-1:-1:-1;;;;;108018:10:0;108004;:24;107996:48;;;;-1:-1:-1;;;107996:48:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;111141:23:0;;::::1;;::::0;;;:15:::1;:23;::::0;;;;:35;;-1:-1:-1;;;;;;111141:35:0::1;::::0;;;::::1;;::::0;;111018:166::o;109070:1279::-;109429:7;108018:10;;-1:-1:-1;;;;;108018:10:0;108004;:24;107996:48;;;;-1:-1:-1;;;107996:48:0;;;;;;;:::i;:::-;109449:30:::1;109545:6;109553:7;109562:6;109570:3;109575:5;109523:58;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;109645:23:0::1;::::0;109606:63:::1;::::0;-1:-1:-1;;;109606:63:0;;-1:-1:-1;;;;;109645:23:0;;::::1;109606:63;::::0;::::1;740:51:1::0;109449:144:0;;-1:-1:-1;109606:38:0;::::1;::::0;::::1;::::0;713:18:1;;109606:63:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;109704:6:0::1;::::0;109682:29:::1;::::0;-1:-1:-1;;;109682:29:0;;-1:-1:-1;;;;;109704:6:0;;::::1;109682:29;::::0;::::1;740:51:1::0;109682:21:0;;::::1;::::0;-1:-1:-1;109682:21:0::1;::::0;-1:-1:-1;713:18:1;;109682:29:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;109757:10:0::1;::::0;109724:44:::1;::::0;-1:-1:-1;;;109724:44:0;;-1:-1:-1;;;;;109757:10:0;;::::1;109724:44;::::0;::::1;740:51:1::0;109724:32:0;;::::1;::::0;-1:-1:-1;109724:32:0::1;::::0;-1:-1:-1;713:18:1;;109724:44:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;109781:45:0::1;::::0;-1:-1:-1;;;109781:45:0;;-1:-1:-1;;;;;109811:14:0::1;758:32:1::0;;109781:45:0::1;::::0;::::1;740:51:1::0;109781:29:0;::::1;::::0;-1:-1:-1;109781:29:0::1;::::0;-1:-1:-1;713:18:1;;109781:45:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;109839:137:0::1;::::0;-1:-1:-1;;;109839:137:0;;-1:-1:-1;;;;;6234:47:1;;109839:137:0::1;::::0;::::1;6216:66:1::0;6330:14;6318:27;;6298:18;;;6291:55;6394:12;6382:25;;6362:18;;;6355:53;-1:-1:-1;;;;;109839:32:0;::::1;::::0;-1:-1:-1;109839:32:0::1;::::0;-1:-1:-1;6189:18:1;;109839:137:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;109989:64:0::1;::::0;-1:-1:-1;;;109989:64:0;;-1:-1:-1;;;;;6664:15:1;;;109989:64:0::1;::::0;::::1;6646:34:1::0;6716:15;;6696:18;;;6689:43;-1:-1:-1;;;;;109989:26:0;::::1;::::0;-1:-1:-1;109989:26:0::1;::::0;-1:-1:-1;6566:18:1;;109989:64:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;-1:-1:-1::0;;110070:13:0::1;:34;110066:109;;110121:42;::::0;-1:-1:-1;;;110121:42:0;;::::1;::::0;::::1;6889:25:1::0;;;-1:-1:-1;;;;;110121:27:0;::::1;::::0;::::1;::::0;6862:18:1;;110121:42:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;110066:109;110235:6;-1:-1:-1::0;;;;;110192:50:0::1;110221:11;-1:-1:-1::0;;;;;110192:50:0::1;;;;;;;;;;;-1:-1:-1::0;;;;;110255:23:0;;::::1;;::::0;;;:15:::1;:23;::::0;;;;:46;;-1:-1:-1;;;;;;110255:46:0::1;::::0;;::::1;::::0;;;::::1;::::0;;;-1:-1:-1;110255:46:0;;109070:1279;-1:-1:-1;;;;;;;;109070:1279:0:o;111400:172::-;108018:10;;-1:-1:-1;;;;;108018:10:0;108004;:24;107996:48;;;;-1:-1:-1;;;107996:48:0;;;;;;;:::i;:::-;-1:-1:-1;;;;;111487:25:0;::::1;111479:50;;;::::0;-1:-1:-1;;;111479:50:0;;4962:2:1;111479:50:0::1;::::0;::::1;4944:21:1::0;5001:2;4981:18;;;4974:30;-1:-1:-1;;;5020:18:1;;;5013:42;5072:18;;111479:50:0::1;4760:336:1::0;111479:50:0::1;111540:10;:24:::0;;-1:-1:-1;;;;;;111540:24:0::1;-1:-1:-1::0;;;;;111540:24:0;;;::::1;::::0;;;::::1;::::0;;111400:172::o;108208:723::-;108359:7;108018:10;;-1:-1:-1;;;;;108018:10:0;108004;:24;107996:48;;;;-1:-1:-1;;;107996:48:0;;;;;;;:::i;:::-;108379:30:::1;108475:6;108483:7;108492:6;108500:3;108505:5;108453:58;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;108575:23:0::1;::::0;108536:63:::1;::::0;-1:-1:-1;;;108536:63:0;;-1:-1:-1;;;;;108575:23:0;;::::1;108536:63;::::0;::::1;740:51:1::0;108379:144:0;;-1:-1:-1;108536:38:0;::::1;::::0;::::1;::::0;713:18:1;;108536:63:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;108634:6:0::1;::::0;108612:29:::1;::::0;-1:-1:-1;;;108612:29:0;;-1:-1:-1;;;;;108634:6:0;;::::1;108612:29;::::0;::::1;740:51:1::0;108612:21:0;;::::1;::::0;-1:-1:-1;108612:21:0::1;::::0;-1:-1:-1;713:18:1;;108612:29:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;108687:10:0::1;::::0;108654:44:::1;::::0;-1:-1:-1;;;108654:44:0;;-1:-1:-1;;;;;108687:10:0;;::::1;108654:44;::::0;::::1;740:51:1::0;108654:32:0;;::::1;::::0;-1:-1:-1;108654:32:0::1;::::0;-1:-1:-1;713:18:1;;108654:44:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;108711:45:0::1;::::0;-1:-1:-1;;;108711:45:0;;-1:-1:-1;;;;;108741:14:0::1;758:32:1::0;;108711:45:0::1;::::0;::::1;740:51:1::0;108711:29:0;::::1;::::0;-1:-1:-1;108711:29:0::1;::::0;-1:-1:-1;713:18:1;;108711:45:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;108774:50:0::1;::::0;-1:-1:-1;;;;;108774:50:0;;::::1;::::0;-1:-1:-1;108774:50:0;::::1;::::0;-1:-1:-1;108774:50:0::1;::::0;;;::::1;-1:-1:-1::0;;;;;108837:23:0;;::::1;;::::0;;;:15:::1;:23;::::0;;;;:46;;-1:-1:-1;;;;;;108837:46:0::1;::::0;;::::1;::::0;;;::::1;::::0;;;-1:-1:-1;108837:46:0;;108208:723;-1:-1:-1;;108208:723:0:o;-1:-1:-1:-;;;;;;;;:::o;14:131:1:-;-1:-1:-1;;;;;89:31:1;;79:42;;69:70;;135:1;132;125:12;69:70;14:131;:::o;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;:::-;386:5;150:247;-1:-1:-1;;;150:247:1:o;802:388::-;870:6;878;931:2;919:9;910:7;906:23;902:32;899:52;;;947:1;944;937:12;899:52;986:9;973:23;1005:31;1030:5;1005:31;:::i;:::-;1055:5;-1:-1:-1;1112:2:1;1097:18;;1084:32;1125:33;1084:32;1125:33;:::i;:::-;1177:7;1167:17;;;802:388;;;;;:::o;1195:188::-;1263:20;;-1:-1:-1;;;;;1312:46:1;;1302:57;;1292:85;;1373:1;1370;1363:12;1292:85;1195:188;;;:::o;1388:165::-;1455:20;;1515:12;1504:24;;1494:35;;1484:63;;1543:1;1540;1533:12;1558:127;1619:10;1614:3;1610:20;1607:1;1600:31;1650:4;1647:1;1640:15;1674:4;1671:1;1664:15;1690:719;1733:5;1786:3;1779:4;1771:6;1767:17;1763:27;1753:55;;1804:1;1801;1794:12;1753:55;1840:6;1827:20;1866:18;1903:2;1899;1896:10;1893:36;;;1909:18;;:::i;:::-;1984:2;1978:9;1952:2;2038:13;;-1:-1:-1;;2034:22:1;;;2058:2;2030:31;2026:40;2014:53;;;2082:18;;;2102:22;;;2079:46;2076:72;;;2128:18;;:::i;:::-;2168:10;2164:2;2157:22;2203:2;2195:6;2188:18;2249:3;2242:4;2237:2;2229:6;2225:15;2221:26;2218:35;2215:55;;;2266:1;2263;2256:12;2215:55;2330:2;2323:4;2315:6;2311:17;2304:4;2296:6;2292:17;2279:54;2377:1;2370:4;2365:2;2357:6;2353:15;2349:26;2342:37;2397:6;2388:15;;;;;;1690:719;;;;:::o;2414:1142::-;2553:6;2561;2569;2577;2585;2593;2601;2609;2617;2670:3;2658:9;2649:7;2645:23;2641:33;2638:53;;;2687:1;2684;2677:12;2638:53;2726:9;2713:23;2745:31;2770:5;2745:31;:::i;:::-;2795:5;-1:-1:-1;2852:2:1;2837:18;;2824:32;2865:33;2824:32;2865:33;:::i;:::-;2917:7;-1:-1:-1;2943:38:1;2977:2;2962:18;;2943:38;:::i;:::-;2933:48;;3000:38;3034:2;3023:9;3019:18;3000:38;:::i;:::-;2990:48;;3085:3;3074:9;3070:19;3057:33;3047:43;;3109:39;3143:3;3132:9;3128:19;3109:39;:::i;:::-;3099:49;;3200:3;3189:9;3185:19;3172:33;3249:14;3240:7;3236:28;3227:7;3224:41;3214:69;;3279:1;3276;3269:12;3214:69;3302:7;-1:-1:-1;3328:38:1;3361:3;3346:19;;3328:38;:::i;:::-;3318:48;;3417:3;3406:9;3402:19;3389:33;3445:18;3437:6;3434:30;3431:50;;;3477:1;3474;3467:12;3431:50;3500;3542:7;3533:6;3522:9;3518:22;3500:50;:::i;:::-;3490:60;;;2414:1142;;;;;;;;;;;:::o;3561:598::-;3648:6;3656;3664;3717:2;3705:9;3696:7;3692:23;3688:32;3685:52;;;3733:1;3730;3723:12;3685:52;3772:9;3759:23;3791:31;3816:5;3791:31;:::i;:::-;3841:5;-1:-1:-1;3898:2:1;3883:18;;3870:32;3911:33;3870:32;3911:33;:::i;:::-;3963:7;-1:-1:-1;4021:2:1;4006:18;;3993:32;4048:18;4037:30;;4034:50;;;4080:1;4077;4070:12;4034:50;4103;4145:7;4136:6;4125:9;4121:22;4103:50;:::i;:::-;4093:60;;;3561:598;;;;;:::o;4164:251::-;4234:6;4287:2;4275:9;4266:7;4262:23;4258:32;4255:52;;;4303:1;4300;4293:12;4255:52;4335:9;4329:16;4354:31;4379:5;4354:31;:::i;4420:335::-;4622:2;4604:21;;;4661:2;4641:18;;;4634:30;-1:-1:-1;;;4695:2:1;4680:18;;4673:41;4746:2;4731:18;;4420:335::o;5101:912::-;5325:4;5371:1;5367;5362:3;5358:11;5354:19;5412:2;5404:6;5400:15;5389:9;5382:34;5435:2;5485;5477:6;5473:15;5468:2;5457:9;5453:18;5446:43;5537:2;5529:6;5525:15;5520:2;5509:9;5505:18;5498:43;5589:2;5581:6;5577:15;5572:2;5561:9;5557:18;5550:43;5630:3;5624;5613:9;5609:19;5602:32;5663:6;5657:13;5643:27;;5707:6;5701:3;5690:9;5686:19;5679:35;5732:1;5742:141;5756:6;5753:1;5750:13;5742:141;;;5852:14;;;5848:23;;5842:30;5817:17;;;5836:3;5813:27;5806:67;5771:10;;5742:141;;;5746:3;;5933:1;5927:3;5918:6;5907:9;5903:22;5899:32;5892:43;6003:3;5996:2;5992:7;5987:2;5979:6;5975:15;5971:29;5960:9;5956:45;5952:55;5944:63;;;5101:912;;;;;;;;:::o
Swarm Source
ipfs://b51a462e32e4cfad9298aff78f080ace9af6f1ba5ed9397c6648bb8a1eabfb4a
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 27 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.