Розробка 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
// SPDX-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% in 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, а творець — забрати виручку. Такий підхід вимагає ретельної роботи з часом та захистом від маніпуляцій з блоком. На одному з проектів ми впровадили цей механізм для маркетплейсу цифрового мистецтва, що дозволило збільшити середню ціну продажу на 40%.

Процес роботи

  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 тижні.
  • Повний маркетплейс з аукціоном та роялті — 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 чи per-vendor?

Порівняння підходів до каталогу товарів:

Аспект 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 місяців.

Вартість розробки розраховується індивідуально після аудиту вимог. Точну оцінку надамо на безкоштовному передпроектному обстеженні.

Що входить в роботу

  • Проектна документація: архітектура, схеми даних, API-специфікації (OpenAPI).
  • Доступи до репозиторію, CI/CD, документації з розгортання.
  • Навчання команди замовника роботі з платформою.
  • Технічна підтримка протягом першого місяця після запуску.

Ми гарантуємо коректність фінансових розрахунків та конфіденційність даних. Архітектурні принципи, на яких ми ґрунтуємося, підтверджені досвідом 10+ років та 50+ успішних проектів. Зв'яжіться з нами для попередньої оцінки вашого маркетплейсу — отримайте консультацію з архітектури та розрахунку виплат. Замовте аудит поточної платформи — виявимо вузькі місця та запропонуємо оптимізацію.