
Симуляция транзакции: что транзакция сделает до того, как вы её подпишете
Адрес верный. Сумма верная. Вы проверили и то и другое. И транзакция всё равно не то, чем вы её считаете.
Это не гипотеза. Это обычная форма большинства криптопотерь, в которых участвует аккуратный человек. Никто не уговаривал его отправить деньги незнакомцу. Он одобрил нечто, у чего все видимые части были правильными, а последствия лежали совсем в другом месте — в разрешении на трату токенов, в вызове контракта, в одном символе адреса, который он видел сто раз.
Симуляция — это попытка закрыть этот разрыв: показать вам последствия транзакции, а не её содержимое, до того как ваша подпись сделает её настоящей.
Разрыв между тем, что вы имели в виду, и тем, что подписываете
Транзакция — не предложение. Это байты.
Когда эти байты — обычный перевод, разрыв между тем, что они говорят, и тем, что делают, невелик: адрес, сумма, комиссия. Когда это вызов контракта, разрыв бывает огромным. approve выглядит как разрешение. Это постоянное право другого адреса двигать ваши токены, и в стандарте ERC-20 ничто в вызове не обязывает ограничить ни объём, ни срок. Одно одобрение, подписанное однажды, могут опустошить месяцы спустя.
Интерфейс, на который вы смотрите при подписи, обязан перевести эти байты в предложение. Этот перевод и есть поверхность атаки. Если его производит тот, кому нужна ваша подпись, он может сказать что угодно.
Прогон, а не обещание
Симуляция означает выполнить транзакцию против текущего состояния сети, не рассылая её, и записать, что меняется.
В SSP Enterprise это происходит при создании предложения, до того как кто-либо подпишет. Симуляция строится из того, что произвёл сборщик предложения, — из получателей, сумм, контракта токена и данных вызова, которые собрала сама SSP, — и никогда из сырого подписанного hex, переданного клиентом. Она работает только на чтение. Три движка покрывают разные семейства сетей:
- EVM-сети выполняют вызов только для чтения к узлу и считывают обратно получившиеся изменения балансов и расшифрованный вызов.
- UTXO-сети не нуждаются в узле вовсе. Входы и выходы уже известны, поэтому «до и после» — это арифметика на выбранных монетах, а получатели классифицируются как сдача, возвращающаяся к вам, или как действительно внешние.
- Solana десериализует неподписанную транзакцию, произведённую сборщиком, и запускает собственный сетевой
simulateTransactionс выключенной проверкой подписей, а затем читает из результата токен-балансы хранилища до и после.
Обратно приходит предпросмотр: каким был баланс каждого актива до, каким он станет после и — на EVM — чем вызов является на самом деле, разложенный на метод и его аргументы.
Двумя вещами она не является. Это не гарантия: состояние сети движется, и симуляция, выполненная в момент предложения, — это снимок сети такой, какой она была тогда. И это не заслон. Что и есть более интересная половина замысла, и мы к ней вернёмся.
Четырнадцать вещей, о которых стоит сказать
Предпросмотр, показывающий одни числа, по-прежнему требует, чтобы вы сами заметили проблему. Поэтому предпросмотр сопровождают предупреждения — их четырнадцать, четырёх степеней серьёзности.
Разрешения — категория, опустошающая больше всего кошельков. Безлимитное или неограниченное разрешение — критическое. Любое ненулевое разрешение на трату адресу, которого нет в вашем списке допущенных, — высокое. А выдача разрешения обычному пользовательскому адресу вместо контракта — высокое, потому что законных причин так делать практически не бывает: разрешения тратят контракты, а не люди.
Получатели — помечается получатель, которого нет ни в контактах вашей организации, ни в белом списке хранилища. И тот, которому ваше хранилище никогда прежде не отправляло. Сами по себе ни то ни другое не ошибка. И то и другое стоит перечитать.
Риск контракта — контракт назначения с непроверенным исходным кодом, развёрнутый в последние семь дней, отправка нативной суммы контракту вообще, и любой адрес, который поставщик помечает как прямо вредоносный.
Исполнение — транзакция откатывается в симуляции, а значит, провалится в сети и сожжёт комиссию. Или симулированный отток не совпадает с суммами, которые заявляет предложение: хранилище теряет больше или меньше, чем говорит экран.
Деградация — и, с ясной подписью, случай, когда симуляция вообще не смогла выполниться. Недоступный узел даёт «недоступно», а не молчание и не выдуманную справку о здоровье.
Различие между этими степенями значит больше, чем их количество. Критическое и высокое — про транзакцию, которая, вероятно, не то, чем кажется. Среднее и информационное — про транзакцию необычную, а законные транзакции время от времени необычны.
Отравление адресов: атака, которая побеждает аккуратных людей
Одно предупреждение заслуживает отдельного раздела, потому что нацелено ровно на ту привычку, которую рекомендует большинство советов по безопасности.
Отравление адресов работает так. Злоумышленник отправляет вашему хранилищу крошечную или нулевую транзакцию с адреса, сконструированного так, чтобы совпадать первыми шестью и последними четырьмя символами с адресом, с которым вы уже имеете дело. Ничего не крадут. Ничего, по сути, даже не делают. Транзакция существует ради того, чтобы похожий адрес появился в вашей истории.
Позже — днями позже, когда вы снова платите тому же контрагенту, — вы копируете адрес из собственной истории транзакций, как поступают аккуратные люди, вместо того чтобы набирать заново. Вы проверяете его так, как проверяют аккуратные люди: первые несколько символов, последние несколько. Оба совпадают. Середина — нет, а деньги уходят именно в середину.
SSP сверяет каждого получателя предложения с адресами, которые ваше хранилище уже знает, ровно тем сравнением префикса и суффикса, которое делает человеческий глаз, и выдаёт критическое предупреждение, называя подделываемый адрес. Та же проверка работает в обратную сторону по входящей истории, так что отравленный адрес помечается уже при поступлении, а не только когда вы собираетесь им воспользоваться.
Почему стоит знать про эту атаку, даже если вы никогда не пользуетесь SSP: привычка проверять, которая останавливает любую другую атаку на адрес, — это ровно та привычка, победить которую эта атака и построена. Сравнивайте адреса целиком — или не сравнивайте вовсе.
Почему предупреждения считаются на сервере — и всё же ничего не блокируют
Набор предупреждений определяется на сервере, а источником истины служат контакты вашей организации и белый список хранилища. Это сделано намеренно: если бы клиент мог решать, что считается допущенным, скомпрометированный клиент мог бы тихо решить, что допущено всё.
И всё же ничто из этого не может остановить транзакцию. Симуляция никогда не обусловливает ни подпись, ни рассылку. Поставщик, который упал с ошибкой, вышел за таймаут или не достучался до узла, возвращает «недоступно», а предложение остаётся полностью подписываемым. Вся подсистема изолирована от сбоев, чтобы падение предпросмотра никогда не могло посадить предложение на мель.
Это прозвучит странным выбором, поэтому рассуждение стоит изложить прямо. Предпросмотр, способный блокировать, — это предпросмотр, который можно заставить блокировать: положив узел, выдав ложное критическое, любым из тысячи способов, какими ломается софт. Средства, которые не могут двинуться, потому что нездоров рекомендательный сервис, — это средства, которые вы отчасти потеряли. Деньги защищает порог мультиподписи; симуляция существует, чтобы информировать людей, держащих ключи. Что на самом деле останавливает транзакцию — это длинная версия того же довода.
Когда сервер и ваше устройство расходятся
Всё вышесказанное — это чтение сервера. Ваше устройство делает своё.

Когда SSP Wallet показывает вам предложение на подпись, он расшифровывает байты сам и показывает то, что нашёл он, — а не сводку сервера. Затем сравнивает одно с другим. Если расшифрованный сервером вызов подразумевает иной набор получателей, чем вывело устройство, устройство поднимает собственное критическое предупреждение о расхождении и визуально понижает предпросмотр сервера.
Расшифровка устройства — главная. Проверка нарочно консервативна: отсутствующая или ожидающая симуляция сервера — это деградация, а не противоречие, и как противоречие не помечается. Кроме того, она применима только к EVM-сетям, где сервер вообще производит расшифрованный вызов; на UTXO-сетях сравнивать не с чем, и собственная расшифровка устройства просто стоит одна.
Вот свойство, которое стоит унести с собой, какой бы кошелёк вы ни использовали. Второе мнение чего-то стоит только тогда, когда оно приходит оттуда, что не могло быть скомпрометировано тем же действием, что и первое. Две сводки от одного сервера — это одна сводка.
Как читать полосу рисков, не научившись её игнорировать
Предупреждения работают, пока не превратятся в обои. Несколько привычек сохраняют их полезными.
Сначала читайте серьёзность, потом подробности. Критическое и высокое стоят того, чтобы остановиться. Среднее или информационное предупреждение при первом платеже новому поставщику — это система, работающая правильно, а не повод для тревоги.
Любое предупреждение о разрешении считайте полной остановкой. Переводы двигают то, о чём говорят. Разрешения дают право, которое переживает транзакцию. Если вы не собирались выдавать постоянное разрешение, ответ — нет.
Верьте устройству, а не экрану. Если они расходятся, телефон в вашей руке — тот, что работает на железе, которое злоумышленнику пришлось бы скомпрометировать отдельно.
Не читайте «недоступно» как «всё в порядке». Это значит, что никто не проверил. Это повод посмотреть внимательнее самому, особенно на крупном или необычном платеже.
Всё здесь — про момент перед подписью. Про то, что происходит после — кто может подписывать, сколько подписей нужно и какие операции снова требуют обоих устройств, — начните с настройки вашего первого корпоративного хранилища и критических действий и повторной подписи. А про схемы атак, вокруг которых сформированы эти предупреждения, фишинговые атаки на пользователей криптовалют закрывают человеческую половину проблемы.


