Assessment reports>Maia DAO V2 Ecosystem>High findings>Flywheel index mismatch issue during ,optOut
Category: Coding Mistakes

Flywheel index mismatch issue during optOut

High Severity
High Impact
High Likelihood

Description

The optOut function is called to stop accruing bribes for each gauge.

The userGaugeFlywheels[msg.sender][strategy] keeps the all flywheel addresses that were optIn for the msg.sender and strategy address. Also, the userGaugeflywheelId[msg.sender][strategy][flywheel] keeps the corresponding index of flywheel in the userGaugeFlywheels array.

During the optOut function execution, there is an optimization if the index of the flywheel address is not the last in the userGaugeFlywheels[msg.sender][strategy] array. To optimize the deletion of the flywheel address from userGaugeFlywheels[msg.sender][strategy], this flywheel address will be rewritten by the last flywheel address and the last element will be popped from the array.

The problem is that userGaugeflywheelId[msg.sender][strategy][flywheel], where flywheel is the address of the last address inside userGaugeFlywheels[msg.sender][strategy], continues to store the index of the last element and is not updated to the new index of the moved address of the flywheel.

function optOut(ERC20 strategy, FlywheelCore flywheel) external {
    FlywheelCore[] storage bribeFlywheels = userGaugeFlywheels[msg.sender][strategy];

    uint256 userFlywheelId = userGaugeflywheelId[msg.sender][strategy][flywheel];

    if (userFlywheelId == 0) revert NotOptedIn();

    flywheel.accrue(strategy, msg.sender);

    flywheelStrategyGaugeWeight[strategy][flywheel] = flywheelStrategyGaugeWeight[strategy][flywheel]
        - bHermesGauges(owner()).getUserGaugeWeight(msg.sender, address(strategy));

    uint256 length = bribeFlywheels.length;
    if (length != userFlywheelId) bribeFlywheels[userFlywheelId - 1] = bribeFlywheels[bribeFlywheels.length - 1];

    bribeFlywheels.pop();
    userGaugeflywheelId[msg.sender][strategy][flywheel] = 0;
}

Impact

The function could experience a malfunction. And if invoked by a user in the future, it might result in the function being reverted, preventing the user from stopping the accrual of their tokens.

Recommendations

We recommend adding code that will update the index value to a new one.

    function optOut(ERC20 strategy, FlywheelCore flywheel) external {
    ...
        uint256 length = bribeFlywheels.length;
        if (length != userFlywheelId) bribeFlywheels[userFlywheelId - 1] = bribeFlywheels[bribeFlywheels.length - 1];
+       userGaugeflywheelId[msg.sender][strategy][bribeFlywheels[length - 1]] = userFlywheelId; 
    ...
    }

Remediation

This issue has been acknowledged by Maia DAO, and a fix was implemented in commit 607537d2.

Zellic © 2025Back to top ↑