Core Contracts

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

Incorrect transfer scaling due to outdated `_liquidityIndex` and inconsistent scaling

Summary

The RToken::transfer and RToken::transferFrom functions apply scaling when transferring tokens, but the scaling mechanism is inconsistent due to the _liquidityIndex not being updated. The RToken::updateLiquidityIndex function, responsible for modifying _liquidityIndex, is never invoked, resulting in a static value that may lead to incorrect transfer calculations.

Vulnerability Details

Problem description

  • In RToken::transfer, the transferred amount is scaled down using ILendingPool(_reservePool).getNormalizedIncome().

  • In RToken::transferFrom, the transferred amount is scaled down using _liquidityIndex.

  • _liquidityIndex is intended to be updated by RToken::updateLiquidityIndex, but since this function is only callable by the reserve pool and is never invoked, _liquidityIndex remains constant.

  • This discrepancy can lead to incorrect calculations for transfer and transferFrom amounts, resulting in potential loss or misrepresentation of value.

function transfer(address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
// @audit-issue scaling down by `ILendingPool(_reservePool).getNormalizedIncome()`
uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
return super.transfer(recipient, scaledAmount);
}
function transferFrom(address sender, address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
// @audit-issue scaling down by `_liquidityIndex`
uint256 scaledAmount = amount.rayDiv(_liquidityIndex);
return super.transferFrom(sender, recipient, scaledAmount);
}
function updateLiquidityIndex(uint256 newLiquidityIndex) external override onlyReservePool {
if (newLiquidityIndex < _liquidityIndex) revert InvalidAmount();
_liquidityIndex = newLiquidityIndex;
emit LiquidityIndexUpdated(newLiquidityIndex);
}

Steps to reproduce

  1. Call transfer or transferFrom on RToken.

  2. Observe that the scaled amount is calculated based on a static _liquidityIndex that does not reflect real-time liquidity changes.

  3. Since _liquidityIndex is never updated, the scaling logic remains outdated, leading to unintended behavior.

Impact

  • Incorrect transfer calculations: Token transfers may not properly reflect the intended amounts.

  • Potential loss of value: Due to outdated scaling, users may receive fewer tokens than expected.

  • Operational inefficiency: The protocol relies on a mechanism that does not function as intended.

Tools Used

Manual Review, VSCode

Recommendations

  1. Invoke updateLiquidityIndex within the reserve pool logic to ensure _liquidityIndex is regularly adjusted based on actual liquidity conditions.

  2. Standardize the scaling mechanism by aligning transfer and transferFrom to use the same scaling factor consistently.

  3. Add fail-safes to prevent transfers if _liquidityIndex is outdated, ensuring users are not affected by incorrect scaling.

Updates

Lead Judging Commences

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

RToken::updateLiquidityIndex() has onlyReservePool modifier but LendingPool never calls it, causing transferFrom() to use stale liquidity index values

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

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

RToken::updateLiquidityIndex() has onlyReservePool modifier but LendingPool never calls it, causing transferFrom() to use stale liquidity index values

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.