Agency Logo
WeBuildCrew

Initializing...

Telegram#telegram#bot#airdrop

How to Build a Telegram Airdrop Bot That Handles 100K Users

Step-by-step guide to building a production-grade Telegram airdrop bot with wallet verification, referral tracking, and anti-sybil protection. Battle-tested with 50,000+ real users.

ZZahid Ghotia May 1, 2025 12 min read
Share

Most airdrop bots fail not because of bad code, but because of architectural decisions made when the project had 100 users — not 100,000. Wallet validation, referral chains, and anti-fraud protection all require database patterns that collapse under real load. This guide covers exactly what we use in production.

The Stack We Use

  • Python 3.11 + aiogram 3.x — async, battle-tested for high-throughput bots
  • PostgreSQL + asyncpg with PgBouncer for connection pooling
  • Redis for rate limiting, session state, and referral chain lookups
  • Celery + Redis broker for background wallet verification tasks
  • Docker + Railway or Render for deployment

Core Bot Setup with aiogram 3

python
from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.redis import RedisStorage

storage = RedisStorage.from_url("redis://localhost:6379/0")
dp = Dispatcher(storage=storage)
bot = Bot(token="BOT_TOKEN", parse_mode="HTML")

@dp.message(Command("start"))
async def cmd_start(message: Message):
    ref_code = message.text.split()[-1] if len(message.text.split()) > 1 else None
    await register_user(message.from_user.id, ref_code)
    await message.answer("Welcome! Use /verify to link your wallet.")

async def main():
    await dp.start_polling(bot)

Wallet Verification Flow

Never trust a wallet address the user submits without cryptographic proof of ownership. Always verify via signed message.

  1. 1.User submits wallet address via /verify command
  2. 2.Bot generates a unique nonce (random 8-char hex string, stored in Redis with 10-minute TTL)
  3. 3.User signs the nonce with their wallet (MetaMask 'Sign Message' or equivalent)
  4. 4.User pastes the signature back into the bot
  5. 5.Bot verifies signature using eth_account — recovers address and compares
  6. 6.Wallet is linked to Telegram user ID in PostgreSQL with a unique constraint
python
from eth_account.messages import encode_defunct
from web3 import Web3

def verify_eth_signature(address: str, nonce: str, signature: str) -> bool:
    w3 = Web3()
    message = encode_defunct(text=f"WeBuildCrew Airdrop Verification: {nonce}")
    recovered = w3.eth.account.recover_message(message, signature=signature)
    return recovered.lower() == address.lower()

Referral Tracking Database Schema

sql
CREATE TABLE users (
  telegram_id   BIGINT PRIMARY KEY,
  wallet_address VARCHAR(64) UNIQUE,
  referred_by   BIGINT REFERENCES users(telegram_id),
  referral_count INTEGER DEFAULT 0,
  points        INTEGER DEFAULT 0,
  joined_at     TIMESTAMP DEFAULT NOW()
);

-- Critical for performance at 100K+ users
CREATE INDEX idx_referred_by ON users(referred_by);
CREATE INDEX idx_joined_at   ON users(joined_at DESC);

Anti-Sybil Protection

Without anti-sybil measures, a single actor can create thousands of fake Telegram accounts and drain your entire airdrop allocation in minutes.

  • Require Telegram account age > 30 days (check via getChat API — accounts < 30 days are auto-rejected)
  • Enforce one wallet per Telegram ID with a unique database constraint
  • IP rate limiting via Redis: max 3 registrations per IP per hour
  • Wallet activity check: reject wallets with zero on-chain transactions
  • Phone number uniqueness: Telegram enforces one account per phone number in most regions

Scaling Infrastructure

💡

At 10K users/day, enable PgBouncer with transaction pooling mode (not session mode). At 50K+ users, partition the users table by joined_at date and run multiple aiogram bot instances behind a webhook load balancer — polling does not scale past ~3 bot instances.

Production Launch Checklist

  1. 1.Switch from polling to webhook (setWebhook API call) — 10x more reliable under load
  2. 2.Enable PgBouncer in transaction pooling mode, pool_size=20 per bot instance
  3. 3.Store all secrets in environment variables — never in code
  4. 4.Implement SIGTERM handler for graceful bot shutdown without message loss
  5. 5.Set up Sentry for real-time error tracking with Telegram user ID in context
  6. 6.Add /status command for ops visibility (user count, pending verifications, queue depth)
  7. 7.Load test with 10,000 simulated concurrent users before public launch

Found this useful? Share it.

Tweet this
Z

Zahid Ghotia

CEO & Founder, WeBuildCrew

Full-stack engineer and automation specialist with 200+ projects delivered. Builds Telegram bots, Discord automation, and high-performance web products for clients worldwide.

Work with Zahid →

Get Weekly Growth Hacks

Telegram bot tutorials, Discord automation, Reddit auto-poster tips and crypto dev insights — every week.