Summary
The protocol calculates dust amount wrongly.
Vulnerability Details
RToken.sol#calculateDustAmount() function is as follows.
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;
}
On L322, totalSupply() returns value scaled up by liquidityIndex.
But L325 multiplies liquidityIndex recursively.
This is wrong. So totalRealBalance is bigger than normal.
And On L319, contractBalance is value which is scaled down by liquidityIndex from asset's balance.
This value is compared to totalRealBalance. This is error, too.
Impact
This vulnerability causes freezing of funds to RToken.
Tools Used
Manual review
Recommendations
Modify RToken.sol#calculateDustAmount() function as follows.
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;
}