Что такое провайдеры и подписывающие лица? Что такое ABI? Что такое BigNumbers? Как контракты работают с токенами ERC-20?


Смешанные темы для второкурсников

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

Оглавление

  • Провайдеры и подписывающие лица
  • 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

Оцените статью
Procodings.ru
Добавить комментарий