Розробка Merkle Distributor для масових виплат токенів

Розробка Merkle Distributor для масових виплат Ми регулярно вирішуємо задачу масових виплат токенів — airdrop на 50 000+ адрес. Наївне рішення — зберігати `mapping(address => uint256)` on-chain і ітеруватися по ньому в скрипті деплою. Деплой такого маппінгу коштує ~50 SLOAD + 50 SSTORE на кожного

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

Часті запитання

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

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

Розробка Merkle Distributor для масових виплат

Ми регулярно вирішуємо задачу масових виплат токенів — airdrop на 50 000+ адрес. Наївне рішення — зберігати mapping(address => uint256) on-chain і ітеруватися по ньому в скрипті деплою. Деплой такого маппінгу коштує ~50 SLOAD + 50 SSTORE на кожного отримувача, разом при 50K отримувачах — кілька ETH тільки на запис даних у storage. Наприклад, при ціні ETH $2000 це близько $5000. Merkle Tree вирішує це принципово інакше: економія газу на деплой сягає 95% порівняно з прямим storage, що дає економію до $4750 при тому ж airdrop. Кожен claim обходиться у фіксовану суму — приблизно $5 (при низькій ціні газу). Це в 4 рази дешевше, ніж прямі перекази.

Як працює Merkle Distributor?

У контракт деплоїться лише один bytes32 merkleRoot — корінь дерева. Вся таблиця виплат (адреса → сума) залишається off-chain. Отримувач сам приходить за своїми токенами з merkleProof — набором хешів, що доводять його включення в дерево.

On-chain верифікація:

function claim( uint256 index, address account, uint256 amount, bytes32[] calldata merkleProof ) external { require(!isClaimed(index), "Already claimed"); bytes32 node = keccak256(abi.encodePacked(index, account, amount)); require(MerkleProof.verify(merkleProof, merkleRoot, node), "Invalid proof"); _setClaimed(index); require(IERC20(token).transfer(account, amount), "Transfer failed"); emit Claimed(index, account, amount); } 

isClaimed(index) перевіряє один біт у mapping(uint256 => uint256) — packed bitmask. 50 000 отримувачів = ~1563 uint256 слотів замість 50 000. Економія на storage — в 32 рази.

Чому цей розподільник — стандарт для airdrop?

Порівняємо витрати на деплой для 50 000 отримувачів:

Підхід Слотів storage Вартість газу (приблизно)
Mapping напряму 50 000 ~2.5 ETH
Merkle Distributor ~1 563 ~0.08 ETH

Економія понад 95% (в 31 раз). Для одиничного claim:

Метод Газ на claim Примітка
Mapping + batch ~300k+ Залежить від кількості отримувачів
Merkle Distributor ~80k В 3.75 рази дешевше

При 50 000 claims економія складе десятки ETH.

Як побудувати Merkle Tree: покрокове керівництво

Підготуйте список отримувачів з індексами, адресами та сумами. Сформуйте листя: leaf = keccak256(abi.encodePacked(index, address, amount)) — подвійне хешування захищає від second preimage attack. Побудуйте дерево: використовуйте бібліотеку @openzeppelin/merkle-tree (JS/TS) або rs_merkle (Rust). Кожен internal node = keccak256(abi.encodePacked(left, right)) з canonical ordering (менший хеш зліва). Отримайте корінь: tree.root — єдине значення, що зберігається в контракті. Згенеруйте proofs: для кожного отримувача за допомогою tree.getProof(...). Роздайте proofs через API або опублікуйте в IPFS.

Типовий скрипт:

import { StandardMerkleTree } from "@openzeppelin/merkle-tree"; const values = recipients.map(([address, amount], index) => [ index, address, amount ]); const tree = StandardMerkleTree.of(values, ["uint256", "address", "uint256"]); console.log("Root:", tree.root); // proof для конкретного отримувача const proof = tree.getProof([index, address, amount]); 

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

Найпоширеніша помилка — некоректна бітова маска для захисту від double spend. Якщо _setClaimed встановлює біт неправильно, можливий повторний claim. Використовуйте перевірений патерн з OpenZeppelin. Друга проблема — колізія листя: якщо листя формуються без index (keccak256(abi.encodePacked(address, amount))), то два отримувачі з однаковою сумою можуть довести claim один на одного. Додавання index гарантує унікальність. Третя помилка — невідповідність кодування: abi.encodePacked в off-chain та в Solidity повинні співпадати.

Розширені патерни

Багатораундовий distributor: новий merkleRoot кожен тиждень/епоху. Замість деплою нового контракту — оновлюваний root через updateMerkleRoot(bytes32) з onlyOwner або governance. Claimed bitmask скидається для нової епохи або індексується по епосі: mapping(uint256 epoch => mapping(uint256 wordIndex => uint256 bitmask)).

Delegated claiming: отримувач підписує дозвіл на claim від свого імені — для gasless UX через релеєр або ERC-2771 meta-transactions. Патерн: claimFor(address account, uint256 amount, bytes32[] calldata proof, bytes calldata signature).

Тестування на Foundry

function test_ClaimValidProof() public { bytes32[] memory leaves = new bytes32[](3); leaves[0] = keccak256(abi.encodePacked(uint256(0), alice, uint256(100e18))); distributor.claim(0, alice, 100e18, proof); assertEq(token.balanceOf(alice), 100e18); vm.expectRevert("Already claimed"); distributor.claim(0, alice, 100e18, proof); } 

Для генерації proofs у Foundry тестах: vm.ffi з викликом TypeScript скрипту через @openzeppelin/merkle-tree. Або пишіть чисту Solidity-реалізацію в setUp().

Що входить до нашої розробки

Ми на ринку понад 5 років, реалізували 20+ distributor-контрактів для airdrop, стейкінгу та масових виплат. У вартість входить:

  • Вихідний код смарт-контракту на Solidity (протестований на Foundry, включає fuzz-тести).
  • Off-chain скрипти: побудова дерева, генерація proofs, деплой та верифікація (TypeScript, ethers.js).
  • Документація: опис архітектури, інструкція з розгортання, опис API.
  • Доопрацювання під ваш токен: ERC-20, ERC-721, ERC-1155 або кросс-чейн за допомогою bridge.
  • Підтримка після запуску: виправлення багів, консультації з інтеграції.

Терміни та вартість

Базовий Merkle Distributor з single root: 2-3 дні включаючи off-chain скрипти. Багатораундовий з governance та gasless claiming: 4-5 днів. Деплой та верифікація контракту на mainnet — додатково кілька годин. Вартість розраховується індивідуально після уточнення деталей. Зв'яжіться з нами для оцінки вашого проекту — проаналізуємо кількість отримувачів, вимоги до епох та UX. Замовте розробку Merkle Distributor і заощадьте тисячі доларів на газі. Отримайте консультацію прямо зараз.