Core Contracts

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

Incorrect Scaling in burn Function

Summary

The burn function in the RToken contract incorrectly scales the amount to burn using rayMul instead of rayDiv when calculating amountScaled, leading to an inflated burn amount that does not accurately reflect the underlying asset units intended to be burned. This fully valid medium-impact, medium-likelihood vulnerability could result in excessive token burns, reducing user balances more than intended and potentially disrupting the lending protocol’s balance sheet by transferring incorrect amounts of the underlying asset.

Vulnerability Details

The burn function is designed to reduce a user’s RToken balance and transfer the corresponding underlying asset amount, scaled by the liquidity index:

Issue:

amount is the underlying asset amount to burn (e.g., crvUSD units).
amountScaled = amount.rayMul(index) multiplies amount by the liquidity index (e.g., 1.1e27 for 10% interest), inflating it (e.g., 1,000 * 1.1e27 = 1.1e30), which is incorrect for burning scaled tokens.
Correct scaling should use rayDiv to convert underlying units to scaled RToken units (e.g., 1,000 / 1.1e27 ≈ 909), matching Aave’s AToken pattern where _burn expects scaled amounts.
Current logic burns amount directly (_burn(from, amount.toUint128())), ignoring amountScaled, but returns amount as the scaled amount, creating inconsistency and potential future misuse.

Scenario:

User has 1,100 RToken (underlying value) with index = 1.1e27, scaled balance = 1,000.
burn called with amount = 1,100 (underlying units).
amountScaled = 1,100.rayMul(1.1e27) ≈ 1.21e30 (incorrectly huge), but _burn uses 1,100 directly.
Intended: amountScaled = 1,100.rayDiv(1.1e27) ≈ 1,000, burning 1,000 scaled tokens.
Transfers 1,100 crvUSD correctly but burns wrong scaled amount, misaligning balances.

Analysis: The use of rayMul in amountScaled and bypassing it in _burn shows a clear scaling error, inconsistent with RToken’s interest-bearing design, leading to incorrect accounting.

Impact

The incorrect scaling in burn could over-burn RToken balances (e.g., 1,100 instead of 1,000 scaled tokens for $1,100 in a $10M pool), a medium-impact issue as it disrupts user balances and protocol accuracy without immediate fund loss. The returned amountScaled misleads external systems, potentially affecting $1M+ in downstream calculations (e.g., pool health). The medium likelihood reflects frequent burn calls in lending operations, making this a persistent risk in active use.

Tools Used

Manual Code Review: Confirmed burn should use rayDiv to scale underlying to scaled units, aligning with mint and balanceOf, revealing the error in logic and return values.

Recommendations

Correct the scaling in burn to use rayDiv and burn the scaled amount:

function burn(
address from,
address receiverOfUnderlying,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256) {
if (amount == 0) {
return (0, totalSupply(), 0);
}
uint256 userBalance = balanceOf(from);
if (amount > userBalance) {
amount = userBalance;
}
uint256 amountScaled = amount.rayDiv(index); // Correct scaling
if (amountScaled == 0) revert InvalidAmount();
_userState[from].index = index.toUint128();
_burn(from, amountScaled.toUint128()); // Burn scaled amount
if (receiverOfUnderlying != address(this)) {
IERC20(_assetAddress).safeTransfer(receiverOfUnderlying, amount);
}
emit Burn(from, receiverOfUnderlying, amount, index);
return (amountScaled, totalSupply(), amount); // Return scaled amount burned
}
Updates

Lead Judging Commences

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

RToken::burn incorrectly calculates amountScaled using rayMul instead of rayDiv, causing incorrect token burn amounts and breaking the interest accrual mechanism

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

RToken::burn incorrectly calculates amountScaled using rayMul instead of rayDiv, causing incorrect token burn amounts and breaking the interest accrual mechanism

Support

FAQs

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