-
Notifications
You must be signed in to change notification settings - Fork 47
/
CheckpointsShared.sol
322 lines (286 loc) · 12.6 KB
/
CheckpointsShared.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
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
pragma solidity ^0.5.17;
pragma experimental ABIEncoderV2;
import "./StakingStorageShared.sol";
import "../../SafeMath96.sol";
/**
* @title Checkpoints contract.
* @notice Increases and decreases storage values for users, delegatees and
* total daily stake.
* */
contract CheckpointsShared is StakingStorageShared, SafeMath96 {
/// @notice An event emitted when an account changes its delegate.
event DelegateChanged(
address indexed delegator,
uint256 lockedUntil,
address indexed fromDelegate,
address indexed toDelegate
);
/// @notice An event emitted when a delegate account's stake balance changes.
event DelegateStakeChanged(
address indexed delegate,
uint256 lockedUntil,
uint256 previousBalance,
uint256 newBalance
);
/// @notice An event emitted when tokens get staked.
event TokensStaked(
address indexed staker,
uint256 amount,
uint256 lockedUntil,
uint256 totalStaked
);
/// @notice An event emitted when staked tokens get withdrawn.
event StakingWithdrawn(
address indexed staker,
uint256 amount,
uint256 until,
address indexed receiver,
bool isGovernance
);
/// @notice An event emitted when vesting tokens get withdrawn.
event VestingTokensWithdrawn(address vesting, address receiver);
/// @notice An event emitted when the owner unlocks all tokens.
event TokensUnlocked(uint256 amount);
/// @notice An event emitted when a staking period gets extended.
event ExtendedStakingDuration(
address indexed staker,
uint256 previousDate,
uint256 newDate,
uint256 amountStaked
);
event AdminAdded(address admin);
event AdminRemoved(address admin);
/// @param pauser address to grant power to pause the contract
/// @param added true - added, false - removed
event PauserAddedOrRemoved(address indexed pauser, bool indexed added);
/// @notice An event emitted when a staking is paused or unpaused
/// @param setPaused true - pause, false - unpause
event StakingPaused(bool indexed setPaused);
/// @notice An event emitted when a staking is frozen or unfrozen
/// @param setFrozen true - freeze, false - unfreeze
event StakingFrozen(bool indexed setFrozen);
event ContractCodeHashAdded(bytes32 hash);
event ContractCodeHashRemoved(bytes32 hash);
event VestingStakeSet(uint256 lockedTS, uint96 value);
event TeamVestingCancelled(address indexed caller, address receiver);
event TeamVestingPartiallyCancelled(
address indexed caller,
address receiver,
uint256 nextStartFrom
);
constructor() internal {
// abstract
}
/**
* @notice Increases the user's vesting stake for a giving lock date and writes a checkpoint.
* @param lockedTS The lock date.
* @param value The value to add to the staked balance.
* */
function _increaseVestingStake(uint256 lockedTS, uint96 value) internal {
uint32 nCheckpoints = numVestingCheckpoints[lockedTS];
uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;
uint96 newVest = add96(vested, value, "CP01"); // vested overflow
_writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);
}
/**
* @notice Decreases the user's vesting stake for a giving lock date and writes a checkpoint.
* @param lockedTS The lock date.
* @param value The value to substract to the staked balance.
* */
function _decreaseVestingStake(uint256 lockedTS, uint96 value) internal {
uint32 nCheckpoints = numVestingCheckpoints[lockedTS];
uint96 vested = vestingCheckpoints[lockedTS][nCheckpoints - 1].stake;
uint96 newVest = sub96(vested, value, "CP02"); // vested underflow
_writeVestingCheckpoint(lockedTS, nCheckpoints, newVest);
}
/**
* @notice Writes on storage the user vested amount.
* @param lockedTS The lock date.
* @param nCheckpoints The number of checkpoints, to find out the last one index.
* @param newVest The new vest balance.
* */
function _writeVestingCheckpoint(
uint256 lockedTS,
uint32 nCheckpoints,
uint96 newVest
) internal {
uint32 blockNumber = safe32(block.number, "CP03"); // block num > 32 bits
if (
nCheckpoints > 0 &&
vestingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber
) {
vestingCheckpoints[lockedTS][nCheckpoints - 1].stake = newVest;
} else {
vestingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newVest);
numVestingCheckpoints[lockedTS] = nCheckpoints + 1;
}
}
/**
* @notice Increases the user's stake for a giving lock date and writes a checkpoint.
* @param account The user address.
* @param lockedTS The lock date.
* @param value The value to add to the staked balance.
* */
function _increaseUserStake(address account, uint256 lockedTS, uint96 value) internal {
uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];
uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;
uint96 newStake = add96(staked, value, "CP04"); // staked overflow
_writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);
}
/**
* @notice Decreases the user's stake for a giving lock date and writes a checkpoint.
* @param account The user address.
* @param lockedTS The lock date.
* @param value The value to substract to the staked balance.
* */
function _decreaseUserStake(address account, uint256 lockedTS, uint96 value) internal {
uint32 nCheckpoints = numUserStakingCheckpoints[account][lockedTS];
uint96 staked = userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake;
uint96 newStake = sub96(staked, value, "CP05"); // staked underflow
_writeUserCheckpoint(account, lockedTS, nCheckpoints, newStake);
}
/**
* @notice Writes on storage the user stake.
* @param account The user address.
* @param lockedTS The lock date.
* @param nCheckpoints The number of checkpoints, to find out the last one index.
* @param newStake The new staked balance.
* */
function _writeUserCheckpoint(
address account,
uint256 lockedTS,
uint32 nCheckpoints,
uint96 newStake
) internal {
uint32 blockNumber = safe32(block.number, "CP06"); // block number > 32 bits
if (
nCheckpoints > 0 &&
userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].fromBlock == blockNumber
) {
userStakingCheckpoints[account][lockedTS][nCheckpoints - 1].stake = newStake;
} else {
userStakingCheckpoints[account][lockedTS][nCheckpoints] = Checkpoint(
blockNumber,
newStake
);
numUserStakingCheckpoints[account][lockedTS] = nCheckpoints + 1;
}
}
/**
* @notice Increases the delegatee's stake for a giving lock date and writes a checkpoint.
* @param delegatee The delegatee address.
* @param lockedTS The lock date.
* @param value The value to add to the staked balance.
* */
function _increaseDelegateStake(address delegatee, uint256 lockedTS, uint96 value) internal {
uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];
uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;
uint96 newStake = add96(staked, value, "CP07"); // block number > 32 bits
_writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);
}
/**
* @notice Decreases the delegatee's stake for a giving lock date and writes a checkpoint.
* @param delegatee The delegatee address.
* @param lockedTS The lock date.
* @param value The value to substract to the staked balance.
* */
function _decreaseDelegateStake(address delegatee, uint256 lockedTS, uint96 value) internal {
uint32 nCheckpoints = numDelegateStakingCheckpoints[delegatee][lockedTS];
uint96 staked = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;
uint96 newStake = 0;
// @dev We need to check delegate checkpoint value here,
// because we had an issue in `stake` function:
// delegate checkpoint wasn't updating for the second and next stakes for the same date
// if first stake was withdrawn completely and stake was delegated to the staker
// (no delegation to another address).
// @dev It can be greater than 0, but inconsistent after 3 transactions
if (staked > value) {
newStake = sub96(staked, value, "CP08"); // staked underflow
}
_writeDelegateCheckpoint(delegatee, lockedTS, nCheckpoints, newStake);
}
/**
* @notice Writes on storage the delegate stake.
* @param delegatee The delegate address.
* @param lockedTS The lock date.
* @param nCheckpoints The number of checkpoints, to find out the last one index.
* @param newStake The new staked balance.
* */
function _writeDelegateCheckpoint(
address delegatee,
uint256 lockedTS,
uint32 nCheckpoints,
uint96 newStake
) internal {
uint32 blockNumber = safe32(block.number, "CP09"); // block numb > 32 bits
uint96 oldStake = delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake;
if (
nCheckpoints > 0 &&
delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].fromBlock ==
blockNumber
) {
delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints - 1].stake = newStake;
} else {
delegateStakingCheckpoints[delegatee][lockedTS][nCheckpoints] = Checkpoint(
blockNumber,
newStake
);
numDelegateStakingCheckpoints[delegatee][lockedTS] = nCheckpoints + 1;
}
emit DelegateStakeChanged(delegatee, lockedTS, oldStake, newStake);
}
/**
* @notice Increases the total stake for a giving lock date and writes a checkpoint.
* @param lockedTS The lock date.
* @param value The value to add to the staked balance.
* */
function _increaseDailyStake(uint256 lockedTS, uint96 value) internal {
uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];
uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;
uint96 newStake = add96(staked, value, "CP10"); // staked overflow
_writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);
}
/**
* @notice Decreases the total stake for a giving lock date and writes a checkpoint.
* @param lockedTS The lock date.
* @param value The value to substract to the staked balance.
* */
function _decreaseDailyStake(uint256 lockedTS, uint96 value) internal {
uint32 nCheckpoints = numTotalStakingCheckpoints[lockedTS];
uint96 staked = totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake;
uint96 newStake = sub96(staked, value, "CP11"); // staked underflow
_writeStakingCheckpoint(lockedTS, nCheckpoints, newStake);
}
/**
* @notice Writes on storage the total stake.
* @param lockedTS The lock date.
* @param nCheckpoints The number of checkpoints, to find out the last one index.
* @param newStake The new staked balance.
* */
function _writeStakingCheckpoint(
uint256 lockedTS,
uint32 nCheckpoints,
uint96 newStake
) internal {
uint32 blockNumber = safe32(block.number, "CP12"); // block num > 32 bits
if (
nCheckpoints > 0 &&
totalStakingCheckpoints[lockedTS][nCheckpoints - 1].fromBlock == blockNumber
) {
totalStakingCheckpoints[lockedTS][nCheckpoints - 1].stake = newStake;
} else {
totalStakingCheckpoints[lockedTS][nCheckpoints] = Checkpoint(blockNumber, newStake);
numTotalStakingCheckpoints[lockedTS] = nCheckpoints + 1;
}
}
/**
* @notice Get the current balance of an account locked until a certain date.
* @param account The user address.
* @param lockDate The lock date.
* @return The stake amount.
* */
function _currentBalance(address account, uint256 lockDate) internal view returns (uint96) {
uint32 _numUnserStakingCheckpoints = numUserStakingCheckpoints[account][lockDate] - 1;
return userStakingCheckpoints[account][lockDate][_numUnserStakingCheckpoints].stake;
}
}