getUsdValue()
returns the USD value using the precision of the token itself, and hance varies based on the token's decimal places. This leads to inconsistent decimal places and causes loss of funds, for example when multiple tokens with different decimal places have been deposited as collateral.
The Chainlink price feed returns price in USD for 1 ETH (or 1 BTC or any other 1 TOKEN) expressed with 8 decimal places for TOKEN/USD pairs. It's seen that currently inside getUsdValue()
, the returned USD value is expressed as USD * token decimal places
.
Examples -
Considering $2000/ETH, getUsdValue(weth, 15e18)
returns 30000e18
- considered to be USD value of 15 wETH.
Considering $1000/BTC, getUsdValue(wbtc, 15e8)
returns 15000e8
- considered to be USD value of 15 wBTC. This means a user with wBTC as collateral will be able to mint way less DSC tokens than they are ideally supposed to.
When multiple tokens are deposited as collateral by a user, their collateral value is calculated incorrectly, hence impacting the health factor and hence affecting the number of DSC tokens that can be minted. Also results in incorrect liquidation and loss of funds, bricking the protocol.
Below is a test to check this:
Run this via forge test --mt testMultipleCollateralTokenTypes -vv
.
Manual review, forge test.
Introduce provision in getUsdValue()
to maintain same price-feed precision for all tokens. This could be one solution:
Same correction can be done in getTokenAmountFromUsd()
, I suppose:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.