Summary
DecentralizedStableCoin's decimal is 18 as it inherits default ERC20 decimal, but collateral token's decimal might be less than DecentralizedStableCoin's decimal.
For example,
WBTC's decimal = 8
WETH's decimal = 18
For 1 WBTC (~29091$)
For 1 WETH(~1836$)
1 WBTC's USD value is wrongly calculated as 0.00029$
function getTokenAmountFromUsd(address token, uint256 usdAmountInWei) public view returns (uint256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
(, int256 price,,,) = priceFeed.staleCheckLatestRoundData();
return (usdAmountInWei * PRECISION) / (uint256(price) * ADDITIONAL_FEED_PRECISION);
}
function getAccountCollateralValue(address user) public view returns (uint256 totalCollateralValueInUsd) {
for (uint256 i = 0; i < s_collateralTokens.length; i++) {
address token = s_collateralTokens[i];
uint256 amount = s_collateralDeposited[user][token];
totalCollateralValueInUsd += getUsdValue(token, amount);
}
return totalCollateralValueInUsd;
}
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) / PRECISION;
}
Impact
Value of collaterals whose decimal is not 18 might be wrongly calculated.
A user with WBTC collateral might be unfairly liquidated as collateral value is significantly underestimated.
Tool used
Manual Review
Recommendation
It should use collateral token's decimal rather than PRECISION to convert token amount into USD amount and vice versa.
It should use price feed's decimal rather than PRECISION / ADDITIONAL_FEED_PRECISION for future safety.
+ function safeDecimals(address token) internal pure returns (uint8) {
+ (bool success, bytes memory data) = token.staticcall(abi.encodeWithSelector(SIG_DECIMALS));
+ return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;
+ }
function getTokenAmountFromUsd(address token, uint256 usdAmountInWei) public view returns (uint256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
(, int256 price,,,) = priceFeed.staleCheckLatestRoundData();
- return (usdAmountInWei * PRECISION) / (uint256(price) * ADDITIONAL_FEED_PRECISION);
+ return usdAmountInWei * (10 ** (priceFeed.decimals() + safeDecimals(token))) / uint256(price) / PRECISION;
}
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) / PRECISION;
+ return uint256(price) * amount * PRECISION / (10 ** (priceFeed.decimals() + safeDecimals(token)));
}