A Foundry-powered implementation by Varun Chauhan
- Introduction
- System Overview
- Architecture
- Contracts
- Health Factor & Liquidations
- Mathematical Formulas
- Security Features
- Getting Started
- Testing
- Deployment
- Foundry Commands
- Risk Considerations
- Gas Optimization
- Contributing
- License
- Author
This repository contains a production-ready, over-collateralized, algorithmic stablecoin protocol designed to maintain a soft peg of 1 DSC = 1 USD. The system is inspired by MakerDAO's DAI but built from scratch with modern Solidity practices and comprehensive testing.
- 🔒 Exogenously collateralized: Backed by external crypto assets (WETH, WBTC)
- 📊 200% collateral requirement: Enforced via a 50% liquidation threshold
- 🌐 Fully on-chain & permissionless: No governance token, no fees
- ⚡ Built with Foundry: For blazing-fast compilation, testing, and deployment
- 🛡️ Security-first: Comprehensive testing with 100% line coverage
- 📈 Liquidation incentives: 10% bonus for liquidators maintaining system health
The DSC (Decentralized Stablecoin) system allows users to:
- Deposit approved collateral tokens (WETH, WBTC)
- Mint DSC stablecoins against their collateral
- Maintain a healthy collateralization ratio (≥200%)
- Redeem collateral by burning DSC tokens
- Participate in liquidations to maintain system health
| Property | Value | Description |
|---|---|---|
| Collateral Type | Exogenous | WETH, WBTC |
| Stability Mechanism | Algorithmic | Liquidation-based |
| Collateral Ratio | 200% minimum | Overcollateralized |
| Liquidation Threshold | 50% | Positions liquidatable at 150% ratio |
| Liquidation Bonus | 10% | Incentive for liquidators |
| Peg Target | $1.00 USD | Soft peg maintained |
flowchart LR
subgraph "External Assets"
WETH[WETH Token]
WBTC[WBTC Token]
end
subgraph "Price Feeds"
PF1[Chainlink WETH/USD<br/>Oracle]
PF2[Chainlink WBTC/USD<br/>Oracle]
end
subgraph "Core Protocol"
DSCEngine[DSC Engine<br/>Core Logic<br/>- Collateral Management<br/>- Minting/Burning<br/>- Liquidations<br/>- Health Checks]
DSCToken[DSC Token<br/>ERC-20<br/>- Mint/Burn Functions<br/>- Ownership Controls]
end
subgraph "Participants"
Users[Regular Users<br/>- Deposit Collateral<br/>- Mint DSC<br/>- Redeem Collateral<br/>- Burn DSC]
Liquidators[Liquidators<br/>- Monitor Health Factors<br/>- Liquidate Unhealthy Positions<br/>- Receive 10% Bonus]
end
subgraph "Oracle Library"
OracleLib[OracleLib<br/>- Stale Price Protection<br/>- 3 Hour Timeout<br/>- Price Validation]
end
Users -->|1. Deposit| WETH
Users -->|1. Deposit| WBTC
WETH -->|Collateral| DSCEngine
WBTC -->|Collateral| DSCEngine
DSCEngine -->|2. Mint| DSCToken
DSCToken -->|To User| Users
PF1 -->|Price Data| OracleLib
PF2 -->|Price Data| OracleLib
OracleLib -->|Validated Prices| DSCEngine
DSCEngine -->|Health Factor Check| DSCEngine
Liquidators -->|3. Liquidate<br/>Unhealthy Positions| DSCEngine
DSCEngine -->|Collateral + 10% Bonus| Liquidators
style DSCEngine fill:#ff9800,color:#fff
style DSCToken fill:#4caf50,color:#fff
style Users fill:#2196f3,color:#fff
style Liquidators fill:#9c27b0,color:#fff
style PF1 fill:#f44336,color:#fff
style PF2 fill:#f44336,color:#fff
style OracleLib fill:#ff5722,color:#fff
sequenceDiagram
participant U as User
participant DE as DSCEngine
participant DSC as DSC Token
participant OL as OracleLib
participant CL as Chainlink Oracle
participant L as Liquidator
Note over U,L: Normal User Flow
U->>DE: 1. depositCollateral(WETH, amount)
DE->>OL: Validate price freshness
OL->>CL: Get latest price data
CL->>OL: Return price with timestamp
OL->>DE: Validated price (revert if stale)
DE->>DE: Update user collateral balance
DE->>U: Transfer WETH to contract
U->>DE: 2. mintDsc(amount)
DE->>DE: Calculate health factor
DE->>DE: Check HF ≥ 1.0
DE->>DSC: mint(user, amount)
DSC->>U: Transfer DSC tokens
Note over U,L: Liquidation Flow
CL->>OL: Price update (collateral drops)
OL->>DE: New validated price
DE->>DE: User health factor < 1.0
L->>DE: 3. liquidate(collateral, user, debtToCover)
DE->>DE: Validate position is liquidatable
DE->>DE: Calculate collateral + 10% bonus
DE->>U: Transfer collateral to liquidator
DE->>DSC: burnDsc(user, debtToCover)
DE->>DE: Verify HF improved
DE->>DE: Check liquidator HF remains healthy
graph TB
subgraph "User Interface Layer"
UI[Frontend dApp]
Web3[Web3 Wallet]
end
subgraph "Smart Contract Layer"
subgraph "Core Contracts"
Engine[DSCEngine.sol<br/>- Collateral Management<br/>- Minting/Burning<br/>- Liquidations<br/>- Health Checks<br/>- Reentrancy Protection]
Token[DecentralizedStableCoin.sol<br/>- ERC-20 Implementation<br/>- Mint/Burn Functions<br/>- Ownership Controls<br/>- Only DSCEngine Access]
end
subgraph "Libraries"
OracleLib[OracleLib.sol<br/>- Stale Price Protection<br/>- 3 Hour Timeout<br/>- Price Validation]
end
subgraph "External Dependencies"
Oracle1[Chainlink WETH/USD<br/>Price Feed]
Oracle2[Chainlink WBTC/USD<br/>Price Feed]
WETH[WETH Contract<br/>ERC-20]
WBTC[WBTC Contract<br/>ERC-20]
end
end
subgraph "Blockchain Layer"
Ethereum[Ethereum Network]
end
UI --> Web3
Web3 --> Engine
Engine <--> Token
Engine --> OracleLib
OracleLib <--> Oracle1
OracleLib <--> Oracle2
Engine <--> WETH
Engine <--> WBTC
Engine --> Ethereum
Token --> Ethereum
style Engine fill:#ff6b35,color:#fff
style Token fill:#f7931e,color:#fff
style OracleLib fill:#ff5722,color:#fff
style Oracle1 fill:#375bd2,color:#fff
style Oracle2 fill:#375bd2,color:#fff
contract DecentralizedStableCoin is ERC20Burnable, Ownable- ERC-20 token contract for DSC stablecoin
- Extends OpenZeppelin's
ERC20BurnableandOwnable - Minting/burning restricted to
DSCEnginecontract only - Implements standard ERC-20 functionality with burn capability
Key Functions:
mint(address to, uint256 amount)- Only callable by DSCEngineburn(uint256 amount)- Inherited from ERC20Burnable- Standard ERC-20 functions (
transfer,approve, etc.)
contract DSCEngine is ReentrancyGuard- Core protocol logic and system management
- Handles all collateral operations and DSC lifecycle
- Implements comprehensive safety checks and liquidation mechanisms
- Uses Chainlink oracles for reliable price feeds
Core Functions:
| Function | Purpose | Access |
|---|---|---|
depositCollateral() |
Deposit approved collateral | Public |
mintDsc() |
Mint DSC against collateral | Public |
depositCollateralAndMintDsc() |
Combined deposit + mint | External |
redeemCollateral() |
Withdraw collateral | External |
burnDsc() |
Burn DSC to improve health | External |
liquidate() |
Liquidate unhealthy positions | External |
getHealthFactor() |
Check position health | View |
uint256 private constant LIQUIDATION_THRESHOLD = 50; // 50%
uint256 private constant LIQUIDATION_BONUS = 10; // 10%
uint256 private constant MIN_HEALTH_FACTOR = 1 ether; // 1.0
uint256 private constant PRECISION = 1e18; // 18 decimalsThe health factor determines the safety of a user's position:
healthFactor = (collateralValueUSD * LIQUIDATION_THRESHOLD) / totalDscMintedHealth Factor Interpretation:
- > 1.0: ✅ Healthy position, cannot be liquidated
- = 1.0:
⚠️ At liquidation threshold, risky position - < 1.0: ❌ Unhealthy position, can be liquidated
- ∞: 🌟 No debt, perfect health
sequenceDiagram
participant U as User (Underwater)
participant L as Liquidator
participant E as DSCEngine
participant OL as OracleLib
participant C as Chainlink
participant DSC as DSC Token
Note over U: Health Factor < 1.0 (MIN_HEALTH_FACTOR)
L->>E: liquidate(collateral, user, debtToCover)
E->>E: Check initial health factor < 1.0
E->>OL: Get validated price data
OL->>C: latestRoundData() with staleness check
C->>OL: Return price + timestamp
OL->>E: Validated price (revert if > 3 hours old)
E->>E: Calculate tokenAmountFromDebtCovered
E->>E: Calculate bonusCollateral (10% of debt coverage)
E->>E: totalCollateralToRedeem = debt + bonus
E->>U: Transfer collateral to liquidator
E->>DSC: burnDsc(user, debtToCover)
E->>E: Verify HF improved (final > initial)
E->>E: Check liquidator's own HF remains healthy
Note over U: Health Factor improved
Note over L: Received collateral + 10% bonus
Liquidation Mechanics:
-
Pre-liquidation Validation:
- Position must have health factor < 1.0 (MIN_HEALTH_FACTOR)
- Liquidator must provide valid collateral token address
- Debt amount must be greater than zero
-
Price Validation:
- OracleLib checks price staleness (3-hour timeout)
- Reverts if price is stale or invalid
- Ensures accurate liquidation calculations
-
Collateral Calculation:
tokenAmountFromDebtCovered = (debtToCover × PRECISION) ÷ (price × ADDITIONAL_PRICEFEED_PRECISION)bonusCollateral = (tokenAmountFromDebtCovered × LIQUIDATION_BONUS) ÷ LIQUIDATION_PRECISIONtotalCollateralToRedeem = tokenAmountFromDebtCovered + bonusCollateral
-
State Updates:
- Transfer collateral from liquidated user to liquidator
- Burn DSC debt from liquidated user's position
- Update user's collateral and debt balances
-
Post-liquidation Validation:
- Verify liquidation improved user's health factor
- Ensure liquidator's own position remains healthy
- Revert if health factor didn't improve
Liquidation Constants:
LIQUIDATION_THRESHOLD = 50; // 50%
LIQUIDATION_BONUS = 10; // 10%
MIN_HEALTH_FACTOR = 1 ether; // 1.0
LIQUIDATION_PRECISION = 100; // 100
PRECISION = 1e18; // 18 decimals
ADDITIONAL_PRICEFEED_PRECISION = 1e10; // 10 decimalsHealth Factor:
Health Factor = (Collateral Value USD × 50%) ÷ Total DSC Minted
Collateral Value:
Collateral Value = Σ(Token Amount × Token Price USD)
Liquidation Collateral:
Collateral to Transfer = (Debt to Cover ÷ Collateral Price) × 1.10
Healthy Position:
- User deposits: $2000 worth of ETH
- User mints: $800 DSC
- Health Factor: ($2000 × 0.5) ÷ $800 = 1.25 ✅
Liquidatable Position:
- ETH price drops, collateral now worth: $1200
- User still owes: $800 DSC
- Health Factor: ($1200 × 0.5) ÷ $800 = 0.75 ❌
- Chainlink Integration: Decentralized, battle-tested price feeds
- Stale Price Protection: Using OracleLib for additional safety
- Multiple Price Sources: WETH/USD and WBTC/USD feeds
- Reentrancy Protection: All state-changing functions protected
- Input Validation: Comprehensive validation of parameters
- Health Factor Monitoring: Continuous position health checks
- Access Control: Proper ownership and permission management
- Liquidation Incentives: 10% bonus ensures rapid liquidations
- Overcollateralization: 200% minimum provides price volatility buffer
- Partial Liquidations: Allows precise debt coverage
- Foundry: Install via
curl -L https://foundry.paradigm.xyz | bash - Git: For cloning and version control
- Node.js 18+: For additional tooling (optional)
# Clone the repository
git clone https://github.com/chauhan-varun/foundry-defi-stablecoin
cd foundry-defi-stablecoin
# Install dependencies
forge install
# Build contracts
forge buildCreate .env file:
cp .env.example .envConfigure your environment variables:
# RPC URLs
MAINNET_RPC_URL=https://eth-mainnet.alchemyapi.io/v2/your-api-key
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/your-api-key
# Private Keys (use test accounts only)
PRIVATE_KEY=your-private-key-here
# API Keys
ETHERSCAN_API_KEY=your-etherscan-api-keytest/
├── fuzz/
│ ├── continueOnRevert/
│ │ ├── ContinueOnRevertHandler.t.sol
│ │ └── ContinueOnRevertInvariants.t.sol
│ ├── failOnRevert/
│ │ ├── StopOnRevertHandler.t.sol
│ │ └── StopOnRevertInvariants.t.sol
├── mocks/
│ ├── ERC20Mock.sol
│ ├── MockFailedMintDSC.sol
│ ├── MockFailedTransfer.sol
│ ├── MockFailedTransferFrom.sol
│ ├── MockMoreDebtDSC.sol
│ └── MockV3Aggregator.sol
├── unit/
│ ├── DecentralizedStableCoinTest.t.sol
│ ├── DSCEngineTest.t.sol
│ └── OracleLibTest.t.sol
# Run all tests
forge test
# Run with verbosity
forge test -vv
# Run specific test file
forge test --match-contract DSCEngineTest
# Run specific test function
forge test --match-test testConstructorSetsTokensAndPriceFeeds
# Run tests with gas reporting
forge test --gas-report
# Generate coverage report
forge coverage
# Generate detailed coverage report
forge coverage --report lcovOur test suite achieves 100% line coverage with comprehensive scenarios:
- ✅ Unit Tests: All individual functions tested
- ✅ Integration Tests: End-to-end user flows
- ✅ Edge Cases: Boundary conditions and error states
- ✅ Fuzz Testing: Property-based testing with random inputs
- ✅ Liquidation Scenarios: Complex multi-user interactions
# View coverage report
forge coverage --report summary
# Generate HTML coverage report
genhtml lcov.info --output-directory coverage-html# Terminal 1: Start Anvil
anvil
# Terminal 2: Deploy contracts
forge script script/DeployDSC.s.sol \
--rpc-url http://127.0.0.1:8545 \
--broadcast \
--private-key $PRIVATE_KEY \
-vvvvforge script script/DeployDSC.s.sol \
--rpc-url $SEPOLIA_RPC_URL \
--broadcast \
--private-key $PRIVATE_KEY \
--verify \
--etherscan-api-key $ETHERSCAN_API_KEY \
-vvvv# Dry run first
forge script script/DeployDSC.s.sol \
--rpc-url $MAINNET_RPC_URL \
--private-key $PRIVATE_KEY
# If dry run succeeds, deploy
forge script script/DeployDSC.s.sol \
--rpc-url $MAINNET_RPC_URL \
--broadcast \
--private-key $PRIVATE_KEY \
--verify \
--etherscan-api-key $ETHERSCAN_API_KEY \
-vvvv| Command | Purpose |
|---|---|
forge build |
Compile contracts |
forge test |
Run test suite |
forge coverage |
Generate coverage report |
forge fmt |
Format Solidity code |
forge snapshot |
Create gas snapshots |
forge doc |
Generate documentation |
# Install specific dependency
forge install openzeppelin/openzeppelin-contracts
# Remove dependency
forge remove openzeppelin-contracts
# Update all dependencies
forge update
# Create gas snapshot for optimization
forge snapshot
# Generate Solidity documentation
forge doc
# Flatten contracts for verification
forge flatten src/DSCEngine.sol| Risk Type | Impact | Mitigation |
|---|---|---|
| Oracle Risk | High | Chainlink integration + stale price protection |
| Smart Contract Risk | High | Extensive testing + code audits |
| Liquidation Risk | Medium | Economic incentives + partial liquidations |
| Price Volatility | Medium | 200% overcollateralization requirement |
- Price Feed Manipulation: Chainlink oracles provide decentralized pricing
- Flash Loan Attacks: Reentrancy guards and health factor checks
- Governance Risk: No governance token reduces centralization risk
- Liquidity Risk: Market makers needed for DSC/USD liquidity
- Maintain health factor well above 1.2 for safety buffer
- Monitor collateral prices regularly
- Consider partial redemptions during market volatility
- Understand liquidation mechanics before using the protocol
- Packed Structs: Efficient storage layout
- Batch Operations: Combined deposit + mint functions
- Minimal External Calls: Reduced gas costs
- Efficient Loops: Optimized collateral iterations
| Operation | Estimated Gas | Notes |
|---|---|---|
| Deposit Collateral | ~85,000 | First deposit higher due to storage |
| Mint DSC | ~65,000 | Includes health factor check |
| Combined Deposit + Mint | ~140,000 | More efficient than separate calls |
| Liquidation | ~180,000 | Complex multi-step operation |
| Redeem Collateral | ~70,000 | Including health factor verification |
We welcome contributions! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write comprehensive tests for new functionality
- Ensure all tests pass (
forge test) - Verify code formatting (
forge fmt) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow Solidity Style Guide
- Write comprehensive NatSpec documentation
- Maintain 100% test coverage for new code
- Include gas optimization considerations
- Use meaningful variable and function names
- Unit Tests: Test individual functions in isolation
- Integration Tests: Test complete user workflows
- Edge Cases: Test boundary conditions and error states
- Gas Tests: Verify gas usage is reasonable
- Coverage: Maintain 100% line coverage
This project is licensed under the MIT License - see the LICENSE file for details.
MIT License
Copyright (c) 2025 Varun Chauhan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
Varun Chauhan - Smart Contract Developer & DeFi Researcher
- 🐦 Twitter: @varunchauhanx
- 💼 LinkedIn: chauhan-varun
- 🐙 GitHub: chauhan-varun
- 📧 Email: [email protected]
- OpenZeppelin - For battle-tested smart contract libraries
- Chainlink - For reliable decentralized oracle infrastructure
- Foundry - For the excellent development framework
- MakerDAO - For pioneering decentralized stablecoin mechanisms
⭐ Star this repo if you found it helpful! ⭐
Built with ❤️ using Foundry
