-
Notifications
You must be signed in to change notification settings - Fork 156
/
Copy pathWAMPL.sol
287 lines (249 loc) · 10.7 KB
/
WAMPL.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
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.4;
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
// solhint-disable-next-line max-line-length
import {SafeERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
// solhint-disable-next-line max-line-length
import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol";
/**
* @title WAMPL (Wrapped AMPL).
*
* @dev A fixed-balance ERC-20 wrapper for the AMPL rebasing token.
*
* Users deposit AMPL into this contract and are minted wAMPL.
*
* Each account's wAMPL balance represents the fixed percentage ownership
* of AMPL's market cap.
*
* For example: 100K wAMPL => 1% of the AMPL market cap
* when the AMPL supply is 100M, 100K wAMPL will be redeemable for 1M AMPL
* when the AMPL supply is 500M, 100K wAMPL will be redeemable for 5M AMPL
* and so on.
*
* We call wAMPL the "wrapper" token and AMPL the "underlying" or "wrapped" token.
*/
contract WAMPL is ERC20Upgradeable, ERC20PermitUpgradeable {
using SafeERC20Upgradeable for IERC20Upgradeable;
//--------------------------------------------------------------------------
// Constants
/// @dev The maximum wAMPL supply.
uint256 public constant MAX_WAMPL_SUPPLY = 10000000 * (10**18); // 10 M
//--------------------------------------------------------------------------
// Attributes
/// @dev The reference to the AMPL token.
address private immutable _ampl;
//--------------------------------------------------------------------------
/// @notice Contract constructor.
/// @param ampl The AMPL ERC20 token address.
constructor(address ampl) {
_ampl = ampl;
}
/// @notice Contract state initialization.
/// @param name_ The wAMPL ERC20 name.
/// @param symbol_ The wAMPL ERC20 symbol.
function init(string memory name_, string memory symbol_) public initializer {
__ERC20_init(name_, symbol_);
__ERC20Permit_init(name_);
}
//--------------------------------------------------------------------------
// WAMPL write methods
/// @notice Transfers AMPLs from {msg.sender} and mints wAMPLs.
///
/// @param wamples The amount of wAMPLs to mint.
/// @return The amount of AMPLs deposited.
function mint(uint256 wamples) external returns (uint256) {
uint256 amples = _wampleToAmple(wamples, _queryAMPLSupply());
_deposit(_msgSender(), _msgSender(), amples, wamples);
return amples;
}
/// @notice Transfers AMPLs from {msg.sender} and mints wAMPLs,
/// to the specified beneficiary.
///
/// @param to The beneficiary wallet.
/// @param wamples The amount of wAMPLs to mint.
/// @return The amount of AMPLs deposited.
function mintFor(address to, uint256 wamples) external returns (uint256) {
uint256 amples = _wampleToAmple(wamples, _queryAMPLSupply());
_deposit(_msgSender(), to, amples, wamples);
return amples;
}
/// @notice Burns wAMPLs from {msg.sender} and transfers AMPLs back.
///
/// @param wamples The amount of wAMPLs to burn.
/// @return The amount of AMPLs withdrawn.
function burn(uint256 wamples) external returns (uint256) {
uint256 amples = _wampleToAmple(wamples, _queryAMPLSupply());
_withdraw(_msgSender(), _msgSender(), amples, wamples);
return amples;
}
/// @notice Burns wAMPLs from {msg.sender} and transfers AMPLs back,
/// to the specified beneficiary.
///
/// @param to The beneficiary wallet.
/// @param wamples The amount of wAMPLs to burn.
/// @return The amount of AMPLs withdrawn.
function burnTo(address to, uint256 wamples) external returns (uint256) {
uint256 amples = _wampleToAmple(wamples, _queryAMPLSupply());
_withdraw(_msgSender(), to, amples, wamples);
return amples;
}
/// @notice Burns all wAMPLs from {msg.sender} and transfers AMPLs back.
///
/// @return The amount of AMPLs withdrawn.
function burnAll() external returns (uint256) {
uint256 wamples = balanceOf(_msgSender());
uint256 amples = _wampleToAmple(wamples, _queryAMPLSupply());
_withdraw(_msgSender(), _msgSender(), amples, wamples);
return amples;
}
/// @notice Burns all wAMPLs from {msg.sender} and transfers AMPLs back,
/// to the specified beneficiary.
///
/// @param to The beneficiary wallet.
/// @return The amount of AMPLs withdrawn.
function burnAllTo(address to) external returns (uint256) {
uint256 wamples = balanceOf(_msgSender());
uint256 amples = _wampleToAmple(wamples, _queryAMPLSupply());
_withdraw(_msgSender(), to, amples, wamples);
return amples;
}
/// @notice Transfers AMPLs from {msg.sender} and mints wAMPLs.
///
/// @param amples The amount of AMPLs to deposit.
/// @return The amount of wAMPLs minted.
function deposit(uint256 amples) external returns (uint256) {
uint256 wamples = _ampleToWample(amples, _queryAMPLSupply());
_deposit(_msgSender(), _msgSender(), amples, wamples);
return wamples;
}
/// @notice Transfers AMPLs from {msg.sender} and mints wAMPLs,
/// to the specified beneficiary.
///
/// @param to The beneficiary wallet.
/// @param amples The amount of AMPLs to deposit.
/// @return The amount of wAMPLs minted.
function depositFor(address to, uint256 amples) external returns (uint256) {
uint256 wamples = _ampleToWample(amples, _queryAMPLSupply());
_deposit(_msgSender(), to, amples, wamples);
return wamples;
}
/// @notice Burns wAMPLs from {msg.sender} and transfers AMPLs back.
///
/// @param amples The amount of AMPLs to withdraw.
/// @return The amount of burnt wAMPLs.
function withdraw(uint256 amples) external returns (uint256) {
uint256 wamples = _ampleToWample(amples, _queryAMPLSupply());
_withdraw(_msgSender(), _msgSender(), amples, wamples);
return wamples;
}
/// @notice Burns wAMPLs from {msg.sender} and transfers AMPLs back,
/// to the specified beneficiary.
///
/// @param to The beneficiary wallet.
/// @param amples The amount of AMPLs to withdraw.
/// @return The amount of burnt wAMPLs.
function withdrawTo(address to, uint256 amples) external returns (uint256) {
uint256 wamples = _ampleToWample(amples, _queryAMPLSupply());
_withdraw(_msgSender(), to, amples, wamples);
return wamples;
}
/// @notice Burns all wAMPLs from {msg.sender} and transfers AMPLs back.
///
/// @return The amount of burnt wAMPLs.
function withdrawAll() external returns (uint256) {
uint256 wamples = balanceOf(_msgSender());
uint256 amples = _wampleToAmple(wamples, _queryAMPLSupply());
_withdraw(_msgSender(), _msgSender(), amples, wamples);
return wamples;
}
/// @notice Burns all wAMPLs from {msg.sender} and transfers AMPLs back,
/// to the specified beneficiary.
///
/// @param to The beneficiary wallet.
/// @return The amount of burnt wAMPLs.
function withdrawAllTo(address to) external returns (uint256) {
uint256 wamples = balanceOf(_msgSender());
uint256 amples = _wampleToAmple(wamples, _queryAMPLSupply());
_withdraw(_msgSender(), to, amples, wamples);
return wamples;
}
//--------------------------------------------------------------------------
// WAMPL view methods
/// @return The address of the underlying "wrapped" token ie) AMPL.
function underlying() external view returns (address) {
return _ampl;
}
/// @return The total AMPLs held by this contract.
function totalUnderlying() external view returns (uint256) {
return _wampleToAmple(totalSupply(), _queryAMPLSupply());
}
/// @param owner The account address.
/// @return The AMPL balance redeemable by the owner.
function balanceOfUnderlying(address owner) external view returns (uint256) {
return _wampleToAmple(balanceOf(owner), _queryAMPLSupply());
}
/// @param amples The amount of AMPL tokens.
/// @return The amount of wAMPL tokens exchangeable.
function underlyingToWrapper(uint256 amples) external view returns (uint256) {
return _ampleToWample(amples, _queryAMPLSupply());
}
/// @param wamples The amount of wAMPL tokens.
/// @return The amount of AMPL tokens exchangeable.
function wrapperToUnderlying(uint256 wamples) external view returns (uint256) {
return _wampleToAmple(wamples, _queryAMPLSupply());
}
//--------------------------------------------------------------------------
// Private methods
/// @dev Internal helper function to handle deposit state change.
/// @param from The initiator wallet.
/// @param to The beneficiary wallet.
/// @param amples The amount of AMPLs to deposit.
/// @param wamples The amount of wAMPLs to mint.
function _deposit(
address from,
address to,
uint256 amples,
uint256 wamples
) private {
IERC20Upgradeable(_ampl).safeTransferFrom(from, address(this), amples);
_mint(to, wamples);
}
/// @dev Internal helper function to handle withdraw state change.
/// @param from The initiator wallet.
/// @param to The beneficiary wallet.
/// @param amples The amount of AMPLs to withdraw.
/// @param wamples The amount of wAMPLs to burn.
function _withdraw(
address from,
address to,
uint256 amples,
uint256 wamples
) private {
_burn(from, wamples);
IERC20Upgradeable(_ampl).safeTransfer(to, amples);
}
/// @dev Queries the current total supply of AMPL.
/// @return The current AMPL supply.
function _queryAMPLSupply() private view returns (uint256) {
return IERC20Upgradeable(_ampl).totalSupply();
}
//--------------------------------------------------------------------------
// Pure methods
/// @dev Converts AMPLs to wAMPL amount.
function _ampleToWample(uint256 amples, uint256 totalAMPLSupply)
private
pure
returns (uint256)
{
return (amples * MAX_WAMPL_SUPPLY) / totalAMPLSupply;
}
/// @dev Converts wAMPLs amount to AMPLs.
function _wampleToAmple(uint256 wamples, uint256 totalAMPLSupply)
private
pure
returns (uint256)
{
return (wamples * totalAMPLSupply) / MAX_WAMPL_SUPPLY;
}
}