Разработка Twitter/X-бота для крипто-проекта
Twitter/X остаётся основной площадкой крипто-коммьюнити — альфа расходится здесь быстрее чем где-либо ещё. Боты нужны для конкретных задач: автоматические анонсы on-chain событий (крупные переводы, liquidations, governance голосования), мониторинг упоминаний, публикация метрик протокола по расписанию. Telegram-боты проще в реализации, но Twitter/X — это публичная видимость и нарратив.
Twitter API v2: текущее состояние
С 2023 года Twitter/X резко изменил условия API. Важно понимать текущую ситуацию перед началом работы:
Free tier — только чтение (1500 твитов в месяц на запись, крайне ограниченно). По сути бесполезен для активного бота.
Basic tier ($100/месяц) — 3000 твитов в месяц на запись, 10K читать. Достаточно для ботов с умеренной активностью.
Pro tier ($5000/месяц) — 300K твитов. Для высокочастотных alert-ботов.
Для большинства крипто-проектов хватает Basic. При планировании бота нужно сразу рассчитать monthly tweet volume — если планируется твитить при каждой крупной транзакции на popular протоколе, это может быть сотни твитов в день.
Архитектура бота
Компонент 1: on-chain монитор
Источник данных — всегда блокчейн-события, а не сторонние агрегаторы (они добавляют задержку). Используем WebSocket подписку для real-time:
const { ethers } = require('ethers')
const provider = new ethers.WebSocketProvider(process.env.WSS_RPC_URL)
const AAVE_POOL = '0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2'
const LIQUIDATION_TOPIC = ethers.id('LiquidationCall(address,address,address,uint256,uint256,address,bool)')
provider.on({ address: AAVE_POOL, topics: [LIQUIDATION_TOPIC] }, async (log) => {
const iface = new ethers.Interface(AAVE_POOL_ABI)
const decoded = iface.parseLog(log)
const collateralAsset = decoded.args.collateralAsset
const debtAsset = decoded.args.debtAsset
const liquidatedCollateralAmount = decoded.args.liquidatedCollateralAmount
// Получаем USD стоимость через Chainlink или Coingecko
const usdValue = await getUSDValue(collateralAsset, liquidatedCollateralAmount)
if (usdValue > MINIMUM_NOTABLE_USD) {
await postLiquidationTweet({ collateralAsset, debtAsset, usdValue, txHash: log.transactionHash })
}
})
Компонент 2: форматирование и публикация
const { TwitterApi } = require('twitter-api-v2')
const client = new TwitterApi({
appKey: process.env.TWITTER_APP_KEY,
appSecret: process.env.TWITTER_APP_SECRET,
accessToken: process.env.TWITTER_ACCESS_TOKEN,
accessSecret: process.env.TWITTER_ACCESS_SECRET,
})
const rwClient = client.readWrite
async function postLiquidationTweet({ collateralAsset, debtAsset, usdValue, txHash }) {
const collSymbol = await getTokenSymbol(collateralAsset)
const debtSymbol = await getTokenSymbol(debtAsset)
const text = [
`🔴 AAVE Liquidation`,
``,
`Collateral: ${collSymbol}`,
`Debt: ${debtSymbol}`,
`Value: $${formatUSD(usdValue)}`,
``,
`Tx: https://etherscan.io/tx/${txHash}`,
``,
`#DeFi #AAVE #Liquidation`
].join('\n')
try {
await rwClient.v2.tweet(text)
} catch (error) {
if (error.code === 403) {
// Duplicate tweet — добавляем timestamp или пропускаем
logger.warn('Duplicate tweet prevented', { txHash })
} else {
throw error
}
}
}
Rate limiting и anti-ban
Twitter/X активно детектирует аномальное поведение. Рекомендации:
- Дедупликация: хранить txHash опубликованных событий (Redis с TTL 24h) — никогда не твитить одно событие дважды
- Cooldown между твитами: минимум 30 секунд между публикациями при серии событий
- Queue с приоритетами: если событий много — твитим самые крупные, мелкие агрегируем в один дайджест-твит
- Graceful reconnect: WebSocket соединения рвутся, нужен exponential backoff при переподключении
// Очередь с дебаунсом для batch событий
class TweetQueue {
constructor(client, maxPerHour = 20) {
this.queue = []
this.maxPerHour = maxPerHour
this.published = []
// Публикуем каждые 3 минуты (максимум 20 в час)
setInterval(() => this.flush(), 3 * 60 * 1000)
}
async add(event) {
// Дедупликация по txHash
if (this.queue.some(e => e.txHash === event.txHash)) return
this.queue.push({ ...event, addedAt: Date.now() })
// Сортируем по usdValue — публикуем самые значимые первыми
this.queue.sort((a, b) => b.usdValue - a.usdValue)
}
async flush() {
if (this.queue.length === 0) return
const toPublish = this.queue.shift()
await this.client.v2.tweet(formatTweet(toPublish))
// Throttle: не публикуем чаще maxPerHour
const lastHour = this.published.filter(t => Date.now() - t < 3600000)
if (lastHour.length >= this.maxPerHour) {
logger.info('Rate limit self-imposed, queuing')
return
}
this.published.push(Date.now())
}
}
Scheduled tweets: метрики протокола
Помимо event-driven публикаций — периодические дайджесты:
const cron = require('node-cron')
// Ежедневная статистика в 12:00 UTC
cron.schedule('0 12 * * *', async () => {
const stats = await fetchProtocolStats()
await rwClient.v2.tweet(
`📊 Daily Stats — ${new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}\n\n` +
`TVL: $${formatBigNumber(stats.tvl)}\n` +
`24h Volume: $${formatBigNumber(stats.volume24h)}\n` +
`Active Users: ${stats.activeUsers.toLocaleString()}\n\n` +
`#DeFi`
)
})
Деплой
Минимальная инфраструктура — Docker контейнер на VPS с постоянным WebSocket соединением. PM2 или systemd для автоперезапуска. Логирование через Winston в файл + опционально Telegram-алерты на ошибки самого бота.
Переменные окружения никогда не в коде — .env файл, в production — secrets manager или переменные окружения хостинга.
Что входит в работу
- Настройка Twitter Developer App и OAuth 2.0 аутентификации
- On-chain монитор с WebSocket подпиской на нужные события
- Форматирование твитов с реальными данными из блокчейна
- Дедупликация, rate limiting, queue менеджмент
- Scheduled публикации по расписанию (дайджесты, метрики)
- Деплой на VPS с мониторингом процесса







