Core Contracts

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

`DebtToken::balanceOf` Doesn't Align With Aave's VariableDebtToken Implementation

Summary

The DebtToken contract claims to align with Aave's VariableDebtToken implementation but deviates from it by omitting a key zero-check optimization in the balanceOf function. While this doesn't affect mathematical correctness, it represents both a gas inefficiency and a deviation from the documented specification.

Vulnerability Details

[](https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/DebtToken.sol#L17)

The DebtToken contract explicitly states in its documentation:

* @dev This contract aligns with Aave's VariableDebtToken implementation, scaling balances by the usage index.

[](https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/tokens/DebtToken.sol#L223-L225)

However, in the DebtToken::balanceOf implementation:

function balanceOf(address account) public view override(ERC20, IERC20) returns (uint256) {
uint256 scaledBalance = super.balanceOf(account);
// MISSING: if zero amount return 0
return scaledBalance.rayMul(ILendingPool(_reservePool).getNormalizedDebt());
}

[](https://github.com/aave/protocol-v2/blob/ce53c4a8c8620125063168620eba0a8a92854eb8/contracts/protocol/tokenization/VariableDebtToken.sol#L75-L82)

This deviates from Aave's implementation which includes a zero check:

function balanceOf(address user) public view virtual override returns (uint256) {
uint256 scaledBalance = super.balanceOf(user);
if (scaledBalance == 0) {
return 0;
}
return scaledBalance.rayMul(_pool.getReserveNormalizedVariableDebt(_underlyingAsset));
}

Impact

The contract fails to fully align with Aave's implementation despite explicit documentation stating otherwise

While this doesn't affect the mathematical correctness of the calculations (as 0 * any number = 0), it represents a deviation from what we are implementing.

Tools Used

Manual Review

Recommendations

Modify the balanceOf function to include the zero check, aligning with Aave's implementation:

function balanceOf(address account) public view override(ERC20, IERC20) returns (uint256) {
uint256 scaledBalance = super.balanceOf(account);
+ if (scaledBalance == 0) {
+ return 0;
+ }
return scaledBalance.rayMul(ILendingPool(_reservePool).getNormalizedDebt());
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
5 months ago
inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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