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

High - Infimal amount of tokens received when collateral has less than 18 decimals

Summary

The protocol handles in unexpected ways collateral tokens with other than 18 decimals. There are two cases: when they have less than 18 decimals and when they are more than 18 decimals. Since both cases have different outcomes, we created two different issues. In this one, we will showcase the case where the collateral token has less than 18 decimals.

This, basically, will allow minting a maximum amount of DSC tokens much lower than it should, breaking that way the expected protocol logic and damaging the user experience.

Vulnerability Details

The protocol is set to be always overcollaterized at least at 200%. That means when you deposit some collateral amount, the maximum amount you are able to mint of DSC will be 50% of the USD value of the collateral.

But, if the token has less than 18 decimals, the logic breaks in a special way. Let's see a few examples.

First, we are going to use WETH as collateral. WETH has 18 decimals and in our sample, its value is 2000 USD / WETH. So if we add 1 ether of WETH (1e18 WETH) as collateral, the maximum amount of DSC we must be able to mint is 1000 ether of DSC which is equal to 1000e18 DSC (DSC is valued at 1 USD / DSC and its token has 18 decimals), so you will get basically 1000 USD in DSC value.

That is fine. But what happens if we have a collateral token with, for example, 6 decimals? Like the Geminis USD. Let's call this token MOCK and its value will be 1 USD / MOCK.

If we add 2 MOCK tokens as collateral (since it has 6 decimals, 2 "full" tokens are 2e6), the maximum amount of DSC we must be able to mint is 1 ether of DSC = 1e18 DSC = 1 USD.

But... the reality is you won't be able to mint that maximum amount. Not even close.

Since the protocol fails to process less than 18 decimals in the right way, if we try to get 1 ether of DSC (as we said, the amount we should be able to get by depositing 2 MOCK tokens), the protocol will revert to saying you are trying to mint too much.

So, how much can you mint? For the MOCK example, 1e6 DSC tokens, which are much less than the amount you should have (1e18 DSC tokens).

In other words, you should receive a maximum of 1e18 DSC tokens, worth 1 USD.
But you will receive a maximum of 1e6 DSC tokens, worth 0.000000000001 USD.

To showcase this issue, we have created a plug-and-play POC you can test. To try it, create a file in your test folder called POC_Collateral_low_decimals.t.sol and paste the content of this gist: https://gist.github.com/TheNaubit/444f983025f58ef29773c93edab2c3c7

Then run the POC by running this command: forge test --match-contract POC_Collateral_low_decimals -vvv

Impact

The basic functionality of the protocol breaks and the users will have a really bad experience by getting a completely wrong (and incredibly small) amount of DSC tokens from their deposited collateral.

Tools Used

Manual review and Foundry.

Recommendations

Review the entire approach for the collateral math when the collateral token has less than 18 decimals. One of the key places to check is https://github.com/Cyfrin/2023-07-foundry-defi-stablecoin/blob/d1c5501aa79320ca0aeaa73f47f0dbc88c7b77e2/src/DSCEngine.sol#L366C38-L366C38, since almost all the functions depend on this and this function is assuming every collateral token has a 18 decimals precision.

Support

FAQs

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