The getUsdValue function anticipates the argument amount to have 18 decimals. However, this is not always the case. For example, USDT token has 6 decimals, which may result in a revert when a user tries to take debt, or, in worst case scenario, the user might get liquidated and lose 10% of his collateral.
Currently, the return value of the function getUsdValue() will have the same decimals of the token amount (the price feed price will always have 8 decimals since the base currency is USD).
Suppose a token has fewer than 18 decimals, let's say 12. In such a case, getUsdValue() would return an amount in 12 decimal places.
This amount is then used to calculate the health factor in the function _calculateHealthFactor() function.
return (collateralAdjustedForThreshold * 1e18) / totalDscMinted;
We are comparing an amount that is in 12 decimal places collateralAdjustedForThreshold with an amount that has 18 decimals places totalDscMinted.
The result will also be in 12 decimal places, causing the function _revertIfHealthFactorIsBroken to revert:
if (userHealthFactor < MIN_HEALTH_FACTOR) {
revert DSCEngine__BreaksHealthFactor(userHealthFactor);
}
Suppose a user deposits a large amount of collateral, such as 2 000 000 tokens (equivalent to 2 * 10**18, assuming 1 token = 1 USD), then mints 1 DSC. If the token price slightly decreases, his position could be opened for liquidation. A liquidator could then repay his debt and get an additional 10% (around 200 000 tokens = 200K USD).
uint256 totalCollateralToRedeem = tokenAmountFromDebtCovered + bonusCollateral;
Working with hardcoded decimal values creates weakesses, unless the collateral addresses are hardcoded and known to have the default decimals.
If a user deposits a large amount of collateral, his position could be opened for liquidation if the token price slightly decreases. This could result in a loss of approximately 10% of the collateral.
A thorough review of the code base was conducted to identify this issue.
The best way to fix this would be to use the ERC20 function decimals() wherever a calculation between token amounts takes places. This ensures the result has the same decimals as the debt token. Consider modifying the getUsdValue function as follows:
return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount * dsc.decimals()) / PRECISION * 10 ** IERC20(token).decimals
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.