Summary
An incorrect calculation in RToken.sol will cause frozen funds in RToken as the dust amount calculation incorrectly handles liquidity index scaling.
Root Cause
In RToken.sol, the calculateDustAmount() function contains two critical scaling errors:
On L322, totalSupply() returns a value already scaled by liquidityIndex, but L325 multiplies by liquidityIndex again
On L319, contractBalance is incorrectly scaled down by liquidityIndex before comparison
function calculateDustAmount() public view returns (uint256) {
319 uint256 contractBalance = IERC20(_assetAddress).balanceOf(address(this)).rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
322 uint256 currentTotalSupply = totalSupply();
325 uint256 totalRealBalance = currentTotalSupply.rayMul(ILendingPool(_reservePool).getNormalizedIncome());
return contractBalance <= totalRealBalance ? 0 : contractBalance - totalRealBalance;
}
Impact
The protocol will calculate incorrect dust amounts, leading to funds being frozen in the RToken contract. This affects all users who interact with the RToken system.
Mitigation
The scaling issues should be fixed by removing the unnecessary liquidity index operations:
function calculateDustAmount() public view returns (uint256) {
- uint256 contractBalance = IERC20(_assetAddress).balanceOf(address(this)).rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
+ uint256 contractBalance = IERC20(_assetAddress).balanceOf(address(this));
uint256 currentTotalSupply = totalSupply();
-
- uint256 totalRealBalance = currentTotalSupply.rayMul(ILendingPool(_reservePool).getNormalizedIncome());
-
- return contractBalance <= totalRealBalance ? 0 : contractBalance - totalRealBalance;
+ return contractBalance <= currentTotalSupply ? 0 : contractBalance - currentTotalSupply;
}