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.
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
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.
Manual review and Foundry.
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.
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.