-
Notifications
You must be signed in to change notification settings - Fork 0
/
IndexToken.sol
227 lines (184 loc) · 7.55 KB
/
IndexToken.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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;
import "../proposable/ProposableOwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "./TokenInterface.sol";
/// @title Index Token
/// @author NEX Labs Protocol
/// @notice The main token contract for Index Token (NEX Labs Protocol)
/// @dev This contract uses an upgradeable pattern
contract IndexToken is
ContextUpgradeable,
ERC20Upgradeable,
ProposableOwnableUpgradeable,
PausableUpgradeable,
TokenInterface
{
uint256 internal constant SCALAR = 1e20;
// Inflation rate (per day) on total supply, to be accrued to the feeReceiver.
uint256 public feeRatePerDayScaled;
// Most recent timestamp when fee was accured.
uint256 public feeTimestamp;
// Address that can claim fees accrued.
address public feeReceiver;
// Address that can publish a new methodology.
address public methodologist;
// Address that has privilege to mint and burn. It will be Controller and Admin to begin.
address public minter;
string public methodology;
uint256 public supplyCeiling;
mapping(address => bool) public isRestricted;
modifier onlyMethodologist() {
require(msg.sender == methodologist, "IndexToken: caller is not the methodologist");
_;
}
modifier onlyMinter() {
require(msg.sender == minter, "IndexToken: caller is not the minter");
_;
}
function initialize(
string memory tokenName,
string memory tokenSymbol,
uint256 _feeRatePerDayScaled,
address _feeReceiver,
uint256 _supplyCeiling
) external override initializer {
require(_feeReceiver != address(0));
__Ownable_init();
__Pausable_init();
__ERC20_init(tokenName, tokenSymbol);
__Context_init();
feeRatePerDayScaled = _feeRatePerDayScaled;
feeReceiver = _feeReceiver;
supplyCeiling = _supplyCeiling;
feeTimestamp = block.timestamp;
}
/// @notice External mint function
/// @dev Mint function can only be called externally by the controller
/// @param to address
/// @param amount uint256
function mint(address to, uint256 amount) external override whenNotPaused onlyMinter {
require(totalSupply() + amount <= supplyCeiling, "will exceed supply ceiling");
require(!isRestricted[to], "to is restricted");
require(!isRestricted[msg.sender], "msg.sender is restricted");
_mintToFeeReceiver();
_mint(to, amount);
}
/// @notice External burn function
/// @dev burn function can only be called externally by the controller
/// @param from address
/// @param amount uint256
function burn(address from, uint256 amount) external override whenNotPaused onlyMinter {
require(!isRestricted[from], "from is restricted");
require(!isRestricted[msg.sender], "msg.sender is restricted");
_mintToFeeReceiver();
_burn(from, amount);
}
function _mintToFeeReceiver() internal {
// total number of days elapsed
uint256 _days = (block.timestamp - feeTimestamp) / 1 days;
if (_days >= 1) {
uint256 initial = totalSupply();
uint256 supply = initial;
uint256 _feeRate = feeRatePerDayScaled;
for (uint256 i; i < _days; ) {
supply += ((supply * _feeRate) / SCALAR);
unchecked {
++i;
}
}
uint256 amount = supply - initial;
feeTimestamp += 1 days * _days;
_mint(feeReceiver, amount);
emit MintFeeToReceiver(feeReceiver, block.timestamp, totalSupply(), amount);
}
}
/// @notice Expands supply and mints fees to fee reciever
/// @dev Can only be called by the owner externally,
/// @dev _mintToFeeReciver is the internal function and is called after each supply/rate change
function mintToFeeReceiver() external override onlyOwner {
_mintToFeeReceiver();
}
/// @notice Only owner function for setting the methodologist
/// @param _methodologist address
function setMethodologist(address _methodologist) external override onlyOwner {
require(_methodologist != address(0));
methodologist = _methodologist;
emit MethodologistSet(_methodologist);
}
/// @notice Callable only by the methodoligst to store on chain data about the underlying weight of the token
/// @param _methodology string
function setMethodology(string memory _methodology) external override onlyMethodologist {
methodology = _methodology;
emit MethodologySet(_methodology);
}
/// @notice Ownable function to set the fee rate
/// @dev Given the annual fee rate this function sets and calculates the rate per second
/// @param _feeRatePerDayScaled uint256
function setFeeRate(uint256 _feeRatePerDayScaled) external override onlyOwner {
_mintToFeeReceiver();
feeRatePerDayScaled = _feeRatePerDayScaled;
emit FeeRateSet(_feeRatePerDayScaled);
}
/// @notice Ownable function to set the receiver
/// @param _feeReceiver address
function setFeeReceiver(address _feeReceiver) external override onlyOwner {
require(_feeReceiver != address(0));
feeReceiver = _feeReceiver;
emit FeeReceiverSet(_feeReceiver);
}
/// @notice Ownable function to set the contract that controls minting
/// @param _minter address
function setMinter(address _minter) external override onlyOwner {
require(_minter != address(0));
minter = _minter;
emit MinterSet(_minter);
}
/// @notice Ownable function to set the limit at which the total supply cannot exceed
/// @param _supplyCeiling uint256
function setSupplyCeiling(uint256 _supplyCeiling) external override onlyOwner {
supplyCeiling = _supplyCeiling;
emit SupplyCeilingSet(_supplyCeiling);
}
function pause() external override onlyOwner {
_pause();
}
function unpause() external override onlyOwner {
_unpause();
}
/// @notice Compliance feature to blacklist bad actors
/// @dev Negates current restriction state
/// @param who address
function toggleRestriction(address who) external override onlyOwner {
isRestricted[who] = !isRestricted[who];
emit ToggledRestricted(who, isRestricted[who]);
}
/// @notice Overriden ERC20 transfer to include restriction
/// @param to address
/// @param amount uint256
/// @return bool
function transfer(address to, uint256 amount) public override whenNotPaused returns (bool) {
require(!isRestricted[msg.sender], "msg.sender is restricted");
require(!isRestricted[to], "to is restricted");
_transfer(msg.sender, to, amount);
return true;
}
/// @notice Overriden ERC20 transferFrom to include restriction
/// @param from address
/// @param to address
/// @param amount uint256
/// @return bool
function transferFrom(
address from,
address to,
uint256 amount
) public override whenNotPaused returns (bool) {
require(!isRestricted[msg.sender], "msg.sender is restricted");
require(!isRestricted[to], "to is restricted");
require(!isRestricted[from], "from is restricted");
_spendAllowance(from, msg.sender, amount);
_transfer(from, to, amount);
return true;
}
}