Core Contracts

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

Users Left with Small Unpayable Debts Due to Rounding Issue in RAAC Lending Protocol

Summary

The RAAC lending protocol has a problem where tiny debts (called "dust") don’t get cleaned up properly because the DebtToken and LendingPool contracts use different rules for what counts as "too small." This leaves users stuck with small amounts of debt they can’t fully repay, locking their assets and causing frustration.

Vulnerability Details

The issue comes from two contracts in the RAAC lending protocol not agreeing on how to handle small leftover debts. The DebtToken contract, which tracks what users owe, sets a limit called DUST_THRESHOLD at 10,000 Wei. The LendingPool contract, which manages lending and repayment, sets its DUST_THRESHOLD at 1,000,000 Wei, a much bigger number.

In DebtToken.sol, the DUST_THRESHOLD is set like this:

uint256 private constant DUST_THRESHOLD = 1e4; // 10,000 Wei

But when users repay debt in the burn function, it doesn’t check or clear amounts below this limit:

function burn(
address from,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256, uint256) {
uint256 userBalance = balanceOf(from);
if (amount > userBalance) {
amount = userBalance;
}
uint256 amountScaled = amount.rayDiv(index);
if (amountScaled == 0) revert InvalidAmount();
_burn(from, amount.toUint128());
...
}
  • If a user has 50,000 Wei of debt and repays 49,999 Wei, they’re left with 1 Wei.

    The code doesn’t say, “If what’s left is less than 10,000 Wei, burn it all.” So, that 1 Wei stays.

In LendingPool, the DUST_THRESHOLD is higher:

uint256 private constant DUST_THRESHOLD = 1e6; // 1,000,000 Wei

It’s used in the closeLiquidation function to let users stop liquidation if their debt is tiny

function closeLiquidation() external nonReentrant whenNotPaused {
...
uint256 userDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex);
if (userDebt > DUST_THRESHOLD) revert DebtNotZero();
...
}

Here, users can exit liquidation only if their debt is 1,000,000 Wei or less. But if it’s between 10,000 and 1,000,000 Wei, it’s too big for DebtToken to ignore but too small for LendingPool to force liquidation.

Imagine a user owes 50,000 Wei:

  • They repay 49,999 Wei, leaving 1 Wei.

  • DebtToken doesn’t burn that 1 Wei because nothing tells it to clear amounts below 10,000 Wei.

  • In LendingPool, that 1 Wei is way below 1,000,000 Wei, so it’s not a problem for liquidation—but the user still can’t get rid of it.

The repay function in LendingPool calls burn:

function _repay(uint256 amount, address onBehalfOf) internal {
...
(uint256 amountScaled, uint256 newTotalSupply, uint256 amountBurned, uint256 balanceIncrease) =
IDebtToken(reserve.reserveDebtTokenAddress).burn(onBehalfOf, amount, reserve.usageIndex);
...
}

If the leftover debt is tiny (e.g., 1 Wei), it stays because burn doesn’t finish the job.

This mismatch means:

  • DebtToken thinks 10,000 Wei is the cutoff for tiny debts.

  • LendingPool thinks 1,000,000 Wei is the cutoff, leaving a gap where debts between 10,000 and 1,000,000 Wei don’t get handled properly.

Impact

  1. People repay almost all their debt but get stuck with tiny amounts (like 1 Wei). They can’t fully close their account because DebtToken doesn’t wipe out these leftovers.

  2. Users can’t get their RAAC NFTs back (their collateral) because withdrawNFT checks if debt is zero

  3. Debts between 10,000 and 1,000,000 Wei are too big for DebtToken to call dust but too small for LendingPool to liquidate. They just sit there, clogging the system.

Tools Used

Manual Review

Recommendations

  1. Make DUST_THRESHOLD the same in both contracts set both to 1,000,000 Wei. This way, they agree on what’s “too small”

  2. Update the burn function to wipe out debt below DUST_THRESHOLD when users repay most of it:

Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

closeLiquidation allows users to exit liquidation with debt under DUST_THRESHOLD (1e6), potentially accumulating bad debt across multiple users over time

The dust amount remains as debt of the user. This continues to accrue interest and will block complete NFT withdrawals if left unpaid.

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

closeLiquidation allows users to exit liquidation with debt under DUST_THRESHOLD (1e6), potentially accumulating bad debt across multiple users over time

The dust amount remains as debt of the user. This continues to accrue interest and will block complete NFT withdrawals if left unpaid.

Support

FAQs

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

Give us feedback!