@@ -10,6 +10,7 @@ import { IStakeManager } from "./interfaces/IStakeManager.sol";
10
10
import { IStakeVault } from "./interfaces/IStakeVault.sol " ;
11
11
import { IRewardProvider } from "./interfaces/IRewardProvider.sol " ;
12
12
import { TrustedCodehashAccess } from "./TrustedCodehashAccess.sol " ;
13
+ import { StakeMath } from "./math/StakeMath.sol " ;
13
14
14
15
// Rewards Streamer with Multiplier Points
15
16
contract RewardsStreamerMP is
@@ -18,15 +19,16 @@ contract RewardsStreamerMP is
18
19
IStakeManager ,
19
20
TrustedCodehashAccess ,
20
21
ReentrancyGuardUpgradeable ,
21
- IRewardProvider
22
+ IRewardProvider ,
23
+ StakeMath
22
24
{
23
25
error StakingManager__InvalidVault ();
24
26
error StakingManager__VaultNotRegistered ();
25
27
error StakingManager__VaultAlreadyRegistered ();
26
28
error StakingManager__AmountCannotBeZero ();
27
29
error StakingManager__TransferFailed ();
28
30
error StakingManager__InsufficientBalance ();
29
- error StakingManager__InvalidLockingPeriod ();
31
+ error StakingManager__LockingPeriodCannotBeZero ();
30
32
error StakingManager__CannotRestakeWithLockedFunds ();
31
33
error StakingManager__TokensAreLocked ();
32
34
error StakingManager__AlreadyLocked ();
@@ -36,12 +38,6 @@ contract RewardsStreamerMP is
36
38
IERC20 public STAKING_TOKEN;
37
39
38
40
uint256 public constant SCALE_FACTOR = 1e18 ;
39
- uint256 public constant MP_RATE_PER_YEAR = 1 ;
40
-
41
- uint256 public constant YEAR = 365 days ;
42
- uint256 public constant MIN_LOCKUP_PERIOD = 90 days ;
43
- uint256 public constant MAX_LOCKUP_PERIOD = 4 * YEAR;
44
- uint256 public constant MAX_MULTIPLIER = 4 ;
45
41
46
42
uint256 public totalStaked;
47
43
uint256 public totalMPAccrued;
@@ -193,40 +189,30 @@ contract RewardsStreamerMP is
193
189
revert StakingManager__AmountCannotBeZero ();
194
190
}
195
191
196
- if (lockPeriod != 0 && (lockPeriod < MIN_LOCKUP_PERIOD || lockPeriod > MAX_LOCKUP_PERIOD)) {
197
- revert StakingManager__InvalidLockingPeriod ();
198
- }
199
-
200
192
_updateGlobalState ();
201
193
_updateVaultMP (msg .sender , true );
202
194
203
195
VaultData storage vault = vaultData[msg .sender ];
204
196
if (vault.lockUntil != 0 && vault.lockUntil > block .timestamp ) {
205
197
revert StakingManager__CannotRestakeWithLockedFunds ();
206
198
}
199
+ (uint256 _deltaMpTotal , uint256 _deltaMPMax , uint256 _newLockEnd ) =
200
+ _calculateStake (vault.stakedBalance, vault.maxMP, vault.lockUntil, block .timestamp , amount, lockPeriod);
207
201
208
202
vault.stakedBalance += amount;
209
203
totalStaked += amount;
210
204
211
- uint256 initialMP = amount;
212
- uint256 potentialMP = amount * MAX_MULTIPLIER;
213
- uint256 bonusMP = 0 ;
214
-
215
205
if (lockPeriod != 0 ) {
216
- bonusMP = _calculateBonusMP (amount, lockPeriod);
217
- vault.lockUntil = block .timestamp + lockPeriod;
206
+ vault.lockUntil = _newLockEnd;
218
207
} else {
219
208
vault.lockUntil = 0 ;
220
209
}
221
210
222
- uint256 vaultMaxMP = initialMP + bonusMP + potentialMP;
223
- uint256 vaultMP = initialMP + bonusMP;
224
-
225
- vault.mpAccrued += vaultMP;
226
- totalMPAccrued += vaultMP;
211
+ vault.mpAccrued += _deltaMpTotal;
212
+ totalMPAccrued += _deltaMpTotal;
227
213
228
- vault.maxMP += vaultMaxMP ;
229
- totalMaxMP += vaultMaxMP ;
214
+ vault.maxMP += _deltaMPMax ;
215
+ totalMaxMP += _deltaMPMax ;
230
216
231
217
vault.rewardIndex = rewardIndex;
232
218
}
@@ -238,33 +224,29 @@ contract RewardsStreamerMP is
238
224
onlyRegisteredVault
239
225
nonReentrant
240
226
{
241
- if (lockPeriod < MIN_LOCKUP_PERIOD || lockPeriod > MAX_LOCKUP_PERIOD) {
242
- revert StakingManager__InvalidLockingPeriod ();
243
- }
244
-
245
227
VaultData storage vault = vaultData[msg .sender ];
246
228
247
229
if (vault.lockUntil > 0 ) {
248
230
revert StakingManager__AlreadyLocked ();
249
231
}
250
232
251
- if (vault.stakedBalance == 0 ) {
252
- revert StakingManager__InsufficientBalance ();
233
+ if (lockPeriod == 0 ) {
234
+ revert StakingManager__LockingPeriodCannotBeZero ();
253
235
}
254
236
255
237
_updateGlobalState ();
256
238
_updateVaultMP (msg .sender , true );
239
+ (uint256 deltaMp , uint256 newLockEnd ) =
240
+ _calculateLock (vault.stakedBalance, vault.maxMP, vault.lockUntil, block .timestamp , lockPeriod);
257
241
258
- uint256 additionalBonusMP = _calculateBonusMP (vault.stakedBalance, lockPeriod);
259
-
260
- // Update vault state
261
- vault.lockUntil = block .timestamp + lockPeriod;
262
- vault.mpAccrued += additionalBonusMP;
263
- vault.maxMP += additionalBonusMP;
242
+ // Update account state
243
+ vault.lockUntil = newLockEnd;
244
+ vault.mpAccrued += deltaMp;
245
+ vault.maxMP += deltaMp;
264
246
265
247
// Update global state
266
- totalMPAccrued += additionalBonusMP ;
267
- totalMaxMP += additionalBonusMP ;
248
+ totalMPAccrued += deltaMp ;
249
+ totalMaxMP += deltaMp ;
268
250
269
251
vault.rewardIndex = rewardIndex;
270
252
}
@@ -277,32 +259,22 @@ contract RewardsStreamerMP is
277
259
nonReentrant
278
260
{
279
261
VaultData storage vault = vaultData[msg .sender ];
280
- if (amount > vault.stakedBalance) {
281
- revert StakingManager__InsufficientBalance ();
282
- }
283
-
284
- if (block .timestamp < vault.lockUntil) {
285
- revert StakingManager__TokensAreLocked ();
286
- }
287
262
_unstake (amount, vault, msg .sender );
288
263
}
289
264
290
265
function _unstake (uint256 amount , VaultData storage vault , address vaultAddress ) internal {
291
266
_updateGlobalState ();
292
267
_updateVaultMP (vaultAddress, true );
293
268
294
- uint256 previousStakedBalance = vault.stakedBalance;
295
-
296
- // solhint-disable-next-line
297
- uint256 mpToReduce = Math.mulDiv (vault.mpAccrued, amount, previousStakedBalance);
298
- uint256 maxMPToReduce = Math.mulDiv (vault.maxMP, amount, previousStakedBalance);
299
-
269
+ (uint256 _deltaMpTotal , uint256 _deltaMpMax ) = _calculateUnstake (
270
+ vault.stakedBalance, vault.lockUntil, block .timestamp , vault.mpAccrued, vault.maxMP, amount
271
+ );
300
272
vault.stakedBalance -= amount;
301
- vault.mpAccrued -= mpToReduce ;
302
- vault.maxMP -= maxMPToReduce ;
273
+ vault.mpAccrued -= _deltaMpTotal ;
274
+ vault.maxMP -= _deltaMpMax ;
303
275
vault.rewardIndex = rewardIndex;
304
- totalMPAccrued -= mpToReduce ;
305
- totalMaxMP -= maxMPToReduce ;
276
+ totalMPAccrued -= _deltaMpTotal ;
277
+ totalMaxMP -= _deltaMpMax ;
306
278
totalStaked -= amount;
307
279
}
308
280
@@ -315,6 +287,8 @@ contract RewardsStreamerMP is
315
287
VaultData storage vault = vaultData[msg .sender ];
316
288
317
289
if (vault.stakedBalance > 0 ) {
290
+ //updates lockuntil to allow unstake early
291
+ vault.lockUntil = block .timestamp ;
318
292
// calling `_unstake` to update accounting accordingly
319
293
_unstake (vault.stakedBalance, vault, msg .sender );
320
294
@@ -358,7 +332,7 @@ contract RewardsStreamerMP is
358
332
return (adjustedRewardIndex, totalMPAccrued);
359
333
}
360
334
361
- uint256 accruedMP = (timeDiff * totalStaked * MP_RATE_PER_YEAR) / YEAR ;
335
+ uint256 accruedMP = _accrueMP ( totalStaked, timeDiff) ;
362
336
if (totalMPAccrued + accruedMP > totalMaxMP) {
363
337
accruedMP = totalMaxMP - totalMPAccrued;
364
338
}
@@ -465,26 +439,19 @@ contract RewardsStreamerMP is
465
439
return (accruedRewards, newRewardIndex);
466
440
}
467
441
468
- function _calculateBonusMP (uint256 amount , uint256 lockPeriod ) internal pure returns (uint256 ) {
469
- return Math.mulDiv (amount, lockPeriod, YEAR);
470
- }
471
-
472
442
function _getVaultPendingMP (VaultData storage vault ) internal view returns (uint256 ) {
473
- if (vault.maxMP == 0 || vault.stakedBalance == 0 ) {
443
+ if (block . timestamp == vault.lastMPUpdateTime ) {
474
444
return 0 ;
475
445
}
476
-
477
- uint256 timeDiff = block .timestamp - vault.lastMPUpdateTime;
478
- if (timeDiff == 0 ) {
446
+ if (vault.maxMP == 0 || vault.stakedBalance == 0 ) {
479
447
return 0 ;
480
448
}
481
449
482
- uint256 accruedMP = Math.mulDiv (timeDiff * vault.stakedBalance, MP_RATE_PER_YEAR, YEAR);
450
+ uint256 deltaMpTotal = _calculateAccrual (
451
+ vault.stakedBalance, vault.mpAccrued, vault.maxMP, vault.lastMPUpdateTime, block .timestamp
452
+ );
483
453
484
- if (vault.mpAccrued + accruedMP > vault.maxMP) {
485
- accruedMP = vault.maxMP - vault.mpAccrued;
486
- }
487
- return accruedMP;
454
+ return deltaMpTotal;
488
455
}
489
456
490
457
function _updateVaultMP (address vaultAddress , bool forceMPUpdate ) internal {
0 commit comments