Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 107556638 | 934 days ago | 0 ETH | ||||
| 107556638 | 934 days ago | 0 ETH | ||||
| 107556638 | 934 days ago | 0 ETH | ||||
| 107556638 | 934 days ago | 0 ETH | ||||
| 107556638 | 934 days ago | 0 ETH | ||||
| 107556638 | 934 days ago | 0 ETH | ||||
| 107556638 | 934 days ago | 0 ETH | ||||
| 107556638 | 934 days ago | 0 ETH | ||||
| 107556638 | 934 days ago | 0 ETH | ||||
| 107556638 | 934 days ago | 0 ETH | ||||
| 107556638 | 934 days ago | 0 ETH | ||||
| 107553401 | 934 days ago | 0 ETH | ||||
| 107553401 | 934 days ago | 0 ETH | ||||
| 107553158 | 934 days ago | 0 ETH | ||||
| 107553158 | 934 days ago | 0 ETH | ||||
| 107553158 | 934 days ago | 0 ETH | ||||
| 107553158 | 934 days ago | 0 ETH | ||||
| 107553158 | 934 days ago | 0 ETH | ||||
| 107553158 | 934 days ago | 0 ETH | ||||
| 107553158 | 934 days ago | 0 ETH | ||||
| 107553148 | 934 days ago | 0 ETH | ||||
| 107553128 | 934 days ago | 0 ETH | ||||
| 107553128 | 934 days ago | 0 ETH | ||||
| 107553128 | 934 days ago | 0 ETH | ||||
| 107553110 | 934 days ago | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
VPool
Compiler Version
v0.8.9+commit.e5eed63a
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "../dependencies/openzeppelin/contracts/proxy/utils/Initializable.sol";
import "../dependencies/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../dependencies/openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./PoolERC20Permit.sol";
import "./PoolStorage.sol";
import "../Errors.sol";
import "../Governable.sol";
import "../Pausable.sol";
import "../interfaces/vesper/IPoolAccountant.sol";
import "../interfaces/vesper/IPoolRewards.sol";
import "vesper-commons/contracts/interfaces/vesper/IStrategy.sol";
/// @title Holding pool share token
// solhint-disable no-empty-blocks
contract VPool is Initializable, PoolERC20Permit, Governable, Pausable, ReentrancyGuard, PoolStorageV3 {
using SafeERC20 for IERC20;
using EnumerableSet for EnumerableSet.AddressSet;
string public constant VERSION = "5.1.0";
uint256 public constant MAX_BPS = 10_000;
// For simplicity we are assuming 365 days as 1 year
uint256 public constant ONE_YEAR = 365 days;
event UpdatedMaximumProfitAsFee(uint256 oldMaxProfitAsFee, uint256 newMaxProfitAsFee);
event UpdatedMinimumDepositLimit(uint256 oldDepositLimit, uint256 newDepositLimit);
event Deposit(address indexed owner, uint256 shares, uint256 amount);
event Withdraw(address indexed owner, uint256 shares, uint256 amount);
event UpdatedUniversalFee(uint256 oldUniversalFee, uint256 newUniversalFee);
event UpdatedPoolRewards(address indexed previousPoolRewards, address indexed newPoolRewards);
event UpdatedWithdrawFee(uint256 previousWithdrawFee, uint256 newWithdrawFee);
event UniversalFeePaid(uint256 strategyDebt, uint256 profit, uint256 fee);
// We are using constructor to initialize implementation with basic details
constructor(string memory name_, string memory symbol_, address token_) PoolERC20(name_, symbol_) {
// 0x0 is acceptable as has no effect on functionality
token = IERC20(token_);
}
/// @dev Equivalent to constructor for proxy. It can be called only once per proxy.
function initialize(
string memory name_,
string memory symbol_,
address token_,
address poolAccountant_
) public initializer {
require(token_ != address(0), Errors.INPUT_ADDRESS_IS_ZERO);
require(poolAccountant_ != address(0), Errors.INPUT_ADDRESS_IS_ZERO);
__ERC20_init(name_, symbol_);
__ERC20Permit_init(name_);
__Governable_init();
token = IERC20(token_);
require(_keepers.add(_msgSender()), Errors.ADD_IN_LIST_FAILED);
require(_maintainers.add(_msgSender()), Errors.ADD_IN_LIST_FAILED);
poolAccountant = poolAccountant_;
universalFee = 200; // 2%
maxProfitAsFee = 5_000; // 50%
minDepositLimit = 1;
}
modifier onlyKeeper() {
require(governor == _msgSender() || _keepers.contains(_msgSender()), "not-a-keeper");
_;
}
modifier onlyMaintainer() {
require(governor == _msgSender() || _maintainers.contains(_msgSender()), "not-a-maintainer");
_;
}
/**
* @notice Get available credit limit of strategy. This is the amount strategy can borrow from pool
* @dev Available credit limit is calculated based on current debt of pool and strategy, current debt limit of pool and strategy.
* credit available = min(pool's debt limit, strategy's debt limit, max debt per rebalance)
* when some strategy do not pay back outstanding debt, this impact credit line of other strategy if totalDebt of pool >= debtLimit of pool
* @param strategy_ Strategy address
*/
function availableCreditLimit(address strategy_) external view returns (uint256) {
return IPoolAccountant(poolAccountant).availableCreditLimit(strategy_);
}
/**
* @notice Calculate how much shares user will get for given amount. Also return externalDepositFee if any.
* @param amount_ Collateral amount
* @return _shares Amount of share that user will get
* @dev Amount should be >= minimum deposit limit which default to 1
*/
function calculateMintage(uint256 amount_) public view returns (uint256 _shares) {
require(amount_ >= minDepositLimit, Errors.INVALID_COLLATERAL_AMOUNT);
uint256 _externalDepositFee = (amount_ * IPoolAccountant(poolAccountant).externalDepositFee()) / MAX_BPS;
_shares = _calculateShares(amount_ - _externalDepositFee);
}
/**
* @notice Calculate universal fee for calling strategy. This is only strategy function.
* @dev Earn strategies will call this during rebalance.
*/
function calculateUniversalFee(uint256 profit_) external view returns (uint256 _fee) {
return _calculateUniversalFee(_msgSender(), profit_);
}
/**
* @notice Deposit ERC20 tokens and receive pool shares depending on the current share price.
* @param amount_ ERC20 token amount.
*/
function deposit(uint256 amount_) external nonReentrant whenNotPaused {
_updateRewards(_msgSender());
_deposit(amount_);
}
/**
* @notice Deposit ERC20 tokens and claim rewards if any
* @param amount_ ERC20 token amount.
*/
function depositAndClaim(uint256 amount_) external nonReentrant whenNotPaused {
_claimRewards(_msgSender());
_deposit(amount_);
}
/**
* @notice Deposit ERC20 tokens with permit aka gasless approval.
* @param amount_ ERC20 token amount.
* @param deadline_ The time at which signature will expire
* @param v_ The recovery byte of the signature
* @param r_ Half of the ECDSA signature pair
* @param s_ Half of the ECDSA signature pair
*/
function depositWithPermit(
uint256 amount_,
uint256 deadline_,
uint8 v_,
bytes32 r_,
bytes32 s_
) external nonReentrant whenNotPaused {
IERC20Permit(address(token)).permit(_msgSender(), address(this), amount_, deadline_, v_, r_, s_);
_updateRewards(_msgSender());
_deposit(amount_);
}
/**
* @notice Debt above current debt limit
* @param strategy_ Address of strategy
*/
function excessDebt(address strategy_) external view returns (uint256) {
return IPoolAccountant(poolAccountant).excessDebt(strategy_);
}
function getStrategies() external view returns (address[] memory) {
return IPoolAccountant(poolAccountant).getStrategies();
}
function getWithdrawQueue() public view returns (address[] memory) {
return IPoolAccountant(poolAccountant).getWithdrawQueue();
}
/**
* @notice Get price per share
* @dev Return value will be in token defined decimals.
*/
function pricePerShare() public view returns (uint256) {
if (totalSupply() == 0 || totalValue() == 0) {
return 10 ** IERC20Metadata(address(token)).decimals();
}
return (totalValue() * 1e18) / totalSupply();
}
/**
* @notice Strategy call this in regular interval. Only strategy function.
* @param profit_ yield generated by strategy. Strategy get performance fee on this amount
* @param loss_ Reduce debt ,also reduce debtRatio, increase loss in record.
* @param payback_ strategy willing to payback outstanding above debtLimit. no performance fee on this amount.
* when governance has reduced debtRatio of strategy, strategy will report profit and payback amount separately.
*/
function reportEarning(uint256 profit_, uint256 loss_, uint256 payback_) external {
address _strategy = _msgSender();
// Calculate universal fee
if (profit_ > 0) {
(, , , uint256 _lastRebalanceAt, uint256 _totalDebt, , , , ) = IPoolAccountant(poolAccountant).strategy(
_strategy
);
uint256 _fee = _calculateUniversalFee(_lastRebalanceAt, _totalDebt, profit_);
// Mint shares equal to universal fee
if (_fee > 0) {
_mint(IStrategy(_strategy).feeCollector(), _calculateShares(_fee));
emit UniversalFeePaid(_totalDebt, profit_, _fee);
}
}
// Report earning in pool accountant
(uint256 _actualPayback, uint256 _creditLine) = IPoolAccountant(poolAccountant).reportEarning(
_strategy,
profit_,
loss_,
payback_
);
uint256 _totalPayback = profit_ + _actualPayback;
// After payback, if strategy has credit line available then send more fund to strategy
// If payback is more than available credit line then get fund from strategy
if (_totalPayback < _creditLine) {
token.safeTransfer(_strategy, _creditLine - _totalPayback);
} else if (_totalPayback > _creditLine) {
token.safeTransferFrom(_strategy, address(this), _totalPayback - _creditLine);
}
}
/**
* @notice Report loss outside of rebalance activity.
* @dev Some strategies pay deposit fee thus realizing loss at deposit.
* For example: Curve's 3pool has some slippage due to deposit of one asset in 3pool.
* Strategy may want report this loss instead of waiting for next rebalance.
* @param loss_ Loss that strategy want to report
*/
function reportLoss(uint256 loss_) external {
if (loss_ > 0) {
IPoolAccountant(poolAccountant).reportLoss(_msgSender(), loss_);
}
}
function strategy(
address strategy_
)
public
view
returns (
bool _active,
uint256 _interestFee, // Obsolete
uint256 _debtRate, // Obsolete
uint256 _lastRebalance,
uint256 _totalDebt,
uint256 _totalLoss,
uint256 _totalProfit,
uint256 _debtRatio,
uint256 _externalDepositFee
)
{
return IPoolAccountant(poolAccountant).strategy(strategy_);
}
/// @dev Returns the token stored in the pool. It will be in token defined decimals.
function tokensHere() public view returns (uint256) {
return token.balanceOf(address(this));
}
/// @notice Get total debt of pool
function totalDebt() external view returns (uint256) {
return IPoolAccountant(poolAccountant).totalDebt();
}
/**
* @notice Get total debt of given strategy
* @param strategy_ Strategy address
*/
function totalDebtOf(address strategy_) external view returns (uint256) {
return IPoolAccountant(poolAccountant).totalDebtOf(strategy_);
}
/// @notice Get total debt ratio. Total debt ratio helps us keep buffer in pool
function totalDebtRatio() external view returns (uint256) {
return IPoolAccountant(poolAccountant).totalDebtRatio();
}
/**
* @notice Returns sum of token locked in other contracts and token stored in the pool.
* It will be in token defined decimals.
*/
function totalValue() public view returns (uint256) {
return IPoolAccountant(poolAccountant).totalDebt() + tokensHere();
}
/**
* @notice Withdraw collateral based on given shares and the current share price.
* Burn remaining shares and return collateral.
* @param shares_ Pool shares. It will be in 18 decimals.
*/
function withdraw(uint256 shares_) external nonReentrant whenNotShutdown {
_updateRewards(_msgSender());
_withdraw(shares_);
}
/**
* @notice Withdraw collateral and claim rewards if any
* @param shares_ Pool shares. It will be in 18 decimals.
*/
function withdrawAndClaim(uint256 shares_) external nonReentrant whenNotShutdown {
_claimRewards(_msgSender());
_withdraw(shares_);
}
/**
* @dev Hook that is called just after burning tokens.
* @param amount_ Collateral amount in collateral token defined decimals.
*/
function _afterBurning(uint256 amount_) internal virtual returns (uint256) {
token.safeTransfer(_msgSender(), amount_);
return amount_;
}
/**
* @dev Before burning hook.
* withdraw amount from strategies
*/
function _beforeBurning(uint256 share_) private returns (uint256 _amount, bool _isPartial) {
_amount = (share_ * pricePerShare()) / 1e18;
uint256 _tokensHere = tokensHere();
// Check for partial withdraw scenario
// If we do not have enough tokens then withdraw whats needed from strategy
if (_amount > _tokensHere) {
// Strategy may withdraw partial
_withdrawCollateral(_amount - _tokensHere);
_tokensHere = tokensHere();
if (_amount > _tokensHere) {
_amount = _tokensHere;
_isPartial = true;
}
}
require(_amount > 0, Errors.INVALID_COLLATERAL_AMOUNT);
}
/**
* @dev Calculate shares to mint/burn based on the current share price and given amount.
* @param amount_ Collateral amount in collateral token defined decimals.
* @return share amount in 18 decimal
*/
function _calculateShares(uint256 amount_) private view returns (uint256) {
uint256 _share = ((amount_ * 1e18) / pricePerShare());
return amount_ > ((_share * pricePerShare()) / 1e18) ? _share + 1 : _share;
}
/**
* @dev Calculate universal fee based on strategy's TVL, profit earned and duration between rebalance and now.
*/
function _calculateUniversalFee(address strategy_, uint256 profit_) private view returns (uint256 _fee) {
// Calculate universal fee
(, , , uint256 _lastRebalance, uint256 _totalDebt, , , , ) = IPoolAccountant(poolAccountant).strategy(
strategy_
);
return _calculateUniversalFee(_lastRebalance, _totalDebt, profit_);
}
function _calculateUniversalFee(
uint256 lastRebalance_,
uint256 totalDebt_,
uint256 profit_
) private view returns (uint256 _fee) {
_fee = (universalFee * (block.timestamp - lastRebalance_) * totalDebt_) / (MAX_BPS * ONE_YEAR);
uint256 _maxFee = (profit_ * maxProfitAsFee) / MAX_BPS;
if (_fee > _maxFee) {
_fee = _maxFee;
}
}
/// @notice claim rewards of account
function _claimRewards(address account_) internal {
if (poolRewards != address(0)) {
IPoolRewards(poolRewards).claimReward(account_);
}
}
/// @dev Deposit incoming token and mint pool token i.e. shares.
function _deposit(uint256 amount_) internal {
uint256 _shares = calculateMintage(amount_);
token.safeTransferFrom(_msgSender(), address(this), amount_);
_mint(_msgSender(), _shares);
emit Deposit(_msgSender(), _shares, amount_);
}
/// @dev Update pool rewards of sender and receiver during transfer.
/// @dev _beforeTokenTransfer can be used to replace _transfer and _updateRewards but that
/// will increase gas cost of deposit, withdraw and transfer.
function _transfer(address sender_, address recipient_, uint256 amount_) internal override {
if (poolRewards != address(0)) {
IPoolRewards(poolRewards).updateReward(sender_);
IPoolRewards(poolRewards).updateReward(recipient_);
}
super._transfer(sender_, recipient_, amount_);
}
function _updateRewards(address account_) internal {
if (poolRewards != address(0)) {
IPoolRewards(poolRewards).updateReward(account_);
}
}
/// @dev Burns shares and returns the collateral value, after fee, of those.
function _withdraw(uint256 shares_) internal {
require(shares_ > 0, Errors.INVALID_SHARE_AMOUNT);
(uint256 _amountWithdrawn, bool _isPartial) = _beforeBurning(shares_);
// There may be scenarios when pool is not able to withdraw all of requested amount
if (_isPartial) {
// Recalculate proportional share on actual amount withdrawn
uint256 _proportionalShares = _calculateShares(_amountWithdrawn);
if (_proportionalShares < shares_) {
shares_ = _proportionalShares;
}
}
_burn(_msgSender(), shares_);
_afterBurning(_amountWithdrawn);
emit Withdraw(_msgSender(), shares_, _amountWithdrawn);
}
function _withdrawCollateral(uint256 amount_) internal {
// Withdraw amount from queue
uint256 _debt;
uint256 _balanceBefore;
uint256 _amountWithdrawn;
uint256 _totalAmountWithdrawn;
address[] memory _withdrawQueue = getWithdrawQueue();
uint256 _len = _withdrawQueue.length;
for (uint256 i; i < _len; i++) {
uint256 _amountNeeded = amount_ - _totalAmountWithdrawn;
address _strategy = _withdrawQueue[i];
_debt = IPoolAccountant(poolAccountant).totalDebtOf(_strategy);
if (_debt == 0) {
continue;
}
if (_amountNeeded > _debt) {
// Should not withdraw more than current debt of strategy.
_amountNeeded = _debt;
}
_balanceBefore = tokensHere();
//solhint-disable no-empty-blocks
try IStrategy(_strategy).withdraw(_amountNeeded) {} catch {
continue;
}
_amountWithdrawn = tokensHere() - _balanceBefore;
// Adjusting totalDebt. Assuming that during next reportEarning(), strategy will report loss if amountWithdrawn < _amountNeeded
IPoolAccountant(poolAccountant).decreaseDebt(_strategy, _amountWithdrawn);
_totalAmountWithdrawn += _amountWithdrawn;
if (_totalAmountWithdrawn >= amount_) {
// withdraw done
break;
}
}
}
/************************************************************************************************
* Authorized function *
***********************************************************************************************/
////////////////////////////// Only Governor //////////////////////////////
/**
* @notice Migrate existing strategy to new strategy.
* @dev Migrating strategy aka old and new strategy should be of same type.
* @param old_ Address of strategy being migrated
* @param new_ Address of new strategy
*/
function migrateStrategy(address old_, address new_) external onlyGovernor {
require(
IStrategy(new_).pool() == address(this) && IStrategy(old_).pool() == address(this),
Errors.INVALID_STRATEGY
);
IPoolAccountant(poolAccountant).migrateStrategy(old_, new_);
IStrategy(old_).migrate(new_);
}
/**
* Only Governor:: Update maximum profit that can be used as universal fee
* @param newMaxProfitAsFee_ New max profit as fee
*/
function updateMaximumProfitAsFee(uint256 newMaxProfitAsFee_) external onlyGovernor {
require(newMaxProfitAsFee_ != maxProfitAsFee, Errors.SAME_AS_PREVIOUS);
emit UpdatedMaximumProfitAsFee(maxProfitAsFee, newMaxProfitAsFee_);
maxProfitAsFee = newMaxProfitAsFee_;
}
/**
* Only Governor:: Update minimum deposit limit
* @param newLimit_ New minimum deposit limit
*/
function updateMinimumDepositLimit(uint256 newLimit_) external onlyGovernor {
require(newLimit_ > 0, Errors.INVALID_INPUT);
require(newLimit_ != minDepositLimit, Errors.SAME_AS_PREVIOUS);
emit UpdatedMinimumDepositLimit(minDepositLimit, newLimit_);
minDepositLimit = newLimit_;
}
/**
* @notice Update pool rewards address for this pool
* @param newPoolRewards_ new pool rewards address
*/
function updatePoolRewards(address newPoolRewards_) external onlyGovernor {
require(newPoolRewards_ != address(0), Errors.INPUT_ADDRESS_IS_ZERO);
emit UpdatedPoolRewards(poolRewards, newPoolRewards_);
poolRewards = newPoolRewards_;
}
/**
* @notice Update universal fee for this pool
* @dev Format: 1500 = 15% fee, 100 = 1%
* @param newUniversalFee_ new universal fee
*/
function updateUniversalFee(uint256 newUniversalFee_) external onlyGovernor {
require(newUniversalFee_ <= MAX_BPS, Errors.FEE_LIMIT_REACHED);
emit UpdatedUniversalFee(universalFee, newUniversalFee_);
universalFee = newUniversalFee_;
}
///////////////////////////// Only Keeper ///////////////////////////////
/**
* @dev Transfer given ERC20 token to governor
* @param fromToken_ Token address to sweep
*/
function sweepERC20(address fromToken_) external onlyKeeper {
require(fromToken_ != address(token), Errors.NOT_ALLOWED_TO_SWEEP);
IERC20(fromToken_).safeTransfer(governor, IERC20(fromToken_).balanceOf(address(this)));
}
function pause() external onlyKeeper {
_pause();
}
function unpause() external onlyKeeper {
_unpause();
}
function shutdown() external onlyKeeper {
_shutdown();
}
function open() external onlyKeeper {
_open();
}
/// @notice Return list of keepers
function keepers() external view returns (address[] memory) {
return _keepers.values();
}
function isKeeper(address address_) external view returns (bool) {
return _keepers.contains(address_);
}
/**
* @notice Add given address in keepers list.
* @param keeperAddress_ keeper address to add.
*/
function addKeeper(address keeperAddress_) external onlyKeeper {
require(_keepers.add(keeperAddress_), Errors.ADD_IN_LIST_FAILED);
}
/**
* @notice Remove given address from keepers list.
* @param keeperAddress_ keeper address to remove.
*/
function removeKeeper(address keeperAddress_) external onlyKeeper {
require(_keepers.remove(keeperAddress_), Errors.REMOVE_FROM_LIST_FAILED);
}
/// @notice Return list of maintainers
function maintainers() external view returns (address[] memory) {
return _maintainers.values();
}
function isMaintainer(address address_) external view returns (bool) {
return _maintainers.contains(address_);
}
/**
* @notice Add given address in maintainers list.
* @param maintainerAddress_ maintainer address to add.
*/
function addMaintainer(address maintainerAddress_) external onlyKeeper {
require(_maintainers.add(maintainerAddress_), Errors.ADD_IN_LIST_FAILED);
}
/**
* @notice Remove given address from maintainers list.
* @param maintainerAddress_ maintainer address to remove.
*/
function removeMaintainer(address maintainerAddress_) external onlyKeeper {
require(_maintainers.remove(maintainerAddress_), Errors.REMOVE_FROM_LIST_FAILED);
}
///////////////////////////////////////////////////////////////////////////
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
interface IStrategy {
function rebalance() external returns (uint256 _profit, uint256 _loss, uint256 _payback);
function sweep(address _fromToken) external;
function withdraw(uint256 _amount) external;
function feeCollector() external view returns (address);
function isReservedToken(address _token) external view returns (bool);
function keepers() external view returns (address[] memory);
function migrate(address _newStrategy) external;
function token() external view returns (address);
function pool() external view returns (address);
// solhint-disable-next-line func-name-mixedcase
function VERSION() external view returns (string memory);
function collateral() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
/// @title Errors library
library Errors {
string public constant INVALID_COLLATERAL_AMOUNT = "1"; // Collateral must be greater than 0 or > defined limit
string public constant INVALID_SHARE_AMOUNT = "2"; // Share must be greater than 0
string public constant INVALID_INPUT_LENGTH = "3"; // Input array length must be greater than 0
string public constant INPUT_LENGTH_MISMATCH = "4"; // Input array length mismatch with another array length
string public constant NOT_WHITELISTED_ADDRESS = "5"; // Caller is not whitelisted to withdraw without fee
string public constant MULTI_TRANSFER_FAILED = "6"; // Multi transfer of tokens has failed
string public constant FEE_COLLECTOR_NOT_SET = "7"; // Fee Collector is not set
string public constant NOT_ALLOWED_TO_SWEEP = "8"; // Token is not allowed to sweep
string public constant INSUFFICIENT_BALANCE = "9"; // Insufficient balance to performs operations to follow
string public constant INPUT_ADDRESS_IS_ZERO = "10"; // Input address is zero
string public constant FEE_LIMIT_REACHED = "11"; // Fee must be less than MAX_BPS
string public constant ALREADY_INITIALIZED = "12"; // Data structure, contract, or logic already initialized and can not be called again
string public constant ADD_IN_LIST_FAILED = "13"; // Cannot add address in address list
string public constant REMOVE_FROM_LIST_FAILED = "14"; // Cannot remove address from address list
string public constant STRATEGY_IS_ACTIVE = "15"; // Strategy is already active, an inactive strategy is required
string public constant STRATEGY_IS_NOT_ACTIVE = "16"; // Strategy is not active, an active strategy is required
string public constant INVALID_STRATEGY = "17"; // Given strategy is not a strategy of this pool
string public constant DEBT_RATIO_LIMIT_REACHED = "18"; // Debt ratio limit reached. It must be less than MAX_BPS
string public constant TOTAL_DEBT_IS_NOT_ZERO = "19"; // Strategy total debt must be 0
string public constant LOSS_TOO_HIGH = "20"; // Strategy reported loss must be less than current debt
string public constant INVALID_MAX_BORROW_LIMIT = "21"; // Max borrow limit is beyond range.
string public constant MAX_LIMIT_LESS_THAN_MIN = "22"; // Max limit should be greater than min limit.
string public constant INVALID_SLIPPAGE = "23"; // Slippage should be less than MAX_BPS
string public constant WRONG_RECEIPT_TOKEN = "24"; // Wrong receipt token address
string public constant AAVE_FLASH_LOAN_NOT_ACTIVE = "25"; // aave flash loan is not active
string public constant DYDX_FLASH_LOAN_NOT_ACTIVE = "26"; // DYDX flash loan is not active
string public constant INVALID_FLASH_LOAN = "27"; // invalid-flash-loan
string public constant INVALID_INITIATOR = "28"; // "invalid-initiator"
string public constant INCORRECT_WITHDRAW_AMOUNT = "29"; // withdrawn amount is not correct
string public constant NO_MARKET_ID_FOUND = "30"; // dydx flash loan no marketId found for token
string public constant SAME_AS_PREVIOUS = "31"; // Input should not be same as previous value.
string public constant INVALID_INPUT = "32"; // Generic invalid input error code
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "./dependencies/openzeppelin/contracts/proxy/utils/Initializable.sol";
import "./dependencies/openzeppelin/contracts/utils/Context.sol";
import "./interfaces/vesper/IGovernable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (governor) that can be granted exclusive access to
* specific functions.
*
* By default, the governor account will be the one that deploys the contract. This
* can later be changed with {transferGovernorship}.
*
*/
abstract contract Governable is IGovernable, Context, Initializable {
address public governor;
address private proposedGovernor;
event UpdatedGovernor(address indexed previousGovernor, address indexed proposedGovernor);
/**
* @dev Initializes the contract setting the deployer as the initial governor.
*/
constructor() {
address msgSender = _msgSender();
governor = msgSender;
emit UpdatedGovernor(address(0), msgSender);
}
/**
* @dev If inheriting child is using proxy then child contract can use
* __Governable_init() function to initialization this contract
*/
// solhint-disable-next-line func-name-mixedcase
function __Governable_init() internal initializer {
address msgSender = _msgSender();
governor = msgSender;
emit UpdatedGovernor(address(0), msgSender);
}
/**
* @dev Throws if called by any account other than the governor.
*/
modifier onlyGovernor() {
require(governor == _msgSender(), "not-governor");
_;
}
/**
* @dev Transfers governorship of the contract to a new account (`proposedGovernor`).
* Can only be called by the current owner.
*/
function transferGovernorship(address _proposedGovernor) external onlyGovernor {
require(_proposedGovernor != address(0), "proposed-governor-is-zero");
proposedGovernor = _proposedGovernor;
}
/**
* @dev Allows new governor to accept governorship of the contract.
*/
function acceptGovernorship() external {
require(proposedGovernor == _msgSender(), "not-the-proposed-governor");
emit UpdatedGovernor(governor, proposedGovernor);
governor = proposedGovernor;
proposedGovernor = address(0);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "./dependencies/openzeppelin/contracts/utils/Context.sol";
import "./interfaces/vesper/IPausable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
*/
abstract contract Pausable is IPausable, Context {
event Paused(address account);
event Shutdown(address account);
event Unpaused(address account);
event Open(address account);
bool public paused;
bool public stopEverything;
modifier whenNotPaused() {
require(!paused, "paused");
_;
}
modifier whenPaused() {
require(paused, "not-paused");
_;
}
modifier whenNotShutdown() {
require(!stopEverything, "shutdown");
_;
}
modifier whenShutdown() {
require(stopEverything, "not-shutdown");
_;
}
/// @dev Pause contract operations, if contract is not paused.
function _pause() internal virtual whenNotPaused {
paused = true;
emit Paused(_msgSender());
}
/// @dev Unpause contract operations, allow only if contract is paused and not shutdown.
function _unpause() internal virtual whenPaused whenNotShutdown {
paused = false;
emit Unpaused(_msgSender());
}
/// @dev Shutdown contract operations, if not already shutdown.
function _shutdown() internal virtual whenNotShutdown {
stopEverything = true;
paused = true;
emit Shutdown(_msgSender());
}
/// @dev Open contract operations, if contract is in shutdown state
function _open() internal virtual whenShutdown {
stopEverything = false;
emit Open(_msgSender());
}
}// SPDX-License-Identifier: MIT
// solhint-disable-next-line compiler-version
pragma solidity ^0.8.0;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
require(_initializing || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor () {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: MIT
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
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
pragma solidity ^0.8.0;
import "../IERC20.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'
// solhint-disable-next-line max-line-length
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
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) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
// Divide the signature in r, s and v variables
bytes32 r;
bytes32 s;
uint8 v;
// Check the signature length
// - case 65: r,s,v signature (standard)
// - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
if (signature.length == 65) {
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
// solhint-disable-next-line no-inline-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
} else if (signature.length == 64) {
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
// solhint-disable-next-line no-inline-assembly
assembly {
let vs := mload(add(signature, 0x40))
r := mload(add(signature, 0x20))
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 27)
}
} else {
revert("ECDSA: invalid signature length");
}
return recover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value");
require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value");
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
require(signer != address(0), "ECDSA: invalid signature");
return signer;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastvalue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastvalue;
// Update the index for the moved value
set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
/**
* @notice Governable interface
*/
interface IGovernable {
function governor() external view returns (address _governor);
function transferGovernorship(address _proposedGovernor) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
/**
* @notice Pausable interface
*/
interface IPausable {
function paused() external view returns (bool);
function stopEverything() external view returns (bool);
function pause() external;
function unpause() external;
function shutdown() external;
function open() external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
interface IPoolAccountant {
function decreaseDebt(address strategy_, uint256 decreaseBy_) external;
function migrateStrategy(address old_, address new_) external;
function reportEarning(
address strategy_,
uint256 profit_,
uint256 loss_,
uint256 payback_
) external returns (uint256 _actualPayback, uint256 _creditLine);
function reportLoss(address strategy_, uint256 loss_) external;
function availableCreditLimit(address strategy_) external view returns (uint256);
function excessDebt(address strategy_) external view returns (uint256);
function getStrategies() external view returns (address[] memory);
function getWithdrawQueue() external view returns (address[] memory);
function strategy(
address strategy_
)
external
view
returns (
bool _active,
uint256 _interestFee, // Obsolete
uint256 _debtRate, // Obsolete
uint256 _lastRebalance,
uint256 _totalDebt,
uint256 _totalLoss,
uint256 _totalProfit,
uint256 _debtRatio,
uint256 _externalDepositFee
);
function externalDepositFee() external view returns (uint256);
function totalDebt() external view returns (uint256);
function totalDebtOf(address strategy_) external view returns (uint256);
function totalDebtRatio() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
interface IPoolRewards {
/// Emitted after reward added
event RewardAdded(address indexed rewardToken, uint256 reward, uint256 rewardDuration);
/// Emitted whenever any user claim rewards
event RewardPaid(address indexed user, address indexed rewardToken, uint256 reward);
/// Emitted after adding new rewards token into rewardTokens array
event RewardTokenAdded(address indexed rewardToken, address[] existingRewardTokens);
function claimReward(address) external;
function notifyRewardAmount(address rewardToken_, uint256 _rewardAmount, uint256 _rewardDuration) external;
function notifyRewardAmount(
address[] memory rewardTokens_,
uint256[] memory rewardAmounts_,
uint256[] memory rewardDurations_
) external;
function updateReward(address) external;
function claimable(
address account_
) external view returns (address[] memory _rewardTokens, uint256[] memory _claimableAmounts);
function lastTimeRewardApplicable(address rewardToken_) external view returns (uint256);
function rewardForDuration()
external
view
returns (address[] memory _rewardTokens, uint256[] memory _rewardForDuration);
function rewardPerToken()
external
view
returns (address[] memory _rewardTokens, uint256[] memory _rewardPerTokenRate);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "../../dependencies/openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "./IGovernable.sol";
import "./IPausable.sol";
interface IVesperPool is IGovernable, IPausable, IERC20Metadata {
function calculateUniversalFee(uint256 profit_) external view returns (uint256 _fee);
function deposit(uint256 collateralAmount_) external;
function excessDebt(address strategy_) external view returns (uint256);
function poolAccountant() external view returns (address);
function poolRewards() external view returns (address);
function reportEarning(uint256 profit_, uint256 loss_, uint256 payback_) external;
function reportLoss(uint256 loss_) external;
function sweepERC20(address fromToken_) external;
function withdraw(uint256 share_) external;
function keepers() external view returns (address[] memory);
function isKeeper(address address_) external view returns (bool);
function maintainers() external view returns (address[] memory);
function isMaintainer(address address_) external view returns (bool);
function pricePerShare() external view returns (uint256);
function strategy(
address strategy_
)
external
view
returns (
bool _active,
uint256 _interestFee, // Obsolete
uint256 _debtRate, // Obsolete
uint256 _lastRebalance,
uint256 _totalDebt,
uint256 _totalLoss,
uint256 _totalProfit,
uint256 _debtRatio,
uint256 _externalDepositFee
);
function token() external view returns (IERC20);
function tokensHere() external view returns (uint256);
function totalDebtOf(address strategy_) external view returns (uint256);
function totalValue() external view returns (uint256);
function totalDebt() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "../dependencies/openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../dependencies/openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "../dependencies/openzeppelin/contracts/utils/Context.sol";
// solhint-disable reason-string, no-empty-blocks
///@title Pool ERC20 to use with proxy. Inspired by OpenZeppelin ERC20
abstract contract PoolERC20 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}.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Sets the values for {name} and {symbol} for proxy
*/
// solhint-disable-next-line func-name-mixedcase
function __ERC20_init(string memory name_, string memory symbol_) internal {
_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 decimals of the token. default to 18
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev Returns total supply of the token.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* Requirements:
*
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
uint256 currentAllowance = _allowances[sender][_msgSender()];
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
_approve(sender, _msgSender(), currentAllowance - amount);
return true;
}
/**
* @dev Moves tokens `amount` from `sender` to `recipient`.
*
* This is internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
_balances[sender] = senderBalance - amount;
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `to` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
}
/**
* @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");
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be to 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 {}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "../dependencies/openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol";
import "../dependencies/openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "./PoolERC20.sol";
///@title Pool ERC20 Permit to use with proxy. Inspired by OpenZeppelin ERC20Permit
// solhint-disable var-name-mixedcase
abstract contract PoolERC20Permit is PoolERC20, IERC20Permit {
bytes32 private constant _EIP712_VERSION = keccak256(bytes("1"));
bytes32 private constant _EIP712_DOMAIN_TYPEHASH =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
bytes32 private constant _PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 private _CACHED_DOMAIN_SEPARATOR;
bytes32 private _HASHED_NAME;
uint256 private _CACHED_CHAIN_ID;
/**
* @dev See {IERC20Permit-nonces}.
*/
mapping(address => uint256) public override nonces;
/**
* @dev Initializes the domain separator using the `name` parameter, and setting `version` to `"1"`.
* It's a good idea to use the same `name` that is defined as the ERC20 token name.
*/
// solhint-disable-next-line func-name-mixedcase
function __ERC20Permit_init(string memory name_) internal {
_HASHED_NAME = keccak256(bytes(name_));
_CACHED_CHAIN_ID = block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(_EIP712_DOMAIN_TYPEHASH, _HASHED_NAME, _EIP712_VERSION);
}
/**
* @dev See {IERC20Permit-permit}.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
// solhint-disable-next-line not-rely-on-time
require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
uint256 _currentNonce = nonces[owner];
bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _currentNonce, deadline));
bytes32 hash = keccak256(abi.encodePacked("\x19\x01", _domainSeparatorV4(), structHash));
address signer = ECDSA.recover(hash, v, r, s);
require(signer == owner, "ERC20Permit: invalid signature");
nonces[owner] = _currentNonce + 1;
_approve(owner, spender, value);
}
/**
* @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view override returns (bytes32) {
return _domainSeparatorV4();
}
/**
* @dev Returns the domain separator for the current chain.
*/
function _domainSeparatorV4() private view returns (bytes32) {
if (block.chainid == _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator(_EIP712_DOMAIN_TYPEHASH, _HASHED_NAME, _EIP712_VERSION);
}
}
function _buildDomainSeparator(bytes32 typeHash, bytes32 name, bytes32 version) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, name, version, block.chainid, address(this)));
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.9;
import "../dependencies/openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../dependencies/openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "../interfaces/vesper/IVesperPool.sol";
abstract contract PoolStorageV1 is IVesperPool {
///@notice Collateral token address
IERC20 public token;
/// @notice PoolAccountant address
address public poolAccountant;
/// @notice PoolRewards contract address
address public poolRewards;
address private feeWhitelistObsolete; // Obsolete in favor of AddressSet of feeWhitelist
address private keepersObsolete; // Obsolete in favor of AddressSet of keepers
address private maintainersObsolete; // Obsolete in favor of AddressSet of maintainers
address private feeCollectorObsolete; // Fee collector address. Obsolete as there is no fee to collect
uint256 private withdrawFeeObsolete; // Withdraw fee for this pool. Obsolete in favor of universal fee
uint256 private decimalConversionFactorObsolete; // It can be used in converting value to/from 18 decimals
bool internal withdrawInETH; // This flag will be used by VETH pool as switch to withdraw ETH or WETH
}
abstract contract PoolStorageV2 is PoolStorageV1 {
EnumerableSet.AddressSet private _feeWhitelistObsolete; // Obsolete in favor of universal fee
EnumerableSet.AddressSet internal _keepers; // List of keeper addresses
EnumerableSet.AddressSet internal _maintainers; // List of maintainer addresses
}
abstract contract PoolStorageV3 is PoolStorageV2 {
/// @notice Universal fee of this pool. Default to 2%
uint256 public universalFee = 200;
/// @notice Maximum percentage of profit that can be counted as universal fee. Default to 50%
uint256 public maxProfitAsFee = 5_000;
/// @notice Minimum deposit limit.
/// @dev Do not set it to 0 as deposit() is checking if amount >= limit
uint256 public minDepositLimit = 1;
}{
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 100
},
"remappings": [],
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"address","name":"token_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Open","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Shutdown","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"strategyDebt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"profit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"UniversalFeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousGovernor","type":"address"},{"indexed":true,"internalType":"address","name":"proposedGovernor","type":"address"}],"name":"UpdatedGovernor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldMaxProfitAsFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxProfitAsFee","type":"uint256"}],"name":"UpdatedMaximumProfitAsFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldDepositLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDepositLimit","type":"uint256"}],"name":"UpdatedMinimumDepositLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousPoolRewards","type":"address"},{"indexed":true,"internalType":"address","name":"newPoolRewards","type":"address"}],"name":"UpdatedPoolRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldUniversalFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newUniversalFee","type":"uint256"}],"name":"UpdatedUniversalFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousWithdrawFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newWithdrawFee","type":"uint256"}],"name":"UpdatedWithdrawFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BPS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE_YEAR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptGovernorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"keeperAddress_","type":"address"}],"name":"addKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"maintainerAddress_","type":"address"}],"name":"addMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"strategy_","type":"address"}],"name":"availableCreditLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"calculateMintage","outputs":[{"internalType":"uint256","name":"_shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"profit_","type":"uint256"}],"name":"calculateUniversalFee","outputs":[{"internalType":"uint256","name":"_fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"depositAndClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"},{"internalType":"uint256","name":"deadline_","type":"uint256"},{"internalType":"uint8","name":"v_","type":"uint8"},{"internalType":"bytes32","name":"r_","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"depositWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"strategy_","type":"address"}],"name":"excessDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStrategies","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWithdrawQueue","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"address","name":"token_","type":"address"},{"internalType":"address","name":"poolAccountant_","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"address_","type":"address"}],"name":"isKeeper","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"address_","type":"address"}],"name":"isMaintainer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keepers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maintainers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxProfitAsFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"old_","type":"address"},{"internalType":"address","name":"new_","type":"address"}],"name":"migrateStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minDepositLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"open","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"poolAccountant","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolRewards","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pricePerShare","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"keeperAddress_","type":"address"}],"name":"removeKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"maintainerAddress_","type":"address"}],"name":"removeMaintainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"profit_","type":"uint256"},{"internalType":"uint256","name":"loss_","type":"uint256"},{"internalType":"uint256","name":"payback_","type":"uint256"}],"name":"reportEarning","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"loss_","type":"uint256"}],"name":"reportLoss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shutdown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopEverything","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"strategy_","type":"address"}],"name":"strategy","outputs":[{"internalType":"bool","name":"_active","type":"bool"},{"internalType":"uint256","name":"_interestFee","type":"uint256"},{"internalType":"uint256","name":"_debtRate","type":"uint256"},{"internalType":"uint256","name":"_lastRebalance","type":"uint256"},{"internalType":"uint256","name":"_totalDebt","type":"uint256"},{"internalType":"uint256","name":"_totalLoss","type":"uint256"},{"internalType":"uint256","name":"_totalProfit","type":"uint256"},{"internalType":"uint256","name":"_debtRatio","type":"uint256"},{"internalType":"uint256","name":"_externalDepositFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"fromToken_","type":"address"}],"name":"sweepERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokensHere","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDebt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"strategy_","type":"address"}],"name":"totalDebtOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDebtRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_proposedGovernor","type":"address"}],"name":"transferGovernorship","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"universalFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMaxProfitAsFee_","type":"uint256"}],"name":"updateMaximumProfitAsFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newLimit_","type":"uint256"}],"name":"updateMinimumDepositLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPoolRewards_","type":"address"}],"name":"updatePoolRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newUniversalFee_","type":"uint256"}],"name":"updateUniversalFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares_","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares_","type":"uint256"}],"name":"withdrawAndClaim","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405260c8601d55611388601e556001601f553480156200002157600080fd5b50604051620046933803806200469383398101604081905262000044916200027b565b8251839083906200005d90600390602085019062000108565b5080516200007390600490602084019062000108565b5050506000620000886200010460201b60201c565b600a80546001600160a01b0319166001600160a01b038316908117909155604051919250906000907fd4459d5b8b913cab0244230fd9b1c08b6ceace7fe9230e60d0f74cbffdf849d0908290a3506001600c55600d80546001600160a01b0319166001600160a01b039290921691909117905550620003459050565b3390565b828054620001169062000308565b90600052602060002090601f0160209004810192826200013a576000855562000185565b82601f106200015557805160ff191683800117855562000185565b8280016001018555821562000185579182015b828111156200018557825182559160200191906001019062000168565b506200019392915062000197565b5090565b5b8082111562000193576000815560010162000198565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001d657600080fd5b81516001600160401b0380821115620001f357620001f3620001ae565b604051601f8301601f19908116603f011681019082821181831017156200021e576200021e620001ae565b816040528381526020925086838588010111156200023b57600080fd5b600091505b838210156200025f578582018301518183018401529082019062000240565b83821115620002715760008385830101525b9695505050505050565b6000806000606084860312156200029157600080fd5b83516001600160401b0380821115620002a957600080fd5b620002b787838801620001c4565b94506020860151915080821115620002ce57600080fd5b50620002dd86828701620001c4565b604086015190935090506001600160a01b0381168114620002fd57600080fd5b809150509250925092565b600181811c908216806200031d57607f821691505b602082108114156200033f57634e487b7160e01b600052602260045260246000fd5b50919050565b61433e80620003556000396000f3fe608060405234801561001057600080fd5b506004361061035b5760003560e01c80638d3d0a26116101ca578063c01e0d4011610105578063ddd6d260116100a8578063ddd6d260146107a5578063e00af4a7146107b8578063f3b27bc3146107cb578063fc0c546a146107d3578063fc0e74d1146107e6578063fc7b9c18146107ee578063fcfff16f146107f6578063fd967f47146107fe578063ffa1ad741461080757600080fd5b8063c01e0d40146106f2578063c12d636b14610705578063d4c3eea014610718578063d505accf14610720578063d53ddc2614610733578063d8baf7cf14610746578063dd57366a14610759578063dd62ed3e1461076c57600080fd5b80639fd5be181161016d5780639fd5be181461067a578063a9059cbb14610683578063a941a90e14610696578063b49a60bb146106a9578063b64321ec146106b1578063b6aa515b146106c4578063b6b55f25146106d7578063b8cb343d146106ea57600080fd5b80638d3d0a26146106035780638f15b41414610616578063940c408214610629578063951dc22c1461063c57806395d89b411461064457806399530b061461064c5780639b6da8df146106545780639f2b28331461066757600080fd5b80633e7729251161029a5780635f895e541161023d5780635f895e541461055d5780636b453c1f146105665780636ba42aaa146105795780636cb56d191461058c57806370a082311461059f5780637ecebe00146105c85780638456cb59146105e85780638bc6beb2146105f057600080fd5b80633e772925146104e35780633f4ba83a146104ec5780634032b72b146104f4578063448a1047146105075780634938649a1461051a57806349eeb8601461052e5780634a970be7146105365780635c975abb1461054957600080fd5b806318160ddd1161030257806318160ddd1461042a578063228bfd9f1461043257806323b872dd1461048b5780632df9eab91461049e5780632e1a7d4d146104a6578063313ce567146104b957806332dd0f49146104c85780633644e515146104db57600080fd5b806305bed0461461036057806306fdde0314610375578063095ea7b3146103935780630c340a24146103b65780630da3fe20146103d657806311183052146103e957806314ae9f2e146103fe57806316d3bfbb14610411575b600080fd5b61037361036e3660046139f6565b61082b565b005b61037d610aac565b60405161038a9190613a4e565b60405180910390f35b6103a66103a1366004613a96565b610b3e565b604051901515815260200161038a565b600a546103c9906001600160a01b031681565b60405161038a9190613ac2565b6103736103e4366004613ad6565b610b55565b6103f1610c41565b60405161038a9190613aef565b61037361040c366004613b3c565b610cc7565b61041c6301e1338081565b60405190815260200161038a565b60025461041c565b610445610440366004613b3c565b610d4c565b604080519915158a5260208a0198909852968801959095526060870193909352608086019190915260a085015260c084015260e08301526101008201526101200161038a565b6103a6610499366004613b59565b610dfd565b61041c610eb0565b6103736104b4366004613ad6565b610f2d565b6040516012815260200161038a565b61041c6104d6366004613ad6565b610f9e565b61041c610faa565b61041c601e5481565b610373610fb4565b610373610502366004613b3c565b610ff7565b610373610515366004613ad6565b611074565b600b546103a690600160a81b900460ff1681565b6103f16110cf565b610373610544366004613ba9565b6110db565b600b546103a690600160a01b900460ff1681565b61041c601d5481565b610373610574366004613b3c565b6111e2565b6103a6610587366004613b3c565b611226565b61037361059a366004613bf2565b611233565b61041c6105ad366004613b3c565b6001600160a01b031660009081526020819052604090205490565b61041c6105d6366004613b3c565b60096020526000908152604090205481565b610373611472565b600f546103c9906001600160a01b031681565b610373610611366004613ad6565b6114b3565b610373610624366004613ce2565b61155b565b610373610637366004613b3c565b611739565b6103f1611800565b61037d61180c565b61041c61181b565b610373610662366004613ad6565b6118f4565b61041c610675366004613b3c565b61199f565b61041c601f5481565b6103a6610691366004613a96565b611a20565b6103736106a4366004613ad6565b611a2d565b6103f1611a91565b61041c6106bf366004613b3c565b611ad6565b6103736106d2366004613b3c565b611b07565b6103736106e5366004613ad6565b611ba5565b61041c611c00565b61041c610700366004613ad6565b611c49565b600e546103c9906001600160a01b031681565b61041c611d3d565b61037361072e366004613d6b565b611dd7565b61041c610741366004613b3c565b611f97565b610373610754366004613b3c565b611fc8565b6103a6610767366004613b3c565b61200c565b61041c61077a366004613bf2565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6103736107b3366004613ad6565b612019565b6103736107c6366004613b3c565b612080565b61037361219b565b600d546103c9906001600160a01b031681565b610373612257565b61041c612298565b6103736122dd565b61041c61271081565b61037d604051806040016040528060058152602001640352e312e360dc1b81525081565b3383156109a057600e5460405163228bfd9f60e01b815260009182916001600160a01b039091169063228bfd9f90610867908690600401613ac2565b6101206040518083038186803b15801561088057600080fd5b505afa158015610894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b89190613df1565b505050509450945050505060006108d083838961231e565b9050801561099c5761095a846001600160a01b031663c415b95c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561091457600080fd5b505afa158015610928573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094c9190613e61565b61095583612391565b6123f6565b60408051838152602081018990529081018290527f692ef79cc704efab4328e6c217b5fb3b1045d0a0314e3e8137029bcb2d59ce4a9060600160405180910390a15b5050505b600e5460405163a066654b60e01b81526001600160a01b038381166004830152602482018790526044820186905260648201859052600092839291169063a066654b906084016040805180830381600087803b1580156109ff57600080fd5b505af1158015610a13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a379190613e7e565b90925090506000610a488388613eb8565b905081811015610a7857610a7384610a608385613ed0565b600d546001600160a01b031691906124c3565b610aa3565b81811115610aa357610aa38430610a8f8585613ed0565b600d546001600160a01b031692919061251e565b50505050505050565b606060038054610abb90613ee7565b80601f0160208091040260200160405190810160405280929190818152602001828054610ae790613ee7565b8015610b345780601f10610b0957610100808354040283529160200191610b34565b820191906000526020600020905b815481529060010190602001808311610b1757829003601f168201915b5050505050905090565b6000610b4b33848461255c565b5060015b92915050565b600a546001600160a01b03163314610b885760405162461bcd60e51b8152600401610b7f90613f22565b60405180910390fd5b604080518082019091526002815261199960f11b602082015281610bbf5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601f5481141560405180604001604052806002815260200161333160f01b81525090610bff5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601f5460408051918252602082018390527f25c9f41f0fb7a055d44b070262516fbd0111daea3b55d40fae1983827dc99292910160405180910390a1601f55565b600e546040805163088c182960e11b815290516060926001600160a01b0316916311183052916004808301926000929190829003018186803b158015610c8657600080fd5b505afa158015610c9a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cc29190810190613f48565b905090565b600a546001600160a01b0316331480610ce85750610ce8335b601990612681565b610d045760405162461bcd60e51b8152600401610b7f90613ffa565b610d0f6019826126a3565b604051806040016040528060028152602001610c4d60f21b81525090610d485760405162461bcd60e51b8152600401610b7f9190613a4e565b5050565b600e5460405163228bfd9f60e01b8152600091829182918291829182918291829182916001600160a01b03169063228bfd9f90610d8d908d90600401613ac2565b6101206040518083038186803b158015610da657600080fd5b505afa158015610dba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dde9190613df1565b9850985098509850985098509850985098509193959799909294969850565b6000610e0a8484846126b8565b6001600160a01b038416600090815260016020908152604080832033845290915290205482811015610e8f5760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b6064820152608401610b7f565b610ea38533610e9e8685613ed0565b61255c565b60019150505b9392505050565b600e5460408051632df9eab960e01b815290516000926001600160a01b031691632df9eab9916004808301926020929190829003018186803b158015610ef557600080fd5b505afa158015610f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc29190614020565b6002600c541415610f505760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a81b900460ff1615610f7f5760405162461bcd60e51b8152600401610b7f90614070565b610f8d33612799565b612799565b610f96816127da565b506001600c55565b6000610b4f3383612896565b6000610cc261293b565b600a546001600160a01b0316331480610fd15750610fd133610ce0565b610fed5760405162461bcd60e51b8152600401610b7f90613ffa565b610ff56129b6565b565b600a546001600160a01b0316331480611014575061101433610ce0565b6110305760405162461bcd60e51b8152600401610b7f90613ffa565b61103b601982612a6d565b60405180604001604052806002815260200161313360f01b81525090610d485760405162461bcd60e51b8152600401610b7f9190613a4e565b6002600c5414156110975760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a81b900460ff16156110c65760405162461bcd60e51b8152600401610b7f90614070565b610f8d33612a82565b6060610cc2601b612ac3565b6002600c5414156110fe5760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff161561112d5760405162461bcd60e51b8152600401610b7f90614092565b600d546001600160a01b031663d505accf336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604481018890526064810187905260ff8616608482015260a4810185905260c4810184905260e401600060405180830381600087803b1580156111ab57600080fd5b505af11580156111bf573d6000803e3d6000fd5b505050506111cd610f883390565b6111d685612ad0565b50506001600c55505050565b600a546001600160a01b03163314806111ff57506111ff33610ce0565b61121b5760405162461bcd60e51b8152600401610b7f90613ffa565b61103b601b82612a6d565b6000610b4f601983612681565b600a546001600160a01b0316331461125d5760405162461bcd60e51b8152600401610b7f90613f22565b306001600160a01b0316816001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112a057600080fd5b505afa1580156112b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d89190613e61565b6001600160a01b031614801561136f5750306001600160a01b0316826001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561132c57600080fd5b505afa158015611340573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113649190613e61565b6001600160a01b0316145b60405180604001604052806002815260200161313760f01b815250906113a85760405162461bcd60e51b8152600401610b7f9190613a4e565b50600e54604051636cb56d1960e01b81526001600160a01b038481166004830152838116602483015290911690636cb56d1990604401600060405180830381600087803b1580156113f857600080fd5b505af115801561140c573d6000803e3d6000fd5b505060405163ce5494bb60e01b81526001600160a01b038516925063ce5494bb915061143c908490600401613ac2565b600060405180830381600087803b15801561145657600080fd5b505af115801561146a573d6000803e3d6000fd5b505050505050565b600a546001600160a01b031633148061148f575061148f33610ce0565b6114ab5760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612b3e565b600a546001600160a01b031633146114dd5760405162461bcd60e51b8152600401610b7f90613f22565b604080518082019091526002815261313160f01b60208201526127108211156115195760405162461bcd60e51b8152600401610b7f9190613a4e565b50601d5460408051918252602082018390527f905d672396c48f9d1e13c57aec0819f00d39364ab4bf40a46a687aa607b67d81910160405180910390a1601d55565b600554610100900460ff1680611574575060055460ff16155b6115905760405162461bcd60e51b8152600401610b7f906140b2565b600554610100900460ff161580156115b2576005805461ffff19166101011790555b604080518082019091526002815261031360f41b60208201526001600160a01b0384166115f25760405162461bcd60e51b8152600401610b7f9190613a4e565b50604080518082019091526002815261031360f41b60208201526001600160a01b0383166116335760405162461bcd60e51b8152600401610b7f9190613a4e565b5061163e8585612ba3565b61164785612bca565b61164f612c49565b600d80546001600160a01b0319166001600160a01b03851617905561167633601990612a6d565b60405180604001604052806002815260200161313360f01b815250906116af5760405162461bcd60e51b8152600401610b7f9190613a4e565b506116bb601b33612a6d565b60405180604001604052806002815260200161313360f01b815250906116f45760405162461bcd60e51b8152600401610b7f9190613a4e565b50600e80546001600160a01b0319166001600160a01b03841617905560c8601d55611388601e556001601f558015611732576005805461ff00191690555b5050505050565b600a546001600160a01b031633146117635760405162461bcd60e51b8152600401610b7f90613f22565b604080518082019091526002815261031360f41b60208201526001600160a01b0382166117a35760405162461bcd60e51b8152600401610b7f9190613a4e565b50600f546040516001600160a01b038084169216907fe239974dad08ac696e723caf1886bd0b5afc0870088f9a1266082757f824927690600090a3600f80546001600160a01b0319166001600160a01b0392909216919091179055565b6060610cc26019612ac3565b606060048054610abb90613ee7565b600061182660025490565b15806118375750611835611d3d565b155b156118cd57600d60009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561188a57600080fd5b505afa15801561189e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c29190614100565b610cc290600a614201565b6002546118d8611d3d565b6118ea90670de0b6b3a7640000614210565b610cc2919061422f565b600a546001600160a01b0316331461191e5760405162461bcd60e51b8152600401610b7f90613f22565b601e5481141560405180604001604052806002815260200161333160f01b8152509061195d5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601e5460408051918252602082018390527fafe4d3ceb3295a8d4ef49288a92d32d94e39396e823d414b81caff61b9fc3990910160405180910390a1601e55565b600e54604051639f2b283360e01b81526000916001600160a01b031690639f2b2833906119d0908590600401613ac2565b60206040518083038186803b1580156119e857600080fd5b505afa1580156119fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4f9190614020565b6000610b4b3384846126b8565b6002600c541415611a505760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff1615611a7f5760405162461bcd60e51b8152600401610b7f90614092565b611a8833612a82565b610f9681612ad0565b600e546040805163b49a60bb60e01b815290516060926001600160a01b03169163b49a60bb916004808301926000929190829003018186803b158015610c8657600080fd5b600e54604051632d90c87b60e21b81526000916001600160a01b03169063b64321ec906119d0908590600401613ac2565b600a546001600160a01b03163314611b315760405162461bcd60e51b8152600401610b7f90613f22565b6001600160a01b038116611b835760405162461bcd60e51b815260206004820152601960248201527870726f706f7365642d676f7665726e6f722d69732d7a65726f60381b6044820152606401610b7f565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6002600c541415611bc85760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff1615611bf75760405162461bcd60e51b8152600401610b7f90614092565b611a8833612799565b600d546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611c31903090600401613ac2565b60206040518083038186803b158015610ef557600080fd5b6000601f54821015604051806040016040528060018152602001603160f81b81525090611c895760405162461bcd60e51b8152600401610b7f9190613a4e565b506000612710600e60009054906101000a90046001600160a01b03166001600160a01b031663346162d56040518163ffffffff1660e01b815260040160206040518083038186803b158015611cdd57600080fd5b505afa158015611cf1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d159190614020565b611d1f9085614210565b611d29919061422f565b9050610ea9611d388285613ed0565b612391565b6000611d47611c00565b600e60009054906101000a90046001600160a01b03166001600160a01b031663fc7b9c186040518163ffffffff1660e01b815260040160206040518083038186803b158015611d9557600080fd5b505afa158015611da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dcd9190614020565b610cc29190613eb8565b83421115611e275760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610b7f565b6001600160a01b0387811660008181526009602090815260408083205481517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98185015280830195909552948b166060850152608084018a905260a0840185905260c08085018a90528151808603909101815260e09094019052825192019190912090611eb261293b565b60405161190160f01b60208201526022810191909152604281018390526062016040516020818303038152906040528051906020012090506000611ef882888888612cf7565b90508a6001600160a01b0316816001600160a01b031614611f5b5760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610b7f565b611f66846001613eb8565b6001600160a01b038c16600090815260096020526040902055611f8a8b8b8b61255c565b5050505050505050505050565b600e54604051636a9eee1360e11b81526000916001600160a01b03169063d53ddc26906119d0908590600401613ac2565b600a546001600160a01b0316331480611fe55750611fe533610ce0565b6120015760405162461bcd60e51b8152600401610b7f90613ffa565b610d0f601b826126a3565b6000610b4f601b83612681565b801561207d57600e546001600160a01b0316637f13086e33836040518363ffffffff1660e01b815260040161204f929190614251565b600060405180830381600087803b15801561206957600080fd5b505af1158015611732573d6000803e3d6000fd5b50565b600a546001600160a01b031633148061209d575061209d33610ce0565b6120b95760405162461bcd60e51b8152600401610b7f90613ffa565b600d546040805180820190915260018152600760fb1b6020820152906001600160a01b03838116911614156121015760405162461bcd60e51b8152600401610b7f9190613a4e565b50600a546040516370a0823160e01b815261207d916001600160a01b0390811691908416906370a082319061213a903090600401613ac2565b60206040518083038186803b15801561215257600080fd5b505afa158015612166573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218a9190614020565b6001600160a01b03841691906124c3565b600b546001600160a01b031633146121f15760405162461bcd60e51b81526020600482015260196024820152783737ba16ba343296b83937b837b9b2b216b3b7bb32b93737b960391b6044820152606401610b7f565b600b54600a546040516001600160a01b0392831692909116907fd4459d5b8b913cab0244230fd9b1c08b6ceace7fe9230e60d0f74cbffdf849d090600090a3600b8054600a80546001600160a01b03199081166001600160a01b03841617909155169055565b600a546001600160a01b0316331480612274575061227433610ce0565b6122905760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612e88565b600e5460408051631f8f738360e31b815290516000926001600160a01b03169163fc7b9c18916004808301926020929190829003018186803b158015610ef557600080fd5b600a546001600160a01b03163314806122fa57506122fa33610ce0565b6123165760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612eee565b60006123306301e13380612710614210565b8361233b8642613ed0565b601d546123489190614210565b6123529190614210565b61235c919061422f565b90506000612710601e54846123719190614210565b61237b919061422f565b905080821115612389578091505b509392505050565b60008061239c61181b565b6123ae84670de0b6b3a7640000614210565b6123b8919061422f565b9050670de0b6b3a76400006123cb61181b565b6123d59083614210565b6123df919061422f565b83116123eb5780610ea9565b610ea9816001613eb8565b6001600160a01b03821661244c5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610b7f565b806002600082825461245e9190613eb8565b90915550506001600160a01b0382166000908152602081905260408120805483929061248b908490613eb8565b90915550506040518181526001600160a01b038316906000906000805160206142e98339815191529060200160405180910390a35050565b6125198363a9059cbb60e01b84846040516024016124e2929190614251565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f6a565b505050565b6040516001600160a01b03808516602483015283166044820152606481018290526125569085906323b872dd60e01b906084016124e2565b50505050565b6001600160a01b0383166125be5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610b7f565b6001600160a01b03821661261f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610b7f565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03811660009081526001830160205260408120541515610ea9565b6000610ea9836001600160a01b03841661303c565b600f546001600160a01b03161561278e57600f5460405163632447c960e01b81526001600160a01b039091169063632447c9906126f9908690600401613ac2565b600060405180830381600087803b15801561271357600080fd5b505af1158015612727573d6000803e3d6000fd5b5050600f5460405163632447c960e01b81526001600160a01b03909116925063632447c9915061275b908590600401613ac2565b600060405180830381600087803b15801561277557600080fd5b505af1158015612789573d6000803e3d6000fd5b505050505b61251983838361312f565b600f546001600160a01b03161561207d57600f5460405163632447c960e01b81526001600160a01b039091169063632447c99061204f908490600401613ac2565b6040805180820190915260018152601960f91b6020820152816128105760405162461bcd60e51b8152600401610b7f9190613a4e565b5060008061281d836132f5565b91509150801561284257600061283283612391565b905083811015612840578093505b505b61284c338461339c565b612855826134d9565b50604080518481526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a2505050565b600e5460405163228bfd9f60e01b8152600091829182916001600160a01b03169063228bfd9f906128cb908890600401613ac2565b6101206040518083038186803b1580156128e457600080fd5b505afa1580156128f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291c9190613df1565b505050509450945050505061293282828661231e565b95945050505050565b600060085446141561294e575060065490565b6007546040805180820190915260018152603160f81b602090910152610cc2907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f907fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66134f6565b600b54600160a01b900460ff166129fc5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd0b5c185d5cd95960b21b6044820152606401610b7f565b600b54600160a81b900460ff1615612a265760405162461bcd60e51b8152600401610b7f90614070565b600b805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b604051612a639190613ac2565b60405180910390a1565b6000610ea9836001600160a01b03841661353f565b600f546001600160a01b03161561207d57600f5460405163d279c19160e01b81526001600160a01b039091169063d279c1919061204f908490600401613ac2565b60606000610ea98361358e565b6000612adb82611c49565b9050612af533600d546001600160a01b031690308561251e565b612aff33826123f6565b604080518281526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a25050565b600b54600160a01b900460ff1615612b685760405162461bcd60e51b8152600401610b7f90614092565b600b805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a563390565b8151612bb6906003906020850190613966565b508051612519906004906020840190613966565b80516020808301919091206007819055466008556040805180820190915260018152603160f81b920191909152612c43907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f907fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66134f6565b60065550565b600554610100900460ff1680612c62575060055460ff16155b612c7e5760405162461bcd60e51b8152600401610b7f906140b2565b600554610100900460ff16158015612ca0576005805461ffff19166101011790555b600a80546001600160a01b0319163390811790915560405181906000907fd4459d5b8b913cab0244230fd9b1c08b6ceace7fe9230e60d0f74cbffdf849d0908290a350801561207d576005805461ff001916905550565b60006fa2a8918ca85bafe22016d0b997e4df60600160ff1b03821115612d6a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610b7f565b8360ff16601b1480612d7f57508360ff16601c145b612dd65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610b7f565b6040805160008082526020820180845288905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa158015612e2a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166129325760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610b7f565b600b54600160a81b900460ff1615612eb25760405162461bcd60e51b8152600401610b7f90614070565b600b805461ffff60a01b191661010160a01b1790557f28b4c24cb1012c094cd2f59f98e89d791973295f8fda6eaa118022d6d318960a33612a56565b600b54600160a81b900460ff16612f365760405162461bcd60e51b815260206004820152600c60248201526b3737ba16b9b43aba3237bbb760a11b6044820152606401610b7f565b600b805460ff60a81b191690557fece7583a70a505ef0e36d4dec768f5ae597713e09c26011022599ee01abdabfc33612a56565b6000612fbf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135ea9092919063ffffffff16565b8051909150156125195780806020019051810190612fdd919061426a565b6125195760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610b7f565b60008181526001830160205260408120548015613125576000613060600183613ed0565b855490915060009061307490600190613ed0565b90508181146130d957600086600001828154811061309457613094614285565b90600052602060002001549050808760000184815481106130b7576130b7614285565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806130ea576130ea61429b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b4f565b6000915050610b4f565b6001600160a01b0383166131935760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610b7f565b6001600160a01b0382166131f55760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610b7f565b6001600160a01b0383166000908152602081905260409020548181101561326d5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610b7f565b6132778282613ed0565b6001600160a01b0380861660009081526020819052604080822093909355908516815290812080548492906132ad908490613eb8565b92505081905550826001600160a01b0316846001600160a01b03166000805160206142e9833981519152846040516132e791815260200190565b60405180910390a350505050565b600080670de0b6b3a764000061330961181b565b6133139085614210565b61331d919061422f565b91506000613329611c00565b90508083111561335f576133456133408285613ed0565b613601565b61334d611c00565b90508083111561335f57809250600191505b6040805180820190915260018152603160f81b6020820152836133955760405162461bcd60e51b8152600401610b7f9190613a4e565b5050915091565b6001600160a01b0382166133fc5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610b7f565b6001600160a01b038216600090815260208190526040902054818110156134705760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610b7f565b61347a8282613ed0565b6001600160a01b038416600090815260208190526040812091909155600280548492906134a8908490613ed0565b90915550506040518281526000906001600160a01b038516906000805160206142e983398151915290602001612674565b60006134f233600d546001600160a01b031690846124c3565b5090565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b600081815260018301602052604081205461358657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b4f565b506000610b4f565b6060816000018054806020026020016040519081016040528092919081815260200182805480156135de57602002820191906000526020600020905b8154815260200190600101908083116135ca575b50505050509050919050565b60606135f98484600085613805565b949350505050565b6000806000806000613611610c41565b805190915060005b818110156137fb57600061362d858a613ed0565b9050600084838151811061364357613643614285565b6020908102919091010151600e54604051639f2b283360e01b81529192506001600160a01b031690639f2b28339061367f908490600401613ac2565b60206040518083038186803b15801561369757600080fd5b505afa1580156136ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136cf9190614020565b9850886136dd5750506137e9565b888211156136e9578891505b6136f1611c00565b604051632e1a7d4d60e01b8152600481018490529098506001600160a01b03821690632e1a7d4d90602401600060405180830381600087803b15801561373657600080fd5b505af1925050508015613747575060015b6137525750506137e9565b8761375b611c00565b6137659190613ed0565b600e54604051632fb9ba3160e01b81529198506001600160a01b031690632fb9ba31906137989084908b90600401614251565b600060405180830381600087803b1580156137b257600080fd5b505af11580156137c6573d6000803e3d6000fd5b5050505086866137d69190613eb8565b95508986106137e65750506137fb565b50505b806137f3816142b1565b915050613619565b5050505050505050565b6060824710156138665760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610b7f565b843b6138b45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7f565b600080866001600160a01b031685876040516138d091906142cc565b60006040518083038185875af1925050503d806000811461390d576040519150601f19603f3d011682016040523d82523d6000602084013e613912565b606091505b509150915061392282828661392d565b979650505050505050565b6060831561393c575081610ea9565b82511561394c5782518084602001fd5b8160405162461bcd60e51b8152600401610b7f9190613a4e565b82805461397290613ee7565b90600052602060002090601f01602090048101928261399457600085556139da565b82601f106139ad57805160ff19168380011785556139da565b828001600101855582156139da579182015b828111156139da5782518255916020019190600101906139bf565b506134f29291505b808211156134f257600081556001016139e2565b600080600060608486031215613a0b57600080fd5b505081359360208301359350604090920135919050565b60005b83811015613a3d578181015183820152602001613a25565b838111156125565750506000910152565b6020815260008251806020840152613a6d816040850160208701613a22565b601f01601f19169190910160400192915050565b6001600160a01b038116811461207d57600080fd5b60008060408385031215613aa957600080fd5b8235613ab481613a81565b946020939093013593505050565b6001600160a01b0391909116815260200190565b600060208284031215613ae857600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015613b305783516001600160a01b031683529284019291840191600101613b0b565b50909695505050505050565b600060208284031215613b4e57600080fd5b8135610ea981613a81565b600080600060608486031215613b6e57600080fd5b8335613b7981613a81565b92506020840135613b8981613a81565b929592945050506040919091013590565b60ff8116811461207d57600080fd5b600080600080600060a08688031215613bc157600080fd5b85359450602086013593506040860135613bda81613b9a565b94979396509394606081013594506080013592915050565b60008060408385031215613c0557600080fd5b8235613c1081613a81565b91506020830135613c2081613a81565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613c6a57613c6a613c2b565b604052919050565b600082601f830112613c8357600080fd5b813567ffffffffffffffff811115613c9d57613c9d613c2b565b613cb0601f8201601f1916602001613c41565b818152846020838601011115613cc557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613cf857600080fd5b843567ffffffffffffffff80821115613d1057600080fd5b613d1c88838901613c72565b95506020870135915080821115613d3257600080fd5b50613d3f87828801613c72565b9350506040850135613d5081613a81565b91506060850135613d6081613a81565b939692955090935050565b600080600080600080600060e0888a031215613d8657600080fd5b8735613d9181613a81565b96506020880135613da181613a81565b955060408801359450606088013593506080880135613dbf81613b9a565b9699959850939692959460a0840135945060c09093013592915050565b80518015158114613dec57600080fd5b919050565b60008060008060008060008060006101208a8c031215613e1057600080fd5b613e198a613ddc565b985060208a0151975060408a0151965060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a015191506101008a015190509295985092959850929598565b600060208284031215613e7357600080fd5b8151610ea981613a81565b60008060408385031215613e9157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b60008219821115613ecb57613ecb613ea2565b500190565b600082821015613ee257613ee2613ea2565b500390565b600181811c90821680613efb57607f821691505b60208210811415613f1c57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600c908201526b3737ba16b3b7bb32b93737b960a11b604082015260600190565b60006020808385031215613f5b57600080fd5b825167ffffffffffffffff80821115613f7357600080fd5b818501915085601f830112613f8757600080fd5b815181811115613f9957613f99613c2b565b8060051b9150613faa848301613c41565b8181529183018401918481019088841115613fc457600080fd5b938501935b83851015613fee5784519250613fde83613a81565b8282529385019390850190613fc9565b98975050505050505050565b6020808252600c908201526b3737ba16b096b5b2b2b832b960a11b604082015260600190565b60006020828403121561403257600080fd5b5051919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526008908201526739b43aba3237bbb760c11b604082015260600190565b6020808252600690820152651c185d5cd95960d21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60006020828403121561411257600080fd5b8151610ea981613b9a565b600181815b8085111561415857816000190482111561413e5761413e613ea2565b8085161561414b57918102915b93841c9390800290614122565b509250929050565b60008261416f57506001610b4f565b8161417c57506000610b4f565b8160018114614192576002811461419c576141b8565b6001915050610b4f565b60ff8411156141ad576141ad613ea2565b50506001821b610b4f565b5060208310610133831016604e8410600b84101617156141db575081810a610b4f565b6141e5838361411d565b80600019048211156141f9576141f9613ea2565b029392505050565b6000610ea960ff841683614160565b600081600019048311821515161561422a5761422a613ea2565b500290565b60008261424c57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b03929092168252602082015260400190565b60006020828403121561427c57600080fd5b610ea982613ddc565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60006000198214156142c5576142c5613ea2565b5060010190565b600082516142de818460208701613a22565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220abf1e07fafbaa608304f172200235d161aa1ebbaa8b9d8c1ba464cd12f8d9be264736f6c63430008090033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b56657370657220706f6f6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000576506f6f6c000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061035b5760003560e01c80638d3d0a26116101ca578063c01e0d4011610105578063ddd6d260116100a8578063ddd6d260146107a5578063e00af4a7146107b8578063f3b27bc3146107cb578063fc0c546a146107d3578063fc0e74d1146107e6578063fc7b9c18146107ee578063fcfff16f146107f6578063fd967f47146107fe578063ffa1ad741461080757600080fd5b8063c01e0d40146106f2578063c12d636b14610705578063d4c3eea014610718578063d505accf14610720578063d53ddc2614610733578063d8baf7cf14610746578063dd57366a14610759578063dd62ed3e1461076c57600080fd5b80639fd5be181161016d5780639fd5be181461067a578063a9059cbb14610683578063a941a90e14610696578063b49a60bb146106a9578063b64321ec146106b1578063b6aa515b146106c4578063b6b55f25146106d7578063b8cb343d146106ea57600080fd5b80638d3d0a26146106035780638f15b41414610616578063940c408214610629578063951dc22c1461063c57806395d89b411461064457806399530b061461064c5780639b6da8df146106545780639f2b28331461066757600080fd5b80633e7729251161029a5780635f895e541161023d5780635f895e541461055d5780636b453c1f146105665780636ba42aaa146105795780636cb56d191461058c57806370a082311461059f5780637ecebe00146105c85780638456cb59146105e85780638bc6beb2146105f057600080fd5b80633e772925146104e35780633f4ba83a146104ec5780634032b72b146104f4578063448a1047146105075780634938649a1461051a57806349eeb8601461052e5780634a970be7146105365780635c975abb1461054957600080fd5b806318160ddd1161030257806318160ddd1461042a578063228bfd9f1461043257806323b872dd1461048b5780632df9eab91461049e5780632e1a7d4d146104a6578063313ce567146104b957806332dd0f49146104c85780633644e515146104db57600080fd5b806305bed0461461036057806306fdde0314610375578063095ea7b3146103935780630c340a24146103b65780630da3fe20146103d657806311183052146103e957806314ae9f2e146103fe57806316d3bfbb14610411575b600080fd5b61037361036e3660046139f6565b61082b565b005b61037d610aac565b60405161038a9190613a4e565b60405180910390f35b6103a66103a1366004613a96565b610b3e565b604051901515815260200161038a565b600a546103c9906001600160a01b031681565b60405161038a9190613ac2565b6103736103e4366004613ad6565b610b55565b6103f1610c41565b60405161038a9190613aef565b61037361040c366004613b3c565b610cc7565b61041c6301e1338081565b60405190815260200161038a565b60025461041c565b610445610440366004613b3c565b610d4c565b604080519915158a5260208a0198909852968801959095526060870193909352608086019190915260a085015260c084015260e08301526101008201526101200161038a565b6103a6610499366004613b59565b610dfd565b61041c610eb0565b6103736104b4366004613ad6565b610f2d565b6040516012815260200161038a565b61041c6104d6366004613ad6565b610f9e565b61041c610faa565b61041c601e5481565b610373610fb4565b610373610502366004613b3c565b610ff7565b610373610515366004613ad6565b611074565b600b546103a690600160a81b900460ff1681565b6103f16110cf565b610373610544366004613ba9565b6110db565b600b546103a690600160a01b900460ff1681565b61041c601d5481565b610373610574366004613b3c565b6111e2565b6103a6610587366004613b3c565b611226565b61037361059a366004613bf2565b611233565b61041c6105ad366004613b3c565b6001600160a01b031660009081526020819052604090205490565b61041c6105d6366004613b3c565b60096020526000908152604090205481565b610373611472565b600f546103c9906001600160a01b031681565b610373610611366004613ad6565b6114b3565b610373610624366004613ce2565b61155b565b610373610637366004613b3c565b611739565b6103f1611800565b61037d61180c565b61041c61181b565b610373610662366004613ad6565b6118f4565b61041c610675366004613b3c565b61199f565b61041c601f5481565b6103a6610691366004613a96565b611a20565b6103736106a4366004613ad6565b611a2d565b6103f1611a91565b61041c6106bf366004613b3c565b611ad6565b6103736106d2366004613b3c565b611b07565b6103736106e5366004613ad6565b611ba5565b61041c611c00565b61041c610700366004613ad6565b611c49565b600e546103c9906001600160a01b031681565b61041c611d3d565b61037361072e366004613d6b565b611dd7565b61041c610741366004613b3c565b611f97565b610373610754366004613b3c565b611fc8565b6103a6610767366004613b3c565b61200c565b61041c61077a366004613bf2565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b6103736107b3366004613ad6565b612019565b6103736107c6366004613b3c565b612080565b61037361219b565b600d546103c9906001600160a01b031681565b610373612257565b61041c612298565b6103736122dd565b61041c61271081565b61037d604051806040016040528060058152602001640352e312e360dc1b81525081565b3383156109a057600e5460405163228bfd9f60e01b815260009182916001600160a01b039091169063228bfd9f90610867908690600401613ac2565b6101206040518083038186803b15801561088057600080fd5b505afa158015610894573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b89190613df1565b505050509450945050505060006108d083838961231e565b9050801561099c5761095a846001600160a01b031663c415b95c6040518163ffffffff1660e01b815260040160206040518083038186803b15801561091457600080fd5b505afa158015610928573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061094c9190613e61565b61095583612391565b6123f6565b60408051838152602081018990529081018290527f692ef79cc704efab4328e6c217b5fb3b1045d0a0314e3e8137029bcb2d59ce4a9060600160405180910390a15b5050505b600e5460405163a066654b60e01b81526001600160a01b038381166004830152602482018790526044820186905260648201859052600092839291169063a066654b906084016040805180830381600087803b1580156109ff57600080fd5b505af1158015610a13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a379190613e7e565b90925090506000610a488388613eb8565b905081811015610a7857610a7384610a608385613ed0565b600d546001600160a01b031691906124c3565b610aa3565b81811115610aa357610aa38430610a8f8585613ed0565b600d546001600160a01b031692919061251e565b50505050505050565b606060038054610abb90613ee7565b80601f0160208091040260200160405190810160405280929190818152602001828054610ae790613ee7565b8015610b345780601f10610b0957610100808354040283529160200191610b34565b820191906000526020600020905b815481529060010190602001808311610b1757829003601f168201915b5050505050905090565b6000610b4b33848461255c565b5060015b92915050565b600a546001600160a01b03163314610b885760405162461bcd60e51b8152600401610b7f90613f22565b60405180910390fd5b604080518082019091526002815261199960f11b602082015281610bbf5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601f5481141560405180604001604052806002815260200161333160f01b81525090610bff5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601f5460408051918252602082018390527f25c9f41f0fb7a055d44b070262516fbd0111daea3b55d40fae1983827dc99292910160405180910390a1601f55565b600e546040805163088c182960e11b815290516060926001600160a01b0316916311183052916004808301926000929190829003018186803b158015610c8657600080fd5b505afa158015610c9a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610cc29190810190613f48565b905090565b600a546001600160a01b0316331480610ce85750610ce8335b601990612681565b610d045760405162461bcd60e51b8152600401610b7f90613ffa565b610d0f6019826126a3565b604051806040016040528060028152602001610c4d60f21b81525090610d485760405162461bcd60e51b8152600401610b7f9190613a4e565b5050565b600e5460405163228bfd9f60e01b8152600091829182918291829182918291829182916001600160a01b03169063228bfd9f90610d8d908d90600401613ac2565b6101206040518083038186803b158015610da657600080fd5b505afa158015610dba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dde9190613df1565b9850985098509850985098509850985098509193959799909294969850565b6000610e0a8484846126b8565b6001600160a01b038416600090815260016020908152604080832033845290915290205482811015610e8f5760405162461bcd60e51b815260206004820152602860248201527f45524332303a207472616e7366657220616d6f756e74206578636565647320616044820152676c6c6f77616e636560c01b6064820152608401610b7f565b610ea38533610e9e8685613ed0565b61255c565b60019150505b9392505050565b600e5460408051632df9eab960e01b815290516000926001600160a01b031691632df9eab9916004808301926020929190829003018186803b158015610ef557600080fd5b505afa158015610f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc29190614020565b6002600c541415610f505760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a81b900460ff1615610f7f5760405162461bcd60e51b8152600401610b7f90614070565b610f8d33612799565b612799565b610f96816127da565b506001600c55565b6000610b4f3383612896565b6000610cc261293b565b600a546001600160a01b0316331480610fd15750610fd133610ce0565b610fed5760405162461bcd60e51b8152600401610b7f90613ffa565b610ff56129b6565b565b600a546001600160a01b0316331480611014575061101433610ce0565b6110305760405162461bcd60e51b8152600401610b7f90613ffa565b61103b601982612a6d565b60405180604001604052806002815260200161313360f01b81525090610d485760405162461bcd60e51b8152600401610b7f9190613a4e565b6002600c5414156110975760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a81b900460ff16156110c65760405162461bcd60e51b8152600401610b7f90614070565b610f8d33612a82565b6060610cc2601b612ac3565b6002600c5414156110fe5760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff161561112d5760405162461bcd60e51b8152600401610b7f90614092565b600d546001600160a01b031663d505accf336040516001600160e01b031960e084901b1681526001600160a01b039091166004820152306024820152604481018890526064810187905260ff8616608482015260a4810185905260c4810184905260e401600060405180830381600087803b1580156111ab57600080fd5b505af11580156111bf573d6000803e3d6000fd5b505050506111cd610f883390565b6111d685612ad0565b50506001600c55505050565b600a546001600160a01b03163314806111ff57506111ff33610ce0565b61121b5760405162461bcd60e51b8152600401610b7f90613ffa565b61103b601b82612a6d565b6000610b4f601983612681565b600a546001600160a01b0316331461125d5760405162461bcd60e51b8152600401610b7f90613f22565b306001600160a01b0316816001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156112a057600080fd5b505afa1580156112b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112d89190613e61565b6001600160a01b031614801561136f5750306001600160a01b0316826001600160a01b03166316f0115b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561132c57600080fd5b505afa158015611340573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113649190613e61565b6001600160a01b0316145b60405180604001604052806002815260200161313760f01b815250906113a85760405162461bcd60e51b8152600401610b7f9190613a4e565b50600e54604051636cb56d1960e01b81526001600160a01b038481166004830152838116602483015290911690636cb56d1990604401600060405180830381600087803b1580156113f857600080fd5b505af115801561140c573d6000803e3d6000fd5b505060405163ce5494bb60e01b81526001600160a01b038516925063ce5494bb915061143c908490600401613ac2565b600060405180830381600087803b15801561145657600080fd5b505af115801561146a573d6000803e3d6000fd5b505050505050565b600a546001600160a01b031633148061148f575061148f33610ce0565b6114ab5760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612b3e565b600a546001600160a01b031633146114dd5760405162461bcd60e51b8152600401610b7f90613f22565b604080518082019091526002815261313160f01b60208201526127108211156115195760405162461bcd60e51b8152600401610b7f9190613a4e565b50601d5460408051918252602082018390527f905d672396c48f9d1e13c57aec0819f00d39364ab4bf40a46a687aa607b67d81910160405180910390a1601d55565b600554610100900460ff1680611574575060055460ff16155b6115905760405162461bcd60e51b8152600401610b7f906140b2565b600554610100900460ff161580156115b2576005805461ffff19166101011790555b604080518082019091526002815261031360f41b60208201526001600160a01b0384166115f25760405162461bcd60e51b8152600401610b7f9190613a4e565b50604080518082019091526002815261031360f41b60208201526001600160a01b0383166116335760405162461bcd60e51b8152600401610b7f9190613a4e565b5061163e8585612ba3565b61164785612bca565b61164f612c49565b600d80546001600160a01b0319166001600160a01b03851617905561167633601990612a6d565b60405180604001604052806002815260200161313360f01b815250906116af5760405162461bcd60e51b8152600401610b7f9190613a4e565b506116bb601b33612a6d565b60405180604001604052806002815260200161313360f01b815250906116f45760405162461bcd60e51b8152600401610b7f9190613a4e565b50600e80546001600160a01b0319166001600160a01b03841617905560c8601d55611388601e556001601f558015611732576005805461ff00191690555b5050505050565b600a546001600160a01b031633146117635760405162461bcd60e51b8152600401610b7f90613f22565b604080518082019091526002815261031360f41b60208201526001600160a01b0382166117a35760405162461bcd60e51b8152600401610b7f9190613a4e565b50600f546040516001600160a01b038084169216907fe239974dad08ac696e723caf1886bd0b5afc0870088f9a1266082757f824927690600090a3600f80546001600160a01b0319166001600160a01b0392909216919091179055565b6060610cc26019612ac3565b606060048054610abb90613ee7565b600061182660025490565b15806118375750611835611d3d565b155b156118cd57600d60009054906101000a90046001600160a01b03166001600160a01b031663313ce5676040518163ffffffff1660e01b815260040160206040518083038186803b15801561188a57600080fd5b505afa15801561189e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118c29190614100565b610cc290600a614201565b6002546118d8611d3d565b6118ea90670de0b6b3a7640000614210565b610cc2919061422f565b600a546001600160a01b0316331461191e5760405162461bcd60e51b8152600401610b7f90613f22565b601e5481141560405180604001604052806002815260200161333160f01b8152509061195d5760405162461bcd60e51b8152600401610b7f9190613a4e565b50601e5460408051918252602082018390527fafe4d3ceb3295a8d4ef49288a92d32d94e39396e823d414b81caff61b9fc3990910160405180910390a1601e55565b600e54604051639f2b283360e01b81526000916001600160a01b031690639f2b2833906119d0908590600401613ac2565b60206040518083038186803b1580156119e857600080fd5b505afa1580156119fc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4f9190614020565b6000610b4b3384846126b8565b6002600c541415611a505760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff1615611a7f5760405162461bcd60e51b8152600401610b7f90614092565b611a8833612a82565b610f9681612ad0565b600e546040805163b49a60bb60e01b815290516060926001600160a01b03169163b49a60bb916004808301926000929190829003018186803b158015610c8657600080fd5b600e54604051632d90c87b60e21b81526000916001600160a01b03169063b64321ec906119d0908590600401613ac2565b600a546001600160a01b03163314611b315760405162461bcd60e51b8152600401610b7f90613f22565b6001600160a01b038116611b835760405162461bcd60e51b815260206004820152601960248201527870726f706f7365642d676f7665726e6f722d69732d7a65726f60381b6044820152606401610b7f565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6002600c541415611bc85760405162461bcd60e51b8152600401610b7f90614039565b6002600c55600b54600160a01b900460ff1615611bf75760405162461bcd60e51b8152600401610b7f90614092565b611a8833612799565b600d546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611c31903090600401613ac2565b60206040518083038186803b158015610ef557600080fd5b6000601f54821015604051806040016040528060018152602001603160f81b81525090611c895760405162461bcd60e51b8152600401610b7f9190613a4e565b506000612710600e60009054906101000a90046001600160a01b03166001600160a01b031663346162d56040518163ffffffff1660e01b815260040160206040518083038186803b158015611cdd57600080fd5b505afa158015611cf1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d159190614020565b611d1f9085614210565b611d29919061422f565b9050610ea9611d388285613ed0565b612391565b6000611d47611c00565b600e60009054906101000a90046001600160a01b03166001600160a01b031663fc7b9c186040518163ffffffff1660e01b815260040160206040518083038186803b158015611d9557600080fd5b505afa158015611da9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dcd9190614020565b610cc29190613eb8565b83421115611e275760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610b7f565b6001600160a01b0387811660008181526009602090815260408083205481517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98185015280830195909552948b166060850152608084018a905260a0840185905260c08085018a90528151808603909101815260e09094019052825192019190912090611eb261293b565b60405161190160f01b60208201526022810191909152604281018390526062016040516020818303038152906040528051906020012090506000611ef882888888612cf7565b90508a6001600160a01b0316816001600160a01b031614611f5b5760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610b7f565b611f66846001613eb8565b6001600160a01b038c16600090815260096020526040902055611f8a8b8b8b61255c565b5050505050505050505050565b600e54604051636a9eee1360e11b81526000916001600160a01b03169063d53ddc26906119d0908590600401613ac2565b600a546001600160a01b0316331480611fe55750611fe533610ce0565b6120015760405162461bcd60e51b8152600401610b7f90613ffa565b610d0f601b826126a3565b6000610b4f601b83612681565b801561207d57600e546001600160a01b0316637f13086e33836040518363ffffffff1660e01b815260040161204f929190614251565b600060405180830381600087803b15801561206957600080fd5b505af1158015611732573d6000803e3d6000fd5b50565b600a546001600160a01b031633148061209d575061209d33610ce0565b6120b95760405162461bcd60e51b8152600401610b7f90613ffa565b600d546040805180820190915260018152600760fb1b6020820152906001600160a01b03838116911614156121015760405162461bcd60e51b8152600401610b7f9190613a4e565b50600a546040516370a0823160e01b815261207d916001600160a01b0390811691908416906370a082319061213a903090600401613ac2565b60206040518083038186803b15801561215257600080fd5b505afa158015612166573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218a9190614020565b6001600160a01b03841691906124c3565b600b546001600160a01b031633146121f15760405162461bcd60e51b81526020600482015260196024820152783737ba16ba343296b83937b837b9b2b216b3b7bb32b93737b960391b6044820152606401610b7f565b600b54600a546040516001600160a01b0392831692909116907fd4459d5b8b913cab0244230fd9b1c08b6ceace7fe9230e60d0f74cbffdf849d090600090a3600b8054600a80546001600160a01b03199081166001600160a01b03841617909155169055565b600a546001600160a01b0316331480612274575061227433610ce0565b6122905760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612e88565b600e5460408051631f8f738360e31b815290516000926001600160a01b03169163fc7b9c18916004808301926020929190829003018186803b158015610ef557600080fd5b600a546001600160a01b03163314806122fa57506122fa33610ce0565b6123165760405162461bcd60e51b8152600401610b7f90613ffa565b610ff5612eee565b60006123306301e13380612710614210565b8361233b8642613ed0565b601d546123489190614210565b6123529190614210565b61235c919061422f565b90506000612710601e54846123719190614210565b61237b919061422f565b905080821115612389578091505b509392505050565b60008061239c61181b565b6123ae84670de0b6b3a7640000614210565b6123b8919061422f565b9050670de0b6b3a76400006123cb61181b565b6123d59083614210565b6123df919061422f565b83116123eb5780610ea9565b610ea9816001613eb8565b6001600160a01b03821661244c5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610b7f565b806002600082825461245e9190613eb8565b90915550506001600160a01b0382166000908152602081905260408120805483929061248b908490613eb8565b90915550506040518181526001600160a01b038316906000906000805160206142e98339815191529060200160405180910390a35050565b6125198363a9059cbb60e01b84846040516024016124e2929190614251565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f6a565b505050565b6040516001600160a01b03808516602483015283166044820152606481018290526125569085906323b872dd60e01b906084016124e2565b50505050565b6001600160a01b0383166125be5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610b7f565b6001600160a01b03821661261f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610b7f565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b6001600160a01b03811660009081526001830160205260408120541515610ea9565b6000610ea9836001600160a01b03841661303c565b600f546001600160a01b03161561278e57600f5460405163632447c960e01b81526001600160a01b039091169063632447c9906126f9908690600401613ac2565b600060405180830381600087803b15801561271357600080fd5b505af1158015612727573d6000803e3d6000fd5b5050600f5460405163632447c960e01b81526001600160a01b03909116925063632447c9915061275b908590600401613ac2565b600060405180830381600087803b15801561277557600080fd5b505af1158015612789573d6000803e3d6000fd5b505050505b61251983838361312f565b600f546001600160a01b03161561207d57600f5460405163632447c960e01b81526001600160a01b039091169063632447c99061204f908490600401613ac2565b6040805180820190915260018152601960f91b6020820152816128105760405162461bcd60e51b8152600401610b7f9190613a4e565b5060008061281d836132f5565b91509150801561284257600061283283612391565b905083811015612840578093505b505b61284c338461339c565b612855826134d9565b50604080518481526020810184905233917ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b568910160405180910390a2505050565b600e5460405163228bfd9f60e01b8152600091829182916001600160a01b03169063228bfd9f906128cb908890600401613ac2565b6101206040518083038186803b1580156128e457600080fd5b505afa1580156128f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061291c9190613df1565b505050509450945050505061293282828661231e565b95945050505050565b600060085446141561294e575060065490565b6007546040805180820190915260018152603160f81b602090910152610cc2907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f907fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66134f6565b600b54600160a01b900460ff166129fc5760405162461bcd60e51b815260206004820152600a6024820152691b9bdd0b5c185d5cd95960b21b6044820152606401610b7f565b600b54600160a81b900460ff1615612a265760405162461bcd60e51b8152600401610b7f90614070565b600b805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b604051612a639190613ac2565b60405180910390a1565b6000610ea9836001600160a01b03841661353f565b600f546001600160a01b03161561207d57600f5460405163d279c19160e01b81526001600160a01b039091169063d279c1919061204f908490600401613ac2565b60606000610ea98361358e565b6000612adb82611c49565b9050612af533600d546001600160a01b031690308561251e565b612aff33826123f6565b604080518281526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a25050565b600b54600160a01b900460ff1615612b685760405162461bcd60e51b8152600401610b7f90614092565b600b805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258612a563390565b8151612bb6906003906020850190613966565b508051612519906004906020840190613966565b80516020808301919091206007819055466008556040805180820190915260018152603160f81b920191909152612c43907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f907fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc66134f6565b60065550565b600554610100900460ff1680612c62575060055460ff16155b612c7e5760405162461bcd60e51b8152600401610b7f906140b2565b600554610100900460ff16158015612ca0576005805461ffff19166101011790555b600a80546001600160a01b0319163390811790915560405181906000907fd4459d5b8b913cab0244230fd9b1c08b6ceace7fe9230e60d0f74cbffdf849d0908290a350801561207d576005805461ff001916905550565b60006fa2a8918ca85bafe22016d0b997e4df60600160ff1b03821115612d6a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610b7f565b8360ff16601b1480612d7f57508360ff16601c145b612dd65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610b7f565b6040805160008082526020820180845288905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa158015612e2a573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166129325760405162461bcd60e51b815260206004820152601860248201527745434453413a20696e76616c6964207369676e617475726560401b6044820152606401610b7f565b600b54600160a81b900460ff1615612eb25760405162461bcd60e51b8152600401610b7f90614070565b600b805461ffff60a01b191661010160a01b1790557f28b4c24cb1012c094cd2f59f98e89d791973295f8fda6eaa118022d6d318960a33612a56565b600b54600160a81b900460ff16612f365760405162461bcd60e51b815260206004820152600c60248201526b3737ba16b9b43aba3237bbb760a11b6044820152606401610b7f565b600b805460ff60a81b191690557fece7583a70a505ef0e36d4dec768f5ae597713e09c26011022599ee01abdabfc33612a56565b6000612fbf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166135ea9092919063ffffffff16565b8051909150156125195780806020019051810190612fdd919061426a565b6125195760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610b7f565b60008181526001830160205260408120548015613125576000613060600183613ed0565b855490915060009061307490600190613ed0565b90508181146130d957600086600001828154811061309457613094614285565b90600052602060002001549050808760000184815481106130b7576130b7614285565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806130ea576130ea61429b565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610b4f565b6000915050610b4f565b6001600160a01b0383166131935760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608401610b7f565b6001600160a01b0382166131f55760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610b7f565b6001600160a01b0383166000908152602081905260409020548181101561326d5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608401610b7f565b6132778282613ed0565b6001600160a01b0380861660009081526020819052604080822093909355908516815290812080548492906132ad908490613eb8565b92505081905550826001600160a01b0316846001600160a01b03166000805160206142e9833981519152846040516132e791815260200190565b60405180910390a350505050565b600080670de0b6b3a764000061330961181b565b6133139085614210565b61331d919061422f565b91506000613329611c00565b90508083111561335f576133456133408285613ed0565b613601565b61334d611c00565b90508083111561335f57809250600191505b6040805180820190915260018152603160f81b6020820152836133955760405162461bcd60e51b8152600401610b7f9190613a4e565b5050915091565b6001600160a01b0382166133fc5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610b7f565b6001600160a01b038216600090815260208190526040902054818110156134705760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610b7f565b61347a8282613ed0565b6001600160a01b038416600090815260208190526040812091909155600280548492906134a8908490613ed0565b90915550506040518281526000906001600160a01b038516906000805160206142e983398151915290602001612674565b60006134f233600d546001600160a01b031690846124c3565b5090565b6040805160208101859052908101839052606081018290524660808201523060a082015260009060c0016040516020818303038152906040528051906020012090509392505050565b600081815260018301602052604081205461358657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610b4f565b506000610b4f565b6060816000018054806020026020016040519081016040528092919081815260200182805480156135de57602002820191906000526020600020905b8154815260200190600101908083116135ca575b50505050509050919050565b60606135f98484600085613805565b949350505050565b6000806000806000613611610c41565b805190915060005b818110156137fb57600061362d858a613ed0565b9050600084838151811061364357613643614285565b6020908102919091010151600e54604051639f2b283360e01b81529192506001600160a01b031690639f2b28339061367f908490600401613ac2565b60206040518083038186803b15801561369757600080fd5b505afa1580156136ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136cf9190614020565b9850886136dd5750506137e9565b888211156136e9578891505b6136f1611c00565b604051632e1a7d4d60e01b8152600481018490529098506001600160a01b03821690632e1a7d4d90602401600060405180830381600087803b15801561373657600080fd5b505af1925050508015613747575060015b6137525750506137e9565b8761375b611c00565b6137659190613ed0565b600e54604051632fb9ba3160e01b81529198506001600160a01b031690632fb9ba31906137989084908b90600401614251565b600060405180830381600087803b1580156137b257600080fd5b505af11580156137c6573d6000803e3d6000fd5b5050505086866137d69190613eb8565b95508986106137e65750506137fb565b50505b806137f3816142b1565b915050613619565b5050505050505050565b6060824710156138665760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610b7f565b843b6138b45760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b7f565b600080866001600160a01b031685876040516138d091906142cc565b60006040518083038185875af1925050503d806000811461390d576040519150601f19603f3d011682016040523d82523d6000602084013e613912565b606091505b509150915061392282828661392d565b979650505050505050565b6060831561393c575081610ea9565b82511561394c5782518084602001fd5b8160405162461bcd60e51b8152600401610b7f9190613a4e565b82805461397290613ee7565b90600052602060002090601f01602090048101928261399457600085556139da565b82601f106139ad57805160ff19168380011785556139da565b828001600101855582156139da579182015b828111156139da5782518255916020019190600101906139bf565b506134f29291505b808211156134f257600081556001016139e2565b600080600060608486031215613a0b57600080fd5b505081359360208301359350604090920135919050565b60005b83811015613a3d578181015183820152602001613a25565b838111156125565750506000910152565b6020815260008251806020840152613a6d816040850160208701613a22565b601f01601f19169190910160400192915050565b6001600160a01b038116811461207d57600080fd5b60008060408385031215613aa957600080fd5b8235613ab481613a81565b946020939093013593505050565b6001600160a01b0391909116815260200190565b600060208284031215613ae857600080fd5b5035919050565b6020808252825182820181905260009190848201906040850190845b81811015613b305783516001600160a01b031683529284019291840191600101613b0b565b50909695505050505050565b600060208284031215613b4e57600080fd5b8135610ea981613a81565b600080600060608486031215613b6e57600080fd5b8335613b7981613a81565b92506020840135613b8981613a81565b929592945050506040919091013590565b60ff8116811461207d57600080fd5b600080600080600060a08688031215613bc157600080fd5b85359450602086013593506040860135613bda81613b9a565b94979396509394606081013594506080013592915050565b60008060408385031215613c0557600080fd5b8235613c1081613a81565b91506020830135613c2081613a81565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613c6a57613c6a613c2b565b604052919050565b600082601f830112613c8357600080fd5b813567ffffffffffffffff811115613c9d57613c9d613c2b565b613cb0601f8201601f1916602001613c41565b818152846020838601011115613cc557600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215613cf857600080fd5b843567ffffffffffffffff80821115613d1057600080fd5b613d1c88838901613c72565b95506020870135915080821115613d3257600080fd5b50613d3f87828801613c72565b9350506040850135613d5081613a81565b91506060850135613d6081613a81565b939692955090935050565b600080600080600080600060e0888a031215613d8657600080fd5b8735613d9181613a81565b96506020880135613da181613a81565b955060408801359450606088013593506080880135613dbf81613b9a565b9699959850939692959460a0840135945060c09093013592915050565b80518015158114613dec57600080fd5b919050565b60008060008060008060008060006101208a8c031215613e1057600080fd5b613e198a613ddc565b985060208a0151975060408a0151965060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a015191506101008a015190509295985092959850929598565b600060208284031215613e7357600080fd5b8151610ea981613a81565b60008060408385031215613e9157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052601160045260246000fd5b60008219821115613ecb57613ecb613ea2565b500190565b600082821015613ee257613ee2613ea2565b500390565b600181811c90821680613efb57607f821691505b60208210811415613f1c57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600c908201526b3737ba16b3b7bb32b93737b960a11b604082015260600190565b60006020808385031215613f5b57600080fd5b825167ffffffffffffffff80821115613f7357600080fd5b818501915085601f830112613f8757600080fd5b815181811115613f9957613f99613c2b565b8060051b9150613faa848301613c41565b8181529183018401918481019088841115613fc457600080fd5b938501935b83851015613fee5784519250613fde83613a81565b8282529385019390850190613fc9565b98975050505050505050565b6020808252600c908201526b3737ba16b096b5b2b2b832b960a11b604082015260600190565b60006020828403121561403257600080fd5b5051919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526008908201526739b43aba3237bbb760c11b604082015260600190565b6020808252600690820152651c185d5cd95960d21b604082015260600190565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b60006020828403121561411257600080fd5b8151610ea981613b9a565b600181815b8085111561415857816000190482111561413e5761413e613ea2565b8085161561414b57918102915b93841c9390800290614122565b509250929050565b60008261416f57506001610b4f565b8161417c57506000610b4f565b8160018114614192576002811461419c576141b8565b6001915050610b4f565b60ff8411156141ad576141ad613ea2565b50506001821b610b4f565b5060208310610133831016604e8410600b84101617156141db575081810a610b4f565b6141e5838361411d565b80600019048211156141f9576141f9613ea2565b029392505050565b6000610ea960ff841683614160565b600081600019048311821515161561422a5761422a613ea2565b500290565b60008261424c57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b03929092168252602082015260400190565b60006020828403121561427c57600080fd5b610ea982613ddc565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60006000198214156142c5576142c5613ea2565b5060010190565b600082516142de818460208701613a22565b919091019291505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220abf1e07fafbaa608304f172200235d161aa1ebbaa8b9d8c1ba464cd12f8d9be264736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b56657370657220706f6f6c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000576506f6f6c000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : name_ (string): Vesper pool
Arg [1] : symbol_ (string): vPool
Arg [2] : token_ (address): 0x0000000000000000000000000000000000000000
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [4] : 56657370657220706f6f6c000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [6] : 76506f6f6c000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
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.