Кейс · P2P-биржа и крипто-инфраструктура · 2026
P2P-биржа, где пользователи обменивают USDT, TON и Jetton-токены на рубли напрямую друг с другом, а платформа держит крипто-часть в собственном кастоди, сверяет активы с обязательствами каждые полчаса и не отпускает вывод, пока ledger не сойдётся до копейки.
P2P-обмен — это всегда доверие между двумя людьми, которые никогда не встретятся, плюс крипто-часть, которую нельзя ни потерять, ни задвоить. Пользователь заводит USDT на TRC-20, TON или Jetton, выставляет объявление, договаривается со встречным в чате и ждёт, что после подтверждения оплаты платформа отпустит крипту — без ошибки на копейку и без второго списания при повторном запросе.
При этом сама биржа не хранит деньги в одном кошельке «на всякий случай»: TON и Jetton приходят и уходят через отдельный кастодиальный микросервис GRAM, а сайт должен доверять его событиям ровно настолько, насколько может их проверить — подписью, идемпотентностью и регулярной сверкой остатков.
Продавец публикует ордер по своему курсу — фиксированному или плавающему от биржевого; покупатель откликается, и для пары создаётся сделка с зафиксированной на момент отклика ценой.
Market · курсы онлайнКрипто-часть продавца замораживается на балансе сразу, чтобы её нельзя было увести в другую сделку. Стороны договариваются в чате в реальном времени, прикладывают чек оплаты.
Deal · WebSocket через ReverbНеоплаченная сделка автоматически отменяется по таймауту, неподтверждённая после оплаты — эскалируется, а фоновые джобы следят за этим независимо от того, открыт ли у сторон браузер.
CancelUnpaidDeal / CancelUnconfirmedDeal / AutoRejectDealЕсли стороны не согласны, любая может открыть спор с одной из заранее заданных причин — сделка замораживается до решения администратора, который видит переписку и чек целиком.
AdminDisputeController · причины из справочникаПодтверждение оплаты снимает заморозку и переводит крипто-часть покупателю одной атомарной операцией — промежуточного состояния, в котором деньги «нигде», не существует.
BalanceService · транзакционноUSDT на TRON, TON и Jetton-токены заходят на платформу не одинаково. У TRON-переводов своя логика аренды энергии и мониторинга адресов, а TON и Jetton вообще не трогают блокчейн напрямую с основного сайта — за это отвечает микросервис GRAM, который сайт вызывает через подписанный HMAC-API.
Собственный TRON-кошелёк на mnemonic-ключах, мониторинг входящих переводов и аренда энергии под исходящий TRC-20 перевод, чтобы не платить полную комиссию в TRX за каждый вывод.
Депозиты приходят подтверждёнными событиями от GRAM в crypto_deposits, отдельно от legacy-баланса USDT. Минимальная сумма и сеть (testnet/mainnet) проверяются на приёме, а не постфактум.
Только allowlisted токены, отдельный endpoint приёма и неизменяемый jetton_ledger_entries. Вывод резервирует сумму и комиссию сразу, а списывает — только после подтверждения из GRAM.
Idempotency-Key и external_id; повторный вызов возвращает тот же результат с credited=false, а не создаёт вторую операцию.gram:custody:audit каждые 30 минут сравнивает управляемые TON-кошельки GRAM с суммой обязательств перед пользователями и держит допуск в 0.1 TON на сетевые комиссии — расхождение сверх допуска уходит администратору алертом.Пользователь просто меняет крипту на рубли с другим человеком в чате — а под капотом каждая копейка проходит через заморозку, идемпотентный ledger и плановую сверку активов, так что ни задвоенный депозит, ни зависшая сделка не остаются незамеченными.
Laravel 12 · MySQL · Redis · Laravel Reverb · Vue 3 · Inertia.js · TRC-20 · TON · Jetton · GRAM