Developing Telegram Bot for DeFi Position Monitoring
Position in Aave: $80k USDC collateral, $50k USDT debt. Health factor 1.21. Market falls at night—three hours later health factor crosses 1.0, position liquidated, 10% penalty. User wakes up, checks wallet. Standard scenario properly-configured alerts prevent within 15 minutes.
Technical Complexities Buried in Production
Polling vs WebSocket: Latency Matters
Naive implementation—cron queries RPC every minute. For health factor works, but blocks on Ethereum release every 12 seconds, Chainlink oracle price updates per heartbeat (1 hour) or 0.5% deviation. Minute polling misses sharp moves.
Right approach: subscribe to events via eth_subscribe("logs") over WebSocket. Aave v3 emits LiquidationCall(address collateralAsset, address debtAsset, address user, ...). Catch event—notify immediately. For health factor monitoring, listen ReserveDataUpdated and recalculate position locally, not wait for next eth_call.
WebSocket problem: connection breaks. Production needs reconnect with exponential backoff, persistent subscription ID, and replay missed blocks on recovery via eth_getLogs with fromBlock: lastProcessedBlock.
Multi-Chain: Different Addresses, Different ABIs
User holds positions in Aave v3 on Ethereum, Optimism and Polygon simultaneously. Three instances with different PoolAddressesProvider. APY on Polygon may differ from Ethereum twofold—information user wants in single place.
Architecture: separate worker per chain, common PostgreSQL with positions(user_address, chain_id, protocol, collateral, debt, health_factor, updated_at) table. Telegram bot reads from DB, not chain—quick command response, low RPC load.
APY Calculation: Pool Doesn't Stand Still
Compound APY in Aave = (1 + APR/secondsPerYear)^secondsPerYear - 1. APR taken from getReserveData().currentLiquidityRate (deposits) or currentVariableBorrowRate (debt)—both in ray (1e27). Error on every second project: divide by 1e18 instead of 1e27. Get APY in thousands percent, users happy until they see real numbers.
What We Build
Stack
| Layer | Technology |
|---|---|
| Chain Monitoring | viem (WebSocket transport), ethers.js fallback |
| Protocols | Aave v3 Pool ABI, Compound v3 Comet ABI |
| Oracles | Chainlink Price Feed (direct calls + The Graph) |
| Database | PostgreSQL—positions, alerts, history |
| Queue | BullMQ (Redis)—processing notifications without spikes |
| Bot | grammY (TypeScript) or python-telegram-bot |
| Deployment | Docker + PM2, VPS with 99.9% uptime |
Alert Logic
Configurable per-user thresholds: health factor <1.3, <1.1 (critical), APY change >20% per 24 hours, new liquidation on watched address. Deduplication via Redis with TTL: one notification per event, repeat after 30 min if situation unchanged.
For health factor: not just current value but trend—bot shows "declined 0.15 over last 6 hours". Actionable information.
Bot Commands
/positions—all open positions with health factor and current APY. /alerts—threshold management. /history [address]—health factor change history for 7 days, text sparkline format. /liquidations—recent liquidations for watched addresses.
Multi-account: one Telegram user can monitor multiple addresses (own + team wallets).
Workflow
Analytics (1-2 days). Protocol list, chains, position types. Determine if Uniswap v3 LP monitoring needed (impermanent loss, out-of-range alerts)—separate module.
Development (3-5 days). Chain listener + position calculator + Telegram bot + PostgreSQL schema. Unit-tests on APY and health factor calculation with RPC mocks.
Deployment and Monitoring. Docker Compose, logs to Loki, metrics to Grafana. SLA on alert: <30 seconds from chain event to Telegram message.
Timeline Expectations
Basic bot for Aave v3 on single chain with health factor alerts—3-4 days. Multi-chain with Aave + Compound + LP position monitoring—1.5-2 weeks. Integration with custom protocol via custom ABI adds 2-3 days.
Cost calculated after requirements analysis.







