Breaking Down High Severity Decimals Issue in CodeHawks StableCoin Contest

Johnny Time
3 min readSep 14, 2023
Breaking Down High Severity Decimals Issue in CodeHawks StableCoin Contest

Today we will break down a High Severity vulnerability that was reported as part of the Foundry DeFi Stablecoin CodeHawks Audit Contest.

This is a great opportunity for you to learn some smart contract auditing! :)

If you prefer to watch a video, check this out:

The DSC System: An Overview

The DSC System is a blockchain-based stablecoin ecosystem designed to ensure that the value of its native token remains consistently pegged to the US dollar (1 DSC = $1). Unlike traditional fiat-backed stablecoins or algorithmic stablecoins, the DSC System relies on a unique set of principles:

  • Exogenous Collateral: The system is backed by collateral assets that exist outside the DSC protocol.
  • Dollar Pegged: The primary goal is to maintain a 1:1 peg with the US dollar.
  • Algorithmically Stable: The system employs algorithms and mechanisms to ensure stability.

Imagine it as a stablecoin system stripped of governance, fees, and backed solely by assets like Wrapped Ethereum (WETH) and Wrapped Bitcoin (WBTC).

The core concept is to ensure that the system is consistently “overcollateralized,” meaning the total value of collateral must always exceed the dollar-backed value of DSC tokens in circulation.

The Vulnerability: Theft of Collateral Tokens with Fewer Decimals

Now, let’s dive into the heart of the matter — the critical vulnerability that has been identified in the DSC System.

The problem arises from two key functions: DSCEngine#getTokenAmountFromUsd() and DSCEngine#getUsdValue(). These functions incorrectly assume that all tokens have 18 decimal places, which is not the case for tokens like Wrapped Bitcoin (WBTC) that have only 8 decimal places on the Ethereum mainnet.

  • DSCEngine#getTokenAmountFromUsd(): This function is responsible for converting USD amounts to token amounts. It returns a value with 18 decimals, but it should align with the token's actual decimal places.
  • DSCEngine#getUsdValue(): Similarly, this function incorrectly returns a value matching the token's decimal places when it should produce an 18-decimal USD amount.
The mentioned functions rely on these 2 constants

The issue becomes particularly critical when the system tries to add various USD values together. Due to differences in decimal places, the total collateral value is inaccurate, leading to vulnerabilities.

The impact of this issue is direct theft of deposited collateral for tokens with fewer than 18 decimals.

How to fix it?

To fix this issue, the solution involves making PRECISION dynamic rather than a constant value. Additionally, DSCEngine#getTokenAmountFromUsd() should account for the token's decimal places when converting USD to token amounts.

The issue cna be solved by changing the following line of code in getTokenAmountFromUsd function:

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

To this:

return (usdAmountInWei * 10 ** token.decimals()) / (uint256(price) * ADDITIONAL_FEED_PRECISION);

This modification ensures accurate conversions and adaptability to various token types.

If you wish to enhance your smart contract auditing and hacking skills, and you want a strong foundation that will help you in auditing contests and in general as a web3 security researcher, checkout the smart contract hacking course.

You can also watch the full live stream where I covered all the vulnerabilities that I found in the DSC and Escrow contests:

Codehawks Contests Breakdown Stream

--

--