Reentrancy
Внешний вызов до обновления состояния позволяет атакующему повторно войти в функцию до уменьшения балансов. Следуйте checks-effects-interactions и используйте reentrancy-guard.
// vulnerable
function withdraw(uint a) public {
require(bal[msg.sender] >= a);
(bool ok,) = msg.sender.call{value:a}("");
bal[msg.sender] -= a; // too late
}
// fixed
function withdraw(uint a) public nonReentrant {
require(bal[msg.sender] >= a);
bal[msg.sender] -= a; // effects first
(bool ok,) = msg.sender.call{value:a}("");
require(ok);
}
Аутентификация через tx.origin
Использование tx.origin для авторизации позволяет промежуточному контракту действовать от имени пользователя. Используйте msg.sender.
Манипуляция оракулом / ценой
Чтение спот-цены из одного пула делает её уязвимой к манипуляции крупным свопом, часто через флеш-заём. Предпочитайте средневзвешенную по времени цену (TWAP) или агрегированный оракул.
Отсутствие контроля доступа
Чувствительную функцию без ограничивающего модификатора может вызвать кто угодно. Защищайте привилегированные функции через onlyOwner или проверки ролей.
Непроверенный внешний вызов
Игнорирование возвращаемого значения низкоуровневого вызова позволяет контракту продолжить после неудачного перевода. Всегда проверяйте возвращённый булев результат.
Ошибки бизнес-логики
Инвертированное сравнение или неверный расчёт доли нарушает инвариант. Такие ошибки специфичны для контракта, ускользают от общих детекторов и часто самые дорогие. Опишите ожидаемое поведение и сравните его с кодом.
Хотите безопасно потренироваться в эксплуатации? См. Обучение. Готовы просканировать свой контракт? Откройте сканер.