
DeFi Bots Series — Part 3: Telegram Bot Lite, Portfolio RPC, and a Lean Path to the Scheduler
TL;DR — I turned the Telegram bot into a lean, production-friendly surface that our upcoming DeFi strategy scheduler can ping directly. We kept Redis and Supabase, disabled Kafka, removed AI-agent hops for core commands, pulled SOL & SPL balances via RPC, fetched prices via Jupiter V3, stitched PnL to Supabase, and made the UI snappy with proper inline buttons + pagination. It’s the calm before the orchestration storm.
Why a “Lite” bot?
For the last six months I worked with the Singapore crew at taigo.ai. I built (and rebuilt) a fair bit:
- Telegram MiniApp + auth and wallet UX (Privy)
- Big refactors across the Telegram bot
- The DeFi server that powers execution:
- Meteora DLMM (open/close/rebalance)
- Jupiter swaps
- pump.fun flows
- Jito tips and tx-acceleration ergonomics
That stack got feature-rich. Which is great… until you need to ship a focused scheduler that opens positions, monitors them, and reacts. I want one narrow surface: a bot that tells me what’s going on and receives alerts—not a festival of agents and brokers.
So I made the bot Lite:
- keep Redis, Supabase, Privy;
- no Kafka;
- no AI agent for basic commands (/start, /asset, /wallet, /delegate);
- keep the door open to reintroduce agents later behind a flag, not in the hot path.
The vibe: progress in chat
ObCat, [28/9/25 23:45]
/start
AIGEXbot, [28/9/25 23:45]
✅ Received. (Lite mode: Kafka disabled)
ObCat, [29/9/25 1:18]
/asset
AIGEXbot, [29/9/25 1:18]
✅ Received. (Lite mode: Kafka disabled)
ObCat, [29/9/25 2:49]
/start
AIGEXbot, [29/9/25 2:49]
💼 Your Wallet
━━━━━━━━━━━━━━━━━━
💳 Wallet Type: privy
📍 Address: 2yhmpEANAmircavh8wRJgWBcCYzUcb3gP88peqpTrQ5b
💰 Balance: 0.1959 SOL (~$41.11)
💵 Price: $209.8456/SOL
AIGEXbot, [29/9/25 2:49]
Hello! I'm Taigo — your smart crypto assistant!
Taigo in, Easy win!
✅ Check holdings: /asset
✅ Manage wallet: /wallet
✅ Monitor LPs: /monitor
ObCat, [29/9/25 3:10]
/wallet
AIGEXbot, [29/9/25 3:10]
✅ Received. (Lite mode: Kafka disabled)
ObCat, [29/9/25 3:29]
/asset
AIGEXbot, [29/9/25 3:30]
My Holdings
💎 SOL: 0.1959 SOL ($ 40.93) — Price $ 208.94/SOL
💳 Wallet: 2yhmpEANAmircavh8wRJgWBcCYzUcb3gP88peqpTrQ5b
📊 Portfolio: $ 72.34 (Tokens: $ 31.41 + SOL: $ 40.93)
📌 USDC (https://t.me/aigex_miniapp_bot?start=trade-EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v-USDC)
💰 0.0671 SOL ($14.01)
💵 Price: $0.999611 🎉 PnL: +%
📌 6p6x…GiPN
💰 0.0408 SOL ($8.52)
💵 Price: $7.630838 🎉 PnL: +%
📌 C3Dw…pump
💰 0.0131 SOL ($2.73)
💵 Price: $0.014445 🎉 PnL: +%
📌 NFTLX (https://t.me/aigex_miniapp_bot?start=trade-BkCjdHWuSxFhzZhqD9kMnKtV4edkpobmxVowsB5cLgar-NFTLX)
💰 0.0076 SOL ($1.58)
💵 Price: $0.{4}22 🎉 PnL: +%
📌 6W4g…pump
💰 0.006 SOL ($1.26)
💵 Price: $0.{5}4 🎉 PnL: +%
*Page 1/4 — Tap token to trade.
ObCat, [29/9/25 3:36]
/wallet
AIGEXbot, [29/9/25 3:36]
💼 Your Wallet
━━━━━━━━━━━━━━━━━━
💳 Type: privy
📍 Solana: 2yhmpEANAmircavh8wRJgWBcCYzUcb3gP88peqpTrQ5b
💰 SOL: 0.1959 SOL (~$ 41.06) — Price $ 209.62/SOL
📊 Portfolio: $ 72.47 (Tokens: $ 31.41 + SOL: $ 41.06)
🔑 Delegation ID: None
ObCat, [29/9/25 4:02]
/delegate
AIGEXbot, [29/9/25 4:02]
✅ You're currently delegated. To revoke server-side consent, click below:Tiny detail, big payoff: the bot now feels instant and honest about what it’s doing.
What I changed (and why)
1) A single Lite flag controls the surface
.env.lite:LITE_MODE=1- Load it early in
aigexbot/__init__.pyso imports see it. - Expose
is_lite()inbot_instance.py. - In
bot_server/__init__.py, conditional imports keep Kafka out of the process in Lite.
# bot_server/__init__.py
from aigexbot.telegram_bot.bot_instance import is_lite
if not is_lite():
from aigexbot.telegram_bot.kafka.client import KafkaClient
from aigexbot.telegram_bot.kafka.consumer_service import KafkaConsumerServiceResult: no accidental Kafka connection attempts before the app even starts.
2) Handlers now do the work—no agent round-trips
Old flow: Telegram → Kafka → AI agent → back again, even for /start. New flow: Telegram handles directly:
/start: shows wallet + SOL balance + SOL USD price (via WSOL)./asset: pulls SPL tokens, prices via Jupiter V3, PnL via Supabase./wallet: same info, with buttons to open/disconnect in MiniApp./delegate: talks to Privy and MiniApp directly.
Cleaner. Faster. Fewer moving pieces to babysit.
3) On-chain balances via native RPC, not Birdeye
Birdeye got pricey and gated. I switched to pure RPC (with simple caching):
getBalance→ SOLgetTokenAccountsByOwner(jsonParsed) → SPL balances (mint, decimals, uiAmount)
# portfolio.py (excerpt)
async def get_spl_tokens(owner: str) -> List[dict]:
body = {"jsonrpc": "2.0","id":1,"method":"getTokenAccountsByOwner",
"params":[owner, {"programId": TOKEN_PROGRAM_ID}, {"encoding":"jsonParsed"}]}
# parse tokenAmount.uiAmount/amount, filter > 0No API keys, no drama. If you run a private endpoint, just set:
SOLANA_RPC_URL=https://your-preferred-rpc
SOLANA_RPC_FALLBACKS=https://fallback-1,https://fallback-24) Prices via Jupiter Price API v3
I fetch up to 50 mints per call and cache them briefly. I also include WSOL to price SOL in USD, then compute token USD values and portfolio totals. Sustainable and consistent with what we use elsewhere.
async def get_prices(mints: List[str]) -> Dict[str, float]:
r = await http.get("https://lite-api.jup.ag/price/v3", params={"ids": ",".join(mints)})
return {k: float(v["usdPrice"]) for k, v in r.json().items() if "usdPrice" in v}5) PnL from Supabase (no Golang proxy)
We used to call a Go webapp that called Supabase. I cut out the middle-hop:
- Replaced
WebAppServerAPIClient.get_user_info/get_privy_idwith direct Supabase queries. - Kept the same response shape so nothing else breaks.
- PnL path uses
trading_tx_recordsmath; if there’s no data yet, it degrades gracefully.
# storage/supabase.py (concept)
supabase_client.table("user_info").select(...).eq("user_id", uid).eq("bot_id", bot).eq("source", MessageSource.TELEGRAM.value)Buttons that actually do something
- Pagination for
/asset: asset_page::<n> - Refresh button:
refresh_assets - Token trade deep-link:
https://t.me/<bot>?start=trade-<mint>-<SYMBOL>
Callbacks route back to the same handler, which edits the previous message in place. Feels native.
Architecture, zoomed out
This isn’t just a cleanup. It’s the foundation for the scheduler (from [Part 2]).
- The orchestrator will run in the DeFi server, kick off strategies (monitor, LP-copy, etc).
- The bot is now a passive receiver and dashboard:
- show holdings / PnL
- dump alerts (TP/SL/rebalance)
- open links to execute flows (MiniApp or direct actions)
- We left enough hooks to expand, but the default path is tight.
What this unlocks (for the scheduler)
- Low-latency notifications straight from the DeFi server
- No need to keep an AI agent, Kafka, and a Go service warm just to say “hey, TP hit”
- Deterministic pricing + balances from sources we already trust in execution
- PnL in the chat tied to the same Supabase the executors write to
Philosophy: make the control surface boring and reliable so the strategy brain can be spicy.
Gotchas & guardrails
- RPC rate limits exist. I added tiny caches (seconds). If you scale up, consider a private RPC or batching.
- Jupiter V3 sometimes won’t price dead tokens; I skip those in the portfolio view.
- Token symbol/name mapping: quick wins from Jupiter token list or cached registry—easy to slot in.
- PnL only sings once
trading_tx_recordshas data. That’s fine; it’s ready when you are. - Keep
LITE_MODEas an explicit choice. Don’t silently fall back.
Credits & context
This journey started with taigo.ai—I shipped their MiniApp, a large refactor of the Telegram bot, and the DeFi server (Meteora DLMM, Jupiter, pump.fun, Jito, “next block”, tx accel). The Lite refactor is me being a smart, modest motherf— (hi, mom) about what actually matters before we spin up the autonomous scheduler.
Less ceremony. More signal.
What’s next
- Wire the scheduler to push position lifecycle updates to Telegram.
- Flip dry-run → live for one controlled user and one strategy.
- Add token metadata mapping for friendlier names everywhere.
- Optional: bring back an LLM helper, but as a sidecar—not in the critical path.
If you’re building something similar, steal shamelessly. And if your bot feels sluggish, remember: sometimes the bravest thing is to delete code.
Stay Updated
Get notified when I publish new articles about Web3 development, hackathon experiences, and cryptography insights.
You might also like

DeFi Bots Series — Part 5: Live Rebalance on Meteora DLMM (RPC Profiles, Clean PnL & One-Sided Liquidity)
I rewired RPC handling with role-based profiles, unified LP strategy controls, fixed PnL accounting, and executed a live one-sided rebalance on a PUMP/USDC DLMM pool over gRPC—end to end with Supabase ledgering.

DeFi Bots Series — Part 4: Prepping the Monitor — Decimals, Prices, Symbols & Clean Balances
Before we let the monitor act on positions, we hardened the boring bits: one source of truth for decimals, fast prices, safe BigInt math, and clean balance reads. The goal is simple: trustworthy PnL so alerts and actions are correct.

DeFi Bots Series — Part 7: The Monitor Test Saga (One-Sided Bids, Skew Rebalances, and Real PnL)
I stress-tested a one-sided, USDC-anchored LP strategy overnight: ~15 rebalances, lots of fee accrual, a few bugs, and a clearer picture of what to fix next. We tightened pool orientation, made SOL/WSOL funding sane, added skew gates (TVL/fees), and wrote proper lineage + flows. The monitor is quieter—until it needs not to be.