Разработка Telegram Mini App Dice/Crash
Dice и Crash — два классических провабли-фэйр жанра. Dice: игрок делает ставку на то, что случайное число окажется выше или ниже порога. Crash: множитель растёт с течением времени, игрок должен кешаутиться до того как всё «падает». Оба жанра отлично работают в Telegram Mini App формате — простая механика, быстрые раунды, социальный элемент.
Provably Fair: математическая честность
Главное отличие от обычного казино — cryptographic provably fairness. Любой пользователь может математически проверить что результат не был подтасован.
Схема для 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% случаев — instant crash
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 для реалтайм Crash
Crash требует реалтайм обновление множителя — 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 на контракт или хот-кошелёк
const depositTx = {
messages: [{
address: DEPOSIT_ADDRESS,
amount: toNano(depositAmount).toString(),
payload: beginCell()
.storeUint(userId, 64) // идентификатор игрока в 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:
// Через бот 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.
Стек и сроки
| Компонент | Технология |
|---|---|
| Frontend | React + Telegram SDK + Chart.js |
| Backend | Node.js + Socket.io + PostgreSQL |
| Кэш / realtime | Redis |
| Blockchain | TON + TonConnect |
| Бот | Grammy.js |
Provably fair Dice Mini App с TON балансами: 3-4 недели. Crash + Dice с публичным leaderboard, реалтайм лентой ставок, реферальной системой: 6-8 недель. Юридическая составляющая (лицензия на азартные игры) зависит от юрисдикции — это отдельный вопрос, выходящий за рамки разработки.







