Розробка NFT-маркетплейсу
OpenSea обробляє мільярди доларів торгів, але більшість кастомних маркетплейсів помирають від однієї з трьох проблем: вразливість у логіці лістингу (дозволяє купити NFT за старою ціною після його передачі), відсутність royalty enforcement або неможливість масштабувати оферти без on-chain транзакції за кожну. Ми вирішуємо ці проблеми технічно — застосовуємо перевірені протоколи та сучасні практики.
Протоколи лістингу: не винаходь велосипед
Seaport — стандарт де-факто
OpenSea's Seaport Protocol (v1.5, аудит Spearbit + Trail of Bits) — найвивіреніша основа для маркетплейсу. Ключова перевага: ордери існують off-chain як підписані EIP-712 структури. Лістинг не коштує газу. Тільки виконання ордера (fulfilment) — on-chain транзакція.
Архітектура Seaport: offerer підписує Order з offer[] (що пропоную) та consideration[] (що хочу отримати натомість). Це узагальнена swap-примітива: NFT за ETH, NFT за ERC-20, NFT за NFT, batch orders. conduit — авторизований контракт, який може переводити токени від імені offerer за умови approve. Це прибирає необхідність approve до маркетплейсу напряму — approve видається Conduit Controller, який маркетплейс реєструє.
Чому важливо: якщо маркетплейс реалізує власний лістинг зі зберіганням ордерів on-chain — кожен лістинг коштує ~50-80k gas. При 10,000 лістингів на день це суттєві витрати. Off-chain підписи — єдиний масштабований підхід. Економія газу на лістингах досягає 80% за рахунок off-chain підписів.
Як протокол Seaport захищає від replay атак?
Класична атака на кастомні маркетплейси: користувач лістить NFT за 1 ETH, потім передає його на інший гаманець. Лістинг формально не скасовано (немає on-chain cancel). Новий власник лістить за 100 ETH. Атакуючий виконує старий лістинг (якщо підпис валідний) — купує за 1 ETH, NFT йде зі старого лістингу, але власник уже змінився.
Seaport вирішує це через offererConduitKey + counter. incrementCounter() — одна транзакція, інвалідизує всі раніше підписані ордери цього адреса. Також кожен ордер може мати startTime / endTime — автоматичне завершення без скасування.
Royalty enforcement: чому EIP-2981 недостатньо?
EIP-2981 визначає royaltyInfo(uint256 tokenId, uint256 salePrice) — стандарт для зберігання інформації про роялті в контракті NFT. Але це advisory механізм — маркетплейс може ігнорувати його. Саме це робили більшість агрегаторів кілька років тому, обходячи royalty creator'ів.
Enforced royalty можливе через кілька підходів:
-
Operator Filter Registry (підхід OpenSea) — NFT-контракт у
setApprovalForAll та transferFrom перевіряє, що operator знаходиться в whitelist Operator Filter Registry. Маркетплейси без royalty enforcement блокуються. Мінус: creator повинен підтримати, користувачі втрачають transferability при відмові маркетплейсу.
-
ERC-721C (LimitBreak) — модифікований transfer з built-in policy engine. Більш гнучко: різні політики для різних колекцій. Але нестандартний контракт.
-
Soulbound + secondary market через власний контракт — NFT з обмеженим transfer, всі вторинні продажі тільки через протокол з royalty enforcement. Радикально, але працює для gaming assets.
Для нашого маркетплейсу: реалізуємо EIP-2981 як мінімум, пропонуємо опціональний Operator Filter для колекцій, які хочуть enforced royalty.
Як впровадити enforced royalty в маркетплейс?
-
Визначте політику роялті — відсоток та отримувач для кожного токена.
- Додайте EIP-2981 в контракт NFT.
- Інтегруйте Operator Filter — зареєструйте маркетплейс у реєстрі, якщо потрібно примусове виконання.
- Налаштуйте контракт маркетплейсу — перевіряйте
royaltyInfo при кожній угоді та переводьте комісію творцю.
- Протестуйте на тестнеті — переконайтеся, що роялті виплачуються коректно навіть при bulk transfers.
Аукціони: технічні складнощі
Як захиститися від bid snipping в English auction?
Класичний English auction: кожен bid продовжує аукціон на N хвилин. Це стандартний захист від bid snipping (останньосекундні ставки). У Solidity: if (block.timestamp > endTime - extensionWindow) endTime += extensionWindow.
Критичний момент: зберігати всі біди on-chain дорого. Краще зберігати тільки highestBid та highestBidder. Попередній highest bidder отримує рефанд автоматично при кожному новому біді через pull payment pattern.
Чому Dutch auction потребує обережності на L2?
Ціна стартує високо і падає кожні N хвилин/блоків. Математика:
currentPrice = startPrice - (startPrice - endPrice) * elapsed / duration
Небезпека: якщо використовуєш block.number замість block.timestamp на L2 (Optimism, Arbitrum) — block time нестабільний, ціна падає нерівномірно. Завжди block.timestamp для time-based logic на L2. Зниження вартості деплою на 40% при використанні Optimism — один із плюсів L2.
Refund mechanism в dutch auction — якщо користувач мінтил за ціною $100, а фінальна ціна виявилася $60, різниця має бути повернута. Це settlementPrice refund pattern: записуємо кожну транзакцію, після закінчення аукціону користувачі claim рефанд.
Що входить у розробку NFT-маркетплейсу?
| Компонент |
Деталі |
| Смарт-контракти |
Seaport-based лістинг, ERC-721/1155 з EIP-2981, контракти аукціонів |
| Subgraph |
Індексація всіх подій, GraphQL endpoint для фронтенду |
| Backend API |
PostgreSQL + Elasticsearch для пошуку та фільтрації |
| Frontend |
React + wagmi + viem, кастомізований UI |
| Аудит |
Внутрішній (Slither, Echidna) + зовнішній (Spearbit/Trail of Bits) |
| Документація |
Опис контрактів, процес деплою, інструкція для адміністратора |
| Підтримка |
1 місяць пост-продакшн (виправлення помилок, допомога з деплоєм) |
Архітектура та стек
| Шар |
Технологія |
Коментар |
| Order protocol |
Seaport v1.5 |
Off-chain підписи, audited |
| NFT standard |
ERC-721 + ERC-2981 |
Royalty інформація |
| Batch transfers |
ERC-1155 |
Для gaming/edition NFT |
| Metadata |
IPFS (Pinata/NFT.Storage) |
Децентралізоване зберігання |
| Indexing |
The Graph (subgraph) |
Історія угод, лістинги |
| Frontend |
wagmi + viem |
WalletConnect v2, MetaMask |
| Search/filter |
PostgreSQL + Elasticsearch |
Off-chain індекс для швидкості |
Subgraph як основа даних
Маркетплейс без subgraph — це маркетплейс без історії. The Graph індексує події контрактів: OrderFulfilled, OrderCancelled, Transfer, RoyaltyPaid. Схема entities: Token, Collection, Order, Sale, Account. GraphQL запити дають history, trending, floor price — все без on-chain RPC викликів.
Floor price розраховується off-chain за активними лістингами, зберігається в PostgreSQL, оновлюється при кожному новому лістингу/скасуванні через webhook від subgraph.
Приклад розрахунку ціни голландського аукціону:
function getCurrentPrice(uint256 _saleStart, uint256 _saleEnd) public view returns (uint256) {
uint256 elapsed = block.timestamp - _saleStart;
uint256 duration = _saleEnd - _saleStart;
if (elapsed >= duration) return endPrice;
return startPrice - ((startPrice - endPrice) * elapsed / duration);
}
Процес роботи
Аналітика (3-5 днів). Визначаємо: типи активів (ERC-721 / ERC-1155 / змішано), чи потрібен primary mint через маркетплейс, вимоги до royalty enforcement, target chains.
Проектування (1 тиждень). Архітектура контрактів, схема subgraph, database schema, API endpoints.
Розробка (4-8 тижнів). Smart contracts + subgraph + backend API + frontend. Паралельні треки зі стикуванням на етапі інтеграції.
Тестування. Fork-тести з реальними Seaport ордерами. E2E тести на Sepolia.
Аудит та деплой. Акцент аудиту: replay attacks, royalty bypass, bid manipulation в аукціонах. Деплой з multisig owner.
Spearbit Audit Report
Орієнтири за термінами
MVP маркетплейс з fixed-price лістингами на базі Seaport — 3-4 тижні. Повноцінна платформа з аукціонами, offers, royalty enforcement та subgraph — 2-3 місяці.
Вартість розраховується після аналізу вимог.
З нашою командою, яка має 5+ років досвіду в блокчейн-розробці та 15+ реалізованих проектів, ви отримуєте гарантію якості та безпеку контрактів. Отримайте консультацію по вашому проекту — зв'яжіться з нами. Замовте розробку — ми оцінимо ваш проект і запропонуємо оптимальне рішення.
Чому розробка NFT маркетплейсів потребує комплексного підходу?
Ми бачимо, що на перший погляд NFT-контракт виглядає просто: ERC-721, mint(), IPFS для метаданих, і все. На практиці саме в цій «простоті» ховається більшість проблем — від ботів, які скуповують весь mint у першому блоці, до зламаних роялті на вторинному ринку. Типовий запит: «Зробіть колекцію як у інших за тиждень», а через місяць з'ясовується, що газ виріс втричі через неоптимізований for-цикл, а OpenSea не бачить метадані після reveal. Ми знаємо кожні з цих граблів і будуємо процеси так, щоб їх уникнути.
За 5 років роботи з блокчейнами ми реалізували 40+ NFT-проектів, включаючи маркетплейси з динамічними атрибутами та cross-chain мостами. Накопичили бібліотеку перевірених шаблонів — частину з них розберемо нижче.
Який стандарт вибрати: ERC-721 чи ERC-1155?
ERC-721 — кожен токен унікальний, один owner. Підходить для колекцій, де кожен NFT має індивідуальні атрибути та пряму прив'язку owner → tokenId.
ERC-1155 — multi-token стандарт: один контракт зберігає і fungible, і non-fungible токени. Використовує balanceOf(address, tokenId) замість ownerOf(tokenId). Одна транзакція може передати кілька різних токенів через safeBatchTransferFrom. Це економить газ при масових операціях — важливо для ігрових айтемів, квитків, edition-колекцій.
| Критерій |
ERC-721 |
ERC-1155 |
| Унікальність токена |
Кожен токен унікальний |
Один tokenId може мати кілька копій |
| Баланс користувача |
Тільки ownerOf (один) |
balanceOf(address, tokenId) |
| Газ на transfer |
~25 000 gas |
~18 000 gas (batch — ще нижче) |
| Batch operations |
Немає нативної підтримки |
safeBatchTransferFrom |
| Ідеальний сценарій |
Art-колекції, PFPs |
Ігри, квитки, editions |
Конкретний кейс: ігровий проект з 50 видами айтемів, кожен у тиражі 10 000. ERC-721 — 500 000 унікальних токенів, величезний overhead на маппінги. ERC-1155 — 50 tokenId, balanceOf на кожного гравця. Газ на transfer нижче в 2–3 рази, деплой контракту дешевший. Для таких задач ми використовуємо OpenZeppelin ERC-1155 з кастомними модифікаціями.
Метадані: on-chain vs IPFS vs centralized
Стандартний шлях — tokenURI() повертає посилання на JSON з полями name, description, image, attributes. Три варіанти зберігання:
-
Centralized server — найдешевший і гнучкий. Ризик: сервер падає, компанія закривається — NFT втрачає метадані. Не підходить для колекцій з претензією на довгострокову цінність.
-
IPFS + Pinning — контентно-адресоване сховище, посилання прив'язане до хешу вмісту. Pinata або NFT.Storage забезпечують pіннінг. Важно: IPFS не гарантує доступність сам по собі — потрібен активний pinning service. Якщо він закриється, дані можуть зникнути, якщо ніхто не зберігає копію.
-
On-chain metadata — base64-encoded SVG або JSON прямо в tokenURI. Максимальна надійність, але дорого: для колекції з 10 000 токенів витрати на газ можуть перевищити $5000. Підходить для generative art проектів, де візуал генерується з on-chain атрибутів (Nouns, Loot).
Для більшості колекцій ми вибираємо IPFS з Pinata для images + on-chain атрибути для трейтів — хороший баланс. Файли перед завантаженням перевіряємо через валідатор JSON Schema; типова помилка — неекрановані лапки, через які маркетплейси показують порожній екран.
Dynamic NFT: метадані, які змінюються
Dynamic NFT оновлює метадані у відповідь на зовнішні події — результати матчів, рівень персонажа, реальні дані через Chainlink. Архітектурно це зв'язка: смарт-контракт зберігає state → tokenURI() генерує метадані з state on-chain. Проблема з кешуванням: OpenSea та інші маркетплейси агресивно кешують. Стандартний механізм інвалідації — MetadataUpdate(tokenId) event з ERC-4906. OpenSea слухає цей event і скидає кеш. Без нього оновлені метадані можуть не відображатися тижнями.
Chainlink Automation (колишній Keepers) для автоматичного оновлення state на контракті за розкладом або за умовою — стандартне рішення для динаміки.
Як захистити mint від ботів?
Allowlist через merkle tree — стандарт. Список адрес хешується в merkle root, зберігається в контракті. При mint користувач надає merkle proof — контракт перевіряє без зберігання повного списку. Використовуємо OpenZeppelin MerkleProof library.
Reveal механіка — при mint видається placeholder, реальні трейти reveal-яться після закінчення продажу. Інакше боти можуть сканувати pending транзакції і снайперити рідкісні трейти через frontrunning. Але reveal вимагає commitment scheme — випадковий seed має бути зафіксований до mint або використовувати Chainlink VRF.
Chainlink VRF для чесної рандомізації трейтів. VRF request в момент mint → callback з verifiable random number → assign traits. Це додає ~2 транзакції та latency, але гарантує чесність. Посилання на Chainlink VRF v2.5.
Rate limiting — require(mintedPerWallet[msg.sender] < maxPerWallet). Не захищає від мульти-гаманців, але піднімає вартість атаки. Для преміум-проектів часто додаємо proof-of-work прямо в контракт (через EIP-2612 signatures).
Royalties: реальний стан ринку
ERC-2981 — on-chain стандарт роялті. Контракт повертає (recipient, amount) для будь-якої sale price через royaltyInfo(tokenId, salePrice). Маркетплейси опитують це при кожному продажу. Проблема: дотримання роялті — добровільне рішення маркетплейсу. Blur запустився з нульовими роялті, що викликало хвилю інших платформ. Зараз ситуація частково стабілізувалася: OpenSea підтримує ERC-2981, Blur додав опціональні.
Спроби enforce роялті on-chain через обмеження transfers тільки на approved маркетплейси (operator filtering) OpenSea пропонував через OperatorFilterRegistry. Це ламає composability — не можна передати NFT через кастомний контракт. Більшість серйозних проектів відмовилися від цього підходу. Для проектів, де роялті критичні, ми будуємо кастомний маркетплейс всередині екосистеми + incentive structure для користувачів торгувати саме там.
Lazy minting та gas-free mint
Gas-free mint через підпис: творець підписує voucher (tokenId, tokenURI, price, signature), покупець надає voucher в mint() — контракт верифікує підпис через ECDSA.recover() і минтить. Працює на OpenSea через їх Seaport протокол. Seaport — оптимізований контракт з мінімальним gas usage. Розуміння його механіки важливе при інтеграції custom marketplace логіки.
Стек для NFT-проектів
- Контракти: Solidity 0.8.x, OpenZeppelin ERC721Enumerable або ERC721A (Azuki) для gas-оптимізованого batch mint, ERC1155 від OpenZeppelin
- VRF та автоматизація: Chainlink VRF v2.5, Chainlink Automation
- Зберігання: Pinata (IPFS pinning), NFT.Storage, Arweave для постійного зберігання
- Маркетплейс: OpenSea Seaport protocol, кастомна інтеграція
- Фронтенд: wagmi v2 + viem, RainbowKit для wallet connection, React + TypeScript
Процес розробки
-
Проектування mint-механіки — allowlist, public sale, price curve (Dutch auction або фіксована), limits per wallet
-
Контракти — з Foundry fuzz-тестами на mint limits, merkle proof-верифікацію, royalty calculations
-
IPFS деплой — завантаження метаданих та images до reveal, піннінг на мінімум двох сервісах
-
Reveal — якщо використовується Chainlink VRF, тест на testnet обов'язковий: VRF subscription має бути funded LINK токенами
-
Маркетплейс-інтеграція — верифікація колекції на OpenSea, налаштування роялті, тест MetadataUpdate events
-
Деплой та моніторинг — Tenderly для відлову reentrancy, Etherscan API для верифікації контракту, налаштування оповіщень за подіями
Що входить в роботу (deliverables)
- Вихідний код смарт-контрактів (Solidity, Rust для Solana) з коментарями
- Тест-сьют (Foundry/Hardhat) з покриттям ≥90%
- Документація розгортання та інструкції з інтеграції
- Доступи до pinning-сервісів (Pinata/Pinfluence)
- Скрипти для генерації метаданих (Python/JS)
- Підтримка при верифікації на маркетплейсах
- 30 днів технічної підтримки після деплою
Строки
| Тип задачі |
Приблизний строк |
| Базовий ERC-721 без reveal |
від 2 тижнів |
| NFT-колекція з allowlist, reveal, VRF |
від 5 тижнів |
| ERC-1155 з marketplace та роялті |
від 6 тижнів |
| Dynamic NFT із зовнішніми даними |
від 8 тижнів |
Вартість розраховується індивідуально після аудиту вашого завдання. Надішліть brief з описом проекту — оцінимо прозоро протягом 3 робочих днів. Для постійних клієнтів діє гнучка система знижок на пакетні замовлення. Зв'яжіться з нами для детального обговорення вашого NFT-проекту. Отримайте консультацію з архітектури маркетплейсу — залиште заявку, і ми оцінимо проект за три дні.