YouTube
Promo
banner
Promo
banner

Как получить и обновить данные из Ethereum с помощью React и SWR

блог 1НовостиДля разработчиковПредприятиеБлокчейн РазъяснениеМероприятия и конференцииПрессаИнформационные бюллетени

Подписывайтесь на нашу новостную рассылку.

Адрес электронной почты

Мы уважаем вашу конфиденциальность

ГлавнаяБлогРазработка блокчейна

Как получить и обновить данные из Ethereum с помощью React и SWR

Вот как настроить интерфейс вашего децентрализованного приложения таким образом, чтобы остатки токенов и переводы средств обновлялись в кошельках Ethereum ваших пользователей. Автор: Лоренцо Сицилия, 18 июня 2020 г.Опубликовано 18 июня 2020 г.

получить данные с помощью Ethereum Hero

Ethereum позволяет нам создавать децентрализованные приложения (dapps). Основное различие между типичным приложением и децентрализованным приложением заключается в том, что вам не нужно развертывать серверную часть – по крайней мере, пока вы используете преимущества других смарт-контрактов, развернутых в основной сети Ethereum..

Из-за этого интерфейс играет важную роль. Он отвечает за маршалинг и демаршалинг данных из смарт-контрактов, обработку взаимодействия с кошельком (аппаратным или программным) и, как обычно, управление UX. Мало того, что по дизайну dapp использует вызовы JSON-RPC и может открывать соединение сокета для получения обновлений..

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

Предпосылки

Во время этого урока я предполагаю, что у вас уже есть следующее:

Кошелек для подключения к узлу Geth

Самый простой подход – установка MetaMask так что вы можете использовать Инфура инфраструктура из коробки.

Немного эфира в вашем аккаунте

Когда вы разрабатываете с Ethereum, я настоятельно рекомендую вам перейти на тестовую сеть и использовать тестовый эфир. Если вам нужны средства для тестирования, вы можете использовать кран, например. https://faucet.rinkeby.io/

Базовое понимание React

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

Рабочая площадка на React

Я написал это руководство с помощью Typescript, но набрано всего несколько вещей, поэтому с минимальными изменениями вы можете использовать его, как и в Javascript. я использовал Parcel.js но не стесняйтесь использовать Создать приложение React тоже или другой сборщик веб-приложений.

Подключиться к основной сети Ethereum

Когда у вас будет готов MetaMask, мы будем использовать web3-реагировать для обработки взаимодействия с сетью. Это даст вам довольно удобный крючок useWeb3React, который содержит множество полезных утилит для игры с Ethereum..

пряжа добавить @ web3-react / core @ web3-response / injected-connector Язык кода: CSS (css)

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

Мы будем использовать Web3Provider от Ether.js.

Вроде уже есть несколько библиотек, но при взаимодействии с Ethereum нужно переводить типы данных Javascript в Solidity. И вы также должны подписывать транзакции, когда хотите выполнить действие. Ether.js элегантно предоставляет эти функции.

пряжа добавить @ ethersproject / ProviderCode язык: CSS (css)

примечание: вышеупомянутый пакет Ether.js – это версия 5, которая сейчас бета.

После этого мы готовы набросать минимальный привет мир, чтобы проверить, есть ли у нас все, что нам нужно:

импортировать React из ‘response’ импортировать {Web3ReactProvider} из ‘@ web3-react / core’ import {Web3Provider} from ‘@ ethersproject / Provider’ import {useWeb3React} from ‘@ web3-response / core’ import {InjectedConnector} from ‘@ web3-react / injected-connector ‘export const injectedConnector = new InjectedConnector ({supportedChainIds: [1, // Mainet 3, // Ropsten 4, // Rinkeby 5, // Goerli 42, // Kovan],}) function getLibrary (поставщик: любой): Web3Provider {const library = new Web3Provider (provider) library.pollingInterval = 12000 return library} export const Wallet = () => {const {chainId, account, activate, active} = useWeb3React () const onClick = () => {активировать (injectedConnector)} return ( <div> <div>ChainId: {chainId} div> <div>Аккаунт: {account} div> {активен? ( <div>✅ div> ): ( <тип кнопки ="кнопка" onClick = {onClick}> Кнопка подключения> )} div> )} экспорт const App = () => { возвращаться ( <Web3ReactProvider getLibrary = {getLibrary}> <Бумажник /> Web3ReactProvider> )} Язык кода: JavaScript (javascript)

Если вы сделали домашнее задание, у вас должно получиться что-то вроде этого:

Инжектированный разъем.

Вот что мы сделали до сих пор: GIT – шаг-1

Как получить данные из основной сети

я буду использовать КСВ управлять получением данных.

Это то, чего я хочу достичь.

const {данные: баланс} = useSWR (["getBalance", учетная запись, "самый последний"]) Язык кода: JavaScript (javascript)

Довольно круто &# 128578;

Давайте раскроем фокус! SWR означает Stale-While-Revalidate, стратегию аннулирования HTTP-кеша, популяризированную RFC 5861.

SWR сначала возвращает данные из кеша (устаревшие), затем отправляет запрос на выборку (повторная проверка) и, наконец, снова возвращает актуальные данные.

SWR принимает ключ и за кулисами сумеет разрешить

Для этого SWR позволяет передавать сборщик, способный разрешить ключ, возвращая обещание. Привет, мир SWR основан на запросах REST API с сборщиком на основе fetch API или Axios..

Что замечательно в SWR, так это то, что единственное требование для создания сборщика – он должен возвращать обещание..

Итак, вот моя первая реализация сборщика для Ethereum:

const fetcher = (библиотека) => (… аргументы) => {const [method, … params] = args console.log (method, params) return library [method] (… params)} Язык кода: JavaScript (javascript)

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

Теперь я могу создать свой компонент

экспорт const Balance = () => {const {account, library} = useWeb3React () const {data: balance} = useSWR ([‘getBalance’, account, ‘latest’], {fetcher: fetcher (library),}) if (! balance) {return <div>…div> } возвращаться <div>Баланс: {balance.toString ()} div> } Язык кода: JavaScript (javascript)

Возвращенный объект баланса – BigNumber..

Компонент баланса.

Как видите, номер не форматированный и очень большой. Это связано с тем, что в Solidity используется целое число до 256 бит..

Для отображения числа в удобочитаемом формате решение использует одну из вышеупомянутых утилит из утилит Ether.js: formatEther (баланс)

yarn install @ ethersproject / units Язык кода: CSS (css)

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

экспорт const Balance = () => {const {account, library} = useWeb3React () const {data: balance} = useSWR ([‘getBalance’, account, ‘latest’], {fetcher: fetcher (library),}) if (! balance) {return <div>…div> } возвращаться <div>Ξ {parseFloat (formatEther (баланс)). ToPrecision (4)} div> } Язык кода: JavaScript (javascript) BitInt в удобочитаемой форме.

это то, что мы сделали до сих пор: GIT шаг-2

Как обновить данные в режиме реального времени

SWR предоставляет функцию изменения для обновления своего внутреннего кеша.

const {data: balance, mutate} = useSWR ([‘getBalance’, account, ‘latest’], {fetcher: fetcher (library),}) const onClick = () => {mutate (new BigNumber (10), false)} Язык кода: JavaScript (javascript)

Функция mutate автоматически привязывается к ключу (например, [‘getBalance’, account, ‘latest’], из которого она была сгенерирована. Она принимает два параметра. Новые данные и должна ли быть запущена проверка. Если необходимо, SWR будет автоматически использовать сборщик для обновления кеша &# 128165;

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

Ether.js имеет простой API для подписки на событие:

const {account, library} = useWeb3React () library.on ("blockNumber", (blockNumber) => {console.log ({blockNumber})}) Язык кода: JavaScript (javascript)

Теперь давайте объединим оба подхода в новом компоненте.

экспорт const Balance = () => {const {account, library} = useWeb3React () const {data: balance, mutate} = useSWR ([‘getBalance’, account, ‘latest’], {fetcher: fetcher (library),}) useEffect (() => {// прослушиваем изменения в адресе Ethereum console.log (`прослушивание блоков …`) library.on (‘block’, () => {console.log (‘обновить баланс …’) mutate (undefined, true)}) // удалить слушателя, когда компонент отключен return () => {library.removeAllListeners (‘block’)} // запускает эффект только при монтировании компонента}, []) if (! balance) {return <div>…div> } возвращаться <div>Ξ {parseFloat (formatEther (баланс)). ToPrecision (4)} div> } Язык кода: JavaScript (javascript)

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

примечание: мы использовали mutate (undefined, true), потому что мы не можем получить из текущего события фактический баланс, мы просто запускаем повторное получение баланса.

Ниже представлена ​​быстрая демонстрация с двумя кошельками Ethereum, которые обменивают немного ETH..

Демо-версия двух кошельков Ethereum, обменивающих ETH.

Вот что мы сделали до сих пор: GIT шаг-3

Как взаимодействовать со смарт-контрактом

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

Ether.js обрабатывает взаимодействие смарт-контрактов с помощью ABI-интерфейса приложения контракта (ABI), созданного компилятором Solidity..

Двоичный интерфейс приложения контракта (ABI) – это стандартный способ взаимодействия с контрактами в экосистеме Ethereum как извне блокчейна, так и для взаимодействия между контрактами..

Например, учитывая простой смарт-контракт ниже:

прагма solidity ^ 0.5.0; контракт Test {constructor () public {b = hex"12345678901234567890123456789012"; } событие Событие (uint проиндексировано a, bytes32 b); событие Event2 (uint проиндексировано a, bytes32 b); функция foo (uint a) public {emit Event (a, b); } bytes32 b; } Язык кода: JavaScript (javascript)

это сгенерированный ABI

[{ "тип": "мероприятие", "входы": [{ "имя": "а", "тип": "uint256", "проиндексирован": истинный }, { "имя": "б", "тип": "байт32", "проиндексирован": ложный } ], "имя": "Мероприятие" }, { "тип": "мероприятие", "входы": [{ "имя": "а", "тип": "uint256", "проиндексирован": истинный }, { "имя": "б", "тип": "байт32", "проиндексирован": ложный } ], "имя": "Событие2" }, { "тип": "функция", "входы": [{ "имя": "а", "тип": "uint256" }], "имя": "фу", "выходы": []}] Язык кода: JSON / JSON с комментариями (json)

Чтобы использовать ABI, мы можем просто скопировать их прямо в ваш код и импортировать там, где это необходимо. В этой демонстрации мы будем использовать стандартный ERC20 ABI, потому что мы хотим получить балансы двух токенов: DAI и MKR.

Следующий шаг – создание компонента

экспорт const TokenBalance = ({символ, адрес, десятичные дроби}) => {const {account, library} = useWeb3React () const {data: balance, mutate} = useSWR ([адрес, ‘balanceOf’, account], {fetcher: fetcher (library, ERC20ABI),}) useEffect (() => {// прослушиваем изменения в адресе Ethereum console.log (`прослушивание передачи …`) const contract = new Contract (address, ERC20ABI, library.getSigner ()) const fromMe = contract.filters.Transfer (account, null) library.on (fromMe, (от, до, сумма, событие) => {console.log (‘Transfer | sent’, {from, to, amount, event}) mutate (undefined, true)}) const toMe = contract.filters.Transfer (null, account) library.on (toMe, (from , к, сумма, событие) => {console.log (‘Transfer | Received’, {from, to, amount, event}) mutate (undefined, true)}) // удаляем слушателя, когда компонент отключен return () => {library.removeAllListeners (toMe) library.removeAllListeners (fromMe)} // запускает эффект только при монтировании компонента}, []) if (! balance) {return <div>…div> } возвращаться ( <div> {parseFloat (formatUnits (баланс, десятичные числа)). toPrecision (4)} {symbol} div> )} Язык кода: JavaScript (javascript)

Давайте увеличим масштаб. Есть два основных отличия:

Ключевое определение

Ключ, используемый useSWR ([адрес, ‘balanceOf’, account])), должен начинаться с адреса Ethereum, а не с метода. Благодаря этому сборщик может распознать, чего мы хотим достичь, и использовать ABI..

Давайте соответствующим образом реорганизуем сборщик:

const fetcher = (библиотека: Web3Provider, abi ?: любой) => (… аргументы) => {const [arg1, arg2, … params] = args // это контракт if (isAddress (arg1)) {const address = arg1 const method = arg2 const contract = new Contract (address, abi, library.getSigner () ) return contract [method] (… params)} // это вызов eth const method = arg1 return library [method] (arg2, … params)} Язык кода: JavaScript (javascript)

Теперь у нас есть сборщик общего назначения, способный взаимодействовать с вызовами JSON-RPC Ethereum.. &# 128588;

Фильтры журнала

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

const contract = new Contract (адрес, ERC20ABI, library.getSigner ()) const fromMe = contract.filters.Transfer (account, null) Язык кода: JavaScript (javascript)

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

Предупреждение:

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

Помните о драконе. Когда вы настраиваете сборщик, вы передали закрытие в качестве обратного вызова функции on, которая содержала значение баланса на тот момент.

Это можно исправить с помощью useRef, но для простоты давайте повторно проверим кеш, чтобы убедиться, что балансы свежие: mutate (undefined, true)

Теперь у нас есть все необходимые детали. Последний кусочек – немного клея.

Я настроил несколько констант, чтобы иметь хороший способ сопоставить мой компонент TokenBalance со списком токенов в зависимости от сети, в которой мы работаем:

export const Networks = {MainNet: 1, Rinkeby: 4, Ropsten: 3, Kovan: 42,} интерфейс экспорта IERC20 {символ: адрес строки: десятичные дроби: число имя: строка} экспорт const TOKENS_BY_NETWORK: {[ключ: число]: IERC20 []} = {[Networks.Rinkeby]: [{адрес: "0x5592EC0cfb4dbc12D3aB100b257153436a1f0FEa", символ: "DAI", имя: "Дай", десятичные дроби: 18,}, {адрес: "0xF9bA5210F91D0474bd1e1DcDAeC4C58E359AaD85", символ: "MKR", имя: "Производитель", десятичные дроби: 18,},],} Язык кода: JavaScript (javascript)

Когда у нас есть константы, легко сопоставить настроенные токены с моим компонентом:

экспорт const TokenList = ({chainId}) => { возвращаться ( <> {TOKENS_BY_NETWORK [chainId] .map ((токен) => ( <Ключ TokenBalance = {token.address} {… token} /> ))})} Язык кода: JavaScript (javascript)

Все готово! Теперь у нас есть кошелек Ethereum, который загружает баланс эфира и токенов. И если пользователь отправляет или получает средства, пользовательский интерфейс кошелька обновляется..

Кошелек Ethereum, который загружает баланс эфира и токенов.

Вот что мы сделали на данный момент: GIT шаг-4

Рефакторинг

Давайте переместим каждый компонент в отдельный файл и сделаем сборщик глобально доступным с помощью поставщика SWRConfig..

<Значение SWRConfig = {{сборщик: сборщик (библиотека, ERC20ABI)}}> <EthBalance /> <TokenList chainId = {chainId} /> <SWRConfig />Язык кода: HTML, XML (xml)

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

const {data: balance, mutate} = useSWR ([адрес, ‘balanceOf’, account]) Язык кода: JavaScript (javascript)

Вот все после рефакторинга: GIT, шаг 5

Заворачивать

КСВ и Ether.js две хорошие библиотеки, с которыми можно работать, если вы хотите оптимизировать свою стратегию получения данных с помощью Ethereum dapp..

Ключевые преимущества
  • Декларативный подход
  • Всегда свежие данные через веб-сокеты или параметры SWR
  • Избегайте изобретать колесо для управления состоянием с помощью настраиваемого контекста React

Если вы используете несколько смарт-контрактов в своем децентрализованном приложении и вам понравился этот урок, я обобщил сборщик web3 в небольшую утилиту: swr-eth (Звезды ценятся &# 128123;)

И, наконец, вот полный репозиторий GIT: (https://github.com/aboutlo/swr-eth-tutorial).

Получите больше руководств по Ethereum прямо в свой почтовый ящик

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

Как создать успешный блокчейн-продукт

Как настроить и запустить узел EthereumВебинар

Как настроить и запустить узел Ethereum

Как создать собственный API EthereumВебинар

Как создать собственный API Ethereum

Как создать социальный токенВебинар

Как создать социальный токен

Использование инструментов безопасности при разработке смарт-контрактовВебинар

Использование инструментов безопасности при разработке смарт-контрактов

Будущее финансовых цифровых активов и DeFiВебинар

Будущее финансов: цифровые активы и DeFi