// SPDX-License-Identifier: MITpragmasolidity >=0.6.2 <0.8.0;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @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
* ====
*/functionisContract(address account) internalviewreturns (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-assemblyassembly { 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].
*/functionsendValue(addresspayable 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._
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
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._
*/functionfunctionCall(address target, bytesmemory data, stringmemory errorMessage) internalreturns (bytesmemory) {
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._
*/functionfunctionCallWithValue(address target, bytesmemory data, uint256 value) internalreturns (bytesmemory) {
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._
*/functionfunctionCallWithValue(address target, bytesmemory data, uint256 value, stringmemory errorMessage) internalreturns (bytesmemory) {
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, bytesmemory 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._
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
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._
*/functionfunctionStaticCall(address target, bytesmemory data, stringmemory errorMessage) internalviewreturns (bytesmemory) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytesmemory 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._
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
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._
*/functionfunctionDelegateCall(address target, bytesmemory data, stringmemory errorMessage) internalreturns (bytesmemory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytesmemory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function_verifyCallResult(bool success, bytesmemory returndata, stringmemory errorMessage) privatepurereturns(bytesmemory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assembly// solhint-disable-next-line no-inline-assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: MITpragmasolidity >=0.6.0 <0.8.0;/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/interfaceIERC20{
/**
* @dev Returns the amount of tokens in existence.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/functionbalanceOf(address account) externalviewreturns (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.
*/functiontransfer(address recipient, uint256 amount) externalreturns (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.
*/functionallowance(address owner, address spender) externalviewreturns (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.
*/functionapprove(address spender, uint256 amount) externalreturns (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.
*/functiontransferFrom(address sender, address recipient, uint256 amount) externalreturns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/eventTransfer(addressindexedfrom, addressindexed 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.
*/eventApproval(addressindexed owner, addressindexed spender, uint256 value);
}
Contract Source Code
File 8 of 21: IPoolRewardsV3.sol
// SPDX-License-Identifier: MITpragmasolidity 0.6.12;interfaceIPoolRewardsV3{
/// Emitted after reward addedeventRewardAdded(uint256 reward);
/// Emitted whenever any user claim rewardseventRewardPaid(addressindexed user, uint256 reward);
/// Emitted when reward is endedeventRewardEnded(addressindexed dustReceiver, uint256 dust);
// Emitted when pool governor update reward end timeeventUpdatedRewardEndTime(uint256 previousRewardEndTime, uint256 newRewardEndTime);
functionclaimReward(address) external;
functionnotifyRewardAmount(uint256 rewardAmount, uint256 endTime) external;
functionupdateRewardEndTime() external;
functionupdateReward(address) external;
functionwithdrawRemaining(address _toAddress) external;
functionclaimable(address) externalviewreturns (uint256);
functionlastTimeRewardApplicable() externalviewreturns (uint256);
functionrewardForDuration() externalviewreturns (uint256);
functionrewardPerToken() externalviewreturns (uint256);
functionrewardToken() externalviewreturns (address);
}
// SPDX-License-Identifier: MITpragmasolidity 0.6.12;import"@openzeppelin/contracts/GSN/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
*/contractPausableisContext{
eventPaused(address account);
eventShutdown(address account);
eventUnpaused(address account);
eventOpen(address account);
boolpublic paused;
boolpublic stopEverything;
modifierwhenNotPaused() {
require(!paused, "Pausable: paused");
_;
}
modifierwhenPaused() {
require(paused, "Pausable: not paused");
_;
}
modifierwhenNotShutdown() {
require(!stopEverything, "Pausable: shutdown");
_;
}
modifierwhenShutdown() {
require(stopEverything, "Pausable: not shutdown");
_;
}
/// @dev Pause contract operations, if contract is not paused.function_pause() internalvirtualwhenNotPaused{
paused =true;
emit Paused(_msgSender());
}
/// @dev Unpause contract operations, allow only if contract is paused and not shutdown.function_unpause() internalvirtualwhenPausedwhenNotShutdown{
paused =false;
emit Unpaused(_msgSender());
}
/// @dev Shutdown contract operations, if not already shutdown.function_shutdown() internalvirtualwhenNotShutdown{
stopEverything =true;
paused =true;
emit Shutdown(_msgSender());
}
/// @dev Open contract operations, if contract is in shutdown statefunction_open() internalvirtualwhenShutdown{
stopEverything =false;
emit Open(_msgSender());
}
}
Contract Source Code
File 17 of 21: SafeERC20.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.0 <0.8.0;import"./IERC20.sol";
import"../../math/SafeMath.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.
*/librarySafeERC20{
usingSafeMathforuint256;
usingAddressforaddress;
functionsafeTransfer(IERC20 token, address to, uint256 value) internal{
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
functionsafeTransferFrom(IERC20 token, addressfrom, 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.
*/functionsafeApprove(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-lengthrequire((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));
}
functionsafeIncreaseAllowance(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));
}
functionsafeDecreaseAllowance(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));
}
/**
* @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, bytesmemory 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.bytesmemory returndata =address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length>0) { // Return data is optional// solhint-disable-next-line max-line-lengthrequire(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
Contract Source Code
File 18 of 21: SafeMath.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.6.0 <0.8.0;/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/librarySafeMath{
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/functiontryAdd(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/functiontrySub(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/functiontryMul(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the// benefit is lost if 'b' is also tested.// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522if (a ==0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/functiontryDiv(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
if (b ==0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/functiontryMod(uint256 a, uint256 b) internalpurereturns (bool, uint256) {
if (b ==0) return (false, 0);
return (true, a % b);
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/functionadd(uint256 a, uint256 b) internalpurereturns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/functionsub(uint256 a, uint256 b) internalpurereturns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/functionmul(uint256 a, uint256 b) internalpurereturns (uint256) {
if (a ==0) return0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/functiondiv(uint256 a, uint256 b) internalpurereturns (uint256) {
require(b >0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/functionmod(uint256 a, uint256 b) internalpurereturns (uint256) {
require(b >0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/functionsub(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/functiondiv(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (uint256) {
require(b >0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/functionmod(uint256 a, uint256 b, stringmemory errorMessage) internalpurereturns (uint256) {
require(b >0, errorMessage);
return a % b;
}
}
Contract Source Code
File 19 of 21: Strategy.sol
// SPDX-License-Identifier: MITpragmasolidity 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";
abstractcontractStrategyisIStrategy, Pausable{
usingSafeERC20forIERC20;
usingSafeMathforuint256;
// solhint-disable-next-line
ISwapManager public swapManager = ISwapManager(0xe382d9f2394A359B01006faa8A1864b8a60d2710);
IController publicimmutable controller;
IERC20 publicimmutable collateralToken;
addresspublicimmutable receiptToken;
addresspublicimmutableoverride pool;
IAddressListExt public keepers;
addressinternalconstant ETH =0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
addressinternalconstant WETH =0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
uint256internalconstant MAX_UINT_VALUE =type(uint256).max;
eventUpdatedSwapManager(addressindexed previousSwapManager, addressindexed 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;
}
modifieronlyAuthorized() {
require(
_msgSender() ==address(controller) || _msgSender() == pool,
"caller-is-not-authorized"
);
_;
}
modifieronlyController() {
require(_msgSender() ==address(controller), "caller-is-not-the-controller");
_;
}
modifieronlyKeeper() {
require(keepers.contains(_msgSender()), "caller-is-not-keeper");
_;
}
modifieronlyPool() {
require(_msgSender() == pool, "caller-is-not-the-pool");
_;
}
functionpause() externaloverrideonlyController{
_pause();
}
functionunpause() externaloverrideonlyController{
_unpause();
}
/// @dev Approve all required tokensfunctionapproveToken() externalonlyController{
_approveToken(0);
_approveToken(MAX_UINT_VALUE);
}
/// @dev Reset approval of all required tokensfunctionresetApproval() externalonlyController{
_approveToken(0);
}
/**
* @notice Create keeper list
* @dev Create keeper list
* NOTE: Any function with onlyKeeper modifier will not work until this function is called.
* NOTE: Due to gas constraint this function cannot be called in constructor.
*/functioncreateKeeperList() externalonlyController{
require(address(keepers) ==address(0), "keeper-list-already-created");
IAddressListFactory factory =
IAddressListFactory(0xD57b41649f822C51a73C44Ba0B3da4A880aF0029);
keepers = IAddressListExt(factory.createList());
keepers.grantRole(keccak256("LIST_ADMIN"), _msgSender());
}
/**
* @notice Update swap manager address
* @param _swapManager swap manager address
*/functionupdateSwapManager(address _swapManager) externalonlyController{
require(_swapManager !=address(0), "sm-address-is-zero");
require(_swapManager !=address(swapManager), "sm-is-same");
emit UpdatedSwapManager(address(swapManager), _swapManager);
swapManager = ISwapManager(_swapManager);
}
/**
* @dev Deposit collateral token into lending pool.
* @param _amount Amount of collateral token
*/functiondeposit(uint256 _amount) publicoverrideonlyKeeper{
_updatePendingFee();
_deposit(_amount);
}
/**
* @notice Deposit all collateral token from pool to other lending pool.
* Anyone can call it except when paused.
*/functiondepositAll() externalvirtualonlyKeeper{
deposit(collateralToken.balanceOf(pool));
}
/**
* @dev Withdraw collateral token from lending pool.
* @param _amount Amount of collateral token
*/functionwithdraw(uint256 _amount) externaloverrideonlyAuthorized{
_updatePendingFee();
_withdraw(_amount);
}
/**
* @dev Withdraw all collateral. No rebalance earning.
* Controller only function, called when migrating strategy.
*/functionwithdrawAll() externaloverrideonlyController{
_withdrawAll();
}
/**
* @dev sweep given token to vesper pool
* @param _fromToken token address to sweep
*/functionsweepErc20(address _fromToken) externalonlyKeeper{
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);
}
}
/// @dev Returns true if strategy can be upgraded.functionisUpgradable() externalviewvirtualoverridereturns (bool) {
return totalLocked() ==0;
}
/// @dev Returns address of token correspond to collateral tokenfunctiontoken() externalviewoverridereturns (address) {
return receiptToken;
}
/// @dev Convert from 18 decimals to token defined decimals. Default no conversion.functionconvertFrom18(uint256 amount) publicpurevirtualreturns (uint256) {
return amount;
}
/// @dev report the interest earned since last rebalancefunctioninterestEarned() externalviewvirtualreturns (uint256);
/// @dev Check whether given token is reserved or not. Reserved tokens are not allowed to sweep.functionisReservedToken(address _token) publicviewvirtualoverridereturns (bool);
/// @dev Returns total collateral locked herefunctiontotalLocked() publicviewvirtualoverridereturns (uint256);
/// @dev For moving between versions of similar strategiesfunctionmigrateIn() externalonlyController{
_migrateIn();
}
/// @dev For moving between versions of similar strategiesfunctionmigrateOut() externalonlyController{
_migrateOut();
}
/**
* @notice Handle earned interest fee
* @dev Earned interest fee will go to the fee collector. We want fee to be in form of Vepseer
* pool tokens not in collateral tokens so we will deposit fee in Vesper pool and send vTokens
* to fee collactor.
* @param _fee Earned interest fee in collateral token.
*/function_handleFee(uint256 _fee) internalvirtual{
if (_fee !=0) {
IVesperPool(pool).deposit(_fee);
uint256 _feeInVTokens = IERC20(pool).balanceOf(address(this));
IERC20(pool).safeTransfer(controller.feeCollector(pool), _feeInVTokens);
}
}
/**
* @notice Safe swap via Uniswap
* @dev There are many scenarios when token swap via Uniswap can fail, so this
* method will wrap Uniswap call in a 'try catch' to make it fail safe.
* @param _from address of from token
* @param _to address of to token
* @param _amount Amount to be swapped
*/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) internalvirtual;
function_withdraw(uint256 _amount) internalvirtual;
function_approveToken(uint256 _amount) internalvirtual;
function_updatePendingFee() internalvirtual;
function_withdrawAll() internalvirtual;
function_migrateIn() internalvirtual;
function_migrateOut() internalvirtual;
function_claimReward() internalvirtual;
}
Contract Source Code
File 20 of 21: VesperV3Strategy.sol
// SPDX-License-Identifier: MITpragmasolidity 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";
/// @title This strategy will deposit collateral token in VesperV3 and earn interest.abstractcontractVesperV3StrategyisStrategy{
usingSafeERC20forIERC20;
usingSafeMathforuint256;
IVesperPoolV3 internalimmutable vToken;
constructor(address _controller,
address _pool,
address _receiptToken
) publicStrategy(_controller, _pool, _receiptToken) {
vToken = IVesperPoolV3(_receiptToken);
}
/**
* @notice Migrate tokens from pool to this address
* @dev Any working VesperV3 strategy has vTokens in strategy contract.
* @dev There can be scenarios when pool already has vTokens and new
* strategy will have to move those tokens from pool to self address.
* @dev Only valid pool strategy is allowed to move tokens from pool.
*/function_migrateIn() internaloverride{
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));
}
/**
* @notice Migrate tokens out to pool.
* @dev There can be scenarios when we want to use new strategy without
* calling withdrawAll(). We can achieve this by moving tokens in pool
* and new strategy will take care from there.
* @dev Pause this strategy and move tokens out.
*/function_migrateOut() internaloverride{
require(controller.isPool(pool), "not-a-valid-pool");
_pause();
IERC20(vToken).safeTransfer(pool, vToken.balanceOf(address(this)));
}
/// @notice Vesper pools are using this function so it should exist in all strategies.//solhint-disable-next-line no-empty-blocksfunctionbeforeWithdraw() externaloverrideonlyPool{}
/**
* @dev Calculate interest fee on earning from VesperV3 and transfer fee to fee collector.
* Deposit available collateral from pool into VesperV3.
* Anyone can call it except when paused.
*/functionrebalance() externaloverridewhenNotPausedonlyKeeper{
_claimReward();
uint256 balance = collateralToken.balanceOf(pool);
if (balance !=0) {
_deposit(balance);
}
}
/**
* @notice Returns interest earned since last rebalance.
*/functioninterestEarned() publicviewoverridereturns (uint256 collateralEarned) {
// V3 Pool rewardToken can change over time so we don't store it in contractaddress _poolRewards = vToken.poolRewards();
if (_poolRewards !=address(0)) {
address _rewardToken = IPoolRewardsV3(_poolRewards).rewardToken();
uint256 _claimableRewards = IPoolRewardsV3(_poolRewards).claimable(address(this));
// if there's any reward earned we add that to collateralEarnedif (_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 = rewards + unrealizedGain proportional to v2 share in v3
collateralEarned = collateralEarned.add(
_unrealizedGain.mul(vToken.balanceOf(address(this))).div(vToken.totalSupply())
);
}
}
/// @notice Returns true if strategy can be upgraded./// @dev If there are no vTokens in strategy then it is upgradablefunctionisUpgradable() externalviewoverridereturns (bool) {
return vToken.balanceOf(address(this)) ==0;
}
/// @notice This method is deprecated and will be removed from Strategies in next releasefunctionisReservedToken(address _token) publicviewoverridereturns (bool) {
address _poolRewards = vToken.poolRewards();
return
_token ==address(vToken) ||
(_poolRewards !=address(0) && _token == IPoolRewardsV3(_poolRewards).rewardToken());
}
function_approveToken(uint256 _amount) internaloverride{
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);
}
}
}
/**
* @dev Converts rewardToken from V3 Pool to collateralToken
* @notice V3 Pools will claim rewardToken onbehalf of caller on every withdraw/deposit
*/function_claimReward() internaloverride{
// V3 Pool rewardToken can change over time so we don't store it in contractaddress _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);
}
}
/**
* @notice Total collateral locked in VesperV3.
* @return Return value will be in collateralToken defined decimal.
*/functiontotalLocked() publicviewoverridereturns (uint256) {
uint256 _totalVTokens = vToken.balanceOf(pool).add(vToken.balanceOf(address(this)));
return _convertToCollateral(_totalVTokens);
}
function_deposit(uint256 _amount) internalvirtualoverride{
collateralToken.safeTransferFrom(pool, address(this), _amount);
vToken.deposit(_amount);
}
function_withdraw(uint256 _amount) internaloverride{
_safeWithdraw(_convertToShares(_amount));
collateralToken.safeTransfer(pool, collateralToken.balanceOf(address(this)));
}
/**
* @dev V3 Pools may withdraw a partial amount of requested shares
* Resulting in more burnt shares than actual collateral in V2
* We make sure burnt shares equals to our expected value
*/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() internaloverride{
_safeWithdraw(vToken.balanceOf(address(this)));
_claimReward();
collateralToken.safeTransfer(pool, collateralToken.balanceOf(address(this)));
}
function_convertToCollateral(uint256 _vTokenAmount) internalviewreturns (uint256) {
uint256 _totalSupply = vToken.totalSupply();
// avoids division by zero error when pool is emptyreturn (_totalSupply !=0) ? vToken.totalValue().mul(_vTokenAmount).div(_totalSupply) : 0;
}
function_convertToShares(uint256 _collateralAmount) internalviewreturns (uint256) {
return _collateralAmount.mul(vToken.totalSupply()).div(vToken.totalValue());
}
/**
* @notice Returns interest earned since last rebalance.
* @dev Empty implementation because V3 Strategies should collect pending interest fee
*///solhint-disable-next-line no-empty-blocksfunction_updatePendingFee() internaloverride{}
}