Miscalculation of dynamic interest rates due to
i) Incorrect logic in getNormalizedDebt
and getNormalizedIncome
ii ) not factoring the accrued interests (computedDebt
, computedLiquidity
) while calculating utilization rate.
Contract : LendingPool
Related functions : updateInterestRatesAndLiquidity
, calculateUtilizationRate
UtilizationRate is a critical parameter as it decides how interest rates are dynamically adjusted.
Popular protocols like Aave and Compound calculate utilization by using up-to-date,
accrued values of total debt and total liquidity.
This helps ensure that the dynamic interest rate adjustments
reflect the current state of the market.
Core Issues in updateInterestRatesAndLiquidity
A) Incorrect logic in getNormalizedDebt
and getNormalizedIncome
getNormalizedDebt
and getNormalizedIncome
are expected to return
totalDebt and totalLiquidity in the system accounting for the accrued interest rates.
Issue Identified:
The current getNormalizedDebt
and getNormalizedIncome
functions only compute updated indices
(compounded or linear factors).
They ignore the stored totalUsage
and totalLiquidity
, respectively.
This means the effective debt and liquidity are not correctly computed.
B) Computed vs. Stored Values
Although the RAAC LendingPool calculates computedDebt
and computedLiquidity
(which include accrued interest)
it then ignores these values when calculating the utilization rate.
Instead, it uses the raw stored reserve.totalLiquidity
and reserve.totalUsage
(which excludes accrued interest)
https://github.com/Cyfrin/2025-02-raac/blob/main/contracts/libraries/pools/ReserveLibrary.sol#L307
This can lead to an underestimation of the effective utilization of the reserve.
This mismatch in utilization calculation is critical
because it directly affects how interest rates are adjusted in the subsequent steps
calculateBorrowRate
and calculateLiquidityRate
Dynamic Example:
Imagine a reserve in which:
Liquidity Rate = 5 % per year and
Usage Rate = 20 % per year
Stage 1 : Initial reserve status
Total Liquidity available = 1,000 tokens
Stored Total Usage (Debt) = 500 tokens
Stage 2: After an year (Accrued Interest):
Due to accrued interests,
the normalized (effective) liquidity = 1,050 tokens
the **normalized (effective) debt = ** 600 tokens
The current implementation calculates **utilization **as below
Miscalculated Utilization
= 500 / (1000 + 500) = 33.3 %
However the correct effective utilization should be calculated using the accrued values:
Effective Utilization
= 600 / (1050 + 600) = 36.36 %
the utilization rate is underestimated by about 3.3 percentage points,
the dynamic interest rate formulas in the subsequent steps will calculate a borrow rate that is too low
relative to the actual economic stress on the reserve.
The risk appears lower than it really is.
Improper interest rate adjustments results in
i)_ Encourage excessive borrowing_
ii) Delay repayments
iii) Unfair incentives for Liquidity providers
iv) Undercollateralization and eventual insolvency
Impact : High
Likelihood : High
Fix getNormalizedDebt
by taking into account the reserve.totalUsage
along with the compounded factor.
A similar correction should be made for getNormalizedIncome
as well.
Utilise the computedDebt
and computedLiquidity
(which includes the accrued interest)
while calculating utilizationrate
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.