Skip to content

Repository files navigation

Telegram Economy Engine

A Telegram bot that gives every group its own gambling economy. Pick Points (free, instant) or ICRC-1 (real ICP, ckBTC, etc. on the Internet Computer). Same dice games, same house edge, swap the backend in one command.

Language: Rust License: MIT Backend: PostgreSQL | ICRC-1 Tests CI crates.io

Quick Start

  1. Create a bot with @BotFather, copy the token.
  2. cp .env.example .env and fill in TELEGRAM_BOT_TOKEN and your PostgreSQL credentials.
  3. cargo run --release
  4. In your Telegram group, type /setup as a group admin.
  5. Any user types /start and gets a starter balance. They type a number to bet.

Total time from cargo run to a working game: under 60 seconds.

Commands

For users

Command What it does
/start Create your account and receive starter balance
/balance Show your balance
/profile Your stats and achievements
/achievements Unlocked achievements
/leaderboard Top 10 players
/deposit Get your deposit address (ICRC-1 rooms)
/withdraw AMOUNT PRINCIPAL Withdraw to external wallet (ICRC-1 rooms)
/help All user commands

Playing: Type any number (e.g. 5) — that's your bet. Pick a game from the buttons the bot sends back.

For group admins

Command What it does
/setup Show room config + treasury health + suggested next step
/treasury Treasury balance and house profit
/stats Economy statistics (24h and all-time)
/setup starter AMOUNT Change the new-user starter balance
/setup edge PERCENT Change the house edge (0–100)
/setup games LIST Enable/disable games (e.g. dice darts slot)
/setup fund AMOUNT Points only: credit (positive) or drain (negative) treasury
/setup mode icrc1|points Switch between real tokens and virtual points
/setup ledger CANISTER ICRC-1 ledger canister (required for icrc1 mode)
/setup token SYM DEC FEE Token symbol, decimals, transfer fee (ICRC-1 only)
/botaddress Show on-chain treasury address (ICRC-1 only)

/configure is supported as a permanent alias for /setup.

Modes

Points ICRC-1
Setup time Instant (one /setup) Ledger canister ID required
Treasury Bot database On-chain ledger
Deposit Not applicable — points come from the bot's treasury User transfers from external wallet to their personal address
Withdraw Not applicable User receives to any ICRC-1 principal
Transfer fee 0 Ledger fee (set by the token)
Best for Casual groups, demos, no-crypto audiences Real-money games, ckBTC/ICP/ICRC-1 token communities

How a round works

  1. User sends /start — bot credits the room's starter balance from the treasury.
  2. (ICRC-1 only) User tops up via /deposit from their own wallet.
  3. User types a number — bot locks it as the bet.
  4. User picks a game from the inline keyboard.
  5. Bot rolls the dice. Win → bot credits reward from treasury. Lose → bet stays with treasury.
  6. Balance is always SUM(credits) − SUM(debits) from an immutable ledger. It can never go negative.

Try It (60-second walkthrough)

  1. Create a bot via @BotFather.
  2. cp .env.example .env, fill in TELEGRAM_BOT_TOKEN + PostgreSQL.
  3. cargo run --release
  4. Add the bot to a Telegram group, promote it to admin.
  5. In the group, type /setup (you're the admin). Bot seeds a Points treasury and starter balance.
  6. From another account, type /start → receive starter balance → type a number → pick a game.

For ICRC-1 mode, swap step 5 with /setup mode icrc1 followed by /setup ledger <canister-id>.

System Guarantees

Guarantee How it's enforced
No double-settlement PostgreSQL UNIQUE constraint on SHA256(room_id‖user_id‖round_millis) in settlement_keys
Ledger always reconciles balance_after stored on every entry; SUM(credits) − SUM(debits) always equals live balance
Balance never goes negative CHECK (balance_after >= 0) on every ledger_entries row — enforced at the schema level
Room isolation Every table and query is room_id-scoped; no cross-room join possible
Achievement writes never block settlement tokio::spawn for async achievement writes
On-chain finality before DB commit ICRC-1 transfer executes first; DB commits only after chain confirmation
Treasury never silently fails /treasury shows ❌ empty / ⚠️ low / ✅ healthy so Points admins spot a depleted house
Deterministic subaccount derivation icrc1_account_id(treasury_principal, Sha256(telegram_user_id)) — same user always gets same address

Settlement Hot Path

Bet arrives from Telegram
        │
        ▼
┌─────────────────────────────────────────────────────────────┐
│ 1. Idempotency Check                                        │
│    INSERT INTO settlement_keys (key) VALUES (sha256(...))   │
│    ON CONFLICT (key) DO UPDATE SET result = existing.result │
│    ← PostgreSQL UNIQUE constraint is the only guard needed   │
│    If conflict: return cached GameSettlement immediately    │
└──────────────────────────────┬──────────────────────────────┘
                               │ (first caller wins the lock)
                               ▼
┌─────────────────────────────────────────────────────────────┐
│ 2. Asset Transfer (ICRC-1 or Points)                        │
│    If ICRC-1: icrc1_transfer() on-chain FIRST              │
│    If Points:  UPDATE ledger + CHECK balance_after >= 0    │
│    On failure: roll back, return error                     │
└──────────────────────────────┬──────────────────────────────┘
                               │ (transfer confirmed)
                               ▼
┌─────────────────────────────────────────────────────────────┐
│ 3. Ledger Write (immutable, append-only)                    │
│    INSERT INTO ledger_entries (room_id, from, to, amount,  │
│      type, balance_after) VALUES (...)                     │
│    balance_after = SUM(credits) - SUM(debits) always       │
└──────────────────────────────┬──────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────┐
│ 4. Achievement (async, non-blocking)                       │
│    tokio::spawn(evaluate_achievements(...))                │
│    Never delays settlement response                         │
└─────────────────────────────────────────────────────────────┘

Benchmark Results

Criterion benchmarks — measured on PostgreSQL 16, single-node, release build:

Benchmark Throughput p50 Latency p99 Latency
balance_of/db_read ~1,660 ops/sec 593 µs ~800 µs
settle_game/losing_bet ~230 ops/sec 4.27 ms ~5.8 ms
settle_game/winning_bet ~155 ops/sec 6.20 ms ~9.1 ms

ICRC-1 chain calls (~400 ms/transfer on live ICP mainnet) are not included — the PointsProvider path above measures DB + in-process latency only. Chain latency dominates in production when using real ICP tokens.

Run: cargo bench --benches

Known Limitations

Limitation Impact Fix path
settlement_keys table has no TTL Long-running deployments accumulate keys; query overhead grows Periodic DELETE WHERE created_at < NOW() - INTERVAL '7 days' migration
Single-process rate limiter Multi-instance deployments share state via Redis Swap RateLimiter (src/router/mod.rs:46) for Redis-backed equivalent
Leaderboard aggregates on read High-traffic rooms compute leaderboard from ledger on every call Materialized view refreshed on settlement, or Redis cache with TTL
ICRC-1 deposit polling not implemented Users who transfer ICP directly to their subaccount (bypassing /deposit) are not auto-credited Background task calling icrc1_get_transactions per known account
Achievement writes are fire-and-forget A DB failure after settlement means the achievement is silently dropped failed_achievement_writes outbox table + background reconciler

Architecture

Telegram Bot API
      │
      ▼
Event Handlers
      │
      ▼
┌─────────────────────────────────┐
│       EconomyEngine             │  Core orchestrator: coordinates
│  (balance, settle, transfer,    │  ledger writes, provider calls,
│   achievements, analytics)     │  and room config in one place
└────────────┬───────────────────┘
             │
    ┌────────┴────────┐
    ▼                 ▼
Achievement        Analytics
System             DAO
    │                 │
    └────────┬────────┘
             ▼
┌──────────────────────────┐
│   AssetProvider Trait   │  Unified interface for all asset types:
│  balance_of / transfer  │  PostgreSQL points or ICRC-1 blockchain
│  account_exists / meta   │  — interchangeable at runtime
└────┬────────────────┬───┘
     │                │
     ▼                ▼
PointsProvider    ICRC1Provider
     │                │
     ▼                ▼
PostgreSQL       Internet Computer
Ledger           Ledger (ic-agent SDK)

Multi-room: every table and query is room_id-scoped.
One deployed bot = thousands of independent economies.

Development Setup

Prerequisites: Rust 1.75+, PostgreSQL 14+ (16 recommended), a Telegram bot token from @BotFather.

# Clone
git clone https://github.com/cordova7/telegram-economy-engine
cd telegram-economy-engine

# Configure
cp .env.example .env
$EDITOR .env  # fill in TELEGRAM_BOT_TOKEN and DATABASE_URL

# Build
cargo build --release

# Run migrations + start the bot
cargo run --release

# In a Telegram group, as admin:
#   /setup

Tests

# Unit + integration tests (needs Postgres)
cargo test

# Benchmarks (optional, takes a few minutes)
cargo bench

Project layout

src/
  main.rs             — entry point, dispatcher wiring
  lib.rs              — library exports
  router/             — message routing, command dispatch, engine cache
  handlers/           — one fn per Telegram command
  views/              — message-text rendering (help text, HTML escape)
  state.rs            — PersistedState (state.json), SharedState
  config.rs           — env-var-driven Config
  room.rs             — Room configuration (provider, token, games, edge)
  game.rs             — Telegram dice → win condition tables
  economy/            — EconomyEngine, AssetProvider, TreasuryReport
  providers/
    points.rs         — PostgreSQL-backed PointsProvider
    icrc1.rs          — ICRC-1 ledger-backed ICRC1Provider
  onboarding.rs       — auto-fund for new users
  database/           — SQL DAOs, schema migrations
  account_id.rs       — ICRC-1 account identifier (CDC) encoding
benches/              — Criterion benchmarks
tests/                — integration tests
migrations/           — SQL schema migrations

Contributing

See CONTRIBUTING.md for the workflow, code style, and audit conventions.

About

A Telegram bot that gives every group its own gambling economy

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages