-
Notifications
You must be signed in to change notification settings - Fork 5
/
BaseRewardPool4626.sol
296 lines (257 loc) · 10.2 KB
/
BaseRewardPool4626.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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import { BaseRewardPool, IDeposit } from "./BaseRewardPool.sol";
import { IERC4626, IERC20Metadata } from "./interfaces/IERC4626.sol";
import { IERC20 } from "@openzeppelin/contracts-0.6/token/ERC20/IERC20.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts-0.6/utils/ReentrancyGuard.sol";
import { SafeERC20 } from "@openzeppelin/contracts-0.6/token/ERC20/SafeERC20.sol";
/**
* @title BaseRewardPool4626
* @notice Simply wraps the BaseRewardPool with the new IERC4626 Vault standard functions.
* @dev See https://github.com/fei-protocol/ERC4626/blob/main/src/interfaces/IERC4626.sol#L58
* This is not so much a vault as a Reward Pool, therefore asset:share ratio is always 1:1.
* To create most utility for this RewardPool, the "asset" has been made to be the crvLP token,
* as opposed to the cvxLP token. Therefore, users can easily deposit crvLP, and it will first
* go to the Booster and mint the cvxLP before performing the normal staking function.
*/
contract BaseRewardPool4626 is BaseRewardPool, ReentrancyGuard, IERC4626 {
using SafeERC20 for IERC20;
/**
* @notice The address of the underlying ERC20 token used for
* the Vault for accounting, depositing, and withdrawing.
*/
address public override asset;
mapping (address => mapping (address => uint256)) private _allowances;
/**
* @dev See BaseRewardPool.sol
*/
constructor(
uint256 pid_,
address stakingToken_,
address rewardToken_,
address operator_,
address rewardManager_,
address lptoken_
) public BaseRewardPool(pid_, stakingToken_, rewardToken_, operator_, rewardManager_) {
asset = lptoken_;
IERC20(asset).safeApprove(operator_, type(uint256).max);
}
/**
* @notice Total amount of the underlying asset that is "managed" by Vault.
*/
function totalAssets() external view virtual override returns(uint256){
return totalSupply();
}
/**
* @notice Mints `shares` Vault shares to `receiver`.
* @dev Because `asset` is not actually what is collected here, first wrap to required token in the booster.
*/
function deposit(uint256 assets, address receiver) public virtual override nonReentrant returns (uint256) {
// Transfer "asset" (crvLP) from sender
IERC20(asset).safeTransferFrom(msg.sender, address(this), assets);
// Convert crvLP to cvxLP through normal booster deposit process, but don't stake
uint256 balBefore = stakingToken.balanceOf(address(this));
IDeposit(operator).deposit(pid, assets, false);
uint256 balAfter = stakingToken.balanceOf(address(this));
require(balAfter - balBefore >= assets, "!deposit");
// Perform stake manually, now that the funds have been received
_processStake(assets, receiver);
emit Deposit(msg.sender, receiver, assets, assets);
emit Staked(receiver, assets);
return assets;
}
/**
* @notice Mints exactly `shares` Vault shares to `receiver`
* by depositing `assets` of underlying tokens.
*/
function mint(uint256 shares, address receiver) external virtual override returns (uint256) {
return deposit(shares, receiver);
}
/**
* @notice Redeems `shares` from `owner` and sends `assets`
* of underlying tokens to `receiver`.
*/
function withdraw(
uint256 assets,
address receiver,
address owner
) public virtual override nonReentrant returns (uint256) {
if (msg.sender != owner) {
_approve(owner, msg.sender, _allowances[owner][msg.sender].sub(assets, "ERC4626: withdrawal amount exceeds allowance"));
}
_withdrawAndUnwrapTo(assets, owner, receiver);
emit Withdraw(msg.sender, receiver, owner, assets, assets);
return assets;
}
/**
* @notice Redeems `shares` from `owner` and sends `assets`
* of underlying tokens to `receiver`.
*/
function redeem(
uint256 shares,
address receiver,
address owner
) external virtual override returns (uint256) {
return withdraw(shares, receiver, owner);
}
/**
* @notice The amount of shares that the vault would
* exchange for the amount of assets provided, in an
* ideal scenario where all the conditions are met.
*/
function convertToShares(uint256 assets) public view virtual override returns (uint256) {
return assets;
}
/**
* @notice The amount of assets that the vault would
* exchange for the amount of shares provided, in an
* ideal scenario where all the conditions are met.
*/
function convertToAssets(uint256 shares) public view virtual override returns (uint256) {
return shares;
}
/**
* @notice Total number of underlying assets that can
* be deposited by `owner` into the Vault, where `owner`
* corresponds to the input parameter `receiver` of a
* `deposit` call.
*/
function maxDeposit(address /* owner */) public view virtual override returns (uint256) {
return type(uint256).max;
}
/**
* @notice Allows an on-chain or off-chain user to simulate
* the effects of their deposit at the current block, given
* current on-chain conditions.
*/
function previewDeposit(uint256 assets) external view virtual override returns(uint256){
return convertToShares(assets);
}
/**
* @notice Total number of underlying shares that can be minted
* for `owner`, where `owner` corresponds to the input
* parameter `receiver` of a `mint` call.
*/
function maxMint(address owner) external view virtual override returns (uint256) {
return maxDeposit(owner);
}
/**
* @notice Allows an on-chain or off-chain user to simulate
* the effects of their mint at the current block, given
* current on-chain conditions.
*/
function previewMint(uint256 shares) external view virtual override returns(uint256){
return convertToAssets(shares);
}
/**
* @notice Total number of underlying assets that can be
* withdrawn from the Vault by `owner`, where `owner`
* corresponds to the input parameter of a `withdraw` call.
*/
function maxWithdraw(address owner) public view virtual override returns (uint256) {
return balanceOf(owner);
}
/**
* @notice Allows an on-chain or off-chain user to simulate
* the effects of their withdrawal at the current block,
* given current on-chain conditions.
*/
function previewWithdraw(uint256 assets) public view virtual override returns(uint256 shares){
return convertToShares(assets);
}
/**
* @notice Total number of underlying shares that can be
* redeemed from the Vault by `owner`, where `owner` corresponds
* to the input parameter of a `redeem` call.
*/
function maxRedeem(address owner) external view virtual override returns (uint256) {
return maxWithdraw(owner);
}
/**
* @notice Allows an on-chain or off-chain user to simulate
* the effects of their redeemption at the current block,
* given current on-chain conditions.
*/
function previewRedeem(uint256 shares) external view virtual override returns(uint256){
return previewWithdraw(shares);
}
/* ========== IERC20 ========== */
/**
* @dev Returns the name of the token.
*/
function name() external view override returns (string memory) {
return string(
abi.encodePacked(IERC20Metadata(address(stakingToken)).name(), " Vault")
);
}
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view override returns (string memory) {
return string(
abi.encodePacked(IERC20Metadata(address(stakingToken)).symbol(), "-vault")
);
}
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view override returns (uint8) {
return 18;
}
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() public view override(BaseRewardPool, IERC20) returns (uint256) {
return BaseRewardPool.totalSupply();
}
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) public view override(BaseRewardPool, IERC20) returns (uint256) {
return BaseRewardPool.balanceOf(account);
}
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address /* recipient */, uint256 /* amount */) external override returns (bool) {
revert("ERC4626: Not supported");
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(msg.sender, spender, amount);
return true;
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC4626: approve from the zero address");
require(spender != address(0), "ERC4626: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*/
function transferFrom(address /* sender */, address /* recipient */, uint256 /* amount */) external override returns (bool) {
revert("ERC4626: Not supported");
}
}