This repository has been archived by the owner on Nov 22, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 215
/
Copy pathyWETH.sol
172 lines (145 loc) · 5.67 KB
/
yWETH.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
pragma solidity ^0.5.17;
import "@openzeppelinV2/contracts/token/ERC20/IERC20.sol";
import "@openzeppelinV2/contracts/math/SafeMath.sol";
import "@openzeppelinV2/contracts/utils/Address.sol";
import "@openzeppelinV2/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelinV2/contracts/token/ERC20/ERC20.sol";
import "@openzeppelinV2/contracts/token/ERC20/ERC20Detailed.sol";
import "@openzeppelinV2/contracts/ownership/Ownable.sol";
import "../../interfaces/weth/WETH.sol";
import "../../interfaces/yearn/IController.sol";
// NOTE: The name of this contract was modified from yVault so as not to conflict with yVault.sol
contract yWETH is ERC20, ERC20Detailed {
using SafeERC20 for IERC20;
using Address for address;
using SafeMath for uint256;
IERC20 public token;
uint256 public min = 9990;
uint256 public constant max = 10000;
address public governance;
address public controller;
constructor(address _token, address _controller)
public
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;
}
function balance() public view returns (uint256) {
return token.balanceOf(address(this)).add(IController(controller).balanceOf(address(token)));
}
function setMin(uint256 _min) external {
require(msg.sender == governance, "!governance");
min = _min;
}
function setGovernance(address _governance) public {
require(msg.sender == governance, "!governance");
governance = _governance;
}
function setController(address _controller) public {
require(msg.sender == governance, "!governance");
controller = _controller;
}
// 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) {
return token.balanceOf(address(this)).mul(min).div(max);
}
function earn() public {
uint256 _bal = available();
token.safeTransfer(controller, _bal);
IController(controller).earn(address(token), _bal);
}
function depositAll() external {
deposit(token.balanceOf(msg.sender));
}
function deposit(uint256 _amount) public {
uint256 _pool = balance();
uint256 _before = token.balanceOf(address(this));
token.safeTransferFrom(msg.sender, address(this), _amount);
uint256 _after = token.balanceOf(address(this));
_amount = _after.sub(_before); // Additional check for deflationary tokens
uint256 shares = 0;
if (totalSupply() == 0) {
shares = _amount;
} else {
shares = (_amount.mul(totalSupply())).div(_pool);
}
_mint(msg.sender, shares);
}
function depositETH() public payable {
uint256 _pool = balance();
uint256 _before = token.balanceOf(address(this));
uint256 _amount = msg.value;
WETH(address(token)).deposit.value(_amount)();
uint256 _after = token.balanceOf(address(this));
_amount = _after.sub(_before); // Additional check for deflationary tokens
uint256 shares = 0;
if (totalSupply() == 0) {
shares = _amount;
} else {
shares = (_amount.mul(totalSupply())).div(_pool);
}
_mint(msg.sender, shares);
}
function withdrawAll() external {
withdraw(balanceOf(msg.sender));
}
function withdrawAllETH() external {
withdrawETH(balanceOf(msg.sender));
}
// 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");
require(reserve != address(token), "token");
IERC20(reserve).safeTransfer(controller, amount);
}
// No rebalance implementation for lower fees and faster swaps
function withdraw(uint256 _shares) public {
uint256 r = (balance().mul(_shares)).div(totalSupply());
_burn(msg.sender, _shares);
// Check balance
uint256 b = token.balanceOf(address(this));
if (b < r) {
uint256 _withdraw = r.sub(b);
IController(controller).withdraw(address(token), _withdraw);
uint256 _after = token.balanceOf(address(this));
uint256 _diff = _after.sub(b);
if (_diff < _withdraw) {
r = b.add(_diff);
}
}
token.safeTransfer(msg.sender, r);
}
// No rebalance implementation for lower fees and faster swaps
function withdrawETH(uint256 _shares) public {
uint256 r = (balance().mul(_shares)).div(totalSupply());
_burn(msg.sender, _shares);
// Check balance
uint256 b = token.balanceOf(address(this));
if (b < r) {
uint256 _withdraw = r.sub(b);
IController(controller).withdraw(address(token), _withdraw);
uint256 _after = token.balanceOf(address(this));
uint256 _diff = _after.sub(b);
if (_diff < _withdraw) {
r = b.add(_diff);
}
}
WETH(address(token)).withdraw(r);
address(msg.sender).transfer(r);
}
function getPricePerFullShare() public view returns (uint256) {
return balance().mul(1e18).div(totalSupply());
}
function() external payable {
if (msg.sender != address(token)) {
depositETH();
}
}
}