Розробка контракту для airdrop через Merkle distributor
Ми часто бачимо класичну помилку — намагатися роздати токени через loop з on-chain відправкою кожному адресу. При 10 000 отримувачів це 10 000 транзакцій, десятки тисяч доларів газу та кілька годин роботи. Наша команда з 5+ річним досвідом у блокчейні рекомендує інший підхід — Merkle distributor. Ви один раз on-chain встановлюєте Merkle root, а кожен отримувач сам клеймить свої токени, платячи лише за своє включення. Це знижує ваш рахунок за газ у сотні разів — Merkle distributor краще прямого перерахування у сотні разів за газом. Базова бібліотека для реалізації — OpenZeppelin MerkleProof. Економія газу становить до $50,000 на 100 000 адрес. Гарантуємо безпеку контракту за допомогою аудиту та формальної верифікації.
Які проблеми вирішуємо
- Завеликий газ при великому списку. 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 адресах. Ми вже реалізували 15 airdrop контрактів для різних екосистем (Ethereum, Arbitrum, Base). Це особливо важливо для команд з обмеженим бюджетом на запуск токена.
Як працює 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 хвилина |
Процес роботи
- Аналітика — обговорюємо список адрес, токен, L1/L2, чи потрібен vesting, deadline.
- Проектування — обираємо структуру Merkle tree, пишемо специфікацію контракту.
- Розробка — пишемо контракт з використанням OpenZeppelin, off‑chain скрипти, API.
- Тестування — unit тести, фаззинг (Echidna), симуляція в Tenderly.
- Деплой — на обрану мережу, верифікація контракту, тестовий claim.
- Підтримка — моніторинг, допомога користувачам при проблемах з 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). Оцінимо ваш проект за один робочий день — просто напишіть нам, і ми підготуємо пропозицію. Замовте реалізацію під ключ вже сьогодні.







