Core Contracts

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

Stale Liquidity Index and Incorrect Scaling in `RToken.transferFrom` Function Lead to Under-Transfer of Funds

Summary:

The transferFrom function in the RToken contract suffers from two critical flaws: it uses a statically stored liquidity index instead of the dynamically updated normalized income, and it uses incorrect scaling logic. These combined issues result in users transferring significantly less than intended.

Vulnerability Details:

The transferFrom function has two distinct problems:

  1. Stale Liquidity Index: The function uses the _liquidityIndex, which is only updated via an external function call (updateLiquidityIndex). This index is not automatically updated to reflect the current normalized income as it changes due to accrued interest. Therefore, it will often be outdated.

  2. Incorrect Scaling: The transferFrom function uses rayDiv (division) to scale the transfer amount. This is the opposite of what is required. Since the user's RToken balance is already in underlying form, the intended transfer amount (in underlying asset units) needs to be scaled up to match the RToken balance scale.

function transferFrom(address sender, address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
uint256 scaledAmount = amount.rayDiv(_liquidityIndex); // Incorrect: Should use normalized income and rayMul
return super.transferFrom(sender, recipient, scaledAmount);
}

Impact:

  • Significant Loss of Funds: Users transferring funds via transferFrom will transfer a fraction of the amount they intended, resulting in a substantial loss. The magnitude of the loss is directly related to the difference between the stored _liquidityIndex and the current normalized income.

Proof of Concept:

  1. Alice has a scaled balance of 110 RTokens (representing 100 underlying units with a current normalized income of 1.1).

  2. The stored _liquidityIndex is still at its initial value of 1 * 10**27 (representing a normalized income of 1.0).

  3. Alice approves Bob to transfer 100 underlying units from her account.

  4. Bob calls transferFrom to transfer 100 units from Alice to himself.

  5. The transferFrom function calculates scaledAmount = 100 / 1.0 = 100. This is wrong. It should be 100 * 1.1 = 110.

  6. Bob receives 100 RTokens, even though Alice intended to transfer the equivalent of 100 units at the current normalized income. Bob should receive 110 RTokens.

Recommended Mitigation:

  1. Use Normalized Income: Change the transferFrom function to use the current normalized income from the LendingPool. This will ensure that the transfer amount is correctly scaled to reflect the accrued interest.

  2. Use Correct Scaling: Use rayMul (multiplication) to scale the amount, not rayDiv (division).

function transferFrom(address sender, address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
- uint256 scaledAmount = amount.rayDiv(_liquidityIndex); // Incorrect: Should use normalized income and rayMul
+ uint256 scaledAmount = amount.rayMul(ILendingPool(_reservePool).getNormalizedIncome()); // Correct: Use normalized income and rayMul
return super.transferFrom(sender, recipient, scaledAmount);
}
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

Support

FAQs

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