Разработка P2P-платформы: сделки, TON и Jetton
P2P Crypto Exchange Platform · FinTech · Laravel · TON / Jetton
P2P-платформа с объявлениями, сделками, чатом и спорами, отдельным финансовым учётом и интеграцией с кошельковым микросервисом GRAM. Инженерная задача проекта — согласовать действия пользователей, внутренние балансы и асинхронные события блокчейна.
Задача проекта
Объединить пользовательский P2P-маркет и финансовый backend: объявления на покупку и продажу, согласование сделки, отметку об оплате, release, отмены и разбор споров. При этом ввод TON и Jetton должен доходить до баланса пользователя даже после временной недоступности основного приложения, а повторная доставка события не должна создавать новое зачисление.
Важная часть задачи — разделить учёт платформы и работу с блокчейном. P2P отвечает за пользовательские сценарии и обязательства перед пользователями; отдельный GRAM обслуживает кошельки, синхронизацию транзакций, доставку депозитов и исполнение заявок на вывод.
Архитектура: P2P-приложение и GRAM
Vue / Inertia → Laravel P2P
Интерфейс связан с Laravel через Inertia. В backend выделены маршруты маркета, сделок, профиля, безопасности, банковских реквизитов и административной части. REST API v2 предоставляет отдельные операции для объявлений, сделок, сообщений и настроек пользователя.
GRAM → TON blockchain
Кошельковый микросервис ведёт собственные модели кошельков и транзакций, работает с blockchain API и передаёт в P2P подтверждённые события по подписанному service-to-service API. TON и Jetton имеют отдельные потоки обработки.

Граница между приложениями проходит по API. Сбой внешнего провайдера или очереди доставки отражается в состоянии операции; пользовательский баланс и баланс кошелька рассматриваются как разные уровни учёта.
P2P Engine: от объявления до завершения сделки
Мейкер создаёт объявление на покупку или продажу, редактирует его и управляет доступностью: предусмотрены пауза, возобновление и отмена объявлений. Тейкер открывает сделку по выбранному объявлению. Для API сделки используется публичный UID, для исходного объявления — его ID.
Создание и подтверждение
Для покупки и продажи предусмотрены отдельные сценарии создания. Затем пользователь проходит checkout и подтверждает сделку. В backend это отдельные операции, а не изменение произвольного статуса из интерфейса.
Принятие или отклонение
После создания доступны самостоятельные действия accept и reject. Для сопровождения сделки есть её страница, история переписки и банковские реквизиты пользователя.
Отметка об оплате
Операция markAsPaid фиксирует подтверждение оплаты участником. Она отделена от release: отметка пользователя об отправке денег сама по себе не является подтверждением банковского зачисления.
Release или отмена
Для release и cancel используются отдельные серверные обработчики. Также предусмотрено действие продления времени сделки. Точная матрица допустимых переходов зависит от бизнес-логики контроллеров.
Спор и его закрытие
У сделки есть действия dispute и closeDispute. Административная часть содержит раздел споров и справочник причин, а также просмотр P2P-сделок.
Это последовательность пользовательских действий, подтверждённая маршрутами проекта. Названия внутренних enum-статусов и правила арбитражного распределения средств здесь не подменяются названиями API-команд.
Чат, история операций и реквизиты
Переписка привязана к сделке: backend предоставляет получение и отправку сообщений, отметку прочтения и загрузку вложения. Отдельно доступны история операций, список банков и создание, редактирование, удаление банковских реквизитов. Эти сценарии позволяют сопровождать обмен в одном приложении.
Real-time инфраструктура на Laravel Reverb
В составе инфраструктуры P2P выделен контейнер Laravel Reverb — сервер WebSocket-соединений. Он запускается отдельно от PHP-FPM, обработчика очередей и планировщика. Vue/Inertia обслуживает пользовательский интерфейс, Reverb — канал real-time взаимодействия.
Переданная конфигурационная документация описывает WebSocket-host, порт и схему подключения через HTTPS. Конкретный перечень broadcast-событий и подписок клиента в предоставленных исходниках отсутствует, поэтому здесь не заявляется, что каждое изменение баланса или статуса уже доставляется через WebSocket.
Security: аккаунт и межсервисный API
Пользовательский контур
Выделены сценарии установки и смены PIN, включения и отключения 2FA, привязки Telegram и восстановления доступа. Доступ к чувствительным данным вынесен в отдельные действия профиля, включая пошаговый сценарий раскрытия seed и подготовку файла восстановления.
API v2 использует auth:sanctum. Web-маркет находится в группе с security.keys.viewed и email.linked; административные маршруты — за auth и admin. Это границы доступа в маршрутах, а не заявление о проведённом пентесте.
Service-to-service контур
Endpoint приёма депозитов находится в группе api.hmac с rate limiting. В GRAM подпись HMAC-SHA256 охватывает HTTP-метод, путь, query string, хеш тела, timestamp, nonce и Idempotency-Key. Подмена подписанных данных приводит к несовпадению подписи.
Timestamp ограничивает срок запроса, nonce используется однократно, IP allowlist ограничивает адреса клиентов. Обязательность HTTPS и allowlist задаётся конфигурацией окружения.
Nonce и Idempotency-Key решают разные задачи
При повторной доставке депозита GRAM создаёт новый nonce и timestamp, но сохраняет прежний Idempotency-Key, равный external_id события. Nonce защищает от воспроизведения запроса; стабильный идентификатор операции позволяет распознать повтор на уровне финансовой логики. Одна лишь корректная HMAC-подпись не делает зачисление идемпотентным.
В публичном описании и схеме нет ключей, seed-фраз, токенов, пользовательских реквизитов или внутренних адресов сервисов.
TON deposits: подтверждение, outbox и повторная доставка
GRAM создаёт событие депозита для подтверждённой входящей транзакции пользовательского кошелька. До постановки в outbox проверяются успешность операции, отсутствие bounce, минимальная сумма и тип сообщения. Технические сообщения Jetton, включая transfer_notification и excesses, а также внутренние управляемые переводы не должны становиться новым TON-зачислением.
Стабильная идентичность события
external_id TON-депозита строится из сети, адреса кошелька, logical time и нормализованного хеша транзакции. В таблице outbox уникальны и исходная транзакция, и external_id.
Доставка через очередь
Задача блокирует outbox-запись в транзакции БД, проверяет состояние и отправляет подписанное событие в P2P. Сохраняются число попыток, время следующей попытки, HTTP-статус и код ошибки.
Подтверждение приёма
GRAM проверяет успешный ответ и совпадение external_id в acknowledgement. Временные ошибки приводят к повторным попыткам с задержкой; исчерпание попыток переводит доставку на ручную проверку.
В P2P, согласно документации интеграции, TON хранится отдельно от legacy-баланса USDT: user_currency_balances содержит валютные балансы, crypto_deposits — журнал зачислений. Повторная доставка того же external_id не должна создавать второе начисление. Endpoint приёма TON зарегистрирован отдельно от endpoint Jetton.
Backfill и reconciliation
GRAM умеет восстанавливать исторические транзакции и недостающие outbox-записи. Команды backfill, dispatch и reconcile разделяют поиск пропущенных событий, доставку и сверку. Для истории транзакций используется отдельный курсор: восстановление прошлого не подменяет опрос новых операций.
Так повторная обработка остаётся частью штатного процесса. Уникальность события и защита принимающей стороны нужны именно потому, что сеть может доставить одно событие несколько раз.
Jetton: atomic amounts, ledger и вывод с резервом
Поддержка Jetton выделена в отдельный контур. В GRAM используются активные активы из allowlist, собственные записи транзакций и балансов. Идентичность депозита включает сеть, кошелёк, адрес Jetton master и идентификатор операции: одинакового символа токена недостаточно.
Документация P2P фиксирует три структуры: jetton_deposits для зачислений, user_jetton_balances для отдельных пользовательских балансов и jetton_ledger_entries для неизменяемого журнала операций. Суммы передаются в атомарных единицах; отображение с учётом decimals отделено от финансового расчёта.
Жизненный цикл заявки на вывод
- При создании заявки P2P атомарно резервирует сумму вывода и комиссию в пользовательском Jetton-балансе.
- Комиссия платформы задаётся в basis points: 100 bps означает 1%. По документации сумма комиссии округляется вверх до минимальной единицы токена; фактическая ставка зависит от конфигурации.
- GRAM создаёт идемпотентную заявку, проверяет доступный токен и отдельно резервирует TON для gas. Резерв на сетевые расходы и комиссия P2P относятся к разным уровням учёта.
- После подтверждения GRAM платформа проводит списание резерва через ledger. При failed или rejected резерв P2P освобождается.
- Команда gram:jetton-withdrawals:sync в P2P документирована как ежеминутное восстановление недоставленных заявок и синхронизация активных статусов после перезапуска очереди.
В модели вывода GRAM определены состояния created, queued, processing, sent, confirmed, failed, rejected и manual_review. Состояние sent отделено от confirmed: отправка транзакции и подтверждение результата — разные этапы. Это статусы заявки на вывод, а не P2P-сделки.
Custody audit: сверка активов и обязательств
Защищённый custody endpoint GRAM возвращает агрегированный снимок: баланс, резерв и доступную сумму по управляемым кошелькам, отдельно пользовательские, collector и standalone кошельки, сведения казначейства. Вместе с суммами передаются признаки ошибок и давность синхронизации.
На стороне P2P документирована плановая сверка активов GRAM с обязательствами перед пользователями каждые 30 минут. Для неё предусмотрены допустимое расхождение в nanoTON, отдельный флаг включения и интервал повторного оповещения администраторов.
Сверка доставки депозитов и custody reconciliation отвечают на разные вопросы: все ли события дошли до P2P и согласуются ли учтённые обязательства с активами кошелькового контура. Снимок зависит от свежести синхронизации; сам по себе он не является доказательством платёжеспособности в реальном времени.
Связанный проект: собственный testnet Jetton TGRAM
Для интеграционного тестирования GRAM и P2P создан отдельный проект gram-test-jetton. Его токен GRAM Integration Test (TGRAM, decimals 9) работает в TON testnet. Он используется для проверки сценариев токенов и не представлен как mainnet-актив.
По документации контрактного проекта в него входят Jetton master/minter и Jetton Wallet, скрипты deploy, mint и transfer, чтение supply, metadata и balance, передача управления через change-admin/claim-admin и изменение on-chain metadata. Отдельно описаны тесты комиссий, bounce и административных операций, а также GitHub Actions CI с build, format, check и test.
Контракты и инструменты TGRAM находятся в собственной кодовой базе. В P2P интегрируется результат работы токена через GRAM; контрактные скрипты не являются частью Laravel-приложения. Исходники контрактов и выполнение CI в рамках этого разбора не проверялись.
Стек и инфраструктура
Приложение
PHP · Laravel · Inertia · Vue · REST API · P2P Engine · Security · Jetton Ledger.
Данные и процессы
MySQL 8 · Redis · Laravel Queue · Laravel Scheduler · Laravel Reverb · WebSocket.
Развёртывание
Docker · Nginx · PHP-FPM. В документации P2P web, app, queue, scheduler и reverb описаны как отдельные контейнеры.
Blockchain
GRAM wallet microservice · TON · Jetton · blockchain API · webhooks · outbox delivery · custody snapshot. TGRAM — отдельный testnet-проект.
Технически сложные моменты и результат
Основная сложность находится на стыке независимых состояний: участник отметил оплату, блокчейн подтвердил входящую транзакцию, очередь доставила событие, платформа отразила его в учёте. Для этих действий выделены разные операции и идентификаторы; сетевой retry не должен становиться новой финансовой операцией.
В проекте соединены P2P-сценарии, защищённый межсервисный API, раздельный учёт TON и Jetton, резервирование вывода и восстановление доставки. GRAM дополняет приложение кошельковой инфраструктурой и проверяемыми журналами обработки. Отдельный TGRAM даёт тестовый токен для проверки интеграции в TON testnet.
Это кейс backend и FinTech-разработки с конкретными механизмами учёта и согласования. Метрики нагрузки, оборота и коммерческого результата здесь не приводятся: подтверждённых измерений в материалах нет.
Основа технического разбора
Описание подготовлено по предоставленным маршрутам и README P2P, исходникам микросервисов GRAM и TON Wallet Lab и документации отдельного проекта TGRAM. Полная кодовая база P2P в этот разбор не входила: детали ledger, комиссии, custody audit и инфраструктуры P2P приведены по документации. Наличие маршрутов не заменяет проверку внутренних контроллеров, а наличие тестов в GRAM — отчёт об их выполнении.
