TechLead
Lesson 12 of 20
5 min read
Web3 & Blockchain

DeFi Fundamentals

Understand decentralized finance protocols including lending, borrowing, liquidity pools, automated market makers, and yield farming

What is DeFi?

Decentralized Finance (DeFi) refers to financial services built on public blockchains — primarily Ethereum — that operate without traditional intermediaries like banks, brokers, or exchanges. DeFi protocols use smart contracts to automate financial operations such as lending, borrowing, trading, and earning yield. Anyone with an internet connection and a wallet can access these services permissionlessly.

Core DeFi Principles

  • Permissionless: Anyone can use DeFi protocols without approval, KYC, or geographic restrictions
  • Non-custodial: Users maintain control of their assets through their own wallets — no deposits with a third party
  • Composable: Protocols can be combined like building blocks — "money Legos" — creating complex financial products from simple ones
  • Transparent: All transactions, rates, and protocol code are publicly verifiable on-chain
  • Programmable: Financial logic is encoded in smart contracts that execute automatically

Automated Market Makers (AMMs)

Traditional exchanges use order books where buyers and sellers place limit orders. AMMs like Uniswap replace order books with liquidity pools — smart contracts holding reserves of two tokens. The price is determined algorithmically by the ratio of the reserves, typically using the constant product formula: x * y = k, where x and y are the reserves of each token and k remains constant.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/// @title SimpleAMM — Demonstrates constant product AMM
contract SimpleAMM {
    IERC20 public tokenA;
    IERC20 public tokenB;
    uint256 public reserveA;
    uint256 public reserveB;

    // LP token tracking (simplified)
    mapping(address => uint256) public liquidity;
    uint256 public totalLiquidity;

    uint256 public constant FEE_NUMERATOR = 3;    // 0.3% fee
    uint256 public constant FEE_DENOMINATOR = 1000;

    event Swap(address indexed user, address tokenIn, uint256 amountIn, uint256 amountOut);
    event LiquidityAdded(address indexed user, uint256 amountA, uint256 amountB);

    constructor(address _tokenA, address _tokenB) {
        tokenA = IERC20(_tokenA);
        tokenB = IERC20(_tokenB);
    }

    /// @notice Add liquidity to the pool
    function addLiquidity(uint256 amountA, uint256 amountB) external {
        tokenA.transferFrom(msg.sender, address(this), amountA);
        tokenB.transferFrom(msg.sender, address(this), amountB);

        uint256 shares;
        if (totalLiquidity == 0) {
            shares = sqrt(amountA * amountB);
        } else {
            shares = min(
                (amountA * totalLiquidity) / reserveA,
                (amountB * totalLiquidity) / reserveB
            );
        }

        liquidity[msg.sender] += shares;
        totalLiquidity += shares;
        reserveA += amountA;
        reserveB += amountB;
        emit LiquidityAdded(msg.sender, amountA, amountB);
    }

    /// @notice Swap tokenA for tokenB using constant product formula
    function swapAForB(uint256 amountIn) external returns (uint256 amountOut) {
        uint256 amountInWithFee = amountIn * (FEE_DENOMINATOR - FEE_NUMERATOR);
        amountOut = (amountInWithFee * reserveB) / (reserveA * FEE_DENOMINATOR + amountInWithFee);

        tokenA.transferFrom(msg.sender, address(this), amountIn);
        tokenB.transfer(msg.sender, amountOut);

        reserveA += amountIn;
        reserveB -= amountOut;
        emit Swap(msg.sender, address(tokenA), amountIn, amountOut);
    }

    function sqrt(uint256 y) internal pure returns (uint256 z) {
        if (y > 3) { z = y; uint256 x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } }
        else if (y != 0) { z = 1; }
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
}

Lending and Borrowing

Lending protocols like Aave and Compound allow users to supply assets to earn interest and borrow assets against their collateral. Because blockchain has no concept of identity or credit scores, all DeFi loans are over-collateralized — you must deposit more value than you borrow. If your collateral's value drops below a threshold, your position can be liquidated.

import { ethers } from 'ethers';

// Interacting with Aave V3 using ethers.js
const AAVE_POOL = '0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2'; // Mainnet
const poolABI = [
  'function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)',
  'function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf)',
  'function repay(address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf)',
  'function getUserAccountData(address user) view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor)',
];

const pool = new ethers.Contract(AAVE_POOL, poolABI, signer);

// Step 1: Approve Aave to spend your USDC
const USDC = new ethers.Contract(usdcAddress, erc20ABI, signer);
await USDC.approve(AAVE_POOL, ethers.parseUnits('1000', 6));

// Step 2: Supply 1000 USDC as collateral
await pool.supply(usdcAddress, ethers.parseUnits('1000', 6), myAddress, 0);

// Step 3: Borrow 500 USDC worth of DAI
await pool.borrow(daiAddress, ethers.parseUnits('500', 18), 2, 0, myAddress);
// interestRateMode: 1 = stable, 2 = variable

// Check health factor (should be > 1.0 to avoid liquidation)
const accountData = await pool.getUserAccountData(myAddress);
const healthFactor = ethers.formatUnits(accountData.healthFactor, 18);
console.log('Health Factor:', healthFactor); // e.g., "1.85"

Yield Farming and Liquidity Mining

Yield farming is the practice of moving assets between DeFi protocols to maximize returns. Users provide liquidity to pools and earn trading fees, protocol tokens, or both. Liquidity mining specifically refers to earning governance tokens as rewards for providing liquidity — protocols distribute their native tokens to incentivize liquidity provision.

DeFi Protocol Categories

Category Examples How You Earn
DEX (Trading)Uniswap, Curve, SushiSwapTrading fees from LP positions
LendingAave, Compound, MorphoInterest from borrowers
StablecoinsMakerDAO (DAI), FraxStability fees from collateral
Liquid StakingLido (stETH), Rocket PoolETH staking rewards
Yield AggregatorsYearn Finance, BeefyAuto-compounded yields

Risks in DeFi

Key Risks to Understand

  • Smart contract risk: Bugs or vulnerabilities in protocol code can lead to exploits and loss of funds
  • Impermanent loss: LP providers can lose value relative to simply holding tokens when prices diverge significantly
  • Liquidation risk: Borrowers face liquidation if their collateral value drops below the required threshold
  • Oracle manipulation: Protocols relying on price oracles can be exploited through price manipulation attacks
  • Regulatory risk: DeFi protocols operate in a rapidly evolving regulatory landscape

Continue Learning