
Создание телеграммы для мониторинга активности кошелька 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)
или следить за транзакциями, влияющими на адрес, чтобы сделать вывод изменений. Для простоты фильтрация входящих/исходящих транзакций (выше) обрабатывает большинство обновлений баланса. - Фильтрация. На каждом событии или транзакции ищите, если оно включает в себя какой -либо подписанный адрес кошелька. Поддерживать поиск (например, JS
Set
или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.");
Оригинал