coinomico

Простой и безопасный старт в криптовалюте.

Колонку ведёт Демид Красильников

Смарт-контракты: почему ошибки в коде лишили меня депозита

Мой депозит исчез после транзакции, которую сеть подтвердила как успешную. Кошелёк работал, блокчейн не падал, а баланс всё равно оказался пустым.

Демид Красильников, Обозреватель и гид по криптограмотности·Обновлено: 31 октября 2026 г.·8 мин

Смарт-контракты: почему ошибки в коде лишили меня депозита

Средства ушли через функцию вывода в смарт-контракте: код вывел актив раньше, чем зафиксировал изменение внутреннего состояния. Когда я попытался вернуть депозит, оказалось, что кнопки «отменить» у блокчейна нет.

Это не «взлом блокчейна», а эксплуатация конкретной ошибки в программе, которая распоряжалась деньгами. Смарт-контракт исполнил заложенную логику буквально. Именно поэтому понимание уязвимостей смарт-контрактов важнее очередного объяснения, что Web3 «перевернёт финансы». База здесь простая: код исполняется, состояние сохраняется, а убытки пользователей часто становятся необратимыми.

Где именно исчезли деньги

Смарт-контракт можно представить как программу, записанную в блокчейне и управляющую средствами по заранее определённым правилам. Пользователь отправляет транзакцию, а контракт проверяет условия, вызывает другие контракты, обновляет балансы и выполняет вывод.

Путь депозита обычно состоит из нескольких звеньев:

1. Кошелёк подписывает транзакцию приватным ключом.

2. Интерфейс сайта формирует вызов нужной функции.

3. Маршрутизатор или роутер передаёт средства между контрактами.

4. Целевой контракт проверяет права, условия и сумму.

5. Транзакция завершается, а её результат записывается в блокчейн.

Ошибка может возникнуть на любом участке. Интерфейс показывает красивый адрес контракта, но вызывает не ту функцию. Маршрутизатор переводит активы не в тот пул. Контракт неверно считает комиссию. Роль администратора получает лишние права. Внешний оракул сообщает поддельную цену.

В моём случае интерфейс оказался лишь входной точкой. Основная проблема находилась в порядке выполнения операций внутри контракта.

Чем длиннее цепочка вызовов между кошельком, протоколом, токеном и оракулом, тем больше мест, где ошибка может выглядеть как обычная успешная транзакция.

Статус «успешно» подтверждал выполнение кода, а не сохранность средств. Для пользователя разница выглядит почти незаметной: транзакция подтверждена, адрес контракта тот же, интерфейс не показывает ошибку. Но после выполнения баланс может оказаться нулевым.

Отменить результат обычным запросом нельзя. В некоторых случаях сообщество способно провести форк или организовать компенсацию, однако это отдельное событие для всей сети, а не персональный возврат средств. История The DAO в 2016 году показала, что вмешательство на уровне протокола возможно. Тогда из-за атаки повторного входа Ethereum провели хардфорк. Но рассчитывать на такой исход для своего депозита нельзя.

При этом смарт-контрактные уязвимости объясняют далеко не каждую потерю. Приватный ключ могут украсть фишингом. У мультисига могут похитить одну из подписей. Администратор может оказаться скомпрометирован. Код может быть безупречным, а рынок — пустым. Разделять эти риски необходимо уже на этапе выбора протокола.

Повторный вход: как код даёт обмануть самого себя

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

Представьте кассира, который сначала отдаёт деньги, а только потом отмечает операцию в журнале. Если покупатель в этот момент снова требует оплату, кассир не успевает закрыть первую запись. Формально он действует по инструкции. Деньги уходят дважды.

В смарт-контракте сценарий выглядит так:

1. Злоумышленник вызывает функцию вывода.

2. Контракт проверяет доступный баланс или заранее рассчитанную сумму.

3. До изменения состояния активы отправляются внешнему контракту.

4. Получив управление, вредоносный контракт повторно вызывает функцию вывода.

5. Пока исходный вызов не завершён, проверка баланса допускает новое списание.

6. Повторяющиеся вызовы опустошают доступный пул ликвидности.

Всё происходит на уровне записанных транзакций. Злоумышленнику не нужно взламывать кошелёк, подбирать пароль или обходить криптографию. Он simply выполняет допустимый вызов функции в неправильно спроектированном контракте. Уязвимость использует саму логику протокола против него.

Сначала проверь, затем измени состояние и только после этого переводи средства. Порядок действий в смарт-контракте часто важнее логики отдельной функции.

Отсюда вытекает архитектурный паттерн Checks-Effects-Interactions. Сначала контракт проверяет условия, затем меняет баланс или статус, и только потом выполняет внешний перевод. Такая последовательность закрывает классический путь повторного входа.

Механизм ReentrancyGuard добавляет дополнительную блокировку повторного входа. Он полезен, однако не исправляет ошибки экономики, контроля доступа или оракулов. Защитный модуль — это предохранитель на одном участке, а не гарантия безопасности всей конструкции.

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

Аудит кода: карта проверенной территории, а не бронежилет

Аудит смарт-контрактов часто подают как точку доверия. Отчёт приложен, галка поставлена, протокол можно считать проверенным. На практике аудит даёт гораздо более узкое обещание: команда проанализировала определённую версию кода, указанный набор функций и заданные разработчиком сценарии.

По данным Immunefi, в 2025 году 89% потерь в DeFi-протоколах было связано с эксплуатацией дефектов протокольной логики. Речь не о повреждении файлов и не о неисправной сети. Люди теряли деньги из-за неверных правил, по которым контракт принимал решения.

Отдельная выборка ack3 за первое полугодие 2026 года показывает ещё одну проблему. Среди взломанных протоколов с известной историей проверок 67,6% путей атаки находились за пределами публичного скоупа аудитов. На эти векторы пришлось 94,4% финансовых потерь в изученных проектах.

Эти две статистики берутся из разных выборок, поэтому складывать проценты нельзя. Вместе они показывают главное: публичная проверка охватывает ограниченную часть системы. Отсутствие замечаний аудита в заявленной области не означает, что протокол не содержит уязвимостей.

Зона проверкиЧто подтверждает аудитГде может оставаться риск
Версия кодаЛогика выбранной реализации разобрана специалистамиПосле аудита код могли обновить или заменить
Набор функцийПроверены заявленные операцииАдминистративные, аварийные и будущие функции могли остаться вне скоупа
Внешние зависимостиУчтено поведение подключённых контрактов на момент проверкиИнтеграция изменилась, контракт обновился или возник новый сценарий
Контроль доступаПроверены роли и ограничения в заданной конфигурацииПрава администратора, мультисига или ключей управляются вне смарт-контракта
Экономические допущенияМодель проверена при определённых состояниях рынкаНизкая ликвидность, необычная цена и массовая ликвидация могли не попасть в сценарии

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

Есть и человеческая часть. Даже безупречно написанный контракт можно передать не тому человеку, изменить настройки через ошибочную роль или выпустить новый токен с прежним контрактом. Защита кода заканчивается там, где начинается управление ключами и параметрами.

По данным TRM Labs, в первом полугодии 2026 года было зафиксировано 207 атак. Масштаб растёт вместе с числом протоколов и стоимостью активов. Аудит снижает вероятность известной ошибки, но не отменяет возможность новой.

Скрытые ловушки протокольной логики

OWASP Smart Contract Top 10 выделяет четыре класса проблем, с которыми регулярно сталкиваются DeFi-протоколы: ошибки контроля доступа, манипуляции ценовыми оракулами, ошибки бизнес-логики и атаки повторного входа. Каждый класс выглядит снаружи по-разному.

  • Контроль доступа. Контракт может содержать правильную функцию вывода, но неверно разграничивать роли. Кто-то получает право выпускать токены, менять комиссию, переводить средства или отключать проверки. Ошибка находится не в формуле, а в правах на её вызов.
  • Манипуляция ценовыми оракулами. Протокол берёт цену актива из внешнего источника и использует её для оценки залога или ликвидации. Если рынок тонкий, цену удаётся временно исказить. Контракт получает ложные данные и принимает экономически неверное решение.
  • Ошибки бизнес-логики. Код выполняет задуманное, но само правило ошибочно: неверно начисляются вознаграждения, обходится лимит депозита, дважды учитывается одна позиция или рассчитываются по устаревшему состоянию.
  • Переполнение чисел. Начиная с Solidity 0.8 обычное арифметическое переполнение по умолчанию отменяет транзакцию. Однако блоки unchecked и inline assembly отключают эту защиту. Старая тема не исчезает полностью с обновлением языка.

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

Поэтому мой порядок изучения протокола теперь выглядит так:

1. Начинаю с маршрута депозита и вывода, а не с рекламного описания проекта.

2. Сверяю адрес активной реализации с версией, которую проверял аудит.

3. Ищу функцию вывода, административные полномочия, механизм паузы и способы обновить параметры.

4. Проверяю источник цен, зависимости от других протоколов и реальную глубину пула ликвидности.

5. Определяю максимальную сумму, полную потерю которой не сломает мою финансовую базу.

Последний пункт звучит сухо. Он и должен звучать сухо. Депозит, потеря которого остановит работу, платежи или заставит продать другие активы, уже слишком велик.

Управление ключами требует отдельной базы. Даже идеальный контракт не защитит средства, если вредоносная ссылка заставила меня подписать разрешение на перевод или если один из участников мультисига оказался скомпрометирован. Проверка адреса контракта не отменяет необходимость защищать подпись. Для крупных сумм разумно использовать аппаратный кошелёк, ограничивать разрешения и не хранить все средства в одной точке отказа.

Цена ошибки: почему после взлома страдают даже те, кто не вносил депозит

По статистике Immunefi, медианный токен взломанного протокола теряет 61% стоимости в течение полугодия после инцидента. Это не абсолютная величина для каждого проекта. Однако масштаб Typical потерь показывает: проблема выходит далеко за пределы кошелька одного атакующего.

Эксплойт часто приводит к продаже токенов, выводу обеспечения из пулов ликвидности и попытке компенсировать убыток. Ликвидность после этого резко ухудшается. Даже продажа небольшой доли позиции начинает двигать цену сильнее обычного. У пользователей, которые не взаимодействовали с уязвимой функцией, остаются токены, но выйти из них становится дороже.

Другие механизмы ущерба мягче, но столь же реальны. Оракул неверно оценивает залог и запускает массовые ликвидации. Администратор в панике переводит средства или блокирует вывод. Маркетинг продолжает обещать прежнюю доходность, хотя база ликвидности уже повреждена. Репутационное последствие превращает техническую ошибку в длительное падение цены.

Код способен ошибиться один раз, а цена токена расплачивается за эту ошибку полгодами.

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

Смарт-контракт остаётся самым строгим исполнителем сделки. Он не забыет обещание, не уволится и не пожалеет пользователя. За это же он без колебаний исполняет ошибочную логику. Аудит кода помогает найти известные слабые места, но не превращает протокол в гарантированно безопасный объект.

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

Частые вопросы

Почему средства пропали, если сеть подтвердила транзакцию как успешную?
Статус успешной транзакции подтверждает выполнение заложенного кода, а не сохранность средств. Деньги уходят, если код выполнил вывод активов раньше, чем зафиксировал изменение внутреннего состояния.
Можно ли отменить транзакцию смарт-контракта?
Отменить результат выполненной транзакции обычным запросом нельзя, так как у блокчейна нет кнопки отмены.
Что такое атака повторного входа и как она работает?
Reentrancy происходит, когда контракт передает управление внешнему контракту до обновления внутреннего состояния. Вредоносный контракт успевает снова вызвать функцию вывода, пока проверка баланса допускает повторное списание.
Гарантирует ли успешное прохождение аудита безопасности полную защиту средств?
Аудит снижает вероятность известной ошибки, но не исключает новую. Публичные проверки охватывают лишь ограниченную часть системы, а пути атак могут находиться за пределами скоупа аудита.
Как влияют взломы протоколов на пользователей, не использовавших уязвимую функцию?
Инцидент приводит к массовой продаже токенов и выводу обеспечения, из-за чего ликвидность ухудшается, а оставшиеся у пользователей токены падают в цене.