DeFi Protocols: Aave, Compound and MakerDAO Deep Dive
In this tutorial, you'll learn major DeFi protocols including Aave for lending, Compound for money markets, and MakerDAO for stablecoins with practical interaction examples. Why it matters: Aave, Compound, and MakerDAO are the three foundational DeFi protocols, managing over $30 billion in combined total value locked and enabling the entire DeFi ecosystem through lending, borrowing, and stablecoin creation. By the end, you'll interact with each protocol programmatically.
DeFi protocols provide decentralized financial services through smart contracts, with Aave and Compound dominating lending markets while MakerDAO provides the DAI stablecoin that underpins DeFi liquidity.
Aave Lending Protocol
Aave is a non-custodial liquidity protocol where users deposit assets to earn interest and borrow assets by providing collateral.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
// Simplified Aave pool interaction contract
contract AaveInteraction {
ILendingPool public lendingPool;
constructor(address _pool) {
lendingPool = ILendingPool(_pool);
}
function deposit(address _asset, uint256 _amount) external {
IERC20(_asset).approve(address(lendingPool), _amount);
lendingPool.deposit(_asset, _amount, msg.sender, 0);
}
function borrow(address _asset, uint256 _amount) external {
lendingPool.borrow(_asset, _amount, 2, 0, msg.sender);
// Interest rate mode: 1=stable, 2=variable
}
function repay(address _asset, uint256 _amount) external {
IERC20(_asset).approve(address(lendingPool), _amount);
lendingPool.repay(_asset, _amount, 2, msg.sender);
}
function withdraw(address _asset, uint256 _amount) external {
lendingPool.withdraw(_asset, _amount, msg.sender);
}
}
const { ethers } = require("ethers");
async function interactWithAave() {
const provider = new ethers.JsonRpcProvider("https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY");
const signer = new ethers.Wallet("YOUR_KEY", provider);
// Aave V3 Pool (Ethereum Mainnet)
const poolAddress = "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2";
const poolABI = [
"function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external",
"function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf) external",
"function withdraw(address asset, uint256 amount, address to) external returns (uint256)",
"function repay(address asset, uint256 amount, uint256 rateMode, address onBehalfOf) external returns (uint256)",
"function getUserAccountData(address user) external view returns (uint256 totalCollateralETH, uint256 totalDebtETH, uint256 availableBorrowsETH, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)",
"function getReserveData(address asset) external view returns (tuple(uint256, ...) )]
];
const pool = new ethers.Contract(poolAddress, poolABI, signer);
// Check account health
const accountData = await pool.getUserAccountData(signer.address);
console.log("Account health:");
console.log(" Total collateral:", ethers.formatEther(accountData.totalCollateralETH), "ETH");
console.log(" Total debt:", ethers.formatEther(accountData.totalDebtETH), "ETH");
console.log(" Available to borrow:", ethers.formatEther(accountData.availableBorrowsETH), "ETH");
console.log(" LTV:", accountData.ltv.toString());
console.log(" Health factor:", ethers.formatEther(accountData.healthFactor));
// Deposit USDC
const usdcAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
const usdcDecimals = 6;
const depositAmount = ethers.parseUnits("1000", usdcDecimals); // 1000 USDC
// Expected output:
// Account health:
// Total collateral: 0.0 ETH
// Total debt: 0.0 ETH
// Available to borrow: 0.0 ETH
// LTV: 0
// Health factor: ∞
}
interactWithAave();
flowchart LR A[Depositor] -->|Deposit aUSDC| B[Aave Pool] B -->|Mint aToken| A C[Borrower] -->|Deposit Collateral| B B -->|Borrow variable/stable| C C -->|Pay interest| B B -->|Distribute yield| A D[Liquidator] -->|Repay debt| B B -->|Seize collateral| D E[Flash Borrower] -->|Flash loanNo collateral| B B -->|Return + fee| E
Compound Protocol
Compound is an algorithmic money market protocol similar to Aave but with cToken architecture and COMP governance.
const { ethers } = require("ethers");
async function interactWithCompound() {
const provider = new ethers.JsonRpcProvider("https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY");
const signer = new ethers.Wallet("YOUR_KEY", provider);
// cUSDC (Compound USDC) contract
const cUSDCAddress = "0x39AA39c021dfbaE8faC545936693aC917d5E7563";
const cTokenABI = [
"function mint(uint256 mintAmount) external returns (uint256)",
"function redeem(uint256 redeemTokens) external returns (uint256)",
"function borrow(uint256 borrowAmount) external returns (uint256)",
"function repayBorrow(uint256 repayAmount) external returns (uint256)",
"function balanceOf(address owner) view returns (uint256)",
"function exchangeRateCurrent() view returns (uint256)",
"function supplyRatePerBlock() view returns (uint256)",
"function borrowRatePerBlock() view returns (uint256)",
"function getCash() view returns (uint256)",
"function totalBorrows() view returns (uint256)",
"function totalSupply() view returns (uint256)]
];
const cUSDC = new ethers.Contract(cUSDCAddress, cTokenABI, signer);
// Get supply rate
const supplyRate = await cUSDC.supplyRatePerBlock();
const borrowRate = await cUSDC.borrowRatePerBlock();
// Convert to APY: (1 + rate_per_block)^blocks_per_year - 1
const blocksPerYear = 2102400; // ~4 second blocks
const supplyAPY = (Math.pow(1 + Number(ethers.formatUnits(supplyRate, 18)), blocksPerYear) - 1) * 100;
const borrowAPY = (Math.pow(1 + Number(ethers.formatUnits(borrowRate, 18)), blocksPerYear) - 1) * 100;
console.log("Compound USDC Market:");
console.log(` Supply APY: ${supplyAPY.toFixed(2)}%`);
console.log(` Borrow APY: ${borrowAPY.toFixed(2)}%`);
// Get exchange rate (1 cUSDC = how much USDC?)
const exchangeRate = await cUSDC.exchangeRateCurrent();
console.log(` Exchange rate: ${ethers.formatUnits(exchangeRate, 28)} USDC/cUSDC`);
// Get market liquidity
const cash = await cUSDC.getCash();
console.log(` Available liquidity: ${ethers.formatUnits(cash, 6)} USDC`);
const totalBorrows = await cUSDC.totalBorrows();
console.log(` Total borrows: ${ethers.formatUnits(totalBorrows, 6)} USDC`);
// Calculate utilization rate
const utilization = Number(totalBorrows) / (Number(totalBorrows) + Number(cash));
console.log(` Utilization: ${(utilization * 100).toFixed(2)}%`);
}
interactWithCompound();
// Expected output:
// Compound USDC Market:
// Supply APY: 3.45%
// Borrow APY: 5.12%
// Exchange rate: 0.020000 USDC/cUSDC
// Available liquidity: 50000000.00 USDC
// Total borrows: 75000000.00 USDC
// Utilization: 60.00%
MakerDAO and DAI Stablecoin
MakerDAO is a decentralized stablecoin protocol that maintains DAI's peg to $1 through overcollateralized vaults (formerly CDPs).
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
// Simplified MakerDAO vault interaction
contract MakerVault {
IDSProxy public proxy;
IManager public manager;
function openVault(address _collateralType) external returns (uint256 vaultId) {
vaultId = manager.open(_collateralType, address(this));
}
function depositCollateral(uint256 _vaultId, uint256 _amount) external {
IERC20(collateral).approve(address(manager), _amount);
manager.deposit(_vaultId, _amount);
}
function generateDAI(uint256 _vaultId, uint256 _amount) external {
manager.draw(_vaultId, _amount);
}
function repayDAI(uint256 _vaultId, uint256 _amount) external {
IERC20(dai).approve(address(manager), _amount);
manager.wipe(_vaultId, _amount);
}
function withdrawCollateral(uint256 _vaultId, uint256 _amount) external {
manager.free(_vaultId, _amount);
}
}
const { ethers } = require("ethers");
async function makerDAOExample() {
const provider = new ethers.JsonRpcProvider("https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY");
// DAI token
const daiAddress = "0x6B175474E89094C44Da98b954EedeAC495271d0F";
const dai = new ethers.Contract(daiAddress, [
"function balanceOf(address) view returns (uint256)",
"function totalSupply() view returns (uint256)]
], provider);
// Get DAI stats
const totalSupply = await dai.totalSupply();
console.log("DAI total supply:", ethers.formatEther(totalSupply));
// Check DAI/USD peg via Chainlink oracle
const oracleAddress = "0xAed0c38402a5d19df6E4c03F4E2DceD6e29c1ee9";
const oracle = new ethers.Contract(oracleAddress, [
"function latestRoundData() view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)]
], provider);
const roundData = await oracle.latestRoundData();
const daiPrice = Number(roundData.answer) / 1e8;
console.log("DAI/USD price:", daiPrice.toFixed(4));
// Check if DAI is pegged
const deviation = Math.abs(daiPrice - 1) * 100;
console.log(`Peg deviation: ${deviation.toFixed(4)}%`);
if (deviation > 1) {
console.log("DAI is de-pegged!");
} else {
console.log("DAI is within peg range.");
}
// Get Maker protocol stats
const mcdVat = new ethers.Contract("0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B", [
"function debt() view returns (uint256)]
], provider);
const systemDebt = await mcdVat.debt();
console.log("System debt (total DAI):", ethers.formatEther(systemDebt));
}
makerDAOExample();
// Expected output:
// DAI total supply: 5000000000.00
// DAI/USD price: 1.0002
// Peg deviation: 0.0200%
// DAI is within peg range.
// System debt (total DAI): 5000000000.00
Comparing Protocols
| Feature | Aave | Compound | MakerDAO |
|---|---|---|---|
| Lending | aTokens | cTokens | Vault-based |
| Interest Rate | Variable + Stable | Algorithmic | Stability fee |
| Governance | AAVE token | COMP token | MKR token |
| Unique Feature | Flash loans, credit delegation | COMP rewards, cToken composability | DAI stablecoin, Peg Stability Module |
| Collateral Type | Multiple (40+ assets) | Multiple (20+ assets) | Mostly ETH, stETH, USDC |
| Risk | Smart contract, oracle | Smart contract, oracle | Collateral volatility, governance |
Common Errors and Misunderstandings
1. Not Understanding Liquidation
Each protocol has different liquidation thresholds. Aave liquidates at health factor < 1, Compound at collateral factor ~75-85%. Know these before borrowing.
2. Confusing Variable and Stable Rates
Aave offers both. Variable rates fluctuate with market conditions. Stable rates are fixed for a period but can be adjusted by the protocol. Variable rates are usually lower initially.
3. Forgetting cToken Exchange Rate
In Compound, cTokens appreciate against the underlying (not increase in quantity). 1 cUSDC = more USDC over time. Users redeem cTokens for the underlying plus interest.
4. DAI Depeg Risk
DAI has historically depegged during extreme market conditions (March 2020, $0.88; March 2023, $0.90). Understanding the Peg Stability Module and liquidation mechanisms is essential.
5. Underestimating Governance Risk
All three protocols are governed by token holders. Governance attacks (proposing malicious upgrades) pose systemic risks. Monitor active proposals.
Practice Questions
How does Aave's aToken model differ from Compound's cToken model? Aave aTokens increase in quantity over time (rebasing). Compound cTokens appreciate in value against the underlying (non-rebasing, exchange rate increases).
What is a flash loan on Aave? A flash loan allows borrowing any amount of assets without collateral, as long as the loan is repaid within the same transaction. If not repaid, the transaction reverts.
How does MakerDAO maintain DAI's peg? Through overcollateralized vaults (minimum 150-170%), the Peg Stability Module (direct USDC/DAI swaps), DAI Savings Rate (adjusting demand), and arbitrage incentives.
What is the health factor in Aave? Health Factor = (Total Collateral * Liquidation Threshold) / Total Borrowed. When below 1, the position is liquidatable. Most users maintain > 1.5 for safety.
How does Compound's interest rate model work? Interest rates are a function of utilization rate (borrows / total liquidity). Higher utilization = higher rates. The "kink" point (~80%) creates steep rate increases above optimal utilization.
Challenge
Build a DeFi portfolio manager in TypeScript using ethers.js that tracks a user's positions across Aave, Compound, and MakerDAO. Calculate net APY across all positions, detect positions approaching liquidation (health factor < 1.2), estimate gas costs for moving positions between protocols for yield optimization, and provide alerts for governance proposals that affect the user.
Real-World Task
Create a yield optimization strategy using Solidity that deposits ETH into Aave, borrows stablecoins against it, deposits the stablecoins into Compound for yield, claims COMP rewards, and compounds the rewards back into the position. Implement safety checks: maintain health factor above 1.8, handle liquidation warnings via React notifications, and allow emergency withdrawal.
Frequently Asked Questions
Next Steps
After mastering these protocols, explore DeFi composability by combining them in strategies, then study Web3 Security for protecting user funds in DeFi applications.
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro