Solidity. Смарт контракты и аудит – Telegram
Solidity. Смарт контракты и аудит
2.62K subscribers
246 photos
7 videos
18 files
547 links
Обучение Solidity. Уроки, аудит, разбор кода и популярных сервисов
Download Telegram
Вредоносные плагины в VScode

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

#vscode
😱12
Самые популярные типы DAO. Часть 1

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

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

Первая децентрализованная автономная организация

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

Первая децентрализованная автономная организация, получившая название «The DAO», была построена на основе смарт-контрактов, использовала фреймворк с открытым исходным кодом и была ориентирована на венчурный капитализм.

К сожалению, из-за ошибки в смарт-контракте The DAO потеряла 3,6 миллиона ETH и не смогла восстановиться в финансовом плане. Тем не менее, The DAO проложила путь для многих других успешных DAO.

Лето DeFi в 2018 году принесло на блокчейн Ethereum флагманские проекты децентрализованных финансов, такие как Compound Finance (COMP), Uniswap (UNI) и Aave (AAVE), которые предлагали участникам сообщества привлекательные способы продемонстрировать свою приверженность децентрализации с помощью токенов управления DAO.

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

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

Можно выделить следующий типы DAO:

1. Protocol DAOs
2. Grant DAOs
3. Philanthropy DAOs
4. Social DAOs
5. Collector DAOs
6. Venture DAOs
7. Media DAOs
8. SubDAOs

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

Protocol DAOs

Протокольный DAO - это тип DAO, который предназначен для управления децентрализованным протоколом, таким как приложение для займов/кредитования, децентрализованная биржа или другой тип dapp.

Примеры протокольных DAO

Три наиболее заметных примера протокольных DAO - MakerDAO, Uniswap и Yearn Finance.

MakerDAO

Одно из приложений DeFi в сети Ethereum, MakerDAO использует смарт-контракты, чтобы позволить пользователям кредитовать и занимать криптовалюты с индивидуальными ставками кредитования и суммами погашения.

MakerDAO использует токены управления MKR, чтобы держатели могли голосовать за изменения в протоколе Maker, включая сумму обеспечения для залоговых долговых позиций (CDP), ежегодные займы и прекращение работы в случае краха Ethereum.

Держатели MKR также выступают в качестве покупателей последней инстанции для займов DAI (алгоритмический стейблкоин, созданный MakerDAO). Если стоимость ETH в хранилищах Maker Vaults не покрывает количество DAI в обращении, MKR создается и продается на долговом аукционе, чтобы привлечь необходимое количество средств.

Uniswap

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

Если держатели токенов хотят изменить Uniswap или ввести новые функции, для дальнейшего обсуждения необходимо подать предложение, набрав не менее 25 000 голосов «за» UNI.

Yearn Finance
👍3
Как и вышеупомянутые DAO с токенами управления, Yearn DAO делегирует финансирование DAO Vaults. Держатели YFI могут предоставлять средства DAO, одобренным для приема финансирования в экосистеме хранилищ DAO. Восполняя пробел в традиционной системе управления персоналом и начисления заработной платы, основатель YFI Андре Кронье создал Coordinape для автономного распределения средств и вознаграждения вкладчиков.

Далее поговорим про остальные виды.

#dao
👍3
Самые популярные типы DAO. Часть 2

Продолжаем разбирать разные форматы DAO.

Грантовые DAO

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

Примеры грантовых DAO

Aave Grants DAO - это программа под руководством сообщества, направленная на финансирование идей и проектов, способствующих развитию протокола Aave, с упором на поддержку более широкой сети разработчиков сообщества.

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

Одним из примеров грантовой DAO, которая является отдельной организацией, является MetaCartel, которая предоставляет финансирование проектам и оказывает операционную поддержку dapp на ранних стадиях.

Задавшись целью ускорить создание Web3, MetaCartel выделяет гранты от 1 000 до 10 000 долларов на dApp, построенные на Ethereum, новые эксперименты с потребительскими кейсами, создание новых DAO, инициативы, ориентированные на сообщество, и многое другое.

Филантропические DAO

Филантропические DAO стремятся содействовать развитию социальной ответственности, организуясь вокруг общей цели для создания влияния в мире Web3.

Примеры филантропических DAO

Первая некоммерческая филантропическая DAO, Big Green DAO, связана с Big Green, национальной благотворительной организацией 501(c3), занимающейся вопросами продовольственной справедливости, которая учит людей выращивать продукты для повышения безопасности питания, улучшения психического здоровья и воздействия на климат. Big Green DAO присоединилась к благотворительной организации с десятилетней историей, чтобы реструктурировать процесс предоставления грантов и привести некоммерческую организацию в выгодное финансовое положение.

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

Социальные DAO

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

Хотя социальные DAO ориентированы на сообщество, обычно они имеют барьер для входа, например, владение определенным количеством токенов, владение NFT или личное приглашение.

Примеры DAO создателей

Developer DAO - это коллектив разработчиков web3, нацеленный на создание будущего web3. Чтобы присоединиться к Developer DAO, участники должны обладать NFT Genesis или быть одним из счастливчиков, приглашенных на частный сервер Discord.

Friends With Benefits - это DAO создателей web3, ориентированная на создание сообщества и развитие творчества. Вход в Friends With Benefits стоит 75 токенов FWB, и после приема участники получают полный доступ к общению со строителями, художниками, креативщиками и посещению эксклюзивных мероприятий.

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

И в понедельник узнаем о еще четырех видах популярных DAO.

#dao
👍2🤔1
Самые популярные типы DAO. Часть 3

С легкого поста мы начинаем неделю и заканчиваем рассказ про DAO, остались последние 4 вида.

Коллекционные DAO

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

Примеры коллекционных DAO

Такие известные DAO, как FlamingoDAO, возникли после бума NFT и собирали невероятно дорогие NFT от таких цифровых художников, как Pak, Hackatao, XCopy, а также CryptoPunk #2890 NFT, который был куплен в 2021 году за $760 тысяч долларов США.

Другая группа коллекционеров сформировала ConstitutionDAO в попытке купить Конституцию Соединенных Штатов. Примечательно, что ConstitutionDAO за одну неделю собрала ETH на сумму 47 миллионов долларов, чтобы попытаться купить копию Конституции США первого издания на аукционе Sotheby's.

Хотя не каждое коллекционное DAO окупится, это новая возможность для инвесторов получить финансовую поддержку в дорогих NFT, не рискуя большими суммами личного капитала.

Инвестиционные и венчурные DAO


Венчурные DAO объединяют капитал для инвестирования в стартапы ранней стадии web3, протоколы, offchain инвестиции и получают доступ к портфелям, недоступным в традиционном финансировании.

Примеры венчурных DAO

Krause House DAO - это венчурная DAO, которая пытается купить профессиональную команду NBA, состоящую из инвесторов и фанатиков баскетбола. Члены Krause House DAO будут участвовать в принятии решений, влияющих на операционные процедуры команды Национальной баскетбольной ассоциации, включая, помимо прочего, общее управление, продажу билетов, мерчендайзинг и партнерские отношения.

Среди других известных венчурных DAO можно отметить MetaCartel Ventures (MCV), которая является коммерческой DAO, созданной сообществом MetaCartel для инвестирования в децентрализованные приложения (DApps) на ранних стадиях, и BessemerDAO, которая была запущена венчурной фирмой Bessemer Venture Partners из Сан-Франциско для обсуждения тенденций в криптоиндустрии и обмена ресурсами.

Медиа DAO

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

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

Примеры медиа DAO

BanklessDAO - это децентрализованное сообщество для координации и распространения безбанковских СМИ, культуры и образования. Его цель - способствовать внедрению действительно безбанковской денежной системы.

Decrypt - еще один пример медиа DAO, который позволяет пользователям голосовать за то, какой контент они хотят видеть.

Медиа DAO особенно эффективны для новых сообществ, которые хотят вознаградить своих пользователей по мере развития криптосообщества и культуры Web 3.0.

SubDAO

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

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

В результате единогласного голосования Balancer DAO успешно интегрировал subDAO в свою структуру и теперь может двигаться более эффективно как децентрализованная автономная организация.

Креативность сообщества - это действительно предел того, что можно создать в рамках DAO.

Возможно, один из этих DAO натолкнет вас на новую идею своего проекта и позволить помочь развитию web3!

#dao
👍21
Безопасная крипта

Мне снова требуется помощь сообщества.

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

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

Задача стоит в том, чтобы рассказать базу про блокчейн, кошельки и крипту. В частности только про стейблкоины USDT/USDC, так как именно их лучше всего принимать в оплату.

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

Например, я хочу рассказать, что при покупке криптовалюты на сетях нужно быть аккуратным так как:

1. Токены с такими же инициалами и названием легко создать в любой сети и обмануть пользователя;
2. Не на каждой сети может быть нужный токен;
3. Существуют обертки токенов (eBTC, WETH);
4. Нужно минимум два токена на кошельке (один дл оплаты комиссии и один требуемый);
5. Как проверить адрес токена;

Или также про владение кошельком:

1. Нельзя покупать уже готовый кошелек;
2. Нужно хранить секретную фразу от всех;
3. Нельзя заходить в чужие кошельки, если где-то встретили сид-фразу;

И все в этом роде про базовую безопасность работы с криптовалютой.

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

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

#safecrypto
🔥4🤔2👍1
Обновляемые контракты (Transparent proxy). Часть 1

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

Transparent Upgradeable Proxy (далее TUP) - это паттерн для обновления прокси контрактов, исключающий возможность столкновения селекторов функций.

Хороший прокси контракт должен обладать как минимум двумя следующими характеристиками:

- слотом для хранения адреса контракта Логики;
- механизмом, позволяющим администратору изменять адрес Логики;

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

Столкновение селекторов функций (Function Selector Clashing)

Объявление публичных функций внутри прокси для обновления адреса Логики влечет за собой возможность столкновения селекторов функций.

Вот простой пример:

contract ProxyUnsafe {

function changeImplementation(
address newImplementation
) public {
// some code...
}

fallback(bytes calldata data) external payable (bytes memory) {
(bool ok, bytes memory data) = getImplementation().delegatecall(data);
require(ok, "delegatecall failed");
return data;
}
}

contract Implementation {
// an identical function is declared here -- they will clash
function changeImplementation(
address newImplementation
) public {

}
//...
}


Помните, что fallback всегда проверяется в последнюю очередь?

Перед вызовом fallback контракт прокси проверит, совпадает ли 4-байтовый селектор функции с changeImplementation (или любой другой публичной функцией в прокси).

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

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

2. Если в контракте Логики есть функция с тем же селектором функций, что и публичная функция в прокси, она также будет невызываемой по той же причине. Этот сценарий представляет собой столкновение селекторов функций. Вероятность того, что у двух разных функций будет одинаковый селектор, равна 1 к 4,29 миллиарда; селектор функции состоит из 4 байт, поэтому существует 4,29 миллиарда возможностей. Это небольшая вероятность, но не нулевая. Например, у clash550254402() тот же селектор функции, что и у proxyAdmin().

А далее мы поговорим, как TUP помогает решить эту проблему.

#proxy #transparent
1👍4🔥3👏1
Обновляемые контракты (Transparent proxy). Часть 2

Transparent Upgradeable Proxy - это паттерн, полностью исключающий возможность столкновения селекторов функций.

В частности, TUP предписывает, что в прокси контракте не должно быть никаких публичных функций, кроме fallback.

Но если есть только функция fallback, как нам вызвать функцию для обновления прокси?

Ответ заключается в том, чтобы определить, является ли отправитель msg.sender администратором.

contract Proxy is ERC1967 {
address immutable admin;

constructor(address admin_) {
admin = admin_
}

fallback() external payable {
if (msg.sender == admin) {
// upgrade logic
} else {
// delegatecall to implementation
}
}
}



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

Изменение неизменяемого администратора

В приведенном выше фрагменте кода администратор является неизменяемым. Это означает, что контракт технически не соответствует стандарту ERC-1967, который гласит, что администратор должен храниться в слоте хранения 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 или bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1).

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

Наличие адреса в этом слоте будет сигнализировать другим программам, что контракт является прокси (одна из целей ERC-1967). Однако чтение из хранилища при каждом обращении к прокси добавляет к вызову еще 2100 газа. Поэтому желательно использовать неизменяемую переменную.

«Смена» администратора

Однако все же желательно иметь возможность обновлять адрес администратора - но изначально это кажется невозможным.

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

Во-вторых, владелец ProxyAdmin является «истинным» администратором. ProxyAdmin просто направляет вызовы от владельца к прокси. «Истинный» администратор вызывает ProxyAdmin, а ProxyAdmin вызывает Transparent Proxy. Изменив владельца ProxyAdmin, мы можем изменить, кто имеет возможность обновлять Transparent Proxy.

Далее поговорим об этом интересном контракте.

#proxy #transparent
1👍4
Обновляемые контракты (Transparent proxy). Часть 3

AdminProxy

Ниже приведен код из OpenZeppelin AdminProxy. Обратите внимание, что есть только одна функция upgradeAndCall(), которая может вызывать upgradeToAndCall() только на прокси.

pragma solidity ^0.8.20;

import {ITransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol";
import {Ownable} from "../../access/Ownable.sol";

contract ProxyAdmin is Ownable {
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";

constructor(address initialOwner) Ownable(initialOwner) {}

function upgradeAndCall(
ITransparentUpgradeableProxy proxy,
address implementation,
bytes memory data
) public payable virtual onlyOwner {
proxy.upgradeToAndCall{value: msg.value}(implementation, data);
}
}


Существует распространенное заблуждение, что администратор Transparent proxy не может использовать контракт, потому что его вызовы переадресуются на upgrade. Однако владелец AdminProxy может использовать Proxy без проблем, как показано на диаграмме на скрине.

На самом деле, существует механизм, позволяющий администратору ProxyAdmin сделать произвольный вызов прокси, как следует из названия функции upgradeToAndCall().

Сделать прокси non-upgradeable?

Если владелец будет изменен на нулевой адрес или другой смарт-контракт, который не сможет правильно использовать функцию upgradeAndCall() (или изменить владельца), то Transparent proxy больше не будет обновляемым. Это может произойти, например, если владельцем AdminProxy будет установлен другой контракт AdminProxy.

TUP от OpenZeppelin реализует стандарт с помощью трех контрактов:

1. Proxy.sol
2. ERC1967Proxy.sol (наследует Proxy.sol)
3. TransparentUgradeableProxy.sol (наследует ERC1967Proxy.sol)

Базовым контрактом является Proxy.sol. Получив адрес реализации, он отправляет delegate call в Логику. Функция _implementation() не реализована в Proxy - она переопределена и реализована его дочерним ERC1967Proxy, что позволяет ему вернуть соответствующий слот хранения.

ERC1967Proxy.sol наследует от Proxy.sol. Он добавляет (и переопределяет) внутреннюю функцию _implementation(), которая возвращает адрес реализации, хранящийся в слоте, указанном ERC-1967. Однако Transparent proxy не будет использовать эту функцию - вместо этого он использует свою собственную неизменяемую переменную.

А о самом TransparentUpgradeableProxy.sol мы поговорим в следующий раз.

#proxy #transparent
1👍5
Обновляемые контракты (Transparent proxy). Часть 4

TransparentUpgradeableProxy.sol наследует от ERC1967Proxy.sol. В конструкторе этого контракта разворачивается ProxyAdmin и устанавливается как адрес неизменяемого admin (первая переменная в контракте).

contract TransparentUpgradeableProxy is ERC1967Proxy {
address private immutable _admin;

error ProxyDeniedAdminAccess();

constructor(address _logic, address initialOwner, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
_admin = address(new ProxyAdmin(initialOwner));
// Set the storage value and emit an event for ERC-1967 compatibility
ERC1967Utils.changeAdmin(_proxyAdmin());
}

function _proxyAdmin() internal view virtual returns (address) {
return _admin;
}

function _fallback() internal virtual override {
if (msg.sender == _proxyAdmin()) {
if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
revert ProxyDeniedAdminAccess();
} else {
_dispatchUpgradeToAndCall();
}
} else {
super._fallback();
}
}

function _dispatchUpgradeToAndCall() private {
(address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
ERC1967Utils.upgradeToAndCall(newImplementation, data);
}
}


Рассмотрим случай, когда отправителем msg.sender является _proxyAdmin. В этом случае вызов направляется в _dispatchUpgradeToAndCall(), но _fallback() сначала проверяет, что предоставленный селектор функций является селектором функций для upgradeToAndCall.

«Селектор» здесь не является "настоящим" селектором, поскольку Transparent Upgradeable Proxy не имеет публичных функций. Однако, чтобы позволить ProxyAdmin сделать вызов интерфейса (вызов высокого уровня), он должен принять от ProxyAdmin кодированные ABI calldata для upgradeToAndCall().

Напомн, что ProxyAdmin делает интерфейсный вызов upgradeToAndCall в прокси, хотя у прокси нет публичных функций, кроме fallback (код ProxyAdmin показан далее):

contract ProxyAdmin is Ownable {
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
constructor(address initialOwner) Ownable(initialOwner) {}

function upgradeAndCall(
ITransparentUpgradeableProxy proxy,
address implementation,
bytes memory data
) public payable virtual onlyOwner {
@> proxy.upgradeToAndCall{value: msg.value}(implementation, data);
}
}


Выше представлено видео, демонстрирующее все три блока кода рядом друг с другом и то, как различные контракты в цепочке наследования (Proxy, ERC1967Proxy и TransparentUpgradeableProxy) взаимодействуют друг с другом.

В следующем посте поговорим о том, почему функция называется upgradeToAndCall(), а не просто upgradeTo().

#proxy #transparent
👍6
Что по аудитам?

Прервусь на день с темой обновляемых контрактов, чтобы рассказать снова про конкурсные аудиты. Если помните, то в конце ноября прошлого года я решил заново научиться проводить аудит протокола. Моей основной идеей тогда было научиться понимать протокол за максимально короткое время, так как я не могу уделять больше 2-3 часов в день на такую работу.

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

До большого отпуска я успел поучаствовать в 4,5 конкурсных аудитах. В общей сложности они принесли мне всего ~ $960. Точнее, их мне принесли всего два аудита и 2 High / 1 Med / 3 Low из двух конкурсов. В Sablier - отличная кодовая база была и он был первый, в котором я решил поучаствовать с заметками. Итог - 0 находок. Другой был на Шерлоке - это отдельная история, вскоре сделаю пост на тему конкурсов там. И еще один, тот 0,5 аудит - смотрел в поезде в течение часа. Нашел только один Med, который нашли еще 90% участников конкурса, поэтому выплат не было.

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

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

Пока что, получилось принять участие в 4 конкурсах и отправить 20 репортов: 7-6-6-1. Обычно же отправлял 3-4 репорта на конкурс.

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

Насколько все сработает буду уже судить по результатам конкурса.

В идеале ставлю себе цель, чтобы как минимум 75% от репортов были валидными High/Med. На данный момент, это около +-30%.

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

#audit
🔥13
Обновляемые контракты (Transparent proxy). Часть 5

Почему функция называется upgradeToAndCall(), а не просто upgradeTo()?

При обновлении контракта Логики можно сделать вызов, как если бы ProxyAdmin был msg.sender и транзакция делегировала вызов в Логику, как если бы это было обычное взаимодействие с прокси. Конечно, внутри fallback() этого не произойдет, потому что вызовы ProxyAdmin направляются в логику обновления.

Приведенный ниже код взят из ERC1967Utils.sol, с которым TransparentUpgradeableProxy компонуется для обеспечения возможности обновления слота Логики. Библиотека предоставляет внутреннюю вспомогательную функцию для обновления слота, содержащего адрес Логики.

/** 
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/

function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit IERC1967.Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}


Он будет выполнять delegatecall в контракт Логики только в том случае, если data.length > 0.

upgradeToAndCall() также выполняет delegatecall от прокси к Логике в той же транзакции, что и обновление. Это то же самое, как если бы ProxyAdmin вызвал прокси, используя любые calldata, указанные в data, а затем прокси сделал бы delegatecall в самой Логике.

Таким образом, ProxyAdmin может делать произвольные вызовы прокси.

Обратите внимание, что upgradeToAndCall не требует, чтобы обновленный контракт был другой реализацией - можно «обновиться» до той же самой Логики.

Из этого следует, что контракт ProxyAdmin может делать произвольные delegatecall в контракт Логики через прокси - но отправителем msg.sender с точки зрения Transparent Proxy является ProxyAdmin.

Единственное ограничение, которое накладывает ProxyAdmin на обновление, заключается в том, что он не может обновить пустой контракт (адрес без байткода). Функция _setImplementation проверяет, что длина кода новой реализации больше нуля.

/**
* @dev Stores a new address in the ERC-1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}


Подведем итоги:

1. Transparent Upgradeable Proxy - это шаблон проектирования для предотвращения столкновения селекторов функций между прокси и Логикой;

2. Функция fallback является единственной публичной функцией в Transparent Upgradeable Proxy;

3. Функциональность обновления может быть вызвана только администратором через функцию fallback. Все вызовы с неадминистративных адресов превращаются в delegatecalls в прокси;

4. Transparent Upgradeable Proxy использует неизменяемую переменную для хранения адреса администратора, чтобы сэкономить газ. Для того, чтобы соответствовать ERC-1967, он хранит адрес администратора в слоте admin, указанном в ERC-1967, даже если он никогда не читает из этого слота;

5. Поскольку администратор не может быть изменен, он устанавливается в смарт-контракт под названием AdminProxy. AdminProxy раскрывает единственную функцию upgradeAndCall(), которая может быть вызвана только владельцем AdminProxy. Владелец AdminProxy может быть изменен.

#proxy #transparent
👍5
Интенсив по Foundry с нуля

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

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

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

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

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

У нас также будет открыт чат для вопрсов-ответов. Материалы с интенсива останутся у вас навсегда, каналы с модулями не удаляются. В любой момент вы сможете вернуться к источнику и пройти урок заново.

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

Сейчас хотел бы узнать, кто планирует пойти на модуль? Прошу пройти опрос ниже.

#foundry
🔥10
Планируете пойти на интенсив?
Final Results
44%
Точно да!
31%
Еще думаю
25%
Не в этот раз
Найти работу или получать заказы?

Пока идет голосование по интенсиву Foundry (приятно, что все же больше людей хотят попасть на модуль), хочу поднять с вами не очень популярную тему среди людей, и еще менее популярную среди разработчиков. А именно тему личного бренда и проявленности в соцсетях.

Буквально вчера я спорил с разработчиком Rust/Solidity, который утверждал, что если ты крутой разработчик, то с легкость найдешь хорошо оплачиваемую работу и иметь присутствие в сети вовсе не обязательно, ну, понятное дело, за исключением профиля на LinkedIn и GitHub.

P.S. По GitHub помню, что обещал сделать пост по оформлению, но пока не могу накопать достаточно инфы по тому, как рекрутеры отбирают профили, на что смотрят и где поискать примеры вдохновения. Но однажды напишу хороший гайд.

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

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

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

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

Количество подписчиков вообще не играет роли. Нужно только чтобы потенциальный заказчик или рекрутер нашел ваш профиль и изучил его.

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

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

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

Да, это заняло у меня более двух лет. Но сейчас я точно могу быть уверен, что не останусь без работы и денег в случае чего.

И это только с текстовых форматов. Если вы сможете все рассказывать в видео/фото формате, то продвинетесь намного скорее.

Что думаете, по этому поводу? Ведете свой канал или планируете начать? Или уверены, что получится найти работу и без этого всего?

#pb
👍22🔥3
Минимальные требования для работы

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

В целом я заметил некую тенденцию, которая меня сильно раздражала в описании вакансий в России и СНГ в целом. Иногда складывалось впечатление, что описания пишутся HR, которые только на Ютубе слышали о существовании web3. Они стараются в требования впихнуть вообще все, что только можно.

Грубо говоря, на позицию мидла ищут разработчика, который знает:
- Python, C+, JS (включая 3-4 популярных фрейма типа TypeScript, Next, React, Vue и т.д.);
- Solidity, Rust, Ton;
- Hardhat, Foundry, Truffle (!!!);
- Имеет степень бакалавра компьютерных наук;

и т.д.

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

И это не мировые компании типа того же Uniswap, Open Zeppelin, Aave и других. О многих из них никто даже не слышал.

Я всегда бы за четкое разделение знаний на позициях. Если у компании нет денег на оплату двух позиций: Фронтенда и Web3 разработчика, то с зп вероятнее всего будут проблемы.

Разработчик смарт контрактов может должен знать язык под задачу (Solidity, Rust), уметь ответить за свою работу (написать тесты и показать, что все работает) и постоянно изучать новое в сфере блокчейна. Ему не нужно знать, как написать лендинг и связать его.

Фронтенд разработчик должен знать свой язык и набор библиотек для связи с блокчейном. Ему нафиг не нужно уметь писать DeFi протоколы!

Это хорошо, когда разработчик знает другой язык и может выполнить некоторые действия (устанавливать плагины на Python, подключать библиотеки, читать конфиги и т.д.), но он вовсе не обязан быть сеньором во всех языках, как требуют того некоторые вакансии.

Я пишу этот пост с обращением ко всем соискателям. Не нужно искать работу в web3, где требуется "мастер на все руки". Многих это может напугать, а другим сбить фокус - и вы начнете изучать все, чтобы соответствовать требованиям.

Для хорошей работы Solidity разработчиком нужно всего три вещи:

1. Отличное знание Solidity и современных паттернов разработки;
2. Навыки тестирования смарт контрактов;
3. Базовые аспекты безопасности кода;

Да, в процессе обучения вы познакомитесь с JS и с Python, но тут не потребуется "навыков работы 3+ лет".

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

#job
👍32🥰43
Media is too big
VIEW IN TELEGRAM
Пробы записи видео и разбор функций

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

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

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

Сейчас пара вопросов:

1. Как вообще видео по формату? Удобно ли смотреть с телефона, не раздражает ли что, все ли четко и по делу?
2. Что надо улучшить (субтитры, крупнее код, подсвечивать код или что-то другое)?

Я только учусь, поэтому любой фидбек будет ценен для меня.

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

#video
11👍4🔥3
Тестирование != тестирование

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

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

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

 constructor(address _aaveV3Pool, address _diva, address _owner) AaveDIVAWrapperCore(_aaveV3Pool, _diva, _owner) {}

constructor(address diva_, address aaveV3Pool_, address owner_) Ownable(owner_) {}


Обратите внимание, что аргументы передаются в не совсем верном порядке: адреса aave и diva перепутаны местами.

Хоть его и засчитали как Medium (по предварительным результатам), мне кажется, что правильнее было бы установить как Low. Контракты сразу после деплоя были бы не рабочими и, вроде как, ни к каким другим последствиям, кроме как ре-деплой, это бы не привело. Но примечательно другое.

Разработчики написали тесты, которые успешно проходили!

В общем, они были написаны правильно: тестировались необходимые функции и ветки, но что-то все же пропустилось... И это случилось у хороших разработчиков.

Разработчикам, которые только начинают писать тесты для своих контрактов, бывает сложно понять саму суть проводимых тестов. Они пишут unit тесты и стараются получить 100% coverage в итоге, не представляя, что тестирование может быть вне рамок кода.

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

Или также дело обстоит с проверками if/else. Тут тесты пишутся не только на два условия, но и для всех состояний, ролей и временных отрезков, которые могут повлиять на эту проверку.

Именно поэтому, на 1000 строк кода контракта мы можем встречать 5000+ строк тестов.

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

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

Пишите правильные тесты!

#testing
🔥11👍3