Разработка token unlock трекера

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1Все 1306 услуг
Разработка token unlock трекера
Средний
~3-5 дней
Часто задаваемые вопросы

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

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

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

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

Разработка Sybil-resistant airdrop системы

Sybil-атака на airdrop — это не экзотика, это норма. Любой airdrop, анонсированный заранее, получает армию ботов ещё до момента snapshot. После того как Optimism раздал токены в 2022 году и быстро выяснилось, что значительная часть получателей — кластеры Sybil-кошельков, стандарт для серьёзных дистрибуций изменился. Теперь Sybil-resistance — обязательный компонент, а не опция.

Анатомия Sybil-атаки на airdrop

Атакующий создаёт N кошельков, имитирует eligibility-критерии на каждом, получает N долей airdrop, переводит всё на главный кошелёк. Сложность атаки зависит от стоимости имитации одного кошелька versus ожидаемой выплаты.

Три уровня Sybil-атак по сложности:

Уровень 1 — address farming. Создать кошельки, сделать минимальные действия. Дёшево и массово. Работает против простых критериев вроде «хотя бы одна транзакция в сети».

Уровень 2 — activity simulation. Скриптованные взаимодействия с протоколами: свапы, bridging, liquidity provision. Стоимость выше — gas + время. Работает против критериев объёма транзакций.

Уровень 3 — social graph manipulation. Создание связей между аккаунтами, имитация organic behavior. Дорого, но применяется при больших суммах airdrop.

Ключевое наблюдение: ни один метод не даёт 100% защиты. Цель — поднять стоимость Sybil-атаки выше ожидаемой прибыли.

On-chain анализ: кластеризация адресов

Граф транзакций и common funder detection

Самый базовый и эффективный метод — анализ источника финансирования кошельков. Sybil-кошельки почти всегда финансируются с одного адреса или через один CEX-вывод.

import networkx as nx
from collections import defaultdict

def build_funding_graph(addresses: list[str], provider) -> nx.DiGraph:
    """
    Строим граф: кто кого финансировал.
    addresses — список eligible адресов.
    """
    G = nx.DiGraph()
    
    for addr in addresses:
        # Берём первую входящую транзакцию (initial funding)
        first_tx = provider.get_first_incoming_tx(addr)
        if first_tx:
            funder = first_tx['from']
            G.add_edge(funder, addr, tx=first_tx['hash'])
    
    return G

def detect_sybil_clusters(G: nx.DiGraph, threshold: int = 5) -> list[list[str]]:
    """
    Если один адрес профинансировал >= threshold eligible адресов — кластер.
    """
    clusters = []
    for node in G.nodes():
        successors = list(G.successors(node))
        if len(successors) >= threshold:
            clusters.append(successors)
    return clusters

На практике threshold подбирается под конкретный airdrop. Для большого airdrop с тысячами адресов — 5 вполне консервативно. Для маленького — достаточно 3.

Temporal pattern analysis

Sybil-кошельки создаются и используются батчами. Характерный паттерн: N кошельков активны в одинаковые временные окна, с одинаковыми паузами между транзакциями.

def detect_temporal_clusters(
    addresses: list[str],
    txs_by_address: dict,
    time_window_seconds: int = 300,
    min_cluster_size: int = 3
) -> list[list[str]]:
    """
    Ищем адреса, чьи транзакции попадают в одинаковые
    временные окна подозрительно часто.
    """
    # Группируем транзакции по временным слотам
    time_slots = defaultdict(list)
    
    for addr, txs in txs_by_address.items():
        for tx in txs:
            slot = tx['timestamp'] // time_window_seconds
            time_slots[slot].append(addr)
    
    # Строим граф совместной активности
    co_activity = defaultdict(lambda: defaultdict(int))
    for slot, addrs in time_slots.items():
        for i, a in enumerate(addrs):
            for b in addrs[i+1:]:
                co_activity[a][b] += 1
                co_activity[b][a] += 1
    
    # Кластеры с высокой совместной активностью
    clusters = []
    visited = set()
    
    for addr in addresses:
        if addr in visited:
            continue
        cluster = [addr]
        for other, count in co_activity[addr].items():
            if count >= 3 and other not in visited:  # совпадали 3+ раза
                cluster.append(other)
        if len(cluster) >= min_cluster_size:
            clusters.append(cluster)
            visited.update(cluster)
    
    return clusters

Gas price и nonce patterns

Скрипты, создающие Sybil-кошельки, часто используют одинаковые параметры gas. Одинаковый gasPrice / maxFeePerGas в транзакциях разных кошельков в одном блоке — сильный сигнал. Nonce = 0 или 1 у большого количества адресов говорит о недавнем создании под конкретный airdrop.

Identity-based верификация

Proof of Humanity и Worldcoin

Самый надёжный Sybil-resistance — доказательство уникальности личности. Два основных протокола:

Proof of Humanity (PoH): видео-регистрация + социальная верификация (vouch от существующих участников). Хранит список verified humans on-chain (Gnosis Chain). Медленно масштабируется, но высокое качество.

Worldcoin: биометрическая верификация через iris scan на Orb-устройствах. Выдаёт World ID — ZK-proof того, что пользователь уникален, без раскрытия биометрии.

interface IWorldID {
    function verifyProof(
        uint256 root,
        uint256 groupId,
        uint256 signalHash,
        uint256 nullifierHash,
        uint256 externalNullifierHash,
        uint256[8] calldata proof
    ) external view;
}

contract SybilResistantAirdrop {
    IWorldID public immutable worldId;
    uint256 public immutable groupId = 1;
    uint256 public immutable externalNullifier;
    
    // nullifierHash привязан к конкретному действию (claim этого airdrop)
    // один человек = один nullifierHash = один claim
    mapping(uint256 => bool) public usedNullifiers;
    
    constructor(IWorldID _worldId, string memory appId, string memory action) {
        worldId = _worldId;
        externalNullifier = abi.encodePacked(
            abi.encodePacked(appId).hashToField(),
            abi.encodePacked(action).hashToField()
        ).hashToField();
    }
    
    function claim(
        address recipient,
        uint256 root,
        uint256 nullifierHash,
        uint256[8] calldata proof
    ) external {
        require(!usedNullifiers[nullifierHash], "Already claimed");
        
        worldId.verifyProof(
            root,
            groupId,
            abi.encodePacked(recipient).hashToField(),
            nullifierHash,
            externalNullifier,
            proof
        );
        
        usedNullifiers[nullifierHash] = true;
        _distributeTokens(recipient);
    }
}

Ключевое свойство: nullifierHash уникален для комбинации (человек, action). Один человек не может получить два разных nullifierHash для одного action — это обеспечивается ZK-proof-ом.

Gitcoin Passport

Gitcoin Passport агрегирует signals из разных источников: GitHub аккаунт, Twitter, ENS имя, BrightID верификация, Proof of Humanity, POAP коллекции. Каждый stamp даёт score. Выше score — выше вероятность что это реальный человек.

// Проверка Gitcoin Passport score через API
async function getPassportScore(address: string): Promise<number> {
  const response = await fetch(
    `https://api.scorer.gitcoin.co/registry/score/${scorerId}/${address}`,
    { headers: { 'X-API-KEY': process.env.GITCOIN_API_KEY! } }
  );
  const data = await response.json();
  return parseFloat(data.score ?? '0');
}

// Порог score для eligibility
const MINIMUM_PASSPORT_SCORE = 15.0;

async function buildEligibleList(candidates: string[]): Promise<string[]> {
  const scores = await Promise.all(
    candidates.map(async (addr) => ({
      address: addr,
      score: await getPassportScore(addr)
    }))
  );
  
  return scores
    .filter(({ score }) => score >= MINIMUM_PASSPORT_SCORE)
    .map(({ address }) => address);
}

Многоуровневая scoring система

На практике ни один метод не используется в изоляции. Лучший подход — scoring: каждый адрес получает баллы за разные сигналы, финальная eligibility определяется суммой.

Критерий Баллы Обоснование
World ID верификация +50 Уникальность личности
Gitcoin Passport ≥ 20 +30 Агрегированная идентичность
ENS имя +10 Долгосрочная on-chain identity
Возраст кошелька > 1 года +10 Не создан под airdrop
Активность в нескольких протоколах +15 Organic usage pattern
Нет совпадений в фандинг-графе +5 Не часть Sybil-кластера
Сумма для eligibility ≥ 40 Настраивается под проект

Адреса, попавшие в Sybil-кластер при анализе графа, получают penalty или полную дисквалификацию независимо от score.

Апелляционный механизм

Любая автоматическая фильтрация даёт false positives. Нужен процесс обжалования:

  • On-chain appeal: адрес отправляет транзакцию с доказательством (Proof of Humanity proof, подпись от PoH регистрации, объяснение связи кошельков)
  • Timelock: период для подачи апелляций фиксирован (например, 14 дней после публикации snapshot)
  • Multisig review: команда рассматривает апелляции через multisig, решения прозрачны on-chain
  • Публичный список: все отфильтрованные адреса и причины публикуются до начала claim-периода

Прозрачность критична — сообщество должно видеть, что фильтрация не произвольна.

Архитектура контракта дистрибуции

contract SybilResistantDistributor {
    bytes32 public merkleRoot;
    mapping(address => bool) public claimed;
    
    // Адреса, заблокированные по результатам Sybil-анализа
    mapping(address => bool) public sybilBlacklist;
    
    // Минимальный Passport score (хранится off-chain, верифицируется подписью)
    address public scoreOracle;
    
    struct ClaimData {
        uint256 amount;
        bytes32[] merkleProof;
        // Опционально: подпись оракула подтверждающая Passport score
        bytes oracleSignature;
        uint256 passportScore;
    }
    
    function claim(ClaimData calldata data) external nonReentrant {
        require(!claimed[msg.sender], "Already claimed");
        require(!sybilBlacklist[msg.sender], "Address flagged as Sybil");
        
        // Верифицируем Passport score если требуется
        if (requirePassport) {
            _verifyPassportScore(msg.sender, data.passportScore, data.oracleSignature);
            require(data.passportScore >= minPassportScore, "Insufficient Passport score");
        }
        
        // Верифицируем merkle proof
        bytes32 leaf = keccak256(bytes.concat(
            keccak256(abi.encode(msg.sender, data.amount))
        ));
        require(
            MerkleProof.verify(data.merkleProof, merkleRoot, leaf),
            "Invalid proof"
        );
        
        claimed[msg.sender] = true;
        token.safeTransfer(msg.sender, data.amount);
        emit Claimed(msg.sender, data.amount);
    }
    
    function _verifyPassportScore(
        address user,
        uint256 score,
        bytes calldata sig
    ) internal view {
        bytes32 hash = keccak256(abi.encodePacked(user, score, block.chainid));
        bytes32 ethHash = hash.toEthSignedMessageHash();
        require(ethHash.recover(sig) == scoreOracle, "Invalid oracle signature");
    }
}

Временные задержки как защита

Один из недооценённых инструментов — временное окно между snapshot и объявлением eligibility. Если аirdrop анонсирован без snapshot даты, farming уже идёт. Лучшая практика:

  • Snapshot делается без предупреждения или с минимальным уведомлением
  • Eligibility объявляется после snapshot — у атакующих нет времени адаптироваться
  • Merkle root деплоится через timelock (24–72 часа) — сообщество может проверить список до начала claim

Инструменты и данные

Анализ on-chain данных: Dune Analytics (готовые запросы по Sybil паттернам), Nansen (wallet labeling), Arkham Intelligence (entity clustering).

Identity протоколы: Worldcoin (World ID), Proof of Humanity, BrightID, Gitcoin Passport, Lens Protocol (social graph).

Технические инструменты: Python + networkx для граф-анализа, The Graph для индексации, Alchemy/QuickNode для bulk RPC запросов.

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

Фаза Содержание Срок
Дизайн критериев eligibility Определение метрик, порогов, scoring модели 1–2 нед
On-chain анализ Сбор данных, кластеризация, фильтрация 2–3 нед
Смарт-контракты Distributor + identity интеграция 2–3 нед
Off-chain инфраструктура API, Merkle tree, оракул подписей 2–3 нед
Апелляционный процесс Контракт + UI + процедура 1–2 нед
Аудит и тестирование 2–3 нед

Минимальный реалистичный срок для production-ready системы — 10–16 недель. Спешка в Sybil-фильтрации дорого обходится репутационно: если сообщество видит очевидных ботов в списке получателей, доверие к проекту падает резко.