Розробка Telegram Mini App Dice/Crash
Dice й Crash — два класичних provably-fair жанри. Dice: гравець робить ставку що випадкове число буде вище або нижче порога. Crash: множник зростає з часом, гравець повинен кешаутиться до того як всё впадає. Обидва жанри відлично працюють у Telegram Mini App форматі — простая механіка, швидкі раунди, соціальний елемент.
Provably Fair: математична чесність
Головне відмінність від звичайного казино — криптографічна провабл справедливість. Будь-який користувач може математично перевірити що результат не був підтасований.
Схема для Dice:
- Сервер генерує
serverSeed, публікуєserverSeedHash = SHA256(serverSeed) - Користувач задає
clientSeed(або приймається випадковий) - Результат:
roll = HMAC_SHA256(serverSeed, clientSeed + ":" + nonce) % 10000 - Після раунду сервер розкриває
serverSeed— користувач перевіряє hash
import crypto from 'crypto'
function generateRoll(serverSeed: string, clientSeed: string, nonce: number): number {
const hmac = crypto.createHmac('sha256', serverSeed)
hmac.update(`${clientSeed}:${nonce}`)
const hex = hmac.digest('hex')
// Беремо перші 8 hex символів (4 байти), нормалізуємо в 0-9999
let result = parseInt(hex.slice(0, 8), 16)
result = result % 10000
return result
}
// Користувач може перевірити:
function verify(serverSeed: string, serverSeedHash: string, clientSeed: string, nonce: number, claimedRoll: number): boolean {
const actualHash = crypto.createHash('sha256').update(serverSeed).digest('hex')
if (actualHash !== serverSeedHash) return false
const computedRoll = generateRoll(serverSeed, clientSeed, nonce)
return computedRoll === claimedRoll
}
nonce — інкрементується з кожною ставкою, унікальний для кожного roll. Користувач може змінити clientSeed в будь-який момент — це ротує серверний seed теж (сервер публікує новий hash). Це стандартная схема — використовується на Stake, BC.Game, Roobet.
Crash: алгоритм множника
Crash множник — не по-настоящему випадковий в кожен момент. Генерується заранее для всього раунду, гравці не знають точку краху до її наступлення.
function generateCrashPoint(serverSeed: string, salt: string): number {
const hash = crypto.createHmac('sha256', serverSeed)
.update(salt)
.digest('hex')
// Використовуємо перші 52 біти хеша
const h = parseInt(hash.slice(0, 13), 16)
// Розподіл: P(crash ≥ x) = 1/x (для x >= 1)
// House edge: 1% (кожен 100-й раунд автоматично краш на 1.00x)
if (h % 100 === 0) return 100 // 1% випадків — миттєвий краш
const e = 2 ** 52
return Math.floor((100 * e - h) / (e - h)) / 100
}
Математично дає розподіл: P(crash ≥ 2x) ≈ 50%, P(crash ≥ 10x) ≈ 10%, і т.д. З house edge 1%.
WebSocket для real-time Crash
Crash вимагає real-time оновлення множника — WebSocket обов'язковий:
// Server (Node.js + Socket.io)
io.on('connection', (socket) => {
// Клієнт підключається, отримує поточний стан раунду
socket.emit('round_state', currentRound)
})
// Під час раунду
let multiplier = 1.00
const interval = setInterval(() => {
multiplier *= 1.003 // експоненціальне зростання
if (multiplier >= crashPoint) {
clearInterval(interval)
io.emit('crash', { multiplier: crashPoint })
startNewRound()
} else {
io.emit('tick', { multiplier: parseFloat(multiplier.toFixed(2)) })
}
}, 100) // кожні 100ms
// Frontend (React + socket.io-client)
useEffect(() => {
const socket = io(BACKEND_URL)
socket.on('tick', ({ multiplier }) => {
setMultiplier(multiplier)
})
socket.on('crash', ({ multiplier }) => {
setGameState('crashed')
setCrashPoint(multiplier)
})
socket.on('round_start', (round) => {
setGameState('playing')
setMultiplier(1.00)
})
return () => socket.disconnect()
}, [])
Telegram Mini App специфіка
Ініціалізація й Auth
const tg = window.Telegram.WebApp
tg.ready()
tg.expand()
// Передаємо initData на backend для верифікації
const response = await fetch('/api/auth', {
headers: { 'X-Init-Data': tg.initData }
})
TON платежі
Для реальних ставок — TON/Jetton переводи через TonConnect. Балансы зберігаються off-chain у системі, поповнення/вивід — через blockchain:
// Поповнення: гравець надсилає TON на контракт або hot-гаманець
const depositTx = {
messages: [{
address: DEPOSIT_ADDRESS,
amount: toNano(depositAmount).toString(),
payload: beginCell()
.storeUint(userId, 64) // ID гравця в payload
.endCell()
.toBoc()
.toString('base64')
}],
validUntil: Math.floor(Date.now() / 1000) + 300
}
await connector.sendTransaction(depositTx)
Backend моніторит TON адресу через tonapi.io або toncenter API, зараховує баланс при підтвердженні транзакції.
Telegram Stars для мікроставок
Для невеликих ставок (розважальний режим без реальних грошей) — Telegram Stars:
// Через bot API: створити invoice для Stars
const invoice = await bot.api.createInvoiceLink(
'Deposit 100 Stars',
'Add 100 Stars to game balance',
JSON.stringify({ userId, amount: 100 }),
'', // provider token (пустий для Stars)
'XTR', // валюта Stars
[{ label: '100 Stars', amount: 100 }]
)
Stars не конвертуються напрямо в TON для гри — це окремий ігровий баланс для fun режиму.
Leaderboard й соціальні механіки
// Redis Sorted Set для realtime leaderboard
await redis.zadd('leaderboard:crash:daily', {
score: winAmount,
member: `${userId}:${username}`
})
// Топ 10
const top10 = await redis.zrange('leaderboard:crash:daily', 0, 9, {
rev: true,
withScores: true
})
Соціальний елемент Crash — бачити ставки інших гравців у реалтайм. Публічна лента: хто поставив скільки, хто кешаутився, хто сгорів — це посилює FOMO й retention.
Стек й часові рамки
| Компонент | Технологія |
|---|---|
| Фронтенд | React + Telegram SDK + Chart.js |
| Backend | Node.js + Socket.io + PostgreSQL |
| Cache / realtime | Redis |
| Blockchain | TON + TonConnect |
| Bot | Grammy.js |
Provably fair Dice Mini App з TON балансами: 3-4 тижні. Crash + Dice з публічним leaderboard, реалтайм лентою ставок, реферальною системою: 6-8 тижнів. Юридична складова (ліцензія на азартні ігри) залежить від юрисдикції — це окремий питання, що виходить за рамки розробки.







