Decentralized Stablecoin

A fully decentralized, algorithmic stablecoin system pegged to USD, backed by WETH and WBTC collateral. Built with Foundry. 🚀

Exogenous Collateral Algorithmic Dollar Pegged 200% Collateralized
3
Smart Contracts
DSCEngine, DSC Token, OracleLib
52
Comprehensive Tests
Unit, Fuzz & Invariant
50%
Liquidation Threshold
Overcollateralization
10%
Liquidation Bonus
Liquidator Incentive

Try it Out! 🎮

Interact with the live deployed contracts on Sepolia testnet

🦊

Connect Your Wallet

Connect MetaMask to interact with the DSC protocol on Sepolia

⚠️ Make sure you're on Sepolia Testnet

System Overview

Protocol Architecture

👤
USER
Deposits WETH/WBTC, Mints DSC
↓↑
DSCEngine.sol
Deposit
Collateral
Mint/Burn
DSC Tokens
Liquidate
Bad Positions
↓↑
DecentralizedStableCoin
ERC20 Token
Chainlink Oracles
Price Feeds
OracleLib
Stale Price Check

User Journey

1
Deposit
Deposit WETH/WBTC as collateral
2
Mint
Mint DSC against collateral
3
Use
Trade, transfer, or hold DSC
4
Repay
Burn DSC & withdraw collateral

Key Concepts

What is Health Factor?

Health Factor determines if your position is safe or can be liquidated. It's calculated based on your collateral value and debt.

Formula
HF = (Collateral × 50%) / Debt
HF > 1.0 = Safe
HF = 1.0 = At Risk
HF < 1.0 = Liquidatable!

Interactive Calculator

Health Factor
1.25
✓ Safe Position

Smart Contracts 🧠

⚙️

DSCEngine.sol

Core protocol logic - handles deposits, minting, burning, and liquidations

View Code →
🪙

DecentralizedStableCoin.sol

ERC20 stablecoin token - only DSCEngine can mint/burn

View Code →
🔮

OracleLib.sol

Chainlink wrapper with staleness protection

View Code →

DSCEngine.sol - Core Functions

depositCollateral()

function depositCollateral(
    address _collateralAddress,
    uint256 _collateralAmount
) public moreThanZero(_collateralAmount) nonReentrant isAllowedToken(_collateralAddress) {
    // Track user's collateral deposit
    s_collateralDeposited[msg.sender][_collateralAddress] += _collateralAmount;
    emit CollateralDeposited(msg.sender, _collateralAddress, _collateralAmount);

    // Transfer tokens from user to this contract
    bool success = IERC20(_collateralAddress).transferFrom(
        msg.sender,
        address(this),
        _collateralAmount
    );
    if (!success) revert DSCEngine__TransferFailed();
}

mintDSC()

function mintDSC(uint256 _amountOfDSCToMint) public moreThanZero(_amountOfDSCToMint) nonReentrant {
    // Increase user's debt
    s_DSCMinted[msg.sender] += _amountOfDSCToMint;

    // Check health factor - MUST stay >= 1.0
    _revertIfHealthFactorIsBroken(msg.sender);

    // Mint DSC tokens to user
    bool success = i_dsc.mint(msg.sender, _amountOfDSCToMint);
    if (!success) revert DSCEngine__MintFailed();
}

liquidate()

function liquidate(
    address _tokenCollateralAddress,
    address _user,
    uint256 _debtToCover
) public moreThanZero(_debtToCover) nonReentrant {
    // 1. Check target is liquidatable
    uint256 startingHealthFactor = _healthFactor(_user);
    if (startingHealthFactor >= MIN_HEALTH_FACTOR) {
        revert DSCEngine__HealthFactorIsNotBroken(startingHealthFactor);
    }

    // 2. Calculate collateral to seize (debt value + 10% bonus)
    uint256 tokenAmount = getTokenAmountFromUsd(_tokenCollateralAddress, _debtToCover);
    uint256 bonus = (tokenAmount * LIQUIDATION_BONUS) / LIQUIDATION_PRECISION;

    // 3. Transfer collateral to liquidator, burn their DSC
    _redeemCollateral(_user, msg.sender, _tokenCollateralAddress, tokenAmount + bonus);
    _burnDSC(_debtToCover, _user, msg.sender);

    // 4. Verify liquidation improved health
    if (_healthFactor(_user) <= startingHealthFactor) {
        revert DSCEngine__HealthFactorNotImproved();
    }
}

Testing Suite ✅

52
Total Tests
45
Unit Tests
5
Fuzz Tests
2
Invariant Tests

Unit Tests (DSCEngine.t.sol)

+

Fuzz Tests

+

Invariant Tests

+

Deployed Contracts 🚀

Live on Sepolia Testnet

🪙 DecentralizedStableCoin (DSC) Verified
0x47AE250261B6142a9Eede69F17FA11DF3d11D5e6
View on Etherscan ↗
⚙️ DSCEngine Verified
0x93d8535A43bC44b28441A42945e14f1CD5871831
View on Etherscan ↗
🔮 OracleLib Library
0x165a43AF20746074D4dbe554AB02a77e0B3892ac
View on Etherscan ↗

Deploy Your Own

# 1. Set up .env file
PRIVATE_KEY=0xyour_private_key
ALCHEMY=https://eth-sepolia.g.alchemy.com/v2/your_key
ETHERSCAN=your_etherscan_api_key

# 2. Deploy & Verify
source .env && forge script script/DeployDSCEngine.s.sol \
    --rpc-url $ALCHEMY \
    --broadcast \
    --verify \
    --etherscan-api-key $ETHERSCAN