Tutoriel·12 min de lecture·Par Solingo

DeFi Development Guide — Build Your First Protocol

Understand AMMs, lending pools, and yield farming. Build a simple DeFi protocol from scratch.

# DeFi Development Guide — Build Your First Protocol

Decentralized Finance (DeFi) has revolutionized the financial industry by removing intermediaries and enabling anyone to access financial services through smart contracts. In this comprehensive guide, we'll explore the core DeFi primitives and build a simple Automated Market Maker (AMM) protocol from scratch.

What is DeFi?

DeFi refers to financial applications built on blockchain technology that operate without traditional intermediaries like banks or brokerages. These applications use smart contracts to automate financial services such as:

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

The total value locked (TVL) in DeFi protocols exceeded $150 billion in 2026, demonstrating the massive adoption of these technologies.

Core DeFi Primitives

1. Decentralized Exchanges (DEX) and Automated Market Makers (AMM)

Traditional exchanges use order books to match buyers and sellers. AMMs replace this with liquidity pools and mathematical formulas. The most famous formula is the constant product formula:

x * y = k

Where:

  • x = reserve of token A
  • y = reserve of token B
  • k = constant product

This formula ensures that as one reserve increases, the other decreases proportionally, creating a price curve.

2. Lending Protocols

Platforms like Aave and Compound allow users to:

  • Deposit assets and earn interest
  • Borrow assets by providing collateral
  • Liquidate under-collateralized positions

Interest rates are typically determined algorithmically based on supply and demand (utilization rate).

3. Staking and Yield Farming

Users can lock their tokens to:

  • Secure a network (Proof of Stake)
  • Provide liquidity to AMMs
  • Earn rewards in native tokens or trading fees

Yield farming involves moving assets between protocols to maximize returns.

Building a Simple AMM

Let's implement a basic constant product AMM supporting two tokens. This simplified version demonstrates the core mechanics of protocols like Uniswap V2.

Step 1: Contract Setup

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.26;

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

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

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

contract SimpleAMM is ERC20, ReentrancyGuard {

IERC20 public immutable token0;

IERC20 public immutable token1;

uint256 public reserve0;

uint256 public reserve1;

event LiquidityAdded(address indexed provider, uint256 amount0, uint256 amount1, uint256 liquidity);

event LiquidityRemoved(address indexed provider, uint256 amount0, uint256 amount1, uint256 liquidity);

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

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

token0 = IERC20(_token0);

token1 = IERC20(_token1);

}

function _update(uint256 _reserve0, uint256 _reserve1) private {

reserve0 = _reserve0;

reserve1 = _reserve1;

}

}

Step 2: Add Liquidity

function addLiquidity(uint256 amount0, uint256 amount1)

external

nonReentrant

returns (uint256 liquidity)

{

require(amount0 > 0 && amount1 > 0, "Invalid amounts");

// Transfer tokens from user

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

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

uint256 _totalSupply = totalSupply();

if (_totalSupply == 0) {

// First liquidity provider

liquidity = sqrt(amount0 * amount1);

} else {

// Subsequent providers - maintain ratio

liquidity = min(

(amount0 * _totalSupply) / reserve0,

(amount1 * _totalSupply) / reserve1

);

}

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

// Mint LP tokens

_mint(msg.sender, liquidity);

// Update reserves

_update(reserve0 + amount0, reserve1 + amount1);

emit LiquidityAdded(msg.sender, amount0, amount1, liquidity);

}

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;

}

Step 3: Swap Function

function swap(address tokenIn, uint256 amountIn)

external

nonReentrant

returns (uint256 amountOut)

{

require(tokenIn == address(token0) || tokenIn == address(token1), "Invalid token");

require(amountIn > 0, "Invalid amount");

bool isToken0 = tokenIn == address(token0);

(IERC20 _tokenIn, IERC20 _tokenOut, uint256 reserveIn, uint256 reserveOut) = isToken0

? (token0, token1, reserve0, reserve1)

: (token1, token0, reserve1, reserve0);

// Transfer token in

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

// Calculate amount out using constant product formula

// amountOut = (amountIn * reserveOut) / (reserveIn + amountIn)

// With 0.3% fee: amountIn * 0.997

uint256 amountInWithFee = amountIn * 997;

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

require(amountOut > 0, "Insufficient output amount");

// Transfer token out

_tokenOut.transfer(msg.sender, amountOut);

// Update reserves

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

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

_update(balance0, balance1);

emit Swap(msg.sender, tokenIn, amountIn, amountOut);

}

Step 4: Remove Liquidity

function removeLiquidity(uint256 liquidity)

external

nonReentrant

returns (uint256 amount0, uint256 amount1)

{

require(liquidity > 0, "Invalid liquidity");

uint256 _totalSupply = totalSupply();

// Calculate token amounts proportional to LP tokens burned

amount0 = (liquidity * reserve0) / _totalSupply;

amount1 = (liquidity * reserve1) / _totalSupply;

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

// Burn LP tokens

_burn(msg.sender, liquidity);

// Transfer tokens to user

token0.transfer(msg.sender, amount0);

token1.transfer(msg.sender, amount1);

// Update reserves

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

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

_update(balance0, balance1);

emit LiquidityRemoved(msg.sender, amount0, amount1, liquidity);

}

Flash Loans Explained

Flash loans are uncollateralized loans that must be borrowed and repaid within the same transaction. They're a unique DeFi primitive enabled by blockchain atomicity.

How They Work

contract FlashLoanProvider {

function flashLoan(uint256 amount, address borrower) external {

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

// 1. Send tokens to borrower

token.transfer(borrower, amount);

// 2. Call borrower's callback

IFlashLoanReceiver(borrower).executeOperation(amount);

// 3. Ensure tokens + fee were returned

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

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

}

}

Use cases include:

  • Arbitrage across DEXes
  • Collateral swaps in lending protocols
  • Liquidations without upfront capital

Composability — The DeFi Superpower

DeFi protocols are like Lego blocks that can be combined. Example:

  • Flash loan 1000 ETH from Aave
  • Swap on Uniswap (ETH → DAI)
  • Deposit DAI in Compound
  • Borrow ETH using DAI collateral
  • Repay flash loan + fee
  • Keep the profit
  • This composability creates powerful strategies but also systemic risks.

    Risks in DeFi

    1. Impermanent Loss

    When you provide liquidity to an AMM, price divergence between tokens causes losses compared to just holding.

    Example: You deposit 1 ETH ($2000) + 2000 USDC when ETH = $2000.

    If ETH rises to $4000:

    • Holding: 1 ETH + 2000 USDC = $6000
    • LP position: ~0.707 ETH + ~2828 USDC = $5656
    • Impermanent loss: $344 (5.7%)

    Formula:

    IL = 2 * sqrt(price_ratio) / (1 + price_ratio) - 1

    2. Smart Contract Risk

    Bugs can lead to:

    • Funds drainage (reentrancy, logic errors)
    • Locked funds (upgradability issues)
    • Oracle manipulation (flash loan attacks on price feeds)

    Always audit code before deploying real value.

    3. Systemic Risk

    DeFi protocols depend on each other. A failure in one can cascade:

    • Aave depends on Chainlink oracles
    • Curve pools use various tokens
    • Leverage protocols amplify losses

    Testing DeFi Protocols

    Use Hardhat or Foundry for comprehensive testing:

    describe("SimpleAMM", function() {
    

    it("should handle swap correctly", async function() {

    const [owner, user] = await ethers.getSigners();

    // Add liquidity

    await amm.connect(owner).addLiquidity(ethers.parseEther("100"), ethers.parseEther("100"));

    // User swaps 10 token0 for token1

    const amountIn = ethers.parseEther("10");

    await token0.connect(user).approve(amm.target, amountIn);

    const amountOut = await amm.connect(user).swap.staticCall(token0.target, amountIn);

    await amm.connect(user).swap(token0.target, amountIn);

    // Verify constant product (with fee)

    const newReserve0 = await amm.reserve0();

    const newReserve1 = await amm.reserve1();

    // k should increase (due to fees)

    expect(newReserve0 * newReserve1).to.be.gt(ethers.parseEther("100") * ethers.parseEther("100"));

    });

    });

    Test edge cases:

    • Zero amounts
    • Very large swaps (price impact)
    • Reentrancy attacks
    • Integer overflow/underflow

    Resources to Go Further

  • Uniswap V2 Documentation: https://docs.uniswap.org/contracts/v2/overview
  • Aave Developer Docs: https://docs.aave.com/developers/
  • DeFi Developer Roadmap: https://github.com/OffcierCia/DeFi-Developer-Road-Map
  • Smart Contract Weakness Classification: https://swcregistry.io/
  • Solingo DeFi Course: Learn to build production-ready protocols
  • Conclusion

    DeFi development requires understanding both financial concepts and smart contract engineering. Start with simple AMMs, then explore lending, derivatives, and advanced yield strategies.

    Key takeaways:

    • AMMs use mathematical formulas (x*y=k) instead of order books
    • Flash loans enable capital-free arbitrage and liquidations
    • Composability is powerful but introduces systemic risks
    • Always test extensively and audit before deploying real value
    • Impermanent loss affects liquidity providers in volatile markets

    Ready to build? Solingo's DeFi Development track takes you from basics to building production protocols like Uniswap, Aave, and Compound. Start learning today.

    Prêt à mettre en pratique ?

    Applique ces concepts avec des exercices interactifs sur Solingo.

    Commencer gratuitement