Контракт отправляет средства, затем обновляет баланс. Между этими шагами атакующий вызывает его снова — и выводит ещё раз. Это реентранси.
Реентранси возникает, когда контракт делает внешний вызов до обновления своего состояния. Вызываемый контракт — который контролирует атакующий — зовёт исходную функцию снова, пока баланс всё ещё показывает старое значение. Вывод срабатывает дважды на один баланс.
Классика — пул или хранилище с наивным выводом. Это баг, стоящий за несколькими известными девятизначными взломами, и его до сих пор релизят, потому что на первый взгляд паттерн выглядит правильным.
Обновляйте состояние до внешнего вызова, защищайте вход замком реентранси или используйте паттерн «проверки — эффекты — взаимодействия». Правило одно: внутреннее состояние должно быть согласовано до передачи контроля недоверенному адресу.
Одна-две недели на один контракт, три-пять на полный протокол с тестами и перепроверкой исправлений.
Да — каждый аудит включает 30 дней поддержки и бесплатную перепроверку закрытого.