Stablecoin intro

Delvir0Delvir0
7 min read

Stablecoins, or a stable asset, is fundamental to any economic industry. That’s why I think they hold an important role in mass adoption. Stablecoins have been on a rise for a while now and are being adopted by major entities, showing it’s importance.

This article is aimed to provide a high level overview of stablecoins, functioning as an intro for future readings about the Smart Contract architecture of different kind of stablecoin projects and common security vulnerabilities.

So why do you need this basic information as a security researcher? Because context is important for identifying vulnerabilities, for example, take the following simplified function from a stablecoin project. Do you see what’s wrong?

// stableCoin backed by other stablecoins
// burns stablecoin and returns collateral to user
// returnAmount: the amount of stableCoin we want to exchange for our collateral
function redeem(uint256 returnAmount) external {
    collateralAmount = calculateCollateral(returnAmount);
    uint256 fee = calculateFee(returnAmount);

    // assume fee = 1
    if (fee > 0) stableCoin.safeTransferFrom(msg.sender, feeVault, fee);

    stableCoin.burnFrom(msg.sender, returnAmount - fee);
    IERC20(USDC).safeTransfer(msg.sender, collateralAmount);
}

Hint: the issue lies with collateralization, I’ll explain this later.

What’s a stablecoin - overview
Generally, stablecoins’s core goal is to provide a steady asset which is tied to the value of the US dollar. So unlike assets like BTC, ETH, BNB, etc which are volatile and are mostly used as an investment, stablecoins aim to be as stable as possible in order to act as a currency. It acts as a medium of exchange or to store value, which is essential in an economy.

Since stablecoins are still a trade-able asset, like all other assets, it will fluctuate in price. Each kind of stablecoin has it’s own way of staying as close to or exactly at the value of 1 US dollar. That stability and maintaining it is called peg. If a stablecoin is at a value of $1, it’s maintaining peg. If it’s under or over the $1, it’s called being under-pegged or over-pegged respectively.

So in summary: hold a specific price and change as little as possible, if changed get back to the specific price as soon as possible.

Under the hood - types of stablecoins
Generally, stablecoins are simply ERC20 tokens in a Smart Contract which is able to mint new tokens and burn tokens. That’s actually it and everyone can create a stablecoin.

The power of a stablecoin is not just the ERC20 Contract, but it’s the mechanism that surround the minting, burning and peg maintenance functionality of the stablecoins. I will go through the top forked stablecoin projects and their codebases in a later series.

As said, the most important part of a stablecoin is to maintain peg. Each type of stablecoin has it’s on way of doing that. I’m going through the 3 most common stablecoins:

  • Fiat backed

  • (Over) Collateralized

  • Algorithmic

Fiat backed
Examples are USDT, USDC and TUSD. These are stablecoins that are backed by fiat currency (US dollar, euro, etc), also called collateral. The aim is to always be able to convert the stablecoins back to a fiat currency. “backed by fiat currency” simply means that for each stablecoin, there’s one fiat currency held in a treasury. So getting 1 USDC requires 1 US dollar and getting my 1 US dollar back requires 1 USDC.

Minting USDC for example, is done on-chain. The collateral lives off-chain.

(Over) collateralized
Examples are DAI, LUSD, sUSD. These are backed by other cryptocurrencies (like Bitcoin, Ethereum or even USDC) as collateral. This happens fully on-chain (Smart Contracts).

The goal here is also to always be able to convert a stablecoin to it’s equivalent in collateral. But there’s a difference when using a volatile assets like Bitcoin or a stable asset like USDC.

Being volatile, Bitcoin can rapidly change in price. This means it can increase 10% in price in a day but also decrease 10%. If we would exchange the value of Bitcoin for stablecoins on a 1:1 basis and Bitcoin drops 10%, that would make the stablecoin under-collateralized.

What this basically means to us users is: there’s a risk that I will not be able to get my full collateral back!

In order to tackle this problem, we over-collateralized. Meaning, for each 1 DAI we need to provide (e.g.) $2 worth of Bitcoin. This way we can absorb the price fluctuation (meaning the actual exchange rate depends on the price). But what if the price drops so much that it’s not able to absorb anymore? That’s called being under-collateralized and where liquidation mechanisms play a crucial role.
Imagine we deposit $2000 with of Bitcoin and receive 1000 DAI. Next, Bitcoin dips up to the point that our deposited collateral is now worth less than $1000 (which is the price of the 1000 DAI). There’s a high chance that we would not repay the loan, because we would need to return the 1000 DAI which is now worth more than our collateral.
This would create something which is called bad debt as the project will need to fix the gap created (the current value of our collateral vs the price of 1000 DAI).
The liquidation mechanism sells the under-collateralized loan in order to ensure bad debt is not created well before this can occur.

As said, there’s a difference between using a cryptocurrencies like Bitcoin and a cryptocurrencies like USDC. While both are digital assets, unlike Bitcoin, USDC is not (or should not be) volatile. This means that we could exchange on a 1:1 basis, like the fiat backed stablecoins.

Algorithmic
Examples are FRAX and Ampleforth. These stablecoins rely on algorithms to maintain peg and do not require collateral backing them. This happens fully on-chain (Smart Contracts) and generally use a seignorage or rebasing mechanism to maintain peg. Algorithmic stablecoins are more complex than the above two mentioned and require an article on their own.

Rebasing algorithmic stablecoins adjust their total supply dynamically, usually once per day or at regular intervals, based on the price deviation from the peg. For example:

  • Target price: $1.00

  • If price > $1 → Supply is increased (rebase up)

  • If price < $1 → Supply is decreased (rebase down)

This change effects all holders.

In seigniorage-style algorithmic stablecoins, the system has multiple tokens and simulates the role of a central bank that prints money when demand increases. For example:

  • When price > $1:

    • System mints new stablecoins.

    • Rewards go to share/token holders (those who took on risk).

  • When price < $1:

    • System offers users bonds: burn 1 stablecoin now, redeem more than 1 later.

    • This reduces circulating supply, aiming to bring the price back up.

Back to the code example!

// stableCoin backed by other stablecoins
// burns stablecoin and returns collateral to user
// returnAmount: the amount of stableCoin we want to exchange for our collateral
function redeem(uint256 returnAmount) external {
    collateralAmount = calculateCollateral(returnAmount);
    uint256 fee = calculateFee(returnAmount);

    // assume fee = 1
    if (fee > 0) stableCoin.safeTransferFrom(msg.sender, feeVault, fee);

    stableCoin.burnFrom(msg.sender, returnAmount - fee);
    IERC20(USDC).safeTransfer(msg.sender, collateralAmount);
}

Now that we know how stablecoins work, let digest what happens here.

  1. We input an amount of stableCoin we want to return in exchange for our provided collateral when we minted the stablecoin

  2. collateralAmount , which is the amount of collateral we’re going to receive back is calculated Why is it calculated, wasn’t it always 1:1? it’s because it’s a 1:1 equivalence. If the stableCoin is now worth more or less, that has impact on the actual collateral received back

  3. fee is calculated according to the amount we want to return. If the fee is set, it’s calculated and send to the projects vault. Note that the fee is in stableCoin !

  4. Then the returnAmount minus the fee (because we already sent that) is burned

  5. The calculated collateralAmount according to the returnAmount is returned to the user

Do you see the issue? Here’s an image of the whole process, simplified:

The ratio is now 1:0, meaning there’s nothing backing the 1 stableCoin. What would happen if we would burn that one in exchange for USDC? Exactly, it would either not be possible or we would redeem someone else’s collateral!

That’s it for this series, hope you learned something and stay tuned for the next one: common stablecoin project vulnerabilities.

0
Subscribe to my newsletter

Read articles from Delvir0 directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Delvir0
Delvir0