Смешанные темы для второкурсников
Есть несколько тем, по которым мы хотели предоставить информацию, но они не были достаточно подробными, чтобы заслуживать отдельного уровня. Этот уровень предназначен для того, чтобы сгруппировать несколько отдельных тем и рассказать о некоторых вещах, которые будет полезно иметь в виду.
Оглавление
- Провайдеры и подписывающие лица
- BigNumbers
- ABI
- React Hooks
- Поток утверждения ERC20
Провайдеры и подписывающие лица
При создании интерфейсов для смарт-контрактов вы часто будете сталкиваться с этими двумя терминами — Provider
и Signer
. Хотя вы будете понимать их гораздо лучше, когда начнете их использовать, мы постараемся дать краткое объяснение того, что они означают.
Мы знаем, что для чтения или записи данных в блокчейн нам необходимо взаимодействовать через узел Ethereum. Узел содержит состояние блокчейна, что позволяет нам считывать данные. Он также может транслировать транзакции майнерам, что позволяет нам записывать данные.
Обратите внимание, что узел должен транслировать транзакции только в том случае, если вы хотите записать данные в блокчейн. Поскольку если вы просто читаете данные, которые уже существуют, майнерам не нужно ничего с этим делать, они уже сделали свою работу.
Provider
— это соединение узла Ethereum, которое позволяет вам читать данные из его состояния. Вы будете использовать Provider
для таких задач, как вызов функций только для чтения в смарт-контрактах, получение остатков на счетах, получение деталей транзакций и т. д.
Signer
— это соединение с узлом Ethereum, которое позволяет записывать данные в блокчейн. Вы будете использовать Signer
для таких действий, как вызов функций записи в смарт-контрактах, перевод ETH между счетами и т. д. Для этого Signer
должен иметь доступ к Private Key
, который он может использовать для совершения транзакций от имени аккаунта.
Кроме того, Signer
может делать все то же самое, что и Provider
. С помощью Signer
можно делать и чтение, и запись, но Provider
подходит только для чтения данных.
Такие кошельки, как Metamask, по умолчанию внедряют Provider
в ваш браузер. Поэтому dApps могут использовать ваш Metamask Provider
для чтения значений из сети блокчейн, к которой подключен ваш кошелек.
Однако иногда вы хотите, чтобы пользователи совершали транзакции, а не просто считывали данные. Конечно, Metamask не может просто так поделиться своими закрытыми ключами со случайными веб-сайтами — это было бы безумием. Для этого Metamask также позволяет веб-сайтам запрашивать Signer
. Таким образом, когда dApp пытается отправить транзакцию в блокчейн, всплывает окно Metamask с просьбой подтвердить действие.
BigNumbers
Изучая Solidity, мы много читали и использовали uint256
. uint256
имеет диапазон от 0
до (2^256) - 1
. Поэтому максимальное число, которое может хранить тип данных uint256
, астрономически велико.
В частности, максимальное значение для uint256
составляет:
115792089237316195423570985008687907853269984665640564039457584007913129639935
Для сравнения, один миллион — это:
1000000
Очевидно, что uint256
может хранить безумно большие числа. Но это создает проблему.
Обычно мы создаем интерфейсы для смарт-контрактов на Javascript. Тип данных Javascript number
имеет значительно меньший верхний предел.
Точнее, максимальное значение числового типа, которое может хранить Javascript, равно just:
9007199254740991
Это даже не близко к тому, что может вместить uint256
!
Итак, допустим, мы используем Javascript для вызова функции на смарт-контракте, которая возвращает uint256
. Если это число превышает максимальное числовое значение Javascript, что вполне определенно возможно, то что произойдет?
Как выясняется, Javascript не может это поддерживать. Поэтому мы должны использовать специальный тип, называемый BigNumber
. Библиотеки, используемые для взаимодействия с узлами Ethereum — ethers.js
и web3.js
— обе имеют поддержку BigNumber
.
BigNumber
— это пользовательская библиотека классов, написанная на Javascript, которая вводит собственные функции для математических функций — add
, sub
, mul
, div
и т.д. BigNumber
имеет значительно большую емкость для чисел, чем та, которую Javascript может поддерживать изначально.
Когда мы будем писать код на следующих уровнях, вы встретите математические операции, выполняемые вызовом функций типа .add()
и .mul()
вместо типичных операторов +
и *
, которые мы знаем — это потому, что при работе с BigNumber
нам нужно использовать его математические функции.
Что же произойдет, если мы попытаемся сделать это с числами Javascript, то мы легко переполнимся или недополнимся. Это означает, что наши вычисления будут совершенно неправильными и неопределенными. Поэтому просто имейте это в виду.
ABI
ABI расшифровывается как Application Binary Interface. Это одна из самых сложных для понимания вещей при работе с Ethereum, но мы постараемся объяснить ее как можно лучше.
В учебниках для первокурсников и в учебниках, с которыми вы столкнетесь в дальнейшем, вы будете активно использовать ABI
.
Когда код Solidity компилируется, он компилируется в байткод, который, по сути, является двоичным кодом. Он не содержит записей об именах функций, существовавших в контракте, о том, какие параметры они содержат и какие значения возвращают.
Однако если вы хотите вызвать функцию Solidity из веб-приложения, вам нужен способ вызвать правильный байткод в контракте. Для этого вам нужен способ преобразования человекочитаемых имен функций и параметров в байткод и обратно.
ABI помогают нам достичь именно этого. Когда вы компилируете код Solidity, ABI автоматически генерируется компилятором. Он содержит правила и метаданные о функциях, присутствующих в контракте, которые помогают выполнить правильное преобразование данных туда и обратно.
Поэтому, когда вы хотите вызвать контракт, вам нужен его адрес (конечно), но вам также нужно предоставить его ABI. Библиотеки вроде ethers.js
используют ABI для кодирования и декодирования человекочитаемых функций в байткод и обратно при взаимодействии с узлом Ethereum и вызове функций в смарт-контрактах.
React Hooks
В учебниках второго курса и далее мы будем разрабатывать веб-сайты с использованием React и Next.js. Часто мы будем использовать некоторые специфические для React функции, помогающие писать чистый код.
Очень важной особенностью React является React Hooks.
Мы не будем пытаться изобретать колесо и подробно рассказывать вам о том, что такое React Hooks, поскольку для этого существует множество других ресурсов, но мы перечислим то, что имеет значение, чтобы вы могли сосредоточиться на этом.
В React встроено ~10 хуков, и разработчики также могут создавать свои собственные хуки. Для наших целей мы сосредоточимся на трех, которые мы используем регулярно, а остальные вы можете изучить, если захотите.
Прочитайте об этих трех хуках и поймите, для чего они используются.
- useState
- useEffect
- useRef
Поток утверждения ERC20
В прошлом мы узнали о функциях payable
, которые позволяют смарт-контрактам принимать платеж в ETH при вызове функции. Это действительно полезно, если вы хотите взимать плату с пользователей в ETH в обмен на что-то — например, продажу NFT.
Но что, если вы хотите использовать для оплаты не ETH, а что-то другое? Что, если вы хотите использовать для оплаты собственную криптовалюту, которую вы создали?
Здесь все становится немного сложнее.
Поскольку ETH является родной валютой Ethereum, а стандарт ERC20 был введен гораздо позже после изобретения Ethereum, они ведут себя не совсем одинаково. В частности, принимать платежи в токенах ERC20 не так просто, как просто сделать функцию payable
в Solidity.
Ключевое слово payable
подходит только для платежей в ETH. Если вы хотите использовать свою собственную криптовалюту ERC20, то сделать это немного сложнее.
Во-первых, давайте немного подумаем об этом.
- Итак, вы не можете отправить токены ERC20 вместе с вызовом функции, как это можно сделать с ETH.
- Возможно, смарт-контракт может каким-то образом получить токены со счета вызывающей функции?
- Но это означает, что я могу написать смарт-контракт, который украдет токены каждого, если кто-то совершит транзакцию с моим контрактом.
- Поэтому нам нужен более безопасный способ извлечения токенов с чьего-либо счета.
Вот здесь и приходит на помощь поток Approve and Transfer
.
В стандарте ERC20
есть понятие Allowance.
Давайте попробуем разобраться в этом на примере.
- Алиса хочет продать свой НМТ
- Алиса хочет принять оплату за НМТ в своей собственной криптовалюте, AliceCoin
- Стоимость НМТ Алисы составляет 10 AliceCoin
- Боб владеет AliceCoin
- Боб хочет купить NFT Алисы
- Бобу нужен способ вызвать функцию на смарт-контракте NFT Алисы, которая примет платеж в 10 Alicecoin и отправит ему его NFT.
- Поскольку смарт-контракты не могут принимать Alicecoin в качестве оплаты напрямую, Алиса закодировала поток
ERC20 Approval and Transfer
в своем контракте NFT
Alicecoin
— это токен ERC20. В ERC20 встроено несколько функций, связанных с концепцией разрешения.
approve(address spender, uint256 amount)
.
Позволяет пользователю approve
по другому адресу потратить до суммы
токенов от своего имени. Т.е. эта функция предоставляет разрешение расходующему
на сумму до суммы
.
transferFrom(address from, address to, uint256 amount)
Позволяет пользователю перевести токен amount
с адреса from
на адрес to
.
Если пользователь, вызывающий функцию, совпадает с адресом from
, жетоны удаляются с баланса пользователя.
Если пользователь не является пользователем адреса from
, адрес from
должен был в прошлом дать пользователю разрешение потратить amount
жетонов с помощью функции approve
.
Продолжаем пример:
- Боб дает контракту NFT Алисы разрешение потратить до 10 своих
Alicecoin
с помощью функцииapprove
. - Боб вызывает функцию для покупки NFT Алисы на ее NFT-контракте
- Функция покупки внутренне вызывает
transferFrom
наAlicecoin
и переводит 10 Alicecoin со счета Боба на счет Алисы. - Поскольку в контракте Бобу ранее была предоставлена возможность потратить до 10 Alicecoin, это действие разрешено.
- Таким образом, Алиса получает свои 10 Alicecoin, а Боб получает свой NFT.
Хорошо, что это значит для нас?
Обратите внимание, что Боб должен был дать согласие на контракт, чтобы контракт мог забрать токены Боба с его счета.
Поэтому Бобу, по сути, пришлось выполнить две транзакции, чтобы воспроизвести поведение, которое можно было бы выполнить в одной транзакции, если бы платежи принимались в ETH.
Транзакция 1 — Дать разрешение контракту
Транзакция 2 — вызов функции контракта, которая внутри использует пособие для перевода токенов Боба на другой адрес.
Таким образом, если бы вы создавали dApp, где вам нужно, чтобы пользователи оплачивали ваш смарт-контракт с помощью токена ERC20, вам также нужно было бы заставить их выполнять обе транзакции. Простое обращение к функции вашего контракта без предварительного предоставления пользователями пособия вашему контракту приведет к сбою вызова функции.
Мы столкнемся с примером использования этого потока при создании биржи DeFi-Exchange на последнем уровне Sophomore track. Поскольку обмен подразумевает возможность конвертировать один токен в другой, вам нужно вызвать функцию на смарт-контракте обмена, которая принимает один токен и отдает вам другой.
Чтобы принять ваш токен для обмена, биржевой контракт требует одобрения на снятие токена с вашего счета.
Поэтому имейте в виду этот поток, если вам интересно, почему для обмена на бирже может использоваться две транзакции, а не одна.
Эта статья предоставлена LearnWeb3 DAO. Бесплатная, всеобъемлющая программа обучения блокчейну от А до Я для разработчиков по всему миру.
Все от «Что такое блокчейн» до «Взлома смарт-контрактов» — и все, что между ними, а также многое другое!
Присоединяйтесь к нам сейчас, чтобы начать строить вместе с 25 000+ разработчиками.
Сайт
Discord
Twitter