DeFi Deep Dives
Stablecoins: How They Actually Work — A Developer's Technical Guide
TL;DR
Stablecoins are the most critical primitive in DeFi, and most developers treat them as a black box — you deposit a dollar, you get a token worth a dollar, done. But the mechanisms that maintain that peg are wildly different depending on the type. In this article, I break down all three models: fiat-backed stablecoins like USDC and USDT that rely on off-chain reserves and trust, crypto-collateralized stablecoins like DAI that use over-collateralized vaults and liquidation engines to stay pegged without centralized backing, and algorithmic stablecoins like UST that tried to maintain peg through pure mint-burn economics and failed catastrophically. I walk through the actual Solidity code for a minimal collateralized stablecoin, explain how Chainlink oracles feed price data into liquidation logic, dissect why Terra's death spiral was architecturally inevitable, and cover how stablecoins integrate into lending protocols and AMM pools. If you're building anything in DeFi, understanding stablecoin internals isn't optional — it's foundational.
The Three Types
Every stablecoin in existence falls into one of three categories. The differences aren't cosmetic — they represent fundamentally different trust assumptions, risk profiles, and failure modes. Before writing a single line of integration code, you need to understand what you're actually plugging into.
┌─────────────────────┬──────────────────────┬──────────────────────┬──────────────────────┐
│ │ FIAT-BACKED │ CRYPTO-COLLATERAL │ ALGORITHMIC │
├─────────────────────┼──────────────────────┼──────────────────────┼──────────────────────┤
│ Examples │ USDC, USDT, BUSD │ DAI, LUSD, sUSD │ UST, FRAX, AMPL │
│ Backing │ Off-chain reserves │ On-chain crypto │ None / partial │
│ Trust Assumption │ Issuer solvency │ Smart contract code │ Market incentives │
│ Peg Mechanism │ Redemption guarantee │ Over-collateral + │ Mint/burn arbitrage │
│ │ │ liquidation │ │
│ Capital Efficiency │ 1:1 │ ~150%+ locked │ Highly efficient │
│ Censorship Risk │ High (blacklists) │ Low │ Low │
│ Failure Mode │ Bank run / freeze │ Black swan crash │ Death spiral │
│ Decentralization │ Centralized │ Decentralized │ Decentralized │
└─────────────────────┴──────────────────────┴──────────────────────┴──────────────────────┘The tradeoff triangle is clear: you get to pick two of the three — capital efficiency, decentralization, and peg stability. No stablecoin has solved all three simultaneously. Fiat-backed coins nail capital efficiency and stability but sacrifice decentralization. Crypto-collateralized coins achieve decentralization and stability but sacrifice capital efficiency. Algorithmic coins chase capital efficiency and decentralization but, as we've seen, peg stability breaks under stress.
Understanding this tradeoff is the first step to making informed architectural decisions when building on top of stablecoins.
Fiat-Backed — USDC and USDT
Fiat-backed stablecoins are the simplest model conceptually. A centralized entity holds real dollars (or dollar-equivalent assets) in a bank account, and for every dollar deposited, they mint one token on-chain. When you redeem, they burn the token and send you dollars.
USDC is issued by Circle. Every USDC token is backed by cash and short-dated U.S. Treasuries held in regulated financial institutions. Circle publishes monthly attestation reports from Grant Thornton. The ERC-20 contract is straightforward — it's a standard token with mint and burn functions controlled by Circle's multisig.
USDT is issued by Tether. The backing composition has historically been more opaque — a mix of cash, commercial paper (now largely replaced by T-bills), secured loans, and other investments. Tether has faced scrutiny over reserve transparency, but USDT remains the most traded stablecoin by volume, particularly in Asian markets and on centralized exchanges.
Here's what the on-chain contract looks like at a high level for a fiat-backed stablecoin:
// Simplified fiat-backed stablecoin pattern
contract FiatStablecoin is ERC20, Ownable {
mapping(address => bool) public blacklisted;
modifier notBlacklisted(address account) {
require(!blacklisted[account], "Account blacklisted");
_;
}
function mint(address to, uint256 amount)
external
onlyOwner
notBlacklisted(to)
{
_mint(to, amount);
}
function burn(address from, uint256 amount)
external
onlyOwner
{
_burn(from, amount);
}
function blacklist(address account) external onlyOwner {
blacklisted[account] = true;
}
}Notice the blacklist function. Both USDC and USDT have the ability to freeze addresses — and they've used it. Circle has blacklisted addresses tied to Tornado Cash sanctions. This is the fundamental tradeoff: you get a rock-solid peg, but a centralized party can freeze your funds. For DeFi protocols, this introduces a dependency that many builders underestimate.
The risk most developers miss: during the March 2023 Silicon Valley Bank collapse, USDC briefly depegged to $0.87 because Circle had $3.3 billion of reserves held at SVB. The peg restored when the FDIC guaranteed deposits. But for those 48 hours, every protocol holding USDC as "safe" collateral was exposed to real credit risk. The peg is only as strong as the banking infrastructure behind it.
Crypto-Collateralized — How DAI Maintains Its Peg
DAI, issued by MakerDAO, takes a fundamentally different approach. There's no bank account holding dollars. Instead, users lock up crypto assets (ETH, WBTC, stETH, and others) as collateral in smart contract vaults, and the protocol mints DAI against that collateral.
The key constraint: every vault must be over-collateralized. If you want to mint 1,000 DAI, you need to deposit at least $1,500 worth of ETH (at the 150% collateralization ratio for ETH vaults). This buffer absorbs price volatility.
The math behind a Maker vault (now called a CDP — Collateralized Debt Position):
Collateralization Ratio = (Collateral Value in USD) / (DAI Debt)
Example:
- Deposit: 1 ETH at $3,000 = $3,000 collateral
- Mint: 1,500 DAI
- Ratio: $3,000 / $1,500 = 200% (healthy)
If ETH drops to $2,000:
- Ratio: $2,000 / $1,500 = 133% (below 150% — liquidatable!)The peg mechanism relies on two economic forces:
- When DAI > $1: Users are incentivized to open vaults and mint new DAI (they're creating dollars at a premium), increasing supply and pushing the price back down.
- When DAI < $1: Users are incentivized to buy cheap DAI on the market and repay their vault debt at a discount, reducing supply and pushing the price back up.
MakerDAO also uses the Dai Savings Rate (DSR) as a monetary policy tool. When DAI trades below $1, governance can raise the DSR to increase demand for holding DAI. When DAI trades above $1, they lower it. It's effectively on-chain central banking.
The governance token MKR serves as the backstop. If the system becomes undercollateralized (say, during a flash crash where liquidations can't process fast enough), new MKR tokens are minted and auctioned to cover the bad debt. MKR holders bear the ultimate risk — which is why they earn protocol fees.
Algorithmic — What Went Wrong with UST
Algorithmic stablecoins attempt the holy grail: maintaining a $1 peg without any collateral at all. The theory is elegant. The practice nearly destroyed an entire blockchain ecosystem.
Terra's UST used a mint-burn arbitrage mechanism with its companion token LUNA:
When UST > $1:
→ Mint 1 UST by burning $1 worth of LUNA
→ Sell UST at premium → profit
→ Increases UST supply → price drops toward $1
When UST < $1:
→ Buy cheap UST on market
→ Burn 1 UST to receive $1 worth of LUNA
→ Sell LUNA → profit
→ Decreases UST supply → price rises toward $1On paper, this is a perpetual-motion peg machine. In practice, it had a fatal architectural flaw: reflexivity.
When UST started depegging in May 2022, people rushed to burn UST for LUNA. But mass-minting LUNA cratered LUNA's price. And since the arbitrage mechanism gives you "$1 worth of LUNA" — and LUNA's price was falling — you needed to mint exponentially more LUNA to cover the same amount of UST. This created a hyperinflationary death spiral:
UST depegs → burn UST for LUNA → LUNA supply explodes →
LUNA price crashes → "$1 worth of LUNA" requires more LUNA →
confidence collapses → more UST selling → deeper depeg →
repeat until both tokens hit zeroThe numbers tell the story. LUNA went from $80 to $0.0001 in five days. UST went from $1 to $0.02. Over $40 billion in value evaporated. Anchor Protocol, which had been offering 19.5% APY on UST deposits (funded by venture capital reserves, not sustainable yield), accelerated the bank run.
The lesson for developers: any system where the backing asset's value is reflexively tied to the stablecoin's demand is architecturally fragile. When confidence breaks, the feedback loop reverses and there's no floor. FRAX took a different approach by being partially collateralized (hybrid model), which gave it a floor that pure algorithmic designs lack.
Building a Simple Stablecoin — Solidity
Here's a minimal but functional crypto-collateralized stablecoin. This demonstrates the core mechanics — deposit collateral, mint stablecoins, track health factors, and enable liquidations.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {AggregatorV3Interface} from
"@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import {ReentrancyGuard} from
"@openzeppelin/contracts/utils/ReentrancyGuard.sol";
contract SimpleStablecoin is ERC20, ReentrancyGuard {
IERC20 public immutable collateralToken; // e.g., WETH
AggregatorV3Interface public immutable priceFeed; // ETH/USD
uint256 public constant MIN_HEALTH_FACTOR = 1e18; // 1.0
uint256 public constant LIQUIDATION_THRESHOLD = 150; // 150%
uint256 public constant LIQUIDATION_BONUS = 10; // 10%
mapping(address => uint256) public collateralDeposited;
mapping(address => uint256) public stablecoinMinted;
event CollateralDeposited(address indexed user, uint256 amount);
event StablecoinMinted(address indexed user, uint256 amount);
event Liquidated(
address indexed user,
address indexed liquidator,
uint256 debtCovered,
uint256 collateralSeized
);
constructor(
address _collateral,
address _priceFeed
) ERC20("Simple USD", "sUSD") {
collateralToken = IERC20(_collateral);
priceFeed = AggregatorV3Interface(_priceFeed);
}
function depositAndMint(
uint256 collateralAmount,
uint256 mintAmount
) external nonReentrant {
collateralToken.transferFrom(
msg.sender, address(this), collateralAmount
);
collateralDeposited[msg.sender] += collateralAmount;
emit CollateralDeposited(msg.sender, collateralAmount);
stablecoinMinted[msg.sender] += mintAmount;
_mint(msg.sender, mintAmount);
emit StablecoinMinted(msg.sender, mintAmount);
require(
healthFactor(msg.sender) >= MIN_HEALTH_FACTOR,
"Health factor too low"
);
}
function healthFactor(address user) public view returns (uint256) {
uint256 debt = stablecoinMinted[user];
if (debt == 0) return type(uint256).max;
uint256 collateralUsd = getCollateralValueUsd(user);
uint256 adjustedCollateral =
(collateralUsd * 100) / LIQUIDATION_THRESHOLD;
return (adjustedCollateral * 1e18) / debt;
}
function getCollateralValueUsd(
address user
) public view returns (uint256) {
uint256 ethPrice = getLatestPrice();
return (collateralDeposited[user] * ethPrice) / 1e18;
}
function getLatestPrice() public view returns (uint256) {
(, int256 price,,,) = priceFeed.latestRoundData();
return uint256(price) * 1e10; // Chainlink 8 decimals → 18
}
function liquidate(
address user,
uint256 debtToCover
) external nonReentrant {
require(
healthFactor(user) < MIN_HEALTH_FACTOR,
"Health factor OK"
);
uint256 ethPrice = getLatestPrice();
uint256 collateralToSeize =
(debtToCover * 1e18) / ethPrice;
uint256 bonusCollateral =
(collateralToSeize * LIQUIDATION_BONUS) / 100;
collateralDeposited[user] -= (collateralToSeize + bonusCollateral);
stablecoinMinted[user] -= debtToCover;
_burn(msg.sender, debtToCover);
collateralToken.transfer(
msg.sender, collateralToSeize + bonusCollateral
);
emit Liquidated(
user, msg.sender, debtToCover,
collateralToSeize + bonusCollateral
);
require(
healthFactor(user) >= MIN_HEALTH_FACTOR,
"Health factor still broken"
);
}
}This is intentionally simplified — a production stablecoin would need multi-collateral support, stability fees, governance parameters, emergency shutdown mechanisms, and comprehensive fuzz testing. But the core mechanics are here: deposit, mint, health checks, and liquidation with bonus incentives.
Liquidation Mechanisms
Liquidation is the immune system of crypto-collateralized stablecoins. Without it, the protocol becomes undercollateralized during price drops, and the peg breaks.
The process works like this:
1. User opens vault: deposits 1 ETH ($3,000), mints 1,500 sUSD
→ Health factor: ($3,000 × 100/150) / $1,500 = 1.33 ✓
2. ETH drops to $2,100
→ Health factor: ($2,100 × 100/150) / $1,500 = 0.93 ✗
3. Liquidator steps in:
→ Repays 1,500 sUSD of user's debt
→ Receives $1,500 + 10% bonus = $1,650 worth of ETH
→ Liquidator profit: $150
→ User keeps: $2,100 - $1,650 = $450 worth of ETH
→ Protocol is safe: debt cleared, system stays collateralizedMakerDAO's auction system takes this further. Instead of instant liquidation, Maker uses a Dutch auction — the collateral starts at a high price and decreases over time until a liquidator bids. This creates competition among liquidators and typically results in better outcomes for vault owners (less collateral seized than the maximum).
Aave and Compound use a simpler model: liquidators can repay up to 50% of the underwater position in a single transaction and receive the collateral plus a fixed bonus (typically 5-10%).
The MEV angle: liquidations are a massive MEV opportunity. Searchers run bots that monitor vault health factors across every block, and when one drops below threshold, they bundle a liquidation transaction with a flashloan to execute the entire operation without any upfront capital. During the March 2020 "Black Thursday," MakerDAO liquidation auctions broke because gas prices spiked so high that legitimate bidders couldn't get transactions included, and some vaults were liquidated for $0.
Oracle Dependencies
Every crypto-collateralized stablecoin lives and dies by its price oracle. If the oracle reports a wrong price — even briefly — liquidations fire incorrectly or fail to fire at all. Both are catastrophic.
Chainlink is the dominant oracle solution. It aggregates prices from multiple data sources and uses a decentralized network of node operators to deliver on-chain price feeds. Here's how a production integration should validate oracle data:
function getValidatedPrice() public view returns (uint256) {
(
uint80 roundId,
int256 price,
,
uint256 updatedAt,
uint80 answeredInRound
) = priceFeed.latestRoundData();
// Stale price check
require(
block.timestamp - updatedAt < 3600,
"Oracle price stale"
);
// Round completeness
require(answeredInRound >= roundId, "Round incomplete");
// Sanity bounds
require(price > 0, "Invalid price");
return uint256(price) * 1e10;
}Critical checks that most tutorials skip:
- Staleness: Chainlink feeds have a heartbeat (usually 1 hour for major pairs). If
updatedAtis older than the heartbeat, the price might be wrong. During network congestion, oracle updates can be delayed. - Round completeness:
answeredInRoundshould equalroundId. If it doesn't, the round hasn't been fully resolved by the oracle network. - Sequencer uptime (L2s): On Arbitrum and Optimism, you must also check the L2 sequencer uptime feed. If the sequencer was down, prices weren't being updated, and liquidations triggered immediately after restart can use stale prices. This is a real attack vector.
// L2 sequencer check (Arbitrum/Optimism)
function isSequencerUp() internal view returns (bool) {
(, int256 answer, , uint256 startedAt,) =
sequencerFeed.latestRoundData();
bool isUp = answer == 0;
uint256 timeSinceUp = block.timestamp - startedAt;
return isUp && timeSinceUp > GRACE_PERIOD;
}Oracle manipulation is also a concern. Flash loan attacks can manipulate spot prices on DEXs, which is why production protocols use time-weighted average prices (TWAPs) or Chainlink (which aggregates off-chain sources) rather than on-chain spot prices.
Risk Analysis for Each Type
Every stablecoin has failure modes. Here's what to evaluate when choosing which to integrate:
Fiat-Backed (USDC/USDT):
- Counterparty risk: Issuer insolvency, banking partner failure (SVB incident)
- Regulatory risk: Government can compel freezing, seizure, or delistings
- Censorship risk: Blacklist function can freeze your protocol's treasury
- Transparency risk: Reserve composition may not match claims (historical USDT concerns)
- Mitigation: Diversify across issuers. Monitor attestation reports. Have contingency plans for depeg events.
Crypto-Collateralized (DAI/LUSD):
- Smart contract risk: Bugs in vault/liquidation logic
- Oracle risk: Stale or manipulated price feeds triggering bad liquidations
- Black swan risk: Flash crash faster than liquidation auctions can process
- Governance risk: MakerDAO governance can change parameters (DAI has onboarded RWAs and USDC as collateral, making it partially centralized)
- Mitigation: Audit contracts thoroughly. Use multiple oracle sources. Monitor governance proposals.
Algorithmic (UST/FRAX):
- Reflexivity risk: Death spiral when backing token is endogenous
- Confidence risk: Peg relies on market belief, not hard backing
- Liquidity risk: Curve pool imbalances during stress events signal trouble early
- Design risk: No amount of mechanism design fixes the fundamental problem of unbacked value creation
- Mitigation: Honestly? Don't build critical infrastructure on purely algorithmic stablecoins. The hybrid model (partial collateral + algorithmic) has shown more resilience.
Stablecoins in DeFi Protocols
Stablecoins aren't just tokens people hold — they're load-bearing infrastructure across every DeFi vertical.
Lending protocols (Aave, Compound): Stablecoins are the most borrowed asset class. Users deposit ETH as collateral and borrow USDC to access liquidity without selling their crypto. The interest rate models for stablecoins use a kinked curve — low rates when utilization is below the optimal point (typically 80-90%), then rates spike sharply above that to incentivize repayment and maintain liquidity for withdrawals.
Interest Rate Model (Aave-style):
If utilization ≤ 90%:
rate = baseRate + (utilization / optimal) × slope1
If utilization > 90%:
rate = baseRate + slope1 + ((utilization - optimal) / (1 - optimal)) × slope2
Where slope2 >> slope1 (e.g., slope2 = 300% APR)AMM pools (Curve, Uniswap): Curve Finance was designed specifically for stablecoin-to-stablecoin swaps. Its StableSwap invariant uses a hybrid of the constant product (x * y = k) and constant sum (x + y = k) formulas, creating a curve that's nearly flat around the peg point (low slippage for same-peg swaps) but curves sharply at the extremes (protecting LPs during depegs). The Curve 3pool (USDC/USDT/DAI) has historically been the deepest stablecoin liquidity on Ethereum.
Yield protocols: Stablecoin yields come from lending interest, trading fees from AMM pools, or protocol incentive emissions. When evaluating yield, always ask: where does this yield come from? If the answer isn't clear — remember Anchor's 19.5% APY. Sustainable stablecoin yields in a normal market environment range from 2-8% APR.
Cross-chain bridges: Stablecoins are the most bridged asset class. Circle's Cross-Chain Transfer Protocol (CCTP) enables native USDC minting on destination chains (burn on source, mint on destination), avoiding the wrapped-token risk that plagued early bridges. For DAI, bridging relies on lock-and-mint or third-party bridge infrastructure.
The Future of Stablecoins
The stablecoin landscape is evolving fast, and several trends are reshaping the design space.
Real-World Asset (RWA) backing is becoming the dominant new paradigm. MakerDAO has onboarded billions in tokenized U.S. Treasuries as collateral for DAI. Ondo Finance's USDY and Mountain Protocol's USDM pass through Treasury yield to holders. This blurs the line between fiat-backed and crypto-collateralized — the collateral is real-world, but the mechanism is on-chain.
Regulatory clarity is coming whether crypto wants it or not. The EU's MiCA framework requires stablecoin issuers to hold reserves in licensed custodians. The U.S. is working on stablecoin legislation that would create a federal licensing framework. For developers, this means fiat-backed stablecoins will become more standardized and transparent — but also more constrained.
Ethena's USDe represents a new hybrid approach — using delta-neutral positions (hold stETH + short ETH perpetual futures) to maintain peg while generating yield from funding rates. It's not algorithmic in the UST sense (there's real economic backing from the hedge), but it introduces new risks: centralized exchange counterparty risk, negative funding rate periods, and smart contract risk on the staking derivatives.
GHO (Aave's stablecoin) and crvUSD (Curve's stablecoin) show that major DeFi protocols are vertically integrating stablecoin issuance. crvUSD introduced a novel "LLAMMA" liquidation mechanism that uses a continuous liquidation/de-liquidation band instead of a hard threshold — potentially solving the MEV extraction and bad debt problems of traditional liquidation designs.
For developers building today, my practical recommendation: use USDC as your primary denomination for its liquidity and regulatory clarity, support DAI as the decentralized alternative, monitor Ethena/GHO/crvUSD for emerging integrations, and never — under any circumstances — build critical infrastructure on a purely algorithmic stablecoin without hard collateral backing. If you're building stablecoin infrastructure yourself, start with the over-collateralized model, integrate Chainlink oracles with full validation, implement robust liquidation mechanics, and get a professional audit before touching mainnet.
The boring answer is usually the right one: the best stablecoin for your protocol is the one with the deepest liquidity, the most battle-tested contracts, and the failure modes you can actually reason about.
Key Takeaways
- Three models, three tradeoff profiles. Fiat-backed (trust issuer, get stability), crypto-collateralized (trust code, sacrifice capital efficiency), algorithmic (trust incentives, risk death spiral).
- Over-collateralization is the proven approach. DAI has maintained its peg through multiple black swan events since 2017. The 150%+ collateral buffer works.
- Liquidation engines are non-negotiable. Without functional liquidations, the system accumulates bad debt until the peg breaks.
- Oracle validation is a security requirement. Check staleness, round completeness, sequencer uptime on L2s, and never use on-chain spot prices.
- UST's failure was architectural, not operational. Reflexive backing (stablecoin backed by endogenous token) creates death spiral risk by design. No amount of reserves can fix a fundamentally broken mechanism under sufficient stress.
- RWA-backed stablecoins are the emerging middle ground. On-chain mechanisms with real-world collateral combine the best of both worlds.
- Always ask where the yield comes from. If the answer is "mechanism design" or "future growth," you're looking at another Anchor waiting to unwind.
*I'm Uvin Vindula↗ — a Web3 and AI engineer building between Sri Lanka and the UK. I write technical deep-dives on DeFi protocols, smart contract architecture, and the infrastructure behind decentralized finance. If you're building a stablecoin integration, a DeFi protocol, or need a security review of your smart contracts, let's talk.*
Working on a Web3 or AI project?

Uvin Vindula
Web3 and AI engineer based in Sri Lanka and the UK. Author of The Rise of Bitcoin. Director of Blockchain and Software Solutions at Terra Labz. Founder of uvin.lk — Sri Lanka's Bitcoin education platform with 10,000+ learners.