Core Contracts

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

`DebtToken::totalSupply()` returned a twice scaled value of the totalSupply

Summary

DebtToken::totalSupply() returns the totalSupplyscaled two times (divided by the index twice) which make no sense.

Vulnerability details

The totalSupply value of DebtToken is already stored as a scaled value, as the DebtToken::_update ERC20 overriden implementation first scale (dividing by the index) the amount to update, which means users and total balances are stored as scaled:

File: contracts/core/tokens/DebtToken.sol
256: function _update(address from, address to, uint256 amount) internal virtual override {
257: if (from != address(0) && to != address(0)) {
258: revert TransfersNotAllowed(); // Only allow minting and burning
259: }
260:
261: uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedDebt());
262: super._update(from, to, scaledAmount);
263: emit Transfer(from, to, amount);
264: }

But then, we see that when requesting the totalSupply, the amount is once again scaled (divided by the index) before being returned, while it should have been normalized:

File: contracts/core/tokens/DebtToken.sol
228: /**
229: * @notice Returns the scaled total supply
230: * @return The total supply (scaled by the usage index)
231: */
232: function totalSupply() public view override(ERC20, IERC20) returns (uint256) {
233: uint256 scaledSupply = super.totalSupply();
234: return scaledSupply.rayDiv(ILendingPool(_reservePool).getNormalizedDebt());
235: }

Impact

Wrong totalSupply returned

Recommended Mitigation Steps

It is ensure if the developer wanted to returned the scaled or normalized totalSupply, but if they want:

  • scaled value (or simply do not override the function):

function totalSupply() public view override(ERC20, IERC20) returns (uint256) {
- uint256 scaledSupply = super.totalSupply();
- return scaledSupply.rayDiv(ILendingPool(_reservePool).getNormalizedDebt());
+ return super.totalSupply();
}
  • normalized value:

function totalSupply() public view override(ERC20, IERC20) returns (uint256) {
uint256 scaledSupply = super.totalSupply();
- return scaledSupply.rayDiv(ILendingPool(_reservePool).getNormalizedDebt());
+ return scaledSupply.rayMul(ILendingPool(_reservePool).getNormalizedDebt());
}
Updates

Lead Judging Commences

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

DebtToken::totalSupply incorrectly uses rayDiv instead of rayMul, severely under-reporting total debt and causing lending protocol accounting errors

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

DebtToken::totalSupply incorrectly uses rayDiv instead of rayMul, severely under-reporting total debt and causing lending protocol accounting errors

Support

FAQs

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