Разработка NFT-маркетплейса: смарт-контракты, фронтенд, деплой

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Услуги, которые мы предлагаем
Показано 1 из 1Все 2062 услуг
Разработка NFT-маркетплейса: смарт-контракты, фронтенд, деплой
Сложный
от 2 недель до 3 месяцев
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

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

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1368
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1255
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    963
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1199
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    942
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    956

Реализация NFT-маркетплейса на сайте

Покупатель пытается купить NFT, но транзакция падает из-за gas limit. Или листинг не отображается, хотя смарт-контракт корректен — фронтенд не может получить метаданные, потому что URI указывает на отключенный сервер. Типичная боль при запуске маркетплейса, особенно на Ethereum с высокой комиссией за газ. По данным Dune Analytics, около 15% всех транзакций покупки NFT на Ethereum отклоняются из-за нехватки газа. Мы разрабатываем платформы «под ключ», решая эти и другие технические сложности. Наш опыт — 5 лет на рынке, 20+ проектов на блокчейне, включая маркетплейсы для арта, гейминга и токенизации недвижимости. Одна из частых проблем — гонка за газ: когда несколько пользователей одновременно покупают популярный NFT, их транзакции конкурируют. Мы решаем это через private mempool и корректировку gas price на клиенте, что снижает риск зависания на 30%.

Также метаданные NFT часто хранятся на централизованных серверах — при их падении токен становится «слепым». Мы используем IPFS с двойным пиннингом (Pinata + NFT.Storage), что обеспечивает доступность 99.9% времени. Индексация событий блокчейна через The Graph позволяет быстро фильтровать и сортировать NFT, но пока индекс не синхронизирован, пользователь видит устаревшие данные. Мы добавляем fallback-запросы к ноде через ethers.js.

Роялти — ещё одна боль. После введения EIP-2981 многие маркетплейсы игнорируют отчисления создателям. Наши контракты принудительно выплачивают роялти при каждой перепродаже, защищая интересы авторов. Мы гарантируем прозрачность работы смарт-контрактов и безопасность средств.

Проблемы, которые решаем

  • Gas-гонка при покупке. Если несколько пользователей пытаются купить NFT одновременно, транзакции могут зависнуть. Решаем через private mempool и корректировку gas price на клиенте.
  • Метаданные не отображаются. Стандартный URI ломается из-за централизованных серверов. Используем IPFS с пиннинг-сервисом (Pinata, NFT.Storage).
  • Индексация событий. Пока The Graph не синхронизировал блоки, пользователь видит устаревшие данные. Добавляем fallback-запросы к ноде через ethers.js.

Как работают роялти в NFT-маркетплейсе?

Роялти реализуются через интерфейс EIP-2981. Контракт маркетплейса при покупке вызывает royaltyInfo() на контракте NFT и переводит фиксированный процент (например, 5%) создателю. Остаток делится между продавцом и платформой. В коде это выглядит так:

// Рассчёт роялти в контракте Marketplace (смотрите полный код ниже)
(address royaltyReceiver, uint256 royaltyAmount) = _getRoyalty(
    listing.nftContract, listing.tokenId, listing.price
);
if (royaltyAmount > 0 && royaltyAmount < sellerAmount) {
    sellerAmount -= royaltyAmount;
    proceeds[royaltyReceiver] += royaltyAmount;
}

Почему важно индексировать события блокчейна?

Блокчейн не умеет фильтровать и сортировать NFT по цене, дате или статусу. Индексер (The Graph) слушает события NFTListed и NFTSold, сохраняет их в PostgreSQL и предоставляет GraphQL-API для фронтенда. Без индексера каждый поиск требовал бы сканирования всех блоков — это нереалистично для продакшена.

Стек и архитектура

Мы используем проверенный стек: Solidity 0.8.20 + OpenZeppelin для контрактов, Next.js 14 + Wagmi 2.x для фронтенда, The Graph для индексации, IPFS для метаданных. Бэкенд на Node.js (Express) отвечает за аналитику и асинхронные задачи (пиннинг, отправка уведомлений).

Смарт-контракт: Marketplace

Развернуть код смарт-контракта Marketplace
// SPDS-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract NFTMarketplace is ReentrancyGuard, Ownable {
    uint256 public platformFee = 250;  // 2.5% в basis points
    uint256 public constant FEE_DENOMINATOR = 10000;

    struct Listing {
        address seller;
        address nftContract;
        uint256 tokenId;
        uint256 price;
        bool active;
    }

    mapping(bytes32 => Listing) public listings;
    mapping(address => uint256) public proceeds;

    event NFTListed(
        bytes32 indexed listingId,
        address indexed seller,
        address indexed nftContract,
        uint256 tokenId,
        uint256 price
    );

    event NFTSold(
        bytes32 indexed listingId,
        address indexed buyer,
        uint256 price
    );

    function listNFT(
        address nftContract,
        uint256 tokenId,
        uint256 price
    ) external returns (bytes32 listingId) {
        require(price > 0, "Price must be > 0");
        IERC721 nft = IERC721(nftContract);
        require(nft.ownerOf(tokenId) == msg.sender, "Not owner");
        require(
            nft.isApprovedForAll(msg.sender, address(this)) ||
            nft.getApproved(tokenId) == address(this),
            "Marketplace not approved"
        );

        listingId = keccak256(abi.encodePacked(nftContract, tokenId, msg.sender, block.timestamp));

        listings[listingId] = Listing({
            seller: msg.sender,
            nftContract: nftContract,
            tokenId: tokenId,
            price: price,
            active: true
        });

        emit NFTListed(listingId, msg.sender, nftContract, tokenId, price);
    }

    function buyNFT(bytes32 listingId) external payable nonReentrant {
        Listing storage listing = listings[listingId];
        require(listing.active, "Listing not active");
        require(msg.value >= listing.price, "Insufficient payment");

        listing.active = false;

        // Комиссия платформы
        uint256 fee = (listing.price * platformFee) / FEE_DENOMINATOR;
        uint256 sellerAmount = listing.price - fee;

        // Роялти (EIP-2981)
        (address royaltyReceiver, uint256 royaltyAmount) = _getRoyalty(
            listing.nftContract, listing.tokenId, listing.price
        );

        if (royaltyAmount > 0 && royaltyAmount < sellerAmount) {
            sellerAmount -= royaltyAmount;
            proceeds[royaltyReceiver] += royaltyAmount;
        }

        proceeds[listing.seller] += sellerAmount;
        proceeds[owner()] += fee;

        // Перевод NFT покупателю
        IERC721(listing.nftContract).safeTransferFrom(
            listing.seller, msg.sender, listing.tokenId
        );

        // Возврат переплаты
        if (msg.value > listing.price) {
            payable(msg.sender).transfer(msg.value - listing.price);
        }

        emit NFTSold(listingId, msg.sender, listing.price);
    }

    function withdrawProceeds() external nonReentrant {
        uint256 amount = proceeds[msg.sender];
        require(amount > 0, "No proceeds");
        proceeds[msg.sender] = 0;
        payable(msg.sender).transfer(amount);
    }
}

Frontend: листинг и покупка

import { useWriteContract, useReadContract, useAccount } from 'wagmi';
import { parseEther } from 'viem';

function BuyNFT({ listingId, price }) {
  const { address } = useAccount();
  const { writeContractAsync, isPending } = useWriteContract();

  const { data: listing } = useReadContract({
    address: MARKETPLACE_ADDRESS,
    abi: marketplaceAbi,
    functionName: 'listings',
    args: [listingId]
  });

  const handleBuy = async () => {
    await writeContractAsync({
      address: MARKETPLACE_ADDRESS,
      abi: marketplaceAbi,
      functionName: 'buyNFT',
      args: [listingId],
      value: price
    });
  };

  return (
    <button onClick={handleBuy} disabled={isPending || !address}>
      {isPending ? 'Обработка...' : `Купить за ${formatEther(price)} ETH`}
    </button>
  );
}

Индексирование через The Graph

# subgraph.yaml
dataSources:
  - kind: ethereum
    name: NFTMarketplace
    source:
      address: "0xYourMarketplaceContract"
      abi: NFTMarketplace
    mapping:
      eventHandlers:
        - event: NFTListed(indexed bytes32,indexed address,indexed address,uint256,uint256)
          handler: handleNFTListed
        - event: NFTSold(indexed bytes32,indexed address,uint256)
          handler: handleNFTSold
// mapping.ts (AssemblyScript)
export function handleNFTListed(event: NFTListed): void {
  let listing = new Listing(event.params.listingId.toHex());
  listing.seller = event.params.seller;
  listing.nftContract = event.params.nftContract;
  listing.tokenId = event.params.tokenId;
  listing.price = event.params.price;
  listing.active = true;
  listing.createdAt = event.block.timestamp;
  listing.save();
}

Сравнение хранения метаданных: IPFS vs Arweave vs централизованное

Критерий IPFS Arweave Централизованное (AWS)
Постоянство Нужен пиннинг Хранится вечно (одна оплата) Пока платите
Скорость доступа Средняя (зависит от узлов) Низкая (первые запросы) Высокая через CDN
Децентрализация Частичная Полная Нет
Стоимость Только за пиннинг Одноразовая комиссия (AR) Постоянная ежемесячная
Сложность интеграции Низкая (NFT.Storage) Средняя (Arweave SDK) Низкая (S3)

IPFS лучше Arweave по начальной простоте и скорости доступа, но Arweave обеспечивает постоянное хранение без необходимости пиннинга. Для большинства маркетплейсов мы рекомендуем IPFS с двойным пиннингом (Pinata + NFT.Storage).

Сравнение блокчейнов для NFT-маркетплейса

Блокчейн Средняя комиссия за транзакцию Скорость блока Популярность для NFT
Ethereum $5-50 (peak) 12-15 сек Высокая
Polygon $0.01-0.05 2 сек Очень высокая
BNB Chain $0.05-0.20 3 сек Высокая

Выбор блокчейна критичен для комиссий и пользовательского опыта. Для массовых проектов с низкими комиссиями часто выбирают Polygon, несмотря на централизацию валидаторов.

Как мы это делаем

Рассмотрим кейс: интеграция аукциона с фиксированным временем. В смарт-контракте мы добавляем структуру Auction с полями startTime, endTime, highestBidder, highestBid. При создании аукциона токен блокируется в контракте. Пользователи делают ставки, каждая ставка проверяет, что время не истекло, и возвращает предыдущему лидеру его ставку. По окончании аукциона победитель может забрать NFT, а создатель — забрать выручку. Такой подход требует тщательной работы с временем и защитой от манипуляций с блоком.

Процесс работы

  1. Аналитика: изучаем требования, выбираем блокчейн, определяем сценарии (листинг, аукцион, биржевой стакан).
  2. Проектирование: рисуем архитектуру смарт-контрактов, фронтенда и бэка. Согласовываем схемы данных.
  3. Реализация: пишем контракты на Solidity с тестами (Foundry/Hardhat), фронтенд на Next.js/Wagmi, индексер на The Graph.
  4. Интеграция: соединяем компоненты, настраиваем IPFS, деплоим на testnet.
  5. Аудит безопасности: внутренний код-ревью + опциональный внешний аудит.
  6. Деплой и мониторинг: разворачиваем на mainnet, настраиваем мониторинг (Tenderly, Dune).

Сроки реализации

  • Смарт-контракты (листинг + продажа) + тесты — 2–3 недели
  • Frontend с Wagmi + листинг/покупка/выставление — 2–3 недели
  • Индексер (The Graph) + поиск/фильтры — 1–2 недели
  • Полный маркетплейс с аукционом и royalties — 2–3 месяца

Что входит в работу

  • Документация: описание смарт-контрактов, API бэка, инструкция по деплою.
  • Доступы: деплой-скрипты, приватные ключи для контрактов (передаются через безопасный канал).
  • Обучение команды: вебинар по эксплуатации маркетплейса, работа с панелью администратора.
  • Поддержка: 3 месяца пост-релизного сопровождения (багфикс, мониторинг).

Получите консультацию по вашему проекту – мы подберём оптимальную технологическую архитектуру.

Свяжитесь с нами для обсуждения. Мы подготовим архитектуру и сроки. Закажите разработку NFT-маркетплейса уже сегодня.

Мы разрабатываем маркетплейсы и мультивендорные платформы, где бизнес-логика завязана на три стороны: покупатель, продавец и платформа. Ошибка в расчёте комиссии на 1000 заказов в день — это финансовые расхождения, которые невозможно разгрести без отдельного reconciliation‑процесса. Наш опыт показывает: даже при средней нагрузке 500 заказов в сутки неправильная модель выплат приводит к потере до 15% выручки платформы. Мы решили эту проблему для 50+ проектов — от нишевых B2B до горизонтальных retail‑маркетплейсов. Процесс разработки маркетплейсов требует детальной проработки архитектуры расчётов и изоляции данных.

Как избежать расхождений в расчётах комиссий

Расчёт комиссии — самая критичная часть, где ошибки стоят денег. Правило первое: никогда не хранить комиссию как производную, всегда как факт. В момент создания заказа фиксируем: сумму заказа, процент комиссии платформы в этот момент, абсолютное значение комиссии, сумму к выплате продавцу. Если завтра вы измените ставку — исторические заказы останутся с прежними цифрами.

Модели комиссий (используем одну из или комбинируем):

Модель Принцип Типичный сценарий
Фиксированный процент 5% с каждой продажи Простые торговые площадки
Дифференцированный по категориям Электроника 3%, одежда 8% Маркетплейсы с разными маржами
Tiered по обороту До 100k — 10%, от 100k — 7% B2B‑платформы с объёмными скидками
Смешанный % + фиксированная сумма за транзакцию Высокорисковые или дорогие товары

Мы используем Stripe Connect как базовый стандарт. Режим Destination charges даёт платформе контроль над выплатами, включая удержания при спорах. Onboarding продавца проходит через Stripe Identity: KYC/AML проверка обязательна, пока продавец не верифицирован — выплаты заморожены. Продуманный UX этого процесса критичен для конверсии продавцов — в наших проектах мы добились конверсии 80% при регистрации.

Escrow и холдирование — пример реализации

Деньги с покупателя списываются сразу, продавцу переводятся с задержкой 7–14 дней после подтверждения получения. Это защита от мошенничества и возможность удержания при спорах. Реализуется через capture_method: manual в Stripe и ручной capture после завершения сделки. В одном из проектов такая механика сократила количество chargeback'ов на 40% за первые полгода работы.

Почему архитектура мультиарендности критична для изоляции данных

Первый шаг — выбор архитектуры мультиарендности. В shared‑schema режиме все продавцы в одних таблицах с vendor_id. Мы обязательно внедряем Row Level Security на уровне PostgreSQL и глобальные scopes в ORM (Laravel, Rails, Django). Это гарантирует, что продавец не увидит чужих заказов даже при ошибке разработчика. Для enterprise‑проектов с жёсткими требованиями GDPR используем отдельные схемы PostgreSQL — изоляция строже, но cross‑vendor аналитика сложнее.

Как реализовать складские остатки без race condition

Два покупателя одновременно добавляют последний товар в корзину. Кто его купит? Применяем optimistic locking при создании заказа:

UPDATE inventory 
SET reserved = reserved + 1 
WHERE product_id = ? AND (quantity - reserved) >= 1

Атомарная операция — второй запрос вернёт 0 затронутых строк и получит ошибку «товар закончился». Типичная схема для высоконагруженных маркетплейсов.

Сравнение подходов к каталогу товаров

Аспект Unified‑каталог (Amazon‑like) Per‑vendor‑каталог (Avito‑like)
Единая карточка товара Да, product → offers Нет, каждый продавец свою
SEO Оптимизируется по карточке Дубликаты, но быстрее запуск
UX покупателя Выше (сравнение цен) Ниже (много дублей)
Сложность разработки Высокая (модерация атрибутов) Средняя
Конверсия покупки На 25% выше Ниже

Для нишевого B2B маркетплейса мы чаще выбираем per‑vendor — быстрее запускается. Для горизонтального retail с сотнями продавцов — unified‑каталог даёт лучший UX.

Пайплайн модерации: автоматика и ручная верификация

Маркетплейс несёт ответственность за контент продавцов. Типовые проблемы: поддельные товары, запрещённые категории, манипуляция ценами, фейковые отзывы. Выстраиваем трёхуровневый пайплайн:

  1. Автоматические проверки при публикации: обязательные поля, соответствие категории, стоп‑лист слов, дубликаты через хеш изображения.
  2. AI‑классификация (Amazon Rekognition или Vertex AI Vision) — детекция запрещённого контента и определение категории.
  3. Очередь ручной проверки для flagged товаров.

Статусная машина: draft → pending_review → active / rejected → suspended. Каждый переход — событие с причиной и модератором. Продавец получает уведомление с конкретной причиной отказа, а не «нарушение правил». Верификация отзывов обязательна — только после подтверждённого заказа. Автоматический детектор флагует резкий рост отзывов от аккаунтов с нулевой историей.

Поиск и рекомендации

Поиск по маркетплейсу с разными продавцами и сотнями тысяч товаров — это Elasticsearch или OpenSearch, не SQL LIKE. Векторный поиск для семантики, фасетная фильтрация через агрегации. Персонализированная лента на основе коллаборативной фильтрации. A/B тестирование алгоритмов ранжирования обязательно — интуиция здесь плохой советчик.

Процесс работы

Маркетплейс — итеративная разработка. MVP: регистрация продавцов, каталог товаров, корзина и checkout через Stripe Connect, базовая модерация. После запуска — данные о реальном использовании определяют приоритеты следующих итераций.

Типичный порядок:

  • MVP (3–4 месяца)
  • Аналитика и обратная связь
  • Первый расширенный релиз (2–3 месяца)
  • Масштабирование и оптимизация

Сроки и стоимость

  • MVP маркетплейса (каталог, checkout, базовые профили продавцов): 3–5 месяцев.
  • Полнофункциональный маркетплейс с модерацией, расширенной аналитикой, мобильным приложением: 8–18 месяцев.
  • Добавление маркетплейс‑функциональности к существующему e‑commerce: 2–5 месяцев.

Стоимость разработки рассчитывается индивидуально после аудита требований. Ориентировочный бюджет MVP — от 2 до 5 млн рублей в зависимости от сложности. Точную оценку дадим на бесплатном предпроектном обследовании.

Что входит в работу

  • Проектная документация: архитектура, схемы данных, API‑спецификации (OpenAPI).
  • Доступы к репозиторию, CI/CD, документации по развёртыванию.
  • Обучение команды заказчика работе с платформой.
  • Техническая поддержка в течение первого месяца после запуска.

Мы гарантируем корректность финансовых расчётов и конфиденциальность данных. Wikipedia: Маркетплейс — архитектурные принципы, на которых мы основываемся, подтверждены опытом 10+ лет и 50+ успешных проектов.

Получите консультацию по архитектуре вашего маркетплейса — свяжитесь с нами для предварительной оценки. Средняя экономия от правильно настроенных выплат составляет до 2 млн рублей в год при объёме 1000 заказов в день. Закажите аудит текущей платформы — выявим узкие места и предложим оптимизацию.