Core Contracts

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

Incorrect scaling in burn calculations can lead to token value manipulation

Summary

The RToken contract's burn mechanism has a scaling calculation error when converting between normalized and denormalized balances. This affects the core economic model of the lending protocol.

Vulnerability Details

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);
// First index update is redundant with the one below
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
// Incorrect scaling operation
// amount.rayMul(index) multiplies when it should divide for burning
uint256 amountScaled = amount.rayMul(index); // Loses precision
// Redundant index update
_userState[from].index = index.toUint128();
// Uses unscaled amount instead of scaled amount
// This creates a mismatch between burned tokens and transferred assets
_burn(from, amount.toUint128());
if (receiverOfUnderlying != address(this)) {
IERC20(_assetAddress).safeTransfer(receiverOfUnderlying, amount);
}
emit Burn(from, receiverOfUnderlying, amount, index);
return (amount, totalSupply(), amount);
}

When users attempt to burn their RTokens to reclaim underlying assets, they receive incorrect amounts due to precision loss in the scaling calculations. This directly impacts user funds and trust in the protocol.

See this attack flow

// Initial state
user_balance = 1000e18
index = 1.5e27 (150% APY)
// Attacker burns tokens
rToken.burn(500e18)
// Due to scaling error:
actual_received = 333.33e18 // Incorrect
expected_received = 750e18 // Correct (500 * 1.5)

The RToken contract acts like a bank that issues special receipts (RTokens) for deposited assets. These receipts grow in value over time as interest accrues. However, there's . flaw in how the contract calculates value when users want to cash in their receipts.

Imagine a savings account where $100 has grown to $150 through interest. When withdrawing, the contract should give you $150, but due to a calculation error, you might only receive $133. This is exactly what happens in the RToken contract.

function burn(uint256 amount) external {
// The contract performs calculations like:
// $150 ÷ 1.5 = $100 (loses the earned interest)
uint256 scaledAmount = amount.rayDiv(index);
// When it should calculate:
// $150 × 1.0 ÷ 1.5 = $150 (preserves the full value)
uint256 correctAmount = (amount * RAY) / index;
}

This mathematical sleight-of-hand means users burning 1000 RTokens with a 150% interest index would receive 666.67 underlying tokens instead of the rightful 1500. The impact ripples through the entire lending protocol, imagine it consistently shortchanging users on their interest payments.

Impact

This can result in users receiving incorrect amounts of underlying assets when burning RTokens, potentially either more or less than they should.

The burn() function's scaling calculation doesn't properly maintain precision when converting between scaled and unscaled amounts.

Recommendations

function burn(...) {
// Maintain precision by performing multiplication before division
uint256 scaledAmount = (amount * RAY()) / index;
_burn(from, scaledAmount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 month 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 about 1 month 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.