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

DSCEngine.sol: WBTC (tokens that don't have 18 decimals) is not supported which can cause loss of funds

Summary

The description for this contest is as follows:

This project is meant to be a stablecoin where users can deposit WETH and WBTC in exchange for a token that will be pegged to the USD. The system is meant to be such that someone could fork this codebase, swap out WETH & WBTC for any basket of assets they like, and the code would work the same.

This makes it clear that WBTC is one of the tokens that MUST be supported.
In other words WBTC is one of the tokens (in addition to WETH) that is supported by default and any issues that arise due to using it cannot be attributed to an error on the deployer's end.

The root cause is that the WBTC <-> USD conversion is faulty.
WBTC has 6 decimals (https://etherscan.io/token/0x2260fac5e5542a773aa44fbcfedf7c193bc2c599#readContract) whereas the DSCEngine contract assumes that it has 18 decimals.

A user sending WBTC to the contract actually sends a whole WBTC token.
According to the contract logic this amount would be treated as a tiny fraction of a whole WBTC token (). (Link)

The same issue exists in the reverse calculation in the getTokenAmountFromUsd function (Link) which outputs the token amount with 18 decimals as opposed to adjusting for a specific token's decimals.

The behavior described so far can result in a direct loss of funds for the user.

Vulnerability Details

In the test suite that is part of the repository, the WBTC/USD price is set to $1000.

And so if we provide as the amount of WBTC, the resulting amount of USD should be 1000e18$).

However the value that is logged by the following test is (only a tiny fraction of 1 USD).

function testGetUsdValueWBTC() public {
uint256 wbtcAmount = 1e6;
uint256 usdValue = dsce.getUsdValue(wbtc, wbtcAmount);
console.log(usdValue);
}

What follows from this incorrect calculation is that any WBTC collateral is essentially worthless.

Here's a scenario how a loss of funds can occur:

  1. The user has WETH and WBTC collateral. He's got so much WETH collateral that he doesn't notice that his WBTC is essentially treated as worthless. I.e. even though his WBTC is treated as worthless he has enough collateral to mint DSC

  2. Price of WETH drops and the user can be liquidated

  3. A liquiditar liquidates the user by providing a tiny amount of DSC and receiving WBTC

  4. Obviously the WBTC is worth much more by a factor of

In summary what happened is that the user got liquidated earlier than necessary because of the miscalculated WBTC value and the liquidator received WBTC by paying off a negligible amount of debt since the protocol treats the WBTC as essentially wothless.

Impact

As described above this can lead to a direct loss of funds.

Tools Used

Manual Review, Foundry

Recommendations

In the DSCEngine.getUsdValue as well as the DSCEngine.getTokenAmountFromUsd functions there needs to be conversion such that the results are accurately calculated for tokens that do not have 18 decimals.

Support

FAQs

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