编译器
0.6.12+commit.27d51765
文件 1 的 21:Address.sol
pragma solidity >=0.6.2 <0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
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");
}
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");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(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 {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 21:Context.sol
pragma solidity >=0.6.0 <0.8.0;
import "../utils/Context.sol";
文件 3 的 21:IAddressList.sol
pragma solidity ^0.6.6;
interface IAddressList {
event AddressUpdated(address indexed a, address indexed sender);
event AddressRemoved(address indexed a, address indexed sender);
function add(address a) external returns (bool);
function addValue(address a, uint256 v) external returns (bool);
function addMulti(address[] calldata addrs) external returns (uint256);
function addValueMulti(address[] calldata addrs, uint256[] calldata values) external returns (uint256);
function remove(address a) external returns (bool);
function removeMulti(address[] calldata addrs) external returns (uint256);
function get(address a) external view returns (uint256);
function contains(address a) external view returns (bool);
function at(uint256 index) external view returns (address, uint256);
function length() external view returns (uint256);
}
文件 4 的 21:IAddressListExt.sol
pragma solidity ^0.6.6;
import "./IAddressList.sol";
interface IAddressListExt is IAddressList {
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleMemberCount(bytes32 role) external view returns (uint256);
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 5 的 21:IAddressListFactory.sol
pragma solidity ^0.6.6;
interface IAddressListFactory {
event ListCreated(address indexed _sender, address indexed _newList);
function ours(address a) external view returns (bool);
function listCount() external view returns (uint256);
function listAt(uint256 idx) external view returns (address);
function createList() external returns (address listaddr);
}
文件 6 的 21:IController.sol
pragma solidity 0.6.12;
interface IController {
function aaveReferralCode() external view returns (uint16);
function feeCollector(address) external view returns (address);
function founderFee() external view returns (uint256);
function founderVault() external view returns (address);
function interestFee(address) external view returns (uint256);
function isPool(address) external view returns (bool);
function pools() external view returns (address);
function strategy(address) external view returns (address);
function rebalanceFriction(address) external view returns (uint256);
function poolRewards(address) external view returns (address);
function treasuryPool() external view returns (address);
function uniswapRouter() external view returns (address);
function withdrawFee(address) external view returns (uint256);
}
文件 7 的 21:IERC20.sol
pragma solidity >=0.6.0 <0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 8 的 21:IPoolRewardsV3.sol
pragma solidity 0.6.12;
interface IPoolRewardsV3 {
event RewardAdded(uint256 reward);
event RewardPaid(address indexed user, uint256 reward);
event RewardEnded(address indexed dustReceiver, uint256 dust);
event UpdatedRewardEndTime(uint256 previousRewardEndTime, uint256 newRewardEndTime);
function claimReward(address) external;
function notifyRewardAmount(uint256 rewardAmount, uint256 endTime) external;
function updateRewardEndTime() external;
function updateReward(address) external;
function withdrawRemaining(address _toAddress) external;
function claimable(address) external view returns (uint256);
function lastTimeRewardApplicable() external view returns (uint256);
function rewardForDuration() external view returns (uint256);
function rewardPerToken() external view returns (uint256);
function rewardToken() external view returns (address);
}
文件 9 的 21:IStrategy.sol
pragma solidity 0.6.12;
interface IStrategy {
function rebalance() external;
function deposit(uint256 amount) external;
function beforeWithdraw() external;
function withdraw(uint256 amount) external;
function withdrawAll() external;
function isUpgradable() external view returns (bool);
function isReservedToken(address _token) external view returns (bool);
function token() external view returns (address);
function pool() external view returns (address);
function totalLocked() external view returns (uint256);
function pause() external;
function unpause() external;
}
文件 10 的 21:IStrategyV3.sol
pragma solidity 0.6.12;
interface IStrategyV3 {
function totalValue() external view returns (uint256);
}
文件 11 的 21:ISwapManager.sol
pragma solidity 0.6.12;
import "../uniswap/IUniswapV2Router02.sol";
interface ISwapManager {
event OracleCreated(address indexed _sender, address indexed _newOracle, uint256 _period);
function N_DEX() external view returns (uint256);
function ROUTERS(uint256 i) external view returns (IUniswapV2Router02);
function bestOutputFixedInput(
address _from,
address _to,
uint256 _amountIn
)
external
view
returns (
address[] memory path,
uint256 amountOut,
uint256 rIdx
);
function bestPathFixedInput(
address _from,
address _to,
uint256 _amountIn,
uint256 _i
) external view returns (address[] memory path, uint256 amountOut);
function bestInputFixedOutput(
address _from,
address _to,
uint256 _amountOut
)
external
view
returns (
address[] memory path,
uint256 amountIn,
uint256 rIdx
);
function bestPathFixedOutput(
address _from,
address _to,
uint256 _amountOut,
uint256 _i
) external view returns (address[] memory path, uint256 amountIn);
function safeGetAmountsOut(
uint256 _amountIn,
address[] memory _path,
uint256 _i
) external view returns (uint256[] memory result);
function unsafeGetAmountsOut(
uint256 _amountIn,
address[] memory _path,
uint256 _i
) external view returns (uint256[] memory result);
function safeGetAmountsIn(
uint256 _amountOut,
address[] memory _path,
uint256 _i
) external view returns (uint256[] memory result);
function unsafeGetAmountsIn(
uint256 _amountOut,
address[] memory _path,
uint256 _i
) external view returns (uint256[] memory result);
function comparePathsFixedInput(
address[] memory pathA,
address[] memory pathB,
uint256 _amountIn,
uint256 _i
) external view returns (address[] memory path, uint256 amountOut);
function comparePathsFixedOutput(
address[] memory pathA,
address[] memory pathB,
uint256 _amountOut,
uint256 _i
) external view returns (address[] memory path, uint256 amountIn);
function ours(address a) external view returns (bool);
function oracleCount() external view returns (uint256);
function oracleAt(uint256 idx) external view returns (address);
function getOracle(
address _tokenA,
address _tokenB,
uint256 _period,
uint256 _i
) external view returns (address);
function createOrUpdateOracle(
address _tokenA,
address _tokenB,
uint256 _period,
uint256 _i
) external returns (address oracleAddr);
function consultForFree(
address _from,
address _to,
uint256 _amountIn,
uint256 _period,
uint256 _i
) external view returns (uint256 amountOut, uint256 lastUpdatedAt);
function consult(
address _from,
address _to,
uint256 _amountIn,
uint256 _period,
uint256 _i
)
external
returns (
uint256 amountOut,
uint256 lastUpdatedAt,
bool updated
);
function updateOracles() external returns (uint256 updated, uint256 expected);
function updateOracles(address[] memory _oracleAddrs)
external
returns (uint256 updated, uint256 expected);
}
文件 12 的 21:IUniswapV2Router01.sol
pragma solidity 0.6.12;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactETHForTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function swapTokensForExactETH(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForETH(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapETHForExactTokens(
uint256 amountOut,
address[] calldata path,
address to,
uint256 deadline
) external payable returns (uint256[] memory amounts);
function quote(
uint256 amountA,
uint256 reserveA,
uint256 reserveB
) external pure returns (uint256 amountB);
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountOut);
function getAmountIn(
uint256 amountOut,
uint256 reserveIn,
uint256 reserveOut
) external pure returns (uint256 amountIn);
function getAmountsOut(uint256 amountIn, address[] calldata path)
external
view
returns (uint256[] memory amounts);
function getAmountsIn(uint256 amountOut, address[] calldata path)
external
view
returns (uint256[] memory amounts);
}
文件 13 的 21:IUniswapV2Router02.sol
pragma solidity 0.6.12;
import "./IUniswapV2Router01.sol";
interface IUniswapV2Router02 is IUniswapV2Router01 {
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external;
}
文件 14 的 21:IVesperPool.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IVesperPool is IERC20 {
function approveToken() external;
function deposit() external payable;
function deposit(uint256) external;
function multiTransfer(uint256[] memory) external returns (bool);
function permit(
address,
address,
uint256,
uint256,
uint8,
bytes32,
bytes32
) external;
function rebalance() external;
function resetApproval() external;
function sweepErc20(address) external;
function withdraw(uint256) external;
function withdrawETH(uint256) external;
function withdrawByStrategy(uint256) external;
function feeCollector() external view returns (address);
function getPricePerShare() external view returns (uint256);
function token() external view returns (address);
function tokensHere() external view returns (uint256);
function totalValue() external view returns (uint256);
function withdrawFee() external view returns (uint256);
}
文件 15 的 21:IVesperPoolV3.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IVesperPoolV3 is IERC20 {
function deposit() external payable;
function deposit(uint256 _share) external;
function governor() external returns (address);
function keepers() external returns (address);
function multiTransfer(address[] memory _recipients, uint256[] memory _amounts)
external
returns (bool);
function excessDebt(address _strategy) external view returns (uint256);
function permit(
address,
address,
uint256,
uint256,
uint8,
bytes32,
bytes32
) external;
function reportEarning(
uint256 _profit,
uint256 _loss,
uint256 _payback
) external;
function resetApproval() external;
function sweepERC20(address _fromToken) external;
function withdraw(uint256 _amount) external;
function withdrawETH(uint256 _amount) external;
function whitelistedWithdraw(uint256 _amount) external;
function feeCollector() external view returns (address);
function pricePerShare() external view returns (uint256);
function token() external view returns (address);
function tokensHere() external view returns (uint256);
function totalDebtOf(address _strategy) external view returns (uint256);
function totalValue() external view returns (uint256);
function withdrawFee() external view returns (uint256);
function poolRewards() external view returns (address);
function getStrategies() external view returns (address[] memory);
}
文件 16 的 21:Pausable.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/GSN/Context.sol";
contract Pausable is 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, "Pausable: paused");
_;
}
modifier whenPaused() {
require(paused, "Pausable: not paused");
_;
}
modifier whenNotShutdown() {
require(!stopEverything, "Pausable: shutdown");
_;
}
modifier whenShutdown() {
require(stopEverything, "Pausable: not shutdown");
_;
}
function _pause() internal virtual whenNotPaused {
paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused whenNotShutdown {
paused = false;
emit Unpaused(_msgSender());
}
function _shutdown() internal virtual whenNotShutdown {
stopEverything = true;
paused = true;
emit Shutdown(_msgSender());
}
function _open() internal virtual whenShutdown {
stopEverything = false;
emit Open(_msgSender());
}
}
文件 17 的 21:SafeERC20.sol
pragma solidity >=0.6.0 <0.8.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
library SafeERC20 {
using SafeMath for uint256;
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));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
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).add(value);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 18 的 21:SafeMath.sol
pragma solidity >=0.6.0 <0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
文件 19 的 21:Strategy.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "../Pausable.sol";
import "../interfaces/bloq/ISwapManager.sol";
import "../interfaces/vesper/IController.sol";
import "../interfaces/vesper/IStrategy.sol";
import "../interfaces/vesper/IVesperPool.sol";
import "../../sol-address-list/contracts/interfaces/IAddressListExt.sol";
import "../../sol-address-list/contracts/interfaces/IAddressListFactory.sol";
abstract contract Strategy is IStrategy, Pausable {
using SafeERC20 for IERC20;
using SafeMath for uint256;
ISwapManager public swapManager = ISwapManager(0xe382d9f2394A359B01006faa8A1864b8a60d2710);
IController public immutable controller;
IERC20 public immutable collateralToken;
address public immutable receiptToken;
address public immutable override pool;
IAddressListExt public keepers;
address internal constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
uint256 internal constant MAX_UINT_VALUE = type(uint256).max;
event UpdatedSwapManager(address indexed previousSwapManager, address indexed newSwapManager);
constructor(
address _controller,
address _pool,
address _receiptToken
) public {
require(_controller != address(0), "controller-address-is-zero");
require(IController(_controller).isPool(_pool), "not-a-valid-pool");
controller = IController(_controller);
pool = _pool;
collateralToken = IERC20(IVesperPool(_pool).token());
receiptToken = _receiptToken;
}
modifier onlyAuthorized() {
require(
_msgSender() == address(controller) || _msgSender() == pool,
"caller-is-not-authorized"
);
_;
}
modifier onlyController() {
require(_msgSender() == address(controller), "caller-is-not-the-controller");
_;
}
modifier onlyKeeper() {
require(keepers.contains(_msgSender()), "caller-is-not-keeper");
_;
}
modifier onlyPool() {
require(_msgSender() == pool, "caller-is-not-the-pool");
_;
}
function pause() external override onlyController {
_pause();
}
function unpause() external override onlyController {
_unpause();
}
function approveToken() external onlyController {
_approveToken(0);
_approveToken(MAX_UINT_VALUE);
}
function resetApproval() external onlyController {
_approveToken(0);
}
function createKeeperList() external onlyController {
require(address(keepers) == address(0), "keeper-list-already-created");
IAddressListFactory factory =
IAddressListFactory(0xD57b41649f822C51a73C44Ba0B3da4A880aF0029);
keepers = IAddressListExt(factory.createList());
keepers.grantRole(keccak256("LIST_ADMIN"), _msgSender());
}
function updateSwapManager(address _swapManager) external onlyController {
require(_swapManager != address(0), "sm-address-is-zero");
require(_swapManager != address(swapManager), "sm-is-same");
emit UpdatedSwapManager(address(swapManager), _swapManager);
swapManager = ISwapManager(_swapManager);
}
function deposit(uint256 _amount) public override onlyKeeper {
_updatePendingFee();
_deposit(_amount);
}
function depositAll() external virtual onlyKeeper {
deposit(collateralToken.balanceOf(pool));
}
function withdraw(uint256 _amount) external override onlyAuthorized {
_updatePendingFee();
_withdraw(_amount);
}
function withdrawAll() external override onlyController {
_withdrawAll();
}
function sweepErc20(address _fromToken) external onlyKeeper {
require(!isReservedToken(_fromToken), "not-allowed-to-sweep");
if (_fromToken == ETH) {
Address.sendValue(payable(pool), address(this).balance);
} else {
uint256 _amount = IERC20(_fromToken).balanceOf(address(this));
IERC20(_fromToken).safeTransfer(pool, _amount);
}
}
function isUpgradable() external view virtual override returns (bool) {
return totalLocked() == 0;
}
function token() external view override returns (address) {
return receiptToken;
}
function convertFrom18(uint256 amount) public pure virtual returns (uint256) {
return amount;
}
function interestEarned() external view virtual returns (uint256);
function isReservedToken(address _token) public view virtual override returns (bool);
function totalLocked() public view virtual override returns (uint256);
function migrateIn() external onlyController {
_migrateIn();
}
function migrateOut() external onlyController {
_migrateOut();
}
function _handleFee(uint256 _fee) internal virtual {
if (_fee != 0) {
IVesperPool(pool).deposit(_fee);
uint256 _feeInVTokens = IERC20(pool).balanceOf(address(this));
IERC20(pool).safeTransfer(controller.feeCollector(pool), _feeInVTokens);
}
}
function _safeSwap(
address _from,
address _to,
uint256 _amount
) internal {
(address[] memory _path, uint256 amountOut, uint256 rIdx) =
swapManager.bestOutputFixedInput(_from, _to, _amount);
if (amountOut != 0) {
swapManager.ROUTERS(rIdx).swapExactTokensForTokens(
_amount,
1,
_path,
address(this),
block.timestamp + 30
);
}
}
function _deposit(uint256 _amount) internal virtual;
function _withdraw(uint256 _amount) internal virtual;
function _approveToken(uint256 _amount) internal virtual;
function _updatePendingFee() internal virtual;
function _withdrawAll() internal virtual;
function _migrateIn() internal virtual;
function _migrateOut() internal virtual;
function _claimReward() internal virtual;
}
文件 20 的 21:VesperV3Strategy.sol
pragma solidity 0.6.12;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "../interfaces/vesper/IController.sol";
import "./Strategy.sol";
import "../interfaces/bloq/ISwapManager.sol";
import "../interfaces/vesper/IVesperPoolV3.sol";
import "../interfaces/vesper/IStrategyV3.sol";
import "../interfaces/vesper/IPoolRewardsV3.sol";
abstract contract VesperV3Strategy is Strategy {
using SafeERC20 for IERC20;
using SafeMath for uint256;
IVesperPoolV3 internal immutable vToken;
constructor(
address _controller,
address _pool,
address _receiptToken
) public Strategy(_controller, _pool, _receiptToken) {
vToken = IVesperPoolV3(_receiptToken);
}
function _migrateIn() internal override {
require(controller.isPool(pool), "not-a-valid-pool");
require(controller.strategy(pool) == address(this), "not-a-valid-strategy");
IERC20(vToken).safeTransferFrom(pool, address(this), vToken.balanceOf(pool));
}
function _migrateOut() internal override {
require(controller.isPool(pool), "not-a-valid-pool");
_pause();
IERC20(vToken).safeTransfer(pool, vToken.balanceOf(address(this)));
}
function beforeWithdraw() external override onlyPool {}
function rebalance() external override whenNotPaused onlyKeeper {
_claimReward();
uint256 balance = collateralToken.balanceOf(pool);
if (balance != 0) {
_deposit(balance);
}
}
function interestEarned() public view override returns (uint256 collateralEarned) {
address _poolRewards = vToken.poolRewards();
if (_poolRewards != address(0)) {
address _rewardToken = IPoolRewardsV3(_poolRewards).rewardToken();
uint256 _claimableRewards = IPoolRewardsV3(_poolRewards).claimable(address(this));
if (_claimableRewards != 0) {
(, collateralEarned, ) = swapManager.bestOutputFixedInput(
_rewardToken,
address(collateralToken),
_claimableRewards
);
}
}
address[] memory _strategies = vToken.getStrategies();
uint256 _len = _strategies.length;
uint256 _unrealizedGain;
for (uint256 i = 0; i < _len; i++) {
uint256 _totalValue = IStrategyV3(_strategies[i]).totalValue();
uint256 _debt = vToken.totalDebtOf(_strategies[i]);
if (_totalValue > _debt) {
_unrealizedGain = _unrealizedGain.add(_totalValue.sub(_debt));
}
}
if (_unrealizedGain != 0) {
collateralEarned = collateralEarned.add(
_unrealizedGain.mul(vToken.balanceOf(address(this))).div(vToken.totalSupply())
);
}
}
function isUpgradable() external view override returns (bool) {
return vToken.balanceOf(address(this)) == 0;
}
function isReservedToken(address _token) public view override returns (bool) {
address _poolRewards = vToken.poolRewards();
return
_token == address(vToken) ||
(_poolRewards != address(0) && _token == IPoolRewardsV3(_poolRewards).rewardToken());
}
function _approveToken(uint256 _amount) internal override {
collateralToken.safeApprove(pool, _amount);
collateralToken.safeApprove(address(vToken), _amount);
address _poolRewards = vToken.poolRewards();
if (_poolRewards != address(0)) {
address _rewardToken = IPoolRewardsV3(_poolRewards).rewardToken();
for (uint256 i = 0; i < swapManager.N_DEX(); i++) {
IERC20(_rewardToken).safeApprove(address(swapManager.ROUTERS(i)), _amount);
}
}
}
function _claimReward() internal override {
address _poolRewards = vToken.poolRewards();
if (_poolRewards != address(0)) {
IERC20 _rewardToken = IERC20(IPoolRewardsV3(_poolRewards).rewardToken());
uint256 _rewardAmount = _rewardToken.balanceOf(address(this));
if (_rewardAmount != 0)
_safeSwap(address(_rewardToken), address(collateralToken), _rewardAmount);
}
}
function totalLocked() public view override returns (uint256) {
uint256 _totalVTokens = vToken.balanceOf(pool).add(vToken.balanceOf(address(this)));
return _convertToCollateral(_totalVTokens);
}
function _deposit(uint256 _amount) internal virtual override {
collateralToken.safeTransferFrom(pool, address(this), _amount);
vToken.deposit(_amount);
}
function _withdraw(uint256 _amount) internal override {
_safeWithdraw(_convertToShares(_amount));
collateralToken.safeTransfer(pool, collateralToken.balanceOf(address(this)));
}
function _safeWithdraw(uint256 _shares) internal {
uint256 _maxShares = vToken.balanceOf(address(this));
if (_shares != 0) {
vToken.withdraw(_shares);
require(
vToken.balanceOf(address(this)) == _maxShares.sub(_shares),
"Not enough shares withdrawn"
);
}
}
function _withdrawAll() internal override {
_safeWithdraw(vToken.balanceOf(address(this)));
_claimReward();
collateralToken.safeTransfer(pool, collateralToken.balanceOf(address(this)));
}
function _convertToCollateral(uint256 _vTokenAmount) internal view returns (uint256) {
uint256 _totalSupply = vToken.totalSupply();
return (_totalSupply != 0) ? vToken.totalValue().mul(_vTokenAmount).div(_totalSupply) : 0;
}
function _convertToShares(uint256 _collateralAmount) internal view returns (uint256) {
return _collateralAmount.mul(vToken.totalSupply()).div(vToken.totalValue());
}
function _updatePendingFee() internal override {}
}
文件 21 的 21:VesperV3StrategyDAI.sol
pragma solidity 0.6.12;
import "./VesperV3Strategy.sol";
contract VesperV3StrategyDAI is VesperV3Strategy {
string public constant NAME = "Strategy-VesperV3-DAI";
string public constant VERSION = "2.0.9";
constructor(
address _controller,
address _pool,
address _receiptToken
) public VesperV3Strategy(_controller, _pool, _receiptToken) {}
}
{
"compilationTarget": {
"contracts/strategies/VesperV3StrategyDAI.sol": "VesperV3StrategyDAI"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_pool","type":"address"},{"internalType":"address","name":"_receiptToken","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"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":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousSwapManager","type":"address"},{"indexed":true,"internalType":"address","name":"newSwapManager","type":"address"}],"name":"UpdatedSwapManager","type":"event"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"approveToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"beforeWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collateralToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"convertFrom18","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"createKeeperList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestEarned","outputs":[{"internalType":"uint256","name":"collateralEarned","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"isReservedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isUpgradable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keepers","outputs":[{"internalType":"contract IAddressListExt","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrateIn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"migrateOut","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":[],"name":"pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"receiptToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"resetApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopEverything","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapManager","outputs":[{"internalType":"contract ISwapManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_fromToken","type":"address"}],"name":"sweepErc20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalLocked","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_swapManager","type":"address"}],"name":"updateSwapManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawAll","outputs":[],"stateMutability":"nonpayable","type":"function"}]