@@ -55,9 +55,15 @@ contract StakingManager is Authorizable, Modifiable, IStakingManager {
55
55
/// @inheritdoc IStakingManager
56
56
mapping (address => uint256 ) public stakedBalances;
57
57
58
+ /// @inheritdoc IStakingManager
59
+ uint256 public totalKiteRewardsAvailable;
60
+
58
61
/// @inheritdoc IStakingManager
59
62
uint256 public totalStaked;
60
63
64
+ /// @inheritdoc IStakingManager
65
+ uint256 public totalStakedRaw;
66
+
61
67
/// @inheritdoc IStakingManager
62
68
// solhint-disable-next-line private-vars-leading-underscore
63
69
mapping (address _account = > PendingWithdrawal) public _pendingWithdrawals;
@@ -120,10 +126,13 @@ contract StakingManager is Authorizable, Modifiable, IStakingManager {
120
126
if (_account == address (0 )) revert StakingManager_StakeNullReceiver ();
121
127
if (_wad == 0 ) revert StakingManager_StakeNullAmount ();
122
128
129
+ _checkpoint ([_account, msg .sender ]);
130
+
123
131
stakedBalances[_account] += _wad;
124
132
125
133
totalStaked += _wad;
126
134
135
+ totalStakedRaw += _wad;
127
136
// Mint stKITE
128
137
stakingToken.mint (_account, _wad);
129
138
@@ -150,6 +159,8 @@ contract StakingManager is Authorizable, Modifiable, IStakingManager {
150
159
revert StakingManager_WithdrawAmountExceedsBalance ();
151
160
}
152
161
162
+ _checkpoint ([msg .sender , address (0 )]);
163
+
153
164
PendingWithdrawal storage _existingWithdrawal = _pendingWithdrawals[msg .sender ];
154
165
stakedBalances[msg .sender ] -= _wad;
155
166
@@ -173,15 +184,17 @@ contract StakingManager is Authorizable, Modifiable, IStakingManager {
173
184
174
185
emit StakingManagerWithdrawalInitiated (msg .sender , _wad);
175
186
}
176
- /// @inheritdoc IStakingManager
177
187
188
+ /// @inheritdoc IStakingManager
178
189
function cancelWithdrawal () external {
179
190
PendingWithdrawal storage _existingWithdrawal = _pendingWithdrawals[msg .sender ];
180
191
181
192
if (_existingWithdrawal.amount == 0 ) {
182
193
revert StakingManager_NoPendingWithdrawal ();
183
194
}
184
195
196
+ _checkpoint ([msg .sender , address (0 )]);
197
+
185
198
uint256 _withdrawalAmount = _existingWithdrawal.amount; // Store the amount before deleting
186
199
187
200
delete _pendingWithdrawals[msg .sender ];
@@ -216,6 +229,8 @@ contract StakingManager is Authorizable, Modifiable, IStakingManager {
216
229
217
230
uint256 _withdrawalAmount = _existingWithdrawal.amount; // Store amount first
218
231
232
+ totalStakedRaw -= _withdrawalAmount;
233
+
219
234
delete _pendingWithdrawals[msg .sender ];
220
235
221
236
stakingToken.burnFrom (msg .sender , _withdrawalAmount);
@@ -243,7 +258,9 @@ contract StakingManager is Authorizable, Modifiable, IStakingManager {
243
258
244
259
IERC20 (_rewardTypes[_id].rewardToken).safeTransfer (_rescueReceiver, _wad);
245
260
246
- // protocolToken.safeTransfer(_rescueReceiver, _wad);
261
+ if (_rewardTypes[_id].rewardToken == address (protocolToken)) {
262
+ totalKiteRewardsAvailable -= _wad;
263
+ }
247
264
248
265
emit StakingManagerEmergencyRewardWithdrawal (_rescueReceiver, _rewardTypes[_id].rewardToken, _wad);
249
266
}
@@ -328,7 +345,6 @@ contract StakingManager is Authorizable, Modifiable, IStakingManager {
328
345
return _claimable;
329
346
}
330
347
331
- // TODO: Check decimals
332
348
function _calcRewardIntegral (
333
349
uint256 _id ,
334
350
address [2 ] memory _accounts ,
@@ -340,60 +356,89 @@ contract StakingManager is Authorizable, Modifiable, IStakingManager {
340
356
341
357
if (! _rewardType.isActive) return ;
342
358
343
- uint256 _balance = IERC20 (_rewardType.rewardToken).balanceOf (address (this ));
359
+ // --- Start: Adjusted Balance Calculation ---
360
+ uint256 _currentRewardBalance;
361
+ // Get the total balance of the reward token in the contract
362
+ uint256 _contractTokenBalance = IERC20 (_rewardType.rewardToken).balanceOf (address (this ));
363
+
364
+ // Check if reward token is the protocol token
365
+ if (_rewardType.rewardToken == address (protocolToken)) {
366
+ // If yes, subtract the *raw* staked principal amount (totalStakedRaw)
367
+ // Ensure non-negative result
368
+ _currentRewardBalance = totalKiteRewardsAvailable;
369
+ } else {
370
+ // If not, the entire balance is potential rewards
371
+ _currentRewardBalance = _contractTokenBalance;
372
+ }
344
373
345
- // Checks if new rewards have been added by comparing current balance with rewardRemaining
346
- if (_balance > _rewardType.rewardRemaining) {
347
- uint256 _newRewards = _balance - _rewardType.rewardRemaining;
348
- // If there are new rewards and there are existing stakers
374
+ // Calculate new rewards based on the difference from remaining
375
+ if (_currentRewardBalance > _rewardType.rewardRemaining) {
376
+ uint256 _newRewards = _currentRewardBalance - _rewardType.rewardRemaining;
349
377
if (_supply > 0 ) {
378
+ // Update integral with new rewards
350
379
_rewardType.rewardIntegral += (_newRewards * WAD) / _supply;
351
- _rewardType.rewardRemaining = _balance;
352
380
}
381
+ // Update remaining rewards to current calculated balance
382
+ _rewardType.rewardRemaining = _currentRewardBalance;
383
+ } else if (_currentRewardBalance < _rewardType.rewardRemaining) {
384
+ // If current balance is less than remaining (e.g., due to direct transfer out), adjust remaining down.
385
+ // This prevents rewardRemaining from staying artificially high.
386
+ _rewardType.rewardRemaining = _currentRewardBalance;
353
387
}
388
+ // --- End: Adjusted Balance Calculation ---
354
389
355
390
for (uint256 _i = 0 ; _i < _accounts.length ; _i++ ) {
356
391
if (_accounts[_i] == address (0 )) continue ;
357
- if (_isClaim && _i != 0 ) continue ; //only update/claim for first address and use second as forwarding
392
+ if (_isClaim && _i != 0 ) continue ; // only update/claim for first address and use second as forwarding
358
393
359
394
uint256 _userBalance = _balances[_i];
360
395
uint256 _userIntegral = _rewardType.rewardIntegralFor[_accounts[_i]];
396
+ uint256 _rewardAccrued = 0 ;
397
+
398
+ // Calculate rewards accrued since last checkpoint for the user
399
+ if (_rewardType.rewardIntegral > _userIntegral) {
400
+ _rewardAccrued = (_userBalance * (_rewardType.rewardIntegral - _userIntegral)) / WAD;
401
+ }
361
402
362
- if (_isClaim || _userIntegral < _rewardType.rewardIntegral) {
363
- if (_isClaim) {
364
- // Calculate total receiveable rewards
365
- uint256 _receiveable = _rewardType.claimableReward[_accounts[_i]]
366
- + (_userBalance * (_rewardType.rewardIntegral - _userIntegral)) / WAD;
403
+ if (_isClaim) {
404
+ uint256 _claimablePreviously = _rewardType.claimableReward[_accounts[_i]];
405
+ uint256 _totalReceivable = _claimablePreviously + _rewardAccrued;
367
406
368
- if (_receiveable > 0 ) {
369
- // Reset claimable rewards to 0
370
- _rewardType.claimableReward[_accounts[_i]] = 0 ;
407
+ if (_totalReceivable > 0 ) {
408
+ // Cap receivable amount by the available remaining rewards
409
+ if (_totalReceivable > _rewardType.rewardRemaining) {
410
+ _totalReceivable = _rewardType.rewardRemaining;
411
+ }
371
412
372
- // Transfer rewards to the next address in the array (forwarding address)
373
- IERC20 (_rewardType.rewardToken).safeTransfer (_accounts[_i + 1 ], _receiveable);
413
+ // Update state *before* transfer
414
+ _rewardType.claimableReward[_accounts[_i]] = 0 ; // Reset claimable
415
+ _rewardType.rewardIntegralFor[_accounts[_i]] = _rewardType.rewardIntegral; // Update integral
416
+ _rewardType.rewardRemaining -= _totalReceivable; // Decrease remaining
374
417
375
- emit StakingManagerRewardPaid (_accounts[_i], _rewardType.rewardToken, _receiveable, _accounts[_i + 1 ]);
376
- // Update the remaining balance
377
- _balance = _balance - _receiveable;
418
+ if (_rewardType.rewardToken == address (protocolToken)) {
419
+ totalKiteRewardsAvailable -= _totalReceivable;
378
420
}
421
+
422
+ // Transfer rewards
423
+ IERC20 (_rewardType.rewardToken).safeTransfer (_accounts[_i + 1 ], _totalReceivable);
424
+
425
+ emit StakingManagerRewardPaid (_accounts[_i], _rewardType.rewardToken, _totalReceivable, _accounts[_i + 1 ]);
379
426
} else {
380
- // Just accumulate rewards without claiming
381
- _rewardType.claimableReward[_accounts[_i]] = _rewardType.claimableReward[_accounts[_i]]
382
- + (_userBalance * (_rewardType.rewardIntegral - _userIntegral)) / WAD;
427
+ // If no rewards to claim, still update the integral
428
+ _rewardType.rewardIntegralFor[_accounts[_i]] = _rewardType.rewardIntegral;
383
429
}
430
+ } else {
431
+ // Not claiming, just checkpointing
432
+ // Add newly accrued rewards to the user's claimable balance
433
+ _rewardType.claimableReward[_accounts[_i]] += _rewardAccrued;
384
434
// Update user's reward integral
385
435
_rewardType.rewardIntegralFor[_accounts[_i]] = _rewardType.rewardIntegral;
386
436
}
387
437
}
388
-
389
- // Update remaining reward here since balance could have changed if claiming
390
- if (_balance != _rewardType.rewardRemaining) {
391
- _rewardType.rewardRemaining = uint256 (_balance);
392
- }
393
438
}
394
439
395
440
function _checkpoint (address [2 ] memory _accounts ) internal {
396
- uint256 _supply = stakingToken. totalSupply () ;
441
+ uint256 _supply = totalStaked ;
397
442
uint256 [2 ] memory _depositedBalance;
398
443
_depositedBalance[0 ] = stakedBalances[_accounts[0 ]];
399
444
_depositedBalance[1 ] = stakedBalances[_accounts[1 ]];
@@ -406,9 +451,9 @@ contract StakingManager is Authorizable, Modifiable, IStakingManager {
406
451
}
407
452
408
453
function _checkpointAndClaim (address [2 ] memory _accounts ) internal {
409
- uint256 _supply = stakingToken. totalSupply () ;
454
+ uint256 _supply = totalStaked ;
410
455
uint256 [2 ] memory _depositedBalance;
411
- _depositedBalance[0 ] = stakedBalances[_accounts[0 ]]; //only do first slot
456
+ _depositedBalance[0 ] = stakedBalances[_accounts[0 ]]; // only do first slot
412
457
413
458
_claimManagerRewards ();
414
459
@@ -420,9 +465,14 @@ contract StakingManager is Authorizable, Modifiable, IStakingManager {
420
465
function _claimManagerRewards () internal {
421
466
for (uint256 _i = 0 ; _i < rewards; _i++ ) {
422
467
RewardType storage _rewardType = _rewardTypes[_i];
423
- IRewardPool _rewardPool = IRewardPool (_rewardType.rewardPool);
424
468
if (! _rewardType.isActive) continue ;
425
- _rewardPool.getReward ();
469
+
470
+ IRewardPool _rewardPool = IRewardPool (_rewardType.rewardPool);
471
+
472
+ uint256 _reward = _rewardPool.getReward ();
473
+ if (_rewardType.rewardToken == address (protocolToken)) {
474
+ totalKiteRewardsAvailable += _reward;
475
+ }
426
476
}
427
477
}
428
478
0 commit comments