Перерыв на канале из-за обучения
Как вам известно, я уже продолжительное время занимаюсь разработкой собственного ассистента на основе локальной нейронной сети. В процессе работы я столкнулся с большим объемом информации, и теперь мне необходимо систематизировать эти знания, чтобы двигаться дальше.
Для этого я решил взять небольшую паузу на одну-две недели, чтобы полностью сосредоточиться на изучении интеграции локальных LLM-моделей. На это время я оставляю только поддержку учеников модуля, а все остальные задачи — аудиты, разработку и анализ отчетов — временно приостанавливаю.
За последнее время я успел познакомиться с возможностями LLM, которые способны серьезно повлиять не только на разработку и тестирование смарт-контрактов, но и на их математические модели и сложную архитектуру. В ближайшем будущем появятся решения, автоматизирующие создание тестов в Foundry с проверкой всех возможных сценариев выполнения функций и логических потоков. Кроме того, нейросети смогут анализировать инварианты математических расчетов, выполняя сотни тысяч итераций, и помогать выявлять серьезные уязвимости уровня Med или High.
Примечательно, что это будут не массовые коммерческие модели вроде ChatGPT, Claude или Gemini, а специализированные локальные решения, оптимизированные под конкретные задачи. Крупные компании вряд ли в ближайшие годы будут заниматься узкой настройкой своих продуктов для отдельных областей, поскольку их основная цель — конкуренция на глобальном рынке.
Моя задача — научиться отличать действительно полезные проекты от поверхностных решений, которые представляют собой всего лишь обертку над API популярных нейросетей. В ходе обучения я планирую разобраться в настройках моделей, их разновидностях, бенчмарках, библиотеках для работы с ними, а также в таких темах, как квантизация и оптимизация производительности.
В скором времени мы вернемся к изучению Solidity и актуальных трендов в этой области — у меня уже есть несколько интересных тем для обсуждения. Желаю вам продуктивной недели и отличного настроения!
Всем хорошего настроения и приятной недели!
#offtop
Как вам известно, я уже продолжительное время занимаюсь разработкой собственного ассистента на основе локальной нейронной сети. В процессе работы я столкнулся с большим объемом информации, и теперь мне необходимо систематизировать эти знания, чтобы двигаться дальше.
Для этого я решил взять небольшую паузу на одну-две недели, чтобы полностью сосредоточиться на изучении интеграции локальных LLM-моделей. На это время я оставляю только поддержку учеников модуля, а все остальные задачи — аудиты, разработку и анализ отчетов — временно приостанавливаю.
За последнее время я успел познакомиться с возможностями LLM, которые способны серьезно повлиять не только на разработку и тестирование смарт-контрактов, но и на их математические модели и сложную архитектуру. В ближайшем будущем появятся решения, автоматизирующие создание тестов в Foundry с проверкой всех возможных сценариев выполнения функций и логических потоков. Кроме того, нейросети смогут анализировать инварианты математических расчетов, выполняя сотни тысяч итераций, и помогать выявлять серьезные уязвимости уровня Med или High.
Примечательно, что это будут не массовые коммерческие модели вроде ChatGPT, Claude или Gemini, а специализированные локальные решения, оптимизированные под конкретные задачи. Крупные компании вряд ли в ближайшие годы будут заниматься узкой настройкой своих продуктов для отдельных областей, поскольку их основная цель — конкуренция на глобальном рынке.
Моя задача — научиться отличать действительно полезные проекты от поверхностных решений, которые представляют собой всего лишь обертку над API популярных нейросетей. В ходе обучения я планирую разобраться в настройках моделей, их разновидностях, бенчмарках, библиотеках для работы с ними, а также в таких темах, как квантизация и оптимизация производительности.
В скором времени мы вернемся к изучению Solidity и актуальных трендов в этой области — у меня уже есть несколько интересных тем для обсуждения. Желаю вам продуктивной недели и отличного настроения!
Всем хорошего настроения и приятной недели!
#offtop
👏18
Держу в курсе и не пропадаю
В течение недели, посвященной учебному отпуску, я ознакомился с базовыми аспектами работы с моделями LLM. В частности, изучил принципы квантизации, основные библиотеки для ее реализации, структуру весов модели, а также такие понятия, как PTQ, QAT, GGUF и GPTQ. Кроме того, рассмотрел различные подходы к бенчмаркингу и другие сопутствующие вопросы. Это позволило более осознанно подходить к выбору моделей для конкретных задач и их настройке с учетом доступных вычислительных ресурсов.
Как часто бывает в процессе изучения сложных тем, углубление в материал порождает новые вопросы. В связи с этим я принял решение постепенно, в свободное время, осваивать основы машинного и глубокого обучения (ML/DL). Это обусловлено двумя ключевыми причинами.
Во-первых, я стремлюсь к системному пониманию данной области, что необходимо для завершения разработки собственного ассистента для аудита.
Во-вторых, все чаще отмечаю рост интереса к применению LLM среди аудиторов и разработчиков. Например, в репозиториях блокчейн-протоколов появляются специализированные файлы (такие как llm.md), описывающие функционал моделей в контексте конкретных задач.
На ближайшие шесть месяцев я планирую сосредоточиться на изучении следующих аспектов ML/DL:
1. Базовые алгоритмы: линейная и логистическая регрессия, метод опорных векторов (SVM), деревья решений, ансамбли моделей.
2. Методы оценки качества моделей: кросс-валидация, метрики (accuracy, precision, recall, F1, ROC-AUC).
3. Регуляризация и методы оптимизации (градиентный спуск, Adam, RMSProp).
4. Архитектуры нейронных сетей.
5. Работа с функциями потерь (loss functions) и оптимизация гиперпараметров.
6. Техники ускорения обучения: batch normalization, dropout, early stopping.
7. Transfer Learning и Fine-Tuning.
8. Предобработка данных: аугментация, нормализация, работа с несбалансированными выборками.
На данный момент я также провел предварительный анализ доступных обучающих курсов, однако большинство из них требуют серьезной математической подготовки и углубленного владения Python, чем я пока не обладаю в достаточной мере.
Текущая неделя будет посвящена формированию детального плана обучения. А со следующей недели планируется возобновление работы с Solidity.
Однако, чтобы канал не пустовал, выйдет пара коротких постов про Foundry на неделе.
Всем хорошего дня и приятной недели!
#offtop
В течение недели, посвященной учебному отпуску, я ознакомился с базовыми аспектами работы с моделями LLM. В частности, изучил принципы квантизации, основные библиотеки для ее реализации, структуру весов модели, а также такие понятия, как PTQ, QAT, GGUF и GPTQ. Кроме того, рассмотрел различные подходы к бенчмаркингу и другие сопутствующие вопросы. Это позволило более осознанно подходить к выбору моделей для конкретных задач и их настройке с учетом доступных вычислительных ресурсов.
Как часто бывает в процессе изучения сложных тем, углубление в материал порождает новые вопросы. В связи с этим я принял решение постепенно, в свободное время, осваивать основы машинного и глубокого обучения (ML/DL). Это обусловлено двумя ключевыми причинами.
Во-первых, я стремлюсь к системному пониманию данной области, что необходимо для завершения разработки собственного ассистента для аудита.
Во-вторых, все чаще отмечаю рост интереса к применению LLM среди аудиторов и разработчиков. Например, в репозиториях блокчейн-протоколов появляются специализированные файлы (такие как llm.md), описывающие функционал моделей в контексте конкретных задач.
На ближайшие шесть месяцев я планирую сосредоточиться на изучении следующих аспектов ML/DL:
1. Базовые алгоритмы: линейная и логистическая регрессия, метод опорных векторов (SVM), деревья решений, ансамбли моделей.
2. Методы оценки качества моделей: кросс-валидация, метрики (accuracy, precision, recall, F1, ROC-AUC).
3. Регуляризация и методы оптимизации (градиентный спуск, Adam, RMSProp).
4. Архитектуры нейронных сетей.
5. Работа с функциями потерь (loss functions) и оптимизация гиперпараметров.
6. Техники ускорения обучения: batch normalization, dropout, early stopping.
7. Transfer Learning и Fine-Tuning.
8. Предобработка данных: аугментация, нормализация, работа с несбалансированными выборками.
На данный момент я также провел предварительный анализ доступных обучающих курсов, однако большинство из них требуют серьезной математической подготовки и углубленного владения Python, чем я пока не обладаю в достаточной мере.
Текущая неделя будет посвящена формированию детального плана обучения. А со следующей недели планируется возобновление работы с Solidity.
Однако, чтобы канал не пустовал, выйдет пара коротких постов про Foundry на неделе.
Всем хорошего дня и приятной недели!
#offtop
🔥12👍5❤3
This media is not supported in your browser
VIEW IN TELEGRAM
Подсказка по Foundry
Если вы часто пишите фазз и инвариант тесты в Foundry, то с флагом "--show-progress" вы сможете увидеть процесс самого тестирования. Бывает полезно, когда вы хотите отследить некоторые моменты - прогоны, успехи и неудачи в вызовах.
Подробнее на видео.
#foundry
Если вы часто пишите фазз и инвариант тесты в Foundry, то с флагом "--show-progress" вы сможете увидеть процесс самого тестирования. Бывает полезно, когда вы хотите отследить некоторые моменты - прогоны, успехи и неудачи в вызовах.
Подробнее на видео.
#foundry
🔥8
И еще одна подсказка по Foundry
Вы можете использовать команду:
чтобы получить селекторы ваших кастомных ошибок. Бывает полезно при работе с дебаггингом функция и function flow.
#foundry
Вы можете использовать команду:
forge inspect MyContract errors
чтобы получить селекторы ваших кастомных ошибок. Бывает полезно при работе с дебаггингом функция и function flow.
#foundry
👍9❤2
Solidity hints. Часть 26
Я как-то очень плотно сейчас погружаюсь в линейную алгебру (векторы, матрицы, спуски) и не сильно способен разбирать новые сложные темы в Solidity. Поэтому сейчас будут более простые темы, которые подойдет и для начинающих.
У нас ранее был цикл постов по материалам Chinmaya, где он делал список пунктов, на которые следует обратить внимание при разработке. Вот думаю продолжить некоторое время делать небольшие разборы.
Сегодня давайте посмотрим на пункт 44:
Library functions can only be called directly (i.e. without the use of DELEGATECALL ) if they do not modify the state (view or pure)
что в переводе:
Функции библиотек могут быть вызваны напрямую (без использования delegatecall), если они не изменяют состояние смарт контракта.
А теперь чуть подробнее.
В Solidity библиотеки (libraries, а не набор контрактов, типа Open Zeppelin) представляют собой наборы функций, которые можно повторно использовать в разных контрактах. Тут важно понимать, как именно вызываются их функции, особенно если они взаимодействуют с состоянием контракта.
Функции библиотек могут быть вызваны напрямую только в том случае, если они не модифицируют состояние блокчейна, то есть помечены как view или pure. Это связано с тем, что библиотеки по умолчанию не хранят собственное состояние и выполняются в контексте вызывающего контракта.
Когда функция библиотеки вызывается напрямую (например, MyLibrary.doSomething()), код выполняется в контексте вызывающего контракта, но без изменения его хранилища (storage). Если бы библиотека могла изменять состояние при таком вызове, это привело бы к неоднозначности: откуда брать storage для записи? Поэтому Solidity запрещает вызов не-view/не-pure функций библиотек без использования DELEGATECALL, который явно указывает, что изменения должны применяться к storage вызывающего контракта.
Если функция библиотеки должна изменять состояние, её вызов должен происходить через DELEGATECALL. На практике это означает, что библиотеку нужно внедрить в контракт с помощью using ... for, а затем вызывать её методы для конкретных переменных. Например:
Здесь increment изменяет storage контракта, поэтому вызывается через механизм DELEGATECALL.
Понимание этого механизма поможет избежать ошибок при разработке смарт-контрактов.
#libraries
Я как-то очень плотно сейчас погружаюсь в линейную алгебру (векторы, матрицы, спуски) и не сильно способен разбирать новые сложные темы в Solidity. Поэтому сейчас будут более простые темы, которые подойдет и для начинающих.
У нас ранее был цикл постов по материалам Chinmaya, где он делал список пунктов, на которые следует обратить внимание при разработке. Вот думаю продолжить некоторое время делать небольшие разборы.
Сегодня давайте посмотрим на пункт 44:
Library functions can only be called directly (i.e. without the use of DELEGATECALL ) if they do not modify the state (view or pure)
что в переводе:
Функции библиотек могут быть вызваны напрямую (без использования delegatecall), если они не изменяют состояние смарт контракта.
А теперь чуть подробнее.
В Solidity библиотеки (libraries, а не набор контрактов, типа Open Zeppelin) представляют собой наборы функций, которые можно повторно использовать в разных контрактах. Тут важно понимать, как именно вызываются их функции, особенно если они взаимодействуют с состоянием контракта.
Функции библиотек могут быть вызваны напрямую только в том случае, если они не модифицируют состояние блокчейна, то есть помечены как view или pure. Это связано с тем, что библиотеки по умолчанию не хранят собственное состояние и выполняются в контексте вызывающего контракта.
Когда функция библиотеки вызывается напрямую (например, MyLibrary.doSomething()), код выполняется в контексте вызывающего контракта, но без изменения его хранилища (storage). Если бы библиотека могла изменять состояние при таком вызове, это привело бы к неоднозначности: откуда брать storage для записи? Поэтому Solidity запрещает вызов не-view/не-pure функций библиотек без использования DELEGATECALL, который явно указывает, что изменения должны применяться к storage вызывающего контракта.
Если функция библиотеки должна изменять состояние, её вызов должен происходить через DELEGATECALL. На практике это означает, что библиотеку нужно внедрить в контракт с помощью using ... for, а затем вызывать её методы для конкретных переменных. Например:
library Math {
function increment(uint256 storage num) external {
num += 1;
}
}
contract MyContract {
using Math for uint256;
uint256 public counter;
function increase() public {
counter.increment(); // Вызов через DELEGATECALL
}
}Здесь increment изменяет storage контракта, поэтому вызывается через механизм DELEGATECALL.
Понимание этого механизма поможет избежать ошибок при разработке смарт-контрактов.
#libraries
👍6❤1
Solidity hints. Часть 27
А вот об этом пункте деплоя контрактов с библиотеками в блокчейн даже я не знал.
Когда компилятор Solidity обрабатывает контракт, использующий библиотеку, он не знает, по какому адресу эта библиотека будет развернута в будущем. В результате скомпилированный байт-код содержит специальные заглушки, которые выглядят как $30bbc0abd4d6364515865950d3e0d10953$. Эти заглушки необходимы, так как на момент компиляции адрес библиотеки неизвестен, и их нужно заменить на реальные адреса после деплоя библиотеки в сеть.
Заглушка формируется как 34-символьный префикс от хеша keccak256 полного имени библиотеки. Например, если библиотека BigInt находится в файле bigint.sol внутри директории libraries, её полное имя будет выглядеть как libraries/bigint.sol:BigInt. Компилятор хеширует это имя и использует часть хеша в качестве временного заполнителя. Это позволяет однозначно идентифицировать библиотеку на этапе линковки.
Такой байт-код с заглушками считается неполным и не должен быть развернут в блокчейн в этом виде. Если контракт с не заменёнными плейсхолдерами всё же попадет в сеть, он окажется неработоспособным, так как виртуальная машина Ethereum не сможет найти библиотеку по несуществующему адресу. Поэтому перед деплоем необходимо выполнить линковку — замену всех заглушек на актуальные адреса развернутых библиотек.
Процесс линковки обычно выполняется с помощью инструментов, таких как Hardhat, Foundry или Remix, которые автоматически находят нужные библиотеки в сети и подставляют их адреса. Вручную это тоже возможно, но требует точного соответствия между именем библиотеки и её адресом. После замены всех плейсхолдеров контракт становится готовым к развертыванию и корректной работе в блокчейне.
#libraries
А вот об этом пункте деплоя контрактов с библиотеками в блокчейн даже я не знал.
Когда компилятор Solidity обрабатывает контракт, использующий библиотеку, он не знает, по какому адресу эта библиотека будет развернута в будущем. В результате скомпилированный байт-код содержит специальные заглушки, которые выглядят как $30bbc0abd4d6364515865950d3e0d10953$. Эти заглушки необходимы, так как на момент компиляции адрес библиотеки неизвестен, и их нужно заменить на реальные адреса после деплоя библиотеки в сеть.
Заглушка формируется как 34-символьный префикс от хеша keccak256 полного имени библиотеки. Например, если библиотека BigInt находится в файле bigint.sol внутри директории libraries, её полное имя будет выглядеть как libraries/bigint.sol:BigInt. Компилятор хеширует это имя и использует часть хеша в качестве временного заполнителя. Это позволяет однозначно идентифицировать библиотеку на этапе линковки.
Такой байт-код с заглушками считается неполным и не должен быть развернут в блокчейн в этом виде. Если контракт с не заменёнными плейсхолдерами всё же попадет в сеть, он окажется неработоспособным, так как виртуальная машина Ethereum не сможет найти библиотеку по несуществующему адресу. Поэтому перед деплоем необходимо выполнить линковку — замену всех заглушек на актуальные адреса развернутых библиотек.
Процесс линковки обычно выполняется с помощью инструментов, таких как Hardhat, Foundry или Remix, которые автоматически находят нужные библиотеки в сети и подставляют их адреса. Вручную это тоже возможно, но требует точного соответствия между именем библиотеки и её адресом. После замены всех плейсхолдеров контракт становится готовым к развертыванию и корректной работе в блокчейне.
#libraries
👍7
Как воспроизвести простую атаку с использованием MEV. Часть 1
В этой серии постов мы рассмотрим один из распространённых способов, с помощью которого злоумышленник может атаковать уязвимый протокол с использованием MEV. Также мы покажем, как разработчикам можно корректно продемонстрировать вектор атаки MEV с помощью PoC.
Начнем с самого начала: что такое MEV?
MEV (Miner Extractable Value — «Стоимость, извлекаемая майнером», или Maximal Extractable Value — «Максимально извлекаемая стоимость») позволяет майнерам исключать, включать и изменять порядок транзакций в блоке до его добычи. После слияния Ethereum (The Merge) эта роль перешла от майнеров к валидаторам сети. Тем не менее, вектор атаки через MEV остаётся актуальным и широко распространённым в блокчейн-среде.
Существует множество способов, которыми злоумышленник может использовать MEV. Мы рассмотрим так называемую «сэндвич-атаку» (sandwich attack), которая осуществляется путём фронтраннинга и бэкраннинга транзакции обмена жертвы.
Фронтраннинг (Frontrunning)
Фронтраннинг — это техника, при которой злоумышленник умудряется разместить свою транзакцию перед транзакцией жертвы, чтобы она выполнилась первой. Это можно сделать, увеличив цену газа в своей вредоносной транзакции, благодаря чему она будет иметь приоритет над транзакцией жертвы, у которой более низкая цена газа.
Бэкраннинг (Backrunning)
Бэкраннинг — это техника, при которой злоумышленник размещает свою вредоносную транзакцию после выполнения транзакции жертвы. Злоумышленник может добиться этого, снизив цену газа в своей транзакции, что позволит транзакции жертвы получить приоритет.
Сэндвич-атака (Sandwich Attack)
При сэндвич-атаке злоумышленник отслеживает мемпул (список ожидающих транзакций) в поисках целевой транзакции, которую можно использовать в своих интересах. Как только такая транзакция обнаружена, злоумышленник отправляет две транзакции — одну до и одну после целевой, «зажимая» её, словно бутерброд. Цель такой атаки — повлиять на выполнение или результат целевой транзакции в свою пользу.
Используя методы, описанные выше, злоумышленник отправляет две транзакции — с более высокой и более низкой стоимостью газа по сравнению с транзакцией жертвы, чтобы успешно выполнить сэндвич-атаку. Альтернативно, он может отправить пакет транзакций (transaction bundle) через специализированные RPC-провайдеры, которые за плату гарантируют нужный порядок транзакций.
Такой тип атак особенно опасен в экосистеме DeFi, где транзакции с токенами, пулами ликвидности или децентрализованными биржами крайне чувствительны к порядку выполнения. Цель злоумышленника в таких случаях — манипулировать ценами активов, получать прибыль от арбитража или использовать другие уязвимости протокола в личных целях.
Далее рассмотрим, как протестировать такие транзакции в Hardhat и Foundry.
#mev
В этой серии постов мы рассмотрим один из распространённых способов, с помощью которого злоумышленник может атаковать уязвимый протокол с использованием MEV. Также мы покажем, как разработчикам можно корректно продемонстрировать вектор атаки MEV с помощью PoC.
Начнем с самого начала: что такое MEV?
MEV (Miner Extractable Value — «Стоимость, извлекаемая майнером», или Maximal Extractable Value — «Максимально извлекаемая стоимость») позволяет майнерам исключать, включать и изменять порядок транзакций в блоке до его добычи. После слияния Ethereum (The Merge) эта роль перешла от майнеров к валидаторам сети. Тем не менее, вектор атаки через MEV остаётся актуальным и широко распространённым в блокчейн-среде.
Существует множество способов, которыми злоумышленник может использовать MEV. Мы рассмотрим так называемую «сэндвич-атаку» (sandwich attack), которая осуществляется путём фронтраннинга и бэкраннинга транзакции обмена жертвы.
Фронтраннинг (Frontrunning)
Фронтраннинг — это техника, при которой злоумышленник умудряется разместить свою транзакцию перед транзакцией жертвы, чтобы она выполнилась первой. Это можно сделать, увеличив цену газа в своей вредоносной транзакции, благодаря чему она будет иметь приоритет над транзакцией жертвы, у которой более низкая цена газа.
Бэкраннинг (Backrunning)
Бэкраннинг — это техника, при которой злоумышленник размещает свою вредоносную транзакцию после выполнения транзакции жертвы. Злоумышленник может добиться этого, снизив цену газа в своей транзакции, что позволит транзакции жертвы получить приоритет.
Сэндвич-атака (Sandwich Attack)
При сэндвич-атаке злоумышленник отслеживает мемпул (список ожидающих транзакций) в поисках целевой транзакции, которую можно использовать в своих интересах. Как только такая транзакция обнаружена, злоумышленник отправляет две транзакции — одну до и одну после целевой, «зажимая» её, словно бутерброд. Цель такой атаки — повлиять на выполнение или результат целевой транзакции в свою пользу.
Используя методы, описанные выше, злоумышленник отправляет две транзакции — с более высокой и более низкой стоимостью газа по сравнению с транзакцией жертвы, чтобы успешно выполнить сэндвич-атаку. Альтернативно, он может отправить пакет транзакций (transaction bundle) через специализированные RPC-провайдеры, которые за плату гарантируют нужный порядок транзакций.
Такой тип атак особенно опасен в экосистеме DeFi, где транзакции с токенами, пулами ликвидности или децентрализованными биржами крайне чувствительны к порядку выполнения. Цель злоумышленника в таких случаях — манипулировать ценами активов, получать прибыль от арбитража или использовать другие уязвимости протокола в личных целях.
Далее рассмотрим, как протестировать такие транзакции в Hardhat и Foundry.
#mev
👍13
Как воспроизвести простую атаку с использованием MEV. Часть 2
Для того, чтобы создать PoC для демонстрации MEV-атаки, мы можем использовать такие инструменты, как Hardhat и Forge, для создания локального форка блокчейна.
И чтобы доказать детерминированный результат между этими двумя тестами, мы будем использовать один и тот же контракт Attacker, доступ к которому можно получить через этот Github gist.
В этом примере мы намеренно заставим жертву инициировать транзакцию обмена WETH на USDC в UniswapV2 с минимальной суммой 0. То, что делает эту транзакцию уязвимой для атаки «сэндвич», так это минимальная сумма, установленная на 0, что означает, что транзакция не будет отменена, даже если жертва получит только 0 USDC или 99% проскальзывания. Вот почему очень важно правильно установить минимальную сумму.
Как все проверить в Foundry?
1. Для начала убедитесь, что Foundry все таки установлен у вас. Затем создайте отдельную папку и выполните forge init.
2. Измените контракт в папке src на контракт атакующего. Также замените тестовый файл в папке test на Sandwich.t.sol.
3. В результате у вас должен получиться такой же output в консоли, как на скрине.
Так нам удалось продемонстрировать атаку "сэндвич" с Forge. Как видно из результатов тестового случая, злоумышленник и жертва начали с начальным балансом в 1000 WETH, и хакеру удалось опередить и обойти транзакцию жертвы, что принесло ему прибыль в размере ~123 WETH. В результате жертва получает меньше USDC.
P.S. Для Hardhat, в целом, все так же для первоначальных настроек проекта, только использовать стоит файл sandwichAttack.js.
#mev
Для того, чтобы создать PoC для демонстрации MEV-атаки, мы можем использовать такие инструменты, как Hardhat и Forge, для создания локального форка блокчейна.
И чтобы доказать детерминированный результат между этими двумя тестами, мы будем использовать один и тот же контракт Attacker, доступ к которому можно получить через этот Github gist.
В этом примере мы намеренно заставим жертву инициировать транзакцию обмена WETH на USDC в UniswapV2 с минимальной суммой 0. То, что делает эту транзакцию уязвимой для атаки «сэндвич», так это минимальная сумма, установленная на 0, что означает, что транзакция не будет отменена, даже если жертва получит только 0 USDC или 99% проскальзывания. Вот почему очень важно правильно установить минимальную сумму.
Router2.swapExactTokensForTokens(amount, 0, path, address(this), block.timestamp + 4200);
Как все проверить в Foundry?
1. Для начала убедитесь, что Foundry все таки установлен у вас. Затем создайте отдельную папку и выполните forge init.
2. Измените контракт в папке src на контракт атакующего. Также замените тестовый файл в папке test на Sandwich.t.sol.
3. В результате у вас должен получиться такой же output в консоли, как на скрине.
Так нам удалось продемонстрировать атаку "сэндвич" с Forge. Как видно из результатов тестового случая, злоумышленник и жертва начали с начальным балансом в 1000 WETH, и хакеру удалось опередить и обойти транзакцию жертвы, что принесло ему прибыль в размере ~123 WETH. В результате жертва получает меньше USDC.
P.S. Для Hardhat, в целом, все так же для первоначальных настроек проекта, только использовать стоит файл sandwichAttack.js.
#mev
👍7
Solidity - деспотизм, Python - анархия
Хотел бы поделиться своими успехами в освоении machine learning и deep learning.
Стоит отметить, что мое изучение этой области не связано со сменой профессии, а направлено на интеграцию навыков работы с Web3 и LLM. Моя цель — научиться эффективно взаимодействовать с моделями и обучать их на примерах уязвимостей смарт-контрактов.
За последний месяц я углубился в теоретические основы линейной алгебры, а на прошлой неделе приступил к изучению Python.
Несмотря на то, что я долгое время избегал этот язык, в сфере машинного обучения без него не обойтись. Популярные библиотеки для работы с LLM реализованы именно на Python, и для эффективной разработки необходимо понимать их устройство и принципы работы.
После недели изучения Python у меня сложилось четкое представление о его кардинальном отличии от Solidity.
Для тех, у кого Solidity был первым языком, переход на Python покажется довольно простым. Отсутствие строгой типизации, минималистичный синтаксис без избыточных скобок и точек с запятой, а также гибкость в обработке данных делают его значительно более доступным. Кортежи можно сравнить с calldata, а декораторы — с модификаторами в Solidity.
Обилие библиотек и подробной документации значительно упрощает процесс освоения. Базовое понимание кода на Python можно получить за несколько дней, а за месяц — научиться писать рабочие решения.
Разумеется, речь не идет о профессиональном уровне владения языком. Чтобы стать senior-разработчиком, потребуются годы практики. Однако для написания функционального кода при наличии опыта в других языках месяца будет достаточно.
В ближайших планах — изучение Fast API, который, вероятно, понадобится для взаимодействия с MCP-серверами, а затем детальное освоение библиотек для работы с моделями.
Кроме того, я подготовил roadmap по освоению профессии Machine Learning / Deep Learning Engineer, основанный на личном опыте и актуальных требованиях индустрии. В нем собраны ключевые темы, включая те, которые часто затрагиваются на собеседованиях. Этим планом можно свободно пользоваться и адаптировать под свои задачи.
Моя текущая цель — за два месяца разобраться в теоретических основах и получить базовые практические навыки, чтобы в дальнейшем углубляться в специфику направления с четким пониманием взаимосвязей между различными компонентами.
Пока это основные итоги моего прогресса. Буду держать вас в курсе дальнейших достижений.
#ml
Хотел бы поделиться своими успехами в освоении machine learning и deep learning.
Стоит отметить, что мое изучение этой области не связано со сменой профессии, а направлено на интеграцию навыков работы с Web3 и LLM. Моя цель — научиться эффективно взаимодействовать с моделями и обучать их на примерах уязвимостей смарт-контрактов.
За последний месяц я углубился в теоретические основы линейной алгебры, а на прошлой неделе приступил к изучению Python.
Несмотря на то, что я долгое время избегал этот язык, в сфере машинного обучения без него не обойтись. Популярные библиотеки для работы с LLM реализованы именно на Python, и для эффективной разработки необходимо понимать их устройство и принципы работы.
После недели изучения Python у меня сложилось четкое представление о его кардинальном отличии от Solidity.
Для тех, у кого Solidity был первым языком, переход на Python покажется довольно простым. Отсутствие строгой типизации, минималистичный синтаксис без избыточных скобок и точек с запятой, а также гибкость в обработке данных делают его значительно более доступным. Кортежи можно сравнить с calldata, а декораторы — с модификаторами в Solidity.
Обилие библиотек и подробной документации значительно упрощает процесс освоения. Базовое понимание кода на Python можно получить за несколько дней, а за месяц — научиться писать рабочие решения.
Разумеется, речь не идет о профессиональном уровне владения языком. Чтобы стать senior-разработчиком, потребуются годы практики. Однако для написания функционального кода при наличии опыта в других языках месяца будет достаточно.
В ближайших планах — изучение Fast API, который, вероятно, понадобится для взаимодействия с MCP-серверами, а затем детальное освоение библиотек для работы с моделями.
Кроме того, я подготовил roadmap по освоению профессии Machine Learning / Deep Learning Engineer, основанный на личном опыте и актуальных требованиях индустрии. В нем собраны ключевые темы, включая те, которые часто затрагиваются на собеседованиях. Этим планом можно свободно пользоваться и адаптировать под свои задачи.
Моя текущая цель — за два месяца разобраться в теоретических основах и получить базовые практические навыки, чтобы в дальнейшем углубляться в специфику направления с четким пониманием взаимосвязей между различными компонентами.
Пока это основные итоги моего прогресса. Буду держать вас в курсе дальнейших достижений.
#ml
❤19
К разработчикам смарт контрактов будут предъявлять новые требования при найме?
Сегодняшний разработчик смарт-контрактов — это уже не просто человек за клавиатурой, который пишет код на Solidity и проверяет его через Foundry. Современный специалист должен понимать, как работают децентрализованные системы, как находить и устранять уязвимости, и при этом держать руку на пульсе технологических изменений. Одно из таких изменений — появление инструментов, которые позволяют искусственному интеллекту взаимодействовать с блокчейном и смарт-контрактами. И ключевую роль здесь начинают играть MCP-серверы — Model Context Protocol серверы. Это, по сути, мост между языковыми моделями и внешними системами, включая блокчейн, API и базы данных. Они позволяют ИИ безопасно получать данные и выполнять действия, не выходя за рамки заданного контекста.
Современные языковые модели уже умеют писать смарт-контракты на Solidity и других языках без дополнительных инструментов — они обучаются на огромных объёмах кода и могут воспроизводить шаблоны, включая использование библиотек вроде OpenZeppelin. Однако одно дело — сгенерировать код по памяти, и совсем другое — гарантировать, что он актуален, безопасен и соответствует последним версиям проверенных шаблонов. Именно здесь на помощь приходит MCP-сервер. Он позволяет модели не просто "вспоминать" код, а запрашивать его напрямую из доверенного источника — например, из официальных репозиториев OpenZeppelin. Сервер выступает в роли посредника, предоставляя модели доступ к точным, аудированным шаблонам и строго регламентируя, какие действия и с какими параметрами могут быть выполнены. Это превращает ИИ из пассивного генератора текста в активного участника разработки, способного безопасно и точно взаимодействовать с внешними системами.
Одна из ведущих компаний в области безопасности — Trail of Bits — уже занялась вопросами защиты таких взаимодействий. Они разработали mcp-context-protector — специальный слой безопасности, который защищает от атак, когда вредоносный сервер может подменить инструкции для модели. Например, через описания инструментов можно внедрить prompt-инъекцию и заставить модель выполнять нежелательные действия. Их решение работает как прокси: оно проверяет все, что приходит от сервера, до того как это попадёт в контекст модели. Это особенно важно, когда вы доверяете стороннему MCP-серверу, потому что теперь можно быть уверенным, что в коде или инструкциях не скрыто ничего опасного.
Но не только про безопасность. OpenZeppelin, известный своими шаблонами для безопасных контрактов, запустил свой MCP-сервер, который позволяет разработчикам генерировать готовые контракты на Solidity, Cairo и других языках. Представьте: вы просто говорите ассистенту — "создай ERC-20 токен с именем MyToken и общим объёмом 1 миллион", — а он, через MCP-сервер OpenZeppelin, получает шаблон, подставляет параметры и возвращает вам готовый, аудированный код. Это экономит время, снижает риск ошибок и делает процесс разработки доступнее даже для новичков.
Что особенно ценно — эти серверы не просто дают доступ к функциям, они делают это в стандартизированной и безопасной форме. MCP-сервер OpenZeppelin не просто генерирует код, он делает это на основе проверенных шаблонов, которые уже используются тысячами проектов. А благодаря интеграции с безопасными протоколами, вы можете быть уверены, что даже если ИИ что-то напутает, базовая архитектура останется надёжной. Это как если бы у вас был старший разработчик, который всегда проверяет ваш код перед тем, как он попадёт в продакшн.
Для разработчика это означает, что скоро будет недостаточно просто знать Solidity. Важно будет понимать, как работают внешние инструменты, как интегрировать их через MCP, и как обеспечивать безопасность этих взаимодействий. Умение настраивать, проверять и использовать MCP-серверы станет частью повседневной работы. И те, кто начнёт изучать это уже сейчас, получат серьёзное преимущество — не только в скорости разработки, но и в качестве итогового продукта.
Сегодняшний разработчик смарт-контрактов — это уже не просто человек за клавиатурой, который пишет код на Solidity и проверяет его через Foundry. Современный специалист должен понимать, как работают децентрализованные системы, как находить и устранять уязвимости, и при этом держать руку на пульсе технологических изменений. Одно из таких изменений — появление инструментов, которые позволяют искусственному интеллекту взаимодействовать с блокчейном и смарт-контрактами. И ключевую роль здесь начинают играть MCP-серверы — Model Context Protocol серверы. Это, по сути, мост между языковыми моделями и внешними системами, включая блокчейн, API и базы данных. Они позволяют ИИ безопасно получать данные и выполнять действия, не выходя за рамки заданного контекста.
Современные языковые модели уже умеют писать смарт-контракты на Solidity и других языках без дополнительных инструментов — они обучаются на огромных объёмах кода и могут воспроизводить шаблоны, включая использование библиотек вроде OpenZeppelin. Однако одно дело — сгенерировать код по памяти, и совсем другое — гарантировать, что он актуален, безопасен и соответствует последним версиям проверенных шаблонов. Именно здесь на помощь приходит MCP-сервер. Он позволяет модели не просто "вспоминать" код, а запрашивать его напрямую из доверенного источника — например, из официальных репозиториев OpenZeppelin. Сервер выступает в роли посредника, предоставляя модели доступ к точным, аудированным шаблонам и строго регламентируя, какие действия и с какими параметрами могут быть выполнены. Это превращает ИИ из пассивного генератора текста в активного участника разработки, способного безопасно и точно взаимодействовать с внешними системами.
Одна из ведущих компаний в области безопасности — Trail of Bits — уже занялась вопросами защиты таких взаимодействий. Они разработали mcp-context-protector — специальный слой безопасности, который защищает от атак, когда вредоносный сервер может подменить инструкции для модели. Например, через описания инструментов можно внедрить prompt-инъекцию и заставить модель выполнять нежелательные действия. Их решение работает как прокси: оно проверяет все, что приходит от сервера, до того как это попадёт в контекст модели. Это особенно важно, когда вы доверяете стороннему MCP-серверу, потому что теперь можно быть уверенным, что в коде или инструкциях не скрыто ничего опасного.
Но не только про безопасность. OpenZeppelin, известный своими шаблонами для безопасных контрактов, запустил свой MCP-сервер, который позволяет разработчикам генерировать готовые контракты на Solidity, Cairo и других языках. Представьте: вы просто говорите ассистенту — "создай ERC-20 токен с именем MyToken и общим объёмом 1 миллион", — а он, через MCP-сервер OpenZeppelin, получает шаблон, подставляет параметры и возвращает вам готовый, аудированный код. Это экономит время, снижает риск ошибок и делает процесс разработки доступнее даже для новичков.
Что особенно ценно — эти серверы не просто дают доступ к функциям, они делают это в стандартизированной и безопасной форме. MCP-сервер OpenZeppelin не просто генерирует код, он делает это на основе проверенных шаблонов, которые уже используются тысячами проектов. А благодаря интеграции с безопасными протоколами, вы можете быть уверены, что даже если ИИ что-то напутает, базовая архитектура останется надёжной. Это как если бы у вас был старший разработчик, который всегда проверяет ваш код перед тем, как он попадёт в продакшн.
Для разработчика это означает, что скоро будет недостаточно просто знать Solidity. Важно будет понимать, как работают внешние инструменты, как интегрировать их через MCP, и как обеспечивать безопасность этих взаимодействий. Умение настраивать, проверять и использовать MCP-серверы станет частью повседневной работы. И те, кто начнёт изучать это уже сейчас, получат серьёзное преимущество — не только в скорости разработки, но и в качестве итогового продукта.
🔥7❤3
Всё это — часть более широкого сдвига: мы переходим от ручного кодирования к агент-ориентированной разработке, где ИИ становится активным участником процесса. Но с ростом возможностей растёт и ответственность. Поэтому важно не просто подключать MCP-серверы, а понимать, как они работают, что они делают и как их можно взломать. Будущее смарт-контрактов — это не только безопасный код, но и безопасные инструменты, которые помогают этот код создавать.
#llm #solidity
#llm #solidity
👍5🔥1
Обновление в Solidity
Об интересном обновлении в Solidity 0.8.29 я узнал на днях из чатика аудиторов, спасибо @SovaSlava!
В этой версии языка появилась поддержка указания кастомных слотов хранилища смарт контрактов, как на скрине выше.
Контракты в Solidity по умолчанию размещают свои переменные состояния, начиная с нулевого слота хранилища, и далее последовательно, в соответствии с порядком определения и иерархией наследования. Однако, начиная с новой версией языка, появилась возможность явно задать начальный слот для размещения хранилища с помощью спецификатора layout at. Это позволяет разработчику управлять тем, с какого именно слота будут начинаться переменные состояния контракта, включая те, что унаследованы от базовых контрактов. Такая гибкость открывает новые возможности для сложных сценариев, особенно в системах с динамической логикой или при работе с прокси-паттернами, где требуется точный контроль над расположением данных в хранилище.
Рассмотрим конкретный пример:
contract C layout at 2**255 - 42 задаёт начальный слот для хранилища как значение, равное 2 в степени 255 минус 42. Это число находится в верхней половине диапазона uint256, но всё ещё достаточно далеко от максимального значения, чтобы оставить место для размещения хотя бы нескольких переменных. Переменная uint x, будучи первой в контракте, будет размещена именно в этом слоте — то есть в слоте с номером 578...66. Это демонстрирует, что выражение в спецификаторе layout at может быть сложным, но при этом оно должно быть вычислимо на этапе компиляции.
Спецификатор layout at должен содержать выражение и результат должен быть значением типа uint256. Это может быть простая константа, сумма или битовый сдвиг, но не может включать вызовы функций или переменные. Компилятор проверяет, не выходит ли суммарный объём статических данных за пределы адресного пространства хранилища. Например, если базовый слот установлен слишком близко к type(uint256).max, и при этом контракт имеет много переменных, компилятор выдаст ошибку, чтобы предотвратить «переполнение» хранилища. Однако динамические структуры, такие как массивы переменной длины и маппинги, не подпадают под эту проверку, поскольку их данные размещаются не линейно, а по хеш-адресам, вычисляемым на основе ключей и базового слота.
Важно понимать, что спецификатор layout at можно указать только для самого верхнего контракта в дереве наследования, и он влияет на все переменные состояния во всей иерархии. Если контракт A наследуется B, а B — C, и только C имеет layout at, то все переменные из A, B и C будут сдвинуты на одну и ту же величину. При этом абстрактные контракты, интерфейсы и библиотеки не могут использовать этот механизм, так как они либо не имеют собственного хранилища, либо не предназначены для развертывания как независимые экземпляры. Также не затрагиваются временные переменные, помеченные как transient, поскольку они хранятся не в постоянном хранилище.
На практике этот механизм может быть использован в системах, где требуется изолировать хранилище контракта от других данных, например, в реализациях UUPS (Universal Upgradeable Proxy Standard), где логика обновления должна гарантированно не затрагивать определённые слоты. Другой пример — многомодульные системы, где каждый модуль размещается в выделенной области хранилища, и использование layout at позволяет избежать случайных пересечений. Однако следует быть осторожным: использование слотов вблизи верхней границы адресного пространства может затруднить будущие обновления или привести к коллизиям при использовании inline assembly для ручной записи данных. Также стоит помнить, что layout и at пока не являются зарезервированными словами, но их использование в качестве идентификаторов в будущем станет невозможным, поэтому лучше избегать их в именах переменных и функций уже сейчас.
#solidity
Об интересном обновлении в Solidity 0.8.29 я узнал на днях из чатика аудиторов, спасибо @SovaSlava!
В этой версии языка появилась поддержка указания кастомных слотов хранилища смарт контрактов, как на скрине выше.
Контракты в Solidity по умолчанию размещают свои переменные состояния, начиная с нулевого слота хранилища, и далее последовательно, в соответствии с порядком определения и иерархией наследования. Однако, начиная с новой версией языка, появилась возможность явно задать начальный слот для размещения хранилища с помощью спецификатора layout at. Это позволяет разработчику управлять тем, с какого именно слота будут начинаться переменные состояния контракта, включая те, что унаследованы от базовых контрактов. Такая гибкость открывает новые возможности для сложных сценариев, особенно в системах с динамической логикой или при работе с прокси-паттернами, где требуется точный контроль над расположением данных в хранилище.
Рассмотрим конкретный пример:
contract C layout at 2**255 - 42 {
uint x;
}contract C layout at 2**255 - 42 задаёт начальный слот для хранилища как значение, равное 2 в степени 255 минус 42. Это число находится в верхней половине диапазона uint256, но всё ещё достаточно далеко от максимального значения, чтобы оставить место для размещения хотя бы нескольких переменных. Переменная uint x, будучи первой в контракте, будет размещена именно в этом слоте — то есть в слоте с номером 578...66. Это демонстрирует, что выражение в спецификаторе layout at может быть сложным, но при этом оно должно быть вычислимо на этапе компиляции.
Спецификатор layout at должен содержать выражение и результат должен быть значением типа uint256. Это может быть простая константа, сумма или битовый сдвиг, но не может включать вызовы функций или переменные. Компилятор проверяет, не выходит ли суммарный объём статических данных за пределы адресного пространства хранилища. Например, если базовый слот установлен слишком близко к type(uint256).max, и при этом контракт имеет много переменных, компилятор выдаст ошибку, чтобы предотвратить «переполнение» хранилища. Однако динамические структуры, такие как массивы переменной длины и маппинги, не подпадают под эту проверку, поскольку их данные размещаются не линейно, а по хеш-адресам, вычисляемым на основе ключей и базового слота.
Важно понимать, что спецификатор layout at можно указать только для самого верхнего контракта в дереве наследования, и он влияет на все переменные состояния во всей иерархии. Если контракт A наследуется B, а B — C, и только C имеет layout at, то все переменные из A, B и C будут сдвинуты на одну и ту же величину. При этом абстрактные контракты, интерфейсы и библиотеки не могут использовать этот механизм, так как они либо не имеют собственного хранилища, либо не предназначены для развертывания как независимые экземпляры. Также не затрагиваются временные переменные, помеченные как transient, поскольку они хранятся не в постоянном хранилище.
На практике этот механизм может быть использован в системах, где требуется изолировать хранилище контракта от других данных, например, в реализациях UUPS (Universal Upgradeable Proxy Standard), где логика обновления должна гарантированно не затрагивать определённые слоты. Другой пример — многомодульные системы, где каждый модуль размещается в выделенной области хранилища, и использование layout at позволяет избежать случайных пересечений. Однако следует быть осторожным: использование слотов вблизи верхней границы адресного пространства может затруднить будущие обновления или привести к коллизиям при использовании inline assembly для ручной записи данных. Также стоит помнить, что layout и at пока не являются зарезервированными словами, но их использование в качестве идентификаторов в будущем станет невозможным, поэтому лучше избегать их в именах переменных и функций уже сейчас.
#solidity
1❤8🔥3👍2
Взломы контрактов с помощью LLM все ближе
Пока одни аудиторы в Твиттере смеются над теми кто использует LLM в своей работе, другие учатся ее использовать на 100%.
На днях попалась очень интересная статья, где группа разработчиков создала агента для взлома смарт контрактов:
https://arxiv.org/abs/2507.05558v2
Постараюсь кратко пересказать ее.
Исследователи представили A1 — агентную систему на основе больших языковых моделей, способную автоматически генерировать эксплойты для уязвимостей в смарт-контрактах DeFi. В отличие от традиционных инструментов анализа, которые лишь указывают на потенциальные баги, A1 строит полный Proof-of-Concept атаки, включая цепочку транзакций, использование flash loan и извлечение реальной экономической выгоды. Это позволяет не просто обнаружить уязвимость, а доказать её эксплуатируемость, что кардинально повышает значимость находки. Система работает итеративно, используя обратную связь от выполнения на симулированной блокчейн-среде, и за несколько шагов уточняет и доводит стратегию до успешного результата.
A1 была протестирована на наборе из 36 реальных инцидентов, включая атаки через манипуляцию цен, реентранси и уязвимости в механизмах распределения токенов. В среднем система достигла успеха в 72,2% случаев, а с использованием самых мощных моделей, таких как OpenAI o3-pro, этот показатель вырос до 88,5%. Общая сумма, которую удалось воспроизвести как извлечённую прибыль, составила 9,33 миллиона долларов. При этом A1 продемонстрировала результативность, сопоставимую с современными фаззерами, такими как ItyFuzz и Efcf, но при этом с меньшим количеством ложных срабатываний, поскольку каждый успех подтверждён реальным экономическим эффектом.
Одним из ключевых аспектов работы является экономический анализ рентабельности использования A1 как в атакующих, так и в защитных целях. Показано, что при реалистичных предположениях — например, при наличии баг-баунти в размере 10% от ущерба — использование A1 может быть прибыльным для аудиторов и защитников. Однако система выявила тревожную асимметрию: атакующим проще окупить затраты на запуск таких агентов, поскольку им не нужно ожидать официального вознаграждения и они могут сразу извлекать прибыль. Это означает, что технология, хотя и доступна обеим сторонам, фактически смещает преимущество в пользу злоумышленников.
Система A1 интегрируется с рядом специализированных инструментов: для получения исходного кода, анализа состояния контрактов, нормализации дохода в базовую валюту и выполнения транзакций в изолированной среде. Она поддерживает как Ethereum, так и BSC, и способна обрабатывать сложные сценарии, включая работу с proxy-контрактами и учёт рыночной ликвидности при построении маршрутов обмена. При этом производительность сильно зависит от выбранной LLM: например, Gemini Flash работает быстро, но менее точно, тогда как o3-pro даёт лучшие результаты, но требует в среднем 34 минуты на один запуск.
Работа поднимает важные вопросы о будущем безопасности смарт-контрактов. Если агенты на основе ИИ могут уже сейчас воспроизводить реальные атаки, это означает, что традиционные методы аудита и анализа требуют модернизации. Авторы подчёркивают, что A1 — не замена фаззерам, а дополнение, особенно эффективное в сценариях, требующих глубокого логического и экономического анализа. Исследование демонстрирует, что граница между программным анализом, машинным рассуждением и экономикой в DeFi продолжает стираться, и дальнейшее развитие в этой области неизбежно потребует более сложных, агентных систем, способных мыслить стратегически и адаптироваться к динамике реальных систем.
#llm #solidity
Пока одни аудиторы в Твиттере смеются над теми кто использует LLM в своей работе, другие учатся ее использовать на 100%.
На днях попалась очень интересная статья, где группа разработчиков создала агента для взлома смарт контрактов:
https://arxiv.org/abs/2507.05558v2
Постараюсь кратко пересказать ее.
Исследователи представили A1 — агентную систему на основе больших языковых моделей, способную автоматически генерировать эксплойты для уязвимостей в смарт-контрактах DeFi. В отличие от традиционных инструментов анализа, которые лишь указывают на потенциальные баги, A1 строит полный Proof-of-Concept атаки, включая цепочку транзакций, использование flash loan и извлечение реальной экономической выгоды. Это позволяет не просто обнаружить уязвимость, а доказать её эксплуатируемость, что кардинально повышает значимость находки. Система работает итеративно, используя обратную связь от выполнения на симулированной блокчейн-среде, и за несколько шагов уточняет и доводит стратегию до успешного результата.
A1 была протестирована на наборе из 36 реальных инцидентов, включая атаки через манипуляцию цен, реентранси и уязвимости в механизмах распределения токенов. В среднем система достигла успеха в 72,2% случаев, а с использованием самых мощных моделей, таких как OpenAI o3-pro, этот показатель вырос до 88,5%. Общая сумма, которую удалось воспроизвести как извлечённую прибыль, составила 9,33 миллиона долларов. При этом A1 продемонстрировала результативность, сопоставимую с современными фаззерами, такими как ItyFuzz и Efcf, но при этом с меньшим количеством ложных срабатываний, поскольку каждый успех подтверждён реальным экономическим эффектом.
Одним из ключевых аспектов работы является экономический анализ рентабельности использования A1 как в атакующих, так и в защитных целях. Показано, что при реалистичных предположениях — например, при наличии баг-баунти в размере 10% от ущерба — использование A1 может быть прибыльным для аудиторов и защитников. Однако система выявила тревожную асимметрию: атакующим проще окупить затраты на запуск таких агентов, поскольку им не нужно ожидать официального вознаграждения и они могут сразу извлекать прибыль. Это означает, что технология, хотя и доступна обеим сторонам, фактически смещает преимущество в пользу злоумышленников.
Система A1 интегрируется с рядом специализированных инструментов: для получения исходного кода, анализа состояния контрактов, нормализации дохода в базовую валюту и выполнения транзакций в изолированной среде. Она поддерживает как Ethereum, так и BSC, и способна обрабатывать сложные сценарии, включая работу с proxy-контрактами и учёт рыночной ликвидности при построении маршрутов обмена. При этом производительность сильно зависит от выбранной LLM: например, Gemini Flash работает быстро, но менее точно, тогда как o3-pro даёт лучшие результаты, но требует в среднем 34 минуты на один запуск.
Работа поднимает важные вопросы о будущем безопасности смарт-контрактов. Если агенты на основе ИИ могут уже сейчас воспроизводить реальные атаки, это означает, что традиционные методы аудита и анализа требуют модернизации. Авторы подчёркивают, что A1 — не замена фаззерам, а дополнение, особенно эффективное в сценариях, требующих глубокого логического и экономического анализа. Исследование демонстрирует, что граница между программным анализом, машинным рассуждением и экономикой в DeFi продолжает стираться, и дальнейшее развитие в этой области неизбежно потребует более сложных, агентных систем, способных мыслить стратегически и адаптироваться к динамике реальных систем.
#llm #solidity
2😱10
Сколько нужно учиться в день?
Вопрос о том, сколько времени нужно уделять обучению каждый день, наверное, один из самых частых перед стартом курса. Люди хотят понять, как правильно распределить усилия, чтобы двигаться вперёд с ощутимым прогрессом.
На протяжении долгого времени мой ответ был примерно одинаковым: учиться стоит столько, сколько потребуется для глубокого понимания темы. Если вы разобрались за полчаса — отлично, если на это ушло два часа или даже больше — тоже прекрасно. У каждого свой темп, и универсальных временных рамок здесь быть не может.
Недавно я сам погрузился в новую для себя область — машинное и глубокое обучение. Это совершенно новая сфера, где я начинаю практически с чистого листа. Математика даётся непросто, и я чувствую себя тем, кто только делает первые шаги, как и многие из вас, осваивая, например, Solidity с самых основ.
За последний месяц я потратил на обучение 33 часа. Поскольку в выходные стараюсь отключаться от компьютера, занятия проходят только в будние дни. Казалось бы, в среднем это чуть больше часа в день — но на деле всё обстоит иначе.
Процесс совсем не равномерный: бывает, что в один день я только знакомлюсь с новой темой, а в другой — полностью погружаюсь в неё, уделяя теории и практике по пять-шесть часов подряд.
Для меня ключевое — не количество затраченного времени, а качество усвоения. Могу ли я объяснить пройденное простыми словами, так, чтобы понял человек без технического бэкграунда? Если да — значит, тема усвоена, можно двигаться дальше. Если нет — возвращаюсь к материалу, выписываю вопросы, ищу дополнительные источники, пока не почувствую уверенность.
За эти 33 часа я освоил базовый синтаксис Python, познакомился с такими модулями, как math и itertools, разобрался с основами линейной алгебры — видами векторов и матриц, операциями над ними — и начал работать с библиотекой numpy.
Скоро я вернусь к началу, чтобы повторить пройденное, систематизировать знания и закрепить их.
Надеюсь, из моего опыта видно, что путь обучения у каждого индивидуален. Нет единого графика, по которому все обязательно добьются результата за определённое время.
Я по-прежнему убеждён: регулярность куда важнее интенсивности. Главное — не пропадать, двигаться вперёд хоть понемногу, но каждый день. И уже через месяц-два вы с удивлением оглянетесь назад и увидите, как много успели освоить.
#study
Вопрос о том, сколько времени нужно уделять обучению каждый день, наверное, один из самых частых перед стартом курса. Люди хотят понять, как правильно распределить усилия, чтобы двигаться вперёд с ощутимым прогрессом.
На протяжении долгого времени мой ответ был примерно одинаковым: учиться стоит столько, сколько потребуется для глубокого понимания темы. Если вы разобрались за полчаса — отлично, если на это ушло два часа или даже больше — тоже прекрасно. У каждого свой темп, и универсальных временных рамок здесь быть не может.
Недавно я сам погрузился в новую для себя область — машинное и глубокое обучение. Это совершенно новая сфера, где я начинаю практически с чистого листа. Математика даётся непросто, и я чувствую себя тем, кто только делает первые шаги, как и многие из вас, осваивая, например, Solidity с самых основ.
За последний месяц я потратил на обучение 33 часа. Поскольку в выходные стараюсь отключаться от компьютера, занятия проходят только в будние дни. Казалось бы, в среднем это чуть больше часа в день — но на деле всё обстоит иначе.
Процесс совсем не равномерный: бывает, что в один день я только знакомлюсь с новой темой, а в другой — полностью погружаюсь в неё, уделяя теории и практике по пять-шесть часов подряд.
Для меня ключевое — не количество затраченного времени, а качество усвоения. Могу ли я объяснить пройденное простыми словами, так, чтобы понял человек без технического бэкграунда? Если да — значит, тема усвоена, можно двигаться дальше. Если нет — возвращаюсь к материалу, выписываю вопросы, ищу дополнительные источники, пока не почувствую уверенность.
За эти 33 часа я освоил базовый синтаксис Python, познакомился с такими модулями, как math и itertools, разобрался с основами линейной алгебры — видами векторов и матриц, операциями над ними — и начал работать с библиотекой numpy.
Скоро я вернусь к началу, чтобы повторить пройденное, систематизировать знания и закрепить их.
Надеюсь, из моего опыта видно, что путь обучения у каждого индивидуален. Нет единого графика, по которому все обязательно добьются результата за определённое время.
Я по-прежнему убеждён: регулярность куда важнее интенсивности. Главное — не пропадать, двигаться вперёд хоть понемногу, но каждый день. И уже через месяц-два вы с удивлением оглянетесь назад и увидите, как много успели освоить.
#study
❤7👍4🔥1
Новый способ взаимодействия Foundry и AI
Недавно наткнулся на интересный проект под названием foundry-mcp-server, который предлагает новый способ взаимодействия с экосистемой Foundry. Этот репозиторий представляет собой сервер, реализующий протокол MCP (Model Context Protocol), что позволяет интегрировать внешние инструменты, например, AI-ассистенты, непосредственно в процесс разработки смарт-контрактов. Идея заключается в том, чтобы сделать взаимодействие между разработчиком и инструментами анализа кода более гибким и контекстно-зависимым, используя стандартный протокол обмена данными.
Особенность foundry-mcp-server в том, что он не просто предоставляет API, а создает среду, в которой AI-модели могут получать доступ к состоянию проекта Foundry, запускать тесты, анализировать контракты и даже предлагать исправления на основе реального контекста. Это особенно полезно при тестировании — например, можно настроить ассистента, который автоматически генерирует edge-case тесты на основе анализа кода или выявляет потенциальные уязвимости, используя статический анализ в сочетании с семантическим пониманием. Такой подход может значительно ускорить процесс ревью и повысить качество кода.
С технической точки зрения, сервер написан на Rust и использует стандартные инструменты Foundry, такие как cast и anvil, для выполнения операций в блокчейн-среде. Он запускается локально и предоставляет HTTP-интерфейс, через который внешние клиенты могут запрашивать информацию о проекте, выполнять команды и получать результаты. Например, можно запросить список всех тестов в проекте, получить ABI контракта или запустить конкретный тест с определёнными параметрами. Всё это делается с сохранением полного контекста — включая состояние сети, переменные окружения и результаты предыдущих операций.
Одним из ключевых преимуществ этой архитектуры является её расширяемость. Поскольку MCP — это открытый протокол, разработчики могут подключать к серверу различные инструменты: от IDE-плагинов до автономных агентов, которые самостоятельно исследуют код и предлагают оптимизации. Это открывает путь к созданию «умных» систем разработки, где AI не просто подсказывает, а активно участвует в процессе — например, перебирает различные сценарии атак на контракт или автоматически генерирует документацию на основе кода и комментариев.
На данный момент проект находится на ранней стадии, но уже демонстрирует большой потенциал. Он может стать важным звеном в цепочке инструментов для безопасной разработки смарт-контрактов, особенно в сочетании с системами CI/CD и автоматизированным тестированием. Если вы работаете с Foundry и интересуетесь автоматизацией процессов разработки, стоит посмотреть на foundry-mcp-server как на экспериментальную, но перспективную платформу для построения следующего поколения инструментов для Solidity.
Примеры его работы можно посмотреть в этой ветке Твиттера.
#foundry
Недавно наткнулся на интересный проект под названием foundry-mcp-server, который предлагает новый способ взаимодействия с экосистемой Foundry. Этот репозиторий представляет собой сервер, реализующий протокол MCP (Model Context Protocol), что позволяет интегрировать внешние инструменты, например, AI-ассистенты, непосредственно в процесс разработки смарт-контрактов. Идея заключается в том, чтобы сделать взаимодействие между разработчиком и инструментами анализа кода более гибким и контекстно-зависимым, используя стандартный протокол обмена данными.
Особенность foundry-mcp-server в том, что он не просто предоставляет API, а создает среду, в которой AI-модели могут получать доступ к состоянию проекта Foundry, запускать тесты, анализировать контракты и даже предлагать исправления на основе реального контекста. Это особенно полезно при тестировании — например, можно настроить ассистента, который автоматически генерирует edge-case тесты на основе анализа кода или выявляет потенциальные уязвимости, используя статический анализ в сочетании с семантическим пониманием. Такой подход может значительно ускорить процесс ревью и повысить качество кода.
С технической точки зрения, сервер написан на Rust и использует стандартные инструменты Foundry, такие как cast и anvil, для выполнения операций в блокчейн-среде. Он запускается локально и предоставляет HTTP-интерфейс, через который внешние клиенты могут запрашивать информацию о проекте, выполнять команды и получать результаты. Например, можно запросить список всех тестов в проекте, получить ABI контракта или запустить конкретный тест с определёнными параметрами. Всё это делается с сохранением полного контекста — включая состояние сети, переменные окружения и результаты предыдущих операций.
Одним из ключевых преимуществ этой архитектуры является её расширяемость. Поскольку MCP — это открытый протокол, разработчики могут подключать к серверу различные инструменты: от IDE-плагинов до автономных агентов, которые самостоятельно исследуют код и предлагают оптимизации. Это открывает путь к созданию «умных» систем разработки, где AI не просто подсказывает, а активно участвует в процессе — например, перебирает различные сценарии атак на контракт или автоматически генерирует документацию на основе кода и комментариев.
На данный момент проект находится на ранней стадии, но уже демонстрирует большой потенциал. Он может стать важным звеном в цепочке инструментов для безопасной разработки смарт-контрактов, особенно в сочетании с системами CI/CD и автоматизированным тестированием. Если вы работаете с Foundry и интересуетесь автоматизацией процессов разработки, стоит посмотреть на foundry-mcp-server как на экспериментальную, но перспективную платформу для построения следующего поколения инструментов для Solidity.
Примеры его работы можно посмотреть в этой ветке Твиттера.
#foundry
🔥9❤1🤔1
Кто-нибудь хочет присоединиться к модулю по Foundry?
На этой неделе завершается основная обучающая часть Летнего модуля. Следующая неделя знаменует собой начало нового блока — практическое освоение экосистемы Foundry для начинающих.
Как я обещал ранее, в ответ на запросы участников этого канала, которые хотели присоединиться именно к этой части курса, мы откроем дополнительный набор.
Если вы заинтересованы в участии в модуле по Foundry, пожалуйста, дайте знать в опросе ниже.
Старт на следующей неделе.
Стоимость: 3000 рублей, 40 USDT
Старт продаж в пятницу.
Напомню темы модуля:
Неделя 1
1. Установка Foundry: что входит в программу и для чего это нужно
2. Знакомство с cast командами. Чем они нужны и как работают
3. Сложные команды cast, которые пригодятся разработчику
4. Работа с chisel. Побитовые сдвиги и форк сети
5. Настройки Foundry: профили, библиотеки, пути
Неделя 2
6. Какие тесты бывают: правила написания и формирования папки проекта
7. Создание setUp() функции для удобного написания тестов. Роли пользователей, управление временем в тестах
8. Логика assert условий
9. Работа с ошибками и событиями в тестах
10. Логирование результатов теста и вывод в консоль
Неделя 3
11. Фазз тесты
12. Форк тесты. Интеграции с другими протоколами
13. Мутационные тесты
14. Тестирование подписей в контрактах
15. Деплой в разные сети. Написание простых скриптов
Неделя 4. Бонусные уроки
16. Интеграция с Hardhat
17. Хранение приватных ключей
18. Современные программы тестирования
19. Финальный практикум
Если есть какие-либо вопросы, буду рад ответить в комментариях!
#foundry
На этой неделе завершается основная обучающая часть Летнего модуля. Следующая неделя знаменует собой начало нового блока — практическое освоение экосистемы Foundry для начинающих.
Как я обещал ранее, в ответ на запросы участников этого канала, которые хотели присоединиться именно к этой части курса, мы откроем дополнительный набор.
Если вы заинтересованы в участии в модуле по Foundry, пожалуйста, дайте знать в опросе ниже.
Старт на следующей неделе.
Стоимость: 3000 рублей, 40 USDT
Старт продаж в пятницу.
Напомню темы модуля:
Неделя 1
1. Установка Foundry: что входит в программу и для чего это нужно
2. Знакомство с cast командами. Чем они нужны и как работают
3. Сложные команды cast, которые пригодятся разработчику
4. Работа с chisel. Побитовые сдвиги и форк сети
5. Настройки Foundry: профили, библиотеки, пути
Неделя 2
6. Какие тесты бывают: правила написания и формирования папки проекта
7. Создание setUp() функции для удобного написания тестов. Роли пользователей, управление временем в тестах
8. Логика assert условий
9. Работа с ошибками и событиями в тестах
10. Логирование результатов теста и вывод в консоль
Неделя 3
11. Фазз тесты
12. Форк тесты. Интеграции с другими протоколами
13. Мутационные тесты
14. Тестирование подписей в контрактах
15. Деплой в разные сети. Написание простых скриптов
Неделя 4. Бонусные уроки
16. Интеграция с Hardhat
17. Хранение приватных ключей
18. Современные программы тестирования
19. Финальный практикум
Если есть какие-либо вопросы, буду рад ответить в комментариях!
#foundry
🔥3❤1👍1
Кто-нибудь хочет присоединиться к модулю по Foundry?
P.S. Ученикам текущего Летнего модуля голосовать не нужно.
P.S. Ученикам текущего Летнего модуля голосовать не нужно.
Final Results
45%
Да, уже готов!
55%
Не в этот раз (не хочу, не нужно, уже знаю)
Атака Denial-of-Service. Часть 1
Пока я обучаюсь линейной алгебре и работаю над своим ассистентом для аудита, подумал, что будет здорово разобрать несколько популярных атак в блокчейне: и для начинающих аудиторов это будет полезно и интересно, и я сам, возможно, найду новые нюансы, на которые стоит обращать внимание.
В блоге Cyfrin мне попался прекрасный цикл статей от крутого аудитора и судьи Hans, который разбирает уязвимости из "Solodit Checklist". Давайте вместе изучим их.
Итак, первая уязвимость, которую мы рассмотрим это "DoS".
Почему нам стоит беспокоиться о DoS-атаках?
Разве DoS-атаки — это проблема только для традиционных централизованных серверов? Что-то, о чем должны переживать только крупные корпорации, верно? Нет!
На самом деле, в децентрализованных финансах (DeFi) DoS-атаки могут быть разрушительными. Представьте себе этот кошмарный сценарий: ваш тщательно разработанный стейкинг-контракт, созданный для щедрого вознаграждения пользователей, внезапно… перестает работать.
Он встает колом, потому что какой-то злоумышленник забрасывает его транзакциями. Пользователи не могут вывести свои средства, и вся система становится безнадежно неработоспособной. А что насчет вашей репутации? Она падает быстрее, чем цена мемкоина после rug pull'а (а мы все знаем, каково это).
DoS-атаки используют уязвимости в вашем коде, делая смарт-контракт бесполезным — либо для конкретных пользователей, либо для всех. Они как цифровые баррикады, мешающие честным людям получить доступ к услугам вашего протокола! В сфере, где доверие решает все, успешная DoS-атака может стать полной катастрофой.
Для наглядности представьте: вы вложили душу в создание прекрасной кофейни. Это лучшая кофейня в мире. Но тут кто-то приходит и начинает заказывать тысячи пустых чашек кофе, забивая всю систему и не давая реальным клиентам получить свой кофеин. Бесит, правда?
Denial-of-Service (DoS) атака: общий обзор
DoS-атаки обычно используют недостатки в логике вашего смарт-контракта, а не грубую силу. Это тонкая манипуляция, которая вас побеждает.
Вот как это работает:
1. Эксплуатация логики — злоумышленники находят хитрые (или, точнее, вредоносные) способы вызвать изменения состояния, которые приводят к откату транзакций или бесконечным циклам, фактически замораживая контракт. Это происходит чаще, чем кажется.
2. Исчерпание ресурсов — представьте себе это как трагедию общего достояния, но с комиссиями за газ. Атакующий заваливает контракт запросами, сжигая огромное количество газа и делая его использование невыгодным для обычных пользователей. Помните: каждое действие в блокчейне требует газа, а лавина транзакций может взвинтить эти расходы.
Теперь, когда мы кратко разобрали основы (и, надеюсь, убедили вас, что DoS-атаки — реальная угроза), давайте углубимся в конкретные способы защиты.
SOL-AM-DOSA-1: Используется ли паттерн вывода средств для защиты от DoS?
Иными словами: Вы применяете "pull" вместо "push" подход для вывода средств?
Классическая ошибка (которую я видел слишком много раз в конкурсах по аудиту) — это передача ETH пользователям в функции вывода средств. Кажется, все просто, правда? Совершенно не так! Давайте посмотрим на код:
Почему это плохо?
Если msg.sender — это контракт, который ревертится при получении ETH (по любой причине — возможно, из-за злонамеренных действий), то вся функция вывода средств будет ревертиться также для всех! Это создает реальную ситуацию DoS, поскольку легитимные пользователи не могут вывести средства из-за одного неработающего адреса. Представьте себе хаос!
Решение: модель pull
Пока я обучаюсь линейной алгебре и работаю над своим ассистентом для аудита, подумал, что будет здорово разобрать несколько популярных атак в блокчейне: и для начинающих аудиторов это будет полезно и интересно, и я сам, возможно, найду новые нюансы, на которые стоит обращать внимание.
В блоге Cyfrin мне попался прекрасный цикл статей от крутого аудитора и судьи Hans, который разбирает уязвимости из "Solodit Checklist". Давайте вместе изучим их.
Итак, первая уязвимость, которую мы рассмотрим это "DoS".
Почему нам стоит беспокоиться о DoS-атаках?
Разве DoS-атаки — это проблема только для традиционных централизованных серверов? Что-то, о чем должны переживать только крупные корпорации, верно? Нет!
На самом деле, в децентрализованных финансах (DeFi) DoS-атаки могут быть разрушительными. Представьте себе этот кошмарный сценарий: ваш тщательно разработанный стейкинг-контракт, созданный для щедрого вознаграждения пользователей, внезапно… перестает работать.
Он встает колом, потому что какой-то злоумышленник забрасывает его транзакциями. Пользователи не могут вывести свои средства, и вся система становится безнадежно неработоспособной. А что насчет вашей репутации? Она падает быстрее, чем цена мемкоина после rug pull'а (а мы все знаем, каково это).
DoS-атаки используют уязвимости в вашем коде, делая смарт-контракт бесполезным — либо для конкретных пользователей, либо для всех. Они как цифровые баррикады, мешающие честным людям получить доступ к услугам вашего протокола! В сфере, где доверие решает все, успешная DoS-атака может стать полной катастрофой.
Для наглядности представьте: вы вложили душу в создание прекрасной кофейни. Это лучшая кофейня в мире. Но тут кто-то приходит и начинает заказывать тысячи пустых чашек кофе, забивая всю систему и не давая реальным клиентам получить свой кофеин. Бесит, правда?
Denial-of-Service (DoS) атака: общий обзор
DoS-атаки обычно используют недостатки в логике вашего смарт-контракта, а не грубую силу. Это тонкая манипуляция, которая вас побеждает.
Вот как это работает:
1. Эксплуатация логики — злоумышленники находят хитрые (или, точнее, вредоносные) способы вызвать изменения состояния, которые приводят к откату транзакций или бесконечным циклам, фактически замораживая контракт. Это происходит чаще, чем кажется.
2. Исчерпание ресурсов — представьте себе это как трагедию общего достояния, но с комиссиями за газ. Атакующий заваливает контракт запросами, сжигая огромное количество газа и делая его использование невыгодным для обычных пользователей. Помните: каждое действие в блокчейне требует газа, а лавина транзакций может взвинтить эти расходы.
Теперь, когда мы кратко разобрали основы (и, надеюсь, убедили вас, что DoS-атаки — реальная угроза), давайте углубимся в конкретные способы защиты.
SOL-AM-DOSA-1: Используется ли паттерн вывода средств для защиты от DoS?
Иными словами: Вы применяете "pull" вместо "push" подход для вывода средств?
Классическая ошибка (которую я видел слишком много раз в конкурсах по аудиту) — это передача ETH пользователям в функции вывода средств. Кажется, все просто, правда? Совершенно не так! Давайте посмотрим на код:
// Anti-pattern: Pushing ETH
function batchWithdraw() public {
address[] memory users = getUsers(); // imaginary function to get users
for (uint i = 0; i < users.length; i++) {
uint amount = balances[users[i]];
if (amount > 0) {
balances[users[i]] = 0;
(bool success, ) = users[i].call{value: amount}(""); // Potential DoS!
require(success, "Transfer failed"); // If any transfer fails, the entire batch reverts
}
}
}
Почему это плохо?
Если msg.sender — это контракт, который ревертится при получении ETH (по любой причине — возможно, из-за злонамеренных действий), то вся функция вывода средств будет ревертиться также для всех! Это создает реальную ситуацию DoS, поскольку легитимные пользователи не могут вывести средства из-за одного неработающего адреса. Представьте себе хаос!
Решение: модель pull
Вместо push, позвольте пользователям самим забирать свои токены. Они инициируют перевод из контракта. Это как дать им ключ от хранилища. Выглядит это так:
Теперь, если вывод средств пользователя не удается, это затрагивает только его самого. Контракт продолжает функционировать для всех остальных. Это и есть правильная децентрализация! Оператор require проверяет, был ли перевод успешным. В случае неудачи транзакция отменяется только для запрашивающего пользователя, что оказывает минимальное влияние на текущие операции.
В примере, приведенном в пункте чеклиста, подробно описан сценарий, в котором комиссии переводятся владельцу до вывода средств пользователем. Если адрес владельца случайно установлен на нулевой адрес или если владелец является, э-э-э, злонамеренным контрактом, который ревертит перевод токенов, вывод средств пользователями не удастся. Это неприятная ошибка для отладки! Минимальный пример и PoC, написанные в Foundry, доступны здесь.
Далее разберем еще два случая атаки.
#dos
// Pull Pattern: Much Safer!
mapping(address => uint) public withdrawableBalances;
// Step 1: Admin marks funds as withdrawable without actually sending them
function startBatchWithdrawal() public {
address[] memory users = getUsers(); // imaginary function to get users
for (uint i = 0; i < users.length; i++) {
uint amount = balances[users[i]];
if (amount > 0) {
balances[users[i]] = 0;
withdrawableBalances[users[i]] += amount;
}
}
}
// Step 2: Each user withdraws their own funds individually
function withdraw() public {
uint amount = withdrawableBalances[msg.sender];
require(amount > 0, "No funds to withdraw");
withdrawableBalances[msg.sender] = 0;
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
Теперь, если вывод средств пользователя не удается, это затрагивает только его самого. Контракт продолжает функционировать для всех остальных. Это и есть правильная децентрализация! Оператор require проверяет, был ли перевод успешным. В случае неудачи транзакция отменяется только для запрашивающего пользователя, что оказывает минимальное влияние на текущие операции.
В примере, приведенном в пункте чеклиста, подробно описан сценарий, в котором комиссии переводятся владельцу до вывода средств пользователем. Если адрес владельца случайно установлен на нулевой адрес или если владелец является, э-э-э, злонамеренным контрактом, который ревертит перевод токенов, вывод средств пользователями не удастся. Это неприятная ошибка для отладки! Минимальный пример и PoC, написанные в Foundry, доступны здесь.
Далее разберем еще два случая атаки.
#dos
👍2❤1
Атака Denial-of-Service. Часть 2
Существует ли минимальная сумма транзакции?
Намек: Вы предотвращаете «пылевые» транзакции (крошечные, незначительные суммы), которые забивают ваш контракт и делают все неиспользуемым?
Здесь речь идет о предотвращении спама, просто и понятно. Если ваш контракт позволяет пользователям взаимодействовать с ним на любую сумму (даже на крошечные, незначительные доли токенов), злоумышленники могут затопить его бесчисленными транзакциями с нулевой или почти нулевой стоимостью. Все эти транзакции потребляют газ и делают законные операции гораздо более дорогостоящими. Это увеличение затрат может потенциально достичь предела лимита газа в блоке. Если это произойдет, нормальные пользователи не смогут взаимодействовать с вашим протоколом. Вот как выглядит уязвимый код:
Решение: ввести минимальное требование!
Простой оператор require может значительно улучшить ситуацию. Введите пороговое значение с помощью оператора require и действуйте как охранник, проверяющий удостоверение личности на входе в клуб. Нам также необходимо обеспечить возможность обработки запросов на снятие средств пакетами. Вот как это сделать:
В примере чеклиста показан контракт, в котором пользователи могут запрашивать вывод буквально любой суммы (даже нулевой), независимо от ее размера. Злоумышленник может воспользоваться этим, чтобы создать огромную очередь запросов на вывод с нулевой стоимостью. Это делает обработку законных запросов на вывод чрезмерно дорогой, что обходится пользователям в огромные расходы на газ. Минимальный пример и PoC, написанные в Foundry, доступны здесь.
#foundry #dos
Существует ли минимальная сумма транзакции?
Намек: Вы предотвращаете «пылевые» транзакции (крошечные, незначительные суммы), которые забивают ваш контракт и делают все неиспользуемым?
Здесь речь идет о предотвращении спама, просто и понятно. Если ваш контракт позволяет пользователям взаимодействовать с ним на любую сумму (даже на крошечные, незначительные доли токенов), злоумышленники могут затопить его бесчисленными транзакциями с нулевой или почти нулевой стоимостью. Все эти транзакции потребляют газ и делают законные операции гораздо более дорогостоящими. Это увеличение затрат может потенциально достичь предела лимита газа в блоке. Если это произойдет, нормальные пользователи не смогут взаимодействовать с вашим протоколом. Вот как выглядит уязвимый код:
// Vulnerable to dust attacks
struct WithdrawalRequest {
address user;
uint amount;
}
WithdrawalRequest[] public withdrawalRequests;
// Anyone can submit withdrawal requests for ANY amount (even 1 wei!)
function requestWithdrawal(uint amount) external {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
// Add to the global withdrawal queue - no minimum amount check!
withdrawalRequests.push(WithdrawalRequest(msg.sender, amount));
}
function processWithdrawals() external onlyOwner {
for (uint256 i = 0; i < withdrawalRequests.length; i++) { // This amplifies the attack even more because it tries to handle all the requests at once
WithdrawalRequest memory request = withdrawalRequests[i];
request.user.transfer(request.amount);
}
withdrawalRequests = new WithdrawalRequest[](0);
}
Решение: ввести минимальное требование!
Простой оператор require может значительно улучшить ситуацию. Введите пороговое значение с помощью оператора require и действуйте как охранник, проверяющий удостоверение личности на входе в клуб. Нам также необходимо обеспечить возможность обработки запросов на снятие средств пакетами. Вот как это сделать:
uint public minimumWithdrawal = 0.1 ether;
function requestWithdrawal(uint amount) external {
require(balances[msg.sender] >= amount, "Insufficient balance");
require(amount >= minimumWithdrawal, "Amount below minimum withdrawal threshold"); // Bouncer!
balances[msg.sender] -= amount;
withdrawalRequests.push(WithdrawalRequest(msg.sender, amount));
}
function processWithdrawals(uint count) external onlyOwner { // We can process in batches now
for (uint256 i = 0; i < count; i++) {
WithdrawalRequest memory request = withdrawalRequests[i];
request.user.transfer(request.amount);
}
for (uint i = 0; i < withdrawalRequests.length - count; i++) {
withdrawalRequests[i] = withdrawalRequests[i + count];
}
withdrawalRequests.length = withdrawalRequests.length - count;
}
В примере чеклиста показан контракт, в котором пользователи могут запрашивать вывод буквально любой суммы (даже нулевой), независимо от ее размера. Злоумышленник может воспользоваться этим, чтобы создать огромную очередь запросов на вывод с нулевой стоимостью. Это делает обработку законных запросов на вывод чрезмерно дорогой, что обходится пользователям в огромные расходы на газ. Минимальный пример и PoC, написанные в Foundry, доступны здесь.
#foundry #dos
👍8❤1