-
Notifications
You must be signed in to change notification settings - Fork 68
Description
Summary:
In the distribute function, rewards are distributed to the delegatee (sequencers), and the amount and preAmount are correctly updated. However, the share field in delegateeDelegations is not updated after the reward distribution, which results in incorrect calculations for delegators’ shares when they stake more tokens.
Root Cause:
The issue arises because, while the amount and preAmount of the delegatee are updated correctly to reflect the total accumulated rewards, the share (which represents the stake weight) is not updated. This omission leads to incorrect calculations for the delegator‘s reward share in subsequent epochs, as the delegator’s reward is proportional to the share.
Reproduce Steps:
- Precondition:
• rewardStarted is true.
• A delegator (e.g., delegatorM1) delegates a certain amount (e.g., 100 Morph tokens) to delegateeM in epoch x.
• After the reward distribution in epoch x, delegateeM receives rewards, and the amount and preAmount fields are updated. - Epoch x+1:
• A second delegator (e.g., delegatorM2) delegates 100 Morph tokens to delegateeM. - Epoch x+2:
• Another reward distribution occurs.
• Since delegateeM’s share has not been updated in previous steps, the rewards calculation for the new delegators becomesincorrect.
Actual Behavior:
• The amount and preAmount are updated, but the share is not updated, which results in incorrect reward calculations for delegators in subsequent epochs.
Expected Behavior:
• After the reward distribution, both amount and share for delegateeDelegations[sequencer] should be updated. The share field must reflect the proportion of the delegatee‘s total reward, allowing delegators’ rewards to be accurately calculated.
code in L2Staking.sol with PR693
/// @dev distribute inflation by system on epoch end
/// @param epochIndex epoch index
/// @param sequencers sequencers
/// @param rewards total rewards
function distribute(
uint256 epochIndex,
address[] calldata sequencers,
uint256[] calldata rewards
) external onlSystem {
if (currentEpoch() != epochIndex) revert ErrInvalidEpoch();
if (sequencers.length != rewards.length) revert ErrInvalidRewards();
for (uint256 i = 0; i < sequencers.length; i++) {
uint256 commissionRate = commissions[sequencers[i]].rate;
uint256 commissionAmount = (rewards[i] * commissionRate) / COMMISSION_RATE_BASE;
uint256 rewardAmount = rewards[i] - commissionAmount;
commissions[sequencers[i]].amount += commissionAmount;
delegateeDelegations[sequencers[i]].amount += rewardAmount;
delegateeDelegations[sequencers[i]].preAmount = delegateeDelegations[sequencers[i]].amount;
delegateeDelegations[sequencers[i]].checkpoint = epochIndex;
emit Distributed(sequencers[i], rewardAmount, commissionAmount);
}
}