Skip to content

Latest commit

 

History

History
67 lines (56 loc) · 3.93 KB

File metadata and controls

67 lines (56 loc) · 3.93 KB

Lone Wintergreen Rattlesnake

Medium

Inconsistent Utilization Rate Calculations Leading to Interest Rate Discrepancies

Summary

The inconsistency in utilization rate calculations between _addInterest and _calculateInterest functions, and the actual addInterest where one subtracts borrowed amounts from available assets while the other doesn't, This inconsistency leads to incorrect utilization rate calculations and can result in interest accrual issues.

Root Cause

In _addInterest():

    function _addInterest()
        internal
        returns (
            bool _isInterestUpdated,
            uint256 _interestEarned,
            uint256 _feesAmount,
            uint256 _feesShare,
            CurrentRateInfo memory _currentRateInfo
        )
    {
        // Pull from storage and set default return values
        _currentRateInfo = currentRateInfo;

        // store the current utilization rate as previous for next check
        uint256 _totalAssetsAvailable = _totalAssetAvailable(totalAsset, totalBorrow, true);
        _prevUtilizationRate = _totalAssetsAvailable == 0 ? 0 : (UTIL_PREC * totalBorrow.amount) / _totalAssetsAvailable;

        // Calc interest
        InterestCalculationResults memory _results = _calculateInterest(_currentRateInfo);

    }

The vault calls the internal function _totalAssetAvailable to get the total assets available, but this function after getting the total assets substracts totalBorrow.amount from it, while this is a descrepancy issue as the calculation use to get _utilizationRatein _calculateInterest() and addInterest() differs:

uint256 _totalAssetsAvailable = totalAsset.totalAmount(address(externalAssetVault));
        uint256 _newUtilizationRate =
            _totalAssetsAvailable == 0 ? 0 : (UTIL_PREC * totalBorrow.amount) / _totalAssetsAvailable;

as this doesnt substract totalBorrow.amount which means manually calling addInterest() sometimes will skip:

        uint256 _currentUtilizationRate = _prevUtilizationRate;
        uint256 _totalAssetsAvailable = totalAsset.totalAmount(address(externalAssetVault));
        uint256 _newUtilizationRate =
            _totalAssetsAvailable == 0 ? 0 : (UTIL_PREC * totalBorrow.amount) / _totalAssetsAvailable;
        uint256 _rateChange = _newUtilizationRate > _currentUtilizationRate
            ? _newUtilizationRate - _currentUtilizationRate
            : _currentUtilizationRate - _newUtilizationRate;
        if (
            _currentUtilizationRate != 0
                && _rateChange < _currentUtilizationRate * minURChangeForExternalAddInterest / UTIL_PREC
        ) {
            emit SkipAddingInterest(_rateChange);
        } else {
            (, _interestEarned, _feesAmount, _feesShare, _currentRateInfo) = _addInterest();
        }

as _currentUtilizationRate will always be > _newUtilizationRate

Impact

The inconsistency in utilization rate calculations between functions leads to systematically higher _currentUtilizationRate compared to _newUtilizationRate, potentially, causing frequent skipping of interest accruals, as LendingAssetVault.sol also relied on this function to update vaults interest, making the function unreliable, with interest only accruing through external user-triggered functions.

Mitigation

Update both functions to use the standardized calculation