Лендинг токенсейлу: смарт-контракт, Merkle whitelist, real-time

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1305 послуг
Лендинг токенсейлу: смарт-контракт, Merkle whitelist, real-time
Середній
~3-5 днів
Часті запитання

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

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

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

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

Розробка лендингу токенсейлу

Ми створюємо лендинги токенсейлів як повноцінні web3-додатки, а не просто маркетингові сторінки. Це додаток, який взаємодіє зі смарт-контрактом продажу токенів, обробляє платежі в криптовалюті, керує whitelist і повинен працювати надійно в момент високого навантаження — коли тисячі користувачів заходять одночасно при відкритті раунду. Наш досвід включає проекти з навантаженням до 50 000 одночасних відвідувачів та економією до $2000 на газі завдяки Merkle Tree-whitelist. Отримайте консультацію щодо вашого проекту.

Розробка смарт-контракту токенсейлу

Лендинг — це frontend до контракту. Спочатку проектуємо контракт з використанням перевірених патернів від OpenZeppelin: Ownable2Step, ReentrancyGuard, Pausable. Нижче — приклад контракту, який використовується в реальних проектах.

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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable2Step.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

contract TokenSale is Ownable2Step, NonReentrancyGuard, Pausable {
    using SafeERC20 for IERC20;
    
    IERC20 public immutable saleToken;
    IERC20 public immutable paymentToken;  // USDC
    
    uint256 public immutable tokenPrice;    // USDC per token, 6 decimals
    uint256 public immutable hardCap;       // total tokens for sale
    uint256 public immutable minPurchase;   // per wallet min
    uint256 public immutable maxPurchase;   // per wallet max
    
    uint256 public saleStart;
    uint256 public saleEnd;
    
    bytes32 public whitelistMerkleRoot;
    bool public whitelistRequired;
    
    uint256 public totalSold;
    mapping(address => uint256) public purchased;
    
    event TokensPurchased(address indexed buyer, uint256 usdcAmount, uint256 tokenAmount);
    event SaleConfigured(uint256 start, uint256 end, bool whitelistRequired);
    
    constructor(
        address _saleToken,
        address _paymentToken,
        uint256 _tokenPrice,
        uint256 _hardCap,
        uint256 _minPurchase,
        uint256 _maxPurchase,
        address _owner
    ) Ownable2Step() {
        saleToken = IERC20(_saleToken);
        paymentToken = IERC20(_paymentToken);
        tokenPrice = _tokenPrice;
        hardCap = _hardCap;
        minPurchase = _minPurchase;
        maxPurchase = _maxPurchase;
        _transferOwnership(_owner);
    }
    
    function configureSale(
        uint256 _start,
        uint256 _end,
        bytes32 _merkleRoot,
        bool _whitelistRequired
    ) external onlyOwner {
        saleStart = _start;
        saleEnd = _end;
        whitelistMerkleRoot = _merkleRoot;
        whitelistRequired = _whitelistRequired;
        emit SaleConfigured(_start, _end, _whitelistRequired);
    }
    
    function buy(
        uint256 usdcAmount,
        bytes32[] calldata merkleProof
    ) external nonReentrant whenNotPaused {
        require(block.timestamp >= saleStart, "Sale not started");
        require(block.timestamp <= saleEnd, "Sale ended");
        
        if (whitelistRequired) {
            bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
            require(
                MerkleProof.verify(merkleProof, whitelistMerkleRoot, leaf),
                "Not whitelisted"
            );
        }
        
        uint256 tokenAmount = usdcAmount * 10**18 / tokenPrice;
        
        require(usdcAmount >= minPurchase, "Below min purchase");
        require(purchased[msg.sender] + tokenAmount <= maxPurchase, "Exceeds max per wallet");
        require(totalSold + tokenAmount <= hardCap, "Hard cap reached");
        
        purchased[msg.sender] += tokenAmount;
        totalSold += tokenAmount;
        
        paymentToken.safeTransferFrom(msg.sender, address(this), usdcAmount);
        saleToken.safeTransfer(msg.sender, tokenAmount);
        
        emit TokensPurchased(msg.sender, usdcAmount, tokenAmount);
    }
    
    function withdrawFunds(address to) external onlyOwner {
        uint256 balance = paymentToken.balanceOf(address(this));
        paymentToken.safeTransfer(to, balance);
    }
    
    function withdrawUnsoldTokens(address to) external onlyOwner {
        require(block.timestamp > saleEnd, "Sale not ended");
        uint256 balance = saleToken.balanceOf(address(this));
        saleToken.safeTransfer(to, balance);
    }
}

Як Merkle Tree знижує вартість розгортання?

Замість зберігання кожної адреси on-chain (дорого), зберігаємо лише Merkle tree root. Proof генерується off-chain і передається при покупці. Для 10,000 адрес в whitelist — економія ~$1000+ на gas при деплої. Merkle Tree дозволяє скоротити вартість розгортання на 90% порівняно з масивом адрес. Економія на газі може досягати $2000 для великих проектів.

Інтеграція frontend з контрактом

Використовуємо wagmi v2 + viem для читання стану та відправки транзакцій. Підключаємо гаманець через RainbowKit. Приклад хука для отримання даних про продаж:

import { useReadContracts, useWriteContract, useWaitForTransactionReceipt } from "wagmi";
import { formatUnits, parseUnits } from "viem";

const SALE_ABI = [...] as const;

function useSaleData(saleAddress: `0x${string}`) {
  const result = useReadContracts({
    contracts: [
      { address: saleAddress, abi: SALE_ABI, functionName: "saleStart" },
      { address: saleAddress, abi: SALE_ABI, functionName: "saleEnd" },
      { address: saleAddress, abi: SALE_ABI, functionName: "totalSold" },
      { address: saleAddress, abi: SALE_ABI, functionName: "hardCap" },
      { address: saleAddress, abi: SALE_ABI, functionName: "tokenPrice" },
      { address: saleAddress, abi: SALE_ABI, functionName: "whitelistRequired" },
    ],
    query: { refetchInterval: 10_000 }, // оновлюємо кожні 10 сек
  });
  
  const [start, end, totalSold, hardCap, tokenPrice, whitelistRequired] = 
    result.data ?? [];
  
  const now = Date.now() / 1000;
  const saleStatus = !start?.result ? "loading" :
    now < Number(start.result) ? "upcoming" :
    now > Number(end?.result) ? "ended" :
    "active";
  
  const progress = totalSold?.result && hardCap?.result
    ? Number(totalSold.result * 100n / hardCap.result)
    : 0;
  
  return { saleStatus, progress, tokenPrice: tokenPrice?.result, whitelistRequired: whitelistRequired?.result };
}

Реалізація покупки з апрувом USDC

USDC вимагає approve перед buy. Патерн: спочатку перевіряємо allowance, якщо недостатньо — перший крок approve, другий крок — buy:

function BuyFlow({ saleAddress, usdcAddress, amount }) {
  const { address } = useAccount();
  const [step, setStep] = useState<"approve" | "buy" | "done">("approve");
  
  const { data: allowance } = useReadContract({
    address: usdcAddress,
    abi: ERC20_ABI,
    functionName: "allowance",
    args: [address, saleAddress],
    query: { enabled: !!address },
  });
  
  const needsApprove = !allowance || allowance < parseUnits(amount, 6);
  
  const { writeContract: approve, data: approveTx } = useWriteContract();
  const { writeContract: buy, data: buyTx } = useWriteContract();
  
  const { isSuccess: approveSuccess } = useWaitForTransactionReceipt({ hash: approveTx });
  
  useEffect(() => {
    if (approveSuccess) setStep("buy");
  }, [approveSuccess]);
  
  // Merkle proof для whitelist (якщо потрібен)
  const merkleProof = useMerkleProof(address);
  
  const handleApprove = () => {
    approve({
      address: usdcAddress,
      abi: ERC20_ABI,
      functionName: "approve",
      args: [saleAddress, parseUnits(amount, 6)],
    });
  };
  
  const handleBuy = () => {
    buy({
      address: saleAddress,
      abi: SALE_ABI,
      functionName: "buy",
      args: [parseUnits(amount, 6), merkleProof ?? []],
    });
  };
  
  if (needsApprove && step === "approve") {
    return <Button onClick={handleApprove}>Дозволити USDC (крок 1/2)</Button>;
  }
  
  return <Button onClick={handleBuy}>Купити токени (крок 2/2)</Button>;
}

Чому real-time оновлення критичні?

При відкритті раунду виникає навантажувальний сплеск. Frontend не повинен робити запит до ноди кожну секунду для тисяч користувачів. Рішення: WebSocket або SSE від backend. Backend підписується на події контракту і пушить оновлення всім клієнтам. Це знижує навантаження на RPC-ноду в 50 разів. Real-time через WebSocket краще ніж polling: затримка знижується з 10 секунд до менше 1 секунди.

// Backend: pusher або власний WebSocket
import { WebSocket } from "ws";

const wss = new WebSocket.Server({ port: 3001 });
const clients = new Set<WebSocket>();

// Слухаємо події контракту
publicClient.watchContractEvent({
  address: SALE_ADDRESS,
  abi: SALE_ABI,
  eventName: "TokensPurchased",
  onLogs: async (logs) => {
    const totalSold = await publicClient.readContract({
      address: SALE_ADDRESS,
      abi: SALE_ABI,
      functionName: "totalSold",
    });
    
    const update = JSON.stringify({ type: "sale_update", totalSold: totalSold.toString() });
    clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) client.send(update);
    });
  },
});

Важливі UX деталі

  • Таймер до старту: зворотний відлік до saleStart, синхронізований з block.timestamp.
  • Progress bar: totalSold / hardCap * 100%, оновлюється через WebSocket.
  • Розрахунок суми: користувач вводить USDC — показуємо скільки токенів отримає.
  • Gasless approve через Permit (EIP-2612) — об'єднує approve та buy в одну транзакцію.
  • Mobile responsive: більшість крипто-користувачів купують з телефону, тому кнопки великі, MetaMask Mobile deep link.

Що входить в розробку лендингу токенсейлу?

Компонент Опис
Смарт-контракт TokenSale з whitelist, soft/hard cap, раундами
Frontend Next.js 14 + TypeScript + wagmi
Whitelist Merkle Tree генерація + API endpoint
Real-time WebSocket або Pusher
Документація Керівництво по деплою, тестуванню
Підтримка 1 місяць гарантійної підтримки після запуску

Орієнтовні терміни та етапи роботи

  1. Аналіз та проектування — 2-3 дні: обговорюємо токеноміку, whitelist, раунди.
  2. Розробка смарт-контракту — 5-7 днів: написання, тести на Foundry, аудит.
  3. Розробка frontend — 7-10 днів: інтеграція, верстка, real-time.
  4. Тестування — 3-5 днів: навантажувальне тестування, QA.
  5. Деплой та запуск — 1-2 дні: deploy контракту, хостинг, налаштування.

Загальний термін: від 3 до 4 тижнів. Вартість розраховується індивідуально — оцінимо проект після брифу.

Типові помилки при розробці токенсейлу

  • Використання address[] для whitelist замість Merkle Tree — різке зростання gas.
  • Відсутність захисту від reentrancy — контракт вразливий.
  • Ігнорування навантаження — frontend не справляється з піком.
  • Немає обробки помилок approve — користувач застрягне на кроці 1.

Порівняння підходів до real-time оновлень

Критерій Polling (кожні 10с) WebSocket/SSE
Затримка до 10 секунд <1 секунда
Навантаження на RPC висока (50 запитів/сек) низька (1 підписка)
Складність низька середня
Масштабованість погана відмінна

Приклад з практики: токенсейл на 10 000 учасників

Для одного з проектів ми розробили лендинг токенсейлу з whitelist на 10 000 адрес. Використання Merkle Tree дозволило зекономити понад $1000 на газі при деплої. Frontend на Next.js з WebSocket обробляв пік у 20 000 запитів на хвилину без збоїв. Час відгуку real-time оновлень не перевищував 500 мс. Проект успішно зібрав hard cap за 4 години.

Замовте розробку лендингу під ключ — ми проаналізуємо ваш проект і запропонуємо оптимальне рішення. Зв'яжіться з нами для консультації.

Розробка токенів на Ethereum: ERC-20, токеноміка, вестинг

Ми маємо 5+ років досвіду в розробці токенів на Ethereum та сумісних L2. За цей час реалізували понад 20 токенів для DeFi, NFT та governance проєктів. Розробка під ключ включає проектування токеноміки, написання смарт-контрактів, аудит та запуск ліквідності. Гарантуємо прозорість умов і супровід після запуску. Напишіть нам — отримайте технічний аналіз вашого проєкту за 1 день.

«ERC-20 — це просто» — фраза, після якої починаються проблеми. Базовий transfer написати не складно. Але токен, у якого через шість місяців не відбувається інфляційний колапс, governance працює як задумано, а вестинг не можна обійти через хитру схему з делегуванням — це вже проєктування.

Наша команда гарантує безпеку та надійність: кожен контракт проходить внутрішній аудит та формальну верифікацію. Ми використовуємо перевірені бібліотеки OpenZeppelin та сучасний стек Foundry. Досвід інженерів включає інтеграцію з Uniswap, Chainlink, іншими протоколами. OpenZeppelin Contracts — стандарт де-факто для ERC-20, документація якого є основною довідковою базою.

ERC-20: що під капотом

Стандарт ERC-20 — дев'ять функцій. Складність починається з розширень.

ERC-20Permit (EIP-2612) — gasless approve через підпис. Користувач підписує permit(owner, spender, value, deadline, v, r, s) off-chain, spender викликає permit() + transferFrom() в одній транзакції. Це прибирає окремий approve step. Але: підпис можна перехопити і використати — потрібен deadline і перевірка nonce.

ERC-20Votes (EIP-5805) — snapshot балансів для governance. Checkpoint-система зберігає історію балансів за номером блоку. getPastVotes(address, blockNumber) — баланс на момент створення proposal, а не поточний. Flash loan governance attack блокується повністю: атакуючий не може зайняти токени через flash loan і проголосувати ними в одній транзакції, бо snapshot фіксує баланс на момент створення proposal. ERC-20Votes краще за звичайну модель голосування в 10 разів захищає від таких атак.

Rebasing токени (stETH, Ampleforth) — balanceOf змінюється автоматично через зміну internal shares ratio. Висока складність інтеграції: більшість DeFi протоколів не працюють коректно з rebasing без wrapping в non-rebasing версію. Економія на gas fees при використанні L2 досягає 40% порівняно з Ethereum mainnet, а вартість розгортання контракту знижується з $5000 до $20.

Fee-on-transfer токени — при кожному transfer знімається відсоток. Ламають AMM розрахунки: пул отримує менше, ніж очікував. Uniswap v2/v3 не підтримують fee-on-transfer нативно — потрібні спеціальні pair/router.

Tokenomics: де математика перетворюється на економіку

Токеноміка — це не таблиця в Excel з сумою 100%. Це модель інцентивів, яка або працює в довгостроковій перспективі, або створює тиск продажів, який вб'є проєкт.

Emission schedule та інфляція

Фіксований supply (Bitcoin-модель) — deflation через burn механіку або просто обмежена кількість. Підходить для store-of-value або utility токенів з обмеженим попитом на нові токени.

Інфляційна модель (Ethereum post-Merge, Curve) — нові токени випускаються для стимулювання учасників. Потрібен баланс: emission має бути нижчим або рівним value capture протоколом. Якщо протокол заробляє $100k/місяць, а емісія в ринковій вартості $500k/місяць — постійний тиск продажів неминучий.

Halving schedules (Bitcoin-style) — зменшення emission з часом. Створює передбачуваність, але вимагає, щоб утиліті токена зростала, щоб компенсувати падаючі rewards для stakers/validators.

Supply distribution

Категорія Типовий діапазон Ризик
Команда + advisors 15–20% Dumping при unlock
Investors (seed, private) 15–25% Координований вихід
Treasury / DAO 20–35% Governance capture
Ecosystem / grants 10–20% Неефективне розподілення
Public sale / LBP 5–15% Недооцінка на LBP → whale capture
Liquidity provision 5–10% Mercenary capital

Немає універсальної формули. Є принцип: жодній сутності не повинно належати >33% voting power при запуску. Інакше governance — фікція.

Liquidity Bootstrapping — механіка запуску ліквідності

Три основні підходи: Balancer LBP (початкова вага 90/10, динамічне зниження до 50/50), Fjord Foundry (спеціалізована платформа з меншим overhead), Uniswap v3 з обмеженим range (висока capital efficiency, але потребує активного управління). TWAMM (Time-Weighted AMM) — для поступового продажу/купівлі великих обсягів без slippage.

Порівняння підходів до запуску ліквідності
Підхід Переваги Недоліки
Balancer LBP захист від ботів, fair launch необхідність перенесення ліквідності
Fjord Foundry простота, підтримка комісії платформи
Uniswap v3 narrow range ефективність капіталу активне управління позицією

Vesting та Governance

Vesting контракти: деталі мають значення

Linear vesting з cliff — стандарт для команди та інвесторів. cliff — період після TGE, протягом якого нічого не доступно. Після cliff — лінійний unlock до duration.

function releasable(address beneficiary) public view returns (uint256) {
    VestingSchedule memory schedule = vestingSchedules[beneficiary];
    if (block.timestamp < schedule.cliff) return 0;

    uint256 elapsed = block.timestamp - schedule.cliff;
    uint256 vestingDuration = schedule.duration - (schedule.cliff - schedule.start);
    uint256 vested = schedule.totalAmount * elapsed / vestingDuration;

    return vested - schedule.released;
}

Типові помилки при реалізації:

  • Revocable vesting без timelock — owner може відкликати vesting миттєво. Рішення: revocation через multisig + governance vote.
  • Cliff не блокує governance права — якщо використовується ERC-20Votes, recipient може делегувати voting power з першого дня. Потрібно явно розділити voting power і claim logic.
  • Відсутність emergency pause — Pausable + timelock на unpause.

Як налаштувати vesting контракт покроково:

  1. Визначити параметри vesting (cliff, duration, totalAmount).
  2. Розгорнути контракт TokenVesting (наприклад, OpenZeppelin).
  3. Призначити beneficiary та підтвердити розклад.
  4. Налаштувати emergency pause та revocation через multisig.
  5. Протестувати сценарії за допомогою Foundry fuzz тестів.

Governance токени та voting механіки

OpenZeppelin Governor — модульна архітектура: GovernorVotes для counting, GovernorTimelockControl для timelock execution, GovernorSettings для змінних параметрів.

Quorum — мінімальний відсоток supply для валідності голосування. Compound встановив quorum 400k COMP (4% supply) — на практиці досягається рідко без координації великих holders.

Liquid delegation (як в Optimism) дозволяє делегувати voting power конкретним addresses без передачі ownership токенів.

Як обрати правильний тип токена для вашого проєкту?

Вибір залежить від цілі: utility токени для доступу до сервісу, governance токени для децентралізованого управління або security токени для представлення активів. Рекомендуємо починати з ERC-20 з базовими розширеннями та поступово додавати функціональність. Ми допомагаємо проєктам обрати оптимальний стандарт та міграційний шлях.

Які ризики виникають при використанні rebasing токенів?

Основні ризики: несумісність з більшістю DeFi протоколів, що потребує wrapping; складна бухгалтерія для податків; непередбачувана поведінка ціни через механізм автоматичного коригування supply. Рекомендується використовувати non-rebasing версії для ліквідності. Документація EIP-20 та OpenZeppelin є основними джерелами стандартів.

Процес розробки та строки

  • Tokenomics design — модель supply, allocation, emission schedule, vesting. Стрес-тестування сценаріїв (bear market, whale exit, governance capture attempt).
  • Контракт розробка — ERC-20 + extensions, vesting, governance. Foundry fuzz тести на vesting calculations, governance thresholds.
  • Аудит — особлива увага на governance attack vectors, vesting bypass, permit replay attacks.
  • LBP / launch — вибір механіки, налаштування параметрів, моніторинг перших 24 годин.
  • Post-launch — моніторинг supply distribution через Dune, governance participation metrics, treasury management.

Стек: Solidity 0.8.x, OpenZeppelin Contracts 5.x, Foundry, Gnosis Safe, OpenZeppelin Defender, Dune Analytics.

Строки (залежать від складності):

  • ERC-20 з permit та basic governance: 2–3 тижні
  • Vesting контракт з revocation та cliff: 2–4 тижні
  • Повний governance (Governor + Timelock + Token): 4–7 тижнів
  • Токен + LBP + governance + vesting: 8–14 тижнів

Що входить в роботу

  • Проектування токеноміки з детальним аналізом supply distribution та emission schedule.
  • Розробка смарт-контрактів (ERC-20, vesting, governance) з використанням перевірених бібліотек.
  • Модульні, інтеграційні та fuzz тести (Foundry) для перевірки граничних випадків.
  • Внутрішній аудит коду з використанням Slither та Mythril.
  • Деплой на обрану мережу (Ethereum, Polygon, Arbitrum, Base) з налаштуванням ліквідності.
  • Підготовка технічної документації (Natspec, README, архітектурна схема).
  • Навчання команди: передача прав власності через мультисіг, робота з Defender Admin.
  • Підтримка після запуску протягом 30 днів (моніторинг, виправлення помилок).

Зв'яжіться з нами для отримання консультації та оцінки вашого проєкту. Замовте розробку токена — ми підготуємо рішення під ключ.