# 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:
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
निष्कर्ष
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: