
Архитектура большинства гарант-сервисов неразрывно связана с рисками: ошибками, возможностью мошенничества, сложными и непрозрачными схемами. Ее можно заменить аналогом с принципиально другим уровнем безопасности — системой по модели эскроу. В ней нет необходимости доверять человеку, только математике.
Показываем, как реализовать технические гарантии безопасности сделок с помощью MultiSig-кошельков, Node.js, smart-контрактов, TronWeb v5. Разбираем код и логику проектирования P2P-платформы, которая не может украсть деньги пользователя (даже если захочет) 👇
👋 Привет, Хабр. На связи Кирилл, основатель KeyShield. В статье показываю, как может работать система для финансовых сделок между физлицами, в архитектуре которой доступ к деньгам не предусмотрен даже у админов.
Проблема — риски денежных переводов на доверии
Независимо от того, по какой причине открывается P2P-сделка (покупаете аккаунт, сайт, курс или платите фрилансеру), есть общая проблема: непонятно, кому ходить первым. Продавец не отдает товар без предоплаты, покупатель не отправляет деньги без гарантий. Участники не доверяют друг другу, поэтому используют гарант-сервисы.

Гарант — посредник (третья сторона) между заказчиком и исполнителем или между продавцом и покупателем. Этот человек или организация следит за безопасностью сделки, принимает оплату от одного участника и передает ее второму участнику только после того, как прописанные условия сделки выполнены.
P2P обмен с гарантом кажется рабочей схемой:
Покупатель открывает сделку (условия, дедлайны, суммы, порядок оплаты).
Покупатель на время отправляет деньги гаранту.
Продавец выполняет работу или продает товар.
Покупатель принимает, и посредник отправляет деньги продавцу.
Гарант-сервисы часто используются в таких сферах, как IT, финансы, недвижимость, маркетинг. Например, они нужны, если вы хотите выплатить гонорар подрядчику или купить цифровые товары. Юз-кейсов P2P обмена много.
Чем гарант-сервисы отличаются от эскроу
Сама по себе гарант-схема содержит уязвимости и риски. В этой модели два участника сделки вынуждены доверять третьему. При этом у посредника есть техническая возможность забрать деньги и исчезнуть.
Репутация и обещания — это не архитектура безопасности.
Если отправить крипто перевод на личный кошелек гаранта, фактически приходится слепо верить отзывам и маркетинговым заявлениям. Невозможно рассчитывать на 100% прозрачность и честность, потому что контроль над деньгами остается у третьей стороны.
Один из вариантов решения этой проблемы — эскроу. Из-за того, что он пока не получил широкого распространения на рынке СНГ, есть искажение восприятия: многие считают, что эскроу = гарант. Это не так.
Три основных отличия:
Гарант вручную контролирует сделку с криптовалютами, эскроу-сервис — автоматизирует P2P сделки за счет smart-контрактов и multisig-кошельков.
Гарант хранит деньги на личном кошельке и решает, кому их отдать. В эскроу деньги находятся в защищенной криптографией среде.
С гарантами все держится на доверии к человеку или бренду. С эскроу-счетами пользователь доверяет только математике и блокчейну.
Мы рассматриваем эскроу в узком смысле, как специальный финтех-сервис на основе блокчейна, где эскроу-счета = адреса кошельков в блокчейне, и выполнение условий договора контролируется автоматически. Это своеобразный условный счет, через который выполняется передача средств (только при выполнении условий).
Требования к архитектуре
Эскроу-модель задает направление, но не отвечает на вопрос реализации. Нужно выбрать конкретный стек: технологию управления средствами, блокчейн и интерфейс.
1. Технология без доверия
Trust-minimized технология уже есть — это multisig-кошельки (2-из-3). Мультиподписные криптокошельки для авторизации перевода требуют несколько закрытых ключей, в данном случае, как минимум двух из трех. Они помогают уйти от единой точки контроля, диверсифицировать управление средствами между несколькими сторонами. Если P2P сделки проходят через multisig-кошелек, ни одна сторона не имеет возможности забрать деньги без согласия других участников.
2. Блокчейн TRON для нативной поддержки USDT
Выбрали TRON, так как это крупнейшая сеть по объему USDT: более 50% всех стейблкоинов в мире — на TRC-20. Также там комиссии в доли цента, а не $5–20 как в Ethereum, и блоки с подтверждением за ~3 секунды. В протоколе TRON инфраструктура и система прав доступа реализованы удобно для разработчика. Он поддерживает мультиподпись на уровне аккаунта (не нужен отдельный smart-контракт).
3. Telegram как интерфейс и TWA
Много P2P-обменов уже происходит в Telegram: там заказчики и исполнители договариваются о работе. Также в TG встроено мини-приложение Wallet для крипто переводов, и платежи через мессенджер уже привычны. Telegram Web Apps позволяет рисовать нормальный фронтенд на JS/HTML. Создавать сервис с нуля казалось лишним, поэтому остановились на формате крипто бота Телеграмм.
Технологический стек и интеграции
Коротко о том, какие инструменты нужны для реализации системы эскроу-сделок с мультисигом на Троне через ТГ:
Технология | Назначение |
Node.js | Серверная логика, асинхронная обработка |
Telegraf v4 | Telegram Bot API фреймворк |
MongoDB + Mongoose | Хранение сделок, пользователей, логов |
TronWeb v5 | Взаимодействие с блокчейном TRON |
TronGrid API | Нода для чтения данных блокчейна |
Express.js | REST API для админ-панели и партнерского API |
FeeSaver | Аренда энергии в TRON для снижения комиссий |
Остро стоит вопрос об интеграциях с P2P-площадками и сообществами. Мы уже сейчас используем бесплатный и стабильный API-провайдер TronGrid (правда, пришлось писать rate-limiter) и сервис аренды энергии FeeSaver. Планируем также добавить:
Кошельки: TrustWallet, TronLink, SafePal;
Биржи: Binance, Bybit, OKX (как источник средств);
P2P-площадки: интеграция как безопасный эскроу;
Фриланс-платформы: плагин для безопасных оплат.
Стек понятен. Теперь разберем, как все это работает изнутри — начиная с самого главного: как создается кошелек, которым не может управлять ни одна сторона.
Как устроены multisig-кошельки 2-��з-3
Каждая сделка генерирует уникальный escrow-адрес в блокчейне TRON с тремя подписантами:
// blockchain.js — создание мультисиг-кошелька async createMultisigWallet(buyerKey, sellerKey, arbiterKey) { const newAccount = await tronWeb.createAccount(); const address = newAccount.address.base58; const permissionConfig = { owner_address: tronWeb.address.toHex(address), actives: [{ type: 2, permission_name: 'escrow_active', threshold: 2, // ← ПОРОГ: нужны 2 подписи из 3 keys: [ { address: buyerAddress, weight: 1 }, { address: sellerAddress, weight: 1 }, { address: arbiterAddress, weight: 1 } ] }] }; return { address, threshold: 2, permissionsJson: permissionConfig }; }
На этот адрес отправляются деньги. Они хранятся там от момента депозита покупателя до вывода продавцу. Для запуска инициализации перевода нужны 2 из 3 подписей. Поэтому сервис-посредник технически не сможет забрать деньги без согласия одной из сторон, даже если захочет.
Ограничение доверия через управление private keys
У участников крипто сделки есть 3 приватных ключа:
🔑 Ключ покупателя
🔑 Ключ продавца
🔑 Ключ арбитра (сервиса)
Генерация ключей для участников проходит так:
// blockchain.js — генерация ключевой пары async generateKeyPair() { const account = await tronWeb.createAccount(); return { privateKey: account.privateKey, // Показывается 1 раз, не сохраняется publicKey: account.publicKey, address: account.address.base58 }; }
Приватные ключи пользователей генерируются автоматически, показываются один раз не более чем на 60 секунд, не хранятся в базе данных и сразу стираются из памяти и логов. Да, требуется минимальное доверие в момент генерации, но доступ админов после нее исключен полностью. Так как сообщение с ключом мгновенно удаляется после первого назначения, ключи хранятся с флагом select: false.
Никто не может украсть деньги, потому что реализуются следующие сценарии:
Ситуация | Почему скам невозможен |
Арбитр хочет забрать деньги | Нужен ключ покупателя ИЛИ продавца |
Покупатель хочет забрать деньги | Нужен ключ продавца ИЛИ арбитра |
Продавец хочет забрать деньги | Нужен ключ покупателя ИЛИ арбитра |
Модель мультисиг-кошелька в БД
При механизме multisig 2-из-3 для запуска перевода крипты нужны две любые подписи. Это обеспечивается на уровне TRON.
// blockchain.js — мультиподпись (2-of-3) async multiSignTransaction(transaction, privateKeys) { let signedTx = transaction; for (const key of privateKeys) { signedTx = await tronWeb.trx.multiSign(signedTx, key); } return signedTx; // Транзакция пройдёт только если набран порог (2 подписи) }
Внутри базы данных можно реализовать модель multisig-кошельков следующим образом:
// MultisigWallet.js — структура хранения const multisigWalletSchema = { dealId: ObjectId, // К какой сделке привязан address: String, // Адрес кошелька в TRON buyerPublicKey: String, sellerPublicKey: String, arbiterPublicKey: String, privateKey: String, // select: false threshold: 2, // Всегда 2-of-3 permissionsJson: Object, balances: { TRX: Number, USDT: Number } };

Сделка от начала до конца: конечный State Machine
Каждой сделке мы присвоили 6 основных состояний и несколько второстепенных (для случаев отхождения от стандартного пути, например, при сорванных дедлайнах). Жизненный цикл — конечный автомат. Сделка не может перескочить из статуса created сразу в completed, она должна получить все статусы последовательно.
Диаграмма основных состояний
pending_counterparty (ожидание контрагента) ↓ waiting_for_wallet (ожидание кошелька) ↓ waiting_for_deposit (ожидание депозита) ↓ locked (средства заблокированы) ↓ in_progress (работа в процессе) ↓ ┌────┴────┐ ↓ ↓ completed dispute → resolved * При дедлайне + 12 часов → expired (автовозврат)
Это важно, потому что нельзя полагаться на последовательность HTTP-запросов от клиента: они могут прийти в любом порядке и задублироваться.
Состояние locked — центр архитектуры. До блокировки средств сделка представляет собой запись в базе данных MongoDB. А после перехода в locked она превращается в смарт-контракт на блокчейне. С этого момента невозможно изменить условия. Запускается серверный таймер автовозврата на случай, если продавец пропадет.
Как это выглядит для пользователя
Процесс сделки мы разделили на 4 основных этапа, каждый из которых состоит из нескольких шагов. Первый этап — создание — самый трудоемкий для пользователя. Все последующие процессы проходят быстро и прозрачно.
Этап 1: Создание (8–10 шагов)
Выбор роли → Покупатель или Продавец
Выбор метода → Username или Invite-ссылка
Указание контрагента
Название товара/услуги
Описание (от 20 символов)
Выбор актива → USDT (TRC-20)
Сумма (от 50 USDT)
Кто платит комиссию → Покупатель / Продавец / 50/50
Срок выполнения → 24ч / 48ч / 3 дня / 7 дней / 14 дней
Указание кошелька → Из сохраненных или ввод нового

Этап 2: Подключение контрагента
Контрагент получает уведомление или переходит по invite-ссылке
Указывает свой кошелек
Получает приватный ключ (показывается один раз)

Этап 3: Депозит
Покупатель переводит USDT на мультисиг-адрес
Система автоматически обнаруживает перевод
После подтверждения: средства заблокированы, статус → locked
Оба участника получают уведомление

Этап 4: Выполнение работы и выплата
Продавец выполняет работу и нажимает «Работа выполнена»
Покупатель проверяет и нажимает «Принять работу»
Победитель вводит свой приватный ключ
Система создает транзакцию, подписывает и о��правляет в блокчейн
Средства поступают на кошелек продавца
Комиссия автоматически отправляется сервису
Обе стороны получают уведомление со ссылкой на TronScan
Изнутри создание и отправка транзакции спроектированы так:
// Полный цикл выплаты const releaseTx = await blockchainService.createReleaseTransaction( deal.multisigAddress, deal.sellerAddress, releaseAmount, 'USDT' ); const signedTx = await blockchainService.signTransaction(releaseTx, wallet.privateKey); const result = await blockchainService.broadcastTransaction(signedTx); if (result.success) { console.log(`Выплата отправлена: ${result.txHash}`); }
💡 TRON — публичная сеть. Через сервис TronScan (TRON BlockChain Explorer) любой пользователь может увидеть, что деньги находятся на адресе, созданном специально для его сделки. Бот работает напрямую с блокчейном. Поэтому у пользователя нет ограничений, касающихся того, с какого кошелька или биржи он может отправить USDT.
Полная модель статусов сделки
Чтобы сделка никогда не оказывалась в неопределенном состоянии, мы разбили процесс на статусы. Это позволяет Telegram-боту показывать только тот экран, который соответствует текущему шагу.
status: { enum: [ 'created', // Создана 'pending_counterparty', // Ожидание контрагента 'waiting_for_seller_wallet', // Ожидание кошелька продавца 'waiting_for_buyer_wallet', // Ожидание кошелька покупателя 'waiting_for_deposit', // Ожидание депозита 'locked', // Средства заблокированы 'in_progress', // Работа в процессе 'completed', // Завершена успешно 'dispute', // Открыт спор 'resolved', // Спор решён 'cancelled', // Отменена 'expired' // Автовозврат ] }
Реальные алгоритмы работы
Депозиты покупателя обнаруживаются автоматически, без ручного подтверждения. Алгоритм обнаружения депозита обновляется каждые 30 секунд. Он должен:
Получить список сделок в статусе «ожидание депозита»;
Для каждой сделки запросить у TronGrid входящие USDT-переводы (Rate-limit: не более 8 запросов/сек к TronGrid);
Проверить сумму, и если она достаточна, записать транзакцию, активировать кошелек и уведомить стороны.
// depositMonitor.js async checkDealDeposit(deal) { let expectedAmount = deal.amount; if (deal.commissionType === 'buyer') { expectedAmount = deal.amount + deal.commission; } const deposit = await blockchainService.checkDeposit( deal.multisigAddress, deal.asset, 0 ); if (deposit) { // Атомарное обновление: защита от race condition const updated = await Deal.findOneAndUpdate( { _id: deal._id, status: 'waiting_for_deposit' }, { $set: { status: 'locked', depositTxHash: deposit.txHash } }, { new: true } ); if (!updated) return; await this.queueActivation(deal._id, deal.multisigAddress); await notifyBothParties(deal, deposit); } }
💡 Атомарная операция findOneAndUpdate гарантирует, что депозит будет обработан ровно один раз.
Алгоритм автовозврата запускается каждые 5 минут, чтобы:
Получить сделки с истекшим дедлайном.
Если дедлайн истек — уведомить обе стороны (12 часов на действия).
Если дедлайн + 12 часов:
работа сдана → автовыплата продавцу;
работа НЕ сдана → автовозврат покупателю.
Алгоритм разрешения спора запускается, если одна из сторон не согласна доводить сделку до завершения. При таком сценарии:
Одна из сторон открывает спор;
Обе стороны могут оставлять комментарии;
Арбитр изучает доказательства и принимает решение;
Победитель вводит приватный ключ → получает средства;
Проигравший получает +1 к счетчику поражений.
Если пользователь проигрывает 3 спора, он улетает в бан. Это можно реализовать, если нужно, чтобы в системе не было проблемных исполнителей и заказчиков, продавцов и покупателей.
Резюме о реализации безопасности
Чтобы была сформирована архитектура безопасной сделки, нужны технические гарантии:
TRON и TronScan дают прозрачность и проверяемость.
Мультисиг 2-из-3 гарантирует, что ни одна сторона не может забрать средства.
Личные подписи никогда не окажутся у арбитра или другой стороны сделки.
Депозиты покупателя обнаруживаются без подтверждения.
Если продавец не выполнил обязательства, деньги вернутся покупателю.
UX в TWA?
Чтобы не перегружать интерфейс десятками уведомлений, иконок, окон, кнопок и ссылок, в чате крипто бота Телеграмм мы используем всего 2 сообщения для всех процессов сделки.
Команда /start от пользователя.
Единственное сообщение бота, которое перерисовывается на каждом этапе.

Как это реализовано:
Стек навигации — как в мобильном приложении. Каждый экран сохраняется в историю.
Кнопка «Назад» — возвращает к предыдущему экрану с сохранением введенных данных.
Автоудаление ввода — когда пользователь вводит текст, сообщение удаляется сразу после обработки. Чат остается чистым.
Новое уведомление заменяет текущий экран — в чате всегда отображается только одно активное сообщение. Предыдущий экран сохраняется и восстанавливается по кнопке «Назад».
Пример UX-потока:
[Главное меню] → «Создать сделку» → [Выбор роли] → «Покупатель» → [Выбор метода] → «Ввести username» → [Ввод username] → пользователь пишет @seller (сообщение удалено, экран обновлён) → [Название товара] → ...
От идеи до рабочего прототипа — 6 недель
Менее чем 2 месяца ушло на архитектуру мультиподписей: permission-систему TRON, генерацию ключей, мониторинг депозитов и логику арбитража. Еще 2–3 недели — на доработку до публичной версии: UX, обработку edge-кейсов (неполный депозит, потерянный ключ), систему уведомлений.
Реализована полная цепочка: создание сделки → депозит → выполнение → выплата / спор / автовозврат. Недавно мы выкатили большое обновление интерфейса и технички и расширили лимит до 3 одновременных сделок на пользователя.
Когда безопасность — свойство архитектуры
Сейчас продукт на стадии early launch. У нас 50 зарегистрированных пользователей — знакомые, для которых вопрос безопасных оплат в крипте актуален в повседневной работе. В планах — расширение фич, поддержка дополнительных сетей и улучшение UX на основе отзывов.
Мы не питаем иллюзий, потому что полностью убрать доверие при ограничениях UX в Telegram сложно, но можно к этому приблизиться. Если подобные нашему подходы начнут применяться шире, возможно, со временем появится и стандарт сделок, где безопасность — свойство архитектуры.
