Skip to content

Refactor Telegram bot to fetch hot Solana pairs - #38

Open
drzhivago123 wants to merge 1 commit into
aeither:mainfrom
drzhivago123:patch-2
Open

drzhivago123 wants to merge 1 commit into
aeither:mainfrom
drzhivago123:patch-2

Conversation

@drzhivago123

@drzhivago123 drzhivago123 commented Mar 23, 2026 •

Copy link
Copy Markdown

Summary by CodeRabbit

Release Notes

  • New Features

    • Added an interactive Telegram menu with button-driven commands for accessing different features
    • Hot Solana Picks now fetches and ranks live Solana trading pair data from the network
    • Introduced Market Summary and Help buttons with informational content
  • Bug Fixes

    • Removed the global echo-all message behavior
    • Streamlined bot startup and initialization

@coderabbitai

coderabbitai Bot commented Mar 23, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Refactors Telegram bot initialization to use a simplified flow. Removes the echo-all message behavior and /hello command. Introduces menu-driven functionality with handlers for /start command, "Hot Solana Picks" (fetches and ranks Solana pair data from Dexscreener), market summary, help text, and a fallback text handler. Adds get_hot_pairs() function to handle external API requests.

Changes

Cohort / File(s) Summary
Bot Initialization & Handlers
main.py
Replaced dotenv-based startup with direct bot initialization. Removed echo-all and /hello handlers. Added keyboard menu builder, /start handler, and button handlers for "Hot Solana Picks" (network-driven), "Market Summary", "Help", and a fallback text handler. Added get_hot_pairs() function that performs HTTP GET to Dexscreener's Solana pairs endpoint, parses JSON response, filters pairs by liquidity/volume/price-change thresholds, computes a ranking score, and returns top 5 results or error dict.

Sequence Diagram

sequenceDiagram
    participant User as User (Telegram)
    participant Bot as Telegram Bot
    participant API as Dexscreener API

    User->>Bot: Click "🔥 Hot Solana Picks" button
    Bot->>API: GET /dex/tokens/solana
    API-->>Bot: JSON response with Solana pairs data
    Bot->>Bot: Filter by liquidity, volume, price-change
    Bot->>Bot: Compute ranking score & sort
    Bot-->>User: Send top 5 hot picks (or error message)
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Hopping through the code with glee,
A simpler bot flow now I see!
Hot Solana picks from Dexscreener's call,
A menu-driven magic for one and all! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes the main change: refactoring the Telegram bot to fetch hot Solana pairs, which aligns with the core functionality addition of the get_hot_pairs() function and the new 'Hot Solana Picks' handler.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
main.py (4)

119-119: Add if __name__ == "__main__": guard.

bot.infinity_polling() runs at import time, which prevents importing this module for testing or reuse without starting the bot.

♻️ Proposed fix
-bot.infinity_polling()
+if __name__ == "__main__":
+    bot.infinity_polling()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main.py` at line 119, The module currently calls bot.infinity_polling() at
import time; wrap that call in a main guard by moving bot.infinity_polling()
inside an if __name__ == "__main__": block so the bot only starts when the
script is executed directly (locate the existing bot.infinity_polling()
invocation and enclose it in the guard).

45-49: Inconsistent return type: list vs dict.

get_hot_pairs() returns a list on success but a dict on error. This forces the caller to use isinstance() checks. Consider raising an exception or returning an empty list with logged error for consistency.

♻️ Proposed fix using exception
     except Exception as e:
-        return {"error": str(e)}
+        logger.error("Failed to fetch hot pairs: %s", e)
+        raise

Then update the handler:

 def hot_picks_handler(message):
     bot.send_message(message.chat.id, "Scanning Solana pairs...")
 
-    results = get_hot_pairs()
-
-    if isinstance(results, dict) and results.get("error"):
-        bot.send_message(message.chat.id, f"Error fetching market data:\n{results['error']}")
-        return
+    try:
+        results = get_hot_pairs()
+    except Exception as e:
+        bot.send_message(message.chat.id, f"Error fetching market data:\n{e}")
+        return
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main.py` around lines 45 - 49, get_hot_pairs() currently returns a list on
success but a dict on error; change it to raise the caught exception instead of
returning {"error": str(e)} so the return type stays a list on success and
errors are handled via exceptions. Replace the "return {"error": ...}" in
get_hot_pairs() with "raise" (propagate the exception) and update the calling
code (the request handler or whichever function invokes get_hot_pairs()) to
catch exceptions, log the error, and return an appropriate HTTP response or an
empty list as the API contract requires.

59-65: Consider cleaning up orphaned commands.py and registering commands.

The commands.py module (which defines register_commands()) is no longer imported or called, leaving it as dead code. Additionally, without calling bot.set_my_commands(), Telegram's command autocomplete menu won't show available commands to users.

Either:

  1. Delete commands.py if command registration is not needed
  2. Or register the /start command for Telegram's autocomplete:
from telebot.types import BotCommand

bot.set_my_commands([BotCommand("start", "Start the bot")])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main.py` around lines 59 - 65, The commands.py module (and its
register_commands()) is orphaned or command registration is missing; either
remove commands.py if unused, or import and call register_commands() at startup
and explicitly register Telegram commands by calling bot.set_my_commands(...)
with a list of telebot.types.BotCommand entries (e.g. for "start") so the /start
command (handled by start_handler) appears in Telegram's autocomplete; update
the main bootstrap to perform this registration before the bot starts polling.

42-43: Silent exception swallowing hinders debugging.

When parsing fails for a pair, the exception is silently discarded. Consider logging the exception for debugging purposes, especially in a bot context where issues may be hard to reproduce.

♻️ Proposed fix
+import logging
+
+logger = logging.getLogger(__name__)

Then in the function:

             except Exception:
-                continue
+                logger.debug("Skipping malformed pair data: %s", p.get("pairAddress", "unknown"))
+                continue
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main.py` around lines 42 - 43, Replace the silent broad except that just does
"except Exception: continue" with logging of the exception and contextual data
before continuing: catch Exception as e (the same except block), call
logger.exception or logging.exception with a message that includes the relevant
parsing item identifier (e.g., the pair variable or input being parsed) and the
exception, then continue; update the except block inside the function that
contains the "except Exception: continue" to ensure errors are recorded (use
logger.exception("Failed parsing pair %s", pair, exc_info=True) or equivalent).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@main.py`:
- Around line 5-6: The code currently passes TOKEN =
os.getenv("TELEGRAM_BOT_TOKEN") directly into TeleBot(TOKEN) which will raise a
cryptic error when the env var is missing; add an explicit validation after
retrieving TOKEN (before calling TeleBot) that checks if TOKEN is None or empty
and fail fast with a clear message (raise SystemExit or ValueError or log and
sys.exit) indicating that TELEGRAM_BOT_TOKEN is not set, so the TeleBot(...)
call only runs with a valid token.

---

Nitpick comments:
In `@main.py`:
- Line 119: The module currently calls bot.infinity_polling() at import time;
wrap that call in a main guard by moving bot.infinity_polling() inside an if
__name__ == "__main__": block so the bot only starts when the script is executed
directly (locate the existing bot.infinity_polling() invocation and enclose it
in the guard).
- Around line 45-49: get_hot_pairs() currently returns a list on success but a
dict on error; change it to raise the caught exception instead of returning
{"error": str(e)} so the return type stays a list on success and errors are
handled via exceptions. Replace the "return {"error": ...}" in get_hot_pairs()
with "raise" (propagate the exception) and update the calling code (the request
handler or whichever function invokes get_hot_pairs()) to catch exceptions, log
the error, and return an appropriate HTTP response or an empty list as the API
contract requires.
- Around line 59-65: The commands.py module (and its register_commands()) is
orphaned or command registration is missing; either remove commands.py if
unused, or import and call register_commands() at startup and explicitly
register Telegram commands by calling bot.set_my_commands(...) with a list of
telebot.types.BotCommand entries (e.g. for "start") so the /start command
(handled by start_handler) appears in Telegram's autocomplete; update the main
bootstrap to perform this registration before the bot starts polling.
- Around line 42-43: Replace the silent broad except that just does "except
Exception: continue" with logging of the exception and contextual data before
continuing: catch Exception as e (the same except block), call logger.exception
or logging.exception with a message that includes the relevant parsing item
identifier (e.g., the pair variable or input being parsed) and the exception,
then continue; update the except block inside the function that contains the
"except Exception: continue" to ensure errors are recorded (use
logger.exception("Failed parsing pair %s", pair, exc_info=True) or equivalent).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d93aff8a-1a1b-42d7-88fb-2c5ab123a864

📥 Commits

Reviewing files that changed from the base of the PR and between 5cfd740 and 1356491.

📒 Files selected for processing (1)
  • main.py

Comment thread main.py
Comment on lines +5 to +6
TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
bot = TeleBot(TOKEN)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Missing validation for TELEGRAM_BOT_TOKEN environment variable.

If TELEGRAM_BOT_TOKEN is not set, TOKEN will be None, causing TeleBot(None) to fail with a cryptic error at runtime. Add validation to fail fast with a clear message.

🛡️ Proposed fix
 TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
+if not TOKEN:
+    raise RuntimeError("TELEGRAM_BOT_TOKEN environment variable is required")
 bot = TeleBot(TOKEN)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
bot = TeleBot(TOKEN)
TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
if not TOKEN:
raise RuntimeError("TELEGRAM_BOT_TOKEN environment variable is required")
bot = TeleBot(TOKEN)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main.py` around lines 5 - 6, The code currently passes TOKEN =
os.getenv("TELEGRAM_BOT_TOKEN") directly into TeleBot(TOKEN) which will raise a
cryptic error when the env var is missing; add an explicit validation after
retrieving TOKEN (before calling TeleBot) that checks if TOKEN is None or empty
and fail fast with a clear message (raise SystemExit or ValueError or log and
sys.exit) indicating that TELEGRAM_BOT_TOKEN is not set, so the TeleBot(...)
call only runs with a valid token.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant