-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathLidoVault.sol
159 lines (140 loc) · 5 KB
/
LidoVault.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import {GeneralVault} from '../GeneralVault.sol';
import {IERC20} from '../../../dependencies/openzeppelin/contracts/IERC20.sol';
import {IWETH} from '../../../misc/interfaces/IWETH.sol';
import {Errors} from '../../libraries/helpers/Errors.sol';
import {TransferHelper} from '../../libraries/helpers/TransferHelper.sol';
import {SafeERC20} from '../../../dependencies/openzeppelin/contracts/SafeERC20.sol';
import {CurveswapAdapter} from '../../libraries/swap/CurveswapAdapter.sol';
/**
* @title LidoVault
* @notice stETH/ETH Vault by using Lido, Uniswap, Curve
* @author Sturdy
**/
contract LidoVault is GeneralVault {
using SafeERC20 for IERC20;
/**
* @dev Receive Ether
*/
receive() external payable {}
/**
* @dev Grab excess stETH which was from rebasing on Lido
* And convert stETH -> ETH -> asset, deposit to pool
*/
function processYield() external override onlyAdmin {
// Get yield from lendingPool
address LIDO = _addressesProvider.getAddress('LIDO');
uint256 yieldStETH = _getYield(LIDO);
// move yield to treasury
if (_vaultFee > 0) {
uint256 treasuryStETH = _processTreasury(yieldStETH);
yieldStETH = yieldStETH.sub(treasuryStETH);
}
// Exchange stETH -> ETH via Curve
uint256 receivedETHAmount = CurveswapAdapter.swapExactTokensForTokens(
_addressesProvider,
_addressesProvider.getAddress('STETH_ETH_POOL'),
LIDO,
ETH,
yieldStETH,
200
);
// ETH -> WETH
address weth = _addressesProvider.getAddress('WETH');
IWETH(weth).deposit{value: receivedETHAmount}();
// transfer WETH to yieldManager
address yieldManager = _addressesProvider.getAddress('YIELD_MANAGER');
TransferHelper.safeTransfer(weth, yieldManager, receivedETHAmount);
emit ProcessYield(_addressesProvider.getAddress('WETH'), receivedETHAmount);
}
/**
* @dev Get yield amount based on strategy
*/
function getYieldAmount() external view returns (uint256) {
return _getYieldAmount(_addressesProvider.getAddress('LIDO'));
}
/**
* @dev Get price per share based on yield strategy
*/
function pricePerShare() external view override returns (uint256) {
return 1e18;
}
/**
* @dev Deposit to yield pool based on strategy and receive stAsset
*/
function _depositToYieldPool(address _asset, uint256 _amount)
internal
override
returns (address, uint256)
{
address LIDO = _addressesProvider.getAddress('LIDO');
uint256 assetAmount = _amount;
if (_asset == address(0)) {
// Case of ETH deposit from user, user has to send ETH
require(msg.value > 0, Errors.VT_COLLATERAL_DEPOSIT_REQUIRE_ETH);
// Deposit ETH to Lido and receive stETH
(bool sent, bytes memory data) = LIDO.call{value: msg.value}('');
require(sent, Errors.VT_COLLATERAL_DEPOSIT_INVALID);
assetAmount = msg.value;
} else {
// Case of stETH deposit from user, receive stETH from user
require(_asset == LIDO, Errors.VT_COLLATERAL_DEPOSIT_INVALID);
IERC20(LIDO).safeTransferFrom(msg.sender, address(this), _amount);
}
// Make lendingPool to transfer required amount
IERC20(LIDO).safeApprove(address(_addressesProvider.getLendingPool()), assetAmount);
return (LIDO, assetAmount);
}
/**
* @dev Get Withdrawal amount of stAsset based on strategy
*/
function _getWithdrawalAmount(address _asset, uint256 _amount)
internal
view
override
returns (address, uint256)
{
// In this vault, return same amount of asset.
return (_addressesProvider.getAddress('LIDO'), _amount);
}
/**
* @dev Withdraw from yield pool based on strategy with stAsset and deliver asset
*/
function _withdrawFromYieldPool(
address _asset,
uint256 _amount,
address _to
) internal override returns (uint256) {
address LIDO = _addressesProvider.getAddress('LIDO');
if (_asset == address(0)) {
// Case of ETH withdraw request from user, so exchange stETH -> ETH via curve
uint256 receivedETHAmount = CurveswapAdapter.swapExactTokensForTokens(
_addressesProvider,
_addressesProvider.getAddress('STETH_ETH_POOL'),
LIDO,
ETH,
_amount,
200
);
// send ETH to user
(bool sent, bytes memory data) = address(_to).call{value: receivedETHAmount}('');
return receivedETHAmount;
require(sent, Errors.VT_COLLATERAL_WITHDRAW_INVALID);
} else {
// Case of stETH withdraw request from user, so directly send
require(_asset == LIDO, Errors.VT_COLLATERAL_WITHDRAW_INVALID);
IERC20(LIDO).safeTransfer(_to, _amount);
}
return _amount;
}
/**
* @dev Move some yield to treasury
*/
function _processTreasury(uint256 _yieldAmount) internal returns (uint256) {
uint256 treasuryAmount = _yieldAmount.percentMul(_vaultFee);
IERC20(_addressesProvider.getAddress('LIDO')).safeTransfer(_treasuryAddress, treasuryAmount);
return treasuryAmount;
}
}