Розробка Telegram Mini App для криптокошелька
Telegram Mini App (TMA) — веб-приложення, вбудоване в Telegram через WebView. Доступно 900+ мільйонам користувачів без установки окремого додатку. Для криптокошелька це радикально змінює onboarding: замість "скачай додаток → створи seed phrase → запиши 12 слів → не втрати" — просто відкрий бота в Telegram.
Але TMA-кошелек накладає жорсткі обмеження: немає доступу до файлової системи, localStorage ненадійний (Telegram може очистити в будь-який момент), WebView на iOS обмежений у crypto API, і головне — зберігати seed phrase у TMA небезпечно. Це визначає архітектурний вибір: або custodial, або MPC, або embedded wallet через Account Abstraction.
Технічна платформа
TON vs EVM
Два основні варіанти для TMA-кошелька:
TON (The Open Network) — нативна інтеграція з Telegram. TON Space (вбудований у Telegram кошелек) вже використовує TON. TonConnect протокол — стандарт для dApp підключень у TON екосистемі. SDK: @tonconnect/sdk, @ton/core. Аудиторія TON вже у Telegram, екосистема DeFi растет швидко.
EVM через Abstract Wallet. Кошелек для Ethereum/BSC/Polygon у TMA — ширша DeFi екосистема, але немає нативної інтеграції. Використовується Web3Auth, Privy, або власний MPC backend. Підходить якщо ваша аудиторія орієнтована на існуючий EVM DeFi.
Комбінований підхід: TON для нативних TG активностей + EVM для DeFi. Технічно складніше, але дає максимальне покриття.
Telegram WebApp API
// Інициалізація TMA
import WebApp from '@twa-dev/sdk';
WebApp.ready(); // сигналізуємо Telegram що додаток готовий
WebApp.expand(); // розворачиваємо на весь екран
// Дані користувача (ВАЖЛИВО: верифікувати на сервері)
const user = WebApp.initDataUnsafe.user;
// initData — строка для верифікації підпису Telegram
// Кнопки
WebApp.MainButton.setText('Підтвердити транзакцію');
WebApp.MainButton.onClick(() => handleTransaction());
WebApp.MainButton.show();
// Haptic feedback для транзакцій
WebApp.HapticFeedback.notificationOccurred('success');
// Колірна схема Telegram
const isDark = WebApp.colorScheme === 'dark';
Верифікація initData на сервері — обов'язкова для будь-якої wallet операції:
// Backend: Node.js
import crypto from 'crypto';
function verifyTelegramData(initData: string, botToken: string): boolean {
const params = new URLSearchParams(initData);
const hash = params.get('hash');
params.delete('hash');
const dataCheckString = Array.from(params.entries())
.sort(([a], [b]) => a.localeCompare(b))
.map(([k, v]) => `${k}=${v}`)
.join('\n');
const secretKey = crypto
.createHmac('sha256', 'WebAppData')
.update(botToken)
.digest();
const expectedHash = crypto
.createHmac('sha256', secretKey)
.update(dataCheckString)
.digest('hex');
return hash === expectedHash;
}
Telegram підписує initData ботовим токеном. Підробити без знання токена неможливо. Кожен запит до wallet API повинен включати initData й проходити цю перевірку.
Архітектура кошелька: три підходи
1. Custodial з MPC backend
Користувач не управляє ключами безпосередньо. Платформа зберігає ключі в MPC (кілька серверних шардів). Ідентифікація: telegram_user_id.
User (TMA) → Backend API (initData verification) → MPC Signing Service → Blockchain
Плюси: немає проблеми зберігання ключів на клієнті, простий recovery, швидкий UX. Мінуси: custodial ризик, потрібна ліцензія (залежить від юрисдикції), користувач довіряє платформі.
Реалізація: Web3Auth MPC Core Kit на сервері, або Fireblocks API. Telegram user ID → детермінований wallet адрес через сервіс. Підтримка EVM + TON в одній системі.
2. Embedded wallet з AA (Account Abstraction)
Використовуємо ERC-4337 Smart Account. Ключ генерується на пристрої (у пам'яті TMA), але контракт-кошелек може мати кілька власників й механізм recovery.
// Створення AA wallet через ZeroDev SDK
import { createKernelAccount, createKernelAccountClient } from '@zerodev/sdk';
import { signerToEcdsaValidator } from '@zerodev/ecdsa-validator';
// Signer з Telegram initData (детермінований з user_id + секрет)
const signer = privateKeyToAccount(deriveKeyFromTelegram(initData));
const ecdsaValidator = await signerToEcdsaValidator(publicClient, {
signer,
kernelVersion: KERNEL_V3_1,
});
const account = await createKernelAccount(publicClient, {
plugins: { sudo: ecdsaValidator },
kernelVersion: KERNEL_V3_1,
});
// Gasless транзакції через Paymaster
const kernelClient = createKernelAccountClient({
account,
paymaster: { getPaymasterData: async (userOp) => ... },
});
Перевага: gasless транзакції (paymaster платить газ), batched операції, social recovery через смарт-контракт. Недолік: ключ у пам'яті TMA — при закритті додатку або зберігати на сервері (custodial елемент), або вимагати повторної деривації.
3. TonConnect для TON
import TonConnect from '@tonconnect/sdk';
const connector = new TonConnect({
manifestUrl: 'https://yourapp.com/tonconnect-manifest.json',
});
// Відкриваємо список кошельків (TON Space, Tonkeeper й ін.)
const walletsList = await connector.getWallets();
// Підключення конкретного кошелька
await connector.connect({
universalLink: wallet.universalLink,
bridgeUrl: wallet.bridgeUrl,
});
// Відправлення транзакції
await connector.sendTransaction({
validUntil: Math.floor(Date.now() / 1000) + 300,
messages: [{
address: recipientAddress,
amount: toNano('0.5').toString(),
payload: cell.toBoc().toString('base64'),
}],
});
TonConnect відкриває TON Space або Tonkeeper через deep link. Для кошелька самого додатку — використовується TON SDK з ключами, збереженими через ваш backend.
Безпечне зберігання ключів у TMA
Головна проблема TMA: немає безпечного сховища. Що НЕ підходить:
-
localStorage— очищується Telegram, читається JavaScript -
sessionStorage— живе лише сесію - IndexedDB — аналогічно localStorage за безпекою
Рішення: серверне сховище з шифруванням. Ключ (або MPC share) зберігається на сервері, зашифрований ключем, відомим лише користувачеві. Користувач вводить PIN → PIN перетворюється в encryption key через PBKDF2/Argon2 → розшифровує share.
// Client-side: шифрування share перед відправленням на сервер
async function encryptShare(share: Uint8Array, pin: string): Promise<string> {
const pinKey = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(pin),
'PBKDF2',
false,
['deriveKey'],
);
const salt = crypto.getRandomValues(new Uint8Array(16));
const aesKey = await crypto.subtle.deriveKey(
{ name: 'PBKDF2', salt, iterations: 600_000, hash: 'SHA-256' },
pinKey,
{ name: 'AES-GCM', length: 256 },
false,
['encrypt'],
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
aesKey,
share,
);
return JSON.stringify({
salt: btoa(String.fromCharCode(...salt)),
iv: btoa(String.fromCharCode(...iv)),
data: btoa(String.fromCharCode(...new Uint8Array(encrypted))),
});
}
Сервер зберігає зашифрований blob, розшифрувати без PIN неможливо. PIN не передається на сервер.
UI/UX паттерни для TMA-кошелька
Адаптація під Telegram UI
TMA повинен виглядати нативно в Telegram. Використовуємо CSS змінні Telegram:
:root {
--tg-theme-bg-color: var(--tg-color-scheme-bg);
--tg-theme-text-color: var(--tg-color-scheme-text);
--tg-theme-button-color: var(--tg-color-scheme-button);
--tg-theme-button-text-color: var(--tg-color-scheme-button-text);
}
Бібліотека компонентів: @telegram-apps/telegram-ui — готові компоненти у стилі Telegram (Cell, List, Section, Modal). Використовуємо замість кастомного дизайну — користувачі одразу відчувають знайомий інтерфейс.
Транзакційний UX
Підтвердження транзакції в TMA — критичний момент. Користувач повинен чітко бачити: що підписує, скільки стоїть, gas fee (або "бесплатно" якщо gasless). Використовуємо WebApp.showConfirm() для простих операцій або кастомний modal для складних.
// Показуємо нативний confirm Telegram для критичних операцій
const confirmed = await new Promise<boolean>((resolve) => {
WebApp.showConfirm(
`Відправити ${amount} USDT на ${shortAddress(recipient)}?`,
resolve,
);
});
Інфраструктура й стек
Frontend: React 18 + TypeScript + Vite. @twa-dev/sdk для Telegram API. wagmi + viem для EVM. @ton/ton для TON. Tailwind CSS з CSS змінними Telegram.
Backend: Node.js + Fastify. Telegram Bot API для сповіщень. PostgreSQL для user data + wallet metadata. Redis для сесій і rate limiting.
Web3 інфраструктура: Alchemy / Infura для EVM RPC. TON Center або orbs.com для TON. Bundler + Paymaster (Pimlico, ZeroDev) для AA.
| Компонент | Технологія |
|---|---|
| TMA Framework | @twa-dev/sdk + React |
| EVM Wallet | Web3Auth MPC / ZeroDev AA |
| TON Wallet | TonConnect + @ton/core |
| Auth | Telegram initData verification |
| Key storage | Server-side encrypted shares |
| Notifications | Telegram Bot API |
Ориентири по срокам
MVP (custodial, один chain, базовий send/receive): 4–6 тижнів. Повнофункціональний кошелек з MPC, AA gasless, мультичейн, TON + EVM: 3–5 місяців.
Окремо: будь-який кошелек, що працює з реальними грошима користувачів, потребує security audit до публічного релізу.







