Summary
balanceIncrease is not correctly calculated when mint DebtToken.
Vulnerability Details
DebtToken balance represents user's debt, when mint DebtToken tokens, if _userState[onBehalfOf].index is less than the usage index at the time of minting, balanceIncrease is computed to reflect the accrued debt.
DebtToken.sol::mint()
uint256 amountScaled = amount.rayDiv(index);
if (amountScaled == 0) revert InvalidAmount();
uint256 scaledBalance = balanceOf(onBehalfOf);
bool isFirstMint = scaledBalance == 0;
@> uint256 balanceIncrease = 0;
@> if (_userState[onBehalfOf].index != 0 && _userState[onBehalfOf].index < index) {
@> balanceIncrease = scaledBalance.rayMul(index) - scaledBalance.rayMul(_userState[onBehalfOf].index);
@> }
_userState[onBehalfOf].index = index.toUint128();
uint256 amountToMint = amount + balanceIncrease;
The problem is that balanceIncrease is incorrectly calculated, DebtToken overrides ERC20's _update() and balanceOf().
In _update(), user balance is stored as amount / index in _balances[user].
DebtToken.sol::_update()
function _update(address from, address to, uint256 amount) internal virtual override {
if (from != address(0) && to != address(0)) {
revert TransfersNotAllowed();
}
uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedDebt());
super._update(from, to, scaledAmount);
emit Transfer(from, to, amount);
}
In balanceOf(), user balance is returned as _balances[user] * index.
DebtToken.sol::balanceOf()
function balanceOf(address account) public view override(ERC20, IERC20) returns (uint256) {
uint256 scaledBalance = super.balanceOf(account);
return scaledBalance.rayMul(ILendingPool(_reservePool).getNormalizedDebt());
}
Therefore, in mint(), balanceIncrease is actually computed as amount / index0 * index1 * index1 - amount / index0 * index1 * index0, that is, the value is wrongly multiplied by index.
Impact
balanceIncrease is wrongly calculated, user will bear more debt than expected.
Tools Used
Manual Review
Recommendations
The correct calculation should be:
- balanceIncrease = scaledBalance.rayMul(index) - scaledBalance.rayMul(_userState[onBehalfOf].index);
+ balanceIncrease = scaledBalance - scaledBalance.rayDiv(index).rayMul(_userState[onBehalfOf].index);