Severity: Medium
Files Affected
cadence/contracts/FlowALPv1.cdc
Description
updateInterestRates` allocates fees as an instantaneous rate-based deduction:
// FixedRate path:
creditRate = debitRate * (1 - protocolFeeRate)
// KinkCurve path:
debitIncome = totalDebitBalance * debitRate creditRate = (debitIncome - protocolFeeAmount) / totalCreditBalance
But the actual collection functions compute fees using compounding over the elapsed period:
// collectInsurance (line 1098):
debitIncome = totalDebitBalance * (currentDebitRate^timeElapsed - 1.0)
insuranceAmount = debitIncome * insuranceRate
// collectStability (line 1168):
interestIncome = totalDebitBalance * (currentDebitRate^timeElapsed - 1.0)
stabilityAmount = interestIncome * stabilityFeeRate
These diverge for three reasons:
totalDebitBalance changes between collections. The collection formula uses the current totalDebitBalance as if it were constant over the entire period, but deposits, withdrawals, and liquidations change it continuously.
currentDebitRate changes between collections. Utilization changes trigger updateInterestRates, which updates currentDebitRate. The collection formula compounds the current rate over the full elapsed period, not the historical rates that were actually in effect.
- Compounding vs. rate allocation. The rate allocation is a continuous reduction of credit income. The collection formula is a discrete, retroactive calculation applied at collection time. These produce different results for the same inputs. The net effect: the amount collected can be more or less than what was actually allocated through the credit rate reduction, creating accounting drift over time.
Recommendation
Consider using the same formula in both the allocation and collection paths.
Parent Issue: #209