Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 2 additions & 20 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,20 +1,2 @@
ARBISCAN_API_KEY=''
BSCSCAN_API_KEY=''
ETHERSCAN_API_KEY=''
OPTIMISM_API_KEY=''
POLYGONSCAN_API_KEY=''
BASESCAN_API_KEY=''

ARBITRUM_RPC=''
ARB_GOERLI_RPC=''
ARB_SEPOLIA_RPC=''
OPTIMISM_RPC=''
OPTIMISM_GOERLI_RPC=''
OPTIMISM_SEPOLIA_RPC=''
POLYGON_RPC=''
POLYGON_MUMBAI_RPC=''
BSC_RPC=''
BSC_TESTNET_RPC=''
ETHEREUM_RPC=''
GOERLI_RPC=''
SEPOLIA_RPC=''
NETWORK=sepolia
SIGNER_KEY=00000
53 changes: 53 additions & 0 deletions contracts/AaveStrategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.20;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/IXERC20Lockbox.sol";
import "./interfaces/IStrategy.sol";
import "./interfaces/IAAVEPool.sol";

contract AaveStrategy is Initializable {
using SafeERC20 for IERC20;

address public aavePool;
IERC20 public token;
address public vault;

error NotAllow();

modifier onlyVault() {
if (msg.sender != vault) revert NotAllow();
_;
}

function initialize(address _aavePool, address _vault) public initializer {
aavePool = _aavePool;
token = IXERC20Lockbox(_vault).ERC20();
vault = _vault;
token.safeIncreaseAllowance(aavePool, type(uint256).max);
}

function withdraw(
uint256 amount_
) external onlyVault returns (uint256 loss_) {
return IAAVEPool(aavePool).withdraw(address(token), amount_, vault);
}

function withdrawAll() external onlyVault {
uint256 totalAsset = totalYieldAsset();
IAAVEPool(aavePool).withdraw(address(token), totalAsset, vault);
}

function totalYieldAsset() public view returns (uint256 totalAssets_) {
address aToken = IAAVEPool(aavePool)
.getReserveData(address(token))
.aTokenAddress;
return IERC20(aToken).balanceOf(address(this));
}

function invest(uint256 amount_) external onlyVault {
IAAVEPool(aavePool).supply(address(token), amount_, address(this), 0);
}
}
79 changes: 79 additions & 0 deletions contracts/ETHAaveStrategy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.20;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/IStrategy.sol";
import "./interfaces/IAAVEPool.sol";
import "./interfaces/IWETH.sol";
import "./interfaces/IwstETH.sol";
import "./interfaces/ILido.sol";
import "./interfaces/IXERC20Lockbox.sol";

contract ETHAaveStrategy is Initializable {
using SafeERC20 for IERC20;

address public immutable lido;
address public immutable wstETH;
address public immutable aavePool;
address public immutable vault;

error NotAllow();
error ErrorStrategy();

modifier onlyVault() {
if (msg.sender != vault) revert NotAllow();
_;
}

constructor(address _wstETH, address _aavePool, address _vault) {
bool isGasToken = IXERC20Lockbox(_vault).IS_GAS_TOKEN();
if (!isGasToken) revert ErrorStrategy();
aavePool = _aavePool;
vault = _vault;
wstETH = _wstETH;
lido = IwstETH(wstETH).stETH();
}

function initialize() public initializer {
IERC20(wstETH).safeIncreaseAllowance(aavePool, type(uint256).max);
}

function withdraw(
uint256 amount_
) public onlyVault returns (uint256 loss_) {
uint256 wstETHAmount = IwstETH(wstETH).getWstETHByStETH(amount_);
//1. AAVE -> wstETH
IAAVEPool(aavePool).withdraw(wstETH, wstETHAmount, address(this));
//2. wstETH -> stETH
IwstETH(wstETH).unwrap(wstETHAmount);
//3. transfer stETH to vault, since we can't withdraw stETH to ETH instantly
ILido(lido).transfer(vault, amount_);
return amount_;
}

function withdrawAll() external {
uint256 totalAsset = totalYieldAsset();
withdraw(totalAsset);
}

function totalYieldAsset() public view returns (uint256 totalAssets_) {
address aToken = IAAVEPool(aavePool)
.getReserveData(wstETH)
.aTokenAddress;
uint256 totalBalance = IERC20(aToken).balanceOf(address(this));
return IwstETH(wstETH).getStETHByWstETH(totalBalance);
}

function invest(uint256 amount_) external payable onlyVault {
//1. ETH -> stETH
ILido(lido).submit{value: amount_}(address(0));
//2. stETH -> wstETH
uint256 wstETHAmount = IwstETH(wstETH).wrap(amount_);
//3. wstETH -> AAVE
IAAVEPool(aavePool).supply(wstETH, wstETHAmount, address(this), 0);
}

receive() external payable {}
}
Loading