-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathyDAIVault.sol
203 lines (184 loc) · 6.91 KB
/
yDAIVault.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/**
*Submitted for verification at Etherscan.io on 2020-08-13
*/
pragma solidity ^0.5.16;
import "./common.sol";
// DAI保险库合约 0xACd43E627e64355f1861cEC6d3a6688B31a6F952
contract yVault is ERC20, ERC20Detailed {
using SafeERC20 for IERC20;
using Address for address;
using SafeMath for uint256;
// Dai Stablecoin (DAI)
IERC20 public token; // 0x6B175474E89094C44Da98b954EedeAC495271d0F
// 最小值 / 最大值 = 95%
uint256 public min = 9500;
uint256 public constant max = 10000;
// 治理地址
address public governance; // 0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52 proxy
// 控制器合约
address public controller; // 0x9e65ad11b299ca0abefc2799ddb6314ef2d91080
/**
* @dev 构造函数
* @param _token 基础资产Dai
* @param _controller 控制器
*/
constructor(address _token, address _controller)
public
// 用编码的方法将原来token的名字和缩写加上前缀
ERC20Detailed(
string(abi.encodePacked("yearn ", ERC20Detailed(_token).name())),
string(abi.encodePacked("y", ERC20Detailed(_token).symbol())),
ERC20Detailed(_token).decimals()
)
{
token = IERC20(_token);
governance = msg.sender;
controller = _controller;
}
/// @notice 当前合约在DAI的余额,加上控制器中当前合约的余额
function balance() public view returns (uint256) {
return
token.balanceOf(address(this)).add(
Controller(controller).balanceOf(address(token))
);
}
/// @notice 设置最小值
function setMin(uint256 _min) external {
require(msg.sender == governance, "!governance");
min = _min;
}
/// @notice 设置治理账号
function setGovernance(address _governance) public {
require(msg.sender == governance, "!governance");
governance = _governance;
}
/// @notice 设置控制器
function setController(address _controller) public {
require(msg.sender == governance, "!governance");
controller = _controller;
}
/**
* @dev 空闲余额
* @notice 当前合约在DAI的余额的95%
*/
// 此处的自定义逻辑用于允许借用保险库的数量
// 设置最低要求,以保持小额取款便宜
// Custom logic in here for how much the vault allows to be borrowed
// Sets minimum required on-hand to keep small withdrawals cheap
function available() public view returns (uint256) {
// 当前合约在DAI的余额 * 95%
return token.balanceOf(address(this)).mul(min).div(max);
}
/**
* @dev 赚钱方法
* @notice 将空闲余额发送到控制器,再调用控制器的赚钱方法
*/
function earn() public {
// 空闲余额
uint256 _bal = available();
// 发送到控制器合约
token.safeTransfer(controller, _bal);
// 调用控制器合约的赚钱方法
Controller(controller).earn(address(token), _bal);
}
/**
* @dev 存款全部方法
* @notice 将当前用户的全部DAI发送到存款方法
*/
function depositAll() external {
deposit(token.balanceOf(msg.sender));
}
/**
* @dev 存款方法
* @param _amount 存款数额
* @notice 当前合约在DAI的余额发送到当前合约,并铸造份额币
*/
function deposit(uint256 _amount) public {
// 池子数量 = 当前合约和控制器合约在DAI的余额
uint256 _pool = balance();
// 之前 = 当前合约在DAI合约的余额
uint256 _before = token.balanceOf(address(this));
// 将调用者的_amount数量的DAI发送到当前合约
token.safeTransferFrom(msg.sender, address(this), _amount);
// 之后 = 当前合约在DAI合约的余额
uint256 _after = token.balanceOf(address(this));
// 数额 = 之后 - 之前
_amount = _after.sub(_before); // Additional check for deflationary tokens
// 份额 = 0
uint256 shares = 0;
// 如果当前合约的总量为0
if (totalSupply() == 0) {
// 份额 = 数额
shares = _amount;
} else {
// 份额 = 数额 * 总量 / 池子数量
shares = (_amount.mul(totalSupply())).div(_pool);
}
// 为调用者铸造份额
_mint(msg.sender, shares);
}
/**
* @dev 提款全部方法
* @notice 将当前用户的份额发送到提款方法
*/
function withdrawAll() external {
withdraw(balanceOf(msg.sender));
}
/**
* @dev 收获方法
* @param reserve 收获的Token地址
* @param amount 收获数额
* @notice 将收获的Token发送到控制器合约
*/
// 用于将超出债务限额的所有借入准备金交换以清算为“代币”
// Used to swap any borrowed reserve over the debt limit to liquidate to 'token'
function harvest(address reserve, uint256 amount) external {
// 只能由控制器合约调用
require(msg.sender == controller, "!controller");
// 收获的资产不能是DAI
require(reserve != address(token), "token");
// 将收获资产发送到控制器合约
IERC20(reserve).safeTransfer(controller, amount);
}
/**
* @dev 提款方法
* @param _shares 份额数量
* @notice
*/
// 无需重新实施余额以降低费用并加快交换速度
// No rebalance implementation for lower fees and faster swaps
function withdraw(uint256 _shares) public {
// 当前合约和控制器合约在DAI的余额 * 份额 / 总量
uint256 r = (balance().mul(_shares)).div(totalSupply());
// 销毁份额
_burn(msg.sender, _shares);
// 检查余额
// Check balance
// 当前合约在DAI的余额
uint256 b = token.balanceOf(address(this));
// 如果余额 < 份额对应的余额
if (b < r) {
// 提款数额 = 份额对应的余额 - 余额
uint256 _withdraw = r.sub(b);
// 控制器的提款方法将DAI提款到当前合约
Controller(controller).withdraw(address(token), _withdraw);
// 之后 = 当前合约的DAI余额
uint256 _after = token.balanceOf(address(this));
// 区别 = 之后 - 份额对应的余额
uint256 _diff = _after.sub(b);
// 如果区别 < 提款数额
if (_diff < _withdraw) {
// 份额对应的余额 = 余额 + 区别
r = b.add(_diff);
}
}
// 将数量为份额对应的余额的DAI发送到调用者账户
token.safeTransfer(msg.sender, r);
}
/**
* @dev 获取每份基础资产对应的份额
*/
function getPricePerFullShare() public view returns (uint256) {
return balance().mul(1e18).div(totalSupply());
}
}