code-423n4 / 2024-03-revert-lend-findings

6 stars 6 forks source link

`V3Vault::_calculateGlobalInterest` Rounding error #474

Closed c4-bot-4 closed 3 months ago

c4-bot-4 commented 4 months ago

Lines of code

https://github.com/code-423n4/2024-03-revert-lend/blob/main/src/V3Vault.sol#L1167-L1195

Vulnerability details

Impact

  1. In the _calculateGlobalInterest() function, the supplyRateX96 is calculated as follows:
supplyRateX96 = supplyRateX96.mulDiv(Q32 - reserveFactorX32, Q32);

The reserveFactorX32 is a value between 0 and 100, representing the percentage of interest that is kept in the protocol for reserves. However, the calculation subtracts reserveFactorX32 from Q32 (which is equal to 2**32), resulting in an incorrect calculation of the supplyRateX96.

Proof of Concept

    function _calculateGlobalInterest()
        internal
        view
        returns (uint256 newDebtExchangeRateX96, uint256 newLendExchangeRateX96)
    {
        uint256 oldDebtExchangeRateX96 = lastDebtExchangeRateX96;
        uint256 oldLendExchangeRateX96 = lastLendExchangeRateX96;

        (, uint256 available,) = _getAvailableBalance(oldDebtExchangeRateX96, oldLendExchangeRateX96);

        uint256 debt = _convertToAssets(debtSharesTotal, oldDebtExchangeRateX96, Math.Rounding.Up);

        (uint256 borrowRateX96, uint256 supplyRateX96) = interestRateModel.getRatesPerSecondX96(available, debt);

        supplyRateX96 = supplyRateX96.mulDiv(Q32 - reserveFactorX32, Q32);

        // always growing or equal
        uint256 lastRateUpdate = lastExchangeRateUpdate;

        if (lastRateUpdate > 0) {
            newDebtExchangeRateX96 = oldDebtExchangeRateX96
                + oldDebtExchangeRateX96 * (block.timestamp - lastRateUpdate) * borrowRateX96 / Q96;
            newLendExchangeRateX96 = oldLendExchangeRateX96
                + oldLendExchangeRateX96 * (block.timestamp - lastRateUpdate) * supplyRateX96 / Q96;
        } else {
            newDebtExchangeRateX96 = oldDebtExchangeRateX96;
            newLendExchangeRateX96 = oldLendExchangeRateX96;
        }
    }

Tools Used

Manual Review

Recommended Mitigation Steps

The correct calculation should be:

supplyRateX96 = supplyRateX96.mulDiv(Q32 - reserveFactorX32, Q32 * 100);

This ensures that the supplyRateX96 is correctly calculated based on the reserve factor percentage.

Assessed type

Decimal

c4-pre-sort commented 3 months ago

0xEVom marked the issue as insufficient quality report

0xEVom commented 3 months ago

reserveFactorX32 is documented as being the "reserve factor multiplied by Q32", not a number between 0 and 100.

c4-judge commented 3 months ago

jhsagd76 marked the issue as unsatisfactory: Invalid