Inconsistent Use of lastCumulativeRate in depositTokens() and withdraw() Functions in Borrowings Contract
Summary
The depositTokens() and withdraw() functions in the Borrowing contract exhibit inconsistent use of the lastCumulativeRate. This inconsistency arises because the lastCumulativeRate is used in calculations before it is updated, leading to potential inaccuracies in interest calculations among multiple transactions.
Root Cause
In both depositTokens() and withdraw() functions, lastCumulativeRate is passed to BorrowLib.deposit() and BorrowLib.withdraw() respectively, before calling calculateCumulativeRate() to update it.
totalNormalizedAmount = BorrowLib.deposit(
BorrowLibDeposit_Params(
LTV,
APR,
@> lastCumulativeRate,
totalNormalizedAmount,
exchangeRate,
ethPrice,
lastEthprice
),
depositParam,
Interfaces(treasury, globalVariables, usda, abond, cds, options),
assetAddress
);
//Call calculateCumulativeRate() to get currentCumulativeRate
@> calculateCumulativeRate();
lastEventTime = uint128(block.timestamp); BorrowWithdraw_Result memory result = BorrowLib.withdraw(
depositDetail,
BorrowWithdraw_Params(
toAddress,
index,
ethPrice,
exchangeRate,
withdrawTime,
lastCumulativeRate,
totalNormalizedAmount,
bondRatio,
collateralRemainingInWithdraw,
collateralValueRemainingInWithdraw
),
Interfaces(treasury, globalVariables, usda, abond, cds, options)
);
.
.
lastEventTime = uint128(block.timestamp);}
// Call calculateCumulativeRate function to get the interest
@> calculateCumulativeRate();And the lastCumulativeRate is used to calculate normalizedAmount and borrowerDebt
// Calculate normalizedAmount
uint256 normalizedAmount = calculateNormAmount(tokensToMint, libParams.lastCumulativeRate); // Calculate th borrower's debt
uint256 borrowerDebt = calculateDebtAmount(depositDetail.normalizedAmount, params.lastCumulativeRate);This results in using an outdated cumulative rate for the first transaction, while subsequent transactions use the updated rate, causing discrepancies.
Attack Path
- Allow a significant time gap since the last transaction to accumulate interest.
- Execute two simultaneous transactions (e.g., deposits or withdrawals).
- Observe that the first transaction uses an outdated
lastCumulativeRate, while the second uses the updated rate.
Impact
The first transaction uses an outdated cumulative rate, while subsequent transactions use the updated cumulative rate, leading to incorrect interest calculations. This discrepancy causes inconsistencies in the normalized deposit amount and borrower debt, potentially affecting the protocol's financial accuracy .
Mitigation
Ensure that calculateCumulativeRate() is called at the beginning of both the depositTokens() and withdraw() functions to update lastCumulativeRate before it is used in any calculations. This ensures that all transactions use the most current cumulative rate.