GRAM: создание и привязка TON-кошельков

TON · Laravel · wallet microservice · testnet / mainnet

GRAM — отдельный микросервис, который создаёт и привязывает TON-кошельки, синхронизирует транзакции и передаёт подтверждённые депозиты в основное приложение. В этом разборе показана фактическая архитектура проекта: от V5R1-кошелька до защищённого межсервисного API.

V5R1версия создаваемых и импортируемых кошельков
3 ролиuser, collector и standalone
Webhook + pollingдва контура синхронизации
HMAC-SHA256подпись service-to-service запросов

Зачем кошельки вынесены в отдельный сервис

Основной сайт хранит пользователей и бизнес-операции. GRAM отвечает за работу с TON: адреса, ключевой материал, балансы, историю транзакций, депозиты, вывод и сбор средств. Такое разделение сокращает область кода, которая имеет доступ к чувствительным данным, и позволяет независимо масштабировать фоновые задачи.

Связь между системами проходит через REST API. Основной сайт запрашивает кошелёк по своему идентификатору пользователя, а GRAM возвращает публичные данные: адрес, сеть, версию, назначение, статус и балансы. Зашифрованная мнемоника в этот ответ не попадает.

Панель управления микросервисом GRAM с состоянием TON testnet, очередями и последними операциями
Панель GRAM сводит в одном месте состояние сети, кошельков, очередей, депозитов, выводов и фоновых операций. На изображении используется TON testnet.

Как создаётся и привязывается пользовательский кошелёк

  1. Запрос основного приложения

    Основной сайт передаёт внутренний ID пользователя и активную сеть. Запрос проходит HMAC-проверку до выполнения бизнес-операции.

  2. Проверка существующей привязки

    GRAM ищет кошелёк этого пользователя в той же сети и версии V5R1. Если запись уже существует, сервис возвращает её и не создаёт второй адрес.

  3. Генерация и сохранение

    TON-адаптер создаёт V5R1-кошелёк. В базе фиксируются адрес, публичный ключ, workchain, global ID, источник ключа и назначение. Мнемоника сохраняется в зашифрованном виде.

  4. Фоновая синхронизация

    Для нового адреса ставится задача подписки на webhook. Баланс и история обрабатываются очередью, поэтому сетевой TON API не задерживает пользовательский запрос.

Конкурентные запросы также учтены: уникальное ограничение в базе не позволяет создать несколько кошельков для одной и той же привязки. При конфликте сервис повторно читает уже созданную запись.

Три роли кошельков

Пользовательский

Связан с ID пользователя основного сайта. Принимает депозиты и участвует в автоматическом сборе средств по заданному порогу.

purpose: user

Кошелёк-сборщик

Используется как целевой адрес для консолидации средств с пользовательских кошельков и для операций казначейства.

purpose: collector

Автономный

Создаётся без связи с пользователем. Подходит для административных переводов и отдельных служебных сценариев.

purpose: standalone

Создание и безопасный импорт

GRAM умеет не только генерировать новые кошельки, но и подключать существующие V5R1-кошельки. Перед одиночным импортом оператор указывает ожидаемый адрес: сервис восстанавливает кандидата из 24 слов и проверяет совпадение. Это защищает от импорта корректной seed-фразы с ошибочно выбранными параметрами сети или wallet global ID.

Для пакетной загрузки каждая строка проходит отдельную проверку. Предпросмотр показывает готовые записи, дубли и ошибки, не раскрывая мнемоники в журнале. При сохранении адрес проверяется под блокировкой транзакции, а уникальный индекс закрывает гонку между параллельными импортами.

Операция доступна только администратору с нужной ролью и настроенной 2FA. Seed-фраза исключена из повторного заполнения формы, скрыта в модели и хранится через шифрование Laravel. Просмотр выполняется отдельной защищённой операцией с одноразовым результатом и журналированием.

Настройки микросервиса GRAM: создание V5R1-кошельков, синхронизация и сбор средств
Настройки кошелькового контура: автоматическое создание V5R1, синхронизация транзакций и параметры сбора средств.

Webhook, polling и история без дублей

Новая транзакция приходит через webhook и запускает адресную задачу синхронизации. Polling работает как резервный контур: он обновляет баланс и забирает историю по расписанию, даже если внешнее событие задержалось или не дошло.

Задачи синхронизации уникальны для кошелька. При ограничениях со стороны TON-провайдера включается общий cooldown, а повторные попытки получают возрастающую задержку и случайный jitter. Так очередь не создаёт лавину одинаковых запросов.

История читается курсорами. Отдельно хранятся последнее увиденное событие и курсор backfill для загрузки старых операций. Входящая транзакция принимается только при успешном результате без признаков aborted или bounced. Идентификатор операции строится из blockchain logical time, а вставка выполняется через уникальность и insertOrIgnore.

От подтверждённого депозита до баланса основного сайта

Подтверждённая входящая транзакция пользовательского кошелька создаёт запись в outbox. Технические Jetton-сообщения, внутренние переводы между управляемыми кошельками и суммы ниже минимального порога не отправляются как пользовательский TON-депозит.

Для события вычисляется стабильный external_id из сети, адреса, logical time и хеша транзакции. Доставка в основное приложение идёт отдельной очередью с повторными попытками. Получатель обязан вернуть тот же идентификатор в подтверждении; после исчерпания попыток операция уходит на ручную проверку. Это позволяет повторить доставку и не начислить депозит дважды.

Защита межсервисного API

Каждый запрос основного сайта подписывается HMAC-SHA256. В подпись входят HTTP-метод, путь, query string, SHA-256 тела, timestamp, nonce и Idempotency-Key. Сервис проверяет подпись через hash_equals, ограничивает допустимое время запроса и резервирует nonce в базе до выполнения операции.

Replay protection

Одноразовый nonce с уникальным ограничением не позволяет повторно воспроизвести уже принятый запрос.

Idempotency-Key

Повторная команда связывается с тем же бизнес-запросом и не создаёт новую финансовую операцию.

IP allowlist

API-клиенту задаётся точный список IPv4, IPv6 или CIDR. Запрос с другого адреса отклоняется до бизнес-логики.

Ограничения

HTTPS, лимит размера тела, rate limiting и метаданные запроса дополняют подпись. Секреты и содержимое ключей в интерфейсе не выводятся.

Экран API и безопасности GRAM с HMAC-SHA256, timestamp, nonce, Idempotency-Key и IP allowlist
В интерфейсе видны применяемые механизмы API-защиты. Значения ключей, секретов и доверенных IP намеренно не отображаются.

Операционная панель и контроль состояния

Администратор видит назначение и источник каждого кошелька, баланс в TON и nanoTON, резерв, время последней синхронизации и ошибку провайдера. Список фильтруется по сети, версии, назначению, статусу, источнику ключа и состоянию синхронизации.

Выбранные кошельки можно отправить на синхронизацию или выгрузить в CSV. Массовые задачи имеют лимит, распределяются по времени с учётом пропускной способности TON API и фиксируются в журнале действий. Для сверки custody строится снимок пользовательских, collector- и standalone-кошельков с общим, зарезервированным и доступным балансом.

Стек проекта

BackendLaravel 13 · PHP 8.3 · REST API
BlockchainTON SDK · V5R1 · TON API · Jetton
Background processingLaravel Queue · Scheduler · Redis
InfrastructureMySQL · Nginx · PHP-FPM · Docker

Связь с P2P-платформой

GRAM — кошельковый и blockchain-контур более крупной FinTech-системы. Пользователь получает отдельный TON-адрес, подтверждённый депозит передаётся в основное приложение, а баланс используется в операциях P2P и выводе. Jetton-депозиты и выводы проходят по тому же принципу, но ведутся в отдельных таблицах и собственном журнале.

В полном кейсе P2P-платформы разобраны сделки, чат, споры, ledger, резервирование вывода и custody reconciliation. Код кошелькового микросервиса остаётся отдельной частью архитектуры.

Обсудить задачу

Если у вас есть проект, связанный с Python, Laravel, Node.js, CRM, Telegram, AI/RAG, API-интеграциями, автоматизацией или TON/GRAM-логикой — напишите в свободной форме, что нужно сделать.

Можно описать задачу коротко: что есть сейчас, что не работает, какой результат нужен и какие сервисы уже используются.


Давайте обсудим проект

Расскажите, что хотите сделать. Я отвечу на вашу почту.

Или напишите в Telegram @ifwcom