Skip to main content

Command Palette

Search for a command to run...

Telegram Bot + Solana: The Complete Developer Guide

Published
4 min read

Telegram Bot + Solana: The Complete Developer Guide

Telegram bots are the backbone of crypto tooling on Solana. From token scanners to copy-trading bots, most tools traders use daily run inside Telegram. Here's how to build one from scratch.

Why Telegram?

Telegram is where crypto lives. Over 80% of Solana degens check Telegram before Twitter. Building a bot here means:

  • Instant distribution — users find you via search or group shares
  • No app store approval — deploy and iterate in minutes
  • Rich UI — inline keyboards, callbacks, formatted messages
  • Always-on — users interact 24/7, your bot runs on a $5 VPS

Prerequisites

  • Node.js 18+
  • A Telegram bot token (get one from @BotFather)
  • Basic familiarity with @solana/web3.js

Step 1: Set Up the Bot

const https = require('https');
const { Connection, PublicKey } = require('@solana/web3.js');

const BOT_TOKEN = 'YOUR_BOT_TOKEN';
const API_BASE = `https://api.telegram.org/bot${BOT_TOKEN}`;
const connection = new Connection('https://api.mainnet-beta.solana.com');

let offset = 0;

async function getUpdates() {
  const url = `${API_BASE}/getUpdates?offset=${offset}&timeout=30`;
  const res = await fetch(url);
  const data = await res.json();

  for (const update of data.result || []) {
    offset = update.update_id + 1;
    if (update.message?.text) {
      await handleMessage(update.message);
    }
  }
}

Long polling is simpler than webhooks for getting started. You call getUpdates in a loop and Telegram sends you new messages.

Step 2: Handle Commands

async function handleMessage(msg) {
  const chatId = msg.chat.id;
  const text = msg.text.trim();

  if (text === '/start') {
    await sendMessage(chatId, 'Welcome! Paste any Solana token address to scan it.');
    return;
  }

  // Check if it looks like a Solana address
  if (/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(text)) {
    await scanToken(chatId, text);
    return;
  }

  await sendMessage(chatId, 'Send a Solana token address to get started.');
}

async function sendMessage(chatId, text, options = {}) {
  await fetch(`${API_BASE}/sendMessage`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      chat_id: chatId,
      text,
      parse_mode: 'Markdown',
      ...options,
    }),
  });
}

Step 3: Add Solana Integration

const { getMint } = require('@solana/spl-token');

async function scanToken(chatId, address) {
  try {
    const mint = new PublicKey(address);
    const mintInfo = await getMint(connection, mint);
    const holders = await connection.getTokenLargestAccounts(mint);

    const risks = [];
    if (mintInfo.mintAuthority) risks.push('Mint authority active');
    if (mintInfo.freezeAuthority) risks.push('Freeze authority active');

    const top10 = holders.value.slice(0, 10);
    const concentration = top10.reduce((s, h) => s + Number(h.amount), 0)
      / Number(mintInfo.supply) * 100;
    if (concentration > 80) risks.push(`Top 10 hold ${concentration.toFixed(0)}%`);

    const score = Math.max(0, 100 - risks.length * 30);
    const emoji = score >= 70 ? '🟢' : score >= 40 ? '🟡' : '🔴';

    let response = `${emoji} *Safety Score: ${score}/100*\n\n`;
    if (risks.length > 0) {
      response += '*Risks Found:*\n' + risks.map(r => `- ${r}`).join('\n');
    } else {
      response += 'No major risks detected.';
    }

    await sendMessage(chatId, response);
  } catch (err) {
    await sendMessage(chatId, `Error scanning token: ${err.message}`);
  }
}

Step 4: Add Inline Keyboards

Inline keyboards make your bot interactive — users tap buttons instead of typing commands.

async function sendTokenResult(chatId, address, score) {
  await sendMessage(chatId, `Score: ${score}/100`, {
    reply_markup: JSON.stringify({
      inline_keyboard: [
        [
          { text: 'Buy Token', callback_data: `buy_${address}` },
          { text: 'Set Alert', callback_data: `alert_${address}` },
        ],
        [
          { text: 'View Holders', callback_data: `holders_${address}` },
        ],
      ],
    }),
  });
}

Step 5: Run Continuously

async function main() {
  console.log('Bot started...');
  while (true) {
    try {
      await getUpdates();
    } catch (err) {
      console.error('Polling error:', err.message);
      await new Promise(r => setTimeout(r, 5000));
    }
  }
}

main();

Production Considerations

  1. Rate limiting — Solana public RPC has limits. Use Helius or QuickNode for production.
  2. User state — Store user settings in a JSON file or SQLite database.
  3. Error handling — Wrap every RPC call in try/catch. Solana is flaky.
  4. Concurrency — Process multiple users simultaneously with Promise.all.
  5. Deployment — Use PM2 on a VPS: pm2 start bot.js --name solana-bot.

Skip the Build — Use What Already Exists

Building a Telegram bot from scratch takes weeks of iteration. @solscanitbot already has 44 commands including token scanning, trading via Jupiter, copy-trading, DCA, limit orders, whale alerts, and more.

It took 4500+ lines of pure Node.js and months of development. Try it free: t.me/solscanitbot


Want the source code? Check out devtools-site-delta.vercel.app/sol-bot-source for the full bot codebase.