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

The amount calculation error does not take into account the collateral decimal

Summary

When converting USD and collateral, the decimal for DSC is fixed at 18, but the collateral decimal is not taken into account, which may not be 18, such as 8 for WBTC.
As a result, there is a huge error in the calculation of getTokenAmountFromUsd / getUsdValue, resulting in funds loss for users.

Vulnerability Details

Taking the getUsdValue function as an example, The POC below shows that BTC is less valuable than ETH due to decimal issues:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {Test, console} from "forge-std/Test.sol";
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract DSCEngine1Test is Test {
address constant btcOracle = 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43;
address constant ethOracle = 0x694AA1769357215DE4FAC081bf1f309aDC325306;
uint256 private constant ADDITIONAL_FEED_PRECISION = 1e10;
uint256 private constant PRECISION = 1e18;
function setUp() public {
vm.createSelectFork("https://eth-sepolia.g.alchemy.com/v2/WhC9CgJA77Pt1e59uRYcDXeq4xuK-CKU");
}
function testUSDValue() public view {
assert(getUsdValue(btcOracle, 1e8) < getUsdValue(ethOracle, 1e18));
}
function getUsdValue(address oracle, uint256 amount) public view returns (uint256) {
(, int256 price,,,) = AggregatorV3Interface(oracle).latestRoundData();
return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION;
}
}

Impact

The decimal of the collateral is not taken into account, which can result in a miscalculation of the result and a huge loss for the user. For example, getUsdValue undervalues WBTC, and users deposit 1WBTC but cannot borrow any DSC.

Tools Used

Foundry

Recommendations

Taken into account the collateral decimals, provide a correct implementation of getUsdValue:

function getUsdValue(address token, uint256 amount) public view returns (uint256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
(, int256 price,,,) = priceFeed.staleCheckLatestRoundData();
return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / 10 ** uint256(CERC20(token).decimals());
}

Support

FAQs

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