Разработка Discord-бота раздачи ролей по NFT

Проектируем и разрабатываем блокчейн-решения полного цикла: от архитектуры смарт-контрактов до запуска DeFi-протоколов, NFT-маркетплейсов и криптобирж. Аудит безопасности, токеномика, интеграция с существующей инфраструктурой.
Показано 1 из 1 услугВсе 1306 услуг
Разработка Discord-бота раздачи ролей по NFT
Средняя
~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
    1058
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    828

Разработка Discord-бота раздачи ролей по NFT

Token gating — стандартная практика для NFT-сообществ. Держишь NFT из коллекции — получаешь доступ к приватным каналам, early access, приватным drop-ам. Технически это верификация: кошелёк с нужным NFT → Discord аккаунт → роль. Задача выглядит простой, но между «верификацией» и «реальным постоянным доступом» — целый слой инфраструктуры, который ломается предсказуемо.

Архитектура системы

Связка wallet ↔ Discord

Пользователь кликает «Verify» → редирект на verification page → подключает кошелёк через WalletConnect v2 → подписывает сообщение (sign message, без gas) → сервер проверяет подпись → сохраняет {discordId: walletAddress}.

Sign message — не транзакция, пользователь ничего не платит. Стандартное сообщение для верификации:

Verify Discord: username#1234
Nonce: a3f8b2c1
Timestamp: 1711234567

Nonce — случайная строка, уникальная для каждой сессии, с TTL 5 минут. Без nonce — возможен replay attack: скопированная подпись может быть переиспользована.

Верификация подписи на бэкенде:

import { verifyMessage } from 'viem';

const isValid = await verifyMessage({
    address: claimedAddress,
    message: expectedMessage,
    signature: userSignature
});

Проверка NFT ownership: три подхода

Прямой RPC вызов. balanceOf(wallet, tokenId) через ethers.js или viem. Простой, работает для маленьких коллекций. Проблема: при 10,000 пользователях — 10,000 RPC вызовов при каждой проверке.

Alchemy/Moralis NFT API. getNFTsForOwner(wallet, contractAddress) — один запрос, возвращает все токены. Быстро, но зависимость от внешнего сервиса. При даунтайме Alchemy — бот не работает.

The Graph subgraph. Индексируем Transfer события коллекции, строим {owner: [tokenIds]} маппинг. Быстрый GraphQL запрос. Задержка индексации ~1-5 минут — при быстрой продаже токена пользователь ещё 5 минут сохраняет роль.

Для продакшн ботов используем Alchemy NFT API как primary с The Graph как backup и прямым RPC как последний fallback.

Discord bot: slash commands и event handling

Бот реализован на discord.js v14. Ключевые slash commands:

  • /verify — начало верификации, бот отправляет ephemeral message со ссылкой
  • /check — принудительная проверка владения (для пользователей, которые продали токен)
  • /roles — показать все роли и требования к ним

Роли назначаются через guild.members.cache.get(userId)?.roles.add(roleId). Требует permission MANAGE_ROLES и чтобы роль бота была выше назначаемых ролей в hierarchy — частая ошибка при настройке.

async function syncUserRoles(userId: string, wallet: string): Promise<void> {
    const member = await guild.members.fetch(userId);
    const ownedTokens = await getNFTsForOwner(wallet, CONTRACT_ADDRESS);
    
    for (const [roleId, requirement] of ROLE_REQUIREMENTS) {
        const qualifies = checkQualification(ownedTokens, requirement);
        if (qualifies && !member.roles.cache.has(roleId)) {
            await member.roles.add(roleId);
        } else if (!qualifies && member.roles.cache.has(roleId)) {
            await member.roles.remove(roleId);
        }
    }
}

Периодическая ресинхронизация

Критический момент: пользователь продал NFT, должен потерять роль. Бот не получает событие от Discord — он должен сам периодически проверять.

Cron job каждые 10-30 минут: для каждого верифицированного пользователя проверяем текущий баланс, обновляем роли. При 1000 пользователях и 30-минутном интервале — ~33 API запроса в минуту. Укладывается в лимиты Alchemy.

Оптимизация: слушаем Transfer события контракта через WebSocket (Alchemy WebSocket API). При любом Transfer проверяем, задействован ли верифицированный кошелёк, и немедленно обновляем роль. Это снижает latency до секунд.

const provider = new WebSocketProvider(ALCHEMY_WS_URL);
const contract = new Contract(NFT_ADDRESS, erc721Abi, provider);

contract.on('Transfer', async (from, to, tokenId) => {
    const affectedWallets = [from, to].filter(w => w !== ethers.ZeroAddress);
    for (const wallet of affectedWallets) {
        await syncRolesForWallet(wallet);
    }
});

Поддержка нескольких коллекций и trait-based роли

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

  • Держишь ≥3 токена из коллекции A → VIP роль
  • Держишь токен с trait «Legendary» → Legendary роль
  • Держишь токен из коллекции A и коллекции B → Collab роль

Для trait-based ролей нужен доступ к метаданным. Alchemy getNFTsForOwner возвращает tokenMetadata включая attributes. Конфигурация ролей в JSON:

{
  "LEGENDARY_ROLE_ID": {
    "contract": "0x...",
    "minBalance": 1,
    "requiredTrait": {"trait_type": "Rarity", "value": "Legendary"}
  }
}

Стек

Компонент Технология
Бот discord.js v14, TypeScript
Wallet connect WalletConnect v2 (web app для верификации)
NFT data Alchemy NFT API + WebSocket
База данных PostgreSQL (userId ↔ wallet маппинг)
Хостинг Railway или Render (persistent process)
Верификация подписей viem verifyMessage

Ориентиры по срокам

Базовый бот с одной коллекцией и одной ролью — 3-4 дня. Расширенный с несколькими коллекциями, trait-based ролями и real-time sync через WebSocket — 4-5 дней.