Summary
In calculateRcrvUSDAmount() function of StabilityPool.sol
function calculateRcrvUSDAmount(uint256 deCRVUSDAmount) public view returns (uint256) {
uint256 scalingFactor = 10**(18 + rTokenDecimals - deTokenDecimals);
return (deCRVUSDAmount * getExchangeRate()) / scalingFactor;
}
The formula is deCRVUSDAmount X getExchangeRate() X (10^deTokenDecimals) / (10^ (18 + rTokenDecimals)
The location of deTokenDecimals and rTokenDecimals have been swapped.
Impact
The function is used in withdraw() function.
function withdraw(uint256 deCRVUSDAmount) external nonReentrant whenNotPaused validAmount(deCRVUSDAmount) {
_update();
if (deToken.balanceOf(msg.sender) < deCRVUSDAmount) revert InsufficientBalance();
uint256 rcrvUSDAmount = calculateRcrvUSDAmount(deCRVUSDAmount);
uint256 raacRewards = calculateRaacRewards(msg.sender);
if (userDeposits[msg.sender] < rcrvUSDAmount) revert InsufficientBalance();
userDeposits[msg.sender] -= rcrvUSDAmount;
if (userDeposits[msg.sender] == 0) {
delete userDeposits[msg.sender];
}
deToken.burn(msg.sender, deCRVUSDAmount);
rToken.safeTransfer(msg.sender, rcrvUSDAmount);
if (raacRewards > 0) {
raacToken.safeTransfer(msg.sender, raacRewards);
}
emit Withdraw(msg.sender, rcrvUSDAmount, deCRVUSDAmount, raacRewards);
}
If rTokenDecimals is not same as deTokenDecimals, rcrvUSDAmount will be different value than expected.
So might revert or withdraw small amount.
Tools Used
Manual
Recommendations
Need to change code as following.
function calculateRcrvUSDAmount(uint256 deCRVUSDAmount) public view returns (uint256) {
--- uint256 scalingFactor = 10**(18 + rTokenDecimals - deTokenDecimals);
+++ uint256 scalingFactor = 10**(18 + deTokenDecimals - rTokenDecimals);
return (deCRVUSDAmount * getExchangeRate()) / scalingFactor;
}