Розробка платформи в стилі pump.fun

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка платформи в стилі pump.fun
Складний
від 2 тижнів до 3 місяців
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1288
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    902
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1123
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    860

Розробка платформи у стилі pump.fun

pump.fun вирішив конкретну інфраструктурну проблему: запуск токена на Solana займав години та вимагав технічних знань. Платформа зробила це доступним за 30 секунд. Механіка простий — bonding curve до досягнення певної ринкової капіталізації, потім автоматична міграція ліквідності в Raydium. Щодня через платформу проходять десятки мільйонів доларів. Технічно це цікава система з кількома нетривіальними компонентами.

Bonding Curve: ядро механіки

Bonding curve — математична функція, що визначає ціну токена залежно від поточного supply. Немає orderbook, немає LP, немає зовнішної ціни — контракт сам визначає обмінний курс.

Лінійна крива:

Price = initial_price + slope * supply

Проста, передбачувана, але зростання ціни пропорційне обсягу покупок — whale може швидко розтовпити ціну.

Експоненціальна крива:

Price = initial_price * e^(k * supply)

Гостріший ріст при високому supply. Ранні покупці отримають значно більшу перевагу.

pump.fun використовує polynomial bonding curve — реалізація з virtual reserves, що імітує поведінку Uniswap AMM без реальної ліквідності:

virtual_sol_reserves = 30 SOL
virtual_token_reserves = 1_073_000_000 токенів
real_sol_reserves = 0 (накопичується від продажів)
real_token_reserves = 793_100_000 токенів (продаються через криву)

Ціна визначається через формулу constant product: k = virtual_sol * virtual_token_supply. При покупці dx SOL:

new_virtual_sol = virtual_sol + dx
new_virtual_token = k / new_virtual_sol
tokens_received = virtual_token - new_virtual_token

Це точна копія механіки Uniswap V2, але з virtual reserves замість реальних LP токенів.

Реалізація на EVM

contract BondingCurve {
    uint256 public constant VIRTUAL_SOL_RESERVES = 30 ether;  // в ETH/SOL
    uint256 public constant VIRTUAL_TOKEN_RESERVES = 1_073_000_000e18;
    uint256 public constant TOTAL_SUPPLY = 1_000_000_000e18;
    uint256 public constant MIGRATION_THRESHOLD = 69_000 * 1e18; // $69k в ETH

    uint256 public realEthReserves;      // накопичений ETH
    uint256 public tokensSold;           // продано через криву

    // Скільки токенів отримаєш за X ETH
    function getTokensOut(uint256 ethIn) public view returns (uint256) {
        uint256 virtualEth = VIRTUAL_SOL_RESERVES + realEthReserves;
        uint256 virtualTokens = VIRTUAL_TOKEN_RESERVES - tokensSold;
        uint256 k = virtualEth * virtualTokens;

        uint256 newVirtualEth = virtualEth + ethIn;
        uint256 newVirtualTokens = k / newVirtualEth;

        return virtualTokens - newVirtualTokens;
    }

    // Скільки ETH отримаєш за X токенів
    function getEthOut(uint256 tokensIn) public view returns (uint256) {
        uint256 virtualEth = VIRTUAL_SOL_RESERVES + realEthReserves;
        uint256 virtualTokens = VIRTUAL_TOKEN_RESERVES - tokensSold;
        uint256 k = virtualEth * virtualTokens;

        uint256 newVirtualTokens = virtualTokens + tokensIn;
        uint256 newVirtualEth = k / newVirtualTokens;

        return virtualEth - newVirtualEth;
    }

    function buy(uint256 minTokensOut) external payable nonReentrant {
        require(msg.value > 0, "No ETH sent");
        require(!migrated, "Token migrated to DEX");

        uint256 fee = (msg.value * FEE_BPS) / 10000;  // 1%
        uint256 ethIn = msg.value - fee;

        uint256 tokensOut = getTokensOut(ethIn);
        require(tokensOut >= minTokensOut, "Slippage exceeded");

        realEthReserves += ethIn;
        tokensSold += tokensOut;

        IERC20(token).safeTransfer(msg.sender, tokensOut);
        payable(feeRecipient).transfer(fee);

        emit Trade(msg.sender, ethIn, tokensOut, true);

        // Перевіряємо поріг міграції
        if (realEthReserves >= MIGRATION_THRESHOLD) {
            _migrateToDEX();
        }
    }

    function sell(uint256 tokensIn, uint256 minEthOut) external nonReentrant {
        require(!migrated, "Token migrated to DEX");
        require(tokensIn > 0, "Zero tokens");

        uint256 ethOut = getEthOut(tokensIn);
        uint256 fee = (ethOut * FEE_BPS) / 10000;
        uint256 ethToUser = ethOut - fee;

        require(ethToUser >= minEthOut, "Slippage exceeded");

        IERC20(token).safeTransferFrom(msg.sender, address(this), tokensIn);
        tokensSold -= tokensIn;
        realEthReserves -= ethOut;

        payable(msg.sender).transfer(ethToUser);
        payable(feeRecipient).transfer(fee);

        emit Trade(msg.sender, tokensIn, ethToUser, false);
    }
}

Автоматична міграція на DEX

При досягненні поріга (pump.fun — $69k ринкова капіталізація) контракт автоматично:

  1. Зупиняє торгівлю через bonding curve
  2. Створює пул на Uniswap V2 (або V3)
  3. Додає накопичений ETH + решта токенів як ліквідність
  4. Спалює або локує LP токени назавжди
function _migrateToDEX() internal {
    migrated = true;

    uint256 ethForLiquidity = realEthReserves;
    uint256 tokensForLiquidity = TOTAL_SUPPLY - tokensSold; // непроданий supply

    // Створюємо пару та додаємо ліквідність
    address pair = IUniswapV2Factory(UNISWAP_FACTORY).createPair(
        token,
        WETH
    );

    // Апрув та додавання ліквідності
    IERC20(token).approve(UNISWAP_ROUTER, tokensForLiquidity);

    (, , uint256 lpTokens) = IUniswapV2Router(UNISWAP_ROUTER).addLiquidityETH{
        value: ethForLiquidity
    }(
        token,
        tokensForLiquidity,
        tokensForLiquidity,  // minTokens = 100% (немає слиппажу при створенні пулу)
        ethForLiquidity,     // minETH = 100%
        address(this),
        block.timestamp + 300
    );

    // Спалюємо LP токени — ліквідність постійна
    IERC20(pair).transfer(address(0xdead), lpTokens);

    emit Migrated(pair, ethForLiquidity, tokensForLiquidity);
}

Заблокована vs спалена LP: pump.fun спалює LP токени (відправляє на dead address). Альтернатива — локування через Unicrypt/Team.Finance. Спалювання більш радикальне, але необоротне — якщо є баг у контракті, не можна його виправити.

Token Factory: запуск за один виклик

Кожний користувач запускає новий токен. Потрібна фабрика, що розгортає токен + bonding curve контракт за одну транзакцію:

contract TokenFactory {
    event TokenCreated(
        address indexed token,
        address indexed curve,
        address indexed creator,
        string name,
        string symbol,
        string uri,
        uint256 timestamp
    );

    address[] public allTokens;
    mapping(address => TokenInfo) public tokenInfo;

    function createToken(
        string calldata name,
        string calldata symbol,
        string calldata uri,
        uint256 initialBuyEth
    ) external payable returns (address token, address curve) {
        // Розгортаємо мінімальний ERC-20
        token = address(new MinimalERC20(name, symbol, TOTAL_SUPPLY));
        curve = address(new BondingCurve(token, msg.sender));

        // Переводимо всі токени у криву
        MinimalERC20(token).transfer(curve, TOTAL_SUPPLY);

        // Перша покупка якщо був ETH
        if (initialBuyEth > 0) {
            uint256 creationFee = CREATION_FEE;
            require(msg.value >= creationFee + initialBuyEth, "Insufficient ETH");
            BondingCurve(payable(curve)).buy{value: initialBuyEth}(0);
        }

        allTokens.push(token);
        tokenInfo[token] = TokenInfo({
            curve: curve,
            creator: msg.sender,
            name: name,
            symbol: symbol,
            uri: uri,
            createdAt: block.timestamp
        });

        emit TokenCreated(token, curve, msg.sender, name, symbol, uri, block.timestamp);
    }
}

CREATE2 для передбачуваних адрес — корисно для frontend: можна розрахувати адресу токена до розгортання та показати користувачу заздалегідь.

Anti-rug механізми

Основні ризики:創atор dump'ає (купив 80% supply через криву при низькій ціні, продає після hype). pump.fun частково вирішує це архітектурно — після міграції LP заблокована та creator не може вивести ліквідність.

Максимальна алокація на адресу — під час використання кривої одна адреса не може купити більше X% supply одразу:

uint256 public constant MAX_BUY_PERCENT = 10; // максимум 10% за транзакцію

function buy(uint256 minTokensOut) external payable {
    uint256 tokensOut = getTokensOut(msg.value);
    uint256 maxTokens = (TOTAL_SUPPLY * MAX_BUY_PERCENT) / 100;
    require(tokensOut <= maxTokens, "Buy too large");
    // ...
}

Затримка між покупками — захист від швидкого накопичення ботами.

Індексування та виявлення

З тисячами нових токенів щодня потрібен real-time індекс:

The Graph subgraph для індексування событій TokenCreated, Trade, Migrated. GraphQL API для frontend.

Алгоритм тренду (спрощено):

score = (volume_1h * 3) + (volume_24h * 1) + (buyers_1h * 50) - (sellers_1h * 30)

Вищий вага на недавній обсяг та кількість унікальних покупців (не обсяг від одного whale).

WebSocket для live trades — frontend підписується на события конкретного токена та показує trades у реальному часі.

Економіка платформи

pump.fun заробляє від:

  • 1% комісії від кожної trade через bonding curve
  • 0.5% обсягу після міграції в Raydium
  • Платної верифікації творців (опціонально)

При обсягу $1M/день це $10,000/день тільки від trading fee. Для EVM реалізації на Base/Arbitrum — модель аналогічна, але gas cost вище ніж на Solana, важливо для малих trades.

Технічний стек

Контракти: Solidity + Foundry (тестування з fuzz для інваріантів: totalEth = sum(all buys) - sum(all sells))

Індексування: The Graph або кастомний indexer (Node.js + ethers.js + PostgreSQL)

Frontend: React + wagmi + viem, real-time через WebSocket до кастомного indexer

Чарти: TradingView Lightweight Charts над indexed trade data

Зберігання метаданих: IPFS (зображення, опис токена)

Етапи розробки

Фаза Вміст Час
Bonding curve математика Параметри кривої, тести інваріантів 1–2 тижні
Core контракти Factory, BondingCurve, міграція 3–4 тижні
Security аудит Фокус на маніпуляцію кривої, reentrancy 2–3 тижні
Indexer Subgraph або кастомний indexer 2–3 тижні
Frontend Trading interface, discovery, charts 4–6 тижнів
Testnet Повний цикл create → trade → migrate 2–3 тижні
Mainnet Розгортання на target chain 1 тиждень

Критичні тести: fuzz invariants (totalETHin - totalETHout = realEthReserves), математика міграції (ціна DEX пулу одразу після міграції повинна совпадати з ціною bonding curve у момент міграції), extreme slippage сценарії.