Skip to content
Request an audit

‹ All findings

FluidLocker::_getUnlockingPercentage() incorrectly divides one of the components of the formula by S, leading to always having 80% penalty

Crit/HighSuperfluid Locker System·Sherlock · Streaming · 20th November 2024CodebaseH-1

Summary

FluidLocker::_getUnlockingPercentage() calculates the percentage to unlock, which is the amount given to the user, while the remaining goes to other stakers. The formula incorrectly divides Math.sqrt(unlockPeriod * _SCALER) by SCALER:

solidity
function _getUnlockingPercentage(uint128 unlockPeriod) internal pure returns (uint256 unlockingPercentageBP) {
    unlockingPercentageBP = (
        _PERCENT_TO_BP
            * (
                ((80 * _SCALER) / Math.sqrt(540 * _SCALER)) * (Math.sqrt(unlockPeriod * _SCALER) / _SCALER //@audit this _SCALER should not be here)
                    + 20 * _SCALER
            )
    ) / _SCALER;
}

Root Cause

In FluidLocker:388, it incorrectly divides the term (Math.sqrt(unlockPeriod * _SCALER) by _SCALER.

Internal pre-conditions

None.

External pre-conditions

None.

Attack Path

  1. User unlocks their Fluid from the locker with a duration bigger than 0, unvesting it through the fountain.

Impact

User suffers a big loss, even if they unlock with the maximum period, they will still get 80% penalty.

PoC

The component (Math.sqrt(unlockPeriod _SCALER) / _SCALER) <= sqrt(540 24 3600 1e18) / 1e18 = 0 is always null, so only 20*_SCALER is left, which always yields a 20% unlocking percentage.

Mitigation

Remove the extra _SCALER.

solidity
function _getUnlockingPercentage(uint128 unlockPeriod) internal pure returns (uint256 unlockingPercentageBP) {
    unlockingPercentageBP = (
        _PERCENT_TO_BP
            * (
                ((80 * _SCALER) / Math.sqrt(540 * _SCALER)) * (Math.sqrt(unlockPeriod * _SCALER))
                    + 20 * _SCALER
            )
    ) / _SCALER;
}