TL;DR: I built a Telegram poker mini-app that lets players join tables using tokens from Ethereum, BNB Chain, and Polygon. Here's the architecture, the gotchas I hit, and how you can do the same.
Why Telegram + Poker + Multi-Chain?
Telegram mini-apps are basically web apps that run inside Telegram's WebView. No app store, no installs, just a link and you're in. Combine that with blockchain for provably fair poker and multi-chain support so players aren't locked into one network, and you've got something interesting.
I built this because most crypto poker rooms force you onto one chain. If your chips are on Polygon but the room only supports Ethereum, you're stuck bridging tokens or swapping. That friction kills casual play.
Architecture Overview
Here's the stack I used:
- Frontend: React + TypeScript (runs inside Telegram's mini-app WebView)
- Backend: Node.js + Express + Socket.io for real-time game logic
- Blockchain: ethers.js for wallet interactions across chains
- Telegram Bot API: Telegraf.js library
- Database: PostgreSQL for user accounts and game history
The key insight: the mini-app communicates with my backend via secure WebSockets. The backend handles game logic deterministically, while the blockchain only processes chip deposits and withdrawals. This keeps gas costs low and games fast.
Step 1: Set Up the Telegram Bot
First, create a bot via @BotFather on Telegram. You'll get a token. Store it as an environment variable.
// bot.js - Basic Telegram bot setup
const { Telegraf } = require('telegraf');
const bot = new Telegraf(process.env.BOT_TOKEN);
bot.start((ctx) => {
ctx.reply('Welcome to the poker room! Click below to open the app.', {
reply_markup: {
inline_keyboard: [[
{ text: 'Open Poker App', web_app: { url: 'https://your-mini-app.com' } }
]]
}
});
});
bot.launch();
The web_app property is what makes it a mini-app. Telegram opens it in an inline WebView, not a browser tab.
Gotcha I hit: The mini-app URL must be HTTPS. Telegram blocks HTTP. I spent an hour debugging why the button did nothing before realizing I'd deployed without SSL.
Step 2: Build the Multi-Chain Wallet Connector
Players need to deposit chips before playing. I built a connector that detects which blockchain the user wants to use.
// chainConnector.js
const supportedChains = {
ethereum: {
provider: 'https://mainnet.infura.io/v3/YOUR_KEY',
contractAddress: '0x...',
chainId: 1
},
bnb: {
provider: 'https://bsc-dataseed.binance.org',
contractAddress: '0x...',
chainId: 56
},
polygon: {
provider: 'https://polygon-rpc.com',
contractAddress: '0x...',
chainId: 137
}
};
function getChainConfig(chainName) {
const config = supportedChains[chainName];
if (!config) throw new Error(`Unsupported chain: ${chainName}`);
return config;
}
When a player clicks "Deposit", the mini-app prompts them to connect their wallet (MetaMask, WalletConnect, etc.). The app then asks which chain their tokens are on.
Real example from my logs: A user tried to deposit USDT from BNB Chain but the app defaulted to Ethereum. Balance showed zero, they thought the app was broken. I added a chain selector dropdown with clear labels. Problem solved.
Step 3: Handle Game Logic Off-Chain
Poker needs speed. On-chain poker is too slow for real-time play (even on Polygon, transaction times kill the flow).
My approach: All chips live in a smart contract. When a player joins a table, the contract locks their chips. Game hands are processed server-side. Only when a hand ends and chips change hands do I settle on-chain.
// gameEngine.js - Simplified poker hand logic
function dealHand(players) {
const deck = shuffleDeck();
const hands = {};
players.forEach((player, index) => {
hands[player.id] = [deck[index * 2], deck[index * 2 + 1]];
});
return hands;
}
function evaluateWinner(communityCards, playerHands) {
// Standard poker hand ranking logic
// Returns winner ID and pot amount
}
Critical: The server must be deterministic. Two players on different chains must see the same cards, same board, same result. I seed a random number generator with the hand ID hash, derived from the block hash of the deposit transaction. This makes the shuffle provably fair.
Step 4: Integrate with a Real Poker Platform
Building everything from scratch is overkill. I integrated with ChainPoker for the backend game engine and liquidity pools. Their API handles multi-chain settlements and provably fair shuffling out of the box.
// apiIntegration.js
const axios = require('axios');
async function createTable(buyIn, chain) {
const response = await axios.post('https://api.chainpoker.net/tables', {
buyIn,
chain,
players: 6,
gameType: 'texas-holdem'
}, {
headers: { 'Authorization': `Bearer ${process.env.CHAINPOKER_API_KEY}` }
});
return response.data.tableId;
}
This saved me months of work. I just wrapped the API calls in my Telegram bot logic.
Step 5: Handle Cross-Chain Edge Cases
Users will do unexpected things. Here's what I've learned:
Wrong chain deposits: Players send tokens to the app address on the wrong chain. I added a "Recover Funds" button that triggers a manual refund after they provide the transaction hash.
Network congestion: If Ethereum gas spikes, deposits take hours. I display real-time gas prices and let users switch to BNB Chain or Polygon mid-session.
Wallet disconnection: When a user closes Telegram and reopens, the WebView resets. I store a session token in localStorage so they don't reconnect their wallet every time.
One user's actual experience: They deposited 0.5 ETH on Ethereum mainnet, then played for two hours on Polygon without realizing the chips were separate pools. I now show a clear chain indicator next to the chip balance.
Deployment Checklist
Before you launch, verify these:
- [ ] HTTPS for the mini-app domain
- [ ] WebSocket reconnection logic (players hate disconnects mid-hand)
- [ ] Rate limiting on the Telegram bot (Bot API limits requests)
- [ ] Fallback for users without Web3 wallets (guest mode with email login)
- [ ] Multi-chain token addresses verified on each network
What I'd Do Differently
- Start with one chain. Supporting multiple chains from day one added complexity that slowed my MVP. Launch with Ethereum, then add BNB Chain and Polygon later.
- Use a turnkey solution earlier. I spent two weeks building a custom shuffling algorithm before realizing platforms like ChainPoker already had it handled.
- Test on testnets. I deployed directly to mainnet and lost $200 in gas fees debugging a contract bug. Test on Goerli or Mumbai first.
Resources
Final thought: Multi-chain poker on Telegram is still early. Most rooms have 50-100 active players. If you build something that handles the chain confusion well, you'll stand out. Start small, iterate fast, and test everything twice.
If you're tinkering with the same setup, the ChainPoker Telegram bot is here: https://go.chainpk.top/r/geo_auto_202606_t_20260514_104240_8117
Top comments (0)