Кошельки

Как проверить транзакцию Safe перед совместной подписью

Что сверить владельцу Safe перед подтверждением: сеть, адрес аккаунта, получатель, value, calldata, operation, nonce, batch, approvals, modules и итоговый Safe transaction hash.

Как проверить транзакцию Safe перед совместной подписью

Коротко: владелец Safe должен проверять не описание заявки, а фактические поля транзакции. Перед подписью сверьте сеть и адрес Safe, получателя, value, calldata, operation, nonce, состав batch и изменения разрешений. Затем сравните Safe transaction hash с тем, который проверили другие owners. Совпадение знакомого интерфейса и имени инициатора не гарантирует безопасность.

Подпись владельца не отправляет средства сама по себе. Она подтверждает конкретный набор параметров Safe transaction. Когда собрано достаточно подписей, любой подходящий исполнитель может передать их в контракт. Поэтому фраза «я только согласовал» опасна: ваша подпись может стать последней недостающей частью готовой операции.

С чего начинать проверку

Сначала подтвердите контекст. Один и тот же интерфейс способен показывать аккаунты в разных EVM-сетях, а одинаково выглядящие токены могут иметь разные контрактные адреса. Сверьте выбранную сеть в кошельке, Safe address и страницу аккаунта.

Затем проверьте статус Safe: актуальный список owners, threshold, nonce, активные modules и guard. Если конфигурация неожиданно изменилась, разбор обычного перевода нужно остановить. Подробный контроль параметров описан в статье о владельцах multisig и пороге подписей.

Получите назначение операции по независимому каналу. Сообщение инициатора должно объяснять получателя, актив, сумму и деловую причину. Но оно служит только контекстом – окончательное решение принимают по данным транзакции.

Основные поля Safe transaction

To. Адрес непосредственного получателя вызова. При переводе нативного актива это может быть конечный адрес. При работе с токеном или DeFi to часто указывает на контракт, а настоящий получатель зашит в calldata.

Value. Количество нативного актива, отправляемого вместе с вызовом. Нулевое value не означает отсутствие финансового действия: calldata может переводить ERC-20, выдавать approval или менять владельцев Safe.

Data. Закодированный вызов функции. Нужно определить selector, имя функции и аргументы. Особое внимание требуют approve, transfer, transferFrom, setApprovalForAll, upgrade, enableModule и вызовы управления Safe.

Operation. Обычный call выполняет функцию в контексте целевого контракта. Delegatecall запускает чужой код в контексте Safe и потому значительно опаснее. Если delegatecall не предусмотрен проверенной процедурой, подписывать его нельзя.

Nonce. Порядковый номер Safe transaction. Он защищает от повторного исполнения и определяет последовательность. Две заявки с одинаковым nonce конкурируют: после выполнения одной другая обычно не сможет исполниться в прежнем виде.

Поля газа и возврата. safeTxGas, baseGas, gasPrice, gasToken и refundReceiver могут влиять на компенсацию исполнителю. В обычной операции значения часто подбираются инфраструктурой, но необычный refundReceiver или платёж в токене требует отдельного объяснения.

Как расшифровать calldata

Интерфейс Safe и Transaction Service могут декодировать известный ABI, но декодирование является удобным представлением, а не источником истины. Сравните selector и аргументы через независимый обозреватель или локальный инструмент. Если ABI неизвестен, нельзя угадывать действие по названию приложения.

Для ERC-20 approval проверьте spender и allowance. Безлимитное разрешение даёт контракту возможность списывать будущий баланс, пока approval не отозван. Для swap проверьте tokenIn, tokenOut, amountIn, минимальный результат, получателя и deadline, если он есть.

Подробный порядок разбора описан в инструкции по расшифровке calldata перед подписью. В Safe этот навык особенно важен, потому что несколько owners могут ошибочно полагаться на проверку первого подписанта.

Проверка batch-транзакции

Safe позволяет объединить несколько действий в один batch. В интерфейсе может быть виден понятный главный шаг, но внутри массива присутствовать дополнительный approval, перевод или вызов управления. Проверять нужно каждый элемент в исходном порядке.

  1. Посчитайте количество внутренних вызовов.
  2. Для каждого запишите to, value, selector и ключевые аргументы.
  3. Проверьте, как результат раннего шага влияет на последующие.
  4. Убедитесь, что при ошибке batch ведёт себя ожидаемо и не оставляет промежуточное разрешение.
  5. Сравните общий Safe transaction hash после окончательной сборки.

Особенно опасна комбинация «дать approval, затем вызвать неизвестный router». Даже если второй вызов симуляции завершается ошибкой, первый может остаться значимым в другой структуре исполнения. Нужно понимать атомарность конкретного batch-контракта и operation.

Изменения конфигурации Safe

Транзакция может быть адресована самому Safe. Так добавляют и удаляют owners, меняют threshold, включают module, назначают guard или fallback handler. Это не техническая мелочь, а изменение контроля над аккаунтом.

Добавление owner вместе со снижением threshold способно дать новому адресу единоличный доступ. Включённый module может исполнять операции по собственным правилам, обходя обычный сбор подписей. Guard способен проверять транзакции, но ошибочный или вредоносный guard может заблокировать работу Safe.

Такие операции следует проводить отдельной заявкой, без смешивания с переводами, и подтверждать по заранее утверждённой процедуре. Если Safe ещё только создаётся, используйте руководство по выбору owners и порога подписей.

Что даёт симуляция

Симуляция показывает вероятный результат вызова на выбранном состоянии: изменения балансов, события, approvals и возможный revert. Она помогает обнаружить очевидную ошибку, но не доказывает безопасность к моменту исполнения.

Между симуляцией и отправкой могут измениться цена, nonce, состояние пула, разрешения и код обновляемого контракта. Некоторые действия зависят от msg.sender, времени или внешнего oracle. Ошибки и ограничения этого метода подробно рассмотрены в статье почему симуляция не гарантирует безопасный результат.

Используйте симуляцию как второй слой после ручного разбора, а не как замену. Если она показывает неожиданный transfer, approval или изменение owner, транзакцию нужно отклонить и собрать заново.

Safe transaction hash и совместная проверка

Safe transaction hash рассчитывается из параметров операции по EIP-712 с привязкой к домену. Любое изменение to, value, data, operation, nonce или параметров газа приводит к другому хешу. Это позволяет нескольким владельцам убедиться, что они изучали одну и ту же заявку.

После проверки один owner передаёт остальным не только скриншот, но и Safe address, сеть, nonce и полный safeTxHash. Каждый участник независимо открывает заявку и сравнивает данные. Если хеш не совпадает, прежнее согласование недействительно.

Transaction Service помогает хранить предложения и собирать off-chain подписи, но не является самим Safe. Запись в сервисе ещё не означает on-chain исполнение, а отсутствие красивой расшифровки не делает неизвестный вызов безопасным.

Практический чек-лист

  • Нужная сеть и точный Safe address.
  • Актуальные owners, threshold, nonce, modules и guard.
  • Проверенный to и назначение контракта.
  • Value в правильной единице и активе.
  • Декодированные selector и все аргументы calldata.
  • Operation равен ожидаемому call, если delegatecall не обоснован.
  • Каждый внутренний вызов batch проверен отдельно.
  • Approvals ограничены необходимым spender и объёмом.
  • Симуляция не показывает неожиданных изменений.
  • Safe transaction hash совпадает у всех подписантов.

Если кошелёк показывает структурированную подпись, дополнительно примените инструкцию по проверке EIP-712. Не подтверждайте слепую подпись на аппаратном устройстве, если экран не позволяет связать хеш с заранее разобранными параметрами.

Итог

Совместная подпись безопасна только при независимой проверке каждым owner. Разберите фактические поля, все вызовы batch и изменения конфигурации, используйте симуляцию как вспомогательный сигнал и сравните единый safeTxHash. Порог multisig защищает от одного скомпрометированного ключа, но не спасает, если несколько владельцев подписывают одну ошибочную заявку не глядя.