Разработка контракта для airdrop через Merkle distributor

Разработка контракта для airdrop Мы часто видим классическую ошибку — пытаться раздать токены через loop с on-chain отправкой каждому адресу. При 10 000 получателей это 10 000 транзакций, десятки тысяч долларов газа и несколько часов работы. Наша команда с 5+ летним опытом в блокчейне рекомендует

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

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1441
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    998
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1267
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    713
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    1003

Разработка контракта для airdrop

Мы часто видим классическую ошибку — пытаться раздать токены через loop с on-chain отправкой каждому адресу. При 10 000 получателей это 10 000 транзакций, десятки тысяч долларов газа и несколько часов работы. Наша команда с 5+ летним опытом в блокчейне рекомендует другой подход — Merkle distributor. Вы один раз on-chain устанавливаете Merkle root, а каждый получатель сам клеймит свои токены, платя только за своё включение. Это снижает ваш счёт за газ в сотни раз — Merkle distributor экономит до 99% газа по сравнению с прямыми переводами. Базовая библиотека для реализации — OpenZeppelin MerkleProof.

Какие проблемы решаем

  • Заоблачный газ при большом списке. On-chain airdrop на 50 000 адресов может стоить >$20 000 только на газе. Merkle distributor экономит 99% средств.
  • Уязвимость second preimage attack. Наивная реализация Merkle tree позволяет злоумышленнику подменить leaf. Мы используем double-hash leaf как в OpenZeppelin, что полностью блокирует атаку.
  • Блокировка токенов без deadline. Токены могут навсегда остаться в контракте, если никто не заклеймил. Добавляем deadline с возможностью возврата оставшихся токенов владельцу.
  • Отсутствие вестинга. Если токены должны распределяться постепенно, встраиваем линейный vesting прямо в distributor.

Сравнение подходов к airdrop

Параметр On-chain loop Merkle distributor
Транзакций N (каждый получатель — отдельный вызов) 1 (установка root) + N (каждый claim — оплачивает получатель)
Газ (10k чел., ETH mainnet) ~30 ETH ~0.1 ETH (за root) + ~0.02 ETH на пользователя
Время выполнения Часы Минуты (после деплоя)
Безопасность Зависит от газа Проверенная MerkleProof библиотека

Фактор экономии газа — до 300 раз при 10 000 адресах. Это особенно важно для команд с ограниченным бюджетом на запуск токена.

Как работает Merkle distributor: сравнение с loop

Переход на L2 снижает затраты на газ ещё на порядок: на Arbitrum или Base claim стоит копейки, а не доллары. Свяжитесь с нами для детального расчёта под вашу аудиторию.

Как мы это делаем

Используем проверенный стек: Solidity 0.8.x + OpenZeppelin библиотеки (MerkleProof, ERC20), для off-chain — TypeScript + @openzeppelin/merkle-tree. Развёртываем на Ethereum L1 или L2 (Arbitrum, Base, Optimism) по вашему выбору. Пример реализации с bit packing для claimed status:

// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; contract MerkleAirdrop { IERC20 public immutable token; bytes32 public immutable merkleRoot; mapping(uint256 => uint256) private claimedBitMap; constructor(address _token, bytes32 _merkleRoot) { token = IERC20(_token); merkleRoot = _merkleRoot; } function isClaimed(uint256 index) public view returns (bool) { uint256 claimedWordIndex = index / 256; uint256 claimedBitIndex = index % 256; uint256 claimedWord = claimedBitMap[claimedWordIndex]; uint256 mask = (1 << claimedBitIndex); return claimedWord & mask == mask; } function claim( uint256 index, address account, uint256 amount, bytes32[] calldata merkleProof ) external { require(!isClaimed(index), "Already claimed"); bytes32 leaf = keccak256(bytes.concat( keccak256(abi.encode(index, account, amount)) )); // Double-hash против second preimage attack require( MerkleProof.verify(merkleProof, merkleRoot, leaf), "Invalid proof" ); _setClaimed(index); require(token.transfer(account, amount), "Transfer failed"); emit Claimed(index, account, amount); } } 

Почему double-hash leaf?

Без него — second preimage attack: злоумышленник может подменить leaf данными, которые совпадают с intermediate node в дереве. OpenZeppelin использует keccak256(bytes.concat(keccak256(abi.encode(...)))) именно по этой причине.

Bit packing для claimed

Вместо mapping(address => bool) используем bit array: 256 статусов в одном uint256 slot. Экономия SLOAD газа существенна при большом количестве кламов.

Генерация Merkle tree off-chain

import { StandardMerkleTree } from "@openzeppelin/merkle-tree" const values = [ [0, "0xAddress1...", ethers.parseEther("100")], [1, "0xAddress2...", ethers.parseEther("250")], ] const tree = StandardMerkleTree.of(values, ["uint256", "address", "uint256"]) console.log("Merkle Root:", tree.root) for (const [i, v] of tree.entries()) { if (v[1] === "0xAddress1...") { const proof = tree.getProof(i) } } import fs from "fs" fs.writeFileSync("tree.json", JSON.stringify(tree.dump())) 

Proofs раздаёте через простой API: GET /proof?address=0x... → возвращает { index, amount, proof[] }. Пользователь вставляет эти данные в UI и вызывает claim. API можно реализовать на Fastify или Express — типовой код занимает около 50 строк.

Когда нужен vesting airdrop?

Если токены не должны быть доступны сразу — встраиваем линейный vesting в distributor. Клейм → токены на vesting schedule → пользователь забирает их по мере времени. Это защищает от мгновенного дампа.

Почему стоит выбрать L2 для airdrop?

На Ethereum mainnet claim стоит ~$2–10 за транзакцию. На Arbitrum, Base или Optimism — центы. Если ваша аудитория массовая, L2 снижают барьер входа. Мы поможем выбрать подходящий роллап и настроить мост для токенов.

Сеть Средняя стоимость claim Время подтверждения
Ethereum L1 $2–10 ~15 секунд
Arbitrum $0.01–0.05 ~1 минута
Base $0.01–0.03 ~1 секунда
Optimism $0.01–0.05 ~1 минута

Процесс работы

  1. Аналитика — обсуждаем список адресов, токен, L1/L2, нужен ли vesting, deadline.
  2. Проектирование — выбираем структуру Merkle tree, пишем спецификацию контракта.
  3. Разработка — пишем контракт с использованием OpenZeppelin, off‑chain скрипты, API.
  4. Тестирование — unit тесты, фаззинг (Echidna), симуляция в Tenderly.
  5. Деплой — на выбранную сеть, верификация контракта, тестовый claim.
  6. Поддержка — мониторинг, помощь пользователям при проблемах с claim.

Что входит в работу

  • Смарт-контракт (Merkle distributor с опциями deadline/vesting)
  • Off-chain генератор Merkle tree + TypeScript скрипты
  • API для раздачи proofs (Fastify/Express)
  • Пример UI интеграции (React + viem)
  • Документация по деплою и эксплуатации
  • 2 недели пост-запуска поддержки

Мы используем Echidna для fuzzing контракта, проверяя корректность проверки proof, невозможность повторного claim и газовые лимиты. Симуляция в Tenderly позволяет воспроизвести любую транзакцию до деплоя.

Сроки и стоимость

Стандартная реализация под ключ занимает от 1 до 2 недель. Стоимость рассчитывается индивидуально в зависимости от опций (vesting, gasless claim, кастомный UI). Оценим ваш проект за один рабочий день — просто напишите нам, и мы подготовим предложение. Закажите реализацию под ключ уже сегодня.