DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Precision loss and incorrect calculations for tokens like wbtc and usdc

Summary

The code assumes Chainlink decimals = 8 without checking. Should query actual decimals from the feed. Uses a fixed normalization formula that doesn't work for all tokens like usdc and wbtc.

Vulnerability Details

WBTC (Wrapped Bitcoin)

  • Token Decimals: 8

  • Chainlink Feed Decimals: 8

  • Current Code Calculation

This calculation is incorrect for WBTC . The code assumes it needs to normalize to 8 decimals, but WBTC is already at 8 decimals. Results in prices being divided by too large a factor.

USDC (USD Coin)

  • Token Decimals: 6

  • Chainlink Feed Decimals: 8

  • Current Code Calculation

Similar to WBTC, Over-adjusts the decimals. Creates significant precision loss

Impact

Precision loss for tokens like wbtc and usdc

Tools Used

Foundry

Recommendations

Get actual decimals from both token and feed and Normalize prices to same decimal basis.

function _check(address token, uint256 price) internal view {
AggregatorV2V3Interface priceFeed = AggregatorV2V3Interface(dataFeed\[token]);
// Get actual decimals from both token and feed
uint8 tokenDecimals = IERC20Meta(token).decimals();
uint8 feedDecimals = priceFeed.decimals();
(, int256 chainLinkPrice, , uint256 updatedAt, ) = priceFeed.latestRoundData();
require(updatedAt > block.timestamp - maxTimeWindow[token], "stale price feed");
// Normalize prices to same decimal basis
if (tokenDecimals > feedDecimals) {
price = price / 10 ** (tokenDecimals - feedDecimals);
} else if (feedDecimals > tokenDecimals) {
price = price * 10 ** (feedDecimals - tokenDecimals);
}
require(
_absDiff(price, chainLinkPrice.toUint256()) * BPS / chainLinkPrice.toUint256() < priceDiffThreshold[token],
"price offset too big"
);

}

Updates

Lead Judging Commences

n0kto Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelihood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

invalid_prices_decimals

GMX github documentation: “Prices stored within the Oracle contract represent the price of one unit of the token using a value with 30 decimals of precision. Representing the prices in this way allows for conversions between token amounts and fiat values to be simplified, e.g. to calculate the fiat value of a given number of tokens the calculation would just be: token amount * oracle price, to calculate the token amount for a fiat value it would be: fiat value / oracle price.” Sponsor confirmed the keeper does the same, so price decimals change in function of the token, to be sure the above rule is true. Example for USDC (6 decimals): Prices will have 24 decimals → 1e6 * 1e24 = 1e30. Just a reminder for some submissions: shortToken == collateralTokens, so the decimals is 1e24 for shortToken prices.

Support

FAQs

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