Core Contracts

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

ReservePool fails to implement updateLiquidityIndex function, permanently freezing RToken's transferFrom() scaling at initial value"

Summary

The ReservePool.sol contract fails to implement the updateLiquidityIndex function that is required to update the _liquidityIndex parameter in RToken.sol. This causes RToken::transferFrom() function to permanently use the initial liquidity index value set at deployment, preventing proper interest accrual scaling for these transfers.

Vulnerability Details

The RToken contract relies on the ReservePool to update its liquidity index through the updateLiquidityIndex function:

// RToken.sol
function updateLiquidityIndex(uint256 newLiquidityIndex) external override onlyReservePool {
if (newLiquidityIndex < _liquidityIndex) revert InvalidAmount();
_liquidityIndex = newLiquidityIndex;
emit LiquidityIndexUpdated(newLiquidityIndex);
}

However, the ReservePool contract does not implement this function at all. This means:

The _liquidityIndex in RToken remains at its initial value forever
All transferFrom() calls use this stale initial value for scaling:

function transferFrom(address sender, address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
uint256 scaledAmount = amount.rayDiv(_liquidityIndex); // _liquidityIndex never updates!
return super.transferFrom(sender, recipient, scaledAmount);
}

Impact

High

  • The transferFrom() function will ALWAYS use the initial liquidity index value

  • No interest accrual will be reflected in transferFrom() operations

  • Users will receive incorrect token amounts when using transferFrom()

Likelihood

High

  • The issue is present from deployment

  • Affects all transferFrom() operations

  • No special conditions needed to trigger

  • Will definitely lead to incorrect transfers as soon as any interest accrues

Proof of Concept

N/A - Vulnerability is straight forward and sufficient information has been provided priorly.

Recommendations

  1. Implement updateLiquidityIndex() in ReservePool.sol:

  2. Ensure the function is called whenever interest accrues in the ReservePool

  3. Alternatively, use this functionality instead: ILendingPool(_reservePool).getNormalizedIncome()

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month 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

Support

FAQs

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