The DebtToken.sol
contract’s burn function causes users to pay the wrong amount of interest when repaying debt. The function uses the wrong number to calculate how much interest a user owes, which can change unexpectedly during a transaction. This leads to users potentially paying too much or too little interest.
The root cause of this issue is in the burn function, which is supposed to reduce a user’s debt when they repay it. In lending systems like this, debt grows over time due to interest, tracked by a number called the "usage index." The burn function takes an index as input, which should show the interest rate at the time of repayment. However, it doesn’t use this number correctly.
In the burn function, there’s a part that figures out how much extra debt (interest) a user has gained since their last update. This extra amount is called balanceIncrease
.
index is the number passed to the function, meant to show the interest rate at the moment the burn (repayment) is supposed to happen. In lending protocols like this, the usage index tracks how much interest has built up over time. It starts at 1.0 and grows as interest accrues, say, to 1.1 if 10% interest has accumulated. When burn is called, the index tells the function: “This is the interest level right now.” It’s set by the caller (the reserve pool) to define the exact point in time for the repayment.
borrowIndex
is a fresh number fetched from the lending pool using getNormalizedDebt()
. This number can change if someone else updates the pool during the same transaction block.
The problem is that burn uses borrowIndex
instead of the index it was given. This is different from how the mint function works, which correctly uses the passed index:
In mint, the index keeps things consistent. But in burn, fetching borrowIndex
makes the calculation unpredictable.
Imagine a user’s debt is 100 tokens, and their last recorded index (_userState[from].index)
is 1.0.
The burn function is called with index = 1.1, meaning 10% interest has built up. The expected extra debt should be:
100 * 1.1 - 100 * 1.0 = 10 tokens.
But if getNormalizedDebt()
returns borrowIndex
= 1.2 (because the pool updated), the calculation becomes:
100 * 1.2 - 100 * 1.0 = 20 tokens.
The user’s debt jumps by 20 tokens instead of 10, doubling the interest they owe. This happens because borrowIndex
doesn’t match the index the function was told to use.
In blockchain transactions, many actions can happen in one block. If another transaction updates the lending pool’s index before burn runs, borrowIndex
won’t equal index. This mismatch throws off the interest calculation, and there’s no way for the user or the caller to control it.
If borrowIndex is higher than index, users pay more interest than they should, losing money unfairly.
Incorrect debt balances could mess up the protocol’s accounting, making it harder to manage loans and repayments.
Manual Review
To fix this, update the burn function to use the index parameter instead of fetching borrowIndex.
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.