Как программно создать TON-кошелёк (v4, v5, highload)
Как программно создать TON-кошелёк одним вызовом generate_wallet: версии v3r2, v4, v5r1, highload. Мнемоника, ключи, адрес и безопасный первый депозит.
Вы запустили генерацию 500 промо-кодов, и под каждую выплату нужен свой TON-кошелёк. Или вы пишете ИИ-агента, который на лету создаёт «горячий» кошелёк, принимает депозит и что-то с ним делает. Первое, что находится в интернете, — куча SDK-примеров: подключи @ton/ton, разберись, чем WalletContractV4 отличается от WalletContractV5R1, вручную вызови mnemonicNew(), выведи ключи, посчитай адрес, не забудь про subwallet_id у highload. Полдня уходит на инфраструктурный код, который не имеет отношения к вашей задаче. А если кошельки создаёт ИИ-агент, он должен уметь это сам — без того, чтобы вы зашивали в него криптографию.
Ниже — как создать TON-кошелёк программно (generate wallet / создание кошелька в TON) одним вызовом инструмента generate_wallet, разобраться в версиях v3r2, v4, v5r1 и highload_v3 и не потерять первый депозит на типичной ошибке с bounceable-адресом.
Зачем создавать TON-кошелёк программно (и почему не через SDK)
Ручное создание через SDK — это нормально ровно до первого продакшена. На масштабе всплывают проблемы:
- Версии. В TON не один «кошелёк», а несколько контрактов: v3r2, v4, v5r1, highload. У каждого своя логика и свой адрес при одном и том же ключе. Ошибётесь версией — получите не тот адрес.
- Форматы адреса. Один и тот же кошелёк имеет форму EQ и UQ. Перепутаете при выдаче адреса для депозита — деньги «отскочат» обратно (об этом ниже).
- ИИ-агент. Агенту (Claude, Cursor, ChatGPT/Codex) нельзя «дать библиотеку» — ему нужен инструмент, который он вызовет по описанию. Через MCP (Model Context Protocol) агент вызывает
generate_walletкак обычную функцию и получает готовый структурированный ответ. Логика версий, ключей и форматов живёт на стороне MCP-сервера. - Полиглот-стек. Не хотите держать TON-SDK на Go, Python и Node одновременно — MCP даёт один интерфейс для всех.
generate_wallet — один из 16 инструментов TONNode, hosted MCP-сервера для TON. Он делает ровно одну вещь: создаёт новый кошелёк и отдаёт вам всё, что нужно, чтобы им владеть. Если вы только знакомитесь с подходом, начните с гайда по MCP для TON.
generate_wallet за один вызов: что именно возвращается
generate_wallet создаёт новый TON-кошелёк и возвращает полный набор для владения им и восстановления:
- мнемонику (seed-фразу) — человекочитаемый набор слов, из которого детерминированно выводится всё остальное;
- приватный ключ — для подписи транзакций;
- публичный ключ;
- адрес кошелька — в стандартных TON-форматах.
Промпт агенту выглядит буквально так:
Создай новый TON-кошелёк версии v5r1 через generate_wallet
и покажи адрес и мнемонику.
Агент вызывает инструмент с параметром версии и возвращает структуру примерно такого вида (значения условные; ключи Ed25519 в TON — это обычный hex, без Ethereum-префикса 0x):
{
"version": "v5r1",
"mnemonic": ["word1", "word2", "...", "word24"],
"public_key": "e3f1a2…",
"private_key": "9b7c4d…",
"address": {
"bounceable": "EQ…",
"non_bounceable": "UQ…",
"raw": "0:abcd…"
}
}
Никакого SDK и ручной деривации. Дальше вы сами решаете, где это хранить. Ключевой момент: сервер эту мнемонику и ключи у себя не оставляет — об этом ниже в разделе про некастодиальность.
Версии кошельков v3r2, v4, v5r1 и highload_v3 — какую выбрать
generate_wallet поддерживает четыре версии контракта кошелька. Это не «новее — значит лучше»: у каждой своя ниша.
v5r1 (W5) — по умолчанию для новых проектов
Новейшая версия. Поддерживает расширения и gasless-сценарии — когда комиссию за пользователя может оплатить сторонний релеер. Это свойство самого контракта v5, а не услуга TONNode: сервер лишь создаёт такой кошелёк, никакого gasless-релеера он не предоставляет. Если вы строите современного агента с нуля и вам не нужен именно highload — берите v5r1.
v4 — версия с плагинами
Предыдущее массовое поколение. Поддерживает плагины: к кошельку можно прикреплять контракты-расширения (например, для подписок и отложенных платежей). Долго был де-факто стандартом, широко поддерживается кошельками и сервисами. Берите, если у вас есть зависимость от плагинной модели v4.
v3r2 — простой базовый кошелёк
Минимальный контракт без расширений и плагинов. Предсказуемый и дешёвый по газу. Подходит для служебных адресов, где вся логика — «принять и отправить».
highload_v3 — для массовых выплат
Отдельный класс. Кошелёк под высокую пропускную способность: одно внешнее сообщение может нести много переводов. Это то, что вы берёте под батч-выплаты, дропы, раздачи наград, платёжные шлюзы, биржевые выводы. За эффективность он платит особой моделью учёта сообщений (query_id / expiration), поэтому требует бережного обращения — см. раздел про хранение параметров.
| Версия | Когда брать |
|---|---|
v5r1 |
Новые проекты, расширения, gasless |
v4 |
Нужны плагины (подписки и т.п.), максимальная совместимость |
v3r2 |
Простой служебный кошелёк без наворотов |
highload_v3 |
Массовые/пакетные выплаты, высокий throughput |
Пример промпта под выплаты:
Сгенерируй highload_v3 кошелёк для пакетных выплат и верни
мнемонику, ключи и адрес.
Первый депозит: почему слать на non-bounceable UQ-адрес
Самая частая и обидная ошибка после создания кошелька — потеря первого депозита. Механика такая: свежесозданный кошелёк ещё не задеплоен в блокчейн — контракта по адресу физически нет, пока на него не придёт первый перевод, разворачивающий код.
В TON у адреса есть флаг «bounceable»:
- EQ (bounceable) — если на адресе нет живого контракта, сеть отбивает («bounce») перевод обратно отправителю. Для нового кошелька это именно ваш случай.
- UQ (non-bounceable) — перевод «прилипает» к адресу, даже если контракт ещё не развёрнут. Ровно то, что нужно для первого депозита.
Правило простое: первый пополняющий перевод на новый кошелёк слать на UQ-адрес. На EQ он вернётся, и вы будете гадать, почему баланс пустой. После того как кошелёк совершит первую исходящую транзакцию и задеплоится, можно спокойно пользоваться bounceable-формой.
Как получить UQ-форму надёжно? Офлайн-инструментом parse_address — он конвертирует и проверяет форматы EQ/UQ/raw без обращения к сети:
Через parse_address переведи этот адрес в non-bounceable
UQ-форму для первого депозита
После пополнения проверьте состояние через get_account_state — он покажет статус аккаунта (uninitialized / active), флаги и последнюю транзакцию:
Проверь get_account_state для UQ… — задеплоен ли кошелёк
и какой баланс
Пока контракт не активен, состояние подскажет, что депозит ещё не «поднял» кошелёк. Подробный разбор форматов — в статье про адресные форматы EQ/UQ/raw.
Highload-кошелёк: зафиксируйте subwallet_id и timeout сами
Отдельное предупреждение для тех, кто взял highload_v3. Одной мнемоники здесь недостаточно, чтобы корректно воссоздать рабочий кошелёк и повторить его поведение. У highload-контракта, кроме ключа, есть ещё два параметра, которые задаются при создании и входят в его initial data (state init):
subwallet_id— идентификатор подкошелька (позволяет из одной seed-фразы получить несколько разных адресов);timeout— окно жизни внешних сообщений, на котором построена логикаquery_idи истечения.
Важно: generate_wallet возвращает мнемонику, ключи и адрес — а subwallet_id и timeout вы выбираете и фиксируете сами как параметры конструкции highload-кошелька. Именно вы отвечаете за то, чтобы записать те значения, с которыми кошелёк был создан.
Highload-кошелёк отслеживает, какие сообщения ещё «живы», исходя из timeout. Если вы восстановите кошелёк только по seed-фразе, без subwallet_id и timeout, то:
- получите не тот адрес — и
subwallet_id, иtimeoutвходят в state init, поэтому изменение любого из них меняет initial data контракта, а значит и его адрес; - не воспроизведёте корректную логику истечения и дедупликации сообщений — и рискуете сломать учёт исходящих переводов.
Практическое правило: для highload_v3 кладите subwallet_id и timeout в хранилище рядом с мнемоникой, как часть одной записи о кошельке. Это не опциональные метаданные — это часть идентичности кошелька.
# псевдо-запись секрета
mnemonic: "word1 word2 … word24"
version: "highload_v3"
subwallet_id: <значение, которое вы задали при создании>
timeout: <значение, которое вы задали при создании>
Для v3r2/v4/v5r1 такого требования нет — там достаточно мнемоники и знания версии.
Некастодиально: сервер не хранит и не подписывает ключи
Главный вопрос, когда кошелёк создаётся «где-то на сервере»: кто в итоге владеет ключами? Ответ здесь однозначный.
generate_wallet строго некастодиален:
- сервер никогда не хранит приватные ключи, мнемонику и средства;
- сервер никогда не подписывает транзакции за вас;
- сгенерированный кошелёк — мнемоника, ключи, адрес — целиком отдаётся вам в ответе и на стороне сервера не сохраняется.
Нет базы с чужими seed-фразами, нет operator-ключа, который что-то подписывает за вас. По сути generate_wallet — это удобная обёртка над детерминированной генерацией: криптография происходит, результат уезжает к вам, у сервера не остаётся ничего. Это принципиальное отличие от кастодиальных агент-кошельков, где сервис держит ключ (или его часть) и подписывает транзакции сам. Разницу разбираем отдельно: кастодиальный против некастодиального MCP.
Практический вывод: сохраните ответ generate_wallet в своё безопасное хранилище сразу. Второй раз этот же кошелёк сервер вам не «достанет» — он его не помнит, и восстановить «через поддержку» будет невозможно. Это фича, а не баг.
Как подключить и создать первый кошелёк
Подключение — минутное дело. Локально и бесплатно поднимаете пакет @tonnode/mcp через npx; полный набор чтения доступен без ключа.
Конфиг MCP-клиента (Claude Desktop, Cursor, любой MCP-клиент):
{
"mcpServers": {
"ton": {
"command": "npx",
"args": ["-y", "@tonnode/mcp"]
}
}
}
Пакет @tonnode/mcp — open source (MIT), лежит на npm и GitHub (tonnode/mcp), и работает по нативному ADNL-протоколу TON, без HTTP-прослоек между вашим агентом и сетью. Перезапустите клиент — и все 16 инструментов, включая generate_wallet, parse_address и get_account_state, станут доступны агенту. Как прикрутить его к конкретному клиенту — в инструкции подключения Claude и Cursor к TON.
generate_wallet входит во все 16 инструментов и доступен на всех тарифах, включая бесплатный Hobby — 60 запросов в минуту, без карты. Бесплатный ключ выдаётся сразу после входа. Платите вы только за пропускную способность, а не за доступ к инструментам.
Дальше — три инструмента, которые закрывают весь сценарий «создать и безопасно пополнить»:
generate_wallet— создать кошелёк нужной версии, забрать мнемонику, ключи, адрес.parse_address— получить UQ-форму адреса для первого депозита (офлайн).get_account_state— убедиться, что депозит развернул контракт.
Пример полного промпта агенту:
Создай v5r1 кошелёк через generate_wallet. Затем через
parse_address дай мне его UQ-адрес для первого пополнения.
После того как я закину монеты, проверь get_account_state,
что кошелёк задеплоен.
Когда нужен hosted-ключ
Локальный npx-запуск использует публичный конфиг и отлично подходит для разработки. Если нужна гарантированная пропускная способность под нагрузкой (те же массовые выплаты с highload), подключите hosted-эндпоинт со своим ключом:
{
"mcpServers": {
"ton": {
"type": "http",
"url": "https://mcp.tonnode.io/mcp",
"headers": { "Authorization": "Bearer tn_live_…" }
}
}
}
Итого
generate_walletсоздаёт TON-кошелёк одним вызовом и возвращает мнемонику, приватный/публичный ключи и адрес — это один вызов с выбором версии, а не сборка SDK вручную.- Версия по умолчанию для нового проекта — v5r1; для массовых выплат — highload_v3; v4 — ради плагинов; v3r2 — когда нужен простой кошелёк.
- Первый депозит шлите на non-bounceable UQ-адрес, иначе он отскочит; UQ-форму даёт
parse_address, а состояние проверяетget_account_state. - Для highload сами зафиксируйте
subwallet_idиtimeoutи храните их вместе с мнемоникой — оба входят в state init и влияют на адрес. - Сервер некастодиален: ключи и средства не хранит и не подписывает — ключи ваши.
Возьмите бесплатный ключ Hobby и создайте первый кошелёк через generate_wallet за пару минут — tonnode.io/dashboard?plan=hobby.
Дайте вашему агенту доступ к TON
16 MCP-инструментов: чтение, некастодиальные свапы, кроссчейн и кошельки. Бесплатный тариф — 60 запр/мин, карта не нужна.