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

`getTokenAmountFromUsd()` doesn't consider different token and oracle decimals

Summary

getTokenAmountFromUSD() returns an incorrect amount for tokens with decimals != 18. It also returns an incorrect amount if chainlink oracle uses a different decimal than 8.

Vulnerability Details

getTokenAmountFromUSD() calculates the final amount as follows:

return ((usdAmountInWei * PRECISION) / (uint256(price) * ADDITIONAL_FEED_PRECISION));

This is fine for current collaterals: WETH and WBTC. However, if new collateral is added in future with different decimals, the protocol will return incorrect amount to liquidator. Here is the derivation of correct formula:

  • Let C be chainlink oracle decimal.

  • Let D be token decimal.

  • price/1eC USD gets 1eD tokens.

  • (price/1eC) * (usdAmountInWei/1e18) USD gets 1eD * (usdAmountInWei/1e18) tokens.

  • (usdAmountInWei/1e18) USD gets:

usdAmountInWei * 1eD * 1eC / (price * 1e18) which is the final formula to be used in getTokenAmountFromUsd().

C and D can be fetched by calling decimals() on the collateral token and chainlink oracle. To save gas, you can also store these values permanently.

Impact

For tokens and chainlink oracle deviating from the 18 and 8 decimals respectively, protocol will work incorrectly.

Tools Used

Manual review.

Recommendations

Update the return value of getTokenAmountFromUsd() to consider token decimals and chainlink decimals.

Support

FAQs

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