Core Contracts

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

Inconsistent Scaled Balance Calculations in `transfer` and `transferFrom`

Summary

The RToken contract’s transfer and transferFrom functions use different scaling methods to calculate the transfer amounts. This inconsistency allows users to exploit whichever method results in a more favorable token amount, potentially causing discrepancies in token balances and unexpected economic behavior.

Vulnerability Details

  • transfer function:

    function transfer(address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
    uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
    return super.transfer(recipient, scaledAmount);
    }
  • transferFrom function:

    function transferFrom(address sender, address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
    uint256 scaledAmount = amount.rayDiv(_liquidityIndex); // @audit-issue using transferFrom will return a different value than transfer()
    return super.transferFrom(sender, recipient, scaledAmount);
    }

Issue

  • The transfer function uses ILendingPool(_reservePool).getNormalizedIncome() for scaling.

  • The transferFrom function uses _liquidityIndex for scaling.

  • These two values may differ, resulting in transferred amounts that are inconsistent depending on which function is used.

Impact

  • Users can exploit the discrepancy to receive more tokens or pay fewer tokens.

  • Potential loss of protocol funds or economic imbalances.

Tools Used

Manual code review.

Recommendations

Use a unified scaling method for both functions to maintain consistency:

  • Option 1: Standardize both to use getNormalizedIncome():

    uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
  • Option 2: Standardize both to use _liquidityIndex if that’s the intended approach:

    uint256 scaledAmount = amount.rayDiv(_liquidityIndex);

This ensures that transfer and transferFrom provide consistent and predictable results.

Updates

Lead Judging Commences

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

RToken::transfer uses getNormalizedIncome() while transferFrom uses _liquidityIndex, creating inconsistent transfer amounts depending on function used

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

RToken::transfer uses getNormalizedIncome() while transferFrom uses _liquidityIndex, creating inconsistent transfer amounts depending on function used

Support

FAQs

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

Give us feedback!