15,000 USDC
View results
Submission Details
Severity: high
Valid

Collateral decimals are hardcoded to be 1e18 in `getUsdValue`

Summary

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.

Vulnerability Detail

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.

Impact

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.

Tools Used

A thorough review of the code base was conducted to identify this issue.

Recommendation

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

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.