Всем привет! Думаю, все уже знают, что в телеге уже год как бум мини-аппов, все тапали хомяка. Подавляющее большинство из них связаны с криптой. Многие хотят внутри приложения давать своим пользователям кошелёк (EVM, TON или Solana, etc.), как некий виртуальный счёт, который можно пополнить, выводить средства, и, самое главное, дергать смарт-контракты.
Простое и небезопасное решение - хранить все ключи на серваке, выполнять транзакции от имени юзера. Взлом вашего сервера = потеря всех клиентских средств, добиться доверия в этом случае очень сложно.
Сложное и неудобное решение - кошелёк, который юзер должен записать на бумажке и следить за его безопасностью сам. В этом случае, вам лучше вообще использовать WalletConnect или не делать миниапп вообще. Правда, в этом случае UI миниаппа превращается в ад, где юзер должен подтверждать каждое действие во внешнем приложении.
Мы искали для нашего миниаппа вариант, который бы давал безопасность некастодиального кошелька, но с максимально гладким UX/UI. И нашли.
В этой статье я хочу сделать обзор TMA Wallet (npm-пакет, сайт, github) - opensource некастодиального multi-party кошелька, подходящего для любых чейнов, работающего на базе недавно появившееся API Telegram Cloud Storage.
Поехали!
Очень краткое объяснение терминов
Кошелёк = приватный ключ. Этот приватный ключ используется для подписи транзакций и даёт тому, кто им владеет, право распоряжаться средствами на конкретном блокчейн-адресе.
Кастодиальный кошелёк = вашим приватным ключом владеет другая организация и выполняет действия от вашего имени. Классический пример - криптобиржи, аля Binance. Это удобно, но требует большого доверия к организации.
Некастодиальный кошелёк = ваш приватный ключ только у вас. Он хранится на вашем устройстве, и все действия со средствами выполняются либо напрямую вами, либо с вашего подтверждения. Главная проблема некастодиальных кошельков - их легко потерять. Утратил доступ к приватному ключу - прощайте, средства.
MPC (multi-party-computation) - попытка решить проблему утери кошелька: разбить ключ на несколько частей, каждая из которых хранится у разных контрагентов, и они все требуются для формирования подписи транзакции. В этом сценарии взлом одного из контрагентов не даёт доступа к средствам клиента. При этом клиенту не надо переживать за хранение ключа самостоятельно.
Поэтому, некастодиальный MPC-кошелёк - это как раз кошелёк, части приватного ключа которого хранятся в разных местах, и никогда не собираются вместе у какого-либо из контрагентов.
Что вообще такое TMA Wallet?
TMA Wallet - это некастодиальный multi-party (MPC) кошелёк, который использует новые возможности Telegram Cloud Storage для безопасного хранения ключей. Всё это завязано на Telegram-аккаунт пользователя и не требует от человека запоминать какие-то seed-фразы или заводить внешние кошельки. Флоу настолько плавный, что ваш пользователь может даже не знать, что под капотом используется крипто-кошелёк - можно сделать совершенно человеческий UI, изолировав от пользователя блокчейн-магию.
Какие конкретные плюсы я бы выделил:
-
Лёгкая интеграция: просто ставишь npm-пакет, прицепляешь его к своему коду - и всё, у каждого юзера вашего мини-аппа теперь есть кошелёк.
-
Никаких костылей с TON Connect, WalletConnect: пользователь остаётся целиком в Telegram, и все транзакции подписываются "под капотом".
-
MPC-технология: приватный ключ не доступен никому — ни Telegram, ни вашему серверу, ни серверам TMA Wallet. Он воссоздаётся на устройстве пользователя, держится в памяти считаные наносекунды (на время транзакции) и исчезает.
-
Удобное восстановление: потерял телефон - без проблем, бери новый, заходи в Telegram, и кошелёк восстановится автоматически.
-
Доступ с разных устройств: если юзер зашёл в миниапп с десктопа с тем же аккаунтом - он получит доступ к тому же воллету, что и на телефоне.
-
Открытый исходный код: всё лежит на GitHub, можно проверить и убедиться в безопасности, либо самостоятельно провести аудит.
-
Поддержка Viem/Wagmi/Ethers.js: если вы пишете под любой EVM-совместимый блокчейн (Ethereum, BSC, Polygon и т.д.), то сможете использовать стандартные либы.
-
Поддержа любых чейнов: из коробки поддерживаются EVM-чейны, но сама суть TMA Wallet - это просто раздельное хранение некоего секрета, так что в качестве секрета может выступать приватник от любого чейна (TON/Solana/etc).
Как это устроено «под капотом»?
Как я уже раза три написал - TMA Wallet основан на принципах Multi-Party Computation (MPC), где приватник, по сути, распределён между несколькими сторонами и собирается только на клиенте, на мгновение при транзакции. Вот краткая схема:
-
При первом запуске мини-аппа у пользователя на устройстве генерируются
ClientPublicKey
иClientSecretKey
.ClientSecretKey
сохраняется в Telegram Cloud Storage. -
ClientPublicKey
иWebApp.initData
(подписанная Telegram'ом авторизационная строка) летят на сервер. -
Сервер проверяет валидность подписи от Telegram и (при желании) запрашивает у пользователя дополнительный фактор аутентификации (2FA). Можно и без него, как у нас.
-
Сервер генерирует так называемый
IntermediaryKey
, подписав(ClientPublicKey + telegramUserId)
своимServerSecretKey
. ЭтотIntermediaryKey
шифруется перед отправкой на клиент. -
IntermediaryKey
возвращается обратно на клиент и расшифровывается там. -
На финальном шаге
IntermediaryKey
подписываетсяClientSecretKey
и превращается вWalletPrivateKey
(собственно, приватный ключ от воллета).
Этот ключ используется для подписи транзакции, при этом нигде не сохраняется, для каждого нового действия вся цепочка выше (кроме 1 пункта) повторяется.
В итоге мы имеем приложение, которое (по UX) выглядит идеально: логин бесшовный благодаря авто-авторизации в миниаппах, а транзакции бесшовные, потому что используется собственный in-app кошелёк.
Как добавить в свой миниапп?
-
Установите SDK в проект:
npm install --save @tmawallet/sdk
-
Добавьте в код инициализацию ключа:
import { TMAWalletClient } from '@tmawallet/sdk'; import { ethers } from 'ethers'; // не забудьте зарегаться на dash.tmawallet.com const myApiKey = '1234567812345678'; // API-ключ из dash.tmawallet.com const client = new TMAWalletClient(myApiKey); // Авторизуем пользователя и создаём/загружаем для него кошелёк await client.authenticate(); console.log('Your wallet address: ', client.walletAddress);
-
Пример, как сделать транзакцию (в данном случае через Ethers.js):
// Используем TMA Wallet как "signer" для ethers const provider = new ethers.JsonRpcProvider(); const signer = client.getEthersSigner(provider); const tx = await signer.sendTransaction({ to: '0x...', value: ethers.parseEther('1.0'), }); console.log('Transaction hash:', tx.hash);
Вуаля.
FAQ
Перевёл вопросы (с легкой редактурой), ответы на которые TMA Wallet написали в своем README:
-
Это точно безопасно?
Да, и это принципиально: благодаря MPC-протоколу ни серверы TMA Wallet, ни Telegram, ни вы не имеете полного доступа к приватному ключу. Только юзер.
-
Мне надо давать вам доступ к токену моего бота?
Нет, мы одни из первых кто поддерживает новую асимметричную схему подписи Telegram. Нам нужен только ID вашего бота, он итак является публичным.
-
Какой блокчейн можно поддерживать?
Любой. Из коробки - всё, что работает с ethers.js (то есть EVM). Если у вас что-то кастомное, можно использовать метод
accessPrivateKey
. -
А если пользователь потерял устройство?
Пока у него есть доступ к его Telegram-аккаунту, он просто залогинится на новом девайсе и кошелёк сам восстановится. Сид-фразу искать не придётся.
-
Можно ли сделать бэкап ключа?
Технически да, но не нужно. Кошелёк и так восстанавливается через Telegram. Если хотите, можете дать пользователю возможность забекапить ключ - но это уже на ваш страх и риск.
Заключение
Мы использовали TMA Wallet в двух собственных приложениях, одно из которых уже в проде (постеснялся выкладывать ссылку в начале статьи, чтобы не выглядело как реклама, но в футере ящитаю уже можно, Only100x)
Это отличный выбор для тех, кто разрабатывает мини-аппы в Telegram и хочет давать своим юзерам секьюрный воллет, не уродуя при этом UX всякими коннекторами.
Пробуйте, изучайте, если есть вопросы - вся документация и исходники проекта доступны на GitHub. Удачи!
P.S. 2025 год на дворе, как же без рекламы канала? собсна, я тоже сделал тг-канал. там я отвратительно себя веду, много матерюсь, но часто пишу всякое полезное про техно-фаундерство, AI, и прочее: как про мои/чужие opensource-либы, так и про то, как я укус за укусом прогрызаю свой путь в этом вашем медиа-пространстве. Подписывайтесь!
Автор: ElKornacio