Розробка whitelist/allowlist для мінтингу NFT

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

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

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

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

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

Розробка Whitelist/Allowlist для мінтингу NFT

Типова ситуація: колекція з 10 000 NFT з whitelist з 3 000 адрес на 12 годин до публічного мінтингу. Якщо зберігати whitelist on-chain як mapping(address => bool)—розгортання контракту з 3 000 адрес коштує приблизно 15-20M газу лише на операції SSTORE. При 20 gwei це $300-400 газу лише на setup. Merkle proof вирішує це за одну транзакцію: root хеш у контракті, proof для кожної адреси off-chain. Газ на верифікацію однієї адреси під час мінтингу — близько 3-5k газу замість повного SLOAD з mapping.

Merkle Proof: Як це працює та де люди помиляються

Merkle дерево будується off-chain: кожна адреса хешується через keccak256(abi.encodePacked(address)), дерево будується попарним хешуванням листів. Результат — 32-байтний merkleRoot. Цей root розгортається у контракті. При мінтингу користувач передає proof[] — масив сімейних хешів вздовж шляху від його листка до кореня. Контракт верифікує через MerkleProof.verify() з OpenZeppelin.

Поширена помилка — подвійний мінтинг. Якщо контракт не має mapping(address => bool) public hasMinted (або mapping(address => uint256) public mintedCount), користувач з whitelist може мінтити необмежену кількість разів. Proof залишається дійсним. Контракт не знає, що адреса вже робила мінтинг.

Друга помилка — кодування листа. OpenZeppelin MerkleProof очікує, що лист — це keccak256(keccak256(data)) (подвійний хеш) для захисту від preimage атак у разі збігу вузлів з листями. Якщо генеруєте дерево через merkletreejs з одиничним хешем, але контракт використовує _leaf = keccak256(abi.encodePacked(account)) без подвійного хешу — можлива collision атака при певних конфігураціях. Використовуйте keccak256(bytes.concat(keccak256(abi.encode(addr)))) або стандартну пару: @openzeppelin/merkle-tree JS бібліотека + MerkleProof.sol.

Варіанти реалізації

Merkle Proof (основний)

Підходить для: списків від 100 до мільйонів адрес. Вартість розгортання не залежить від розміру списку. Proof передається користувачем під час мінтингу (frontend генерує автоматично).

Обмеження: не можна додати адресу після розгортання без перебудови дерева та оновлення root. Якщо контракт upgradeable або owner може викликати setMerkleRoot(bytes32) — це вирішується. Якщо immutable — ні.

Підпис від бекенду (ECDSA)

Owner контракту тримає приватний ключ. Для кожної whitelist-адреси бекенд підписує keccak256(abi.encodePacked(address, nonce)). Контракт верифікує підпис через ECDSA.recover() та порівнює з адресою підписувача.

Перевага: динамічне управління — можна додавати адреси без зміни контракту, можна видавати пріоритети, різні квоти. Недолік: централізований signer — єдина точка відмови та довіри. Якщо ключ витекти — будь-хто може заминтити.

Застосування: gaming мінт (бекенд знає досягнення користувача), динамічні кампанії.

On-chain Mapping

Тільки для дуже малих списків (<100 адрес) або коли список відомий заздалегідь і не зміниться. addToWhitelist(address[]) з модифікатором onlyOwner. 20 000 газу на адресу.

Додаткова механіка

Багаторівневий whitelist — різні квоти для різних рівнів. Merkle дерево містить листи keccak256(abi.encode(address, maxMintAmount)). Користувач передає proof + свій maxMintAmount, контракт верифікує обидва параметри разом.

Часові фази — WL → Allowlist → Public. Контракт тримає enum SalePhase { PAUSED, WHITELIST, ALLOWLIST, PUBLIC }. Різні root'и для кожної фази, різні ціни. owner змінює фазу через setPhase().

Batch мінт з WL — користувач може заминтити N NFT в одній транзакції, якщо його квота дозволяє. mintedCount[msg.sender] += amount замість bool флага.

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

Реалізація (1-2 дні). Контракт з Merkle verify + hasMinted mapping + phase management. Тести в Foundry з edge cases: повторний мінт, невалідний proof, вичерпана квота.

Інтеграція з фронтендом (1 день). Генерація proof через @openzeppelin/merkle-tree, wagmi hook useMint().

Розгортання. Foundry скрипт з автоматичною верифікацією Etherscan.

Оцінка часу

Whitelist контракт з Merkle proof — 2-3 дні включаючи тести та інтеграцію з фронтендом.

Вартість розраховується індивідуально.