Создание телеграммы для мониторинга активности кошелька BNB с помощью GetBlock

Создание телеграммы для мониторинга активности кошелька BNB с помощью GetBlock

12 июня 2025 г.

В этом уроке я хочу показать, как создать бот Telegram (в node.js с использованием Telegraf), которая общается с цепочкой BNB (Binance Smart) с использованием веб-питания (например, GetBlock) и информирует пользователей в режиме реального времени о активности кошелька. Бот может следить за изменениями баланса, передачи токенов BEP-20, NFT Mints и крупных транзакций BNB. Пользователи могут/subscribeпо любому адресу кошелька и получение мгновенных уведомлений. Я расскажу о настройке бота, подключении к WebSocket, подписке на события, логике фильтрации, системе подписки и рекомендациям по развертыванию/настойчивости.

1. Создайте и настройте свой бот Telegram

Создайте Telegram Bot и установите свой токен API через @botfather. В Telegram инициируйте разговор с Botfather и тип/newbotПолем Продолжайте назвать своего бота и получить уникальный токен. Например, Botfather напечатает токен, такой как123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11Полем Обработайте этот токен как пароль.

Сохраните токен и поместите его в вашу среду (например, в.envфайл) так, чтобы ваш код мог получить к нему доступ какprocess.env.BOT_TOKENПолем Ваш бот будет аутентифицировать с помощью API Telegram, используя этот токен.

2. Создайте соединение WebSocket с цепью BNB

Чтобы следить за событиями цепочки BNB в режиме реального времени, подключитесь через поставщика WebSocket. GetBlock имеет конечные точки BNB Smart Chail Websocket. После регистрации на GetBlock и получения клавиши API используйте конечную точку: "

wss://bsc.getblock.io/mainnet/?api_key=YOUR_API_KEY

Этот адрес (с вашим ключом) дает живое соединение WS с BSC. В коде вы можете использовать библиотеки, такие какEthers.jsилиweb3.jsдля подключения:

const { Web3 } = require("web3");
const BSC_WS = "wss://bsc.getblock.io/mainnet/?api_key=YOUR_API_KEY";
const web3 = new Web3(BSC_WS);

Этотweb3Экземпляр теперь слушает данные блокчейна. Вы также можете использоватьEthers.js:

const { ethers } = require("ethers");
const provider = new ethers.providers.WebSocketProvider(BSC_WS);

Любая библиотека позволит вам подписаться на ожидающие транзакции и журналы через подключение к WebSocket.

3. Подписка на события блокчейна

3.1 прослушивание ожидающих транзакций BNB

Чтобы поймать все новые транзакции BNB (нативная монета) до их добычи, подпишитесь наpendingTransactionsтранслировать. С использованиемweb3.js:

async function subscribeToPending() {
  const subscription = await web3.eth.subscribe('pendingTransactions');
  subscription.on('data', async (txHash) => {
    try {
      const tx = await web3.eth.getTransaction(txHash);
      // process tx.from, tx.to, tx.value, etc.
    } catch (err) { console.error(err); }
  });
  subscription.on('error', console.error);
}

Этот код создает подписку, которая получает новые хэши транзакции в меморандум. Для каждогоtxHash, мы получаем всю транзакцию. Затем мы можем подтвердитьtx.fromВtx.to, иtx.value(Значение BNB в WEI). Например, чтобы поймать большие переводы BNB, сравнитеtx.valueс порогом (10 BNB) и поднимите предупреждение, если она пересечена.

Цепностак документовпроиллюстрировать этот шаблон, гдеhandleNewPendingчекиvalueи регистрирует только большие транзакции. Мы адаптируем это в нашем боте, чтобы предупредить подписчиков, адреса которых соответствуютtx.fromилиtx.toПолем

3.2 Мониторинг передачи токенов BEP-20

BEP-20 (формат ERC-20) передачи токенов издаютTransferсобытия. Мы можем подписаться на журналы для этих событий. Подписка на все журналы и фильтрация наTransferПодписи - это один из способов, но лучшая практика - указать фильтры. Например, через web3.js:

const transferSig = web3.utils.sha3("Transfer(address,address,uint256)");
const logsSubscription = await web3.eth.subscribe('logs', {
  topics: [transferSig]
});
logsSubscription.on('data', (log) => {
  // log.address = token contract; log.topics[1]=from, [2]=to
  const from = '0x' + log.topics[1].slice(26);
  const to   = '0x' + log.topics[2].slice(26);
  // convert data (hex) to token amount
  const value = web3.eth.abi.decodeParameter('uint256', log.data);
  // handle transfer where from/to matches a subscriber
});
logsSubscription.on('error', console.error);

Это подписывается на все BSCTransferсобытия. В обратном вызове извлечьfromиtoадреса отlog.topics(Индексированные параметры события) иlog.dataдля передачи суммы. Затем проверьте, соответствует ли любому адресу наблюдаемый кошелек.

3.3 NFT Minting и обнаружение переноса

BEP-721/BEP-1155 NFTS на цепи BNB также испускаютTransferСобытия (та же подпись) при майнинге или передаче. Мы можем поймать их по той же подписке журналов. Мята обычноTransferгдеfromнулевой адрес (0x0000000000000000000000000000000000000000) иtoэто новый владелец. В коде:

if (from === '0x0000000000000000000000000000000000000000') {
  // NFT minted to 'to'
  notifyUser(tokenId, to, 'NFT minted');
}

Для любых NFT -трансферов, включающих наблюдаемый адрес (в качестве отправителя или приемника), запускайте предупреждение. В случае множества типов токенов вам, возможно, придется сортировать между ними по интерфейсу контракта или диапазона идентификатора токена, если есть несколько стандартов, но общая логика оповещения была бы аналогична BEP-20 выше.

3.4 Логика для других событий и балансов

  • Баланс обновлений. Иногда вы можете позвонитьweb3.eth.getBalance(address)или следить за транзакциями, влияющими на адрес, чтобы сделать вывод изменений. Для простоты фильтрация входящих/исходящих транзакций (выше) обрабатывает большинство обновлений баланса.
  • Фильтрация. На каждом событии или транзакции ищите, если оно включает в себя какой -либо подписанный адрес кошелька. Поддерживать поиск (например, JSSetилиMap), представляющие интерес для легко проверитьfrom/toПолем
  • Несколько подписок. В случае множества адресов рассмотрите возможность масштабирования фильтров или использования нескольких библиотек фильтров адреса. Для простого бота мы рассмотрим заинтересованные адреса в обратном вызове.

4. Команды бота и система подписки

Используйте библиотеку Telegraf для Telegram с node.js. Это предоставляет аккуратный способ получить команды и отправлять сообщения. Настройка образца:

const { Telegraf } = require('telegraf');
const bot = new Telegraf(process.env.BOT_TOKEN);

Реализовать команды для управления подписками:

  • /subscribe <address>: Пользователь подписывается на кошелек. В обработчике сохраните отображение кошелька с идентификатором чата этого пользователя.
  • /unsubscribe <address>: Удалить подписку.
  • /list: (Необязательно) Перечислите текущие подписки.

Пример обработчиков команд:

let subscribers = {}; // mapping: address -> Set of chatIds

bot.command('subscribe', (ctx) => {
  const address = ctx.message.text.split(' ')[1];
  if (!web3.utils.isAddress(address)) {
    return ctx.reply("Invalid address.");
  }
  const userId = ctx.chat.id;
  subscribers[address] = subscribers[address] || new Set();
  subscribers[address].add(userId);
  ctx.reply(`Subscribed ${address} for alerts.`);
});

bot.command('unsubscribe', (ctx) => {
  const address = ctx.message.text.split(' ')[1];
  const userId = ctx.chat.id;
  if (subscribers[address]) {
    subscribers[address].delete(userId);
    ctx.reply(`Unsubscribed from ${address}.`);
  } else {
    ctx.reply("No active subscription found for that address.");
  }
});

В этом хранится простое отображение адресов в памяти с наборами идентификаторов чата. В реальном развертывании вы будете сохранять это (например, база данных или файл), чтобы подписки пережили перезапуск. Например, вы можете периодически писатьsubscribersв файл JSON и загрузите его на запуск.

5. Отправка оповещений в реальном времени

Всякий раз, когда событие блокчейна соответствует подписке, отправляйте сообщение Telegram. Например, в ожидаемом слушателю транзакции:

const threshold = web3.utils.toWei('10', 'ether'); // 10 BNB
if (subscribers[tx.to]) {
  for (const chatId of subscribers[tx.to]) {
    bot.telegram.sendMessage(chatId, 
      `📥 *Received*: ${web3.utils.fromWei(tx.value, 'ether')} BNB\n` +
      `From: ${tx.from}\n` +
      `TxHash: ${txHash}`, { parse_mode: 'Markdown' });
  }
}
if (subscribers[tx.from] && tx.value >= threshold) {
  for (const chatId of subscribers[tx.from]) {
    bot.telegram.sendMessage(chatId, 
      `🚀 *Large Transfer Out*: ${web3.utils.fromWei(tx.value, 'ether')} BNB\n` +
      `To: ${tx.to}\nTxHash: ${txHash}`, { parse_mode: 'Markdown' });
  }
}

Аналогично, в обработчике журналов для передачи токенов:

if (subscribers[from]) {
  const symbol = await getTokenSymbol(log.address); // optional helper
  for (const chatId of subscribers[from]) {
    bot.telegram.sendMessage(chatId, 
      `🔻 *Sent*: ${web3.utils.fromWei(value, 'ether')} ${symbol}\n` +
      `To: ${to}\nContract: ${log.address}`, { parse_mode: 'Markdown' });
  }
}
if (subscribers[to]) {
  const symbol = await getTokenSymbol(log.address);
  for (const chatId of subscribers[to]) {
    bot.telegram.sendMessage(chatId, 
      `🔺 *Received*: ${web3.utils.fromWei(value, 'ether')} ${symbol}\n` +
      `From: ${from}\nContract: ${log.address}`, { parse_mode: 'Markdown' });
  }
}

В этих уведомлениях используется простой форматирование маркировки (жирный, смайлики), чтобы выделить активность. Телеграфbot.telegram.sendMessage(chatId, text, opts)Отправляет предупреждение. Имейте в виду, чтобы учесть потенциальные ошибки при отправке (BOT BONTER BOT и т. Д.).

6. Обработка отключения и ограничения скорости

Веблетная достоверность.Подключения WebSocket можно прекратить. Послушатьprovider._websocket.on('close')(Ethers.js) или подпискаerrorСобытия и попытка воссоединиться. Используйте стратегию повторной/отступления. Например:

provider._websocket.on('close', (code) => {
  console.error(`WS closed with code ${code}, reconnecting...`);
  setTimeout(() => {
    provider = new ethers.providers.WebSocketProvider(BSC_WS);
    subscribeToEvents(); // re-subscribe after reconnect
  }, 5000);
});

Пределы оценки.GetBlock имеет ограничения по цене по количеству сообщений. Избегайте чрезмерного опроса. Подписки великолепны, потому что данные выдвигаются. Если вы достигнете пределов (например, слишком много запросов подписки), рассмотрите возможность обновления вашего плана или партии. Всегда поймайте ошибки поставщика Web3 (например, превышенная квота) и применяйте откат.

7. Развертывание и настойчивость

Чтобы бот работал 24/7, разверните его на сервере или в облачном экземпляре. Несколько хороших вариантов будут VPS, AWS или Heroku. Например, на Heroku вы можете развернуть приложение Node.js с помощьюProcfileУказаниеworker: node index.jsПолем Обратите внимание, что файловая система Heroku-это эфемерная, поэтому подписки с хранением файлов не будут доступны при перезапуске или Dyno Restart. Храните информацию о подписке в фактической базе данных (Postgresql, Redis и т. Д.).

Если вы на Heroku, помните, Dynos Dynos Dynos спит, когда нет веб -трафика. Использование бота с длинным заводом на Heroku включает в себя использование Webhooks (bot.telegram.setWebhook(URL)) или поддержание работы работника динамо (что может понести расходы). В качестве альтернативы запустите бот в качестве сервиса AWS EC2 или контейнера Docker (с управлением процессами PM2).

Наконец, держите свои ключи в безопасности: не впадайте в код клавиши API или токены жесткой кодировки. Используйте переменные среды и/или менеджер секретов.

Полный пример кода (node.js с Telegraf)

// index.js
require('dotenv').config();
const { Telegraf } = require('telegraf');
const { Web3 } = require('web3');

const bot = new Telegraf(process.env.BOT_TOKEN);
const BSC_WS = `wss://bsc.getblock.io/mainnet/?api_key=${process.env.GETBLOCK_KEY}`;
const web3 = new Web3(BSC_WS);

// In-memory subscription map: address -> Set of chat IDs
let subscribers = {};

// Helper to ensure checksum and lowercase
function normalize(addr) { return web3.utils.toChecksumAddress(addr); }

// Telegram command: subscribe to address
bot.command('subscribe', (ctx) => {
  const parts = ctx.message.text.split(' ');
  if (parts.length < 2) return ctx.reply("Usage: /subscribe <address>");
  let address = parts[1];
  if (!web3.utils.isAddress(address)) return ctx.reply("Invalid address.");
  address = normalize(address);
  const id = ctx.chat.id;
  if (!subscribers[address]) subscribers[address] = new Set();
  subscribers[address].add(id);
  ctx.reply(`Subscribed to wallet ${address}.`);
});

// Telegram command: unsubscribe from address
bot.command('unsubscribe', (ctx) => {
  const parts = ctx.message.text.split(' ');
  if (parts.length < 2) return ctx.reply("Usage: /unsubscribe <address>");
  const address = normalize(parts[1]);
  const id = ctx.chat.id;
  if (subscribers[address]) {
    subscribers[address].delete(id);
    ctx.reply(`Unsubscribed from ${address}.`);
  } else {
    ctx.reply(`You were not subscribed to ${address}.`);
  }
});

// Start bot
bot.launch();
console.log("Telegram bot started.");

// Subscribe to pending BNB transactions
web3.eth.subscribe('pendingTransactions', (err, txHash) => {
  if (err) return console.error(err);
  // For each pending tx, fetch details
  web3.eth.getTransaction(txHash)
    .then(tx => {
      if (!tx) return; // might be null if it got dropped
      const from = tx.from ? normalize(tx.from) : null;
      const to = tx.to ? normalize(tx.to) : null;
      const value = web3.utils.toBN(tx.value);
      // Notify if recipient is watched
      if (to && subscribers[to]) {
        subscribers[to].forEach(chatId => {
          bot.telegram.sendMessage(chatId,
            `📥 *Incoming* ${web3.utils.fromWei(value, 'ether')} BNB\nFrom: ${from}\nTx: [${txHash}](https://bscscan.com/tx/${txHash})`,
            { parse_mode: 'Markdown' });
        });
      }
      // Notify if sender is watched and large transfer
      const threshold = web3.utils.toBN(web3.utils.toWei('10', 'ether')); // 10 BNB
      if (from && subscribers[from] && value.gte(threshold)) {
        subscribers[from].forEach(chatId => {
          bot.telegram.sendMessage(chatId,
            `🚀 *Large Outgoing* ${web3.utils.fromWei(value, 'ether')} BNB\nTo: ${to}\nTx: [${txHash}](https://bscscan.com/tx/${txHash})`,
            { parse_mode: 'Markdown' });
        });
      }
    })
    .catch(console.error);
});

// Subscribe to Transfer logs (BEP-20 and NFTs)
const transferSig = web3.utils.sha3("Transfer(address,address,uint256)");
web3.eth.subscribe('logs', { topics: [transferSig] }, (err, log) => {
  if (err) { console.error(err); return; }
  // Parse log fields
  const from = '0x' + log.topics[1].slice(26);
  const to   = '0x' + log.topics[2].slice(26);
  const value = web3.utils.toBN(log.data);
  const fromNorm = normalize(from);
  const toNorm   = normalize(to);
  // Determine token symbol (optional helper could use web3+ABI or an on-chain call)
  const tokenContract = log.address;
  // Send outgoing transfer alert
  if (subscribers[fromNorm]) {
    subscribers[fromNorm].forEach(chatId => {
      bot.telegram.sendMessage(chatId,
        `🔻 *Token Sent* (${tokenContract})\nAmount: ${web3.utils.fromWei(value, 'ether')}\nTo: ${toNorm}`,
        { parse_mode: 'Markdown' });
    });
  }
  // Send incoming transfer alert
  if (subscribers[toNorm]) {
    subscribers[toNorm].forEach(chatId => {
      bot.telegram.sendMessage(chatId,
        `🔺 *Token Received* (${tokenContract})\nAmount: ${web3.utils.fromWei(value, 'ether')}\nFrom: ${fromNorm}`,
        { parse_mode: 'Markdown' });
    });
  }
});

console.log("Subscribed to blockchain events.");


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE