Назначение и возможности
Ledger — это аппаратное устройство, холодный кошелек, такой как Nano S, Nano X, Nano S Plus и другие, на котором установлено приложение TON через Ledger Live. Ключи никогда не покидают устройство, а подтверждение переводов и подписей происходит непосредственно на Ledger.В Tonhub Ledger используется как отдельный тип кошелька: пользователь подключает устройство по USB, то есть HID, на Android или по Bluetooth, то есть BLE, на iOS и Android, выбирает один из аккаунтов с индексами 0-9 и после этого может просматривать баланс, отправлять TON и токены, стейкать, пользоваться Holders и подключать dApp через TON Connect. Подписание транзакций и данных всегда выполняется на Ledger. Подключать можно неограниченное количество холодных кошельков.
Минимальная версия приложения TON на Ledger — 2.4.1. Если установлена более старая версия, приложение покажет сообщение с просьбой обновить TON-приложение через Ledger Live.
Подключение Ledger
Добавление устройства
- Пользователь на приветственном экране выбирает “Import Wallet” или аналогичный пункт и на экране выбора метода импорта нажимает “Connect Ledger”.
- Открывается Ledger Onboarding, то есть
LedgerOnboardingFragment: краткое описание и кнопка “Continue”. По ссылке можно перейти к инструкции по установке TON-приложения: https://tonwhales.com/ledger - Пользователь принимает условия и политику, то есть
LegalCreateс параметромledger: true, после чего попадает на экран создания кошелька с настройкой PIN-кода, то естьWalletSecurePasscodeComponentс флагомledger. Этот PIN нужен для доступа к приложению, а не к ключам на Ledger. - После настройки PIN пользователь переходит на экран подключения устройства, то есть
HardwareWalletFragment, который в навигации отображается как “Ledger”.
Экран подключения (HardwareWalletFragment)
Android: доступны два способа:
- USB (HID): кнопка “Connect via USB”. Устройство подключается кабелем, приложение создает HID transport и переходит к выбору аккаунта, то есть
LedgerSelectAccount, либо сразу возвращает пользователя в приложение, если аккаунт уже был выбран. - Bluetooth: кнопка “Connect via Bluetooth”. Запускается поиск BLE-устройств; при необходимости приложение запрашивает разрешения, например доступ к геолокации на Android для BLE.
- На экране также показываются краткие инструкции и ссылка на руководство по установке TON-приложения на Ledger по адресу
tonwhales.com/ledger.
Выбор BLE-устройства (LedgerDeviceSelectionFragment)
После запуска поиска BLE отображается список найденных устройств. Пользователь выбирает свой Ledger.Приложение подключается к выбранному устройству через
TransportBLE.open(device.id) и сохраняет соединение в контексте TransportContext. Если выбранный аккаунт еще не задан, пользователь переходит на экран выбора аккаунта, то есть LedgerSelectAccount.При ошибке доступа, например если на Android не выданы разрешения на геолокацию, показывается сообщение с кнопкой “Grant Permissions”; при необходимости открываются настройки приложения.
Выбор аккаунта (LedgerSelectAccountFragment)
- Ledger поддерживает несколько TON-аккаунтов, индексы 0-9; в коде используется
pathFromAccountNumber(i, isTestnet). Приложение запрашивает адреса для каждого индекса, максимум до 10, и показывает список с балансами. - Пользователь должен разблокировать Ledger и открыть на устройстве приложение TON. Пока TON-приложение закрыто или устройство заблокировано, экран показывает подсказки вроде “Unlock Ledger” или “Open TON application”.
- Проверка готовности выполняется через
isLedgerTonAppReady(tonTransport): приложение опрашивает состояние “app open” и при необходимости запрашивает адрес для индекса 0, включая обход особенностей Ledger S. - Пользователь выбирает аккаунт из списка. Выбранный аккаунт сохраняется в контексте и хранилище через
setLedgerSelected(addr.address); список Ledger-кошельковledgerWalletsобновляется, после чего происходит переход в основное Ledger-приложение, то естьLedgerApp.
Повторное подключение и переключение кошельков
На главном экране, то естьHomeFragment, по нажатию на карточку кошелька или через меню открывается выбор аккаунта, то есть AccountSelectorFragment. В списке отображаются и обычные кошельки, и ранее добавленные аккаунты Ledger из ledgerContext.wallets.Если Ledger уже подключен, то есть есть
tonTransport, при выборе “Ledger” открывается экран выбора аккаунта LedgerSelectAccount с текущим выбранным адресом.Если Ledger не подключен, выбор “Ledger” вызывает
ledgerContext.reset() и открывает экран подключения HardwareWalletFragment. После BLE-подключения пользователь снова переходит к выбору аккаунта; после HID-подключения — к выбору аккаунта или обратно, если аккаунт уже был выбран.
Основной интерфейс Ledger
После выбора аккаунта пользователь попадает вLedgerApp — полноэкранный режим с нижними вкладками:
- Home (
LedgerHome) — карточка кошелька, баланс, продукты, такие как переводы, получение, стейкинг, обмены, Holders и другие, а также переключатель режимов Holders и Wallet, то естьAppModeToggle. - History (
LedgerTransactions) — список транзакций. Режим зависит от типа аккаунта: для обычного кошелька этоTransactionsFragment, а для Holders —HoldersTransactionsFragment. - Settings (
LedgerSettings) — для обычного кошелька открываетсяSettingsFragment, а в режиме Holders —HoldersSettings.
ledgerSelected в appState. При следующем запуске, если выбран Ledger, onboarding сразу переводит пользователя в состояние LedgerApp, и он попадает туда без повторного выбора, если в ledgerContext.wallets уже есть сохраненный аккаунт и восстановлен ledgerContext.addr.
Подписание транзакций
Когда пользователь отправляет TON или токены с Ledger-кошелька, приложение формирует order операции, то естьLedgerOrder, и открывает экран подписи LedgerSignTransfer. Пользователь видит сводку: получатель, сумма, комиссия и при необходимости данные токена.Подписание выполняется через
tonTransport, то есть TonTransport из @ton-community/ton-ledger: строится сообщение и вызывается метод подписи на устройстве через путь аккаунта pathFromAccountNumber(addr.acc, isTestnet).Важно: на Ledger должно быть открыто TON-приложение, а само устройство должно быть разблокировано. Иначе подпись завершится ошибкой.
Обработка ошибок подписи
- LockedDeviceError: показывается сообщение “Unlock Ledger”.
- Нет соединения, то есть
!tonTransport: приложение возвращает пользователя назад и показывает диалог “Ledger connection error” с кнопками “Connect” и “Cancel”. - TON-приложение не открыто: после проверки
isLedgerTonAppReadyпоказывается сообщение с просьбой открыть TON-приложение на Ledger. - Версия TON-приложения ниже 2.4.1: проверяется через
checkLedgerTonAppVersion; пользователь получает сообщение о необходимости обновить TON-приложение в Ledger Live. - “Небезопасная” транзакция при отключенном Blind Signing: если операция помечена как unsafe и в настройках Ledger отключена подпись неподтвержденных данных, показывается сообщение наподобие “Enable unconfirmed data signing in TON app settings on Ledger”.
- Пользователь отменил операцию на Ledger, код
0x6985: показывается сообщение о том, что подпись была отменена.
Подписание данных
Для dApp и TON Connect-сценариев может потребоваться подпись произвольных данных, например для аутентификации. ЭкранLedgerSignData позволяет ввести данные, в том числе в Base64, домен и extension, если это нужно, а затем подписать их на Ledger через tonTransport.signData с типом app-data.Используется текущий путь аккаунта; результат, то есть подпись, cell и timestamp, показывается на экране. Требования те же: устройство должно быть разблокировано, а TON-приложение открыто.
Потеря соединения и повторное подключение
При потере соединения, например при отключении USB, выключении Bluetooth или самого Ledger, вызывается обработчикonDisconnect. Приложение пытается переподключиться ограниченное число раз: для HID — один раз, для BLE — два раза. Во время попыток может показываться состояние переподключения isReconnectLedger.Если переподключение не удалось, BLE-состояние сбрасывается в ошибку и вызывается
reset(): соединение и выбранный адрес очищаются из контекста, а пользователю нужно снова подключить Ledger и, при необходимости, заново выбрать аккаунт.При явном выходе из Ledger-кошелька показывается диалог подтверждения; после согласия выбранный Ledger-аккаунт удаляется из списка кошельков, выбор очищается через
clearLedgerSelected. Если это был последний Ledger-кошелек, контекст полностью сбрасывается.
Ограничения и отличия от обычного кошелька
DeDust: если выбран Ledger-кошелек, в разделе “Exchanges”, то естьSelectExchangeFragment, элемент DeDust.io не показывается, то есть !isLedger. Доступен только Changelly. Причина в том, что интеграция DeDust через WebView и TON Connect в текущем виде не поддерживает Ledger.
Хранение данных
- Список Ledger-кошельков
ledgerWallets: массив объектов вида{ acc, address, deviceId?, publicKey }, который хранится в storage по ключуledgerWalletsKey. При выборе аккаунта он добавляется в список, если еще не был добавлен. - Выбранный Ledger-аккаунт: адрес сохраняется через
setLedgerSelected(addr.address)вappState. При следующем входе вLedgerAppэтот адрес восстанавливается. - Включенная поддержка Ledger в приложении: флаг
app_ledger_enabledв storage; он используется для отображения или скрытия опции Ledger в списке кошельков, например в настройках или при первом выборе способа входа. - Ключи и seed-фраза не хранятся в приложении; они остаются только на Ledger.