Summary
DebtToken::totalSupply()
returns the totalSupply
scaled 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();
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:
function totalSupply() public view override(ERC20, IERC20) returns (uint256) {
- uint256 scaledSupply = super.totalSupply();
- return scaledSupply.rayDiv(ILendingPool(_reservePool).getNormalizedDebt());
+ return super.totalSupply();
}
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());
}