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.