-
Notifications
You must be signed in to change notification settings - Fork 68
Description
Summary:
A division by zero bug occurs when a delegator tries to delegate to a delegatee with an initial amount of zero. This bug happens because the _tAmount value (representing the total amount of the delegatee) is zero, which leads to a division by zero error when calculating the delegator’s share.
Root Cause:
The issue arises when a delegator delegates to a delegatee for the first time. At that point, the delegatee’s amount is initialized to zero. The formula for updating the delegator’s share involves dividing by the delegatee’s total amount (_tAmount). Since the delegatee’s amount is zero, the division operation results in a division by zero error.
Reproduce Steps:
1. Initialize the contract and set up a delegatee (DelegateeA1) with an initial amount of zero.
2. A delegator (DelegatorA1) delegates a non-zero amount of Morph tokens (e.g., 100 tokens) to DelegateeA1 for the first time.
3. The contract tries to update the delegator’s share using the formula: delegatorDelegations[delegatee][_msgSender()].share = _uShare + (amount * _tshare) / _tAmount;
4. Since _tAmount is zero (as it’s the first delegation to this delegatee), a division by zero error occurs.
Solution:
Implement a check before performing the division to ensure _tAmount is not zero. If it is zero, handle it appropriately, such as initializing the share calculation with a default value or skipping the calculation until the delegatee’s amount is updated.
code in L2Staking.sol with PR693
// first delegate stake at this epoch, update checkpoint & preShare
if (delegatorDelegations[delegatee][_msgSender()].checkpoint < effectiveEpoch) {
delegatorDelegations[delegatee][_msgSender()].checkpoint = effectiveEpoch;
delegatorDelegations[delegatee][_msgSender()].preShare = delegatorDelegations[delegatee][_msgSender()]
.share;
}
// first delegate stake at this epoch, update checkpoint & preAmount & preShare
if (delegateeDelegations[delegatee].checkpoint < effectiveEpoch) {
delegateeDelegations[delegatee].checkpoint = effectiveEpoch;
delegateeDelegations[delegatee].preAmount = delegateeDelegations[delegatee].amount;
delegateeDelegations[delegatee].preShare = delegateeDelegations[delegatee].share;
}
uint256 _tshare = delegateeDelegations[delegatee].share;
uint256 _tAmount = delegateeDelegations[delegatee].amount;
uint256 _uShare = delegatorDelegations[delegatee][_msgSender()].share;
delegatorDelegations[delegatee][_msgSender()].share = _uShare + (amount * _tshare) / _tAmount;
delegateeDelegations[delegatee].amount += amount;
delegateeDelegations[delegatee].share = _tshare + (amount * _tshare) / _tAmount;