Коротко: calldata – это входные байты, которые отправитель передаёт контракту вместе с транзакцией. Они указывают, какую функцию вызвать, и обычно содержат её аргументы. Сами по себе эти байты не переводят токены и не меняют состояние сети. Изменение возникает, когда EVM исполняет код контракта, читает текущее состояние, проверяет условия и записывает допустимый результат. Поэтому понимание calldata помогает увидеть намерение вызова, но для оценки последствий нужно учитывать код, состояние и итог выполнения.
Из чего состоит вызов контракта
Внешний аккаунт подписывает транзакцию, в которой указываются сеть, nonce, получатель, значение нативной монеты, лимит газа, параметры комиссии и поле данных. Если получатель – контракт, поле data часто содержит ABI-кодированный вызов функции. Первые четыре байта обычно служат селектором, полученным из сигнатуры функции, а после него идут кодированные аргументы. Это распространённая схема внешнего вызова Solidity, но не всякое поле данных означает именно такой вызов.
Например, вызов transfer токена ERC-20 включает адрес получателя и сумму в кодированном виде. Но надпись transfer сама не гарантирует, что баланс изменится именно ожидаемым образом. Контракт может добавить ограничения, проверку паузы или комиссии, а адрес получателя может быть другим, чем вы предполагаете. Интерфейс кошелька пытается декодировать данные и показать действие, но результат зависит от правильного ABI и доверия к коду.
Чтобы понять, что именно подписывается, сравните сеть и адрес назначения с контрактом, выясните selector и типы аргументов. Руководство о том, как расшифровать calldata, помогает перейти от шестнадцатеричных байтов к понятным параметрам. При этом декодирование не показывает все последствия вызова и не доказывает, что контракт соответствует официальному интерфейсу.
Как EVM превращает входные данные в действие
После включения транзакции исполнитель запускает код адреса назначения с указанными calldata и value. Контракт может прочитать аргументы, сравнить права отправителя и проверить баланс, лимиты или состояние рынка. Затем он выполняет внутренние вызовы других контрактов, рассчитывает результат и, если правила выполнены, меняет хранилище, переводит активы или выпускает события. Конкретная последовательность зависит от кода и текущего состояния сети.
Одна и та же calldata может приводить к разным результатам в разное время, поскольку баланс, цена, состояние пула, права пользователя и код прокси могли измениться. Селектор не фиксирует рыночные условия. Именно поэтому транзакции обмена включают параметры вроде минимального получаемого количества: контракт проверяет ограничение уже при исполнении. Если условие не выполнено, вызов откатывается. Однако даже отклонённая транзакция может потребить газ.
Внешняя транзакция может вызывать целую цепочку контрактов. Кошелёк показывает верхнеуровневого получателя, но токены могут передаваться внутренними вызовами. Поэтому при разборе результата смотрите на receipt, события и внутренние транзакции. В статье о внутренних вызовах и событиях токенов объясняется, почему один хеш иногда отражает несколько движений активов.
Calldata, memory, storage и events
В Solidity термин calldata имеет ещё и более узкое значение: это область данных вызова, где могут храниться аргументы внешней функции. Она доступна только для чтения и не является постоянным хранилищем контракта. Memory – временная область для работы в рамках исполнения. Storage – долговременное состояние контракта, которое сохраняется между транзакциями. Эти области нельзя смешивать: массив, переданный как аргумент, не становится автоматически частью storage.
События событийного журнала записываются в receipt и удобны для индексаторов и интерфейсов. Они не являются тем же самым, что storage, и смарт-контракт не может читать произвольный исторический лог как состояние. Разработчики могут объявить событие Transfer, но это само по себе не меняет баланс. Правильный токен обновляет storage и затем выпускает событие; некорректная реализация может нарушить ожидаемую связь между ними.
Calldata остаётся частью транзакции и доступна в её записи, однако это не означает, что каждое переданное значение стало отдельной постоянной переменной контракта. Некоторые данные используются только в момент выполнения, другие могут быть записаны в storage или отражены в событии. Для хранения и доступности данных в блокчейне существуют разные варианты, и выбор зависит от того, кому и когда нужно их читать.
Почему симуляция и декодирование не гарантируют исход
Симуляция запускает предполагаемую транзакцию на выбранном состоянии сети и оценивает возможный результат. Между симуляцией и включением в блок другие транзакции могут изменить баланс, цену или состояние контракта. Даже если calldata осталась прежней, исполнение происходит в новых условиях. Это особенно важно для свопов и операций, где результат зависит от порядка транзакций или изменяемой ликвидности.
Декодирование тоже зависит от качества ABI и источника контракта. Один и тот же селектор может совпадать с несколькими функциями, а прокси может перенаправлять вызов в другую реализацию. До подписи проверьте адрес, сеть, права вызова и все параметры. Полезно сравнить получателя и суммы с тем, что показано интерфейсом, а затем посмотреть полный список операций в кошельке. Не подписывайте данные, смысл которых кошелёк не может объяснить.
Некоторые защиты ограничивают риск: минимальная сумма получения, максимальный расход, срок действия разрешения, аппаратная подпись и проверка адреса. Они должны быть указаны явно и поддержаны кодом. Если контрактный вызов предоставляет unlimited allowance, это не просто «данные для обмена», а разрешение потратить токены позже. Проверяйте spender и срок в разрешениях, а ненужный доступ можно отозвать по инструкции о поиске spender и allowance.
Практический порядок чтения транзакции
- Сначала сверьте сеть, адрес отправителя и адрес получателя.
- Отделите value в нативной монете от calldata – это разные поля.
- Если вызывается контракт, определите селектор, аргументы и ABI.
- Проверьте ограничения суммы, срока, адреса, slippage и разрешений.
- Посмотрите симуляцию как прогноз, а не обещание.
- После включения сверьте статус, события, внутренние вызовы и изменившиеся балансы.
Главная мысль проста: calldata описывает запрос, а состояние блокчейна отражает результат исполнения запроса вместе с правилами контракта и условиями блока. Для безопасного анализа недостаточно расшифровать одну строку данных. Нужно выяснить, какой код её обрабатывает, какие внешние вызовы он делает, какие ограничения проверяет и какие изменения действительно попали в итоговый receipt.



