A complete interactive guide to understanding how a DeFi stablecoin works - from concepts to code
Scroll down to begin your journey โ
Let's start from the very basics
Imagine you have a special piggy bank. For every $2 worth of toys you put in, you get a special golden coin worth $1.
๐ฆ You put in: $2 worth of toys (WETH/WBTC)
๐ช You get: $1 golden coin (DSC)
Why $2 for $1? Because even if your toys lose some value, there's still enough to back your golden coin!
| Property | What It Means | Real World Example |
|---|---|---|
| ๐ Exogenous | Backed by EXTERNAL assets (WETH, WBTC) | Like a gold-backed currency - the gold exists outside the money system |
| ๐ค Algorithmic | Rules-based, no human decisions | Like a vending machine - put in money, get product, no cashier needed |
| ๐ต USD Pegged | 1 DSC = $1 always | Like how arcade tokens are always worth the same in that arcade |
Imagine ETH price drops 30%. If you only had 100% backing:
โ Your $1000 collateral is now worth $700 โ Can't back $1000 DSC!
With 200% backing:
โ Your $2000 collateral is now worth $1400 โ Still backs $1000 DSC!
The most important number in DeFi lending
Health Factor Formula:
Think of Health Factor like a safety score for your loan:
Your Health Factor:
โ Safe - You cannot be liquidated
When your safety score drops below 1.0, you become a "wanted" person. Anyone can be a bounty hunter!
๐ค Bounty Hunter (Liquidator): "I'll pay off some of your debt!"
๐ฐ Reward: They get your collateral + 10% bonus!
This keeps the whole system healthy because bad positions get cleaned up.
Bob deposited 1 ETH at $2000, minted $1000 DSC. ETH crashes to $1500.
Health Factor: ($1500 ร 50%) รท $1000 = 0.75 โ
Alice has $500 DSC and wants to liquidate Bob's position.
Alice pays: $500 DSC
Alice receives: $500 worth of ETH + 10% bonus = $550 worth of ETH
Alice profit: $50! ๐
You pay: $500 DSC
You receive: 0.367 ETH ($550)
That's your 10% liquidation bonus! ๐
How all the pieces fit together
Handles all collateral management, minting, burning, and liquidations
Deposit WETH or WBTC as collateral
Mint DSC against your collateral
Liquidate unhealthy positions and earn 10% bonus
Simple ERC20 token that only DSCEngine can mint/burn
The token itself doesn't need to be smart. It's just a "receipt" for your position.
All the intelligence is in DSCEngine - the token just says "DSCEngine is my boss".
Protects against stale/manipulated price data
Imagine you only trust today's newspaper for stock prices. If someone gives you a 3-day old newspaper and says "buy!", you'd refuse.
OracleLib does the same - it checks if the price data is "fresh" (less than 3 hours old).
Real ETH: $1000 (crashed!)
Stale Oracle: $2000 (old data)
Attacker deposits 1 ETH โ Protocol thinks $2000 โ Mints $1000 DSC
Protocol is now UNDERCOLLATERALIZED! ๐
How we ensure the protocol is secure
An invariant is something that must ALWAYS be true, no matter what users do.
Our invariant: "Total collateral value โฅ Total DSC minted"
We let the fuzzer do THOUSANDS of random actions, then check if this rule still holds!
Without a Handler, the fuzzer calls random functions with random inputs - most calls fail!
The Handler is like a helpful assistant that:
Fuzzer: "deposit 1000 WETH!"
Contract: "You don't have any WETH..."
REVERT!
Handler: "Let me mint WETH first..."
Handler: "And approve spending..."
Handler: "Now deposit!"
SUCCESS!
The math behind Solidity's number system
Solidity doesn't have decimals! You can't write 1.5 ETH.
Solution: Use REALLY big numbers and pretend the last 18 digits are decimals.
1 ETH = 1,000,000,000,000,000,000 wei (that's 1 followed by 18 zeros = 1e18)
If I want $500 worth of ETH and ETH is $2000, how much ETH do I get?
Simple: $500 รท $2000 = 0.25 ETH
In code: (500e18 ร 1e18) รท (2000e8 ร 1e10) = 0.25e18 = 250000000000000000 wei
Follow the entire flow from start to finish
s_collateralDeposited[alice][weth]: 0 โ
2e18
weth.balanceOf(alice): 2e18 โ
0
weth.balanceOf(dscEngine): 0 โ
2e18
s_DSCMinted[alice]: 0 โ
1500e18
dsc.balanceOf(alice): 0 โ
1500e18
dsc.totalSupply(): 0 โ
1500e18
The DSC is REAL money on the blockchain!
There's also redeemCollateralForDSC() that does burn +
redeem in one transaction!
Complete flow of a liquidation event
Bob deposited: 1 ETH @ $2000
Bob minted: $800 DSC
Health Factor: ($2000 ร 50%) รท $800 = 1.25 โ
ETH drops from $2000 โ $1400
Bob's collateral value: 1 ETH ร $1400 = $1400
New Health Factor: ($1400 ร 50%) รท $800 = 0.875 โ
โ ๏ธ Bob is now LIQUIDATABLE!
Alice has $400 DSC and wants to liquidate Bob
| Variable | Before | After |
|---|---|---|
| Bob's Collateral | 1 ETH | 0.6857 ETH |
| Bob's Debt | $800 DSC | $400 DSC |
| Bob's Health Factor | 0.875 | 1.2 โ |
| Alice's DSC | $400 | $0 |
| Alice's ETH | 0 | 0.3143 ETH ($440) |
Understanding all custom errors
| Error | When It Happens | Fix |
|---|---|---|
NeedsMoreThanZero |
Trying to deposit/mint/burn 0 amount | Pass amount > 0 |
TokenNotAllowed |
Using unsupported collateral token | Only use WETH or WBTC |
TransferFailed |
ERC20 transfer didn't work | Check token approval/balance |
BreaksHealthFactor
|
Action would make health factor < 1 | Deposit more or mint less |
MintFailed |
DSC token mint returned false | Check DSCEngine is owner |
HealthFactorOk |
Trying to liquidate healthy user | Can only liquidate HF < 1 |
HealthFactorNotImproved
|
Liquidation didn't help the user | Cover more debt |
OracleLib__StalePrice()
This error is thrown when:
updatedAt == 0 - Price was never setansweredInRound < roundId - Oracle is behindblock.timestamp - updatedAt > 3 hours - Price too old
When this happens, the ENTIRE protocol freezes. No deposits, mints, or redeems. Safety first!
How DSC compares to other stablecoins
| Feature | DSC (Ours) | DAI | USDT | USDC |
|---|---|---|---|---|
| Type | Crypto-backed | Crypto-backed | Fiat-backed | Fiat-backed |
| Collateral | WETH, WBTC | ETH, WBTC, etc. | USD in bank | USD in bank |
| Decentralized | โ Fully | โ Mostly | โ No | โ No |
| Can be frozen | โ No | โ No | โ Yes | โ Yes |
| Overcollateralized | โ 200% | โ 150%+ | 100% (claimed) | 100% (audited) |
| Trust Required | Code only | Code + DAO | Tether company | Circle company |
| Transparency | 100% on-chain | 100% on-chain | Quarterly reports | Monthly attestations |
Pros: Fully trustless, censorship-resistant, transparent, overcollateralized
Cons: Capital inefficient (need $2 to get $1), volatile collateral risk
It's a trade-off: Do you trust code or companies?
How the contracts get deployed
Every function in DSCEngine explained
Combo: Deposit + Mint in one transaction
Gas Efficient: Saves ~21000 gas vs two separate calls
Combo: Burn DSC + Withdraw collateral in one transaction
Frontend apps call these to show users their positions. Liquidation bots call these to find liquidatable users!
Visual step-by-step flows for every user action
Users might want to:
Understanding the smart contract structure and design patterns
Separation of Concerns: The token (DSC) is simple - it just moves value. The engine (DSCEngine) is smart - it handles all the complex logic.
This is like a bank: The vault (DSC) holds the money, but the bank manager (DSCEngine) decides who can deposit/withdraw.
i_dsc
DSC token contract address
s_collateralDeposited
user โ token โ amount
s_DSCMinted
user โ debt amount
s_priceFeeds
token โ price feed
s_collateralTokens
List of allowed tokens [WETH, WBTC]
depositCollateral()
Deposit single token
depositCollateralAndMintDSC()
Deposit + mint combo
mintDSC()
Mint against collateral
redeemCollateral()
Withdraw collateral
redeemCollateralForDSC()
Burn + withdraw combo
burnDSC()
Reduce debt
liquidate()
Liquidate unhealthy user
getAccountInformation()
Debt + collateral
getHealthFactor()
User's health score
getUSDValue()
Token โ USD
getTokenAmountFromUsd()
USD โ token
Prevents reentrancy attacks on external calls
nonReentrant modifier
State changes before external calls
Update mapping โ Transfer
Only DSCEngine can mint/burn DSC
onlyOwner modifier
All operations validate position health
_revertIfHealthFactorIsBroken()
Rejects stale price data (>3 hours)
OracleLib.check()
Zero address, zero amount checks
moreThanZero modifier
depositCollateral()
moreThanZero
isZeroAddress
isAllowedToken
nonReentrant
Deep dives into the fundamental mechanisms
Think of overcollateralization like a down payment on a house:
DSC requires 200% because crypto is volatile!
Your position is very healthy
Your position is at risk
Your position can be liquidated!
Liquidator finds user with HF < 1.0
Pay $500 DSC to cover user's debt
Receive $550 worth of collateral
Instant $50 profit (10%)
| Debt Covered | 10% Bonus | Your Profit |
|---|---|---|
| $100 DSC | $10 | $10 |
| $500 DSC | $50 | $50 |
| $1,000 DSC | $100 | $100 |
| $5,000 DSC | $500 | $500 |
Chainlink is a decentralized oracle network:
DSC is created when users deposit collateral
DSC trades at $1 in the market
DSC is destroyed when debt is repaid
When ETH price rises, users can mint more DSC
More collateral value โ More DSC supply
When ETH price drops, users burn DSC to avoid liquidation
Less collateral value โ Less DSC supply
DSC maintains $1 peg through overcollateralization
Always backed by more collateral than DSC issued
Everything at a glance
| Formula | Calculation | Example |
|---|---|---|
| Health Factor | (Collateral ร 50%) รท Debt | ($2000 ร 50%) รท $500 = 2.0 |
| Max Mintable DSC | Collateral Value ร 50% | $2000 ร 50% = $1000 DSC |
| Liquidation Bonus | Debt Covered ร 10% | $500 ร 10% = $50 |
| USD to Token | USD Amount รท Token Price | $500 รท $1500 = 0.333 ETH |
Deploy on Sepolia or Anvil local network