文件 1 的 20:AaveV2Core.sol
pragma solidity 0.8.9;
import "vesper-pools/contracts/dependencies/openzeppelin/contracts/utils/math/Math.sol";
import "vesper-pools/contracts/Errors.sol";
import "../../../interfaces/aave/IAave.sol";
abstract contract AaveV2Core {
StakedAave public constant stkAAVE = StakedAave(0x4da27a545c0c5B758a6BA100e3a049001de870f5);
address public constant AAVE = 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9;
AaveLendingPool public immutable aaveLendingPool;
AaveProtocolDataProvider public aaveProtocolDataProvider;
AaveIncentivesController public immutable aaveIncentivesController;
PoolAddressesProvider internal immutable aaveAddressesProvider_;
AToken internal immutable aToken;
bytes32 private constant AAVE_PROVIDER_ID = 0x0100000000000000000000000000000000000000000000000000000000000000;
constructor(address _receiptToken) {
require(_receiptToken != address(0), Errors.INPUT_ADDRESS_IS_ZERO);
aToken = AToken(_receiptToken);
try AToken(_receiptToken).getIncentivesController() returns (address _aaveIncentivesController) {
aaveIncentivesController = AaveIncentivesController(_aaveIncentivesController);
} catch {}
aaveAddressesProvider_ = PoolAddressesProvider(0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5);
aaveLendingPool = AaveLendingPool(aaveAddressesProvider_.getLendingPool());
aaveProtocolDataProvider = AaveProtocolDataProvider(aaveAddressesProvider_.getAddress(AAVE_PROVIDER_ID));
}
function _startCooldown() internal returns (bool) {
if (canStartCooldown()) {
stkAAVE.cooldown();
return true;
}
return false;
}
function _unstakeAave() internal {
stkAAVE.redeem(address(this), type(uint256).max);
}
function canUnstake() external view returns (bool) {
(, uint256 _cooldownEnd, uint256 _unstakeEnd) = cooldownData();
return _canUnstake(_cooldownEnd, _unstakeEnd);
}
function canStartCooldown() public view returns (bool) {
(uint256 _cooldownStart, , uint256 _unstakeEnd) = cooldownData();
return _canStartCooldown(_cooldownStart, _unstakeEnd);
}
function cooldownData() public view returns (uint256 _cooldownStart, uint256 _cooldownEnd, uint256 _unstakeEnd) {
_cooldownStart = stkAAVE.stakersCooldowns(address(this));
_cooldownEnd = _cooldownStart + stkAAVE.COOLDOWN_SECONDS();
_unstakeEnd = _cooldownEnd + stkAAVE.UNSTAKE_WINDOW();
}
function _claimAave() internal returns (uint256) {
(uint256 _cooldownStart, uint256 _cooldownEnd, uint256 _unstakeEnd) = cooldownData();
if (address(aaveIncentivesController) != address(0) && (_cooldownStart == 0 || block.timestamp > _unstakeEnd)) {
aaveIncentivesController.claimRewards(getAssets(), type(uint256).max, address(this));
}
if (stkAAVE.balanceOf(address(this)) > 0) {
(_cooldownStart, _cooldownEnd, _unstakeEnd) = cooldownData();
if (_canUnstake(_cooldownEnd, _unstakeEnd)) {
stkAAVE.redeem(address(this), type(uint256).max);
} else if (_canStartCooldown(_cooldownStart, _unstakeEnd)) {
stkAAVE.cooldown();
}
stkAAVE.claimRewards(address(this), type(uint256).max);
}
return IERC20(AAVE).balanceOf(address(this));
}
function _deposit(address _asset, uint256 _amount) internal {
if (_amount > 0) {
try aaveLendingPool.deposit(_asset, _amount, address(this), 0) {} catch Error(string memory _reason) {
require(bytes32(bytes(_reason)) == "56", _reason);
}
}
}
function getAssets() internal view returns (address[] memory) {
address[] memory _assets = new address[](1);
_assets[0] = address(aToken);
return _assets;
}
function _safeWithdraw(address _asset, address _to, uint256 _amount) internal returns (uint256) {
uint256 _aTokenBalance = aToken.balanceOf(address(this));
uint256 _availableLiquidity = IERC20(_asset).balanceOf(address(aToken));
return _withdraw(_asset, _to, Math.min(_amount, Math.min(_aTokenBalance, _availableLiquidity)));
}
function _withdraw(address _asset, address _to, uint256 _amount) internal returns (uint256) {
if (_amount > 0) {
require(aaveLendingPool.withdraw(_asset, _amount, _to) == _amount, Errors.INCORRECT_WITHDRAW_AMOUNT);
}
return _amount;
}
function _canStartCooldown(uint256 _cooldownStart, uint256 _unstakeEnd) internal view returns (bool) {
return stkAAVE.balanceOf(address(this)) > 0 && (_cooldownStart == 0 || block.timestamp > _unstakeEnd);
}
function _canUnstake(uint256 _cooldownEnd, uint256 _unstakeEnd) internal view returns (bool) {
return block.timestamp > _cooldownEnd && block.timestamp <= _unstakeEnd;
}
function _totalAave() internal view returns (uint256) {
if (address(aaveIncentivesController) == address(0)) {
return 0;
}
return
aaveIncentivesController.getRewardsBalance(getAssets(), address(this)) +
stkAAVE.balanceOf(address(this)) +
stkAAVE.getTotalRewardsBalance(address(this));
}
}
文件 2 的 20:AaveV2VesperXy.sol
pragma solidity 0.8.9;
import "vesper-pools/contracts/interfaces/vesper/IVesperPool.sol";
import "../../VesperRewards.sol";
import "./AaveV2Xy.sol";
contract AaveV2VesperXy is AaveV2Xy {
using SafeERC20 for IERC20;
IVesperPool public immutable vPool;
constructor(
address _pool,
address _swapper,
address _rewardToken,
address _receiptToken,
address _borrowToken,
address _vPool,
string memory _name
) AaveV2Xy(_pool, _swapper, _rewardToken, _receiptToken, _borrowToken, _name) {
require(address(IVesperPool(_vPool).token()) == borrowToken, "invalid-grow-pool");
vPool = IVesperPool(_vPool);
}
function _afterBorrowY(uint256 _amount) internal virtual override {
vPool.deposit(_amount);
}
function _approveToken(uint256 _amount) internal virtual override {
super._approveToken(_amount);
IERC20(borrowToken).safeApprove(address(vPool), _amount);
VesperRewards._approveToken(vPool, swapper, _amount);
}
function _beforeRepayY(uint256 _amount) internal virtual override {
_withdrawFromVesperPool(_amount);
}
function _claimAndSwapRewards() internal override {
uint256 _aaveAmount = _claimAave();
if (_aaveAmount > 0) {
_safeSwapExactInput(AAVE, address(collateralToken), _aaveAmount);
}
VesperRewards._claimAndSwapRewards(vPool, swapper, address(collateralToken));
}
function _getInvestedBorrowBalance() internal view virtual override returns (uint256) {
return
IERC20(borrowToken).balanceOf(address(this)) +
((vPool.pricePerShare() * vPool.balanceOf(address(this))) / 1e18);
}
function _rebalanceBorrow(uint256 _excessBorrow) internal virtual override {
if (_excessBorrow > 0) {
_withdrawFromVesperPool(_excessBorrow);
uint256 _borrowedHere = IERC20(borrowToken).balanceOf(address(this));
if (_borrowedHere > 0) {
_safeSwapExactInput(borrowToken, address(collateralToken), _borrowedHere);
}
}
}
function _withdrawFromVesperPool(uint256 _amount) internal {
if (_amount > 0) {
uint256 _pricePerShare = vPool.pricePerShare();
uint256 _shares = (_amount * 1e18) / _pricePerShare;
_shares = _amount > ((_shares * _pricePerShare) / 1e18) ? _shares + 1 : _shares;
vPool.withdraw(Math.min(_shares, vPool.balanceOf(address(this))));
}
}
}
文件 3 的 20:AaveV2Xy.sol
pragma solidity 0.8.9;
import "vesper-pools/contracts/interfaces/vesper/IPoolRewards.sol";
import "../../../interfaces/aave/IAave.sol";
import "../../Strategy.sol";
import "./AaveV2Core.sol";
contract AaveV2Xy is Strategy, AaveV2Core {
using SafeERC20 for IERC20;
string public NAME;
string public constant VERSION = "5.1.0";
uint256 internal constant MAX_BPS = 10_000;
uint256 public minBorrowLimit = 7_000;
uint256 public maxBorrowLimit = 8_500;
uint32 internal constant TWAP_PERIOD = 3600;
address public rewardToken;
address public borrowToken;
AToken public vdToken;
address internal aBorrowToken;
event UpdatedBorrowLimit(
uint256 previousMinBorrowLimit,
uint256 newMinBorrowLimit,
uint256 previousMaxBorrowLimit,
uint256 newMaxBorrowLimit
);
constructor(
address _pool,
address _swapper,
address _rewardToken,
address _receiptToken,
address _borrowToken,
string memory _name
) Strategy(_pool, _swapper, _receiptToken) AaveV2Core(_receiptToken) {
NAME = _name;
rewardToken = _rewardToken;
(address _aBorrowToken, , address _vdToken) = aaveProtocolDataProvider.getReserveTokensAddresses(_borrowToken);
vdToken = AToken(_vdToken);
borrowToken = _borrowToken;
aBorrowToken = _aBorrowToken;
}
function isReservedToken(address _token) public view virtual override returns (bool) {
return _token == address(aToken) || address(vdToken) == _token || borrowToken == _token;
}
function tvl() external view override returns (uint256) {
return aToken.balanceOf(address(this)) + collateralToken.balanceOf(address(this));
}
function _afterBorrowY(uint256 _amount) internal virtual {}
function _approveToken(uint256 _amount) internal virtual override {
super._approveToken(_amount);
collateralToken.safeApprove(address(aToken), _amount);
collateralToken.safeApprove(address(aaveLendingPool), _amount);
IERC20(borrowToken).safeApprove(address(aaveLendingPool), _amount);
IERC20(collateralToken).safeApprove(address(swapper), _amount);
IERC20(rewardToken).safeApprove(address(swapper), _amount);
IERC20(borrowToken).safeApprove(address(swapper), _amount);
}
function _beforeMigration(address _newStrategy) internal virtual override {
require(IStrategy(_newStrategy).token() == address(aToken), "wrong-receipt-token");
_repayY(vdToken.balanceOf(address(this)));
}
function _beforeRepayY(uint256 _amount) internal virtual {}
function _borrowY(uint256 _amount) internal virtual {
if (_amount > 0) {
aaveLendingPool.borrow(borrowToken, _amount, 2, 0, address(this));
_afterBorrowY(_amount);
}
}
function _calculateBorrowPosition(
uint256 _depositAmount,
uint256 _withdrawAmount
) internal view returns (uint256 _borrowAmount, uint256 _repayAmount) {
require(_depositAmount == 0 || _withdrawAmount == 0, "all-input-gt-zero");
uint256 _borrowed = vdToken.balanceOf(address(this));
if (maxBorrowLimit == 0) {
return (0, _borrowed);
}
uint256 _collateral = aToken.balanceOf(address(this));
uint256 _hypotheticalCollateral = _depositAmount > 0
? _collateral + _depositAmount
: _collateral > _withdrawAmount
? _collateral - _withdrawAmount
: 0;
if (_hypotheticalCollateral == 0) {
return (0, _borrowed);
}
AaveOracle _aaveOracle = AaveOracle(aaveAddressesProvider_.getPriceOracle());
uint256 _borrowTokenPrice = _aaveOracle.getAssetPrice(borrowToken);
uint256 _collateralTokenPrice = _aaveOracle.getAssetPrice(address(collateralToken));
if (_borrowTokenPrice == 0 || _collateralTokenPrice == 0) {
return (0, _borrowed);
}
(, uint256 _collateralFactor, , , , , , , , ) = aaveProtocolDataProvider.getReserveConfigurationData(
address(collateralToken)
);
uint256 _actualCollateralForBorrow = (_hypotheticalCollateral * _collateralFactor * _collateralTokenPrice) /
(MAX_BPS * (10 ** IERC20Metadata(address(collateralToken)).decimals()));
uint256 _maxBorrowPossible = (_actualCollateralForBorrow *
(10 ** IERC20Metadata(address(borrowToken)).decimals())) / _borrowTokenPrice;
if (_maxBorrowPossible == 0) {
return (0, _borrowed);
}
uint256 _borrowUpperBound = (_maxBorrowPossible * maxBorrowLimit) / MAX_BPS;
uint256 _borrowLowerBound = (_maxBorrowPossible * minBorrowLimit) / MAX_BPS;
if (_borrowed > _borrowUpperBound) {
_repayAmount = _borrowed - _borrowLowerBound;
} else if (_borrowLowerBound > _borrowed) {
_borrowAmount = _borrowLowerBound - _borrowed;
uint256 _availableLiquidity = IERC20(borrowToken).balanceOf(aBorrowToken);
if (_borrowAmount > _availableLiquidity) {
_borrowAmount = _availableLiquidity;
}
}
}
function _claimRewards() internal override returns (address, uint256) {
return (AAVE, _claimAave());
}
function _deposit() internal {
uint256 _collateralBalance = collateralToken.balanceOf(address(this));
(uint256 _borrowAmount, uint256 _repayAmount) = _calculateBorrowPosition(_collateralBalance, 0);
if (_repayAmount > 0) {
_repayY(_repayAmount);
_mint(_collateralBalance);
} else {
_mint(_collateralBalance);
_borrowY(_borrowAmount);
}
}
function _getInvestedBorrowBalance() internal view virtual returns (uint256) {
return IERC20(borrowToken).balanceOf(address(this));
}
function _mint(uint256 _amount) internal virtual {
_deposit(address(collateralToken), _amount);
}
function _rebalance() internal override returns (uint256 _profit, uint256 _loss, uint256 _payback) {
uint256 _excessDebt = IVesperPool(pool).excessDebt(address(this));
uint256 _totalDebt = IVesperPool(pool).totalDebtOf(address(this));
uint256 _borrow = vdToken.balanceOf(address(this));
uint256 _investedBorrowBalance = _getInvestedBorrowBalance();
if (_borrow > _investedBorrowBalance) {
_swapToBorrowToken(_borrow - _investedBorrowBalance);
} else {
_rebalanceBorrow(_investedBorrowBalance - _borrow);
}
uint256 _supply = aToken.balanceOf(address(this));
uint256 _collateralHere = collateralToken.balanceOf(address(this));
uint256 _totalCollateral = _supply + _collateralHere;
if (_totalCollateral > _totalDebt) {
_profit = _totalCollateral - _totalDebt;
} else {
_loss = _totalDebt - _totalCollateral;
}
uint256 _profitAndExcessDebt = _profit + _excessDebt;
if (_collateralHere < _profitAndExcessDebt) {
uint256 _totalAmountToWithdraw = Math.min((_profitAndExcessDebt - _collateralHere), _supply);
if (_totalAmountToWithdraw > 0) {
_withdrawHere(_totalAmountToWithdraw);
_collateralHere = collateralToken.balanceOf(address(this));
}
}
_payback = Math.min(_collateralHere, _excessDebt);
_profit = _collateralHere > _payback ? Math.min((_collateralHere - _payback), _profit) : 0;
IVesperPool(pool).reportEarning(_profit, _loss, _payback);
_deposit();
}
function _rebalanceBorrow(uint256 _excessBorrow) internal virtual {}
function _redeemX(uint256 _amount) internal virtual {
_safeWithdraw(address(collateralToken), address(this), _amount);
}
function _repayY(uint256 _amount) internal virtual {
_beforeRepayY(_amount);
aaveLendingPool.repay(borrowToken, _amount, 2, address(this));
}
function _swapToBorrowToken(uint256 _shortOnBorrow) internal {
uint256 _amountIn = swapper.getAmountIn(address(collateralToken), borrowToken, _shortOnBorrow);
if (_amountIn > 0) {
uint256 _collateralHere = collateralToken.balanceOf(address(this));
if (_amountIn > _collateralHere) {
_redeemX(_amountIn - _collateralHere);
}
swapper.swapExactOutput(address(collateralToken), borrowToken, _shortOnBorrow, _amountIn, address(this));
}
}
function _withdrawHere(uint256 _requireAmount) internal override {
(, uint256 _repayAmount) = _calculateBorrowPosition(0, _requireAmount);
if (_repayAmount > 0) {
_repayY(_repayAmount);
}
_redeemX(_requireAmount);
}
function updateBorrowLimit(uint256 _minBorrowLimit, uint256 _maxBorrowLimit) external onlyGovernor {
require(_maxBorrowLimit < MAX_BPS, "invalid-max-borrow-limit");
require(
(_maxBorrowLimit == 0 && _minBorrowLimit == 0) || _maxBorrowLimit > _minBorrowLimit,
"max-should-be-higher-than-min"
);
emit UpdatedBorrowLimit(minBorrowLimit, _minBorrowLimit, maxBorrowLimit, _maxBorrowLimit);
minBorrowLimit = _minBorrowLimit;
maxBorrowLimit = _maxBorrowLimit;
}
}
文件 4 的 20:Address.sol
pragma solidity ^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);
}
}
}
}
文件 5 的 20:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
this;
return msg.data;
}
}
文件 6 的 20:EnumerableSet.sol
pragma solidity ^0.8.0;
library EnumerableSet {
struct Set {
bytes32[] _values;
mapping(bytes32 => uint256) _indexes;
}
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
function _remove(Set storage set, bytes32 value) private returns (bool) {
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastvalue = set._values[lastIndex];
set._values[toDeleteIndex] = lastvalue;
set._indexes[lastvalue] = valueIndex;
}
set._values.pop();
delete set._indexes[value];
return true;
} else {
return false;
}
}
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
struct Bytes32Set {
Set _inner;
}
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
struct AddressSet {
Set _inner;
}
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
struct UintSet {
Set _inner;
}
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
文件 7 的 20:Errors.sol
pragma solidity 0.8.9;
library Errors {
string public constant INVALID_COLLATERAL_AMOUNT = "1";
string public constant INVALID_SHARE_AMOUNT = "2";
string public constant INVALID_INPUT_LENGTH = "3";
string public constant INPUT_LENGTH_MISMATCH = "4";
string public constant NOT_WHITELISTED_ADDRESS = "5";
string public constant MULTI_TRANSFER_FAILED = "6";
string public constant FEE_COLLECTOR_NOT_SET = "7";
string public constant NOT_ALLOWED_TO_SWEEP = "8";
string public constant INSUFFICIENT_BALANCE = "9";
string public constant INPUT_ADDRESS_IS_ZERO = "10";
string public constant FEE_LIMIT_REACHED = "11";
string public constant ALREADY_INITIALIZED = "12";
string public constant ADD_IN_LIST_FAILED = "13";
string public constant REMOVE_FROM_LIST_FAILED = "14";
string public constant STRATEGY_IS_ACTIVE = "15";
string public constant STRATEGY_IS_NOT_ACTIVE = "16";
string public constant INVALID_STRATEGY = "17";
string public constant DEBT_RATIO_LIMIT_REACHED = "18";
string public constant TOTAL_DEBT_IS_NOT_ZERO = "19";
string public constant LOSS_TOO_HIGH = "20";
string public constant INVALID_MAX_BORROW_LIMIT = "21";
string public constant MAX_LIMIT_LESS_THAN_MIN = "22";
string public constant INVALID_SLIPPAGE = "23";
string public constant WRONG_RECEIPT_TOKEN = "24";
string public constant AAVE_FLASH_LOAN_NOT_ACTIVE = "25";
string public constant DYDX_FLASH_LOAN_NOT_ACTIVE = "26";
string public constant INVALID_FLASH_LOAN = "27";
string public constant INVALID_INITIATOR = "28";
string public constant INCORRECT_WITHDRAW_AMOUNT = "29";
string public constant NO_MARKET_ID_FOUND = "30";
string public constant SAME_AS_PREVIOUS = "31";
string public constant INVALID_INPUT = "32";
}
文件 8 的 20:IAave.sol
pragma solidity 0.8.9;
import "vesper-pools/contracts/dependencies/openzeppelin/contracts/token/ERC20/IERC20.sol";
interface PoolAddressesProviderV3 {
function getPool() external view returns (AaveLendingPool);
function getPoolDataProvider() external view returns (AaveProtocolDataProvider);
}
interface PoolAddressesProvider {
function getPool() external view returns (address);
function getLendingPool() external view returns (address);
function getPoolDataProvider() external view returns (address);
function getAddress(bytes32 id) external view returns (address);
function getPriceOracle() external view returns (address);
}
interface AaveOracle {
function getAssetPrice(address _asset) external view returns (uint256);
}
interface AToken is IERC20 {
function getIncentivesController() external view returns (address);
function mint(address user, uint256 amount, uint256 index) external returns (bool);
function burn(address user, address receiverOfUnderlying, uint256 amount, uint256 index) external;
function UNDERLYING_ASSET_ADDRESS() external view returns (address);
}
interface AaveIncentivesController {
function getRewardsBalance(address[] calldata assets, address user) external view returns (uint256);
function claimRewards(address[] calldata assets, uint256 amount, address to) external returns (uint256);
function claimAllRewards(
address[] calldata assets,
address to
) external returns (address[] memory rewardsList, uint256[] memory claimedAmounts);
function getRewardsList() external view returns (address[] memory);
}
interface AaveLendingPool {
function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
function withdraw(address asset, uint256 amount, address to) external returns (uint256);
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata interestRateModes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
function borrow(
address asset,
uint256 amount,
uint256 interestRateMode,
uint16 referralCode,
address onBehalfOf
) external;
function repay(address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf) external;
function getUserAccountData(
address _user
)
external
view
returns (
uint256 totalCollateralETH,
uint256 totalDebtETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
}
interface AaveProtocolDataProvider {
function getReserveTokensAddresses(
address asset
) external view returns (address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress);
function getReserveData(
address asset
)
external
view
returns (
uint256 availableLiquidity,
uint256 totalStableDebt,
uint256 totalVariableDebt,
uint256 liquidityRate,
uint256 variableBorrowRate,
uint256 stableBorrowRate,
uint256 averageStableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex,
uint40 lastUpdateTimestamp
);
function getReserveConfigurationData(
address asset
)
external
view
returns (
uint256 decimals,
uint256 ltv,
uint256 liquidationThreshold,
uint256 liquidationBonus,
uint256 reserveFactor,
bool usageAsCollateralEnabled,
bool borrowingEnabled,
bool stableBorrowRateEnabled,
bool isActive,
bool isFrozen
);
}
interface StakedAave is IERC20 {
function claimRewards(address to, uint256 amount) external;
function cooldown() external;
function stake(address onBehalfOf, uint256 amount) external;
function redeem(address to, uint256 amount) external;
function getTotalRewardsBalance(address staker) external view returns (uint256);
function stakersCooldowns(address staker) external view returns (uint256);
function COOLDOWN_SECONDS() external view returns (uint256);
function UNSTAKE_WINDOW() external view returns (uint256);
}
文件 9 的 20:IERC20.sol
pragma solidity ^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);
}
文件 10 的 20:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 11 的 20:IGovernable.sol
pragma solidity 0.8.9;
interface IGovernable {
function governor() external view returns (address _governor);
function transferGovernorship(address _proposedGovernor) external;
}
文件 12 的 20:IPausable.sol
pragma solidity 0.8.9;
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;
}
文件 13 的 20:IPoolRewards.sol
pragma solidity 0.8.9;
interface IPoolRewards {
event RewardAdded(address indexed rewardToken, uint256 reward, uint256 rewardDuration);
event RewardPaid(address indexed user, address indexed rewardToken, uint256 reward);
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);
function getRewardTokens() external view returns (address[] memory);
function isRewardToken(address) external view returns (bool);
function addRewardToken(address newRewardToken_) external;
function periodFinish(address) external view returns (uint256);
}
文件 14 的 20:IRoutedSwapper.sol
pragma solidity 0.8.9;
interface IRoutedSwapper {
function getAllExchanges() external view returns (address[] memory);
function getAmountIn(address tokenIn_, address tokenOut_, uint256 amountOut_) external returns (uint256 _amountIn);
function getAmountOut(address tokenIn_, address tokenOut_, uint256 amountIn_) external returns (uint256 _amountOut);
function swapExactInput(
address tokenIn_,
address tokenOut_,
uint256 amountIn_,
uint256 amountOutMin_,
address _receiver
) external returns (uint256 _amountOut);
function swapExactOutput(
address tokenIn_,
address tokenOut_,
uint256 amountOut_,
uint256 amountInMax_,
address receiver_
) external returns (uint256 _amountIn);
}
文件 15 的 20:IStrategy.sol
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);
function VERSION() external view returns (string memory);
function collateral() external view returns (address);
}
文件 16 的 20:IVesperPool.sol
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,
uint256 _debtRate,
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);
}
文件 17 的 20:Math.sol
pragma solidity ^0.8.0;
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
文件 18 的 20:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
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));
}
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) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function _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");
}
}
}
文件 19 的 20:Strategy.sol
pragma solidity 0.8.9;
import "vesper-pools/contracts/interfaces/vesper/IVesperPool.sol";
import "vesper-pools/contracts/dependencies/openzeppelin/contracts/token/ERC20/IERC20.sol";
import "vesper-pools/contracts/dependencies/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "vesper-pools/contracts/dependencies/openzeppelin/contracts/utils/Context.sol";
import "vesper-pools/contracts/dependencies/openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "vesper-pools/contracts/dependencies/openzeppelin/contracts/utils/math/Math.sol";
import "vesper-commons/contracts/interfaces/vesper/IStrategy.sol";
import "../interfaces/swapper/IRoutedSwapper.sol";
abstract contract Strategy is IStrategy, Context {
using SafeERC20 for IERC20;
using EnumerableSet for EnumerableSet.AddressSet;
IERC20 public immutable collateralToken;
address public receiptToken;
address public immutable override pool;
address public override feeCollector;
IRoutedSwapper public swapper;
address internal constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
uint256 internal constant MAX_UINT_VALUE = type(uint256).max;
EnumerableSet.AddressSet private _keepers;
event UpdatedFeeCollector(address indexed previousFeeCollector, address indexed newFeeCollector);
event UpdatedSwapper(IRoutedSwapper indexed oldSwapper, IRoutedSwapper indexed newSwapper);
constructor(address _pool, address _swapper, address _receiptToken) {
require(_pool != address(0), "pool-address-is-zero");
require(_swapper != address(0), "swapper-address-is-zero");
swapper = IRoutedSwapper(_swapper);
pool = _pool;
collateralToken = IVesperPool(_pool).token();
receiptToken = _receiptToken;
require(_keepers.add(_msgSender()), "add-keeper-failed");
}
modifier onlyGovernor() {
require(_msgSender() == IVesperPool(pool).governor(), "caller-is-not-the-governor");
_;
}
modifier onlyKeeper() {
require(_keepers.contains(_msgSender()), "caller-is-not-a-keeper");
_;
}
modifier onlyPool() {
require(_msgSender() == pool, "caller-is-not-vesper-pool");
_;
}
function addKeeper(address _keeperAddress) external onlyGovernor {
require(_keepers.add(_keeperAddress), "add-keeper-failed");
}
function approveToken(uint256 _approvalAmount) external onlyKeeper {
_approveToken(_approvalAmount);
}
function claimAndSwapRewards(uint256 _minAmountOut) external onlyKeeper returns (uint256 _amountOut) {
uint256 _collateralBefore = collateralToken.balanceOf(address(this));
_claimAndSwapRewards();
_amountOut = collateralToken.balanceOf(address(this)) - _collateralBefore;
require(_amountOut >= _minAmountOut, "not-enough-amountOut");
}
function isReservedToken(address _token) public view virtual override returns (bool);
function keepers() external view override returns (address[] memory) {
return _keepers.values();
}
function migrate(address _newStrategy) external virtual override onlyPool {
require(_newStrategy != address(0), "new-strategy-address-is-zero");
require(IStrategy(_newStrategy).pool() == pool, "not-valid-new-strategy");
_beforeMigration(_newStrategy);
IERC20(receiptToken).safeTransfer(_newStrategy, IERC20(receiptToken).balanceOf(address(this)));
collateralToken.safeTransfer(_newStrategy, collateralToken.balanceOf(address(this)));
}
function rebalance() external onlyKeeper returns (uint256 _profit, uint256 _loss, uint256 _payback) {
return _rebalance();
}
function removeKeeper(address _keeperAddress) external onlyGovernor {
require(_keepers.remove(_keeperAddress), "remove-keeper-failed");
}
function swapToCollateral(IERC20 _tokenIn, uint256 _minAmountOut) external onlyKeeper returns (uint256 _amountOut) {
require(address(_tokenIn) != address(collateralToken), "not-allowed-to-sweep-collateral");
require(!isReservedToken(address(_tokenIn)), "not-allowed-to-sweep");
uint256 _collateralBefore = collateralToken.balanceOf(address(this));
uint256 _amountIn = _tokenIn.balanceOf(address(this));
if (_amountIn > 0) {
if (_amountIn > _tokenIn.allowance(address(this), address(swapper))) {
_tokenIn.safeApprove(address(swapper), 0);
_tokenIn.safeApprove(address(swapper), MAX_UINT_VALUE);
}
_swapExactInput(address(_tokenIn), address(collateralToken), _amountIn);
}
_amountOut = collateralToken.balanceOf(address(this)) - _collateralBefore;
require(_amountOut >= _minAmountOut, "not-enough-amountOut");
}
function sweep(address _fromToken) external override onlyKeeper {
require(feeCollector != address(0), "fee-collector-not-set");
require(_fromToken != address(collateralToken), "not-allowed-to-sweep-collateral");
require(!isReservedToken(_fromToken), "not-allowed-to-sweep");
if (_fromToken == ETH) {
Address.sendValue(payable(feeCollector), address(this).balance);
} else {
uint256 _amount = IERC20(_fromToken).balanceOf(address(this));
IERC20(_fromToken).safeTransfer(feeCollector, _amount);
}
}
function token() external view override returns (address) {
return receiptToken;
}
function collateral() external view override returns (address) {
return address(collateralToken);
}
function tvl() external view virtual returns (uint256);
function updateFeeCollector(address _feeCollector) external onlyGovernor {
require(_feeCollector != address(0), "fee-collector-address-is-zero");
require(_feeCollector != feeCollector, "fee-collector-is-same");
emit UpdatedFeeCollector(feeCollector, _feeCollector);
feeCollector = _feeCollector;
}
function updateSwapper(IRoutedSwapper _swapper) external onlyGovernor {
require(address(_swapper) != address(0), "swapper-address-is-zero");
require(_swapper != swapper, "swapper-is-same");
emit UpdatedSwapper(swapper, _swapper);
swapper = _swapper;
}
function withdraw(uint256 _amount) external override onlyPool {
uint256 _collateralHere = collateralToken.balanceOf(address(this));
if (_collateralHere >= _amount) {
collateralToken.safeTransfer(pool, _amount);
} else {
_withdrawHere(_amount - _collateralHere);
_collateralHere = collateralToken.balanceOf(address(this));
collateralToken.safeTransfer(pool, Math.min(_amount, _collateralHere));
}
}
function _approveToken(uint256 _amount) internal virtual {
collateralToken.safeApprove(pool, _amount);
}
function _beforeMigration(address _newStrategy) internal virtual;
function _claimAndSwapRewards() internal virtual {
(address _rewardToken, uint256 _rewardsAmount) = _claimRewards();
if (_rewardsAmount > 0) {
_safeSwapExactInput(_rewardToken, address(collateralToken), _rewardsAmount);
}
}
function _claimRewards() internal virtual returns (address, uint256) {}
function _rebalance() internal virtual returns (uint256 _profit, uint256 _loss, uint256 _payback);
function _swapExactInput(
address _tokenIn,
address _tokenOut,
uint256 _amountIn
) internal returns (uint256 _amountOut) {
_amountOut = swapper.swapExactInput(_tokenIn, _tokenOut, _amountIn, 1, address(this));
}
function _safeSwapExactInput(address _tokenIn, address _tokenOut, uint256 _amountIn) internal {
try swapper.swapExactInput(_tokenIn, _tokenOut, _amountIn, 1, address(this)) {} catch {}
}
function _withdrawHere(uint256 _amount) internal virtual;
}
文件 20 的 20:VesperRewards.sol
pragma solidity 0.8.9;
import "vesper-commons/contracts/interfaces/vesper/IStrategy.sol";
import "vesper-pools/contracts/interfaces/vesper/IVesperPool.sol";
import "vesper-pools/contracts/interfaces/vesper/IPoolRewards.sol";
import "vesper-pools/contracts/dependencies/openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/swapper/IRoutedSwapper.sol";
library VesperRewards {
using SafeERC20 for IERC20;
function _approveToken(IVesperPool vPool_, IRoutedSwapper swapper_, uint256 amount_) internal {
address _poolRewards = vPool_.poolRewards();
if (_poolRewards != address(0)) {
address[] memory _rewardTokens = IPoolRewards(_poolRewards).getRewardTokens();
uint256 _length = _rewardTokens.length;
for (uint256 i; i < _length; ++i) {
if (IERC20(_rewardTokens[i]).allowance(address(this), address(swapper_)) == 0) {
IERC20(_rewardTokens[i]).safeApprove(address(swapper_), amount_);
} else {
IERC20(_rewardTokens[i]).safeApprove(address(swapper_), 0);
IERC20(_rewardTokens[i]).safeApprove(address(swapper_), amount_);
}
}
}
}
function _claimAndSwapRewards(IVesperPool vPool_, IRoutedSwapper swapper_, address collateralToken_) internal {
address _poolRewards = vPool_.poolRewards();
if (_poolRewards != address(0)) {
IPoolRewards(_poolRewards).claimReward(address(this));
address[] memory _rewardTokens = IPoolRewards(_poolRewards).getRewardTokens();
uint256 _length = _rewardTokens.length;
for (uint256 i; i < _length; ++i) {
uint256 _rewardAmount = IERC20(_rewardTokens[i]).balanceOf(address(this));
if (_rewardAmount > 0 && _rewardTokens[i] != collateralToken_) {
try
swapper_.swapExactInput(_rewardTokens[i], collateralToken_, _rewardAmount, 1, address(this))
{} catch {}
}
}
}
}
}
{
"compilationTarget": {
"vesper-strategies/contracts/strategies/aave/v2/AaveV2VesperXy.sol": "AaveV2VesperXy"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 500
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_pool","type":"address"},{"internalType":"address","name":"_swapper","type":"address"},{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"address","name":"_receiptToken","type":"address"},{"internalType":"address","name":"_borrowToken","type":"address"},{"internalType":"address","name":"_vPool","type":"address"},{"internalType":"string","name":"_name","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"previousMinBorrowLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMinBorrowLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"previousMaxBorrowLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMaxBorrowLimit","type":"uint256"}],"name":"UpdatedBorrowLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousFeeCollector","type":"address"},{"indexed":true,"internalType":"address","name":"newFeeCollector","type":"address"}],"name":"UpdatedFeeCollector","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IRoutedSwapper","name":"oldSwapper","type":"address"},{"indexed":true,"internalType":"contract IRoutedSwapper","name":"newSwapper","type":"address"}],"name":"UpdatedSwapper","type":"event"},{"inputs":[],"name":"AAVE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"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":"aaveIncentivesController","outputs":[{"internalType":"contract AaveIncentivesController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aaveLendingPool","outputs":[{"internalType":"contract AaveLendingPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aaveProtocolDataProvider","outputs":[{"internalType":"contract AaveProtocolDataProvider","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_keeperAddress","type":"address"}],"name":"addKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_approvalAmount","type":"uint256"}],"name":"approveToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"canStartCooldown","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"canUnstake","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minAmountOut","type":"uint256"}],"name":"claimAndSwapRewards","outputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"collateral","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"collateralToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cooldownData","outputs":[{"internalType":"uint256","name":"_cooldownStart","type":"uint256"},{"internalType":"uint256","name":"_cooldownEnd","type":"uint256"},{"internalType":"uint256","name":"_unstakeEnd","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"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":"keepers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxBorrowLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newStrategy","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"minBorrowLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pool","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalance","outputs":[{"internalType":"uint256","name":"_profit","type":"uint256"},{"internalType":"uint256","name":"_loss","type":"uint256"},{"internalType":"uint256","name":"_payback","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"receiptToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_keeperAddress","type":"address"}],"name":"removeKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stkAAVE","outputs":[{"internalType":"contract StakedAave","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_tokenIn","type":"address"},{"internalType":"uint256","name":"_minAmountOut","type":"uint256"}],"name":"swapToCollateral","outputs":[{"internalType":"uint256","name":"_amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapper","outputs":[{"internalType":"contract IRoutedSwapper","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_fromToken","type":"address"}],"name":"sweep","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tvl","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minBorrowLimit","type":"uint256"},{"internalType":"uint256","name":"_maxBorrowLimit","type":"uint256"}],"name":"updateBorrowLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeCollector","type":"address"}],"name":"updateFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRoutedSwapper","name":"_swapper","type":"address"}],"name":"updateSwapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vPool","outputs":[{"internalType":"contract IVesperPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vdToken","outputs":[{"internalType":"contract AToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]