פיתוח בורסה מבוזרת (DEX) במפתח מלא

אובדן כספים עקב פרצות בחוזים חכמים וניצול לא יעיל של נזילות הם סיכונים מרכזיים בהשקת בורסה מבוזרת. אנו מפתחים פתרונות DEX מלאים, ומתכננים ארכיטקטורה מאובטחת המותאמת למודל העסקי שלך. הצוות המומחה שלנו מוביל מהקונספט ועד הביקורת והתמיכה השוטפת, ומבטיח אמינות וסקאלביליות.

שירותי פיתוח בלוקצ'יין

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1481
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1335
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1034
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1293
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    738
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1031

אובדן מיליונים עקב התקפות Reentrancy, ניצול לא יעיל של הון בבריכות נזילות ומניפולציה באמצעות Flash Loans — אלו סיכונים אמיתיים שאנו מבטלים בשלב התכנון. הצוות שלנו בנה למעלה מ-50 פרויקטי DeFi, וכל אחד מהם עבר ביקורת אבטחה. המשתמשים לעולם לא מוותרים על השליטה בכספים: כל העסקאות מתבצעות על השרשרת (on-chain), והפיקדונות נשארים בארנק. Uniswap V3 מתמודד עם למעלה מ-1 מיליארד דולר ביום — DEX הופך לסטנדרט למסחר בטוקנים. אנו בונים בורסות עם AMM, ספרי הזמנות או ארכיטקטורה היברידית המותאמת לפרויקט שלך.

בעיות שאנו פותרים

  • ניצול לא יעיל של נזילות: מוצר קבוע (constant product) משאיר 90% מהכספים ללא שימוש. אנו מיישמים נזילות מרוכזת, שמגבירה את היעילות פי 10–100. זה יכול לייצר עד פי 10 יותר הכנסות מעמלות עבור ספקי נזילות (LPs) באותו נפח מסחר.
  • מניפולציית מחירים באמצעות Flash Loans: אורקל TWAP מגן מפני מניפולציה בתוך בלוק בודד. המחיר הממוצע לאורך N שניות הופך התקפות ללא כדאיות כלכלית. ביקורות אבטחה של Trail of Bits מתחילות ב-50,000 דולר אך מונעות הפסדים של מיליונים.
  • Frontrunning ו-MEV: סובלנות לסטייה (slippage) וזמן תפוגה (deadline) הם הגנה סטנדרטית. לעסקאות גדולות, אנו משתמשים ב-mempools פרטיים (Flashbots).
  • ביקורת אבטחה: כל חוזה נבדק עבור reentrancy, גלישת מספרים (overflow) ובקרת גישה. מבקרים מומלצים: Trail of Bits, OpenZeppelin Security.

איך אנחנו עושים את זה: טכנולוגיות ומקרה בוחן

אנו משתמשים ב-Solidity 0.8.x עם OpenZeppelin, Foundry לבדיקות, ו-ethers.js/viem לצד הלקוח. להלן מימוש של בריכת Constant Product עם עמלה של 0.3%, הגנת reentrancy ואינווריאנט K.

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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract ConstantProductPool is ERC20, ReentrancyGuard {
    address public immutable token0;
    address public immutable token1;
    uint256 private reserve0;
    uint256 private reserve1;
    uint256 private constant FEE_NUMERATOR = 997; // 0.3% fee
    uint256 private constant FEE_DENOMINATOR = 1000;

    event Swap(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 amount0Out, uint256 amount1Out, address indexed to);
    event Mint(address indexed sender, uint256 amount0, uint256 amount1);
    event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);

    constructor(address _token0, address _token1) ERC20("LP Token", "LP") {
        token0 = _token0;
        token1 = _token1;
    }

    // Добавление ликвидности
    function mint(address to) external returns (uint256 liquidity) {
        uint256 balance0 = IERC20(token0).balanceOf(address(this));
        uint256 balance1 = IERC20(token1).balanceOf(address(this));
        uint256 amount0 = balance0 - reserve0;
        uint256 amount1 = balance1 - reserve1;
        uint256 totalSupply_ = totalSupply();
        if (totalSupply_ == 0) {
            liquidity = Math.sqrt(amount0 * amount1) - 1000;
            _mint(address(0xdead), 1000);
        } else {
            liquidity = Math.min(
                amount0 * totalSupply_ / reserve0,
                amount1 * totalSupply_ / reserve1
            );
        }
        require(liquidity > 0, "INSUFFICIENT_LIQUIDITY_MINTED");
        _mint(to, liquidity);
        reserve0 = balance0;
        reserve1 = balance1;
        emit Mint(msg.sender, amount0, amount1);
    }

    // Вывод ликвидности
    function burn(address to) external returns (uint256 amount0, uint256 amount1) {
        uint256 liquidity = balanceOf(address(this));
        uint256 totalSupply_ = totalSupply();
        amount0 = liquidity * reserve0 / totalSupply_;
        amount1 = liquidity * reserve1 / totalSupply_;
        require(amount0 > 0 && amount1 > 0, "INSUFFICIENT_LIQUIDITY_BURNED");
        _burn(address(this), liquidity);
        IERC20(token0).transfer(to, amount0);
        IERC20(token1).transfer(to, amount1);
        reserve0 = IERC20(token0).balanceOf(address(this));
        reserve1 = IERC20(token1).balanceOf(address(this));
        emit Burn(msg.sender, amount0, amount1, to);
    }

    // Swap
    function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external nonReentrant returns (uint256 amount0In, uint256 amount1In) {
        require(amount0Out > 0 || amount1Out > 0, "INSUFFICIENT_OUTPUT_AMOUNT");
        require(amount0Out < reserve0 && amount1Out < reserve1, "INSUFFICIENT_LIQUIDITY");
        if (amount0Out > 0) IERC20(token0).transfer(to, amount0Out);
        if (amount1Out > 0) IERC20(token1).transfer(to, amount1Out);
        uint256 balance0 = IERC20(token0).balanceOf(address(this));
        uint256 balance1 = IERC20(token1).balanceOf(address(this));
        amount0In = balance0 > reserve0 - amount0Out ? balance0 - (reserve0 - amount0Out) : 0;
        amount1In = balance1 > reserve1 - amount1Out ? balance1 - (reserve1 - amount1Out) : 0;
        require(amount0In > 0 || amount1In > 0, "INSUFFICIENT_INPUT_AMOUNT");
        // Проверка инварианта с учётом fee
        uint256 balance0Adjusted = balance0 * FEE_DENOMINATOR - amount0In * (FEE_DENOMINATOR - FEE_NUMERATOR);
        uint256 balance1Adjusted = balance1 * FEE_DENOMINATOR - amount1In * (FEE_DENOMINATOR - FEE_NUMERATOR);
        require(
            balance0Adjusted * balance1Adjusted >= reserve0 * reserve1 * FEE_DENOMINATOR ** 2,
            "K_INVARIANT_VIOLATED"
        );
        reserve0 = uint256(balance0);
        reserve1 = uint256(balance1);
        emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
    }

    function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) public pure returns (uint256) {
        require(amountIn > 0, "INSUFFICIENT_INPUT_AMOUNT");
        require(reserveIn > 0 && reserveOut > 0, "INSUFFICIENT_LIQUIDITY");
        uint256 amountInWithFee = amountIn * FEE_NUMERATOR;
        uint256 numerator = amountInWithFee * reserveOut;
        uint256 denominator = reserveIn * FEE_DENOMINATOR + amountInWithFee;
        return numerator / denominator;
    }
}

Factory ו-Router

ה-Factory יוצר בריכות באמצעות CREATE2, וה-Router הוא נקודת הכניסה למשתמש עם תמיכה ב-multi-hop וב-ETH/WETH.

contract DEXFactory {
    mapping(address => mapping(address => address)) public getPool;
    address[] public allPools;
    event PoolCreated(address indexed token0, address indexed token1, address pool);

    function createPool(address tokenA, address tokenB) external returns (address pool) {
        require(tokenA != tokenB, "IDENTICAL_ADDRESSES");
        (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        require(token0 != address(0), "ZERO_ADDRESS");
        require(getPool[token0][token1] == address(0), "POOL_EXISTS");
        bytes memory bytecode = type(ConstantProductPool).creationCode;
        bytes32 salt = keccak256(abi.encodePacked(token0, token1));
        assembly {
            pool := create2(0, add(bytecode, 32), mload(bytecode), salt)
        }
        ConstantProductPool(pool).initialize(token0, token1);
        getPool[token0][token1] = pool;
        getPool[token1][token0] = pool;
        allPools.push(pool);
        emit PoolCreated(token0, token1, pool);
    }
}

contract DEXRouter {
    address public immutable factory;
    address public immutable WETH;

    function swapExactTokensForTokens(
        uint256 amountIn,
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external returns (uint256[] memory amounts) {
        require(deadline >= block.timestamp, "EXPIRED");
        amounts = getAmountsOut(amountIn, path);
        require(amounts[amounts.length - 1] >= amountOutMin, "INSUFFICIENT_OUTPUT_AMOUNT");
        IERC20(path[0]).transferFrom(msg.sender, getPool(path[0], path[1]), amounts[0]);
        _swap(amounts, path, to);
    }

    function swapExactETHForTokens(
        uint256 amountOutMin,
        address[] calldata path,
        address to,
        uint256 deadline
    ) external payable returns (uint256[] memory amounts) {
        require(path[0] == WETH, "INVALID_PATH");
        amounts = getAmountsOut(msg.value, path);
        require(amounts[amounts.length - 1] >= amountOutMin, "INSUFFICIENT_OUTPUT_AMOUNT");
        IWETH(WETH).deposit{value: amounts[0]}();
        IERC20(WETH).transfer(getPool(path[0], path[1]), amounts[0]);
        _swap(amounts, path, to);
    }
}

למה אבטחה קריטית עבור DEX

DEX מנהלת כספי משתמשים אמיתיים. כל פרצה — reentrancy, התקפת flash loan או מניפולציית מחירים — עלולה להוביל להפסדים של מיליונים. אנו מיישמים:

  • ReentrancyGuard מ-OpenZeppelin על כל הפונקציות החיצוניות.
  • אורקל TWAP להגנה מפני מניפולציית מחיר ספוט.
  • בדיקת אינווריאנט K כולל עמלה בכל עסקה.
  • סובלנות לסטייה (slippage) וזמן תפוגה (deadline) — המשתמשים שולטים בסטייה המקסימלית ובזמן חיי העסקה.

דוגמה למימוש TWAP:

uint256 price0CumulativeLast;
uint256 price1CumulativeLast;
uint32 blockTimestampLast;

function _updatePriceAccumulators() private {
    uint32 blockTimestamp = uint32(block.timestamp);
    uint32 timeElapsed = blockTimestamp - blockTimestampLast;
    if (timeElapsed > 0 && reserve0 != 0 && reserve1 != 0) {
        price0CumulativeLast += uint256(UQ112x112.encode(reserve1).uqdiv(reserve0)) * timeElapsed;
        price1CumulativeLast += uint256(UQ112x112.encode(reserve0).uqdiv(reserve1)) * timeElapsed;
    }
    blockTimestampLast = blockTimestamp;
}

איך תהליך הפיתוח עובד

  1. אנליטיקה: קביעת מודל ה-DEX, הטוקנים ופרמטרי הבריכה.
  2. עיצוב: ארכיטקטורה של חוזים חכמים, Router ואורקלים.
  3. מימוש: כתיבת חוזים ב-Solidity עם Foundry, צד לקוח עם React/wagmi.
  4. בדיקות: בדיקות יחידה, בדיקות אינטגרציה, fuzzing (Echidna).
  5. ביקורת: ביקורת אבטחה חיצונית (Trail of Bits, OpenZeppelin).
  6. פריסה: פריסה על mainnet/L2, אימות חוזים ב-Etherscan.
  7. תמיכה: ניטור, עדכונים ושיפורים.
דוגמה לחישוב הכנסות ספק נזילותעם נפח מסחר יומי של מיליון דולר ועמלה של 0.3%, ההכנסה היומית של הבריכה היא 3,000 דולר. עבור ספק נזילות עם נתח של 1%, מדובר ב-30 דולר ליום. נזילות מרוכזת יכולה להגדיל הכנסה זו עד פי 10 באותו נפח מסחר.

לוחות זמנים משוערים

רכיב זמן
חוזי ליבת AMM 4–6 שבועות
Factory + Router 3–4 שבועות
אורקל TWAP 1–2 שבועות
Subgraph (אנליטיקה) 2–3 שבועות
צד לקוח (swap + נזילות) 4–6 שבועות
ביקורת חוזים חכמים 4–8 שבועות

MVP של DEX על mainnet: 4–6 חודשים כולל ביקורת. העלות נקבעת באופן אישי — צרו קשר להערכה.

מה כלול

  • חוזים חכמים עבור AMM, Router, Factory (עם קוד מקור).
  • אורקל TWAP ואינטגרציה עם Chainlink אם נדרש.
  • צד לקוח עם תמיכה בארנקים (MetaMask, WalletConnect).
  • Subgraph (The Graph) לאנליטיקה.
  • תיעוד (ארכיטקטורה, מדריך פריסה).
  • ביקורת אבטחה (מבקרים מוסמכים).
  • תמיכה טכנית למשך 3 חודשים לאחר ההשקה.

הזמינו פיתוח DEX מאיתנו — קבלו מוצר מוכן עם ביקורת ותמיכה. אנו מבטיחים אבטחה וסקלביליות. צרו קשר לייעוץ פרויקט להערכת לוחות זמנים והיקף.