Tutorial·12 मिनट का पठन·Solingo द्वारा

DeFi Development Guide — अपना पहला Protocol बनाएं

AMMs, lending pools और yield farming को समझें। Scratch से simple DeFi protocol build करें।

# DeFi Development Guide — अपना पहला Protocol बनाएं

Decentralized Finance (DeFi) ने financial industry को revolutionize किया है intermediaries को हटाकर और सभी को financial services access करने देकर smart contracts के through। इस comprehensive guide में, हम core DeFi primitives explore करेंगे और scratch से simple Automated Market Maker (AMM) protocol build करेंगे।

DeFi क्या है?

DeFi का मतलब है blockchain technology पर built financial applications जो traditional intermediaries जैसे banks या brokerages के बिना operate करते हैं। ये applications financial services automate करने के लिए smart contracts use करते हैं जैसे:

  • Trading (Decentralized Exchanges)
  • Lending and Borrowing
  • Staking and Yield Farming
  • Derivatives and Synthetic Assets
  • Insurance protocols

2026 में DeFi protocols में locked total value $150 billion exceed कर गया, demonstrating massive adoption।

Core DeFi Primitives

1. Decentralized Exchanges (DEX) और Automated Market Makers (AMM)

Traditional exchanges order books use करते हैं buyers और sellers को match करने के लिए। AMMs इसे liquidity pools और mathematical formulas से replace करते हैं। सबसे famous formula है constant product formula:

x * y = k

जहां:

  • x = token A का reserve
  • y = token B का reserve
  • k = constant product

Simple AMM Implementation

आइए basic AMM build करें:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

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

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

contract SimpleAMM is ERC20 {

IERC20 public immutable token0;

IERC20 public immutable token1;

uint256 public reserve0;

uint256 public reserve1;

constructor(address _token0, address _token1) ERC20("LP Token", "LP") {

token0 = IERC20(_token0);

token1 = IERC20(_token1);

}

// Add liquidity

function addLiquidity(uint256 amount0, uint256 amount1)

external

returns (uint256 shares)

{

// Transfer tokens to contract

token0.transferFrom(msg.sender, address(this), amount0);

token1.transferFrom(msg.sender, address(this), amount1);

// Calculate LP tokens to mint

if (totalSupply() == 0) {

// Initial liquidity

shares = sqrt(amount0 * amount1);

} else {

// Proportional to existing reserves

shares = min(

(amount0 * totalSupply()) / reserve0,

(amount1 * totalSupply()) / reserve1

);

}

require(shares > 0, "Insufficient liquidity minted");

_mint(msg.sender, shares);

// Update reserves

_update(

token0.balanceOf(address(this)),

token1.balanceOf(address(this))

);

}

// Remove liquidity

function removeLiquidity(uint256 shares)

external

returns (uint256 amount0, uint256 amount1)

{

// Calculate token amounts

uint256 balance0 = token0.balanceOf(address(this));

uint256 balance1 = token1.balanceOf(address(this));

amount0 = (shares * balance0) / totalSupply();

amount1 = (shares * balance1) / totalSupply();

require(amount0 > 0 && amount1 > 0, "Insufficient liquidity burned");

// Burn LP tokens

_burn(msg.sender, shares);

// Transfer tokens

token0.transfer(msg.sender, amount0);

token1.transfer(msg.sender, amount1);

// Update reserves

_update(

token0.balanceOf(address(this)),

token1.balanceOf(address(this))

);

}

// Swap tokens

function swap(address tokenIn, uint256 amountIn)

external

returns (uint256 amountOut)

{

require(

tokenIn == address(token0) || tokenIn == address(token1),

"Invalid token"

);

bool isToken0 = tokenIn == address(token0);

(IERC20 tokenInContract, IERC20 tokenOutContract, uint256 reserveIn, uint256 reserveOut) =

isToken0

? (token0, token1, reserve0, reserve1)

: (token1, token0, reserve1, reserve0);

// Transfer token in

tokenInContract.transferFrom(msg.sender, address(this), amountIn);

// Calculate amount out (with 0.3% fee)

uint256 amountInWithFee = (amountIn * 997) / 1000;

amountOut = (reserveOut * amountInWithFee) / (reserveIn + amountInWithFee);

// Transfer token out

tokenOutContract.transfer(msg.sender, amountOut);

// Update reserves

_update(

token0.balanceOf(address(this)),

token1.balanceOf(address(this))

);

}

// Internal functions

function _update(uint256 balance0, uint256 balance1) private {

reserve0 = balance0;

reserve1 = balance1;

}

function sqrt(uint256 y) private 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 x, uint256 y) private pure returns (uint256) {

return x < y ? x : y;

}

}

How It Works:

  • Liquidity Providers दोनों tokens deposit करते हैं
  • LP tokens receive करते हैं ownership represent करने के लिए
  • Traders tokens swap करते हैं 0.3% fee pay करके
  • Fees liquidity providers में distribute होते हैं
  • LP holders apne LP tokens burn करके liquidity withdraw कर सकते हैं
  • 2. Lending Protocol

    Basic lending protocol build करें:

    contract SimpleLending {
    

    IERC20 public token;

    mapping(address => uint256) public deposits;

    mapping(address => uint256) public borrows;

    uint256 public totalDeposits;

    uint256 public totalBorrows;

    uint256 public constant INTEREST_RATE = 5; // 5% per year

    uint256 public constant COLLATERAL_RATIO = 150; // 150%

    constructor(address _token) {

    token = IERC20(_token);

    }

    // Deposit tokens

    function deposit(uint256 amount) external {

    token.transferFrom(msg.sender, address(this), amount);

    deposits[msg.sender] += amount;

    totalDeposits += amount;

    }

    // Borrow tokens (over-collateralized)

    function borrow(uint256 amount) external {

    require(deposits[msg.sender] > 0, "No collateral");

    uint256 maxBorrow = (deposits[msg.sender] * 100) / COLLATERAL_RATIO;

    require(borrows[msg.sender] + amount <= maxBorrow, "Insufficient collateral");

    borrows[msg.sender] += amount;

    totalBorrows += amount;

    token.transfer(msg.sender, amount);

    }

    // Repay borrowed tokens

    function repay(uint256 amount) external {

    require(borrows[msg.sender] >= amount, "Repay exceeds borrow");

    token.transferFrom(msg.sender, address(this), amount);

    borrows[msg.sender] -= amount;

    totalBorrows -= amount;

    }

    // Withdraw deposited tokens

    function withdraw(uint256 amount) external {

    require(deposits[msg.sender] >= amount, "Insufficient deposit");

    // Check collateral ratio if user has borrows

    if (borrows[msg.sender] > 0) {

    uint256 remainingDeposit = deposits[msg.sender] - amount;

    uint256 maxBorrow = (remainingDeposit * 100) / COLLATERAL_RATIO;

    require(borrows[msg.sender] <= maxBorrow, "Would under-collateralize");

    }

    deposits[msg.sender] -= amount;

    totalDeposits -= amount;

    token.transfer(msg.sender, amount);

    }

    // Calculate interest earned

    function getInterestEarned(address user) public view returns (uint256) {

    // Simplified: real protocol would track time

    return (deposits[user] * INTEREST_RATE) / 100;

    }

    // Liquidation (simplified)

    function liquidate(address user) external {

    uint256 maxBorrow = (deposits[user] * 100) / COLLATERAL_RATIO;

    require(borrows[user] > maxBorrow, "Not liquidatable");

    // Liquidator pays debt, receives collateral + bonus

    uint256 debt = borrows[user];

    uint256 collateralSeized = (debt * 110) / 100; // 10% bonus

    token.transferFrom(msg.sender, address(this), debt);

    borrows[user] = 0;

    totalBorrows -= debt;

    deposits[user] -= collateralSeized;

    totalDeposits -= collateralSeized;

    token.transfer(msg.sender, collateralSeized);

    }

    }

    3. Staking Contract

    Rewards distribute करने वाला staking mechanism:

    contract StakingRewards {
    

    IERC20 public stakingToken;

    IERC20 public rewardsToken;

    uint256 public rewardRate = 100; // Rewards per second

    uint256 public lastUpdateTime;

    uint256 public rewardPerTokenStored;

    mapping(address => uint256) public userRewardPerTokenPaid;

    mapping(address => uint256) public rewards;

    mapping(address => uint256) public balances;

    uint256 private _totalSupply;

    constructor(address _stakingToken, address _rewardsToken) {

    stakingToken = IERC20(_stakingToken);

    rewardsToken = IERC20(_rewardsToken);

    }

    function rewardPerToken() public view returns (uint256) {

    if (_totalSupply == 0) {

    return rewardPerTokenStored;

    }

    return

    rewardPerTokenStored +

    (((block.timestamp - lastUpdateTime) * rewardRate * 1e18) / _totalSupply);

    }

    function earned(address account) public view returns (uint256) {

    return

    ((balances[account] * (rewardPerToken() - userRewardPerTokenPaid[account])) /

    1e18) + rewards[account];

    }

    modifier updateReward(address account) {

    rewardPerTokenStored = rewardPerToken();

    lastUpdateTime = block.timestamp;

    if (account != address(0)) {

    rewards[account] = earned(account);

    userRewardPerTokenPaid[account] = rewardPerTokenStored;

    }

    _;

    }

    function stake(uint256 amount) external updateReward(msg.sender) {

    _totalSupply += amount;

    balances[msg.sender] += amount;

    stakingToken.transferFrom(msg.sender, address(this), amount);

    }

    function withdraw(uint256 amount) external updateReward(msg.sender) {

    _totalSupply -= amount;

    balances[msg.sender] -= amount;

    stakingToken.transfer(msg.sender, amount);

    }

    function claimReward() external updateReward(msg.sender) {

    uint256 reward = rewards[msg.sender];

    if (reward > 0) {

    rewards[msg.sender] = 0;

    rewardsToken.transfer(msg.sender, reward);

    }

    }

    }

    Security Considerations

    1. Reentrancy Protection

    import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
    
    

    contract SecureAMM is ReentrancyGuard {

    function swap(...) external nonReentrant {

    // Safe from reentrancy

    }

    }

    2. Oracle Price Manipulation

    // ❌ VULNERABLE: Using spot price
    

    function getPrice() public view returns (uint256) {

    return (reserve1 * 1e18) / reserve0;

    }

    // ✅ SECURE: Using TWAP (Time-Weighted Average Price)

    uint256 public priceCumulativeLast;

    uint32 public blockTimestampLast;

    function update() external {

    uint32 blockTimestamp = uint32(block.timestamp % 2**32);

    uint32 timeElapsed = blockTimestamp - blockTimestampLast;

    if (timeElapsed > 0 && reserve0 != 0 && reserve1 != 0) {

    priceCumulativeLast += uint256((reserve1 * 1e18) / reserve0) * timeElapsed;

    blockTimestampLast = blockTimestamp;

    }

    }

    3. Flash Loan Attacks

    // Protect against manipulation within single transaction
    

    uint256 private unlocked = 1;

    modifier lock() {

    require(unlocked == 1, "Locked");

    unlocked = 0;

    _;

    unlocked = 1;

    }

    4. Integer Overflow/Underflow

    // Solidity 0.8+ automatically protects
    

    // लेकिन unchecked blocks में careful रहें

    Testing DeFi Protocols

    // SPDX-License-Identifier: MIT
    

    pragma solidity ^0.8.20;

    import "forge-std/Test.sol";

    import "../src/SimpleAMM.sol";

    import "../src/MockERC20.sol";

    contract AMMTest is Test {

    SimpleAMM amm;

    MockERC20 token0;

    MockERC20 token1;

    address alice = address(0x1);

    address bob = address(0x2);

    function setUp() public {

    token0 = new MockERC20("Token0", "TK0");

    token1 = new MockERC20("Token1", "TK1");

    amm = new SimpleAMM(address(token0), address(token1));

    // Mint tokens

    token0.mint(alice, 1000 ether);

    token1.mint(alice, 1000 ether);

    token0.mint(bob, 1000 ether);

    token1.mint(bob, 1000 ether);

    }

    function testAddLiquidity() public {

    vm.startPrank(alice);

    token0.approve(address(amm), 100 ether);

    token1.approve(address(amm), 100 ether);

    uint256 shares = amm.addLiquidity(100 ether, 100 ether);

    assertGt(shares, 0);

    assertEq(amm.balanceOf(alice), shares);

    vm.stopPrank();

    }

    function testSwap() public {

    // Add initial liquidity

    vm.startPrank(alice);

    token0.approve(address(amm), 100 ether);

    token1.approve(address(amm), 100 ether);

    amm.addLiquidity(100 ether, 100 ether);

    vm.stopPrank();

    // Bob swaps

    vm.startPrank(bob);

    token0.approve(address(amm), 10 ether);

    uint256 amountOut = amm.swap(address(token0), 10 ether);

    assertGt(amountOut, 0);

    assertEq(token1.balanceOf(bob), 1000 ether + amountOut);

    vm.stopPrank();

    }

    function testFuzz_swap(uint256 amountIn) public {

    vm.assume(amountIn > 0 && amountIn < 50 ether);

    // Setup liquidity

    vm.startPrank(alice);

    token0.approve(address(amm), 100 ether);

    token1.approve(address(amm), 100 ether);

    amm.addLiquidity(100 ether, 100 ether);

    vm.stopPrank();

    // Test swap

    vm.startPrank(bob);

    token0.approve(address(amm), amountIn);

    amm.swap(address(token0), amountIn);

    vm.stopPrank();

    }

    }

    Advanced DeFi Concepts

    1. Flash Loans

    एक transaction के within borrow और repay:

    interface IFlashLoan {
    

    function flashLoan(uint256 amount) external;

    }

    contract FlashLoanProvider {

    IERC20 public token;

    function flashLoan(uint256 amount, address receiver) external {

    uint256 balanceBefore = token.balanceOf(address(this));

    token.transfer(receiver, amount);

    // Receiver executes arbitrary logic

    IFlashLoanReceiver(receiver).executeOperation(amount);

    uint256 balanceAfter = token.balanceOf(address(this));

    require(balanceAfter >= balanceBefore, "Flash loan not repaid");

    }

    }

    2. Yield Farming

    Multiple protocols across yield maximize करना।

    3. Liquidity Mining

    LP tokens stake करके extra rewards earn करना।

    DeFi Development Best Practices

  • Audit करें deployment से पहले
  • Formal verification critical math logic के लिए
  • Gradual rollout (testnets → small mainnet deployment → full)
  • Emergency pause mechanism
  • Timelock for upgrades
  • Bug bounties (Immunefi, Code4rena)
  • Insurance (Nexus Mutual)
  • Monitoring (Tenderly, Defender)
  • निष्कर्ष

    DeFi development complex है लेकिन incredibly rewarding। आपने सीखा:

    • AMM basics और constant product formula
    • Lending protocol implementation
    • Staking rewards mechanism
    • Security considerations
    • Testing strategies

    Key takeaways:

    • Math correctness critical है
    • Reentrancy से protect करें
    • Oracle manipulation से सावधान
    • Thoroughly test करें
    • Professional audit करवाएं

    अगले कदम: Solingo पर DeFi challenges practice करें!

    ---

    अतिरिक्त Resources:

    Practice में लगाने के लिए तैयार हैं?

    Solingo पर interactive exercises के साथ इन concepts को apply करें।

    मुफ्त में शुरू करें