Skip to content

Division by Zero when First Delegation to a Delegatee with Zero Amount #719

@GingerLiu123

Description

@GingerLiu123

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;

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions