Разработка системы массового распределения токенов

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка системы массового распределения токенов
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1056
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка системы массового распределения токенов

Массовая раздача токенов — это не просто цикл с transfer() в смарт-контракте. Когда получателей десятки тысяч, а каждая транзакция стоит gas, неправильная архитектура превращает airdrop в убыточное мероприятие для проекта и в кошмар для пользователей, которые не могут получить токены часами из-за перегрузки сети.

Задача системы массового распределения: доставить токены максимальному числу адресов с минимальными затратами на gas, с защитой от злоупотреблений и с возможностью аудита каждой выплаты.

Push vs Pull: ключевой архитектурный выбор

Первое решение — кто инициирует передачу токенов.

Push (project → user): проект сам отправляет токены на адреса. Просто для пользователя, дорого для проекта. При 50,000 получателях и стандартном transfer (21,000 gas) на Ethereum mainnet — миллионы долларов gas при любой нагрузке на сеть.

Pull (user claims): получатель сам вызывает claim(). Затраты на gas ложатся на пользователя. Дополнительный барьер входа, но экономически более честно.

Merkle drop (pull с доказательством): золотой стандарт для крупных airdrop. Список получателей публикуется как Merkle tree, on-chain хранится только root. Пользователь предоставляет proof принадлежности своего адреса к списку.

contract MerkleDistributor {
    address public immutable token;
    bytes32 public immutable merkleRoot;
    
    // Битовая карта для отслеживания claim без хранения маппинга адресов
    mapping(uint256 => uint256) private claimedBitMap;
    
    event Claimed(uint256 indexed index, address indexed account, uint256 amount);
    
    constructor(address token_, bytes32 merkleRoot_) {
        token = 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 node = keccak256(abi.encodePacked(index, account, amount));
        require(
            MerkleProof.verify(merkleProof, merkleRoot, node),
            "Invalid proof"
        );
        
        _setClaimed(index);
        IERC20(token).transfer(account, amount);
        
        emit Claimed(index, account, amount);
    }
    
    function _setClaimed(uint256 index) private {
        uint256 claimedWordIndex = index / 256;
        uint256 claimedBitIndex = index % 256;
        claimedBitMap[claimedWordIndex] |= (1 << claimedBitIndex);
    }
}

Битовая карта вместо mapping(address => bool) экономит существенный объём storage, особенно при сотнях тысяч получателей.

Генерация и верификация Merkle tree

Off-chain генерация дерева — критически важный этап. Ошибка в списке получателей означает невозможность получить токены или двойные выплаты.

const { MerkleTree } = require('merkletreejs');
const keccak256 = require('keccak256');
const { ethers } = require('ethers');

function generateMerkleTree(recipients) {
    // recipients: [{ index, address, amount }, ...]
    
    const leaves = recipients.map(({ index, address, amount }) => {
        return ethers.solidityPackedKeccak256(
            ['uint256', 'address', 'uint256'],
            [index, address, amount]
        );
    });
    
    const tree = new MerkleTree(leaves, keccak256, { sortPairs: true });
    const root = tree.getHexRoot();
    
    // Генерируем proofs для каждого получателя
    const proofs = recipients.map(({ index, address, amount }, i) => ({
        index,
        address,
        amount: amount.toString(),
        proof: tree.getHexProof(leaves[i])
    }));
    
    return { root, proofs };
}

// Публикуем proofs через IPFS или API
// Пользователь получает свой proof и вызывает claim()

Защита от sybil и злоупотреблений

Массовая раздача без защиты — это приглашение к sybil-атаке. Типичный сценарий: атакующий создаёт тысячи кошельков, выполняет минимальные требования с каждого и получает непропорциональную долю airdrop.

Уровни защиты:

On-chain критерии: учитывать только кошельки с реальной историей — первая транзакция до определённой даты, объём комиссий выше порога, взаимодействие с конкретными протоколами.

Off-chain верификация: Gitcoin Passport (агрегатор identity proof), Proof of Humanity, верификация через social proof (Twitter/Github аккаунт связанный с адресом). Интегрируется через signature: пользователь подписывает своим кошельком сообщение, подтверждающее ownership.

Tiered airdrop: разные суммы для разных категорий активности. Early users получают больше, чем те, кто начал взаимодействовать за неделю до snapshot.

Категория Критерий Множитель
OG users Первая транзакция > 12 месяцев назад 3x
Active users > 10 транзакций за последние 6 месяцев 2x
Regular users Хотя бы 1 транзакция за последние 3 месяца 1x
Snapshot hunters Транзакция за последние 2 недели 0.5x

Batch distribution для push-сценариев

Когда push необходим (например, компенсация пострадавшим в exploit, retroactive rewards для верифицированных адресов), используют batch transfer контракты.

Простой паттерн: multicall с несколькими transfer() в одной транзакции. Более эффективный: Disperse.app паттерн — один вызов контракта, который итерируется по массиву получателей.

function disperseToken(
    IERC20 token,
    address[] calldata recipients,
    uint256[] calldata amounts
) external {
    uint256 total = 0;
    for (uint256 i = 0; i < amounts.length; i++) {
        total += amounts[i];
    }
    
    token.transferFrom(msg.sender, address(this), total);
    
    for (uint256 i = 0; i < recipients.length; i++) {
        token.transfer(recipients[i], amounts[i]);
    }
}

Оптимальный размер батча — 200–500 адресов на транзакцию в зависимости от сети. Превышение лимита block gas limit приводит к reverts.

Vesting поверх airdrop

Для команд и инвесторов часто комбинируют массовое распределение с vesting: токены клеймятся, но не сразу доступны полностью, а разблокируются по расписанию.

Реализация: при claim пользователь не получает токены напрямую, а деплоится персональный VestingWallet (или создаётся запись в общем vesting контракте) с заданным расписанием. Это дороже по gas, но даёт полную гибкость в настройке индивидуальных vesting schedules.

Мониторинг и аналитика

После запуска airdrop нужно отслеживать: процент claimed от общего пула, сколько адресов claim'нули в первые 24/48/72 часа, адреса которые немедленно продают (on-chain через DEX events), средний retention токенов через 30 дней.

Эти метрики напрямую связаны с качеством аудитории и позволяют скорректировать следующий airdrop.

Сроки разработки

Merkle distributor с off-chain генерацией дерева и базовым frontend для claim — 3–4 недели. Полноценная система с sybil-защитой, tiered распределением, vesting интеграцией и аналитическим dashboard — 2–3 месяца.