Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions examples/telegram-bot-integration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# Telegram Bot Integration β€” TGE Discord Agent

Autonomous TGE monitoring agent that watches Discord, discovers markets via x402, and trades on Polymarket.

## Architecture

```
Discord Channel
β†’ TGE Discord Agent (Supabase Edge Function)
β†’ Step 1: Monitor Discord messages for TGE keywords
β†’ Step 2: x402 tool discovery (PayAI bazaar)
β†’ Step 3: Fetch market data via x402 β†’ Dome API
β†’ Step 4: Execute trade via Polymarket CLOB
β†’ JSON Response
β†’ Telegram notification + trade confirmation
```

## Setup

1. Deploy PredictOS locally

```
cd supabase
supabase start
supabase functions serve --env-file .env.local
```

2. Required environment variables

```bash
# Edge function
DISCORD_TOKEN="your_discord_bot_token"
DOME_API_KEY="your_dome_api_key"
X402_DISCOVERY_URL="https://bazaar.payai.network/api/v1/resources"
POLYMARKET_WALLET_PRIVATE_KEY="your_eoa_private_key"
POLYMARKET_PROXY_WALLET_ADDRESS="your_safe_wallet_address"

# Python bot
PREDICTOS_URL="http://127.0.0.1:54321/functions/v1"
PREDICTOS_KEY="your_supabase_anon_key"
TELEGRAM_TOKEN="your_telegram_bot_token"
```

3. Install Python dependencies

```
pip install requests python-telegram-bot
```

4. Run the bot

```
python bot_example.py
```

## Usage

### One-time check (no trade)

```python
from client import PredictOSClient

client = PredictOSClient()
result = client.check_tge(channel_id="1072952844161916938")
```

### Auto-trade on detection

```python
result = client.check_tge(
channel_id="1072952844161916938",
market_slug="will-x-launch-tge-2025",
auto_trade={
"side": "YES",
"budget_usdc": 10,
"min_confidence": 0.6,
},
)

if result.get("trade", {}).get("success"):
print(f"Bought {result['trade']['size']} shares!")
```

### Telegram bot commands

- **Check TGE** β€” one-time check on a selected project
- **Start Monitor** β€” polls every 60s with auto-trade enabled
- **Stop Monitor** β€” stops the polling loop

## Production

```
supabase functions deploy tge-discord-agent
```

Update `PREDICTOS_URL` to your production Supabase URL.

## Integration Points

- **Privy**: Connect wallet on PredictOS frontend for browser-based trading
- **Custom bots**: Use `client.py` as HTTP wrapper from any Python app
- **Direct HTTP**: POST to `/functions/v1/tge-discord-agent` from any language

## Support

- Repo: https://github.com/PredictionXBT/PredictOS
- Twitter: @prediction_xbt
206 changes: 206 additions & 0 deletions examples/telegram-bot-integration/bot_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
"""
Telegram Bot Example - TGE Discord Monitoring via PredictOS

Shows how a bot integrates with the TGE Discord Agent:
- Agent handles detection (Discord + Dome + x402)
- Bot handles trading (user's own wallet from DB)
"""

import os
import asyncio
from typing import Dict, Any

from telegram import Update, ReplyKeyboardMarkup, KeyboardButton
from telegram.ext import Application, CommandHandler, MessageHandler, ContextTypes, filters

from client import PredictOSClient


predictos = PredictOSClient()

# Project configs: Discord channel + Polymarket market
PROJECTS: Dict[str, Dict[str, Any]] = {
"Base": {
"channel_id": "1072952844161916938",
"market_slug": "will-base-launch-tge",
"side": "YES",
},
"Opinion": {
"channel_id": "your_opinion_channel_id",
"market_slug": "will-opinion-launch-token",
"side": "YES",
},
}

_monitors: Dict[int, bool] = {}


def format_signal(signal: Dict[str, Any], project: str) -> str:
if not signal.get("detected"):
return f"[{project}] No TGE detected."

lines = [
f"[{project}] TGE DETECTED",
f"Confidence: {signal.get('confidence', 0):.0%}",
f"Keywords: {', '.join(signal.get('keywords', []))}",
f"Action: {signal.get('recommendation', 'N/A')}",
]

msg = signal.get("message")
if msg:
lines.append(f"\nSignal: {msg.get('content', '')[:200]}")

# Dome market data
for m in signal.get("dome_markets", []):
prices = m.get("outcome_prices", [])
yes_price = f"{prices[0]*100:.0f}%" if prices else "?"
lines.append(f"\nMarket: {m['question']}")
lines.append(f" YES: {yes_price} | Vol: ${m.get('volume', 0):,.0f}")

# x402 info
tool = signal.get("tool_discovery")
if tool:
lines.append(f"\nx402: {tool['name']}")

return "\n".join(lines)


async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if not update.message:
return
keyboard = [
[KeyboardButton("Check TGE"), KeyboardButton("Start Monitor")],
[KeyboardButton("Stop Monitor")],
]
await update.message.reply_text(
"TGE Discord Agent (powered by PredictOS)\n\n"
"Check TGE - one-time signal check\n"
"Start Monitor - auto-poll every 60s\n"
"Stop Monitor - stop polling",
reply_markup=ReplyKeyboardMarkup(keyboard, resize_keyboard=True),
)


async def check_tge(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if not update.message:
return
keyboard = [[KeyboardButton(p) for p in PROJECTS], [KeyboardButton("Back")]]
await update.message.reply_text(
"Select project:",
reply_markup=ReplyKeyboardMarkup(keyboard, resize_keyboard=True),
)
context.user_data["mode"] = "check"


async def start_monitor(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if not update.message:
return
keyboard = [[KeyboardButton(p) for p in PROJECTS], [KeyboardButton("Back")]]
await update.message.reply_text(
"Select project to monitor:",
reply_markup=ReplyKeyboardMarkup(keyboard, resize_keyboard=True),
)
context.user_data["mode"] = "monitor"


async def handle_selection(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if not update.message:
return

project = update.message.text
mode = context.user_data.pop("mode", None)

if project not in PROJECTS:
await update.message.reply_text("Unknown project.")
return

config = PROJECTS[project]

if mode == "monitor":
chat_id = update.message.chat_id
if _monitors.get(chat_id):
await update.message.reply_text("Already monitoring. Stop first.")
return

_monitors[chat_id] = True
await update.message.reply_text(f"Monitoring {project} every 60s...")

async def poll() -> None:
while _monitors.get(chat_id):
try:
signal = await asyncio.to_thread(
predictos.detect,
channel_id=config["channel_id"],
market_slug=config.get("market_slug"),
)
if signal.get("detected"):
msg = format_signal(signal, project)
confidence = signal.get("confidence", 0)

if confidence >= 0.6:
# ── YOUR BOT TRADES HERE ──
# user_wallet = get_wallet_from_db(chat_id)
# clob = create_clob_client(user_wallet)
# clob.place_order(tokenId=..., price=..., side="BUY")
msg += "\n\n>> Your bot would execute trade here <<"

await context.bot.send_message(chat_id=chat_id, text=msg)
except Exception as exc:
await context.bot.send_message(chat_id=chat_id, text=f"Error: {exc}")
await asyncio.sleep(60)

asyncio.create_task(poll())
return

# One-time check
loading = await update.message.reply_text(f"Checking {project}...")
signal = await asyncio.to_thread(
predictos.detect,
channel_id=config["channel_id"],
market_slug=config.get("market_slug"),
)
await loading.delete()
await update.message.reply_text(format_signal(signal, project))


async def stop_monitor(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if not update.message:
return
chat_id = update.message.chat_id
if _monitors.pop(chat_id, None):
await update.message.reply_text("Stopped.")
else:
await update.message.reply_text("No monitor running.")


async def router(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if not update.message:
return
text = update.message.text
if context.user_data.get("mode"):
await handle_selection(update, context)
elif text == "Check TGE":
await check_tge(update, context)
elif text == "Start Monitor":
await start_monitor(update, context)
elif text == "Stop Monitor":
await stop_monitor(update, context)
elif text == "Back":
await start(update, context)


def main() -> None:
token = os.getenv("TELEGRAM_TOKEN")
if not token:
print("TELEGRAM_TOKEN not set")
return

app = Application.builder().token(token).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, router))
print("Bot started")
app.run_polling()


if __name__ == "__main__":
main()
Loading