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);
}