medium

All of the USD pair price feeds doesn't have 8 decimals

Reward

Total

27.67 USDC

0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
Selected
1.09 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
0.78 USDC
Selected Submission

All of the USD pair price feeds doesn't have 8 decimals

Severity

High Risk

Relevant GitHub Links

https://github.com/Cyfrin/2023-07-foundry-defi-stablecoin/blob/d1c5501aa79320ca0aeaa73f47f0dbc88c7b77e2/src/DSCEngine.sol#L340-L348

https://github.com/Cyfrin/2023-07-foundry-defi-stablecoin/blob/d1c5501aa79320ca0aeaa73f47f0dbc88c7b77e2/src/DSCEngine.sol#L361-L367

Summary

DSCEngine contract assumes all of the USD pair chinlink price feeds have 8 decimals but there are certain token's USD feed has a different decimals

Vulnerability Details

In the getTokenAmountFromUsd and getUsdValue functions price of tokens are calculated with chainlink price feeds and the function assumed that all of USD pairs has 8 decimals but there are certain tokens which they have different decimals.

For example AMPL / USD feed has 18 decimals

So if some tokens's price feed has not 8 decimals it will break a lots of things in the contract

Impact

Since returned value of this two functions is used for health factor and liquidation process it will cause loss of funds for users and protocol

Tools Used

Manual Analysis

Recommendations

Consider calling decimals() function on the price feed contract to get the correct decimals and calculate the value based on the returned decimals

    function getTokenAmountFromUsd(address token, uint256 usdAmountInWei) public view returns (uint256) {
        // price of ETH (token)
        // $/ETH ETH ??
        // $2000 / ETH. $1000 = 0.5 ETH
        AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
        (, int256 price,,,) = priceFeed.staleCheckLatestRoundData();
        
+       uint8 decimals = priceFeed.decimals();
+       uint256 priceWithDecimals = (uint256(price) * 1e18) / (10 ** decimals);

-       return (usdAmountInWei * PRECISION) / (uint256(price) * ADDITIONAL_FEED_PRECISION);
+       return (usdAmountInWei * PRECISION) / priceWithDecimals;        
    }


    function getUsdValue(address token, uint256 amount) public view returns (uint256) {
        AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
        (, int256 price,,,) = priceFeed.staleCheckLatestRoundData();
        // 1 ETH = $1000
        // The returned value from CL will be 1000 * 1e8
+       uint8 decimals = priceFeed.decimals();
+       uint256 priceWithDecimals = (uint256(price) * 1e18) / (10 ** decimals);
-       return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION;
+       return (priceWithDecimals * amount) / PRECISION;
    }