Discord NFT Holder Verification Bot Development

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
Discord NFT Holder Verification Bot Development
Medium
~3-5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

Development of Discord Bot for NFT Holder Verification

An NFT project without a holder verification system—a public Discord where token owners are indistinguishable from random visitors. Holder-only channels, early access to new mints, governance votes—all require proof of ownership, updated with each token transfer. Technically, the task consists of three layers: on-chain verification via RPC, OAuth authorization via Discord, and periodic role revalidation when balance changes.

Architecture of the Verification System

Wallet Signature Flow

Standard verification flow without storing private keys:

  1. User clicks /verify in Discord
  2. Bot sends them a DM with a unique challenge message (UUID + timestamp)
  3. User signs the message in MetaMask via WalletConnect or custody wallet
  4. Sends the signature to the bot
  5. Bot recovers address via ecrecover (or viem.verifyMessage()), checks NFT balance via RPC
import { verifyMessage } from 'viem';

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

if (!recoveredAddress) throw new Error('Invalid signature');

const balance = await publicClient.readContract({
  address: NFT_CONTRACT,
  abi: erc721Abi,
  functionName: 'balanceOf',
  args: [claimedAddress],
});

Challenge message must contain a timestamp with short TTL (5-10 minutes). Without TTL—attacker can replay a captured signature (signature replay). Store used challenges in Redis with auto-expiration.

Multi-contract Verification

Most real projects verify not one contract but several: main collection + companion collection + staking contract. Roles are issued by condition combinations:

Gold holder = balance(MainNFT) >= 1 AND balance(CompanionNFT) >= 1
Diamond holder = balance(MainNFT) >= 5
Staker = stakedBalance(StakingContract, address) >= 1

For staking contracts, a separate ABI call is needed: standard ERC-721 balanceOf doesn't account for staked tokens (owned by staking contract, not user). Call stakedTokensOf(address) or equivalent from custom staking contract.

Periodic Role Revalidation

Critical part often missed. User sells NFT—Discord role should be revoked. Implement via scheduled job:

// Cron job every 6-12 hours
async function revalidateAllHolders() {
  const verifiedUsers = await db.getAllVerifiedUsers();
  
  for (const user of verifiedUsers) {
    const currentBalance = await checkNFTBalance(user.walletAddress);
    const requiredRoles = calculateRoles(currentBalance);
    
    await syncDiscordRoles(user.discordId, requiredRoles);
  }
}

Revalidation frequency—balance between current state and RPC rate limits. For high-activity collections (> 100 transfers/day)—every 6 hours. For slow—once per 24 hours. Alternative—event listening via WebSocket subscription to contract Transfer events, but requires stable 24/7 WebSocket connection.

Data Storage and GDPR

Store minimum: {discordId, walletAddress, verifiedAt}. No additional on-chain data. In EU with European audience—right to deletion via /unverify command. Implement purge when deleted from Discord server.

Wallet password—never request. Message signature ≠ fund access, but explain this explicitly to users in bot interface.

Implementation Stack

Discord.js v14—main framework. Slash commands (not message commands—Discord deprecated). Buttons for inline verification without DM if needed.

viem for on-chain interaction—lighter than ethers.js by bundle size, strictly typed.

PostgreSQL for storing verified users. Redis for challenge message cache.

Alchemy/QuickNode as RPC provider—native WebSocket for event subscriptions, higher rate limits than public nodes.

For multi-chain collections (Ethereum + Polygon, for example)—separate publicClient for each chain, aggregate results before issuing roles.

Development Process

Setup (0.5 days). Discord Application registration, bot permissions configuration (MANAGE_ROLES mandatory), role setup on server.

Development (2-3 days). Core bot with verify flow, multi-contract logic, scheduled revalidation, database, deployment on VPS (Docker + PM2).

Testing (0.5-1 day). Testing on staging server: correct role issuing, revalidation after transfer, edge cases (zero balance, multiple wallets).

Basic bot with one-contract verification—2-3 days. With multi-contract logic, custom roles, and event-driven revalidation—4-5 days. Cost is calculated individually.