Core Contracts

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

A user loses funds when he transfers `RToken`.

Summary

A user loses funds when he transfers RToken.

Vulnerability Details

RToken.sol#_update() function is as follows.

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 function is called when mint, burn and transfer.
Here, it used LendingPool.sol#getNormalizedIncome() function for liquidity index.

File: LendingPool
function getNormalizedIncome() external view returns (uint256) {
return reserve.liquidityIndex;
}

As we can see above, getNormalizedIncome() returns old liquidityIndex, not updated index with currentTime.
And liquidityIndex is updated with following code.

File: ReserveLibrary.sol
function updateReserveInterests(ReserveData storage reserve,ReserveRateData storage rateData) internal {
@> uint256 timeDelta = block.timestamp - uint256(reserve.lastUpdateTimestamp);
if (timeDelta < 1) {
return;
}
uint256 oldLiquidityIndex = reserve.liquidityIndex;
if (oldLiquidityIndex < 1) revert LiquidityIndexIsZero();
// Update liquidity index using linear interest
@> reserve.liquidityIndex = calculateLiquidityIndex(
rateData.currentLiquidityRate,
@> timeDelta,
reserve.liquidityIndex
);
// Update usage index (debt index) using compounded interest
reserve.usageIndex = calculateUsageIndex(
rateData.currentUsageRate,
timeDelta,
reserve.usageIndex
);
// Update the last update timestamp
reserve.lastUpdateTimestamp = uint40(block.timestamp);
emit ReserveInterestsUpdated(reserve.liquidityIndex, reserve.usageIndex);
}

Impact

Therefore, if a user transfers RToken, he uses old liquidity index. So more scaledAmount is transfered.
This is user's loss.

Tools Used

Manual review

Recommendations

Modify LendingPool.sol#getNormalizedIncome() to return current liquidity index.

Updates

Lead Judging Commences

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

LendingPool::getNormalizedIncome() and getNormalizedDebt() returns stale data without updating state first, causing RToken calculations to use outdated values

Support

FAQs

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

Give us feedback!