Разработка 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, 2023
Ориентиры по срокам
MVP маркетплейс с fixed-price листингами на базе Seaport — 3-4 недели. Полноценная платформа с аукционами, offers, royalty enforcement и subgraph — 2-3 месяца.
Стоимость рассчитывается после анализа требований.
С нашей командой, имеющей 5+ лет опыта в блокчейн-разработке и 15+ реализованных проектов, вы получаете гарантию качества и безопасность контрактов. Получите консультацию по вашему проекту — свяжитесь с нами. Закажите разработку — мы оценим ваш проект и предложим оптимальное решение.







