Паттерн commit/reveal
Для начала давайте расшифруем, что такое commit и reveal для тех, кто только начал свой путь в программировании.
По сути, commit - это добавление какой-либо информации куда-либо. Коммитом можно назвать, когда вы отдаете свой голос за кандидата на сайте (отправляете лайк за него в базу данных портала), или вносите правки в код на GitHub (отправляете обновленный код в файл текущего кода программы). Пример довольно грубый, но должен быть понятен.
А reveal - это раскрытие данных. Как, например, в покере, когда в конце раунда все раскрывают свои карты.
Вот и текущий паттерн позволяет сохранить закодированные данные в блокчейне, чтобы позже можно было раскрыть их. Хотя и это грубое описание, так как в реальности происходит обычное сравнение захешированных данных и если они одинаковы, то система подтверждает их.
Хеширование данных происходит на стороне клиента, в браузере, для большей безопасности и конфиденциальности данных, затем они сохраняются в блокчейне.
Мы же помним, что с помощью keccak256 можно только закодировать данные в формате bytes32, но раскодировать обратно их не получится?
И вот когда мы делаем reveal, мы отправляем еще раз наши закодированные данные в блокчейн, там они сравниваются с теми, что уже хранятся от нашего имени и выдается подтверждение.
Если хоть одна часть, один символ в отсылаемых данных будет изменен, то система выдаст ошибку. Именно поэтому обмануть ее не получится.
Ну вот и весь смысл паттерна commit\reveal. Все довольно просто.
#commit #reveal
Для начала давайте расшифруем, что такое commit и reveal для тех, кто только начал свой путь в программировании.
По сути, commit - это добавление какой-либо информации куда-либо. Коммитом можно назвать, когда вы отдаете свой голос за кандидата на сайте (отправляете лайк за него в базу данных портала), или вносите правки в код на GitHub (отправляете обновленный код в файл текущего кода программы). Пример довольно грубый, но должен быть понятен.
А reveal - это раскрытие данных. Как, например, в покере, когда в конце раунда все раскрывают свои карты.
Вот и текущий паттерн позволяет сохранить закодированные данные в блокчейне, чтобы позже можно было раскрыть их. Хотя и это грубое описание, так как в реальности происходит обычное сравнение захешированных данных и если они одинаковы, то система подтверждает их.
Хеширование данных происходит на стороне клиента, в браузере, для большей безопасности и конфиденциальности данных, затем они сохраняются в блокчейне.
Мы же помним, что с помощью keccak256 можно только закодировать данные в формате bytes32, но раскодировать обратно их не получится?
И вот когда мы делаем reveal, мы отправляем еще раз наши закодированные данные в блокчейн, там они сравниваются с теми, что уже хранятся от нашего имени и выдается подтверждение.
Если хоть одна часть, один символ в отсылаемых данных будет изменен, то система выдаст ошибку. Именно поэтому обмануть ее не получится.
Ну вот и весь смысл паттерна commit\reveal. Все довольно просто.
#commit #reveal
Урок 21 - DAO и Governance
В последний день лета мы переходим к уже серьезным темам, которые обязательно нужно понимать разработчику смарт-контрактов.
Последующие три урока будут как бы вводными в тему, и дополнительно мы будем возвращаться к этим темам уже в рамках других уроков и мастер-классов.
Видео урок про DAO и Governance
По сути, это тоже легкая тема, однако нужно немного посидеть с ней и разобраться что к чему. Я же, со своей стороны, постараюсь расписать основы и основную идею максимально просто и понятно.
Приятного дня и легкого обучения!
#урок #dao #governance
В последний день лета мы переходим к уже серьезным темам, которые обязательно нужно понимать разработчику смарт-контрактов.
Последующие три урока будут как бы вводными в тему, и дополнительно мы будем возвращаться к этим темам уже в рамках других уроков и мастер-классов.
Видео урок про DAO и Governance
По сути, это тоже легкая тема, однако нужно немного посидеть с ней и разобраться что к чему. Я же, со своей стороны, постараюсь расписать основы и основную идею максимально просто и понятно.
Приятного дня и легкого обучения!
#урок #dao #governance
YouTube
Solidity и смарт-контракты Ethereum, урок #26 | DAO и Governance - пишем сами (АПДЕЙТ В ЗАКРЕПЕ!!!)
ХОТИТЕ СТАТЬ РАЗРАБОТЧИКОМ Solidity, узнать об Ethereum, блокчейне и многом другом ещё больше?!
Мои друзья из GUIDE DAO (бывшая школа MCS) предлагают скидку 0,1 ETH на ВСЕ СВОИ БУТКЕМЫ ПО КРИПТЕ! Материалы этих буткемов подготовлены мной и другими специалистами:…
Мои друзья из GUIDE DAO (бывшая школа MCS) предлагают скидку 0,1 ETH на ВСЕ СВОИ БУТКЕМЫ ПО КРИПТЕ! Материалы этих буткемов подготовлены мной и другими специалистами:…
Подробнее о DAO
Для начала нам нужно понять, а что такое DAO вообще?
DAO или Decentralized Autonomous Organization (Децентрализованная автономная организация) - это такой тип смарт-контрактов, который позиционирует себя, как отдельное лицо (организация), через которое происходит управление другим смарт-контрактом.
В DAO нет какого-либо пользователя, который принимает решения в одиночку. Нет даже отдельной группы лиц, по типу совета директоров обычной компании, которые принимают решения за всех.
Каждый пользователь, у которого есть токен этого DAO - может принимать участие в голосовании и управлении контрактами.
Грубый пример. Представьте, что есть некий контракт, который может покупать и продавать криптовалюту на бирже, и затем распределять прибыль между его участниками.
Так вот, мы пишем еще один контракт (governance) для управление первым контрактом и выпускаем специальные токены на базе ERC20, которые распределяем между участниками.
Участники с токенами могут создавать предложения по тем или иным действиям с первым контрактом: докупить еще валюты, продать ее или распределить прибыль.
В управляющем контракте создается голосование, по итогам которого принимается решение.
Также в governance можно прописать дополнительные правила для участников, чтобы сделать голосование еще более прозрачным и равноправным. Например, что решение может быть принято, если 51% голосующих одобрит его. Или 1 токен будет равен 1 голосу. Или еще что-либо.
Именно из-за прозрачности и явной децентрализации DAO так полюбился многим крипто энтузиастам. На мой взгляд, DAO отличный пример демократии и реальной власти народа.
#dao #governance
Для начала нам нужно понять, а что такое DAO вообще?
DAO или Decentralized Autonomous Organization (Децентрализованная автономная организация) - это такой тип смарт-контрактов, который позиционирует себя, как отдельное лицо (организация), через которое происходит управление другим смарт-контрактом.
В DAO нет какого-либо пользователя, который принимает решения в одиночку. Нет даже отдельной группы лиц, по типу совета директоров обычной компании, которые принимают решения за всех.
Каждый пользователь, у которого есть токен этого DAO - может принимать участие в голосовании и управлении контрактами.
Грубый пример. Представьте, что есть некий контракт, который может покупать и продавать криптовалюту на бирже, и затем распределять прибыль между его участниками.
Так вот, мы пишем еще один контракт (governance) для управление первым контрактом и выпускаем специальные токены на базе ERC20, которые распределяем между участниками.
Участники с токенами могут создавать предложения по тем или иным действиям с первым контрактом: докупить еще валюты, продать ее или распределить прибыль.
В управляющем контракте создается голосование, по итогам которого принимается решение.
Также в governance можно прописать дополнительные правила для участников, чтобы сделать голосование еще более прозрачным и равноправным. Например, что решение может быть принято, если 51% голосующих одобрит его. Или 1 токен будет равен 1 голосу. Или еще что-либо.
Именно из-за прозрачности и явной децентрализации DAO так полюбился многим крипто энтузиастам. На мой взгляд, DAO отличный пример демократии и реальной власти народа.
#dao #governance
👍1
В двух словах о Governance
Governance - это смарт-контракт, который управляет другим контрактом через голосование его участников при помощи токенов ERC20.
#dao #governance
Governance - это смарт-контракт, который управляет другим контрактом через голосование его участников при помощи токенов ERC20.
#dao #governance
👍1
Описание контракта Governance из урока. Часть 1
Для начала обратите внимание, что было создано 4 контракта и 1 интерфейс.
Контракты ERC20 и IERC20 мы уже разбирали ранее, поэтому мы должны уже знать, что они отвечают за выпуск токенов.
Контракт MyToken - выпускает токены для наших пользователей, которые будут создавать голосования и принимать участие в них.
В контракте Demo, над которым мы и будет брать управление, стоит обратить внимание на функцию transferOwnership(). Именно через нее, при деплое контрактов, мы будем передавать владение от пользователя, развернувшего его, к контракту Governance.
Далее идет Governance контракт.
Для начала мы импортируем интерфейс IERC20, чтобы можно было вызывать функции оттуда, в частности запрашивать баланс токенов на конкретном адресе.
Создаем две структуры: proposalVote и Proposals, где ведем подсчет голосов, а также время голосования и исполнения. Это можно было объединить и в одну структуру, но по словам лектора, через два struct достигается большая гибкость в работе с функциями в дальнейшем.
Затем создаем enum для описания статуса голосования, а также два mapping, которые содержат в себе адреса, как ключи, и структуры, как значения. Это нужно для того, чтобы по id предложения можно было легко ориентироваться в его статусах и находить значения.
Также нам потребуется создать объект токена IERC20, который мы инициализируем в конструкторе.
Далее переходим к функциям.
#dao #governance
Для начала обратите внимание, что было создано 4 контракта и 1 интерфейс.
Контракты ERC20 и IERC20 мы уже разбирали ранее, поэтому мы должны уже знать, что они отвечают за выпуск токенов.
Контракт MyToken - выпускает токены для наших пользователей, которые будут создавать голосования и принимать участие в них.
В контракте Demo, над которым мы и будет брать управление, стоит обратить внимание на функцию transferOwnership(). Именно через нее, при деплое контрактов, мы будем передавать владение от пользователя, развернувшего его, к контракту Governance.
Далее идет Governance контракт.
Для начала мы импортируем интерфейс IERC20, чтобы можно было вызывать функции оттуда, в частности запрашивать баланс токенов на конкретном адресе.
Создаем две структуры: proposalVote и Proposals, где ведем подсчет голосов, а также время голосования и исполнения. Это можно было объединить и в одну структуру, но по словам лектора, через два struct достигается большая гибкость в работе с функциями в дальнейшем.
Затем создаем enum для описания статуса голосования, а также два mapping, которые содержат в себе адреса, как ключи, и структуры, как значения. Это нужно для того, чтобы по id предложения можно было легко ориентироваться в его статусах и находить значения.
Также нам потребуется создать объект токена IERC20, который мы инициализируем в конструкторе.
Далее переходим к функциям.
#dao #governance
Описание контракта Governance из урока. Часть 2
Для начала нам потребуется функция для создания уникального id предложения. Поэтому создаем generateProposalId(), куда передаем информацию о самом предложении (адрес, сумму, функцию для вызова, данные, и захешированное описание), и через знакомый нам keccak256 кодируем все и возвращаем.
Также создаем функцию для определения состояния (enum) предложения. Для этого берем из storage (так как предложение уже находится там после своего создания) и проверяем значения, в соответствии с которыми выставляем статус состояния.
Затем можно написать функции создания, исполнения и голосования.
В функции создания предложения мы принимаем необходимую информацию, создаем уникальный id через generateProposalId() и сохраняем в mapping структуру. При этом не забываем выполнить проверку на наличие токенов у пользователя, для создания предложения. И в конце возвращаем id.
В функции голосования мы делаем проверки на наличие токенов у пользователя, статуса предложения (ведь он не должен быть уже состоявшемся), а также голосовал ли ранее этот пользователь по данному предложению. В зависимости от его выбора, добавляем голос в значения "за", "против" или "воздержался". Ну, и выставляем статус, что данный пользователь успешно проголосовал.
В функции исполнения голосования мы принимаем все те же данные, что и в предыдущих функциях. Генерируем id и проверяем его статусы и наличие в базе.
Затем определяем его статус, как исполненный и через низкоуровневый вызов отправляем данные в контракт, которым управляем.
#dao #governance
Для начала нам потребуется функция для создания уникального id предложения. Поэтому создаем generateProposalId(), куда передаем информацию о самом предложении (адрес, сумму, функцию для вызова, данные, и захешированное описание), и через знакомый нам keccak256 кодируем все и возвращаем.
Также создаем функцию для определения состояния (enum) предложения. Для этого берем из storage (так как предложение уже находится там после своего создания) и проверяем значения, в соответствии с которыми выставляем статус состояния.
Затем можно написать функции создания, исполнения и голосования.
В функции создания предложения мы принимаем необходимую информацию, создаем уникальный id через generateProposalId() и сохраняем в mapping структуру. При этом не забываем выполнить проверку на наличие токенов у пользователя, для создания предложения. И в конце возвращаем id.
В функции голосования мы делаем проверки на наличие токенов у пользователя, статуса предложения (ведь он не должен быть уже состоявшемся), а также голосовал ли ранее этот пользователь по данному предложению. В зависимости от его выбора, добавляем голос в значения "за", "против" или "воздержался". Ну, и выставляем статус, что данный пользователь успешно проголосовал.
В функции исполнения голосования мы принимаем все те же данные, что и в предыдущих функциях. Генерируем id и проверяем его статусы и наличие в базе.
Затем определяем его статус, как исполненный и через низкоуровневый вызов отправляем данные в контракт, которым управляем.
#dao #governance
Деплой и тесты контрактов из урока. Часть 3
В конце хочу сказать пару слов о деплое и тестах в данном уроке: я ничего не понял.
В этом уроке лектор использовал typenoscript и typechain, с которыми я ранее не сталкивался в этой реализации. Поэтому, если вы также ничего не поняли, есть два варианта:
1. Вы можете сами поискать информацию об этом в сети, сделать пост или поскидывать материал в чат канала;
2. Немного подождать. Про typechain есть отдельный урок у лектора, который мы будем проходить послезавтра. А по деплою контрактов я планирую выделить день-два на следующей неделе. Там я постараюсь найти информацию о плагинах, библиотеках, функциях и т.д. по этой теме, и написать разборы.
Вообще не переживайте, если не понимаете объяснения лектора или информацию из моих постов. Я сам возвращаюсь к прошлым урокам довольно часто, так как многое забывается через день-два.
В Solidity, как и в изучении любого другого языка, главное практика. Выделяйте час-два на занятия в день, на повторение материала, но поиск другой информации - и все это постепенно уложится в голове.
Мы учим язык всего 1,5 месяца. И если вы занимаетесь вместе со мной, то уже знаете столько, сколько другой ученик получает за пол-года или даже больше! И этим точно можно гордиться!
#dao #governance
В конце хочу сказать пару слов о деплое и тестах в данном уроке: я ничего не понял.
В этом уроке лектор использовал typenoscript и typechain, с которыми я ранее не сталкивался в этой реализации. Поэтому, если вы также ничего не поняли, есть два варианта:
1. Вы можете сами поискать информацию об этом в сети, сделать пост или поскидывать материал в чат канала;
2. Немного подождать. Про typechain есть отдельный урок у лектора, который мы будем проходить послезавтра. А по деплою контрактов я планирую выделить день-два на следующей неделе. Там я постараюсь найти информацию о плагинах, библиотеках, функциях и т.д. по этой теме, и написать разборы.
Вообще не переживайте, если не понимаете объяснения лектора или информацию из моих постов. Я сам возвращаюсь к прошлым урокам довольно часто, так как многое забывается через день-два.
В Solidity, как и в изучении любого другого языка, главное практика. Выделяйте час-два на занятия в день, на повторение материала, но поиск другой информации - и все это постепенно уложится в голове.
Мы учим язык всего 1,5 месяца. И если вы занимаетесь вместе со мной, то уже знаете столько, сколько другой ученик получает за пол-года или даже больше! И этим точно можно гордиться!
#dao #governance
Урок 22 - Паттерн Proxy/Upgradeable: Transparent, UUPS
Сегодня у нас очень интересный урок, особенно для новичков в Solidity.
Как известно, загрузив смарт-контракт в майннет, его уже никак нельзя изменять или удалять. Однако, если действовать не напрямую, все же есть один способ делать обновления.
Для начинающих разработчиков этот паттерн является достаточно сложным для понимания и написания своего решения, при этом уже есть готовые контракты, основываясь на которых, можно делать обновления в своих. Именно это и рассматривается в уроке.
Видео урок о proxy.
Что нужно взять из этого урока?
Во-первых, конечно, можно попрактиковаться в написании своих прокси контрактов, чтобы понять как они работают, но на данном этапе обучения лучше понять как использовать готовые решения.
Во-вторых, из этого урока можно разобраться, как работать с openzeppelin, таким хранилищем смарт-контрактов, откуда можно брать примеры или создавать наследования.
Я же постараюсь также расписать все нюансы, чтобы в любой момент можно было по тега найти подсказку.
Приятного дня и легкого обучения!
#урок #proxy #upgradeable #transparent #uups
Сегодня у нас очень интересный урок, особенно для новичков в Solidity.
Как известно, загрузив смарт-контракт в майннет, его уже никак нельзя изменять или удалять. Однако, если действовать не напрямую, все же есть один способ делать обновления.
Для начинающих разработчиков этот паттерн является достаточно сложным для понимания и написания своего решения, при этом уже есть готовые контракты, основываясь на которых, можно делать обновления в своих. Именно это и рассматривается в уроке.
Видео урок о proxy.
Что нужно взять из этого урока?
Во-первых, конечно, можно попрактиковаться в написании своих прокси контрактов, чтобы понять как они работают, но на данном этапе обучения лучше понять как использовать готовые решения.
Во-вторых, из этого урока можно разобраться, как работать с openzeppelin, таким хранилищем смарт-контрактов, откуда можно брать примеры или создавать наследования.
Я же постараюсь также расписать все нюансы, чтобы в любой момент можно было по тега найти подсказку.
Приятного дня и легкого обучения!
#урок #proxy #upgradeable #transparent #uups
YouTube
Solidity и смарт-контракты Ethereum, урок #28 | Паттерн Proxy/Upgradeable: Transparent, UUPS
ХОТИТЕ СТАТЬ РАЗРАБОТЧИКОМ Solidity, узнать об Ethereum, блокчейне и многом другом ещё больше?!
Мои друзья из GUIDE DAO (бывшая школа MCS) предлагают скидку 0,1 ETH на ВСЕ СВОИ БУТКЕМЫ ПО КРИПТЕ! Материалы этих буткемов подготовлены мной и другими специалистами:…
Мои друзья из GUIDE DAO (бывшая школа MCS) предлагают скидку 0,1 ETH на ВСЕ СВОИ БУТКЕМЫ ПО КРИПТЕ! Материалы этих буткемов подготовлены мной и другими специалистами:…
👍2
Паттерн Proxy
Основная проблема смарт-контрактов заключается в том, что после деплоя в блокчейн их нельзя изменить или удалить.
И в случае, если мы создали крутой проект, которым пользуются много человек, и в какой-то момент нужно добавить новые функции или другие фишки, мы должны будем переписать наш контракт, загрузить его в сеть и сказать пользователям, что теперь они должны отправлять все свои транзакции туда. Более того, встает вопрос, как перебросить данные из старого контракта в новый.
С этими проблемами и призван бороться прокси паттерн. Так как он работает?
Когда пользователь отправляет транзакцию, он делает это не в смарт-контракт напрямую, а в прокси-контракт, который уже после отправляет данную транзакцию в нужный контракт.
По факту прокси будет выполнять функционал нашего смарт-контракта, но в своем контексте за счет такой штуки, как delegatecall.
Этот подход позволяет разделить логику работы смарт-контракта и данные, с которыми мы работаем. Получается, что логика лежит в нашем СК, а данные - в прокси.
И когда нам потребуется обновить логику работы СК, то мы просто загрузим в блокчейн новый контракт и как бы скажем прокси, что теперь нужно выполнять функции из обновленного контракта. При этом данные никуда не потеряются, так как они находятся в прокси.
#proxy
Основная проблема смарт-контрактов заключается в том, что после деплоя в блокчейн их нельзя изменить или удалить.
И в случае, если мы создали крутой проект, которым пользуются много человек, и в какой-то момент нужно добавить новые функции или другие фишки, мы должны будем переписать наш контракт, загрузить его в сеть и сказать пользователям, что теперь они должны отправлять все свои транзакции туда. Более того, встает вопрос, как перебросить данные из старого контракта в новый.
С этими проблемами и призван бороться прокси паттерн. Так как он работает?
Когда пользователь отправляет транзакцию, он делает это не в смарт-контракт напрямую, а в прокси-контракт, который уже после отправляет данную транзакцию в нужный контракт.
По факту прокси будет выполнять функционал нашего смарт-контракта, но в своем контексте за счет такой штуки, как delegatecall.
Этот подход позволяет разделить логику работы смарт-контракта и данные, с которыми мы работаем. Получается, что логика лежит в нашем СК, а данные - в прокси.
И когда нам потребуется обновить логику работы СК, то мы просто загрузим в блокчейн новый контракт и как бы скажем прокси, что теперь нужно выполнять функции из обновленного контракта. При этом данные никуда не потеряются, так как они находятся в прокси.
#proxy
👍1🔥1
Паттерн Transparent Proxy
Transparent Proxy более старая версия прокси, суть которой заключается в том, что тут есть специальные админские функции для указания на контракт исполнения.
Однако остается вопрос, а что делать, если у нас две одинаковые функции, два одинаковых селектора, и в прокси и в контракте исполнения?
Но все оказывается достаточно просто. Если функции вызываются администратором, то их выполнение идет только в прокси. Если же данную функцию вызывает обычный пользователь, то выполнение происходит в другом контракте.
При этом, если вдруг администратору все таки нужно вызвать функцию в исполняемом контракте, то ему придется делать это из под аккаунта (адреса) обычного пользователя.
#proxy #transparent
Transparent Proxy более старая версия прокси, суть которой заключается в том, что тут есть специальные админские функции для указания на контракт исполнения.
Однако остается вопрос, а что делать, если у нас две одинаковые функции, два одинаковых селектора, и в прокси и в контракте исполнения?
Но все оказывается достаточно просто. Если функции вызываются администратором, то их выполнение идет только в прокси. Если же данную функцию вызывает обычный пользователь, то выполнение происходит в другом контракте.
При этом, если вдруг администратору все таки нужно вызвать функцию в исполняемом контракте, то ему придется делать это из под аккаунта (адреса) обычного пользователя.
#proxy #transparent
👍1
Паттерн UUPS Proxy
UUPS или Universal Upgradeable Proxy Standard (Универсальный Обновляемых Прокси Стандарт) - более новый и легковесный прокси контракт.
В случае UUPS все админские функции находятся в контракте исполнения, а не в самом прокси. По сути, тут нет ничего, за исключением логики перенаправления в другой контракт.
#proxy #uups
UUPS или Universal Upgradeable Proxy Standard (Универсальный Обновляемых Прокси Стандарт) - более новый и легковесный прокси контракт.
В случае UUPS все админские функции находятся в контракте исполнения, а не в самом прокси. По сути, тут нет ничего, за исключением логики перенаправления в другой контракт.
#proxy #uups
👍2
Паттерн Diamond Proxy
Есть еще один вид прокси контрактов под названием Diamond. В этом уроке мы его не рассматриваем, но упомянуть стоит.
Diamond используется в крупных проектах, где существует большое количество смарт-контрактов, которые нужно иногда обновлять.
В этом случае исполняемый контракт разбивается не несколько более мелких контрактов, которые и управляются через прокси.
#proxy #diamond
Есть еще один вид прокси контрактов под названием Diamond. В этом уроке мы его не рассматриваем, но упомянуть стоит.
Diamond используется в крупных проектах, где существует большое количество смарт-контрактов, которые нужно иногда обновлять.
В этом случае исполняемый контракт разбивается не несколько более мелких контрактов, которые и управляются через прокси.
#proxy #diamond
Простая идея реализации прокси контракта
В начале урока лектор приводит пример простой реализации прокси контракта. Так вот, его использовать не надо! Он показал его просто для того, чтобы вы поняли основную суть данного паттерна.
Я просто повторю основные моменты тут.
Есть контракт Proxy, в котором всего три функции: setImplementation(), _delegate() и fallback().
В первой устанавливается контракт, куда мы будем передавать все действия.
В _delegate() как раз прописывается логика отправки запроса и получения ответа в исполняемый контракт при помощи delegatecall.
Тут интересно то, что написана она с помощью assembly. Мы принимает селектор функции из исполняемого контракта (берем его из памяти), затем передаем через delegatecall в другой контракт и принимаем оттуда ответ. Если приходит "0", то показываем ошибку, так как данных нет, а значит в другом контракте что-то пошло не так. Если данные получены, то показываем их.
Также интерес представляет функция fallback(). Как мы помним, она вызывается в том случае, когда в контракте нет функции с таким именем, которую пытаются тут вызвать. Следовательно, в этом случае вызывается fallback, которая в свою очередь вызывает _delegate.
И вот по этой цепочке и происходит работа прокси. При этом все данные остаются тут, а не в исполняемом контракте.
Это самый простой способ работы с прокси, поэтому еще раз повторяю, что его не следует использовать в реальных проектах!
#proxy #upgradeable #transparent #uups
В начале урока лектор приводит пример простой реализации прокси контракта. Так вот, его использовать не надо! Он показал его просто для того, чтобы вы поняли основную суть данного паттерна.
Я просто повторю основные моменты тут.
Есть контракт Proxy, в котором всего три функции: setImplementation(), _delegate() и fallback().
В первой устанавливается контракт, куда мы будем передавать все действия.
В _delegate() как раз прописывается логика отправки запроса и получения ответа в исполняемый контракт при помощи delegatecall.
Тут интересно то, что написана она с помощью assembly. Мы принимает селектор функции из исполняемого контракта (берем его из памяти), затем передаем через delegatecall в другой контракт и принимаем оттуда ответ. Если приходит "0", то показываем ошибку, так как данных нет, а значит в другом контракте что-то пошло не так. Если данные получены, то показываем их.
Также интерес представляет функция fallback(). Как мы помним, она вызывается в том случае, когда в контракте нет функции с таким именем, которую пытаются тут вызвать. Следовательно, в этом случае вызывается fallback, которая в свою очередь вызывает _delegate.
И вот по этой цепочке и происходит работа прокси. При этом все данные остаются тут, а не в исполняемом контракте.
Это самый простой способ работы с прокси, поэтому еще раз повторяю, что его не следует использовать в реальных проектах!
#proxy #upgradeable #transparent #uups
👍1
Наследование из openzeppelin
Прежде чем использовать контракты из openzeppelin, нужно сначала установить их в свой проект.
Сделать это можно двумя способами. И так как тема у нас про обновляемые контракты, то сразу покажу установку для них.
1. Вам необходимо прописать следующие строки в консоли:
npm install @openzeppelin/contracts
npm install --save-dev @openzeppelin/hardhat-upgrades
npm install --save-dev @nomiclabs/hardhat-ethers ethers # peer dependencies
На случай, если возникнут проблемы с версиями пакетов, вы всегда можете посмотреть актуальные команды по ссылкам тут и тут.
2. Можно также зайти в файл package.json в папке своего проекта, и в блоке dependencies прописать:
"@openzeppelin/contracts": "^4.7.2",
"@openzeppelin/contracts-upgradeable": "^4.7.2"
Затем зайти в консоль и выполнить команду:
npm install
После чего у вас установятся все необходимые пакеты.
При этом после добавления openzeppelin/contracts-upgradeable вам следует открыть файл hardhat.config.json в своем проекте и добавить строки в начале:
import "@openzeppelin/hardhat-upgrades";
(если вы используете typenoscript)
или
require('@openzeppelin/hardhat-upgrades');
(если используете javanoscript)
После этого уже в файле своего контракта вы сможете импортировать контракты openzeppelin и наследовать от них. Для этого нужно будет добавлять следующие строки (как в примере урока):
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
и т.д.
#proxy #upgradeable #npm #openzeppelin
Прежде чем использовать контракты из openzeppelin, нужно сначала установить их в свой проект.
Сделать это можно двумя способами. И так как тема у нас про обновляемые контракты, то сразу покажу установку для них.
1. Вам необходимо прописать следующие строки в консоли:
npm install @openzeppelin/contracts
npm install --save-dev @openzeppelin/hardhat-upgrades
npm install --save-dev @nomiclabs/hardhat-ethers ethers # peer dependencies
На случай, если возникнут проблемы с версиями пакетов, вы всегда можете посмотреть актуальные команды по ссылкам тут и тут.
2. Можно также зайти в файл package.json в папке своего проекта, и в блоке dependencies прописать:
"@openzeppelin/contracts": "^4.7.2",
"@openzeppelin/contracts-upgradeable": "^4.7.2"
Затем зайти в консоль и выполнить команду:
npm install
После чего у вас установятся все необходимые пакеты.
При этом после добавления openzeppelin/contracts-upgradeable вам следует открыть файл hardhat.config.json в своем проекте и добавить строки в начале:
import "@openzeppelin/hardhat-upgrades";
(если вы используете typenoscript)
или
require('@openzeppelin/hardhat-upgrades');
(если используете javanoscript)
После этого уже в файле своего контракта вы сможете импортировать контракты openzeppelin и наследовать от них. Для этого нужно будет добавлять следующие строки (как в примере урока):
import "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol";
и т.д.
#proxy #upgradeable #npm #openzeppelin
OpenZeppelin Docs
Contracts
The official documentation for OpenZeppelin Libraries and Tools
Upgradeable ERC721. Часть 1
Отдельный урок про ERC721 у нас будет на следующей неделе, так как потребуется пара дней, чтобы научиться работать с ним. А сейчас мы, на его примере, рассмотрим, как работают обновляемые контракты.
Для начала нам нужно импортировать все необходимые обновляемые контракты с openzeppelin, а также прокси контракт Initializable.
Коммит по уроку можно посмотреть тут.
Так как конструкторы, как я понял из урока, в обновляемых контракта могут работать некорректно, было принято решение заменить его новой функцией initialize() с модификатором initializer. По правилам она вызывается только один раз при разворачивании контракта, поэтому ее можно как бы назвать неким конструктором обновляемых контрактов.
И уже в этой функции мы можем другие функции, с помощью которых можно установить владельца контракта или передать данные о токене, например, в ERC721.
Также необходимо функции, в которых используются обновляемые контракты, также обновить.
#proxy #upgradeable #transparent
Отдельный урок про ERC721 у нас будет на следующей неделе, так как потребуется пара дней, чтобы научиться работать с ним. А сейчас мы, на его примере, рассмотрим, как работают обновляемые контракты.
Для начала нам нужно импортировать все необходимые обновляемые контракты с openzeppelin, а также прокси контракт Initializable.
Коммит по уроку можно посмотреть тут.
Так как конструкторы, как я понял из урока, в обновляемых контракта могут работать некорректно, было принято решение заменить его новой функцией initialize() с модификатором initializer. По правилам она вызывается только один раз при разворачивании контракта, поэтому ее можно как бы назвать неким конструктором обновляемых контрактов.
И уже в этой функции мы можем другие функции, с помощью которых можно установить владельца контракта или передать данные о токене, например, в ERC721.
Также необходимо функции, в которых используются обновляемые контракты, также обновить.
#proxy #upgradeable #transparent
👍1
Upgradeable ERC721. Часть 2
По умолчанию все обновляемые контракты используют transparent proxy. Для того, чтобы переключиться на UUPS proxy нам нужно сделать следующие действия.
1. Добавить в импортируемые файлы с openzeppelin строку
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
2. Добавить наследование от UUPS в наш контракт;
3. В функции initialize() добавить функцию __UUPSUpgradeable_init(), чтобы при разворачивании система поняла, что мы используем именно UUPS;
4. Также вспоминаем, что в случае UUPS proxy все права администратора записываются в обновляемом контракте, т.е. том, который пишем мы. Поэтому нужно добавить функцию администрирования.
function _authorizeUpgrade(address newImplementation) internal onlyOwner override {}
Этих действий будет достаточно, чтобы развернуть UUPS прокси к нашему контракту.
#proxy #upgradeable #uups
По умолчанию все обновляемые контракты используют transparent proxy. Для того, чтобы переключиться на UUPS proxy нам нужно сделать следующие действия.
1. Добавить в импортируемые файлы с openzeppelin строку
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
2. Добавить наследование от UUPS в наш контракт;
3. В функции initialize() добавить функцию __UUPSUpgradeable_init(), чтобы при разворачивании система поняла, что мы используем именно UUPS;
4. Также вспоминаем, что в случае UUPS proxy все права администратора записываются в обновляемом контракте, т.е. том, который пишем мы. Поэтому нужно добавить функцию администрирования.
function _authorizeUpgrade(address newImplementation) internal onlyOwner override {}
Этих действий будет достаточно, чтобы развернуть UUPS прокси к нашему контракту.
#proxy #upgradeable #uups
Деплой Upgradeable ERC721. Часть 3
Отдельно деплой контрактов мы будем разбирать на следующей неделе, а пока пройдемся по коду из урока.
В начале файла лектор подключает три импорта:
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { expect } from "chai";
import { ethers, upgrades } from "hardhat";
С "chai" и "ethers" мы уже знакомы, поэтому остановлюсь на двух других.
"upgrades" - это плагин, который стал доступен, когда мы установили пакет hardhat-upgrades. Он помогает разворачивать и тестировать прокси контракты.
"loadFixture" - это также новый плагин, который был добавлен в toolbox. Лектор, говорит, что это новая фича в hardhat, но на момент, когда мы учились устанавливать среду разработки, он уже был доступен и я рассказывал, как его установить.
В данном тесте у нас нет обычной функции beforeEach(), которая вызывалась перед каждым тестом. В этом случае мы пишем отдельную функцию dep() (или деплой).
Также используем ethers.getSigners(), чтобы получить адрес пользователя, который разворачивает контракт, а также getContractFactory(), чтобы указать, с каким контрактом мы работаем.
И вот дальше мы используем плагин "upgrades", для деплоя прокси контракта, где в аргументах передаем разворачиваемый контракт, аргументы для функции initialize() в нашем контракте, если необходимо, и набор опций для прокси:
const token = await upgrades.deployProxy(NFTFactory, [], {
initializer: 'initialize',
kind: 'uups',
});
Если мы работаем с UUPS контрактами, то добавляем сюда kind: "uups". Если же с transparent proxy, то оставляем только initializer.
Из этой функции деплоя нам нужно вернуть контракт и адрес деплоера.
Далее в тестах, с помощью плагина loadFixture(), мы обращаемся к функции нашего деплоя, откуда получаем token (наш прокси) и deployer.
const { token, deployer } = await loadFixture(dep);
После этого можно писать тесты, как мы уже делали раньше.
Далее посмотрим, как работать с обновленным контрактом в тестах.
Для начала его также нужно получить через getContractFactory(), и уже потом использовать плагин upgrades, чтобы обновить прокси, передав в него адрес прокси и новый контракт.
const token2 = await upgrades.upgradeProxy(token.address, NFTFactoryv2);
После этого мы можем писать тесты уже для обновленного контакта.
P.S. Для меня сейчас деплой контрактов также немного сложная тема. Потребуется некоторое время и практика, чтобы понять суть и свободно ориентироваться в коде.
#proxy #upgradeable #transparent #uups #deploy
Отдельно деплой контрактов мы будем разбирать на следующей неделе, а пока пройдемся по коду из урока.
В начале файла лектор подключает три импорта:
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { expect } from "chai";
import { ethers, upgrades } from "hardhat";
С "chai" и "ethers" мы уже знакомы, поэтому остановлюсь на двух других.
"upgrades" - это плагин, который стал доступен, когда мы установили пакет hardhat-upgrades. Он помогает разворачивать и тестировать прокси контракты.
"loadFixture" - это также новый плагин, который был добавлен в toolbox. Лектор, говорит, что это новая фича в hardhat, но на момент, когда мы учились устанавливать среду разработки, он уже был доступен и я рассказывал, как его установить.
В данном тесте у нас нет обычной функции beforeEach(), которая вызывалась перед каждым тестом. В этом случае мы пишем отдельную функцию dep() (или деплой).
Также используем ethers.getSigners(), чтобы получить адрес пользователя, который разворачивает контракт, а также getContractFactory(), чтобы указать, с каким контрактом мы работаем.
И вот дальше мы используем плагин "upgrades", для деплоя прокси контракта, где в аргументах передаем разворачиваемый контракт, аргументы для функции initialize() в нашем контракте, если необходимо, и набор опций для прокси:
const token = await upgrades.deployProxy(NFTFactory, [], {
initializer: 'initialize',
kind: 'uups',
});
Если мы работаем с UUPS контрактами, то добавляем сюда kind: "uups". Если же с transparent proxy, то оставляем только initializer.
Из этой функции деплоя нам нужно вернуть контракт и адрес деплоера.
Далее в тестах, с помощью плагина loadFixture(), мы обращаемся к функции нашего деплоя, откуда получаем token (наш прокси) и deployer.
const { token, deployer } = await loadFixture(dep);
После этого можно писать тесты, как мы уже делали раньше.
Далее посмотрим, как работать с обновленным контрактом в тестах.
Для начала его также нужно получить через getContractFactory(), и уже потом использовать плагин upgrades, чтобы обновить прокси, передав в него адрес прокси и новый контракт.
const token2 = await upgrades.upgradeProxy(token.address, NFTFactoryv2);
После этого мы можем писать тесты уже для обновленного контакта.
P.S. Для меня сейчас деплой контрактов также немного сложная тема. Потребуется некоторое время и практика, чтобы понять суть и свободно ориентироваться в коде.
#proxy #upgradeable #transparent #uups #deploy
Урок 23 - Typechain и hardhat toolbox
Заканчиваем нашу ударную неделю в Solidity с изучением урока про typechain.
Хорошие новости в том, что, если вчера вы со мной посидели над уроком про прокси и разобрались с деталями кода, а в особенности деплоя контракта, который я описывал в последнем посте, то половину данного урока вы поймете без каких-либо сложностей.
Как оказалось, использование loadFixture более современный метод деплоя, и уже можно не писать beforeEach(). Более того лектор немного ругается про плагин hardhat deploy, который они часто использовал ранее, обосновывая, что там есть ошибки, которые "ломают" npx.
Но о деплое мы поговорим еще на следующей неделе, а сегодня будут посты про typechain.
Видео урок про typechain и toolbox.
Для меня это тоже новая тема, поэтому буду писать, как я сам понимаю реализацию. Если среди вас есть те, кто уже работал с typenoscript, то буду рад комментариям или поправкам.
Приятного дня и легкого обучения!
#урок #typechain #toolbox
Заканчиваем нашу ударную неделю в Solidity с изучением урока про typechain.
Хорошие новости в том, что, если вчера вы со мной посидели над уроком про прокси и разобрались с деталями кода, а в особенности деплоя контракта, который я описывал в последнем посте, то половину данного урока вы поймете без каких-либо сложностей.
Как оказалось, использование loadFixture более современный метод деплоя, и уже можно не писать beforeEach(). Более того лектор немного ругается про плагин hardhat deploy, который они часто использовал ранее, обосновывая, что там есть ошибки, которые "ломают" npx.
Но о деплое мы поговорим еще на следующей неделе, а сегодня будут посты про typechain.
Видео урок про typechain и toolbox.
Для меня это тоже новая тема, поэтому буду писать, как я сам понимаю реализацию. Если среди вас есть те, кто уже работал с typenoscript, то буду рад комментариям или поправкам.
Приятного дня и легкого обучения!
#урок #typechain #toolbox
YouTube
Solidity и смарт-контракты Ethereum, урок #29 | Typechain, новые фичи Hardhat (toolbox), автотесты
ХОТИТЕ СТАТЬ РАЗРАБОТЧИКОМ Solidity, узнать об Ethereum, блокчейне и многом другом ещё больше?!
Мои друзья из GUIDE DAO (бывшая школа MCS) предлагают скидку 0,1 ETH на ВСЕ СВОИ БУТКЕМЫ ПО КРИПТЕ! Материалы этих буткемов подготовлены мной и другими специалистами:…
Мои друзья из GUIDE DAO (бывшая школа MCS) предлагают скидку 0,1 ETH на ВСЕ СВОИ БУТКЕМЫ ПО КРИПТЕ! Материалы этих буткемов подготовлены мной и другими специалистами:…
Немного о Typechain
Для начала нужно разобраться, а что такое typechain и зачем он нужен в hardhat?
Typechain - это решение, которое уже входит в hardhat toolbox и генерирует для наших смарт-контрактов специальные типы для typenoscript. Они помогают нам работать с объектами СК.
Попробую объяснить чуть понятнее.
До этого мы писали все тесты в файле с расширением js, т.е. javanoscript.
JavaScript потрясающий язык программирования, но в нем есть некоторые проблемы с типами данных. Напомню, что типы данных это string, uint, bool и т.д. Только в js не uint, а number.
Так вот, в работе с этими данными в некоторых случаях нужно было конкретно указывать js, что мы работаем, например, с числами, иначе могло получиться так, что "1+1" было бы равно "11", а не "2".
Для решения этой и других проблем языка был создан typenoscript. Я плохо с ним знаком, но могу сказать, что уже на старте работы там требуется конкретизировать тип данных в переменных.
И как я понял из урока, typechain использует typenoscript для работы с объектами СК, а именно дает подсказки по функциям и типам данных в них.
Более того, немного покопавшись в других примерах разработки СК, я понял, что typechain более "крутой" и современный подход. И теперь нам нужно будет стараться учиться писать тесты, используя именно его.
#урок #typechain
Для начала нужно разобраться, а что такое typechain и зачем он нужен в hardhat?
Typechain - это решение, которое уже входит в hardhat toolbox и генерирует для наших смарт-контрактов специальные типы для typenoscript. Они помогают нам работать с объектами СК.
Попробую объяснить чуть понятнее.
До этого мы писали все тесты в файле с расширением js, т.е. javanoscript.
JavaScript потрясающий язык программирования, но в нем есть некоторые проблемы с типами данных. Напомню, что типы данных это string, uint, bool и т.д. Только в js не uint, а number.
Так вот, в работе с этими данными в некоторых случаях нужно было конкретно указывать js, что мы работаем, например, с числами, иначе могло получиться так, что "1+1" было бы равно "11", а не "2".
Для решения этой и других проблем языка был создан typenoscript. Я плохо с ним знаком, но могу сказать, что уже на старте работы там требуется конкретизировать тип данных в переменных.
И как я понял из урока, typechain использует typenoscript для работы с объектами СК, а именно дает подсказки по функциям и типам данных в них.
Более того, немного покопавшись в других примерах разработки СК, я понял, что typechain более "крутой" и современный подход. И теперь нам нужно будет стараться учиться писать тесты, используя именно его.
#урок #typechain
👍1