Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Invalid

During the repay user has to pay way higher interest.

Summary

When the users call the function LendingPool::repay to repay there borrowed amount than they have to pay way higher interest then they should be.

Vulnerability Details

  • User called borrow and he borrowed 10000 tokens at the usageIndex= 1.05.

  • Now calls repay function with 11000 as amount, and the current usageIndex = 1.09

  • Call execution will go as LendingPool::repay => _repay => DebtToken.burn

  • If we look at the burn function
    It first calculates the userBalance = balance * usageIndex = 10000 * 1.09 = 10,900.
    If amount > userBalance then amount = userBalance = 10,900.
    Then this amount of DebtToken in burnt and the this amount variable is returned to the LendingPool::repay.

  • Then the returned value is stored by amountScaled and this amount of asset tokens has been sent by the user to the RToken address as the debt.

IERC20(reserve.reserveAssetAddress).safeTransferFrom(msg.sender, reserve.reserveRTokenAddress, amountScaled);

But due to miscalculation the user has to pay very high interest, as the interest the user has to pay is =
10000(1.09(Index during Repayment) -1.05(index During Borrowing)) = 0.04 * 10,000 = 400 , and user has payed interest as 900.

Impact

Loss for the Borrowers as they are paying way higher interest due to incorrect calcualtions.

Tools Used

Manual review

Recommendations

function burn(
address from,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256, uint256) {
if (from == address(0)) revert InvalidAddress();
if (amount == 0) {
return (0, totalSupply(), 0, 0);
}
uint256 userBalance = balanceOf(from);
+ uint256 scaledBalance = userBalance/index;
uint256 balanceIncrease = 0;
if (_userState[from].index != 0 && _userState[from].index < index) {
uint256 borrowIndex = ILendingPool(_reservePool).getNormalizedDebt();
- balanceIncrease = userBalance.rayMul(borrowIndex) - userBalance.rayMul(_userState[from].index);
- amount = amount;
+ balanceIncrease = scaledBalance.rayMul(borrowIndex) - scaledBalance.rayMul(_userState[from].index);
+ amount = scaledBalance+ balanceIncrease;
}
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
uint256 amountScaled = amount.rayDiv(index);
if (amountScaled == 0) revert InvalidAmount();
_burn(from, amount.toUint128());
emit Burn(from, amountScaled, index);
return (amount, totalSupply(), amountScaled, balanceIncrease);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

DebtToken::burn calculates balanceIncrease (interest) but never applies it, allowing borrowers to repay loans without paying accrued interest

Interest IS applied through the balanceOf() mechanism. The separate balanceIncrease calculation is redundant/wrong. Users pay full debt including interest via userBalance capping.

inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

DebtToken::burn calculates balanceIncrease (interest) but never applies it, allowing borrowers to repay loans without paying accrued interest

Interest IS applied through the balanceOf() mechanism. The separate balanceIncrease calculation is redundant/wrong. Users pay full debt including interest via userBalance capping.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.