Розробка системи антибот-захисту при мінтингу

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

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

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

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

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

Розробка системи антибот-захисту при мінтингу

Azuki у січні 2022: 8700 NFT за 3 хвилини, 30 ETH газу в піці. Боти сминтили 2/3 колекції раніше реальних користувачів. OpenSea через тиждень: одні адреси перепродають по 10x. Це класична ситуація без антибот-захисту. Наступні великі запуски — BAYC, CryptoPunks — вчилися на помилках та впровадили різні механізми. Який з них правильний для вашої колекції — залежить від розміру аудиторії та бажаного розподілу.

Механізми захисту та їх trade-offs

Merkle whitelist: найпоширеніша захист

Merkle tree з адрес вайтлісту. Кожна адреса з листа може довести своє членство, надавши proof з O(log n) хешів. Контракт зберігає тільки один root (32 байти), не весь список.

bytes32 public merkleRoot;

function whitelistMint(uint256 quantity, bytes32[] calldata proof) external payable {
    bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
    require(MerkleProof.verify(proof, merkleRoot, leaf), "Not whitelisted");
    require(!_whitelistClaimed[msg.sender], "Already claimed");
    _whitelistClaimed[msg.sender] = true;
    _mint(msg.sender, quantity);
}

Генерація Merkle tree — off-chain TypeScript скрипт через merkletreejs. Root оновлюється перед мінтом через setMerkleRoot() (onlyOwner). Proofs користувачі отримують через API або заранее публікуються в IPFS.

Уязвимість: якщо frontend компрометований, атакуючий може запросити proof для будь-якої адреси з листа через API. Захист: proof видаватись тільки wallet, який його запитує (signature-gated API), або весь список публікується заранее (повна відкритість).

Commit-reveal: захист від frontrunning при random mint

Без commit-reveal: бот аналізує mempool, бачить транзакцію з параметрами, робить точну копію з більш високим gas — frontrunning. З commit-reveal: користувач спочатку публікує keccak256(secret + address), потім через N блоків розкриває secret. За ці N блоків копіювати бесмисленно — secret невідомий.

Двухетапний процес незручний для користувачів. Використовуємо тільки де random розподіл критичний та користувачі готові до двох транзакцій.

Per-address ліміти: необхідний мінімум

Найбазовіша захист — ліміт на адресу:

mapping(address => uint256) public mintedByAddress;
uint256 public constant MAX_PER_ADDRESS = 3;

function mint(uint256 quantity) external {
    require(mintedByAddress[msg.sender] + quantity <= MAX_PER_ADDRESS, "Limit exceeded");
    mintedByAddress[msg.sender] += quantity;
    _mint(msg.sender, quantity);
}

Не захищає від Sybil — один бот створює тисячі адрес. Але підвищує вартість атаки: потрібно більше гаманців, газ на переміщення ETH між ними. У комбінації з іншими методами — ефективно.

Глибоке занурення: proof-of-work при мінтингу

Найрідше застосовуємий, але цікавий механізм. Ідея: перед мінтом потрібно вирішити обчислювальну задачу — знайти nonce такий, що keccak256(address + nonce) < difficulty. Це CPU/GPU робота, яку бот робить швидше, але вона створює resource constraint.

uint256 public mintDifficulty = type(uint256).max / 1000; // 0.1% хешів проходять

function mint(uint256 nonce) external {
    bytes32 hash = keccak256(abi.encodePacked(msg.sender, nonce, block.number / 100));
    require(uint256(hash) < mintDifficulty, "Invalid proof of work");
    _mint(msg.sender, 1);
}

block.number / 100 — вікно в ~100 блоків (~20 хвилин). Nonce валідний тільки в цьому вікні, нельзя обчислити заранее. Складність настроюється через mintDifficulty.

Проблема: мобільні користувачі витрачають 10-30 секунд на обчислення. Боти з GPU — 0.1 секунди. Асиметрія не на користь звичайних користувачів. Proof-of-work ефективний тільки у комбінації з вайтлістом, де боти спочатку не у листі.

Час очікування та batch ліміти

Додаткова механіка проти ботів: максимальний mint у перші N блоків від початку — 1 токен. Після N блоків — до MAX_PER_ADDRESS. Бот, який б'є в першу секунду, отримує тільки 1 токен. Користувачі, які прийшли через хвилину, можуть взяти більше.

uint256 public publicMintStartBlock;

function maxMintForBlock(uint256 _block) public view returns (uint256) {
    if (_block < publicMintStartBlock + 50) return 1;  // перші ~10 хв
    return MAX_PER_ADDRESS;
}

Порівняння механізмів

Механізм Вартість атаки UX для користувача Складність реалізації
Per-address ліміт Низька (Sybil) Чудово Мінімальна
Merkle whitelist Висока Хорошо Середня
Commit-reveal Висока Погано (2 txs) Висока
Proof-of-work Середня Нормально Середня
Batch ліміт за часом Середня Чудово Низька

Рекомендовані комбінації

Мала колекція (<1000), закрита спільнота: Merkle whitelist + per-address ліміт 2-3.

Середня колекція (1000-10000), відкритий мінт: Whitelist фаза (Merkle) → public фаза з batch лімітом за часом + per-address ліміт.

Велика колекція (>10000), високий попит: Whitelist фаза + public фаза з proof-of-work або raffle через VRF.

Процес розробки

Аналітика (1 день). Визначаємо механіку: є ли whitelist, скільки фаз, ліміти на адресу.

Розробка (1-3 дні). Контракт з обраними механізмами. Off-chain скрипт генерації Merkle tree. API для видачі proofs.

Тестування. Окремо тестуємо кожен механізм: whitelist proof перевірка, ліміти, timing механіки. Foundry fuzz тест: testMintLimit(address,uint256) — будь-яка комбінація не повинна перевищувати ліміт.

Орієнтири за часом

Система з Merkle whitelist + per-address ліміт — 1-2 дні. Повна багатофазна система з proof-of-work та commit-reveal — 3-5 днів.