code-423n4/2024-07-loopfi-validation

Rate Integrity Compromise During and After Frozen Periods in `GaugeV3.sol`

Closed this issue · 0 comments

Lines of code

https://github.com/code-423n4/2024-07-loopfi/blob/57871f64bdea450c1f04c9a53dc1a78223719164/src/quotas/GaugeV3.sol#L78-L92

Vulnerability details

Vulnerability Detail

The GaugeV3 contract, which is responsible for managing quota rates based on user votes, contains an issue in its epoch update mechanism. The problem lies in the _checkAndUpdateEpoch function, which is called by various operations including voting and unvoting.

The current implementation of _checkAndUpdateEpoch is as follows:

function _checkAndUpdateEpoch() internal {
    uint16 epochNow = IGearStakingV3(voter).getCurrentEpoch(); // U:[GA-14]

    if (epochNow > epochLastUpdate) {
        epochLastUpdate = epochNow; // U:[GA-14]

        if (!epochFrozen) {
            // The quota keeper should call back to retrieve quota rates for needed tokens
            _poolQuotaKeeper().updateRates(); // U:[GA-14]
        }

        emit UpdateEpoch(epochNow); // U:[GA-14]
    }
}

The issue arises from the fact that epochLastUpdate is always updated to the current epoch, regardless of whether the contract is in a frozen state or not. However, the actual rate update (via _poolQuotaKeeper().updateRates()) only occurs when the contract is not frozen.
This creates a discrepancy between the recorded last update epoch and the actual last rate update, which becomes problematic when the contract transitions from a frozen to an unfrozen state.

The current implementation allows voting to continue during frozen periods, but doesn't update rates, leading to a discrepancy between voting activity and actual rate adjustments.

Impact

  • Outdated Rates: During frozen periods and immediately after unfreezing, the system operates with outdated rates that don't reflect current voting state.
  • Economic Implications: Users interacting with the system during these periods may be unfairly advantaged or disadvantaged based on outdated rates.
  • Compressed Rate Updates: When unfreezing, multiple epochs of voting are compressed into a single rate update, potentially causing abrupt and significant rate changes.

Proof of Concept

Scenario demonstrating the issue:

  • GaugeV3 is operational at epoch 100 with current rates.
  • The contract is frozen at epoch 101.
  • Users continue voting during epochs 102-106, but rates remain unchanged.
  • The contract is unfrozen at the start of epoch 107.
  • _checkAndUpdateEpoch is called:
    It updates epochLastUpdate to 107.
    It triggers a rate update.
    This update compresses all voting activity from epochs 101-106 into a single rate change.
  • Users interacting with the system during epochs 101-107 are subject to outdated rates, and the sudden rate change at 107 may cause unexpected economic impacts.

Tools Used

Manual code review

Recommended Mitigation Steps

  • Block voting and unvoting during frozen periods
  • Implement a grace period after unfreezing

Assessed type

Other