Архитектура Trustless моста (TVM ↔ TVM)
Общее описание
Trustless мост — это децентрализованная кроссчейн система для передачи токенов между TVM-совместимыми сетями, такими как TON и Tetra L2. В отличие от relay-based моста (используемого для переводов между EVM и TVM сетями), Trustless мост не полагается на relay-ноды для подтверждения трансферов. Вместо этого система использует криптографическую верификацию на основе Merkle proofs и специализированных LiteClient контрактов.
Ключевая особенность архитектуры — математическое доказательство корректности каждой транзакции, которое может быть независимо проверено любым участником сети. Такой подход устраняет необходимость доверять централизованным операторам или группам валидаторов моста.
Ключевое преимущество
Пользователю не нужно доверять третьим сторонам — только криптографическим алгоритмам и консенсусу валидаторов TVM сети. Это обеспечивает полную децентрализацию трансферов: ни один актор не может заблокировать средства или подделать транзакцию без контроля большинства валидаторов сети.
Принципиальная схема

Глоссарий
Native и Alien токены
Система оперирует двумя типами токенов в зависимости от их происхождения относительно текущей сети:
| Термин | Описание |
|---|---|
| Native токен | Токен, изначально созданный и существующий в данной сети. При трансфере в другую сеть блокируется (lock) в Proxy-контракте исходной сети, оставаясь в ней как обеспечение. Право собственности на эти заблокированные токены представлено соответствующими alien токенами в сети назначения. |
| Alien токен | Обёрнутое (wrapped) представление токена из другой сети. Создаётся (mint) в сети назначения при входящем трансфере, полностью обеспечено заблокированными native токенами в исходной сети. При обратном трансфере сжигается (burn), освобождая соответствующие native токены. |
Пример:
- USDT в сети TON — это Native токен для TON
- При трансфере USDT из TON в Tetra L2:
- В TON: USDT блокируется в NativeProxy (остаётся Native, физически находится в исходной сети)
- В Tetra L2: минтится USDT (Alien токен) — обёрнутая версия, полностью обеспеченная заблокированными токенами в TON
Компоненты верификации
Система верификации состоит из нескольких взаимосвязанных компонентов, обеспечивающих криптографическую проверку кроссчейн транзакций:
| Термин | Описание |
|---|---|
| LiteClient | Смарт-контракт легкого клиента, развёрнутый в каждой сети и хранящий актуальную информацию о ключевых блоках другой сети. Содержит текущий набор валидаторов, их веса (влияние в консенсусе), временные метки эпох. Автоматически обновляется Sync Service при смене эпох валидаторов. Выступает как доверенный источник истины о состоянии другой сети. |
| TransactionChecker | Контракт для верификации транзакций через Merkle proofs. Проверяет включение транзакции в блок через Merkle proof, затем валидирует подписи блока через LiteClient. Работает как независимый арбитр, математически подтверждающий существование транзакции. |
| Proof Chain | Цепочка криптографических доказательств, связывающая транзакцию с консенсусом валидаторов: Merkle proof транзакции → Merkle proof блока → верификация подписей валидаторов через LiteClient. Каждое звено цепи проверяется независимо, обеспечивая надёжность всей конструкции. |
| Key Block | Ключевой блок TVM сети, содержащий информацию о смене набора валидаторов (validator set rotation). Синхронизируется между сетями через Sync Service, обеспечивая актуальность информации о валидаторах в LiteClient контрактах. |
Конфигурация и управление
Управление трансферами осуществляется через систему конфигурационных контрактов и специализированных proxy-контрактов:
| Термин | Описание |
|---|---|
| EventConfiguration | Контракт конфигурации события, управляющий жизненным циклом Event-контрактов. Осуществляет деплой Event-контрактов для обработки входящих трансферов, верифицирует параметры событий (chainId, временные метки, источник события). Выступает как фабрика и валидатор событий. |
| NativeProxy | Контракт-прокси для управления native токенами. Выполняет блокировку (lock) токенов при исходящих трансферах, сохраняя их как обеспечение, и разблокировку (unlock) при входящих трансферах после верификации. Управляет комиссиями, дневными лимитами и ликвидностью. |
| AlienProxy | Контракт-прокси для управления alien токенами. Выполняет минтинг (создание) новых alien токенов при входящих трансферах и сжигание (burn) при исходящих. Управляет деплоем новых типов alien токенов и интеграцией с MergePool для объединения токенов из разных источников. |
| MergePool | Контракт для объединения alien токенов из разных сетей в единое каноническое представление (canon token). Позволяет использовать токены одного типа, но из разных источников (например, USDT из TON и USDT из Ethereum), как взаимозаменяемые активы. Обрабатывает конвертацию между разными decimals. |
| Predeployed Token | Заранее зарегистрированный токен для сценария native-native, когда токен является нативным в обеих сетях. Используется для специальных токенов (например, wrapped native токенов типа wTON), которые должны существовать как native в нескольких сетях одновременно. |
Типы трансферов
Система поддерживает три основных типа трансферов в зависимости от направления и природы токенов:
| Поток | Действие в сети отправления | Действие в сети назначения | Event-контракт |
|---|---|---|---|
| Lock Native → Mint Alien | NativeProxy блокирует native токены | AlienProxy создаёт соответствующие alien токены | MultiVaultTvmTvmEventAlien |
| Burn Alien → Unlock Native | AlienProxy сжигает alien токены | NativeProxy разблокирует соответствующие native токены | MultiVaultTvmTvmEventNative |
| Lock Native → Unlock Native | NativeProxy блокирует native токены | AlienProxy проверяет predeployed token и передаёт управление NativeProxy для разблокировки | MultiVaultTvmTvmEventAlien (!) |
Структура трансфера
Каждый кросс-чейн трансфер представляет собой атомарную операцию, состоящую из двух логических частей, выполняемых последовательно:
- Часть в сети отправления — пользователь инициирует блокировку (для native) или сжигание (для alien) токенов, Proxy-контракт эмитит событие, содержащее все параметры трансфера
- Часть в сети назначения — система строит криптографическое доказательство (proof chain), верифицирует событие через TransactionChecker и LiteClient, затем выполняет минтинг (для alien) или разблокировку (для native) токенов получателю
Важно понимать, что обе части связаны криптографически: вторая часть может быть выполнена только при наличии математически корректного доказательства первой части.
Event-контракт
Для каждого трансфера в сети назначения деплоится индивидуальный Event-контракт — уникальный смарт-контракт, представляющий конкретную операцию трансфера. Event-контракт выполняет несколько критически важных функций:
Защита от double-spending — адрес контракта детерминированно вычисляется из
msgHashисходного сообщения через функцию деривации. Это математически гарантирует, что одна транзакция может быть обработана только один раз: повторная попытка деплоя Event-контракта с тем же msgHash завершится ошибкой на уровне TVM, так как контракт с таким адресом уже существует.Координация процесса верификации — Event-контракт управляет взаимодействием с TransactionChecker и LiteClient, отслеживая статус верификации и обрабатывая результаты.
Участие в логике Merge — Event-контракт взаимодействует с MergePool/MergeRouter для определения, какой токен получит пользователь: derive-токен (специфичный для источника) или canon-токен (объединённое представление) на основе конфигурации MergePool.
Управление edge cases — обработка ситуаций превышения лимитов и нехватки ликвидности, координация с провайдерами ликвидности.
Механизм верификации
Trustless верификация основана на математическом доказательстве того, что транзакция была включена в блок и этот блок был подтверждён валидаторами исходной сети через их криптографические подписи.
Обзор
Система верификации состоит из трёх взаимосвязанных компонентов:
- LiteClient — хранит актуальный набор валидаторов другой сети (публичные ключи, веса, параметры эпохи), выступая как источник истины о консенсусе
- TransactionChecker — верифицирует Merkle proofs транзакций и блоков, подтверждая математически корректное включение транзакции в блокчейн
- Sync Service — автоматически синхронизирует ключевые блоки между сетями, обеспечивая актуальность validator set в LiteClient
LiteClient и Key Blocks
LiteClient — это специализированный смарт-контракт, развёрнутый в каждой сети и хранящий информацию о текущем наборе валидаторов другой TVM сети (из которой приходят трансферы). Он работает как легковесная версия полной ноды, но хранит только информацию о ключевых блоках и validator set, без полной истории транзакций.
Информация обновляется автоматически при смене эпох валидаторов (validator set rotation) через специализированную службу Sync Service, которая отслеживает ключевые блоки и транслирует изменения между сетями.
Структура хранимых данных:
current_seq_no— номер последовательности текущего ключевого блока (monotonically increasing sequence number)current_epoch_since/until— временные границы текущей эпохи валидаторов (unix timestamp), определяющие период действия validator setcurrent_cutoff_weight— минимальный порог подписей для подтверждения блока: 2/3 + 1 от общего веса валидаторов (византийский порог)current_validators_set— словарь валидаторов: validator_index → (публичный ключ ed25519 + вес в консенсусе)
Процесс обновления validator set:
Обновление набора валидаторов — критически важная операция, требующая строгой верификации:
Отслеживание key blocks: Sync Service непрерывно мониторит блокчейн исходной сети, отслеживая появление key blocks (блоков, содержащих информацию о смене validator set)
Подготовка доказательства: При появлении нового key block Sync Service:
- Скачивает полный блок с Merkle proof структурой
- Собирает подписи валидаторов для этого блока
- Формирует proof chain, связывающий блок с консенсусом
Верификация на LiteClient: Sync Service вызывает
new_key_block()на контракте LiteClient, передавая:- Данные блока
- Merkle proof блока
- Коллекцию подписей валидаторов
Проверки LiteClient:
- Корректность Merkle proof: проверка математической корректности proof структуры блока
- Тип блока: верификация, что блок является key block (содержит
ConfigParamsс новым validator set) - Валидность подписей: проверка криптографических подписей блока через
ed25519_check_signature()для каждого валидатора из текущего набора (используется existing validator set для подтверждения нового) - Достижение порога: проверка, что суммарный вес подписавших валидаторов ≥
cutoff_weight
Обновление состояния: При успешной верификации LiteClient:
- Извлекает новый validator set из
ConfigParamskey block - Обновляет
current_validators_setс новыми публичными ключами и весами - Обновляет
current_epoch_since/untilс новыми временными границами эпохи - Вычисляет новый
cutoff_weight=(total_weight * 2 / 3) + 1 - Инкрементирует
current_seq_no
- Извлекает новый validator set из
Византийская отказоустойчивость
Cutoff weight формула (total_weight * 2 / 3) + 1 реализует классический византийский порог, гарантирующий безопасность при наличии до 1/3 злонамеренных или отказавших валидаторов.
В математическом выражении: для успешной атаки злоумышленнику необходимо скомпрометировать >1/3 всех валидаторов по весу. Если скомпрометировано ≤1/3, они физически не смогут набрать требуемый cutoff weight для подтверждения поддельного блока — им не хватит суммарного веса даже если все скомпрометированные валидаторы будут действовать согласованно.
Это свойство обеспечивает cryptographic safety: даже если треть сети контролируется атакующими, честное большинство (≥2/3) сохраняет контроль над консенсусом.
TransactionChecker и Merkle Proofs
TransactionChecker — это специализированный контракт верификации, выполняющий криптографическую проверку того, что конкретная транзакция была включена в определённый блок, и этот блок был подписан достаточным количеством валидаторов.
Механизм работает на основе Merkle proofs — математических структур данных, позволяющих эффективно доказать включение элемента в набор без необходимости передавать весь набор. В контексте блокчейна: можно доказать, что транзакция находится в блоке, не передавая все транзакции блока.
Алгоритм верификации (пошаговый):
Инициация проверки: Event-контракт вызывает
check_transaction()на TransactionChecker, передавая:- Адрес аккаунта, выполнившего транзакцию
- Логическое время (lt) транзакции
- Закодированное доказательство (proof data)
Декодирование proof структуры: TransactionChecker разбирает proof data, извлекая:
tx_proof— Merkle proof, связывающий транзакцию с блоком (цепочка хешей от транзакции до корня Merkle tree блока)block_proof— Merkle proof блока (доказательство, что блок принадлежит мастерчейну)signatures— коллекция подписей валидаторов для этого блока (validator_index → signature)
Верификация транзакции в блоке: TransactionChecker вызывает
lookup_tx_in_block():- Проверяет Merkle path от хеша транзакции к корню блока
- Верифицирует, что
hash(transaction) ∈ block.transactions_rootчерез последовательность хешей - Извлекает хеш блока (
block_hash) для дальнейшей верификации
Делегирование проверки подписей: TransactionChecker отправляет
check_block()запрос в LiteClient с:block_hash— хеш блока для проверкиblock_proof— доказательство блокаsignatures— коллекция подписей валидаторов
Верификация подписей в LiteClient: LiteClient выполняет критическую проверку:
- Итерируется по коллекции
signatures - Для каждой подписи:
- Извлекает
validator_indexиsignature - Получает
pubkeyиweightвалидатора изcurrent_validators_set[validator_index] - Вызывает
ed25519_check_signature(block_hash, signature, pubkey) - При успехе:
total_signed_weight += weight
- Извлекает
- Финальная проверка:
total_signed_weight >= cutoff_weight
- Итерируется по коллекции
Подтверждение верификации: При успешной проверке:
- LiteClient отправляет обратный вызов с результатом верификации
- TransactionChecker получает подтверждение
- TransactionChecker отправляет
response::transaction_checkedEvent-контракту - Event-контракт обновляет статус и продолжает обработку трансфера
Защита от атак
Система реализует многоуровневую защиту от различных векторов атак:
| Атака | Защитный механизм |
|---|---|
| Double-spending | Адрес Event-контракта детерминированно вычисляется из msgHash. Повторный деплой контракта с идентичным адресом физически невозможен в TVM. |
| Replay attack | EventConfiguration верифицирует chainId и destinationChainId — событие из одной сети не может быть применено в другой. |
| Forged proofs | Merkle proof верифицируется криптографически. Подделка математически невозможна без знания приватных ключей валидаторов. |
| Invalid signatures | LiteClient проверяет, что суммарный вес подписей ≥ 2/3 + 1 от общего веса. |
Компоненты системы
On-chain компоненты (Смарт-контракты)
LiteClient
Контракт легкого клиента, хранящий информацию о ключевых блоках другой сети.
Хранимые данные:
current_seq_no— номер последовательности текущего ключевого блокаcurrent_epoch_since/until— временные метки начала/окончания эпохи валидаторовcurrent_cutoff_weight— минимальный вес подписей (2/3 + 1 от общего веса валидаторов)current_validators_set— набор валидаторов с публичными ключами и весами
Операции:
new_key_block— обработка нового ключевого блока: верификация подписей, обновление набора валидаторовcheck_block— проверка подписей блока против текущего набора валидаторов
TransactionChecker
Контракт для верификации транзакций из другой сети через Merkle proofs.
Операции:
check_transaction— проверка транзакции:- Извлекает Merkle proof транзакции и блока
- Проверяет, что транзакция существует в блоке
- Отправляет запрос в LiteClient для верификации подписей блока
- При успешной верификации отправляет
response::transaction_checked
ProxyMultiVaultNative (NativeProxy)
Proxy-контракт для работы с native токенами (jettons).
Основные функции:
- Принимает native токены (lock) при исходящих трансферах
- Отправляет native токены (unlock) при входящих трансферах
- Эмитит события для трансферов в другие сети
- Управляет комиссиями и дневными лимитами
Ключевые методы:
transferNotification— callback при получении jetton-токенов, инициирует исходящий трансферonTvmEventConfirmedExtended— обработка подтверждённого события, завершение входящего трансфера
ProxyMultiVaultAlien (AlienProxy)
Proxy-контракт для работы с alien токенами.
Основные функции:
- Минтит alien токены при входящих трансферах
- Обрабатывает callback после сжигания alien токенов и инициирует исходящий трансфер
- Управляет деплоем новых alien токенов
- Работает с MergePool/MergeRouter для объединения токенов
Ключевые методы:
onTvmEventConfirmedExtended— минтинг alien токенов при входящем трансфереonAcceptTokensBurn— callback от jetton-контракта после сжигания токеновdeployTvmAlienToken— деплой нового alien токена
EventConfiguration (TvmTvmEventConfiguration)
Контракт конфигурации событий, управляющий деплоем event-контрактов.
Хранимые данные:
- Адрес TransactionChecker
- Код event-контракта
- Адрес proxy-контракта
- Параметры конфигурации (chainId, startTimestamp, endTimestamp)
Ключевые методы:
deployEvent— деплой нового event-контракта для обработки входящего трансфераderiveEventAddress— вычисление детерминированного адреса Event-контракта изmsgHashonTvmEventConfirmedExtended— callback от Event, проксирует вызов на Proxy
MultiVaultTvmTvmEvent (Alien / Native)
Event-контракты для обработки конкретных трансферов.
Ключевые методы:
processProof— обработка proof транзакции, вызов TransactionCheckeronTrustlessVerify— callback от TransactionChecker при успешной верификации_onConfirm— вызов proxy для завершения трансфера
MergePool / MergeRouter
Контракты для объединения alien токенов из разных сетей в единое представление (canon token). Например, USDT переведённый из TON и USDT переведённый из Ethereum могут быть объединены в один canon USDT.
MergeRouter:
- Роутинг к соответствующему MergePool для токена
MergePool:
- Хранит маппинг derive-токенов к canon-токену
- Конвертация между decimals разных представлений
Off-chain компоненты (Backend)
Sync Service
Фоновый сервис синхронизации ключевых блоков между сетями.
Важно
Sync Service работает в фоновом режиме и синхронизирует ключевые блоки периодически, а не для каждого трансфера. Это необходимо для поддержания актуального набора валидаторов в LiteClient.
Функции:
- Отслеживает ключевые блоки в сети отправления
- Загружает актуальную информацию о validator set в контракт LiteClient сети назначения
- Вызывает
new_key_blockна LiteClient для обновления набора валидаторов
Частота обновлений:
- Key blocks появляются при смене эпох валидаторов
- Обычно 1-2 раза в сутки (зависит от сети)
Proof API
Легкая нода, синхронизирующая блоки и предоставляющая API для построения proof chain.
Функции:
- Синхронизирует все блоки в реальном времени
- Формирует Merkle tree proof для транзакции
- Формирует proof блока
- Endpoint:
GET /v1/proof_chain/{address}/{lt}— возвращает BOC с proof chain
Bridge API
Индексатор событий для конкретной TVM сети.
Функции:
- Индексация событий из proxy-контрактов
- Отслеживание статусов трансферов
- Предоставление данных для деплоя event-контрактов
Особенность: Один инстанс Bridge API обслуживает одну TVM сеть.
Bridge Aggregator API
Агрегатор над всеми API для работы с трансферами.
Функции:
- Подготовка payload для трансферов
- Объединение истории трансферов из всех сетей
- Отслеживание статусов трансферов независимо от сетей
Ключевые endpoints:
POST /payload/build— построить payload для транзакции трансфераPOST /transfers/search— поиск трансферов с фильтрациейPOST /transfers/status— получить статус конкретного трансфера
Жизненный цикл Event-контракта
Статусы Event-контракта
| Код | Статус | Описание |
|---|---|---|
| 0 | Initializing | Начальное состояние после деплоя |
| 1 | Pending | Ожидание верификации через TransactionChecker |
| 2 | Confirmed | Трансфер подтверждён, proxy вызван, токены доставлены |
| 3 | Rejected | Трансфер отклонён (верификация провалена) |
| 4 | Cancelled | Трансфер отменён пользователем |
| 5 | LimitReached | Превышен дневной лимит, ожидает одобрения |
| 6 | LiquidityRequested | Запрошена ликвидность от провайдеров |
| 7 | LiquidityProvided | Ликвидность предоставлена |
| 8 | Verified | Транзакция верифицирована (trustless), но токены ещё не доставлены |
Диаграмма переходов
Основной поток (успешный трансфер)
- Initializing — EventConfiguration деплоит контракт, вызывает
processProof() - Pending — Event отправляет
verifyTx()в TransactionChecker, ожидает ответа - Verified — TransactionChecker подтвердил транзакцию через
onTrustlessVerify(true) - Confirmed — Event вызвал
_onConfirm(), Proxy выполнил mint/unlock
Edge Cases
LimitReached (превышен дневной лимит)
Когда сумма трансфера превышает дневной лимит:
- Proxy вызывает
Event.dailyLimitReached(limitApprover) - Статус → LimitReached
limitApproverможет:approveLimit()→ продолжить трансфер → ConfirmedrejectLimit()→ отклонить → Rejected
- Пользователь может:
cancel()→ Cancelled (обратный трансфер)
LiquidityRequested (недостаточно ликвидности)
Когда NativeProxy не может unlock токены (недостаточно баланса):
- NativeProxy вызывает
Event.notEnoughLiquidity() - Статус → LiquidityRequested
- Event запрашивает
eventTokenWalletдля приёма ликвидности - Провайдер ликвидности может отправить токены с bounty
- После получения → LiquidityProvided → токены доставлены пользователю
- Или пользователь может:
cancel()→ Cancelled (обратный трансфер)
Bounty для провайдера
Провайдер ликвидности получает bounty — вознаграждение от пользователя за предоставление ликвидности. Размер bounty устанавливается пользователем или sender'ом при инициации трансфера.
Потоки трансферов
Lock Native → Mint Alien
Этот поток описывает перевод native токена из сети отправления в сеть назначения, где он становится alien токеном.
Пошаговое описание
Шаг 1-2: Инициация и блокировка
Пользователь отправляет jetton-токены на NativeProxy. В payload указывается адрес получателя и целевая сеть. Proxy блокирует токены и эмитит событие TvmTvmNative.
Шаг 3: Деплой Event-контракта
Proof API генерирует Merkle proof транзакции. EventConfiguration деплоит event-контракт с данными proof в сети назначения.
Шаг 4-5: Верификация
Event-контракт вызывает TransactionChecker для верификации транзакции. TransactionChecker проверяет Merkle proof и запрашивает LiteClient для верификации подписей блока.
Шаг 6-7: Подтверждение
При успешной верификации TransactionChecker вызывает onTrustlessVerify(true) на Event-контракте. Статус меняется на Verified. Затем Event-контракт вызывает _onConfirm(), который:
- Меняет статус на
Confirmed - Отправляет
onTvmEventConfirmedExtendedв AlienProxy
Шаг 8-9: Минтинг
AlienProxy получает подтверждение, проверяет лимиты, взимает комиссию и минтит alien-токены получателю.
Burn Alien → Unlock Native
Обратный поток: возврат alien токена в исходную сеть, где разблокируются native токены.
Пошаговое описание
Шаг 1-2: Пользователь сжигает alien токены через AlienProxy. Proxy эмитит событие TvmTvmAlien.
Шаг 3-5: Деплой Event-контракта и верификация аналогично предыдущему потоку.
Шаг 6-7: Event-контракт получает подтверждение, статус меняется Verified → Confirmed.
Шаг 8-9: NativeProxy получает подтверждение и разлокивает (unlock) native токены получателю.
Edge Case: Недостаточно ликвидности
Если баланс wallet NativeProxy недостаточен для unlock:
- NativeProxy вызывает
Event.notEnoughLiquidity() - Event → статус LiquidityRequested
- Провайдер ликвидности может отправить токены с bounty
- Или пользователь может отменить трансфер через
cancel()
Lock Native → Unlock Native
Поток для трансфера native токена между сетями, где в обеих сетях токен является native.
Особенность реализации
Трансфер технически выполняется через Alien-поток, но на AlienProxy происходит проверка: если для токена настроен native-native сценарий (есть запись в predeployedTokens), то AlienProxy не минтит токен, а проксирует вызов на NativeProxy.
Пошаговое описание
Шаг 1-2: Пользователь отправляет native токены на NativeProxy в сети отправления. Токены блокируются, эмитится событие TvmTvmNative.
Шаг 3-5: В сети назначения деплоится MultiVaultTvmTvmEventAlien (не Native!) через AlienEventConfiguration. Происходит верификация через TransactionChecker.
Шаг 6-7: Event-контракт вызывает receivePredeployedToken на AlienProxy. Если токен зарегистрирован в predeployedTokens, возвращается PredeployedTokenData с адресом nativeProxyTokenWallet.
Шаг 8-9: После верификации Event-контракт вызывает onTvmEventConfirmedExtended на AlienProxy, передавая nativeProxyTokenWallet в метаданных.
Шаг 10: AlienProxy проверяет nativeProxyTokenWallet.hasValue(). Если true — не минтит, а проксирует вызов на NativeProxy через proxyMultiVaultNative.onTvmEventConfirmedExtended().
Шаг 11: NativeProxy получает вызов (принимает от AlienProxy или напрямую от EventConfig), разблокирует native токены и отправляет получателю.
Когда используется этот поток?
Lock Native → Unlock Native используется когда токен настроен как native в обеих сетях через predeployedTokens в AlienProxy. Это возможно для:
- Wrapped native токенов (например, wTON)
- Токенов, специально настроенных администратором
Настройка происходит через регистрацию PredeployedTokenData в маппинге tvmConfiguration.predeployedTokens.
Риски и защитные механизмы
| Риск | Причина | Защитный механизм |
|---|---|---|
| Double-spending | Повторная обработка той же транзакции | Адрес Event-контракта детерминированно вычисляется из msgHash. Повторный деплой невозможен. |
| Forged Merkle proof | Подделка proof транзакции | Merkle proof верифицируется криптографически через extract_merkle_proof() и lookup_tx_in_block() |
| Invalid block signatures | Недостаточно подписей или подписи неверны | LiteClient проверяет: суммарный вес подписавших ≥ cutoff_weight (2/3 + 1) |
| Outdated validator set | LiteClient хранит устаревший набор валидаторов | Sync Service периодически обновляет validator set через new_key_block() |
| Replay attack | Event из одной сети обрабатывается в другой | EventConfiguration проверяет chainId в proof == networkConfiguration.chainId |
| Wrong destination chain | Event предназначен для другой сети | EventConfiguration проверяет destinationChainId |
| Unauthorized event emitter | Событие эмитировано не Proxy-контрактом | EventConfiguration проверяет accountAddr == eventEmitter |
| Daily limit exceeded | Превышен дневной лимит трансфера | Proxy проверяет лимиты; при превышении → статус LimitReached, ожидает одобрения |
| Not enough liquidity | NativeProxy не может unlock токены | NativeProxy вызывает notEnoughLiquidity(); провайдер может предоставить ликвидность с bounty |
| Wrong predeployed token | Неверный externalNativeProxyWallet | Event проверяет соответствие с данными из predeployedTokens |
Что делать при проблемах с трансфером?
- LimitReached — дождитесь одобрения от
limitApproverили отмените трансфер - LiquidityRequested — дождитесь провайдера ликвидности или отмените трансфер (получите обратный трансфер в сеть отправления)
- Cancelled — токены будут возвращены в сеть отправления через обратный трансфер
Ошибки смарт-контрактов
Event-контракты
Ошибки Event-контрактов (MultiVaultTvmTvmEventAlien, MultiVaultTvmTvmEventNative):
| Код | Условие |
|---|---|
| 2321 | Неверный статус для processProof(): status != Initializing && status != Pending && status != Verified |
| 2313 | Вызов не от EventConfiguration: msg.sender != eventInitData.configuration |
| 2329 | Callback не от TransactionChecker: msg.sender != transactionChecker |
| 2312 | Неверный статус для onTrustlessVerify(): status != Pending |
| 2901 | Callback не от Proxy: msg.sender != transitionalData.proxy |
| 2330 | Неверный externalNativeProxyWallet для predeployed token |
| 2326 | Callback не от TokenRoot: msg.sender != transitionalData.token |
| 2327 | Callback не от MergeRouter: msg.sender != transitionalData.router |
| 2328 | Callback не от MergePool: msg.sender != transitionalData.pool |
| 2335 | Вызов не от limitApprover: msg.sender != limitApprover |
| 2332 | Вызов не от recipient/sender (для cancel/setBounty) |
| 2324 | Неверный статус для операции (approveLimit, rejectLimit, cancel, setBounty, retry) |
| 2333 | Bounty превышает amount: bounty > eventData.amount |
| 2334 | Callback не от eventTokenWallet: msg.sender != eventTokenWallet |
| 2331 | Callback не от Proxy (Native Event) или не от proxy/native_proxy (Alien Event) |
EventConfiguration
Ошибки контракта TvmTvmEventConfiguration:
| Код | Условие |
|---|---|
| 2218 | endTimestamp уже установлен: networkConfiguration.endTimestamp != 0 |
| 2216 | endTimestamp меньше startTimestamp |
| 2221 | Proof из другой сети: chainId != networkConfiguration.chainId |
| 2222 | Неверный msgHash: tvm.hash(message) != _eventVoteData.msgHash |
| 2223 | Событие не для целевой сети: destinationChainId != TON_GLOBAL_ID |
| 2220 | Событие не от Proxy: accountAddr != eventEmitter.value |
| 2211 | Событие раньше startTimestamp: txTimestamp < networkConfiguration.startTimestamp |
| 2215 | Событие позже endTimestamp (если endTimestamp != 0) |
| 2212 | Callback не от Event-контракта: deriveEventAddress(_eventInitData) != msg.sender |
Proxy-контракты
Ошибки контрактов ProxyMultiVaultAlien и ProxyMultiVaultNative:
| Код | Условие |
|---|---|
| 2710 | Callback не от разрешённой EventConfiguration: конфигурация отсутствует в tvmConfiguration.incomingConfigurations |
TransactionChecker
Ошибки контракта TransactionChecker:
| Код | Условие |
|---|---|
| 200 | Транзакция не найдена в блоке |
| 201 | Неверный хеш транзакции |
| 202 | Блок не является masterchain блоком |
| 203 | Callback не от LiteClient: sender_address != ctx_lite_client_addr |
LiteClient
Ошибки контракта LiteClient:
| Код | Условие |
|---|---|
| 111 | Блок не является key block |
| 112 | Key block из той же эпохи |
| 113 | Key block из старой эпохи |
| 114 | Неверная подпись валидатора |
| 115 | Недостаточный вес подписей: total_signed_weight < ctx_current_cutoff_weight |
| 116 | Некорректные параметры эпохи валидаторов |
Общие ошибки Merkle Proof
| Код | Условие |
|---|---|
| 101 | Cell не является exotic cell |
| 102 | Cell не является Merkle proof |
| 103 | Cell не является Merkle update |