Core Contracts

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

Broken Reward (Interest) Mechanism for Lenders

Summary

The RAAC lending protocol’s RToken contract mishandles scaled vs. unscaled amounts when minting and burning tokens. Instead of minting the scaled amount (principal adjusted for the current liquidityIndex), it mints the full unscaled deposit. Likewise, during burn(), it transfers the unscaled amount instead of the interest-accrued sum. As a result, depositors fail to earn interest properly, negating the core function of the lending protocol.

Vulnerability Details

1. Correct Interest Accrual Model

  • Deposits:

    1. Convert the user’s deposit to a “scaled amount” by dividing by liquidityIndex.

    2. Mint that scaled amount of RTokens.

  • Withdrawals:

    1. Convert the user’s scaled RToken balance back into an underlying amount by multiplying by liquidityIndex—reflecting principal + accrued interest.

Simple Example

  • User deposits 100 tokens at liquidityIndex = 1.1.

    • Should receive 100 / 1.1 ≈ 90.9 RTokens.

  • Later, if liquidityIndex grows to 1.2, the user’s 90.9 RTokens should yield 90.9 * 1.2 = 109 tokens on withdrawal (9 tokens of interest).

2. Actual Broken Implementation

  1. RToken::mint (unscaled mint)

    uint256 amountScaled = amountToMint.rayDiv(index); // correct scaled
    _mint(onBehalfOf, amountToMint.toUint128()); // incorrectly uses unscaled amount
    • The user is minted 100 RTokens instead of 90.9.

  2. RToken::burn (unscaled transfer)

    uint256 amountScaled = amount.rayMul(index); // the correct scaled calculation
    _burn(from, amount.toUint128());
    IERC20(_assetAddress).safeTransfer(receiverOfUnderlying, amount); // wrongly transfers unscaled
    • The user withdraws only 100 tokens when they should have received ~109.

Impact

  • Loss of Interest: Depositors never see the accrued amount reflected in withdrawals.

  • Overminting: The user initially receives too many RTokens, but it doesn’t help them in the end, since withdrawal also ignores interest.

3. Similar Issue in DebtToken::burn

In DebtToken::burn, the contract also calls _burn(from, amount.toUint128()) instead of using the scaled amount. Although this primarily affects borrowers rather than lenders, it is the same scaled/unscaled bug that disrupts consistent accounting across the protocol.

Impact

Interest Accrual is Broken: Lenders fail to collect interest, undermining the protocol’s primary incentive to deposit.

Recommendations

  1. Use Scaled Amounts in RToken::mint:

    - _mint(onBehalfOf, amountToMint.toUint128());
    + _mint(onBehalfOf, amountScaled.toUint128());
  2. Use Scaled Amounts in RToken::burn:

    - safeTransfer(receiverOfUnderlying, amount);
    + safeTransfer(receiverOfUnderlying, amountScaled);
  3. Address DebtToken::burn Similarly:

    - _burn(from, amount.toUint128());
    + _burn(from, scaledAmount.toUint128());
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

RToken::burn incorrectly burns amount (asset units) instead of amountScaled (token units), breaking token economics and interest-accrual mechanism

DebtToken::burn incorrectly burns amount (asset units) instead of amountScaled (token units), breaking token economics and interest-accrual mechanism

RToken::mint should mint the amountScaled not the amountToMint

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

RToken::burn incorrectly burns amount (asset units) instead of amountScaled (token units), breaking token economics and interest-accrual mechanism

DebtToken::burn incorrectly burns amount (asset units) instead of amountScaled (token units), breaking token economics and interest-accrual mechanism

RToken::mint should mint the amountScaled not the amountToMint

Support

FAQs

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

Give us feedback!