Разработка NFT-gated контента

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка NFT-gated контента
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы
Направления блокчейн-разработки
Этапы блокчейн-разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1221
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1163
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    855
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1062
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка NFT-gated контента

Типичная ошибка при реализации NFT-gated доступа — проверять ownership только на фронтенде. Пользователь подключает кошелёк, JS делает ownerOf(tokenId), получает адрес, сравнивает с account из кошелька — всё, доступ открыт. Проблема: эту проверку тривиально обойти из DevTools. Весь gating должен происходить на бэкенде, фронтенд только инициирует flow.

Как правильно верифицировать ownership

Схема с подписью сообщения (Sign-In With Ethereum)

Стандарт EIP-4361 (SIWE) — правильный путь. Пользователь подписывает стандартизированное сообщение своим приватным ключом, бэкенд верифицирует подпись и проверяет ownership контракта.

Схема:

  1. Фронтенд запрашивает у бэкенда nonce для адреса (защита от replay-атак)
  2. Формирует SIWE message — стандартный текст с доменом, адресом, nonce, timestamp, expiry
  3. Пользователь подписывает через кошелёк (personal_sign)
  4. Бэкенд верифицирует подпись: восстанавливает адрес из подписи через ecrecover, проверяет nonce, проверяет timestamp, проверяет ownerOf / balanceOf на контракте
// Backend verification (Node.js)
import { SiweMessage } from "siwe"
import { createPublicClient, http } from "viem"

async function verifyNFTAccess(message: string, signature: string, contractAddress: string) {
  const siweMessage = new SiweMessage(message)
  const { success, data } = await siweMessage.verify({ signature })

  if (!success) throw new Error("Invalid signature")
  if (data.nonce !== await getNonce(data.address)) throw new Error("Invalid nonce")
  if (new Date(data.expirationTime!) < new Date()) throw new Error("Expired")

  // Check NFT ownership on-chain
  const client = createPublicClient({ chain: mainnet, transport: http(RPC_URL) })
  const balance = await client.readContract({
    address: contractAddress,
    abi: ERC721_ABI,
    functionName: "balanceOf",
    args: [data.address as `0x${string}`]
  })

  if (balance === 0n) throw new Error("No NFT found")

  // Issue JWT session token
  return issueJWT(data.address)
}

После успешной верификации — JWT токен с коротким TTL (например, 24 часа). Повторная верификация ownership при каждом запросе не нужна — проверяем JWT, а ownership перепроверяем при обновлении токена.

Гранулярный доступ: конкретный токен vs. любой из коллекции

Два режима:

Collection-level gating: любой держатель токена коллекции получает доступ. Проверяем balanceOf(address) > 0. Быстро, дёшево по RPC вызовам.

Token-specific gating: доступ только для держателя конкретного tokenId (например, NFT-тикет на ивент). Проверяем ownerOf(tokenId) == address. Нужно хранить маппинг tokenId → ресурс.

Trait-based gating: доступ только для NFT с определёнными атрибутами (редкие traits, определённый уровень). Здесь нужна либо on-chain запись атрибутов, либо верифицируемый маппинг с IPFS метаданных. Самый сложный вариант — нужно заранее проиндексировать metadata коллекции.

ERC-1155: multi-token gating

ERC-1155 открывает более гибкие модели. balanceOf(address, tokenId) возвращает количество токенов конкретного ID. Можно строить tier-based доступ:

  • tokenId 1 = базовый доступ
  • tokenId 2 = премиум доступ
  • tokenId 3 = VIP доступ

Или: require 10 токенов tokenId 1 для определённого действия (gamification). Логика сложнее, но всё так же верифицируется одним balanceOf вызовом.

Инфраструктура для масштабируемого gating

Кеширование ownership данных

При активной аудитории 10k+ пользователей проверять ownerOf на каждый запрос — это нагрузка на RPC. Решение: кеш с TTL.

User authenticates → check ownership → cache result (TTL: 5 min) → issue JWT (TTL: 24h)
На каждый API запрос: проверяем JWT (локально, быстро)
При refresh JWT: проверяем кеш, если промах — идём к RPC

При transfer NFT кеш устаревает за 5 минут — для большинства сценариев приемлемо. Если нужна немедленная реакция на transfer — подписываемся на Transfer events через WebSocket и инвалидируем кеш.

Мониторинг transfer events для отзыва доступа

Продажа NFT должна немедленно отзывать доступ у продавца — критично для платных сообществ. Подписка на Transfer event через Alchemy/Infura WebSocket:

const filter = {
  address: NFT_CONTRACT,
  topics: [
    ethers.id("Transfer(address,address,uint256)"),
    null,  // from: any
    null   // to: any
  ]
}

provider.on(filter, (log) => {
  const [from, to, tokenId] = parseTransferEvent(log)
  revokeAccess(from)    // invalidate session for previous owner
  grantAccess(to)       // pre-cache for new owner
})

Мультичейн gating

Коллекция может быть на Ethereum, а пользователи хотят платить gas на Polygon — частый кейс для бриджнутых коллекций. Мультичейн gating: проверяем ownership на нескольких чейнах, достаточно одного совпадения.

Библиотека Moralis или Alchemy NFT API упрощают это — single API call с указанием нескольких чейнов:

const nfts = await alchemy.nft.getNftsForOwner(address, {
  contractAddresses: [CONTRACT_ETH, CONTRACT_POLYGON],
})
const hasAccess = nfts.ownedNfts.length > 0

Контентная часть: что и как защищать

Статический контент (PDF, видео, изображения): файлы хранятся в S3/R2 с приватным доступом. Бэкенд генерирует signed URL с коротким TTL (15-60 минут) только для верифицированных держателей. Прямые ссылки на файлы не утекают.

Динамический контент (страницы, API данные): middleware на бэкенде проверяет JWT токен перед каждым ответом. Без валидного JWT — 401.

Стриминговый контент (видео прямые эфиры): аутентификация через токен в query param или заголовке при подключении к стриму. После подключения — периодическая ревалидация каждые N минут.

Сроки разработки

SIWE интеграция с базовым collection-level gating и JWT сессиями — 2 дня. Добавление Transfer event watcher и автоматического отзыва доступа — ещё день. Trait-based gating с индексацией metadata — 1-2 дня в зависимости от размера коллекции. Мультичейн поддержка — ещё 1-2 дня.

Полная система с мониторингом, кешированием и мультичейн верификацией — 4-5 рабочих дней.