Overview
in the updateInterestRatesAndLiquidity
the total liquidity and total usage are updated and adjusted accordingly,
*/
function updateInterestRatesAndLiquidity(ReserveData storage reserve,ReserveRateData storage rateData,uint256 liquidityAdded,uint256 liquidityTaken) internal {
if (liquidityAdded > 0) {
reserve.totalLiquidity = reserve.totalLiquidity + liquidityAdded.toUint128();
}
if (liquidityTaken > 0) {
if (reserve.totalLiquidity < liquidityTaken) revert InsufficientLiquidity();
reserve.totalLiquidity = reserve.totalLiquidity - liquidityTaken.toUint128();
}
uint256 totalLiquidity = reserve.totalLiquidity;
uint256 totalDebt = reserve.totalUsage;
uint256 computedDebt = getNormalizedDebt(reserve, rateData);
uint256 computedLiquidity = getNormalizedIncome(reserve, rateData);
uint256 utilizationRate = calculateUtilizationRate(reserve.totalLiquidity, reserve.totalUsage);
rateData.currentUsageRate = calculateBorrowRate(
rateData.primeRate,
rateData.baseRate,
rateData.optimalRate,
rateData.maxRate,
rateData.optimalUtilizationRate,
utilizationRate
);
rateData.currentLiquidityRate = calculateLiquidityRate(
utilizationRate,
rateData.currentUsageRate,
rateData.protocolFeeRate,
totalDebt
);
updateReserveInterests(reserve, rateData);
emit InterestRatesUpdated(rateData.currentLiquidityRate, rateData.currentUsageRate);
}
Accrued Interest Is Not Accounted for in totalUsage and totalLiquidity
The following functions are called:
uint256 computedDebt = getNormalizedDebt(reserve, rateData);
uint256 computedLiquidity = getNormalizedIncome(reserve, rateData);
These functions compute interest but do not update totalUsage and totalLiquidity accordingly.
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);
}
function getNormalizedIncome(ReserveData storage reserve, ReserveRateData storage rateData) internal view returns (uint256) {
uint256 timeDelta = block.timestamp - uint256(reserve.lastUpdateTimestamp);
if (timeDelta < 1) {
return reserve.liquidityIndex;
}
return calculateLinearInterest(rateData.currentLiquidityRate, timeDelta, reserve.liquidityIndex).rayMul(reserve.liquidityIndex);
}
The issue here is both this two functions getNormalizedDebt
contribute to the totalUsage and getNormalizedIncome
contribute to the totalLiquidity
later we calculate the utilizationRate
which uses the totalUsage and totalLiquidity values as shown below
uint256 utilizationRate = calculateUtilizationRate(reserve.totalLiquidity, reserve.totalUsage);
Given that our getNormalizedDebt
and getNormalizedIncome
are just computing the accrued interests without updating the new values of the new totalUsage and the totalLiquidity our utilizationRate is using wrong values that ought to have been increased after the interests are determined based on the liquidity index and usageIndex.
Impact
inaccurate utilization rate
Recommendation
Update totalUsage
and totalLiquidity
After Calculating Normalized Debt and normalized income accordingly.