Lucene search

K
code423n4Code4renaCODE423N4:2023-08-LIVEPEER-FINDINGS-ISSUES-200
HistorySep 06, 2023 - 12:00 a.m.

LastRewardRound is sometimes not checkpointed for Delegators

2023-09-0600:00:00
Code4rena
github.com
6
vulnerability
impact
proof of concept
bondingcheckpoint
transcoder
delegator
checkpointing logic
mitigation
mapping
manual review
technical specification
state change
rewardwithhint
updatetranscoderwithfees
checkpointbondingstate
delegates

Lines of code

Vulnerability details

Impact

  • lastRewardRound is not updated/checkpointed for delegators when transcoder changes state. This results in incorrect rewards and votes. It also violates this checkpointing condition specified by the technical specification:

Quote:

_"In practical terms, it can be defined that after any write function called on the BONDING_MANAGER (including the checkpointBondingState below), the checkpointed state of all involved accounts should follow that mutation consistently. The “involved accounts” include:

If any of the above is a transcoder, all their delegators with at least 1 checkpoint."_

Proof of Concept

The BondingCheckpoint for an address that interacts with the BondingManager takes several inputs which are stored in the Delegate struct and one input from the Transcoder struct - t.lastRewardRound.

The checkpointing logic generally checkpoints the addresses where a state change occurs. For example, increaseTotalStake will checkpoint the state of the transcoder which had their stake increased. However, a delegator’s bonding state can change when their transcoder’s state - specifically the lastRewardRound changes.

When the lastRewardRound for a transcoder is updated in the rewardWithHint or updateTranscoderWithFees functions, it does not update the lastRewardRound for all the delegators to this transcoder. If the functions were implemented correctly they would contain a code block which iterates through all the delegators of the transcoder and updates their bonding checkpoint. Instead, the rewardWithHint function only checkpoints the transcoder (who is also msg.sender):

function rewardWithHint(address _newPosPrev, address _newPosNext)
        public
        whenSystemNotPaused
        currentRoundInitialized
        autoCheckpoint(msg.sender)
    {

After t.lastRewardRound is updated, the function ends without additional checkpointing other than the autoCheckpoint(msg.sender) modifier:

t.lastRewardRound = currentRound;

        emit Reward(msg.sender, transcoderRewards);
    } //----FUNCTION END-----

This means that the lastRewardRound will be incorrect for the delegator leading to incorrect rewards and the delegator’s bonding state can change without the bonding checkpoint being updated.

Tools Used

Manual Review

Recommended Mitigation Steps

There could be a mapping from transcoder to an array of delegates which gets updated every time a delegate is added or removed. When lastRewardRound is updated, it could iterate through the deleagtors and update the checkpoint for t.lastRewardRound.

Assessed type

Other


The text was updated successfully, but these errors were encountered:

All reactions