/** * Pump Fun Agent Tracker Bot — Telegram Bot & Commands * * Grammy bot with commands: * /start — Welcome message * /status — Show tracker stats * /wallet — Check developer wallet balance * /claims — Show recent claims summary * /buybacks — Show recent buybacks summary * /help — Command reference * * Sends real-time notifications for: * - Agent payments received * - Creator fee claims * - Token buybacks by developer wallet */ import { Bot } from 'grammy'; import type { Context } from 'grammy'; import type { AgentMonitor } from './monitor.js'; import type { BotConfig } from './types.js'; import { formatBuybackNotification, formatClaimNotification, formatHelp, formatPaymentNotification, formatStatus, formatWalletBalance, } from './formatters.js'; export function createBot(config: BotConfig, monitor: AgentMonitor): Bot { const bot = new Bot(config.telegramToken); // ── /start ──────────────────────────────────────────────────────────── bot.command('start', async (ctx: Context) => { await ctx.reply( `Pump Fun Agent Tracker\n\n` + `Monitoring agent token:\n${config.agentTokenMint}\n\n` + `Developer wallet:\n${config.developerWallet}\n\n` + `Use /help for commands.`, { parse_mode: 'HTML' }, ); }); // ── /status ─────────────────────────────────────────────────────────── bot.command('status', async (ctx: Context) => { const msg = formatStatus(monitor.state, { agentMint: config.agentTokenMint, devWallet: config.developerWallet, }); await ctx.reply(msg, { parse_mode: 'HTML' }); }); // ── /wallet ─────────────────────────────────────────────────────────── bot.command('wallet', async (ctx: Context) => { try { const snapshot = await monitor.getWalletBalance(); await ctx.reply(formatWalletBalance(snapshot), { parse_mode: 'HTML', link_preview_options: { is_disabled: true }, }); } catch (err) { await ctx.reply('Failed to fetch wallet balance. Try again later.'); } }); // ── /claims ─────────────────────────────────────────────────────────── bot.command('claims', async (ctx: Context) => { const { totalClaims, totalClaimsSol, lastClaim } = monitor.state; let msg = `Claims Summary\n\n`; msg += `Total Claims: ${totalClaims}\n`; msg += `Total SOL Claimed: ${totalClaimsSol.toFixed(4)} SOL\n`; if (lastClaim) { msg += `\nLast Claim:\n`; msg += formatClaimNotification(lastClaim); } else { msg += `\nNo claims detected yet.`; } await ctx.reply(msg, { parse_mode: 'HTML', link_preview_options: { is_disabled: true }, }); }); // ── /buybacks ───────────────────────────────────────────────────────── bot.command('buybacks', async (ctx: Context) => { const { totalBuybacks, totalBuybackSol, lastBuyback } = monitor.state; let msg = `Buybacks Summary\n\n`; msg += `Total Buybacks: ${totalBuybacks}\n`; msg += `Total SOL Spent: ${totalBuybackSol.toFixed(4)} SOL\n`; if (lastBuyback) { msg += `\nLast Buyback:\n`; msg += formatBuybackNotification(lastBuyback); } else { msg += `\nNo buybacks detected yet.`; } await ctx.reply(msg, { parse_mode: 'HTML', link_preview_options: { is_disabled: true }, }); }); // ── /help ───────────────────────────────────────────────────────────── bot.command('help', async (ctx: Context) => { await ctx.reply(formatHelp(), { parse_mode: 'HTML' }); }); return bot; } /** * Send a notification to all configured chat IDs. * Used by the monitor callbacks to push real-time alerts. */ export async function broadcastMessage( bot: Bot, chatIds: number[], message: string, ): Promise { for (const chatId of chatIds) { try { await bot.api.sendMessage(chatId, message, { parse_mode: 'HTML', link_preview_options: { is_disabled: true }, }); } catch (err) { console.error(`[Bot] Failed to send to chat ${chatId}:`, err); } } }