Summary
The ReserveLibrary.getNormalizedDebt function should return normalized debt, however it returns current usageIdex.
Vulnerability Details
The following ReserveLibrary.getBorrowRate(), ReserveLibrary.getLiquidityRate() retrieves totalDebt from ReserveLibrary.getNormalizedDebt function and totalDebt refers to total normalized debt.
function getBorrowRate(ReserveData storage reserve,ReserveRateData storage rateData) internal view returns (uint256) {
>> uint256 totalDebt = getNormalizedDebt(reserve, rateData);
uint256 utilizationRate = calculateUtilizationRate(reserve.totalLiquidity, totalDebt);
return calculateBorrowRate(rateData.primeRate, rateData.baseRate, rateData.optimalRate, rateData.maxRate, rateData.optimalUtilizationRate, utilizationRate);
}
function getLiquidityRate(ReserveData storage reserve,ReserveRateData storage rateData) internal view returns (uint256) {
>> uint256 totalDebt = getNormalizedDebt(reserve, rateData);
uint256 utilizationRate = calculateUtilizationRate(reserve.totalLiquidity, totalDebt);
return calculateLiquidityRate(utilizationRate, rateData.currentUsageRate, rateData.protocolFeeRate, totalDebt);
}
However, ReserveLibrary.getNormalizedDebt function doesn't return total normalized debt. It returns the current usageIdex. This could result incorrect calculation for utilizationRate.
utilizationRate is used for base calculations of the library and this impacts to entire calculations of library.
* @notice Gets the normalized debt of the reserve.
* @param reserve The reserve data.
* @return The normalized debt (in underlying asset units).
*/
function getNormalizedDebt(ReserveData storage reserve, ReserveRateData storage rateData) internal view returns (uint256) {
uint256 timeDelta = block.timestamp - uint256(reserve.lastUpdateTimestamp);
if (timeDelta < 1) {
return reserve.totalUsage;
}
@> return calculateCompoundedInterest(rateData.currentUsageRate, timeDelta).rayMul(reserve.usageIndex);
}
Impact
The several calculations such as rateData.currentUsageRate and rateData.currentLiquidityRate will be incorrect and breaks the protocol's sustainability.
Tools Used
Manual Review
Recommendations
Multiply reserve.totalUsage to the return value:
/**
* @notice Gets the normalized debt of the reserve.
* @param reserve The reserve data.
* @return The normalized debt (in underlying asset units).
*/
function getNormalizedDebt(ReserveData storage reserve, ReserveRateData storage rateData) internal view returns (uint256) {
uint256 timeDelta = block.timestamp - uint256(reserve.lastUpdateTimestamp);
if (timeDelta < 1) {
return reserve.totalUsage;
}
- return calculateCompoundedInterest(rateData.currentUsageRate, timeDelta).rayMul(reserve.usageIndex);
+ uint256 currentUsageIndex = calculateCompoundedInterest(rateData.currentUsageRate, timeDelta).rayMul(reserve.usageIndex);
+ return reserve.totalUsage.rayMul(currentUsageIndex);
}