Core Contracts

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

Normalized income division is applied twice in `RToken`

Summary

When transferring RTokens, the real value of underlying amount will be calculated by dividing normalized income. But this is done twice for all transfer, causing loss of funds for user.

Vulnerability Details

Here in transfer, we can see scaled amount is derived by dividing amount by normalized income:

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

But in _update:

function _update(address from, address to, uint256 amount) internal override {
// Scale amount by normalized income for all operations (mint, burn, transfer)
uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
super._update(from, to, scaledAmount);
}

This is done again. This raises one issue, since RToken inherits OZ's ERC20 contract, and in the parent contract, both transfer and transferFrom will internally call _transfer:

function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}

And _transfer also calls _update to update accounting of token:

function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}

So, this means both RToken::transfer and RToken::transferFrom will call _update anyway, but in transfer, for instance, the transferred amount is scaled already when passing to super.transfer, which will later reach _update, and gets scaled again. This will result in incorrect transfer of amount, and gain or loss for users depending on the normalized income value.

Impact

If normalized income is less than 1, more tokens will be transferred, and vice versa.

Tools Used

Manual review.

Recommendations

Since amount is scaled already in _update, remove those in transfer and transferFrom.

Updates

Lead Judging Commences

inallhonesty Lead Judge 3 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 3 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.