Core Contracts

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

Double Scaling in RToken Transfers Leads to Incorrect Transfers

Summary

This bug results in users transferring significantly fewer RTokens than expected, leading to incorrect balance updates and potential loss of funds due to unintended transfer reductions.

Affected Components:

  • transfer function in RToken

  • transferFrom function in RToken

  • _update function in RToken

Vulnerability Description:

The RToken contract implements a scaling mechanism for transferring tokens based on the underlying asset's value. However, due to redundant scaling in both the transfer function and the _update function, the transferred amount is scaled twice, causing an incorrect and lower-than-expected transfer.

Issue Breakdown:

  1. The transfer and transferFrom functions scale the amount using rayDiv(ILendingPool(_reservePool).getNormalizedIncome()) before calling super.transfer().

  2. The _update function, which is invoked on every transfer operation, scales the amount again using the same rayDiv operation before calling super._update().

  3. As a result, the transferred amount is effectively reduced by an additional factor of rayDiv(ILendingPool(_reservePool).getNormalizedIncome()), making it significantly lower than expected.

Relevant Code:

function transfer(address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
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) {
uint256 scaledAmount = amount.rayDiv(_liquidityIndex);
return super.transferFrom(sender, recipient, scaledAmount);
}
function _update(address from, address to, uint256 amount) internal override {
uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
super._update(from, to, scaledAmount);
}

Exploit Scenario:

  • Assume 1 RToken is backed by 2 underlying tokens.

  • A user wants to transfer 2 underlying tokens worth of RTokens.

  • The transfer function scales amount by rayDiv(ILendingPool(_reservePool).getNormalizedIncome()), reducing it to 1 RToken.

  • The _update function then applies the same scaling again, further reducing the transfer amount unexpectedly.

  • The recipient ends up receiving much less than the intended amount.

Impact:

  • Users transferring RTokens experience unintended balance reductions.

  • Contract logic relying on accurate token transfers may fail.

  • Potential financial loss due to incorrect value transfers.

Recommended Fix:

  • Remove the redundant scaling operation from either the transfer function or the _update function.

  • A potential fix:

function _update(address from, address to, uint256 amount) internal override {
super._update(from, to, amount); // Remove additional scaling
}
Updates

Lead Judging Commences

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

RToken::transfer and transferFrom double-scale amounts by dividing in both external functions and _update, causing users to transfer significantly less than intended

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

RToken::transfer and transferFrom double-scale amounts by dividing in both external functions and _update, causing users to transfer significantly less than intended

Support

FAQs

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

Give us feedback!