Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 9 from a total of 9 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Harvest | 17964588 | 937 days ago | IN | 0 ETH | 0.01252124 | ||||
| Set Rewards | 17906059 | 945 days ago | IN | 0 ETH | 0.0007991 | ||||
| Set Strategist | 17868678 | 951 days ago | IN | 0 ETH | 0.0005744 | ||||
| Set Keeper | 17868677 | 951 days ago | IN | 0 ETH | 0.00061048 | ||||
| Harvest | 17864567 | 951 days ago | IN | 0 ETH | 0.01201659 | ||||
| Set Strategist | 17779456 | 963 days ago | IN | 0 ETH | 0.0008851 | ||||
| Set Keeper | 17779454 | 963 days ago | IN | 0 ETH | 0.00098706 | ||||
| Harvest | 17779420 | 963 days ago | IN | 0 ETH | 0.01335727 | ||||
| Harvest | 17727174 | 970 days ago | IN | 0 ETH | 0.00850682 |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
FraxStrategy
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 50 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.18;
import {BaseStrategy, StrategyParams} from "@yearn-protocol/contracts/BaseStrategy.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../integrations/weth/IWETH.sol";
import "../integrations/frax/IFraxMinter.sol";
import "../integrations/frax/ISfrxEth.sol";
import "../integrations/curve/ICurve.sol";
contract FraxStrategy is BaseStrategy {
using SafeERC20 for IERC20;
using Address for address;
address internal constant fraxMinter =
0xbAFA44EFE7901E04E39Dad13167D089C559c1138;
address internal constant sfrxEth =
0xac3E018457B222d93114458476f3E3416Abbe38F;
address internal constant frxEth =
0x5E8422345238F34275888049021821E8E08CAa1f;
address internal constant frxEthCurvePool =
0xa1F8A6807c402E4A15ef4EBa36528A3FED24E577;
address internal constant curveSwapRouter =
0x99a58482BD75cbab83b27EC03CA68fF489b5788f;
uint256 public slippage = 9900; // 1%
constructor(address _vault) BaseStrategy(_vault) {
IERC20(frxEth).safeApprove(curveSwapRouter, type(uint256).max);
}
function name() external view override returns (string memory) {
return "StrategyFrax";
}
/// @notice Balance of want sitting in our strategy.
function balanceOfWant() public view returns (uint256) {
return want.balanceOf(address(this));
}
function estimatedTotalAssets()
public
view
override
returns (uint256 _wants)
{
_wants = balanceOfWant();
_wants += sfrxToWant(IERC20(sfrxEth).balanceOf(address(this)));
_wants += frxToWant(IERC20(frxEth).balanceOf(address(this)));
return _wants;
}
function sfrxToWant(uint256 _amount) public view returns (uint256) {
return frxToWant(ISfrxEth(sfrxEth).previewRedeem(_amount));
}
function wantToSfrx(uint256 _amount) public view returns (uint256) {
return ISfrxEth(sfrxEth).previewWithdraw(wantToFrx(_amount));
}
function frxToWant(uint256 _amount) public view returns (uint256) {
return (ICurve(frxEthCurvePool).price_oracle() * _amount) / 1e18;
}
function wantToFrx(uint256 _amount) public view returns (uint256) {
return (_amount * 1e18) / ICurve(frxEthCurvePool).price_oracle();
}
function prepareReturn(
uint256 _debtOutstanding
)
internal
override
returns (uint256 _profit, uint256 _loss, uint256 _debtPayment)
{
uint256 _totalAssets = estimatedTotalAssets();
uint256 _totalDebt = vault.strategies(address(this)).totalDebt;
if (_totalAssets >= _totalDebt) {
_profit = _totalAssets - _totalDebt;
_loss = 0;
} else {
_profit = 0;
_loss = _totalDebt - _totalAssets;
}
uint256 _liquidWant = balanceOfWant();
uint256 _amountNeeded = _debtOutstanding + _profit;
if (_liquidWant <= _amountNeeded) {
withdrawSome(_amountNeeded - _liquidWant);
_liquidWant = balanceOfWant();
}
if (_liquidWant <= _profit) {
// enough to pay profit (partial or full) only
_profit = _liquidWant;
_debtPayment = 0;
} else {
// enough to pay for all profit and _debtOutstanding (partial or full)
_debtPayment = Math.min(_liquidWant - _profit, _debtOutstanding);
}
}
function adjustPosition(uint256 _debtOutstanding) internal override {
if (emergencyExit) {
return;
}
uint256 _wethBal = want.balanceOf(address(this));
if (_wethBal > _debtOutstanding) {
uint256 _excessWeth = _wethBal - _debtOutstanding;
IWETH(address(want)).withdraw(_excessWeth);
}
if (address(this).balance > 0) {
IFraxMinter(fraxMinter).submitAndDeposit{
value: address(this).balance
}(address(this));
}
}
function withdrawSome(uint256 _amountNeeded) internal {
uint256 sfrxToUnstake = Math.min(
wantToSfrx(_amountNeeded),
IERC20(sfrxEth).balanceOf(address(this))
);
if (sfrxToUnstake > 0) {
_exitPosition(sfrxToUnstake);
}
}
function liquidatePosition(
uint256 _amountNeeded
) internal override returns (uint256 _liquidatedAmount, uint256 _loss) {
uint256 _wethBal = want.balanceOf(address(this));
if (_wethBal < _amountNeeded) {
withdrawSome(_amountNeeded - _wethBal);
_wethBal = balanceOfWant();
}
if (_amountNeeded > _wethBal) {
_liquidatedAmount = _wethBal;
_loss = _amountNeeded - _wethBal;
} else {
_liquidatedAmount = _amountNeeded;
}
}
function liquidateAllPositions() internal override returns (uint256) {
_exitPosition(IERC20(sfrxEth).balanceOf(address(this)));
return want.balanceOf(address(this));
}
function _exitPosition(uint256 _sfrxToUnstake) internal {
ISfrxEth(sfrxEth).redeem(_sfrxToUnstake, address(this), address(this));
_sellAllFrx();
}
function _sellAllFrx() internal {
uint256 _frxAmount = IERC20(frxEth).balanceOf(address(this));
uint256 _minAmountOut = (frxToWant(_frxAmount) * slippage) / 10000;
address[9] memory _route = [
frxEth, // FRX
frxEthCurvePool, // frxeth pool
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, // ETH
address(want), // no pool for ETH->WETH
address(want), // wETH
address(0),
address(0),
address(0),
address(0)
];
uint256[3][4] memory _swap_params = [
[uint256(1), uint256(0), uint256(1)], // FRX -> ETH, stableswap exchange
[uint256(0), uint256(0), uint256(15)], // ETH -> WETH, special 15 op
[uint256(0), uint256(0), uint256(0)],
[uint256(0), uint256(0), uint256(0)]
];
ICurveSwapRouter(curveSwapRouter).exchange_multiple(
_route,
_swap_params,
_frxAmount,
_minAmountOut
);
}
function prepareMigration(address _newStrategy) internal override {
uint256 sfrxBal = IERC20(sfrxEth).balanceOf(address(this));
if (sfrxBal > 0) {
IERC20(sfrxEth).safeTransfer(_newStrategy, sfrxBal);
}
uint256 frxBal = IERC20(frxEth).balanceOf(address(this));
if (frxBal > 0) {
IERC20(frxEth).safeTransfer(_newStrategy, frxBal);
}
uint256 ethBal = address(this).balance;
if (ethBal > 0) {
payable(_newStrategy).transfer(ethBal);
}
}
function protectedTokens()
internal
view
override
returns (address[] memory)
{
address[] memory protected = new address[](2);
protected[0] = sfrxEth;
protected[1] = frxEth;
return protected;
}
function ethToWant(
uint256 _amtInWei
) public view virtual override returns (uint256) {
return _amtInWei;
}
function setSlippage(uint256 _slippage) external onlyStrategist {
require(_slippage < 10_000, "!_slippage");
slippage = _slippage;
}
receive() external payable {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
interface ICurve {
function exchange(int128 i, int128 j, uint256 dx, uint256 min_dy) external;
function exchange_underlying(
int128 i,
int128 j,
uint256 dx,
uint256 min_dy
) external;
function get_dx_underlying(
int128 i,
int128 j,
uint256 dy
) external view returns (uint256);
function get_dy_underlying(
int128 i,
int128 j,
uint256 dx
) external view returns (uint256);
function get_dx(
int128 i,
int128 j,
uint256 dy
) external view returns (uint256);
function get_dy(
int128 i,
int128 j,
uint256 dx
) external view returns (uint256);
function get_virtual_price() external view returns (uint256);
function price_oracle() external view returns (uint256);
function calc_withdraw_one_coin(
uint256 token_amount,
uint256 i
) external view returns (uint256);
function add_liquidity(
uint256[2] memory amounts,
uint256 min_mint_amount,
bool use_eth
) external payable returns (uint256);
function remove_liquidity_one_coin(
uint256 _token_amount,
uint256 i,
uint256 min_amount,
bool use_eth
) external returns (uint256);
function lp_price() external view returns (uint256);
}
interface ICurveSwapRouter {
function exchange_multiple(
address[9] memory _route,
uint256[3][4] memory _swap_params,
uint256 _amount,
uint256 _expected
) external payable returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
interface IFraxMinter {
function submitAndDeposit(address recipient) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface ISfrxEth is IERC20 {
function previewRedeem(uint256 shares) external view returns (uint256);
function previewWithdraw(uint256 assets) external view returns (uint256);
function withdraw(
uint256 assets,
address receiver,
address owner
) external returns (uint256);
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256);
function syncRewards() external;
function rewardsCycleEnd() external view returns (uint256);
function totalAssets() external view returns (uint256);
function pricePerShare() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.15;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
struct StrategyParams {
uint256 performanceFee;
uint256 activation;
uint256 debtRatio;
uint256 minDebtPerHarvest;
uint256 maxDebtPerHarvest;
uint256 lastReport;
uint256 totalDebt;
uint256 totalGain;
uint256 totalLoss;
}
interface VaultAPI is IERC20 {
function name() external view returns (string calldata);
function symbol() external view returns (string calldata);
function decimals() external view returns (uint256);
function apiVersion() external pure returns (string memory);
function permit(
address owner,
address spender,
uint256 amount,
uint256 expiry,
bytes calldata signature
) external returns (bool);
// NOTE: Vyper produces multiple signatures for a given function with "default" args
function deposit() external returns (uint256);
function deposit(uint256 amount) external returns (uint256);
function deposit(uint256 amount, address recipient) external returns (uint256);
// NOTE: Vyper produces multiple signatures for a given function with "default" args
function withdraw() external returns (uint256);
function withdraw(uint256 maxShares) external returns (uint256);
function withdraw(uint256 maxShares, address recipient) external returns (uint256);
function token() external view returns (address);
function strategies(address _strategy) external view returns (StrategyParams memory);
function pricePerShare() external view returns (uint256);
function totalAssets() external view returns (uint256);
function depositLimit() external view returns (uint256);
function maxAvailableShares() external view returns (uint256);
/**
* View how much the Vault would increase this Strategy's borrow limit,
* based on its present performance (since its last report). Can be used to
* determine expectedReturn in your Strategy.
*/
function creditAvailable() external view returns (uint256);
/**
* View how much the Vault would like to pull back from the Strategy,
* based on its present performance (since its last report). Can be used to
* determine expectedReturn in your Strategy.
*/
function debtOutstanding() external view returns (uint256);
/**
* View how much the Vault expect this Strategy to return at the current
* block, based on its present performance (since its last report). Can be
* used to determine expectedReturn in your Strategy.
*/
function expectedReturn() external view returns (uint256);
/**
* This is the main contact point where the Strategy interacts with the
* Vault. It is critical that this call is handled as intended by the
* Strategy. Therefore, this function will be called by BaseStrategy to
* make sure the integration is correct.
*/
function report(
uint256 _gain,
uint256 _loss,
uint256 _debtPayment
) external returns (uint256);
/**
* This function should only be used in the scenario where the Strategy is
* being retired but no migration of the positions are possible, or in the
* extreme scenario that the Strategy needs to be put into "Emergency Exit"
* mode in order for it to exit as quickly as possible. The latter scenario
* could be for any reason that is considered "critical" that the Strategy
* exits its position as fast as possible, such as a sudden change in
* market conditions leading to losses, or an imminent failure in an
* external dependency.
*/
function revokeStrategy() external;
/**
* View the governance address of the Vault to assert privileged functions
* can only be called by governance. The Strategy serves the Vault, so it
* is subject to governance defined by the Vault.
*/
function governance() external view returns (address);
/**
* View the management address of the Vault to assert privileged functions
* can only be called by management. The Strategy serves the Vault, so it
* is subject to management defined by the Vault.
*/
function management() external view returns (address);
/**
* View the guardian address of the Vault to assert privileged functions
* can only be called by guardian. The Strategy serves the Vault, so it
* is subject to guardian defined by the Vault.
*/
function guardian() external view returns (address);
}
/**
* This interface is here for the keeper bot to use.
*/
interface StrategyAPI {
function name() external view returns (string memory);
function vault() external view returns (address);
function want() external view returns (address);
function apiVersion() external pure returns (string memory);
function keeper() external view returns (address);
function isActive() external view returns (bool);
function delegatedAssets() external view returns (uint256);
function estimatedTotalAssets() external view returns (uint256);
function tendTrigger(uint256 callCost) external view returns (bool);
function tend() external;
function harvestTrigger(uint256 callCost) external view returns (bool);
function harvest() external;
event Harvested(uint256 profit, uint256 loss, uint256 debtPayment, uint256 debtOutstanding);
}
interface HealthCheck {
function check(
uint256 profit,
uint256 loss,
uint256 debtPayment,
uint256 debtOutstanding,
uint256 totalDebt
) external view returns (bool);
}
interface IBaseFee {
function isCurrentBaseFeeAcceptable() external view returns (bool);
}
/**
* @title Yearn Base Strategy
* @author yearn.finance
* @notice
* BaseStrategy implements all of the required functionality to interoperate
* closely with the Vault contract. This contract should be inherited and the
* abstract methods implemented to adapt the Strategy to the particular needs
* it has to create a return.
*
* Of special interest is the relationship between `harvest()` and
* `vault.report()'. `harvest()` may be called simply because enough time has
* elapsed since the last report, and not because any funds need to be moved
* or positions adjusted. This is critical so that the Vault may maintain an
* accurate picture of the Strategy's performance. See `vault.report()`,
* `harvest()`, and `harvestTrigger()` for further details.
*/
abstract contract BaseStrategy {
using SafeERC20 for IERC20;
string public metadataURI;
// health checks
bool public doHealthCheck;
address public healthCheck;
/**
* @notice
* Used to track which version of `StrategyAPI` this Strategy
* implements.
* @dev The Strategy's version must match the Vault's `API_VERSION`.
* @return A string which holds the current API version of this contract.
*/
function apiVersion() public pure returns (string memory) {
return "0.4.6";
}
/**
* @notice This Strategy's name.
* @dev
* You can use this field to manage the "version" of this Strategy, e.g.
* `StrategySomethingOrOtherV1`. However, "API Version" is managed by
* `apiVersion()` function above.
* @return This Strategy's name.
*/
function name() external view virtual returns (string memory);
/**
* @notice
* The amount (priced in want) of the total assets managed by this strategy should not count
* towards Yearn's TVL calculations.
* @dev
* You can override this field to set it to a non-zero value if some of the assets of this
* Strategy is somehow delegated inside another part of of Yearn's ecosystem e.g. another Vault.
* Note that this value must be strictly less than or equal to the amount provided by
* `estimatedTotalAssets()` below, as the TVL calc will be total assets minus delegated assets.
* Also note that this value is used to determine the total assets under management by this
* strategy, for the purposes of computing the management fee in `Vault`
* @return
* The amount of assets this strategy manages that should not be included in Yearn's Total Value
* Locked (TVL) calculation across it's ecosystem.
*/
function delegatedAssets() external view virtual returns (uint256) {
return 0;
}
VaultAPI public vault;
address public strategist;
address public rewards;
address public keeper;
IERC20 public want;
// So indexers can keep track of this
event Harvested(uint256 profit, uint256 loss, uint256 debtPayment, uint256 debtOutstanding);
event UpdatedStrategist(address newStrategist);
event UpdatedKeeper(address newKeeper);
event UpdatedRewards(address rewards);
event UpdatedMinReportDelay(uint256 delay);
event UpdatedMaxReportDelay(uint256 delay);
event UpdatedBaseFeeOracle(address baseFeeOracle);
event UpdatedCreditThreshold(uint256 creditThreshold);
event ForcedHarvestTrigger(bool triggerState);
event EmergencyExitEnabled();
event UpdatedMetadataURI(string metadataURI);
event SetHealthCheck(address);
event SetDoHealthCheck(bool);
// The minimum number of seconds between harvest calls. See
// `setMinReportDelay()` for more details.
uint256 public minReportDelay;
// The maximum number of seconds between harvest calls. See
// `setMaxReportDelay()` for more details.
uint256 public maxReportDelay;
// See note on `setEmergencyExit()`.
bool public emergencyExit;
// See note on `isBaseFeeOracleAcceptable()`.
address public baseFeeOracle;
// See note on `setCreditThreshold()`
uint256 public creditThreshold;
// See note on `setForceHarvestTriggerOnce`
bool public forceHarvestTriggerOnce;
// modifiers
modifier onlyAuthorized() {
_onlyAuthorized();
_;
}
modifier onlyEmergencyAuthorized() {
_onlyEmergencyAuthorized();
_;
}
modifier onlyStrategist() {
_onlyStrategist();
_;
}
modifier onlyGovernance() {
_onlyGovernance();
_;
}
modifier onlyRewarder() {
_onlyRewarder();
_;
}
modifier onlyKeepers() {
_onlyKeepers();
_;
}
modifier onlyVaultManagers() {
_onlyVaultManagers();
_;
}
function _onlyAuthorized() internal {
require(msg.sender == strategist || msg.sender == governance());
}
function _onlyEmergencyAuthorized() internal {
require(msg.sender == strategist || msg.sender == governance() || msg.sender == vault.guardian() || msg.sender == vault.management());
}
function _onlyStrategist() internal {
require(msg.sender == strategist);
}
function _onlyGovernance() internal {
require(msg.sender == governance());
}
function _onlyRewarder() internal {
require(msg.sender == governance() || msg.sender == strategist);
}
function _onlyKeepers() internal {
require(
msg.sender == keeper ||
msg.sender == strategist ||
msg.sender == governance() ||
msg.sender == vault.guardian() ||
msg.sender == vault.management()
);
}
function _onlyVaultManagers() internal {
require(msg.sender == vault.management() || msg.sender == governance());
}
constructor(address _vault) {
_initialize(_vault, msg.sender, msg.sender, msg.sender);
}
/**
* @notice
* Initializes the Strategy, this is called only once, when the
* contract is deployed.
* @dev `_vault` should implement `VaultAPI`.
* @param _vault The address of the Vault responsible for this Strategy.
* @param _strategist The address to assign as `strategist`.
* The strategist is able to change the reward address
* @param _rewards The address to use for pulling rewards.
* @param _keeper The adddress of the _keeper. _keeper
* can harvest and tend a strategy.
*/
function _initialize(
address _vault,
address _strategist,
address _rewards,
address _keeper
) internal {
require(address(want) == address(0), "Strategy already initialized");
vault = VaultAPI(_vault);
want = IERC20(vault.token());
want.safeApprove(_vault, type(uint256).max); // Give Vault unlimited access (might save gas)
strategist = _strategist;
rewards = _rewards;
keeper = _keeper;
// initialize variables
maxReportDelay = 30 days;
creditThreshold = 1_000_000 * 10**vault.decimals(); // set this high by default so we don't get tons of false triggers if not changed
vault.approve(rewards, type(uint256).max); // Allow rewards to be pulled
}
function setHealthCheck(address _healthCheck) external onlyVaultManagers {
emit SetHealthCheck(_healthCheck);
healthCheck = _healthCheck;
}
function setDoHealthCheck(bool _doHealthCheck) external onlyVaultManagers {
emit SetDoHealthCheck(_doHealthCheck);
doHealthCheck = _doHealthCheck;
}
/**
* @notice
* Used to change `strategist`.
*
* This may only be called by governance or the existing strategist.
* @param _strategist The new address to assign as `strategist`.
*/
function setStrategist(address _strategist) external onlyAuthorized {
require(_strategist != address(0));
strategist = _strategist;
emit UpdatedStrategist(_strategist);
}
/**
* @notice
* Used to change `keeper`.
*
* `keeper` is the only address that may call `tend()` or `harvest()`,
* other than `governance()` or `strategist`. However, unlike
* `governance()` or `strategist`, `keeper` may *only* call `tend()`
* and `harvest()`, and no other authorized functions, following the
* principle of least privilege.
*
* This may only be called by governance or the strategist.
* @param _keeper The new address to assign as `keeper`.
*/
function setKeeper(address _keeper) external onlyAuthorized {
require(_keeper != address(0));
keeper = _keeper;
emit UpdatedKeeper(_keeper);
}
/**
* @notice
* Used to change `rewards`. EOA or smart contract which has the permission
* to pull rewards from the vault.
*
* This may only be called by the strategist.
* @param _rewards The address to use for pulling rewards.
*/
function setRewards(address _rewards) external onlyRewarder {
require(_rewards != address(0));
vault.approve(rewards, 0);
rewards = _rewards;
vault.approve(rewards, type(uint256).max);
emit UpdatedRewards(_rewards);
}
/**
* @notice
* Used to change `minReportDelay`. `minReportDelay` is the minimum number
* of blocks that should pass for `harvest()` to be called.
*
* For external keepers (such as the Keep3r network), this is the minimum
* time between jobs to wait. (see `harvestTrigger()`
* for more details.)
*
* This may only be called by governance or the strategist.
* @param _delay The minimum number of seconds to wait between harvests.
*/
function setMinReportDelay(uint256 _delay) external onlyAuthorized {
minReportDelay = _delay;
emit UpdatedMinReportDelay(_delay);
}
/**
* @notice
* Used to change `maxReportDelay`. `maxReportDelay` is the maximum number
* of blocks that should pass for `harvest()` to be called.
*
* For external keepers (such as the Keep3r network), this is the maximum
* time between jobs to wait. (see `harvestTrigger()`
* for more details.)
*
* This may only be called by governance or the strategist.
* @param _delay The maximum number of seconds to wait between harvests.
*/
function setMaxReportDelay(uint256 _delay) external onlyAuthorized {
maxReportDelay = _delay;
emit UpdatedMaxReportDelay(_delay);
}
/**
* @notice
* Used to ensure that any significant credit a strategy has from the
* vault will be automatically harvested.
*
* This may only be called by governance or management.
* @param _creditThreshold The number of want tokens that will
* automatically trigger a harvest.
*/
function setCreditThreshold(uint256 _creditThreshold) external onlyVaultManagers {
creditThreshold = _creditThreshold;
emit UpdatedCreditThreshold(_creditThreshold);
}
/**
* @notice
* Used to automatically trigger a harvest by our keepers. Can be
* useful if gas prices are too high now, and we want to harvest
* later once prices have lowered.
*
* This may only be called by governance or management.
* @param _forceHarvestTriggerOnce Value of true tells keepers to harvest
* our strategy
*/
function setForceHarvestTriggerOnce(bool _forceHarvestTriggerOnce) external onlyVaultManagers {
forceHarvestTriggerOnce = _forceHarvestTriggerOnce;
emit ForcedHarvestTrigger(_forceHarvestTriggerOnce);
}
/**
* @notice
* Used to set our baseFeeOracle, which checks the network's current base
* fee price to determine whether it is an optimal time to harvest or tend.
*
* This may only be called by governance or management.
* @param _baseFeeOracle Address of our baseFeeOracle
*/
function setBaseFeeOracle(address _baseFeeOracle) external onlyVaultManagers {
baseFeeOracle = _baseFeeOracle;
emit UpdatedBaseFeeOracle(_baseFeeOracle);
}
/**
* @notice
* Used to change `metadataURI`. `metadataURI` is used to store the URI
* of the file describing the strategy.
*
* This may only be called by governance or the strategist.
* @param _metadataURI The URI that describe the strategy.
*/
function setMetadataURI(string calldata _metadataURI) external onlyAuthorized {
metadataURI = _metadataURI;
emit UpdatedMetadataURI(_metadataURI);
}
/**
* Resolve governance address from Vault contract, used to make assertions
* on protected functions in the Strategy.
*/
function governance() internal view returns (address) {
return vault.governance();
}
/**
* @notice
* Provide an accurate conversion from `_amtInWei` (denominated in wei)
* to `want` (using the native decimal characteristics of `want`).
* @dev
* Care must be taken when working with decimals to assure that the conversion
* is compatible. As an example:
*
* given 1e17 wei (0.1 ETH) as input, and want is USDC (6 decimals),
* with USDC/ETH = 1800, this should give back 1800000000 (180 USDC)
*
* @param _amtInWei The amount (in wei/1e-18 ETH) to convert to `want`
* @return The amount in `want` of `_amtInEth` converted to `want`
**/
function ethToWant(uint256 _amtInWei) public view virtual returns (uint256);
/**
* @notice
* Provide an accurate estimate for the total amount of assets
* (principle + return) that this Strategy is currently managing,
* denominated in terms of `want` tokens.
*
* This total should be "realizable" e.g. the total value that could
* *actually* be obtained from this Strategy if it were to divest its
* entire position based on current on-chain conditions.
* @dev
* Care must be taken in using this function, since it relies on external
* systems, which could be manipulated by the attacker to give an inflated
* (or reduced) value produced by this function, based on current on-chain
* conditions (e.g. this function is possible to influence through
* flashloan attacks, oracle manipulations, or other DeFi attack
* mechanisms).
*
* It is up to governance to use this function to correctly order this
* Strategy relative to its peers in the withdrawal queue to minimize
* losses for the Vault based on sudden withdrawals. This value should be
* higher than the total debt of the Strategy and higher than its expected
* value to be "safe".
* @return The estimated total assets in this Strategy.
*/
function estimatedTotalAssets() public view virtual returns (uint256);
/*
* @notice
* Provide an indication of whether this strategy is currently "active"
* in that it is managing an active position, or will manage a position in
* the future. This should correlate to `harvest()` activity, so that Harvest
* events can be tracked externally by indexing agents.
* @return True if the strategy is actively managing a position.
*/
function isActive() public view returns (bool) {
return vault.strategies(address(this)).debtRatio > 0 || estimatedTotalAssets() > 0;
}
/**
* Perform any Strategy unwinding or other calls necessary to capture the
* "free return" this Strategy has generated since the last time its core
* position(s) were adjusted. Examples include unwrapping extra rewards.
* This call is only used during "normal operation" of a Strategy, and
* should be optimized to minimize losses as much as possible.
*
* This method returns any realized profits and/or realized losses
* incurred, and should return the total amounts of profits/losses/debt
* payments (in `want` tokens) for the Vault's accounting (e.g.
* `want.balanceOf(this) >= _debtPayment + _profit`).
*
* `_debtOutstanding` will be 0 if the Strategy is not past the configured
* debt limit, otherwise its value will be how far past the debt limit
* the Strategy is. The Strategy's debt limit is configured in the Vault.
*
* NOTE: `_debtPayment` should be less than or equal to `_debtOutstanding`.
* It is okay for it to be less than `_debtOutstanding`, as that
* should only used as a guide for how much is left to pay back.
* Payments should be made to minimize loss from slippage, debt,
* withdrawal fees, etc.
*
* See `vault.debtOutstanding()`.
*/
function prepareReturn(uint256 _debtOutstanding)
internal
virtual
returns (
uint256 _profit,
uint256 _loss,
uint256 _debtPayment
);
/**
* Perform any adjustments to the core position(s) of this Strategy given
* what change the Vault made in the "investable capital" available to the
* Strategy. Note that all "free capital" in the Strategy after the report
* was made is available for reinvestment. Also note that this number
* could be 0, and you should handle that scenario accordingly.
*
* See comments regarding `_debtOutstanding` on `prepareReturn()`.
*/
function adjustPosition(uint256 _debtOutstanding) internal virtual;
/**
* Liquidate up to `_amountNeeded` of `want` of this strategy's positions,
* irregardless of slippage. Any excess will be re-invested with `adjustPosition()`.
* This function should return the amount of `want` tokens made available by the
* liquidation. If there is a difference between them, `_loss` indicates whether the
* difference is due to a realized loss, or if there is some other sitution at play
* (e.g. locked funds) where the amount made available is less than what is needed.
*
* NOTE: The invariant `_liquidatedAmount + _loss <= _amountNeeded` should always be maintained
*/
function liquidatePosition(uint256 _amountNeeded) internal virtual returns (uint256 _liquidatedAmount, uint256 _loss);
/**
* Liquidate everything and returns the amount that got freed.
* This function is used during emergency exit instead of `prepareReturn()` to
* liquidate all of the Strategy's positions back to the Vault.
*/
function liquidateAllPositions() internal virtual returns (uint256 _amountFreed);
/**
* @notice
* Provide a signal to the keeper that `tend()` should be called. The
* keeper will provide the estimated gas cost that they would pay to call
* `tend()`, and this function should use that estimate to make a
* determination if calling it is "worth it" for the keeper. This is not
* the only consideration into issuing this trigger, for example if the
* position would be negatively affected if `tend()` is not called
* shortly, then this can return `true` even if the keeper might be
* "at a loss" (keepers are always reimbursed by Yearn).
* @dev
* `callCostInWei` must be priced in terms of `wei` (1e-18 ETH).
*
* This call and `harvestTrigger()` should never return `true` at the same
* time.
* @param callCostInWei The keeper's estimated gas cost to call `tend()` (in wei).
* @return `true` if `tend()` should be called, `false` otherwise.
*/
function tendTrigger(uint256 callCostInWei) public view virtual returns (bool) {
// We usually don't need tend, but if there are positions that need
// active maintainence, overriding this function is how you would
// signal for that.
// If your implementation uses the cost of the call in want, you can
// use uint256 callCost = ethToWant(callCostInWei);
// It is highly suggested to use the baseFeeOracle here as well.
return false;
}
/**
* @notice
* Adjust the Strategy's position. The purpose of tending isn't to
* realize gains, but to maximize yield by reinvesting any returns.
*
* See comments on `adjustPosition()`.
*
* This may only be called by governance, the strategist, or the keeper.
*/
function tend() external onlyKeepers {
// Don't take profits with this call, but adjust for better gains
adjustPosition(vault.debtOutstanding());
}
/**
* @notice
* Provide a signal to the keeper that `harvest()` should be called. The
* keeper will provide the estimated gas cost that they would pay to call
* `harvest()`, and this function should use that estimate to make a
* determination if calling it is "worth it" for the keeper. This is not
* the only consideration into issuing this trigger, for example if the
* position would be negatively affected if `harvest()` is not called
* shortly, then this can return `true` even if the keeper might be "at a
* loss" (keepers are always reimbursed by Yearn).
* @dev
* `callCostInWei` must be priced in terms of `wei` (1e-18 ETH).
*
* This call and `tendTrigger` should never return `true` at the
* same time.
*
* See `maxReportDelay`, `creditThreshold` to adjust the
* strategist-controlled parameters that will influence whether this call
* returns `true` or not. These parameters will be used in conjunction
* with the parameters reported to the Vault (see `params`) to determine
* if calling `harvest()` is merited.
*
* This trigger also checks the network's base fee to avoid harvesting during
* times of high network congestion.
*
* Consider use of super.harvestTrigger() in any override to build on top
* of this logic instead of replacing it. For example, if using `minReportDelay`.
*
* It is expected that an external system will check `harvestTrigger()`.
* This could be a script run off a desktop or cloud bot (e.g.
* https://github.com/iearn-finance/yearn-vaults/blob/main/scripts/keep.py),
* or via an integration with the Keep3r network (e.g.
* https://github.com/Macarse/GenericKeep3rV2/blob/master/contracts/keep3r/GenericKeep3rV2.sol).
* @param callCostInWei The keeper's estimated gas cost to call `harvest()` (in wei).
* @return `true` if `harvest()` should be called, `false` otherwise.
*/
function harvestTrigger(uint256 callCostInWei) public view virtual returns (bool) {
// Should not trigger if strategy is not active (no assets or no debtRatio)
if (!isActive()) return false;
// check if the base fee gas price is higher than we allow. if it is, block harvests.
if (!isBaseFeeAcceptable()) return false;
// trigger if we want to manually harvest, but only if our gas price is acceptable
if (forceHarvestTriggerOnce) return true;
// Should trigger if hasn't been called in a while
StrategyParams memory params = vault.strategies(address(this));
if ((block.timestamp - params.lastReport) >= maxReportDelay) return true;
// harvest our credit if it's above our threshold or return false
return (vault.creditAvailable() > creditThreshold);
}
/**
* @notice
* Check if the current network base fee is below our external target. If
* not, then harvestTrigger will return false.
* @return `true` if `harvest()` should be allowed, `false` otherwise.
*/
function isBaseFeeAcceptable() public view returns (bool) {
if (baseFeeOracle == address(0)) return true;
else return IBaseFee(baseFeeOracle).isCurrentBaseFeeAcceptable();
}
/**
* @notice
* Harvests the Strategy, recognizing any profits or losses and adjusting
* the Strategy's position.
*
* In the rare case the Strategy is in emergency shutdown, this will exit
* the Strategy's position.
*
* This may only be called by governance, the strategist, or the keeper.
* @dev
* When `harvest()` is called, the Strategy reports to the Vault (via
* `vault.report()`), so in some cases `harvest()` must be called in order
* to take in profits, to borrow newly available funds from the Vault, or
* otherwise adjust its position. In other cases `harvest()` must be
* called to report to the Vault on the Strategy's position, especially if
* any losses have occurred.
*/
function harvest() external onlyKeepers {
uint256 profit = 0;
uint256 loss = 0;
uint256 debtOutstanding = vault.debtOutstanding();
uint256 debtPayment = 0;
if (emergencyExit) {
// Free up as much capital as possible
uint256 amountFreed = liquidateAllPositions();
if (amountFreed < debtOutstanding) {
loss = debtOutstanding - amountFreed;
} else if (amountFreed > debtOutstanding) {
profit = amountFreed - debtOutstanding;
}
debtPayment = debtOutstanding - loss;
} else {
// Free up returns for Vault to pull
(profit, loss, debtPayment) = prepareReturn(debtOutstanding);
}
// we're done harvesting, so reset our trigger if we used it
forceHarvestTriggerOnce = false;
emit ForcedHarvestTrigger(false);
// Allow Vault to take up to the "harvested" balance of this contract,
// which is the amount it has earned since the last time it reported to
// the Vault.
uint256 totalDebt = vault.strategies(address(this)).totalDebt;
debtOutstanding = vault.report(profit, loss, debtPayment);
// Check if free returns are left, and re-invest them
adjustPosition(debtOutstanding);
// call healthCheck contract
if (doHealthCheck && healthCheck != address(0)) {
require(HealthCheck(healthCheck).check(profit, loss, debtPayment, debtOutstanding, totalDebt), "!healthcheck");
} else {
emit SetDoHealthCheck(true);
doHealthCheck = true;
}
emit Harvested(profit, loss, debtPayment, debtOutstanding);
}
/**
* @notice
* Withdraws `_amountNeeded` to `vault`.
*
* This may only be called by the Vault.
* @param _amountNeeded How much `want` to withdraw.
* @return _loss Any realized losses
*/
function withdraw(uint256 _amountNeeded) external returns (uint256 _loss) {
require(msg.sender == address(vault), "!vault");
// Liquidate as much as possible to `want`, up to `_amountNeeded`
uint256 amountFreed;
(amountFreed, _loss) = liquidatePosition(_amountNeeded);
// Send it directly back (NOTE: Using `msg.sender` saves some gas here)
want.safeTransfer(msg.sender, amountFreed);
// NOTE: Reinvest anything leftover on next `tend`/`harvest`
}
/**
* Do anything necessary to prepare this Strategy for migration, such as
* transferring any reserve or LP tokens, CDPs, or other tokens or stores of
* value.
*/
function prepareMigration(address _newStrategy) internal virtual;
/**
* @notice
* Transfers all `want` from this Strategy to `_newStrategy`.
*
* This may only be called by the Vault.
* @dev
* The new Strategy's Vault must be the same as this Strategy's Vault.
* The migration process should be carefully performed to make sure all
* the assets are migrated to the new address, which should have never
* interacted with the vault before.
* @param _newStrategy The Strategy to migrate to.
*/
function migrate(address _newStrategy) external {
require(msg.sender == address(vault));
require(BaseStrategy(_newStrategy).vault() == vault);
prepareMigration(_newStrategy);
want.safeTransfer(_newStrategy, want.balanceOf(address(this)));
}
/**
* @notice
* Activates emergency exit. Once activated, the Strategy will exit its
* position upon the next harvest, depositing all funds into the Vault as
* quickly as is reasonable given on-chain conditions.
*
* This may only be called by governance or the strategist.
* @dev
* See `vault.setEmergencyShutdown()` and `harvest()` for further details.
*/
function setEmergencyExit() external onlyEmergencyAuthorized {
emergencyExit = true;
if (vault.strategies(address(this)).debtRatio != 0) {
vault.revokeStrategy();
}
emit EmergencyExitEnabled();
}
/**
* Override this to add all tokens/tokenized positions this contract
* manages on a *persistent* basis (e.g. not just for swapping back to
* want ephemerally).
*
* NOTE: Do *not* include `want`, already included in `sweep` below.
*
* Example:
* ```
* function protectedTokens() internal override view returns (address[] memory) {
* address[] memory protected = new address[](3);
* protected[0] = tokenA;
* protected[1] = tokenB;
* protected[2] = tokenC;
* return protected;
* }
* ```
*/
function protectedTokens() internal view virtual returns (address[] memory);
/**
* @notice
* Removes tokens from this Strategy that are not the type of tokens
* managed by this Strategy. This may be used in case of accidentally
* sending the wrong kind of token to this Strategy.
*
* Tokens will be sent to `governance()`.
*
* This will fail if an attempt is made to sweep `want`, or any tokens
* that are protected by this Strategy.
*
* This may only be called by governance.
* @dev
* Implement `protectedTokens()` to specify any additional tokens that
* should be protected from sweeping in addition to `want`.
* @param _token The token to transfer out of this vault.
*/
function sweep(address _token) external onlyGovernance {
require(_token != address(want), "!want");
require(_token != address(vault), "!shares");
address[] memory _protectedTokens = protectedTokens();
for (uint256 i; i < _protectedTokens.length; i++) require(_token != _protectedTokens[i], "!protected");
IERC20(_token).safeTransfer(governance(), IERC20(_token).balanceOf(address(this)));
}
}
abstract contract BaseStrategyInitializable is BaseStrategy {
bool public isOriginal = true;
event Cloned(address indexed clone);
constructor(address _vault) BaseStrategy(_vault) {}
function initialize(
address _vault,
address _strategist,
address _rewards,
address _keeper
) external virtual {
_initialize(_vault, _strategist, _rewards, _keeper);
}
function clone(address _vault) external returns (address) {
return clone(_vault, msg.sender, msg.sender, msg.sender);
}
function clone(
address _vault,
address _strategist,
address _rewards,
address _keeper
) public returns (address newStrategy) {
require(isOriginal, "!clone");
// Copied from https://github.com/optionality/clone-factory/blob/master/contracts/CloneFactory.sol
bytes20 addressBytes = bytes20(address(this));
assembly {
// EIP-1167 bytecode
let clone_code := mload(0x40)
mstore(clone_code, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
mstore(add(clone_code, 0x14), addressBytes)
mstore(add(clone_code, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
newStrategy := create(0, clone_code, 0x37)
}
BaseStrategyInitializable(newStrategy).initialize(_vault, _strategist, _rewards, _keeper);
emit Cloned(newStrategy);
}
}{
"optimizer": {
"enabled": true,
"runs": 50
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"@yearn-protocol/=lib/yearn-vaults/"
],
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_vault","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[],"name":"EmergencyExitEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"triggerState","type":"bool"}],"name":"ForcedHarvestTrigger","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loss","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtPayment","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtOutstanding","type":"uint256"}],"name":"Harvested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"","type":"bool"}],"name":"SetDoHealthCheck","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"","type":"address"}],"name":"SetHealthCheck","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"baseFeeOracle","type":"address"}],"name":"UpdatedBaseFeeOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"creditThreshold","type":"uint256"}],"name":"UpdatedCreditThreshold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newKeeper","type":"address"}],"name":"UpdatedKeeper","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"UpdatedMaxReportDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"metadataURI","type":"string"}],"name":"UpdatedMetadataURI","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"UpdatedMinReportDelay","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rewards","type":"address"}],"name":"UpdatedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newStrategist","type":"address"}],"name":"UpdatedStrategist","type":"event"},{"inputs":[],"name":"apiVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"balanceOfWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseFeeOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"creditThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegatedAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"doHealthCheck","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"emergencyExit","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"estimatedTotalAssets","outputs":[{"internalType":"uint256","name":"_wants","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amtInWei","type":"uint256"}],"name":"ethToWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forceHarvestTriggerOnce","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"frxToWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCostInWei","type":"uint256"}],"name":"harvestTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"healthCheck","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBaseFeeAcceptable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keeper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxReportDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newStrategy","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minReportDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_baseFeeOracle","type":"address"}],"name":"setBaseFeeOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_creditThreshold","type":"uint256"}],"name":"setCreditThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_doHealthCheck","type":"bool"}],"name":"setDoHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setEmergencyExit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_forceHarvestTriggerOnce","type":"bool"}],"name":"setForceHarvestTriggerOnce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_healthCheck","type":"address"}],"name":"setHealthCheck","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_keeper","type":"address"}],"name":"setKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setMaxReportDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_metadataURI","type":"string"}],"name":"setMetadataURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delay","type":"uint256"}],"name":"setMinReportDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_rewards","type":"address"}],"name":"setRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_slippage","type":"uint256"}],"name":"setSlippage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_strategist","type":"address"}],"name":"setStrategist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"sfrxToWant","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"slippage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"strategist","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"tend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"callCostInWei","type":"uint256"}],"name":"tendTrigger","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract VaultAPI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"want","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"wantToFrx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"wantToSfrx","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amountNeeded","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"_loss","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040526126ac600c553480156200001757600080fd5b5060405162003af838038062003af88339810160408190526200003a91620006d0565b80620000498133808062000094565b506200008d735e8422345238f34275888049021821e8e08caa1f7399a58482bd75cbab83b27ec03ca68ff489b5788f600019620002ff602090811b62001bf817901c565b50620008f6565b6006546001600160a01b031615620000f35760405162461bcd60e51b815260206004820152601c60248201527f537472617465677920616c726561647920696e697469616c697a65640000000060448201526064015b60405180910390fd5b600280546001600160a01b0319166001600160a01b03861690811790915560408051637e062a3560e11b8152905163fc0c546a916004808201926020929091908290030181865afa1580156200014d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001739190620006d0565b600680546001600160a01b0319166001600160a01b03929092169182179055620001ad9085600019620002ff602090811b62001bf817901c565b600380546001600160a01b038086166001600160a01b031992831617909255600480548584169083161781556005805485851693169290921790915562278d006008556002546040805163313ce56760e01b81529051919093169263313ce56792818101926020929091908290030181865afa15801562000232573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000258919062000702565b6200026590600a62000831565b6200027490620f42406200083f565b600a556002546004805460405163095ea7b360e01b81526001600160a01b039182169281019290925260001960248301529091169063095ea7b3906044016020604051808303816000875af1158015620002d2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002f8919062000859565b5050505050565b8015806200037d5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa15801562000355573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200037b919062000702565b155b620003f15760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e6365000000000000000000006064820152608401620000ea565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b17909152620004499185916200044e16565b505050565b6000620004aa826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200052c60201b62001d38179092919060201c565b805190915015620004495780806020019051810190620004cb919062000859565b620004495760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401620000ea565b60606200053d848460008562000545565b949350505050565b606082471015620005a85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401620000ea565b600080866001600160a01b03168587604051620005c69190620008a3565b60006040518083038185875af1925050503d806000811462000605576040519150601f19603f3d011682016040523d82523d6000602084013e6200060a565b606091505b5090925090506200061e8783838762000629565b979650505050505050565b606083156200069d57825160000362000695576001600160a01b0385163b620006955760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401620000ea565b50816200053d565b6200053d8383815115620006b45781518083602001fd5b8060405162461bcd60e51b8152600401620000ea9190620008c1565b600060208284031215620006e357600080fd5b81516001600160a01b0381168114620006fb57600080fd5b9392505050565b6000602082840312156200071557600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b600181815b80851115620007735781600019048211156200075757620007576200071c565b808516156200076557918102915b93841c939080029062000737565b509250929050565b6000826200078c575060016200082b565b816200079b575060006200082b565b8160018114620007b45760028114620007bf57620007df565b60019150506200082b565b60ff841115620007d357620007d36200071c565b50506001821b6200082b565b5060208310610133831016604e8410600b841016171562000804575081810a6200082b565b62000810838362000732565b80600019048211156200082757620008276200071c565b0290505b92915050565b6000620006fb83836200077b565b80820281158282048414176200082b576200082b6200071c565b6000602082840312156200086c57600080fd5b81518015158114620006fb57600080fd5b60005b838110156200089a57818101518382015260200162000880565b50506000910152565b60008251620008b78184602087016200087d565b9190910192915050565b6020815260008251806020840152620008e28160408501602087016200087d565b601f01601f19169190910160400192915050565b6131f280620009066000396000f3fe60806040526004361061024c5760003560e01c8063826cddf61161013a578063b252720b116100b1578063b252720b146106a5578063c1a3d44c146106ca578063c7b9d530146106df578063ce5494bb146106ff578063ec38a8621461071f578063ed882c2b1461073f578063efbb5cb01461075f578063f017c92f14610774578063f0fa55a914610794578063fbfa77cf146107b4578063fcf2d0ad146107d4578063fe2508a6146107e957600080fd5b8063826cddf6146105515780638e6350e21461057657806395326e2d1461058a57806395e80c501461059f5780639ec5a894146105b55780639f450b5a146105d5578063a763cf5b146105f5578063aa5480cf1461060f578063ac00ff2614610625578063ac8b84f614610645578063aced166114610665578063b1e67b391461068557600080fd5b806339a172a8116101ce57806339a172a8146103fe5780633e032a3b1461041e578063440368a3146104345780634641257d146104495780635641ec031461045e578063567bf24d14610478578063650d1880146104985780636718835f146104b9578063748747e6146104d3578063750521f5146104f357806377af352014610513578063780022a01461053357600080fd5b806301681a621461025857806303ee438c1461027a57806306fdde03146102a55780630ada4dab146102da57806311bc8245146102fa5780631f1fcd511461031a5780631fe4a6861461034757806322f3e2d414610367578063258294101461038c57806328b7ccf7146103ba5780632e1a7d4d146103de57600080fd5b3661025357005b600080fd5b34801561026457600080fd5b50610278610273366004612c6a565b610809565b005b34801561028657600080fd5b5061028f6109c3565b60405161029c9190612cab565b60405180910390f35b3480156102b157600080fd5b5060408051808201909152600c81526b0a6e8e4c2e8cacef28ce4c2f60a31b602082015261028f565b3480156102e657600080fd5b506102786102f5366004612cec565b610a51565b34801561030657600080fd5b50610278610315366004612c6a565b610aa1565b34801561032657600080fd5b5060065461033a906001600160a01b031681565b60405161029c9190612d09565b34801561035357600080fd5b5060035461033a906001600160a01b031681565b34801561037357600080fd5b5061037c610b08565b604051901515815260200161029c565b34801561039857600080fd5b5060408051808201909152600581526418171a171b60d91b602082015261028f565b3480156103c657600080fd5b506103d060085481565b60405190815260200161029c565b3480156103ea57600080fd5b506103d06103f9366004612d1d565b610b9b565b34801561040a57600080fd5b50610278610419366004612d1d565b610c0f565b34801561042a57600080fd5b506103d0600c5481565b34801561044057600080fd5b50610278610c4c565b34801561045557600080fd5b50610278610cca565b34801561046a57600080fd5b5060095461037c9060ff1681565b34801561048457600080fd5b506103d0610493366004612d1d565b61107d565b3480156104a457600080fd5b5061037c6104b3366004612d1d565b50600090565b3480156104c557600080fd5b5060015461037c9060ff1681565b3480156104df57600080fd5b506102786104ee366004612c6a565b611101565b3480156104ff57600080fd5b5061027861050e366004612d36565b611167565b34801561051f57600080fd5b506103d061052e366004612d1d565b6111ba565b34801561053f57600080fd5b506103d061054e366004612d1d565b90565b34801561055d57600080fd5b5060095461033a9061010090046001600160a01b031681565b34801561058257600080fd5b5060006103d0565b34801561059657600080fd5b5061037c611230565b3480156105ab57600080fd5b506103d060075481565b3480156105c157600080fd5b5060045461033a906001600160a01b031681565b3480156105e157600080fd5b506102786105f0366004612c6a565b6112c5565b34801561060157600080fd5b50600b5461037c9060ff1681565b34801561061b57600080fd5b506103d0600a5481565b34801561063157600080fd5b50610278610640366004612cec565b61131d565b34801561065157600080fd5b506103d0610660366004612d1d565b61136d565b34801561067157600080fd5b5060055461033a906001600160a01b031681565b34801561069157600080fd5b506103d06106a0366004612d1d565b611403565b3480156106b157600080fd5b5060015461033a9061010090046001600160a01b031681565b3480156106d657600080fd5b506103d061148d565b3480156106eb57600080fd5b506102786106fa366004612c6a565b6114ff565b34801561070b57600080fd5b5061027861071a366004612c6a565b611565565b34801561072b57600080fd5b5061027861073a366004612c6a565b611695565b34801561074b57600080fd5b5061037c61075a366004612d1d565b6117e5565b34801561076b57600080fd5b506103d061193a565b34801561078057600080fd5b5061027861078f366004612d1d565b611a0f565b3480156107a057600080fd5b506102786107af366004612d1d565b611a4c565b3480156107c057600080fd5b5060025461033a906001600160a01b031681565b3480156107e057600080fd5b50610278611a97565b3480156107f557600080fd5b50610278610804366004612d1d565b611bbb565b610811611d4f565b6006546001600160a01b039081169082160361085c5760405162461bcd60e51b8152602060048201526005602482015264085dd85b9d60da1b60448201526064015b60405180910390fd5b6002546001600160a01b03908116908216036108a45760405162461bcd60e51b81526020600482015260076024820152662173686172657360c81b6044820152606401610853565b60006108ae611d74565b905060005b8151811015610935578181815181106108ce576108ce612da8565b60200260200101516001600160a01b0316836001600160a01b0316036109235760405162461bcd60e51b815260206004820152600a602482015269085c1c9bdd1958dd195960b21b6044820152606401610853565b8061092d81612dd4565b9150506108b3565b506109bf610941611e20565b6040516370a0823160e01b81526001600160a01b038516906370a082319061096d903090600401612d09565b602060405180830381865afa15801561098a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ae9190612ded565b6001600160a01b0385169190611e8e565b5050565b600080546109d090612e06565b80601f01602080910402602001604051908101604052809291908181526020018280546109fc90612e06565b8015610a495780601f10610a1e57610100808354040283529160200191610a49565b820191906000526020600020905b815481529060010190602001808311610a2c57829003601f168201915b505050505081565b610a59611ead565b600b805460ff19168215159081179091556040519081527f6ad28df1b554fa6cacd46ae82fa811748d53798feeb437ddf234bf3083953319906020015b60405180910390a150565b610aa9611ead565b7fc8db9c35f716b87af1fbb83f03c78646061931269301fd7ba6dcf189b4cdc2fc81604051610ad89190612d09565b60405180910390a1600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6002546040516339ebf82360e01b815260009182916001600160a01b03909116906339ebf82390610b3d903090600401612d09565b61012060405180830381865afa158015610b5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7f9190612e7a565b604001511180610b9657506000610b9461193a565b115b905090565b6002546000906001600160a01b03163314610be15760405162461bcd60e51b8152602060048201526006602482015265085d985d5b1d60d21b6044820152606401610853565b6000610bec83611f4f565b600654909350909150610c09906001600160a01b03163383611e8e565b50919050565b610c17612012565b60078190556040518181527fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b190602001610a96565b610c5461202e565b6002546040805163bf3759b560e01b81529051610cc8926001600160a01b03169163bf3759b59160048083019260209291908290030181865afa158015610c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc39190612ded565b612183565b565b610cd261202e565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4e9190612ded565b60095490915060009060ff1615610dab576000610d696122ef565b905082811015610d8457610d7d8184612ef5565b9350610d99565b82811115610d9957610d968382612ef5565b94505b610da38484612ef5565b915050610dbc565b610db48261239d565b919550935090505b600b805460ff19169055604051600081527f6ad28df1b554fa6cacd46ae82fa811748d53798feeb437ddf234bf30839533199060200160405180910390a16002546040516339ebf82360e01b81526000916001600160a01b0316906339ebf82390610e2b903090600401612d09565b61012060405180830381865afa158015610e49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6d9190612e7a565b60c001516002546040516328766ebf60e21b81526004810188905260248101879052604481018590529192506001600160a01b03169063a1d9bafc906064016020604051808303816000875af1158015610ecb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eef9190612ded565b9250610efa83612183565b60015460ff168015610f1b575060015461010090046001600160a01b031615155b15610fed5760015460405163c70fa00b60e01b815260048101879052602481018690526044810184905260648101859052608481018390526101009091046001600160a01b03169063c70fa00b9060a401602060405180830381865afa158015610f89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fad9190612f08565b610fe85760405162461bcd60e51b815260206004820152600c60248201526b216865616c7468636865636b60a01b6044820152606401610853565b61102e565b604051600181527ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b9060200160405180910390a16001805460ff1916811790555b6040805186815260208101869052908101839052606081018490527f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d5099060800160405180910390a15050505050565b600060008051602061319d833981519152630a28a47761109c84611403565b6040518263ffffffff1660e01b81526004016110ba91815260200190565b602060405180830381865afa1580156110d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fb9190612ded565b92915050565b611109612012565b6001600160a01b03811661111c57600080fd5b600580546001600160a01b0319166001600160a01b0383161790556040517f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe715490610a96908390612d09565b61116f612012565b600061117c828483612f73565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda682826040516111ae929190613033565b60405180910390a15050565b60405163266d6a8360e11b8152600481018290526000906110fb9060008051602061319d83398151915290634cdad506906024015b602060405180830381865afa15801561120c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106609190612ded565b60095460009061010090046001600160a01b031661124e5750600190565b600960019054906101000a90046001600160a01b03166001600160a01b03166334a9e75c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112a1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b969190612f08565b6112cd611ead565b60098054610100600160a81b0319166101006001600160a01b038416021790556040517f711be97287cb9ec921887b9be36e148e1a27c6b158547b22b9704ffc54447a0f90610a96908390612d09565b611325611ead565b60405181151581527ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b9060200160405180910390a16001805460ff1916911515919091179055565b6000670de0b6b3a76400008273a1f8a6807c402e4a15ef4eba36528a3fed24e5776001600160a01b03166386fc88d36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ef9190612ded565b6113f99190613062565b6110fb9190613079565b600073a1f8a6807c402e4a15ef4eba36528a3fed24e5776001600160a01b03166386fc88d36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611457573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147b9190612ded565b6113f983670de0b6b3a7640000613062565b6006546040516370a0823160e01b81526000916001600160a01b0316906370a08231906114be903090600401612d09565b602060405180830381865afa1580156114db573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b969190612ded565b611507612012565b6001600160a01b03811661151a57600080fd5b600380546001600160a01b0319166001600160a01b0383161790556040517f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b490610a96908390612d09565b6002546001600160a01b0316331461157c57600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf9160048083019260209291908290030181865afa1580156115c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ec919061309b565b6001600160a01b0316146115ff57600080fd5b611608816124c3565b6006546040516370a0823160e01b81526116929183916001600160a01b03909116906370a082319061163e903090600401612d09565b602060405180830381865afa15801561165b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167f9190612ded565b6006546001600160a01b03169190611e8e565b50565b61169d612640565b6001600160a01b0381166116b057600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b039384169363095ea7b3936116e79390911691600091016130b8565b6020604051808303816000875af1158015611706573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172a9190612f08565b50600480546001600160a01b0319166001600160a01b03838116918217835560025460405163095ea7b360e01b815291169263095ea7b39261177292909160001991016130b8565b6020604051808303816000875af1158015611791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b59190612f08565b507fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a06981604051610a969190612d09565b60006117ef610b08565b6117fb57506000919050565b611803611230565b61180f57506000919050565b600b5460ff161561182257506001919050565b6002546040516339ebf82360e01b81526000916001600160a01b0316906339ebf82390611853903090600401612d09565b61012060405180830381865afa158015611871573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118959190612e7a565b90506008548160a00151426118aa9190612ef5565b106118b85750600192915050565b600a54600260009054906101000a90046001600160a01b03166001600160a01b031663112c1f9b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561190e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119329190612ded565b119392505050565b600061194461148d565b6040516370a0823160e01b81529091506119bd9060008051602061319d833981519152906370a082319061197c903090600401612d09565b602060405180830381865afa158015611999573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052e9190612ded565b6119c790826130d1565b6040516370a0823160e01b8152909150611a0590735e8422345238f34275888049021821e8e08caa1f906370a08231906111ef903090600401612d09565b610b9690826130d1565b611a17612012565b60088190556040518181527f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c590602001610a96565b611a54612679565b6127108110611a925760405162461bcd60e51b815260206004820152600a602482015269215f736c69707061676560b01b6044820152606401610853565b600c55565b611a9f612690565b6009805460ff191660011790556002546040516339ebf82360e01b81526001600160a01b03909116906339ebf82390611adc903090600401612d09565b61012060405180830381865afa158015611afa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b1e9190612e7a565b6040015115611b9057600260009054906101000a90046001600160a01b03166001600160a01b031663a0e4af9a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611b7757600080fd5b505af1158015611b8b573d6000803e3d6000fd5b505050505b6040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b90600090a1565b611bc3611ead565b600a8190556040518181527fe5ef7832c564a10cbe7b4f1e01ac33a406cb63fcf430a97a9af8616d150af5f390602001610a96565b801580611c725750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611c4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c709190612ded565b155b611cdd5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610853565b611d338363095ea7b360e01b8484604051602401611cfc9291906130b8565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526126ac565b505050565b6060611d47848460008561277e565b949350505050565b611d57611e20565b6001600160a01b0316336001600160a01b031614610cc857600080fd5b6040805160028082526060808301845292600092919060208301908036833701905050905060008051602061319d83398151915281600081518110611dbb57611dbb612da8565b60200260200101906001600160a01b031690816001600160a01b031681525050735e8422345238f34275888049021821e8e08caa1f81600181518110611e0357611e03612da8565b6001600160a01b0390921660209283029190910190910152919050565b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e6759160048083019260209291908290030181865afa158015611e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b96919061309b565b611d338363a9059cbb60e01b8484604051602401611cfc9291906130b8565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f24919061309b565b6001600160a01b0316336001600160a01b03161480611f465750611d57611e20565b610cc857600080fd5b6006546040516370a0823160e01b8152600091829182916001600160a01b0316906370a0823190611f84903090600401612d09565b602060405180830381865afa158015611fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc59190612ded565b905083811015611fec57611fe1611fdc8286612ef5565b612859565b611fe961148d565b90505b80841115612008579150816120018185612ef5565b915061200c565b8392505b50915091565b6003546001600160a01b0316331480611f465750611d57611e20565b6005546001600160a01b031633148061205157506003546001600160a01b031633145b80612074575061205f611e20565b6001600160a01b0316336001600160a01b0316145b806121065750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f1919061309b565b6001600160a01b0316336001600160a01b0316145b80611f465750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561215f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d57919061309b565b60095460ff16156121915750565b6006546040516370a0823160e01b81526000916001600160a01b0316906370a08231906121c2903090600401612d09565b602060405180830381865afa1580156121df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122039190612ded565b90508181111561227a5760006122198383612ef5565b600654604051632e1a7d4d60e01b8152600481018390529192506001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561226057600080fd5b505af1158015612274573d6000803e3d6000fd5b50505050505b47156109bf57604051634dcd454760e01b815273bafa44efe7901e04e39dad13167d089c559c113890634dcd45479047906122b9903090600401612d09565b6000604051808303818588803b1580156122d257600080fd5b505af11580156122e6573d6000803e3d6000fd5b50505050505050565b6040516370a0823160e01b815260009061236d9060008051602061319d833981519152906370a0823190612327903090600401612d09565b602060405180830381865afa158015612344573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123689190612ded565b6128eb565b6006546040516370a0823160e01b81526001600160a01b03909116906370a08231906114be903090600401612d09565b6000806000806123ab61193a565b6002546040516339ebf82360e01b81529192506000916001600160a01b03909116906339ebf823906123e1903090600401612d09565b61012060405180830381865afa1580156123ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124239190612e7a565b60c0015190508082106124455761243a8183612ef5565b945060009350612456565b600094506124538282612ef5565b93505b600061246061148d565b9050600061246e87896130d1565b905080821161248f57612484611fdc8383612ef5565b61248c61148d565b91505b8682116124a257819650600094506124b8565b6124b56124af8884612ef5565b89612971565b94505b505050509193909250565b6040516370a0823160e01b815260009060008051602061319d833981519152906370a08231906124f7903090600401612d09565b602060405180830381865afa158015612514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125389190612ded565b905080156125595761255960008051602061319d8339815191528383611e8e565b6040516370a0823160e01b8152600090735e8422345238f34275888049021821e8e08caa1f906370a0823190612593903090600401612d09565b602060405180830381865afa1580156125b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d49190612ded565b905080156125fb576125fb735e8422345238f34275888049021821e8e08caa1f8483611e8e565b47801561263a576040516001600160a01b0385169082156108fc029083906000818181858888f19350505050158015612638573d6000803e3d6000fd5b505b50505050565b612648611e20565b6001600160a01b0316336001600160a01b03161480611f4657506003546001600160a01b03163314610cc857600080fd5b6003546001600160a01b03163314610cc857600080fd5b6003546001600160a01b0316331480612074575061205f611e20565b6000612701826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d389092919063ffffffff16565b805190915015611d33578080602001905181019061271f9190612f08565b611d335760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610853565b6060824710156127df5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610853565b600080866001600160a01b031685876040516127fb91906130e4565b60006040518083038185875af1925050503d8060008114612838576040519150601f19603f3d011682016040523d82523d6000602084013e61283d565b606091505b509150915061284e87838387612989565b979650505050505050565b60006128de6128678361107d565b6040516370a0823160e01b815260008051602061319d833981519152906370a0823190612898903090600401612d09565b602060405180830381865afa1580156128b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d99190612ded565b612971565b905080156109bf576109bf815b604051635d043b2960e11b8152600481018290523060248201819052604482015260008051602061319d8339815191529063ba087652906064016020604051808303816000875af1158015612944573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129689190612ded565b50611692612a02565b60008183106129805781612982565b825b9392505050565b606083156129f85782516000036129f1576001600160a01b0385163b6129f15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610853565b5081611d47565b611d478383612c2b565b6040516370a0823160e01b8152600090735e8422345238f34275888049021821e8e08caa1f906370a0823190612a3c903090600401612d09565b602060405180830381865afa158015612a59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a7d9190612ded565b90506000612710600c54612a908461136d565b612a9a9190613062565b612aa49190613079565b6040805161012081018252735e8422345238f34275888049021821e8e08caa1f815273a1f8a6807c402e4a15ef4eba36528a3fed24e57760208083019190915273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee828401526006546001600160a01b03166060808401829052608080850192909252600060a080860182905260c080870183905260e0808801849052610100880184905288519081018952600195810186815292810184905290810194909452835285518083018752818152808501829052600f8188015283850152855180830187528181528085018290528087018290528387015285518083018752818152938401819052838601528101919091529151630d4f290960e21b8152929350917399a58482bd75cbab83b27ec03ca68ff489b5788f9063353ca42490612be8908590859089908990600401613100565b6020604051808303816000875af1158015612c07573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126389190612ded565b815115612c3b5781518083602001fd5b8060405162461bcd60e51b81526004016108539190612cab565b6001600160a01b038116811461169257600080fd5b600060208284031215612c7c57600080fd5b813561298281612c55565b60005b83811015612ca2578181015183820152602001612c8a565b50506000910152565b6020815260008251806020840152612cca816040850160208701612c87565b601f01601f19169190910160400192915050565b801515811461169257600080fd5b600060208284031215612cfe57600080fd5b813561298281612cde565b6001600160a01b0391909116815260200190565b600060208284031215612d2f57600080fd5b5035919050565b60008060208385031215612d4957600080fd5b823567ffffffffffffffff80821115612d6157600080fd5b818501915085601f830112612d7557600080fd5b813581811115612d8457600080fd5b866020828501011115612d9657600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612de657612de6612dbe565b5060010190565b600060208284031215612dff57600080fd5b5051919050565b600181811c90821680612e1a57607f821691505b602082108103610c0957634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715612e7457612e74612e3a565b60405290565b60006101208284031215612e8d57600080fd5b612e95612e50565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b818103818111156110fb576110fb612dbe565b600060208284031215612f1a57600080fd5b815161298281612cde565b601f821115611d3357600081815260208120601f850160051c81016020861015612f4c5750805b601f850160051c820191505b81811015612f6b57828155600101612f58565b505050505050565b67ffffffffffffffff831115612f8b57612f8b612e3a565b612f9f83612f998354612e06565b83612f25565b6000601f841160018114612fd35760008515612fbb5750838201355b600019600387901b1c1916600186901b178355612638565b600083815260209020601f19861690835b828110156130045786850135825560209485019460019092019101612fe4565b50868210156130215760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b80820281158282048414176110fb576110fb612dbe565b60008261309657634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156130ad57600080fd5b815161298281612c55565b6001600160a01b03929092168252602082015260400190565b808201808211156110fb576110fb612dbe565b600082516130f6818460208701612c87565b9190910192915050565b6102e08101818660005b60098110156131325781516001600160a01b031683526020928301929091019060010161310a565b50505061012082018560005b60048110156131855781518360005b600381101561316c57825182526020928301929091019060010161314d565b505050606092909201916020919091019060010161313e565b5050506102a08201939093526102c001529291505056fe000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38fa264697066735822122019002eccc6dc79895f03db84e1255f58449d9cc7dd18aa4244cfd8d93bb53d6964736f6c634300081200330000000000000000000000003edbe670d03c4a71367deda78e73ea4f8d68f2e4
Deployed Bytecode
0x60806040526004361061024c5760003560e01c8063826cddf61161013a578063b252720b116100b1578063b252720b146106a5578063c1a3d44c146106ca578063c7b9d530146106df578063ce5494bb146106ff578063ec38a8621461071f578063ed882c2b1461073f578063efbb5cb01461075f578063f017c92f14610774578063f0fa55a914610794578063fbfa77cf146107b4578063fcf2d0ad146107d4578063fe2508a6146107e957600080fd5b8063826cddf6146105515780638e6350e21461057657806395326e2d1461058a57806395e80c501461059f5780639ec5a894146105b55780639f450b5a146105d5578063a763cf5b146105f5578063aa5480cf1461060f578063ac00ff2614610625578063ac8b84f614610645578063aced166114610665578063b1e67b391461068557600080fd5b806339a172a8116101ce57806339a172a8146103fe5780633e032a3b1461041e578063440368a3146104345780634641257d146104495780635641ec031461045e578063567bf24d14610478578063650d1880146104985780636718835f146104b9578063748747e6146104d3578063750521f5146104f357806377af352014610513578063780022a01461053357600080fd5b806301681a621461025857806303ee438c1461027a57806306fdde03146102a55780630ada4dab146102da57806311bc8245146102fa5780631f1fcd511461031a5780631fe4a6861461034757806322f3e2d414610367578063258294101461038c57806328b7ccf7146103ba5780632e1a7d4d146103de57600080fd5b3661025357005b600080fd5b34801561026457600080fd5b50610278610273366004612c6a565b610809565b005b34801561028657600080fd5b5061028f6109c3565b60405161029c9190612cab565b60405180910390f35b3480156102b157600080fd5b5060408051808201909152600c81526b0a6e8e4c2e8cacef28ce4c2f60a31b602082015261028f565b3480156102e657600080fd5b506102786102f5366004612cec565b610a51565b34801561030657600080fd5b50610278610315366004612c6a565b610aa1565b34801561032657600080fd5b5060065461033a906001600160a01b031681565b60405161029c9190612d09565b34801561035357600080fd5b5060035461033a906001600160a01b031681565b34801561037357600080fd5b5061037c610b08565b604051901515815260200161029c565b34801561039857600080fd5b5060408051808201909152600581526418171a171b60d91b602082015261028f565b3480156103c657600080fd5b506103d060085481565b60405190815260200161029c565b3480156103ea57600080fd5b506103d06103f9366004612d1d565b610b9b565b34801561040a57600080fd5b50610278610419366004612d1d565b610c0f565b34801561042a57600080fd5b506103d0600c5481565b34801561044057600080fd5b50610278610c4c565b34801561045557600080fd5b50610278610cca565b34801561046a57600080fd5b5060095461037c9060ff1681565b34801561048457600080fd5b506103d0610493366004612d1d565b61107d565b3480156104a457600080fd5b5061037c6104b3366004612d1d565b50600090565b3480156104c557600080fd5b5060015461037c9060ff1681565b3480156104df57600080fd5b506102786104ee366004612c6a565b611101565b3480156104ff57600080fd5b5061027861050e366004612d36565b611167565b34801561051f57600080fd5b506103d061052e366004612d1d565b6111ba565b34801561053f57600080fd5b506103d061054e366004612d1d565b90565b34801561055d57600080fd5b5060095461033a9061010090046001600160a01b031681565b34801561058257600080fd5b5060006103d0565b34801561059657600080fd5b5061037c611230565b3480156105ab57600080fd5b506103d060075481565b3480156105c157600080fd5b5060045461033a906001600160a01b031681565b3480156105e157600080fd5b506102786105f0366004612c6a565b6112c5565b34801561060157600080fd5b50600b5461037c9060ff1681565b34801561061b57600080fd5b506103d0600a5481565b34801561063157600080fd5b50610278610640366004612cec565b61131d565b34801561065157600080fd5b506103d0610660366004612d1d565b61136d565b34801561067157600080fd5b5060055461033a906001600160a01b031681565b34801561069157600080fd5b506103d06106a0366004612d1d565b611403565b3480156106b157600080fd5b5060015461033a9061010090046001600160a01b031681565b3480156106d657600080fd5b506103d061148d565b3480156106eb57600080fd5b506102786106fa366004612c6a565b6114ff565b34801561070b57600080fd5b5061027861071a366004612c6a565b611565565b34801561072b57600080fd5b5061027861073a366004612c6a565b611695565b34801561074b57600080fd5b5061037c61075a366004612d1d565b6117e5565b34801561076b57600080fd5b506103d061193a565b34801561078057600080fd5b5061027861078f366004612d1d565b611a0f565b3480156107a057600080fd5b506102786107af366004612d1d565b611a4c565b3480156107c057600080fd5b5060025461033a906001600160a01b031681565b3480156107e057600080fd5b50610278611a97565b3480156107f557600080fd5b50610278610804366004612d1d565b611bbb565b610811611d4f565b6006546001600160a01b039081169082160361085c5760405162461bcd60e51b8152602060048201526005602482015264085dd85b9d60da1b60448201526064015b60405180910390fd5b6002546001600160a01b03908116908216036108a45760405162461bcd60e51b81526020600482015260076024820152662173686172657360c81b6044820152606401610853565b60006108ae611d74565b905060005b8151811015610935578181815181106108ce576108ce612da8565b60200260200101516001600160a01b0316836001600160a01b0316036109235760405162461bcd60e51b815260206004820152600a602482015269085c1c9bdd1958dd195960b21b6044820152606401610853565b8061092d81612dd4565b9150506108b3565b506109bf610941611e20565b6040516370a0823160e01b81526001600160a01b038516906370a082319061096d903090600401612d09565b602060405180830381865afa15801561098a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109ae9190612ded565b6001600160a01b0385169190611e8e565b5050565b600080546109d090612e06565b80601f01602080910402602001604051908101604052809291908181526020018280546109fc90612e06565b8015610a495780601f10610a1e57610100808354040283529160200191610a49565b820191906000526020600020905b815481529060010190602001808311610a2c57829003601f168201915b505050505081565b610a59611ead565b600b805460ff19168215159081179091556040519081527f6ad28df1b554fa6cacd46ae82fa811748d53798feeb437ddf234bf3083953319906020015b60405180910390a150565b610aa9611ead565b7fc8db9c35f716b87af1fbb83f03c78646061931269301fd7ba6dcf189b4cdc2fc81604051610ad89190612d09565b60405180910390a1600180546001600160a01b0390921661010002610100600160a81b0319909216919091179055565b6002546040516339ebf82360e01b815260009182916001600160a01b03909116906339ebf82390610b3d903090600401612d09565b61012060405180830381865afa158015610b5b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b7f9190612e7a565b604001511180610b9657506000610b9461193a565b115b905090565b6002546000906001600160a01b03163314610be15760405162461bcd60e51b8152602060048201526006602482015265085d985d5b1d60d21b6044820152606401610853565b6000610bec83611f4f565b600654909350909150610c09906001600160a01b03163383611e8e565b50919050565b610c17612012565b60078190556040518181527fbb2c369a0355a34b02ab5fce0643150c87e1c8dfe7c918d465591879f57948b190602001610a96565b610c5461202e565b6002546040805163bf3759b560e01b81529051610cc8926001600160a01b03169163bf3759b59160048083019260209291908290030181865afa158015610c9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc39190612ded565b612183565b565b610cd261202e565b6000806000600260009054906101000a90046001600160a01b03166001600160a01b031663bf3759b56040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d4e9190612ded565b60095490915060009060ff1615610dab576000610d696122ef565b905082811015610d8457610d7d8184612ef5565b9350610d99565b82811115610d9957610d968382612ef5565b94505b610da38484612ef5565b915050610dbc565b610db48261239d565b919550935090505b600b805460ff19169055604051600081527f6ad28df1b554fa6cacd46ae82fa811748d53798feeb437ddf234bf30839533199060200160405180910390a16002546040516339ebf82360e01b81526000916001600160a01b0316906339ebf82390610e2b903090600401612d09565b61012060405180830381865afa158015610e49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6d9190612e7a565b60c001516002546040516328766ebf60e21b81526004810188905260248101879052604481018590529192506001600160a01b03169063a1d9bafc906064016020604051808303816000875af1158015610ecb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eef9190612ded565b9250610efa83612183565b60015460ff168015610f1b575060015461010090046001600160a01b031615155b15610fed5760015460405163c70fa00b60e01b815260048101879052602481018690526044810184905260648101859052608481018390526101009091046001600160a01b03169063c70fa00b9060a401602060405180830381865afa158015610f89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fad9190612f08565b610fe85760405162461bcd60e51b815260206004820152600c60248201526b216865616c7468636865636b60a01b6044820152606401610853565b61102e565b604051600181527ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b9060200160405180910390a16001805460ff1916811790555b6040805186815260208101869052908101839052606081018490527f4c0f499ffe6befa0ca7c826b0916cf87bea98de658013e76938489368d60d5099060800160405180910390a15050505050565b600060008051602061319d833981519152630a28a47761109c84611403565b6040518263ffffffff1660e01b81526004016110ba91815260200190565b602060405180830381865afa1580156110d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fb9190612ded565b92915050565b611109612012565b6001600160a01b03811661111c57600080fd5b600580546001600160a01b0319166001600160a01b0383161790556040517f2f202ddb4a2e345f6323ed90f8fc8559d770a7abbbeee84dde8aca3351fe715490610a96908390612d09565b61116f612012565b600061117c828483612f73565b507f300e67d5a415b6d015a471d9c7b95dd58f3e8290af965e84e0f845de2996dda682826040516111ae929190613033565b60405180910390a15050565b60405163266d6a8360e11b8152600481018290526000906110fb9060008051602061319d83398151915290634cdad506906024015b602060405180830381865afa15801561120c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106609190612ded565b60095460009061010090046001600160a01b031661124e5750600190565b600960019054906101000a90046001600160a01b03166001600160a01b03166334a9e75c6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112a1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b969190612f08565b6112cd611ead565b60098054610100600160a81b0319166101006001600160a01b038416021790556040517f711be97287cb9ec921887b9be36e148e1a27c6b158547b22b9704ffc54447a0f90610a96908390612d09565b611325611ead565b60405181151581527ff769f6bf659bbbdabf212d830720ce893eedc57f25ebb8e44edf5b300618a35b9060200160405180910390a16001805460ff1916911515919091179055565b6000670de0b6b3a76400008273a1f8a6807c402e4a15ef4eba36528a3fed24e5776001600160a01b03166386fc88d36040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113ef9190612ded565b6113f99190613062565b6110fb9190613079565b600073a1f8a6807c402e4a15ef4eba36528a3fed24e5776001600160a01b03166386fc88d36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611457573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061147b9190612ded565b6113f983670de0b6b3a7640000613062565b6006546040516370a0823160e01b81526000916001600160a01b0316906370a08231906114be903090600401612d09565b602060405180830381865afa1580156114db573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b969190612ded565b611507612012565b6001600160a01b03811661151a57600080fd5b600380546001600160a01b0319166001600160a01b0383161790556040517f352ececae6d7d1e6d26bcf2c549dfd55be1637e9b22dc0cf3b71ddb36097a6b490610a96908390612d09565b6002546001600160a01b0316331461157c57600080fd5b6002546040805163fbfa77cf60e01b815290516001600160a01b039283169284169163fbfa77cf9160048083019260209291908290030181865afa1580156115c8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ec919061309b565b6001600160a01b0316146115ff57600080fd5b611608816124c3565b6006546040516370a0823160e01b81526116929183916001600160a01b03909116906370a082319061163e903090600401612d09565b602060405180830381865afa15801561165b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061167f9190612ded565b6006546001600160a01b03169190611e8e565b50565b61169d612640565b6001600160a01b0381166116b057600080fd5b6002546004805460405163095ea7b360e01b81526001600160a01b039384169363095ea7b3936116e79390911691600091016130b8565b6020604051808303816000875af1158015611706573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061172a9190612f08565b50600480546001600160a01b0319166001600160a01b03838116918217835560025460405163095ea7b360e01b815291169263095ea7b39261177292909160001991016130b8565b6020604051808303816000875af1158015611791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b59190612f08565b507fafbb66abf8f3b719799940473a4052a3717cdd8e40fb6c8a3faadab316b1a06981604051610a969190612d09565b60006117ef610b08565b6117fb57506000919050565b611803611230565b61180f57506000919050565b600b5460ff161561182257506001919050565b6002546040516339ebf82360e01b81526000916001600160a01b0316906339ebf82390611853903090600401612d09565b61012060405180830381865afa158015611871573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118959190612e7a565b90506008548160a00151426118aa9190612ef5565b106118b85750600192915050565b600a54600260009054906101000a90046001600160a01b03166001600160a01b031663112c1f9b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561190e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119329190612ded565b119392505050565b600061194461148d565b6040516370a0823160e01b81529091506119bd9060008051602061319d833981519152906370a082319061197c903090600401612d09565b602060405180830381865afa158015611999573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061052e9190612ded565b6119c790826130d1565b6040516370a0823160e01b8152909150611a0590735e8422345238f34275888049021821e8e08caa1f906370a08231906111ef903090600401612d09565b610b9690826130d1565b611a17612012565b60088190556040518181527f5430e11864ad7aa9775b07d12657fe52df9aa2ba734355bd8ef8747be2c800c590602001610a96565b611a54612679565b6127108110611a925760405162461bcd60e51b815260206004820152600a602482015269215f736c69707061676560b01b6044820152606401610853565b600c55565b611a9f612690565b6009805460ff191660011790556002546040516339ebf82360e01b81526001600160a01b03909116906339ebf82390611adc903090600401612d09565b61012060405180830381865afa158015611afa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b1e9190612e7a565b6040015115611b9057600260009054906101000a90046001600160a01b03166001600160a01b031663a0e4af9a6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611b7757600080fd5b505af1158015611b8b573d6000803e3d6000fd5b505050505b6040517f97e963041e952738788b9d4871d854d282065b8f90a464928d6528f2e9a4fd0b90600090a1565b611bc3611ead565b600a8190556040518181527fe5ef7832c564a10cbe7b4f1e01ac33a406cb63fcf430a97a9af8616d150af5f390602001610a96565b801580611c725750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015611c4c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c709190612ded565b155b611cdd5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610853565b611d338363095ea7b360e01b8484604051602401611cfc9291906130b8565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526126ac565b505050565b6060611d47848460008561277e565b949350505050565b611d57611e20565b6001600160a01b0316336001600160a01b031614610cc857600080fd5b6040805160028082526060808301845292600092919060208301908036833701905050905060008051602061319d83398151915281600081518110611dbb57611dbb612da8565b60200260200101906001600160a01b031690816001600160a01b031681525050735e8422345238f34275888049021821e8e08caa1f81600181518110611e0357611e03612da8565b6001600160a01b0390921660209283029190910190910152919050565b60025460408051635aa6e67560e01b815290516000926001600160a01b031691635aa6e6759160048083019260209291908290030181865afa158015611e6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b96919061309b565b611d338363a9059cbb60e01b8484604051602401611cfc9291906130b8565b600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa158015611f00573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f24919061309b565b6001600160a01b0316336001600160a01b03161480611f465750611d57611e20565b610cc857600080fd5b6006546040516370a0823160e01b8152600091829182916001600160a01b0316906370a0823190611f84903090600401612d09565b602060405180830381865afa158015611fa1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc59190612ded565b905083811015611fec57611fe1611fdc8286612ef5565b612859565b611fe961148d565b90505b80841115612008579150816120018185612ef5565b915061200c565b8392505b50915091565b6003546001600160a01b0316331480611f465750611d57611e20565b6005546001600160a01b031633148061205157506003546001600160a01b031633145b80612074575061205f611e20565b6001600160a01b0316336001600160a01b0316145b806121065750600260009054906101000a90046001600160a01b03166001600160a01b031663452a93206040518163ffffffff1660e01b8152600401602060405180830381865afa1580156120cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f1919061309b565b6001600160a01b0316336001600160a01b0316145b80611f465750600260009054906101000a90046001600160a01b03166001600160a01b03166388a8d6026040518163ffffffff1660e01b8152600401602060405180830381865afa15801561215f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d57919061309b565b60095460ff16156121915750565b6006546040516370a0823160e01b81526000916001600160a01b0316906370a08231906121c2903090600401612d09565b602060405180830381865afa1580156121df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122039190612ded565b90508181111561227a5760006122198383612ef5565b600654604051632e1a7d4d60e01b8152600481018390529192506001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561226057600080fd5b505af1158015612274573d6000803e3d6000fd5b50505050505b47156109bf57604051634dcd454760e01b815273bafa44efe7901e04e39dad13167d089c559c113890634dcd45479047906122b9903090600401612d09565b6000604051808303818588803b1580156122d257600080fd5b505af11580156122e6573d6000803e3d6000fd5b50505050505050565b6040516370a0823160e01b815260009061236d9060008051602061319d833981519152906370a0823190612327903090600401612d09565b602060405180830381865afa158015612344573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123689190612ded565b6128eb565b6006546040516370a0823160e01b81526001600160a01b03909116906370a08231906114be903090600401612d09565b6000806000806123ab61193a565b6002546040516339ebf82360e01b81529192506000916001600160a01b03909116906339ebf823906123e1903090600401612d09565b61012060405180830381865afa1580156123ff573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124239190612e7a565b60c0015190508082106124455761243a8183612ef5565b945060009350612456565b600094506124538282612ef5565b93505b600061246061148d565b9050600061246e87896130d1565b905080821161248f57612484611fdc8383612ef5565b61248c61148d565b91505b8682116124a257819650600094506124b8565b6124b56124af8884612ef5565b89612971565b94505b505050509193909250565b6040516370a0823160e01b815260009060008051602061319d833981519152906370a08231906124f7903090600401612d09565b602060405180830381865afa158015612514573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125389190612ded565b905080156125595761255960008051602061319d8339815191528383611e8e565b6040516370a0823160e01b8152600090735e8422345238f34275888049021821e8e08caa1f906370a0823190612593903090600401612d09565b602060405180830381865afa1580156125b0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125d49190612ded565b905080156125fb576125fb735e8422345238f34275888049021821e8e08caa1f8483611e8e565b47801561263a576040516001600160a01b0385169082156108fc029083906000818181858888f19350505050158015612638573d6000803e3d6000fd5b505b50505050565b612648611e20565b6001600160a01b0316336001600160a01b03161480611f4657506003546001600160a01b03163314610cc857600080fd5b6003546001600160a01b03163314610cc857600080fd5b6003546001600160a01b0316331480612074575061205f611e20565b6000612701826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d389092919063ffffffff16565b805190915015611d33578080602001905181019061271f9190612f08565b611d335760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610853565b6060824710156127df5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610853565b600080866001600160a01b031685876040516127fb91906130e4565b60006040518083038185875af1925050503d8060008114612838576040519150601f19603f3d011682016040523d82523d6000602084013e61283d565b606091505b509150915061284e87838387612989565b979650505050505050565b60006128de6128678361107d565b6040516370a0823160e01b815260008051602061319d833981519152906370a0823190612898903090600401612d09565b602060405180830381865afa1580156128b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d99190612ded565b612971565b905080156109bf576109bf815b604051635d043b2960e11b8152600481018290523060248201819052604482015260008051602061319d8339815191529063ba087652906064016020604051808303816000875af1158015612944573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129689190612ded565b50611692612a02565b60008183106129805781612982565b825b9392505050565b606083156129f85782516000036129f1576001600160a01b0385163b6129f15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610853565b5081611d47565b611d478383612c2b565b6040516370a0823160e01b8152600090735e8422345238f34275888049021821e8e08caa1f906370a0823190612a3c903090600401612d09565b602060405180830381865afa158015612a59573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a7d9190612ded565b90506000612710600c54612a908461136d565b612a9a9190613062565b612aa49190613079565b6040805161012081018252735e8422345238f34275888049021821e8e08caa1f815273a1f8a6807c402e4a15ef4eba36528a3fed24e57760208083019190915273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee828401526006546001600160a01b03166060808401829052608080850192909252600060a080860182905260c080870183905260e0808801849052610100880184905288519081018952600195810186815292810184905290810194909452835285518083018752818152808501829052600f8188015283850152855180830187528181528085018290528087018290528387015285518083018752818152938401819052838601528101919091529151630d4f290960e21b8152929350917399a58482bd75cbab83b27ec03ca68ff489b5788f9063353ca42490612be8908590859089908990600401613100565b6020604051808303816000875af1158015612c07573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126389190612ded565b815115612c3b5781518083602001fd5b8060405162461bcd60e51b81526004016108539190612cab565b6001600160a01b038116811461169257600080fd5b600060208284031215612c7c57600080fd5b813561298281612c55565b60005b83811015612ca2578181015183820152602001612c8a565b50506000910152565b6020815260008251806020840152612cca816040850160208701612c87565b601f01601f19169190910160400192915050565b801515811461169257600080fd5b600060208284031215612cfe57600080fd5b813561298281612cde565b6001600160a01b0391909116815260200190565b600060208284031215612d2f57600080fd5b5035919050565b60008060208385031215612d4957600080fd5b823567ffffffffffffffff80821115612d6157600080fd5b818501915085601f830112612d7557600080fd5b813581811115612d8457600080fd5b866020828501011115612d9657600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612de657612de6612dbe565b5060010190565b600060208284031215612dff57600080fd5b5051919050565b600181811c90821680612e1a57607f821691505b602082108103610c0957634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715612e7457612e74612e3a565b60405290565b60006101208284031215612e8d57600080fd5b612e95612e50565b825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c082015260e083015160e08201526101008084015181830152508091505092915050565b818103818111156110fb576110fb612dbe565b600060208284031215612f1a57600080fd5b815161298281612cde565b601f821115611d3357600081815260208120601f850160051c81016020861015612f4c5750805b601f850160051c820191505b81811015612f6b57828155600101612f58565b505050505050565b67ffffffffffffffff831115612f8b57612f8b612e3a565b612f9f83612f998354612e06565b83612f25565b6000601f841160018114612fd35760008515612fbb5750838201355b600019600387901b1c1916600186901b178355612638565b600083815260209020601f19861690835b828110156130045786850135825560209485019460019092019101612fe4565b50868210156130215760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208152816020820152818360408301376000818301604090810191909152601f909201601f19160101919050565b80820281158282048414176110fb576110fb612dbe565b60008261309657634e487b7160e01b600052601260045260246000fd5b500490565b6000602082840312156130ad57600080fd5b815161298281612c55565b6001600160a01b03929092168252602082015260400190565b808201808211156110fb576110fb612dbe565b600082516130f6818460208701612c87565b9190910192915050565b6102e08101818660005b60098110156131325781516001600160a01b031683526020928301929091019060010161310a565b50505061012082018560005b60048110156131855781518360005b600381101561316c57825182526020928301929091019060010161314d565b505050606092909201916020919091019060010161313e565b5050506102a08201939093526102c001529291505056fe000000000000000000000000ac3e018457b222d93114458476f3e3416abbe38fa264697066735822122019002eccc6dc79895f03db84e1255f58449d9cc7dd18aa4244cfd8d93bb53d6964736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003edbe670d03c4a71367deda78e73ea4f8d68f2e4
-----Decoded View---------------
Arg [0] : _vault (address): 0x3edbE670D03C4A71367dedA78E73EA4f8d68F2E4
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000003edbe670d03c4a71367deda78e73ea4f8d68f2e4
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.