Solidity. Смарт контракты и аудит
2.63K subscribers
246 photos
7 videos
18 files
550 links
Обучение Solidity. Уроки, аудит, разбор кода и популярных сервисов
Download Telegram
Foundry и старые pragma

На канале в комментариях где-то были вопросы, а как писать тесты, когда контракты имеют разную версию pragma? Ведь может быть и 0.6.0 и 0.8.19 в одном проекте!

В Foundry есть специальный читкод, который помогает деплоить контракты разных версий в тестах:

function deployCode(string memory what) public returns (address);


Пример использования этого читкода вы можете видеть выше на скрине!

Больше о нем можно прочитать тут:

https://book.getfoundry.sh/reference/forge-std/deployCode

Теперь тесты можно писать еще быстрее!

#foundry
🔥7👏1🤯1
Забытый скрин к посту выше)
2👍1
Чеклист от Solodit

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

Есть такая платформа Solodit, которая собирает отчеты по уязвимостям со многих площадок (типа С4) и частных аудиторов (типа Trust).

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

https://solodit.xyz/checklist

Все разбито по темам и категориям. Вы можете выбрать те, которые относятся к вашему проекту и "пробежаться" по ним.

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

#solodit
🔥7👍2
Новости и программа 4 модуля курса

Многие в прошлом году спрашивали про 4 модуль курса и его темы, поэтому потихоньку буду раскрывать детали. Прежде всего начнем с программы, которая рассчитана на 4 недели обучения:

Модуль 4

Неделя 1

1. Древо Меркла: общее
2. Подписи и стандарты
3. ecrecover и ECDSA
4. Безопасность подписей

Неделя 2

5. Прокси. Общее
6. Transparent и UUPS proxy
7. Beacon proxy, Diamond
8. Безопасность proxy

Неделя 3

9. Работа с памятью: code
10. Работа с памятью: storage
11. Работа с памятью: memory
12. Работа с памятью: calldata
13. Работа с памятью: stack

Неделя 4

14. Опкоды
15. Yul и assembly
16. Побитовые операции
17. Дебаггинг контрактов

В этом модуле будут уже более серьезные темы, но в простом изложении и с понятными примерами.

Напоминаю, что 4 модуль это продолжение курса для начинающих разработчиков, поэтому мы касаемся тем только связанных с Solidity, исключая материал про Hardhat с javascript / typescript, и фокусируясь исключительно на практических знаниях.

Кроме того, к написанию уроков и поддержке учеников подключится новый преподаватель! Но об этом в следующем посте!

Ориентировочный запуск модуля будет в конце января. Не пропустите!

#курс
🔥11👍51🥴1
Новости модуля 4

Вчера я упоминал, что этот модуль я буду писать вместе с другим преподавателем. И это @elawbek!

Вот что он пишет о своем пути:

"Разработчик смарт-контрактов для EVM сетей с опытом работы около 1.5 лет.

С 2021 года активно изучаю Solidity и глубоко интересуюсь внутренним устройством Ethereum Virtual Machine (EVM).

Стремление понять, как контракты попадают в сеть, как устроен вызов контракта и какие действия происходят на более низком уровне, побудило меня систематически исследовать данную тематику.

Я сосредотачивался на поиске материалов, раскрывающих внутреннее устройство EVM, чтобы более глубоко понять принципы работы кода в различных сценариях.

Понимаю, что low-level аспекты Ethereum Virtual Machine несравненны с другими языками программирования, так как EVM была разработана с учетом ограниченной области применения в блокчейне. Тем не менее, с развитием технологий и инфраструктуры уверен, что мои знания и опыт, накопленные до настоящего времени, будут востребованы в будущем.

Готов поделиться своими знаниями на курсе и внести свой вклад в обучение других участников!
"

Вы могли часто видеть, как он помогает участникам нашего чата и других тематических по web3 с ответами на вопросы по тому, как работают опкоды / memory / storage, что делает assembly в коде или почему EVM работает так, как она работает. К нему всегда можно было обратиться за советом!

На 4 модуле он будет рассказывать вам последние 8 уроков: работа с памятью, assembly / yul, побитовые операции и дебаггинг!

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

Запуск уже совсем скоро!

#курс
🔥13🥴1
Текстовые уроки по аудиту

Хотел еще пару дней назад выложить на канале, да как-то забыл.

В Твиттере достаточно много хороших отзывов было по урокам по безопасности смарт контрактов и аудиту от Zokyo, еще одной аудиторской компании.

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

https://zokyo-auditing-tutorials.gitbook.io/zokyo-tutorials/

Хорошо то, что команда потихоньку развивает свой проект и будут выходить новые уроки со временем.

#zokyo #audit
👍8
Пока идет какой-то не реальный загруз, выложу этот скрин, который описывает дейтствия функции call(). Нашел когда-то в Твиттере, сохранил, а тут просматривал заметки и решил, что можно выложить и на своем канале.

Кстати, продолжается работа над 4 модулем курса. Хочется сделать его не похожим на обучающие программы других школ. Дать не только навыки по заявленным темам, но научить искать правильные паттерны, строить архитектуру и избегать популярных проблем / уязвимостей. На днях расскажу чуточку больше!

#call
8
Еще про 4 модуль курса

На 4 модуле поднимаются достаточно сложные темы даже для тех, кто продолжает свое обучение в Solidity.

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

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

Про assembly я вообще молчу. Знаю, что многие просто пропускают эти участки кода на ревью, потому что просто не понимают, как это работает!

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

На предыдущем модуле было в уроках часто были примеры из реальных протоколов, где ученики могли увидеть, как та или иная тема реализована в "боевых" контрактах. Многие оценили этот подход, сказав, что это было крайне полезно.

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

В целом это будет так, мы проходим тему, делаем упражнения, изучаем протоколы, а в конце - проводит аудит реального проекта, где описываем возможные проблемы и, что самое главное, влияние этих проблем на сам контракт!

Это будет достаточно сложный модуль, после которого вы получите твердые знания и умения обращаться с кодом и видеть в нем несоответствия!

Запуск уже скоро!

#курс
🔥12🤯1
Что нужно знать перед 4 модулем

Вчера в личку была пара вопросов на тему, а что нужно знать, чтобы было комфортно учиться на 4 модуле. Вопрос достаточно актуальный для тех, кто впервые хочет зайти на курс и не был ни на одном из предыдущих модулей.

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

1. Знание базового синтаксиса языка;
2. Умение писать простые смарт контракты;
3. Умение работать с библиотеками и наследованиями;
4. Знать популярные стандарты: ERC20, ERC721;
5. Базовые знания Hardhat / Foundry (уметь подготовить проект);
6. Понимать популярные паттерны, типа голландского аукциона, DAO, ролевую системы;
7. Уметь работать с не популярными стандартами, например, ERC4626;
8. Уметь работать с Ремикс и одном из редакторов кода, например, VS Code;

Это тот необходимый минимум, чтобы продолжить обучение на 4 модуле.

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

Запуск уже скоро!

#курс
5
Хочу узнать, сколько человек планирует пойти на 4 модуль?
Anonymous Poll
48%
Я точно иду!
52%
Пропускаю в этот раз
4 модуль и результат опроса

Интересная статистика опроса получилась в этот раз: 32 - за, 35 - пропускают (на момент написания поста). Полагаю, это из-за того, что 4 модуль проводится с достаточно большим перерывом и многие участники уже успели пройти эти темы самостоятельно. Если у кого-то не так, буду рад узнать в комментариях.

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

Я также хочу узнать, какие темы для модулей или канала вам было бы интересно изучить? За полтора года ведения канала я написал кучу постов на самые разные темы Solidity и аудита. Может я что-то пропустил?

#курс
👍5
Сложные темы 4 модуля

Уже достаточно долгое время мы пишем 4 модуль курса, стараясь сделать его более простым и понятным для учеников. Огромное количество уязвимостей постоянно находится на конкурсных аудитах по каждой из этих тем. Если зайти на проект Solodit (тот, который собирает отчеты с аудитов) и поискать сколько багов было найдено, то мы увидим, что:

- 594 проблемы в контрактах с подписями,
- 513 репортов по теме прокси,
- 160 не правильно использовали assembly,
- 37 ошиблись с Merkle tree,


И это количество постоянно растет! После последних трех конкурсов на code4rena, с уверенностью могу сказать, что прибавятся еще репорты связанные с неправильной работой с EIP-712!

Нашей задачей на 4 модуль будет научить вас не только, как правильно работать с этими темами, но и дать практические навыки по поиску уязвимостей, чтобы вы могли просматривать свой проект после его завершения и делать его еще более безопасным.

В итоге, у нас будет 17 уроков и 3 мини аудита реальных протокола, как финальный практикум! 2 преподавателей будут отвечать на ваши вопросы по темам уроков.

В этот раз стоимость чуть выше: 5000 рублей или 60 USDT.

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

А так, сможем начать уже совсем скоро!

#курс
13🔥2🌭1
Assembly, yul и opcodes на 4 модуле

Я встречал на многих курсах и обучениях, что эти темы дают чуть ли не в начале всего. Типа: "Посмотрите, как работает EVM, что использует и это все может быть в контракте". Я был слегка не согласен с этим и на своем курсе решил подождать до 4 модуля с этими темами, когда ученики уже освоят обычный Solidity, получат навыки написания контрактов и будут готовы воспринимать более сложную информацию.

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

Именно по этой причине на 4 модуле будет второй преподаватель @elawbek, который прекрасно понимает все детали работы storage, memory, calldata, opcodes и может с нуля писать сложные функции.

Например, в одной из библиотек, что он лично писал, есть такая функция:


function pow(uint256 a, uint256 b) pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
switch b
case 0x00 {
result := 0x01
}
case 0x01 {
result := a
}
default {
switch a
case 0x00 {
// do nothing, result already zero
}
case 0x01 {
result := 0x01
}
case 0x02 {
if gt(b, 0xff) {
mstore(0x00, 0x35278d12)
revert(0x1c, 0x04)
}
result := shl(b, 0x01)
}
default {
switch or(
and(lt(a, 0x0b), lt(b, 0x4e)),
and(lt(a, 0x133), lt(b, 0x20))
)
case 0x01 {
result := exp(a, b)
}
default {
let maxUint256 := not(0x00)
let helper := 0x01

for {
let one := helper
} one {

} {
if gt(a, div(maxUint256, a)) {
mstore(0x00, 0x35278d12)
revert(0x1c, 0x04)
}

switch and(b, one)
case 0x00 {
b := shr(one, b)
}
case 0x01 {
helper := mul(a, helper)
b := shr(one, b)
}

a := mul(a, a)

if gt(b, one) {
continue
}

break
}

if gt(helper, div(maxUint256, a)) {
mstore(0x00, 0x35278d12)
revert(0x1c, 0x04)
}

result := mul(helper, a)
}
}
}
}
}


Она вызовет "взрыв мозга" даже у бывалого разработчика.

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

Это будет еще один крутой месяц обучения!

До старта продаж уже совсем немного времени!

#курс
11🤯1
4-5 модули, перезапуск и планы

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

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

Вы можете дальше изучать язык JavaScript, для получения профессии фронтенд разработчика, где вам потребуется изучить TypeScript, Hardhat, ethers.js, web.js и другие библиотеки для "связывания" контрактов с обычным сайтом.

Либо начать изучать Foundry, чтобы писать продвинутые тесты.

Да, я также говорил и о 5 модуле курса, где разбирались бы темы DeFi протоколов, их версий и интеграций, а также работа с оракулами, сложные паттерны и EIP стандарты, как например account abstraction. Но это уже скорее всего будет осенью, когда пройдет еще один поток курса. Кстати, о нем пару слов...

Весной я планирую перезапустить обучение с нуля с 1 модуля. Я добавлю материал в программу, сделаю его еще более понятным (основываясь на вопросах и затруднениях первых учеников) и, скорее всего, еще более практическим.

На канале же дальше будут идти общетематические посты про Solidity, тестирование и все новое, что появляется в сети.

Приятного дня и позитивного обучения!

#курс
🔥9👍4
Первые ученики уже на канале!

Если вы только пришли с работы или учебы, то пост для вас! Сегодня старт продаж 4 модуля нашего курса!

Если вы уже работали с темами прокси контрактов и подписями в Solidity, то сейчас у вас есть хорошая возможность еще лучше разобраться с работой storage, memory и calldata, а также понять как работают опкоды и assembly.

В ру чатах и каналах мало кто может дать дельный совет по работе с низкоуровневым языком, а на курсе у вас будет возможность задать свой вопрос напрямую и получить ответ от преподавателя, который написал не один контракт с assembly!


Продажи открыты только до конца недели! Успейте занять свое место!



Программа и условия оплаты в посте выше.

Старт 5 февраля!

#курс
👍3
Использование структур, маппингов и событий с библиотеками

Неделя продаж завершена и канал возвращается к своему привычному ритму.

Недавно мое внимание привлек контракт Uniswap V3, где были использованы библиотеки для работы со структурами и и маппингами. Я не так часто встречал этот способ и решил рассказать о нем на канале.


Структуры в библиотеках

Посмотрите на код:

 Solidity

library CounterLib {
struct Counter { uint i; }

function incremented(Counter storage self) internal returns (uint) {
return ++self.i;
}
}

contract CounterContract {
using CounterLib for CounterLib.Counter;

CounterLib.Counter public counter;

function increment() public returns (uint) {
return counter.incremented();
}
}


При том, что у библиотек не может быть собственного хранилища (storage), они могут работать и изменять память контракта, к которому подключены. В данном примере в бибилотеке мы создали структуру данных и функцию, которая инкрементирует значение. Обратите внимание на self, который в данном случае будет помогать обновлять память контракта.

Далее в самом контракте мы создаем переменную counter и подключаем библиотеку к структуре.


Порождение событий

Порождение событий также сопряжено с изменением памяти контракта и записи логов. Но библиотеки и тут можно использовать:

 Solidity

library EventEmitterLib {
function emitEvent(string memory s) internal{
emit Emit(s);
}

event Emit(string s);
}

contract EventEmitterContract {
using EventEmitterLib for string;

function emitEvent(string memory s) public {
s.emitEvent();
}

}


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


Структура библиотеки в маппинге

Еще один не самый популярный способ:

 Solidity

library Library {
struct data {
uint val;
bool isValue;
}
}

contract Array{

using Library for Library.data;
mapping(address => Library.data) clusterContract;

function addCluster(address id) public view returns(bool){
if(clusterContract[id].isValue) revert();
return true;
}

}


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


Использование библиотеки для маппинга

С простым примером для этого способа были некоторые трудности, поэтому покажу на примере контракта Uniswap.

 Solidity

library TickBitmap {
...
function flipTick(
mapping(int16 => uint256) storage self,
int24 tick,
int24 tickSpacing
) internal {
unchecked {
require(tick % tickSpacing == 0); // ensure that the tick is spaced
(int16 wordPos, uint8 bitPos) = position(tick / tickSpacing);
uint256 mask = 1 << bitPos;
self[wordPos] ^= mask;
}
}
...

}

contract UniswapV3Pool is IUniswapV3Pool, NoDelegateCall {


using TickBitmap for mapping(int16 => uint256);

mapping(int16 => uint256) public override tickBitmap;

function _updatePosition(
...
) private returns (Position.Info storage position) {
...
if (flippedLower) {
tickBitmap.flipTick(tickLower, tickSpacing);
}
if (flippedUpper) {
tickBitmap.flipTick(tickUpper, tickSpacing);
}
...
}
}


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

Тут мы используем библиотеку для определенного вида маппинга с нужными размерностями ключа и значений. Далее в контракте в функции мы вызываем функцию flipTick по переменной маппинга tickBitmap и передаем в библиотеку сам маппинг и две аргумента.
1
Как я понял такие способы работы с библиотеками позволяют также сократить размер самого контракта, а также разделить служебные функции от логики остальных.

Интересная реализация, не так ли?

#library #mapping #struct
👍3
Простые инвариант тесты с Foundry

Мы уже разбирали как писать инвариант тесты в цикле постов про Foundry, где разбирали пример с WETH контрактом.

Я нашел еще один прекрасный пример урока от RareSkills по этой теме.

В нем разбираются как просты примеры, так и с Handlers / Actors, показываются примеры контрактов, команды forge и многое чего другого!

Если хотите сами еще раз разобраться, что такое инварианты, то эта статья как раз для вас. В целом на практическое изучение урока может уйти 2-3 часа! Но это того стоит!

Урок от RareSkills - https://www.rareskills.io/post/invariant-testing-solidity

Приятного обучения! Вопросы по Foundry вы можете смело задавать в чате.

#foundry #invariant
🔥4
Разбор Uniswap V2: swap(). Часть 1

Я все еще не могу подступиться к математике в DeFi, поэтому решил маленькими шажками изучать код контрактов и работу протоколов в целом. В RareSkills есть несколько прекрасных статей по темам Uniswap, Compound, Aave и других, которые можно читать и публиковать на канале. По сути, это будут короткие переводы.

И начнем мы сегодня с функции swap в контракте Uniswap V2. Именно она как раз на скрине.

1. Обратите внимание на область, помеченную желтым блоком. Именно тут токены после обмена пересылаются адресату. Примечательно то, что тут вообще нет вызовов для получения токенов от адресата для обмена! Это делается на другом уровне.

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

3. В самом начале функции в комментариях обозначено, что вызов swap() должен идти из другого контракта, где необходимо выполнять все проверки безопасности (красное подчеркивание на скрине).

4. Переменные _reserve0 и _reserve1 (синее подчеркивание) получаются на строке 161, и читаются по ходу функции, но их обновление происходит в другой служебной функции.

5. На 182 строке нет строгой проверки на равенство Константы (X x Y = K), здеь она выполнена по условию >=.

6. Балансы токенов (в переменных balance0 и balance1) читаются напрямую из контракта токенов по balanceOf().

7. Код на линии 172 исполняется только когда передаются данные при вызове.

Эти пункты помогут нам при дальнейшем разборе функции swap().

#swap #uniswap #v2
👍5👌2