The borrow
function in the LendingPool
contract incorrectly stores the scaled down debt balance instead of the actual amount borrowed. This discrepancy between the recorded debt and the real debt can lead to several severe issues, including inaccurate user debt calculations, potential for manipulation, and complications during liquidations.
The borrow
function calculates a scaled amount for internal accounting but then uses this scaled amount to update the user's debt balance. This is incorrect. The user's debt should reflect the actual amount borrowed, not a scaled-down version.
Incorrect Debt Storage: The user.scaledDebtBalance
is updated with scaledAmount
, which is the actual amount borrowed divided by the reserve.usageIndex
. This means the user's recorded debt is significantly lower than the actual amount they owe.
Inconsistent Accounting: This discrepancy creates inconsistency in the accounting of the user's debt. While the getUserDebt
function attempts to rectify this by multiplying the scaled balance by the current reserve.usageIndex
, it multiples with wrong user debt.
Inaccurate Debt Calculations: The most immediate impact is that the stored debt is incorrect. While getUserDebt
attempts to compensate, any other function or external system relying on user.scaledDebtBalance
directly will receive incorrect information.
Potential for Manipulation: This discrepancy can be exploited. Because the user's recorded debt is lower than their actual debt, they might be able to interact with other parts of the protocol (or other protocols) in ways that are detrimental to the system's overall health. For example, they might be able to borrow more than they should be allowed to.
Complications during Liquidations: Liquidations become significantly more complex. Because the recorded debt is incorrect, the liquidation process may not function as intended, potentially allows liquidatable users to escape for liquidaton and leading to losses for the protocol.
Alice borrows 100 units of an asset.
The reserve.usageIndex
is 1.1 * 10**27
.
The borrow
function calculates scaledAmount = 100 / 1.1 = 90.91
(approximately).
Alice's user.scaledDebtBalance
is updated to 90.91.
Alice's actual debt is 100, but the protocol records it as 90.91.
Later, when Alice wants to repay or checked for liquidation threshold, the protocol will consider her debt as 90.91 instead of 100.
Use this guide to intergrate foundry into your project: foundry
Create a new file FortisAudits.t.sol
in the test
directory.
Add the following gist code to the file: Gist Code
Run the test using forge test --mt test_FortisAudits_IncorrectDebtStorageInLendingPool -vvvv
.
Logs before the fix:
Logs after the fix:
To mitigate this issue, store the actual amount borrowed in user.scaledDebtBalance
, not the scaled-down version. Remove rayDiv
in the borrow
function. This ensures that the user's debt balance accurately reflects the amount they owe, preventing potential issues with debt calculations, liquidations, and other protocol interactions.
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.