Обзор самых крутых частей eth-hot-wallet

Эта статья представляет собой технический обзор интересных частей eth-hot-wallet, веб-приложения Ethereum wallet с встроенной поддержкой токена erc20. Исходный код можно найти на GitHub (лицензия MIT).

Содержание:

  • Кошелек Ethereum как веб-приложение
  • Стек
  • Контейнеры eth-hot-wallet
  • Единый дизайн кошелька Ethereum
  • Redux и Redux-Saga
  • Безопасный генератор паролей
  • eth-lightwallet и SignerProvider
  • Зашифрованное автономное хранилище
  • Отправка Ethereum с помощью Web3.js
  • Отправка токенов erc20 с помощью Web3.js
  • Подписка на жизненный цикл транзакции Ethereum с использованием каналов Web3.js V1 и Redux-Saga
  • Опрос блокчейна Ethereum и данных о ценах с помощью Redux-Saga
  • Следите за размером связки
  • Заключение

Кошелек Ethereum как веб-приложение

Когда программное обеспечение развертывается в виде веб-приложения, первое, что приходит на ум, - это широкая доступность. В конце концов, Интернет - это наиболее доступная платформа для кросс-устройств. Eth-hot-wallet - это PWA (прогрессивное веб-приложение), которое можно использовать из любого современного веб-браузера.

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

Плюсы:

  • Никакого дополнительного программного обеспечения не требуется
  • Никакой установки не требуется
  • Умение использовать современные инструменты веб-разработки.
  • Легко развернуть и обновить

Минусы:

  • Более подвержен фишинговым атакам.
  • Плагины браузера могут внедрять на страницу вредоносный код.
  • Большое время загрузки при медленном интернет-соединении
  • Ограниченный доступ к хранилищу устройства

Тот факт, что вредоносные расширения браузера могут внедрить код JavaScript при попытке извлечь ключи, имеет большое значение. Чтобы перенести этот риск, пользователя следует поощрять отключать расширения (т. Е. Использовать в режиме инкогнито) или интегрировать Интернет с внешним провайдером web3, таким как MetaMask или Trust browser. Преобразование веб-приложения в настольное приложение также является жизнеспособным вариантом.

Что касается фишинга, следует поощрять пользователя сделать закладку на странице и получить к ней доступ через поиск Google. Маловероятно, что фишинговый сайт окажется выше реального сайта в результатах поиска.

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

Стек

Большая часть кода предназначена для внешнего интерфейса:

Последний пакет состоит из множества пакетов, как показано в package.json.

Компоненты верхнего уровня включают:

И для серверной части:

Последний пакет развертывается непосредственно на страницах GitHub из специальной ветки в репозитории. В традиционной сцене нет необходимости в серверной части.

Для создания сборщика Ethereum Testnet мы будем использовать Serverless framework. Это значительно улучшает опыт разработчиков при использовании AWS Lambda. Это очень экономичное решение, которое избавляет от необходимости поддерживать инфраструктуру, особенно для приложений с небольшим объемом.

Контейнеры eth-hot-wallet

При использовании комбинации React, Redux, Saga.js и Reselect каждый контейнер (может) состоять из следующих ингредиентов:

  • index.js - для рендеринга графического интерфейса
  • actions.js
  • reducer.js
  • saga.js
  • selectors.js
  • constants.js

Как заявил Дэн Абрамов, существует несколько подходов к тому, использовать ли компонент или контейнер. По моему опыту, если компонент имеет более ~ 8 атрибутов внутри состояния приложения, его следует выделить в новый контейнер. Это просто практическое правило. Количество атрибутов со временем может увеличиваться. Для сложных компонентов лучше иметь уникальный контейнер, чем кластеризовать состояние основного контейнера.

Не в каждом контейнере должны быть все ингредиенты. В eth-hot-wallet sendTokencontainer не использует собственный Saga.js. Мы разделили его, чтобы не перегружать состояние компонента домашней страницы.

Контейнер домашней страницы

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

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

Контейнер заголовка

Заголовок демонстрирует тот факт, что контейнер - это намного больше, чем просто компонент графического интерфейса:

Сначала этот контейнер может показаться простым, только с логотипом и переключателем сети. Должен ли он вообще быть в собственном контейнере? Ответ заключается в том, что в eth-hot-wallet каждое действие, связанное с сетевым взаимодействием, и управление состоянием выполняется внутри контейнера заголовка. Более чем достаточно для любой тары.

Контейнер SendToken

SendToken - это модальное окно, которое появляется, когда пользователь выбирает отправку Ether / токенов.

Модальное окно включает в себя базовую проверку ввода, такую ​​как проверка суммы и адреса Ethereum. Он не использует Saga.js для инициирования побочных эффектов, а вместо этого использует действия, предоставляемые контейнерами домашней страницы и заголовка.

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

Контейнер TokenChooser

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

Имя TokenChooser было выбрано, чтобы не путать с термином селектор, который много раз встречается в коде кошелька в другом контексте (reduxjs / Reselect: библиотека селекторов для Redux).

Как и в случае с контейнером SendToken, TokenChooser не использует собственный файл Saga.js, но при необходимости вызывает действия из контейнера домашней страницы.

Единый дизайн кошелька Ethereum

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

Под капотом API для отправки эфира и отправки токенов совершенно другой. Так же проверяется баланс, но в графическом интерфейсе они будут отображаться одинаково.

Чтобы отправить эфир, нам нужно использовать собственные функции, предоставляемые библиотекой web3.js, а отправка токенов и проверка балансов предполагает взаимодействие со смарт-контрактом. Подробнее об этом позже.

Redux и Redux-Saga

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

Помимо сохранения состояния пользовательского интерфейса, хранилище Redux также содержит объект хранилища ключей (частично зашифрованный объект JavaScript, предоставляемый eth-lightwallet). Это делает хранилище ключей доступным для всего приложения с помощью селектора.

Redux-Saga - вот что заставляет сиять всю установку.

redux-saga - это библиотека, которая призвана упростить управление побочными эффектами приложений (т.

Saga.js использует генераторы, чтобы сделать асинхронные потоки удобными для чтения и записи. Таким образом, эти асинхронные потоки выглядят как ваш стандартный синхронный код JavaScript (вроде как _6 _ / _ 7_, но с большим количеством параметров настройки).

В случае кошелька Ethereum с помощью Saga мы получаем удобный способ обработки асинхронных действий, таких как вызовы API отдыха, действия хранилища ключей, вызовы блокчейна Ethereum через web3.js и многое другое. Все запросы обрабатываются в одном месте, без обратных вызовов и очень интуитивно понятный API.

Пример использования redux-saga:

Безопасный генератор паролей

Чтобы надежно защитить хранилище ключей пользователя, нам необходимо зашифровать его надежным паролем. При использовании eth-lightwallet пароль необходимо предоставить во время запуска hd-кошелька.

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

Если пользователь хочет создать новый кошелек, мы создадим следующие параметры:

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

generateString реализация: мы будем использовать относительно новый window.crypto API для получения случайных значений (в настоящее время поддерживается всеми основными браузерами).

Реализация Eth-hot-wallet основана на следующем коде для генерации случайных, но удобочитаемых строк:

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

eth-lightwallet и SignerProvider

  1. LightWallet предназначен в качестве поставщика подписи для подключенного провайдера Web3.
  2. Подключенный провайдер Web3 устарел, и в настоящее время автор рекомендует пакет ethjs-provider-signer в качестве альтернативы.
  3. На момент написания в ethjs-provider-signer есть ошибка, которая не позволяет отображать сообщения об ошибках. Ошибка была исправлена, но не слилась обратно в основную ветку. Эти сообщения об ошибках имеют решающее значение для правильной работы этой настройки.

Итог: используйте eth-lightwallet с этой версией ethjs-provider-signer: https://github.com/ethjs/ethjs-provider-signer/pull/3, чтобы сэкономить время на пробной версии. и ошибка.

Зашифрованное автономное хранилище

JSON-объект хранилища ключей Lightwallet зашифрован, и для безопасного хранения ключа шифрования от нас требуется внешний passwordProvider. Объект keystrore всегда зашифрован. Приложение отвечает за сохранность пароля и предоставляет ему любые действия.

eth-hot-wallet использует Store.js - кроссбраузерное хранилище для всех вариантов использования, используемых в Интернете. Store.js позволяет нам легко хранить зашифрованное хранилище ключей и извлекать его обратно из хранилища при доступе к веб-странице.

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

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

Отправка Ethereum с помощью Web3.js

При использовании [email protected] функция sendTransaction предоставляется в следующей форме:

web3.eth.sendTransaction(transactionObject [, callback])

Обратный вызов вернет TX как результат в случае успеха.

Однако, чтобы правильно интегрировать его в наш поток saga.js, нам нужно обернуть sendTransaction функцию обещанием:

Таким образом мы продолжаем обычное выполнение Saga.js после вызова sendTransaction.

Отправка токенов erc20 с помощью Web3.js

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

Когда мы отправляем токен в Ethereum, мы взаимодействуем со смарт-контрактом. Чтобы взаимодействовать со смарт-контрактом, нам необходимо знать его API, формат для обмена API контракта, называемый Ethereum Contract ABI.

Мы сохраним erc20 ABI как часть нашего пакета JavaScript и создадим экземпляр контракта во время выполнения программы:

const erc20Contract = web3.eth.contract(erc20Abi);

После настройки контракта мы можем легко взаимодействовать с ним программно, используя API контракта Web3.js.

Для каждого токена нам понадобится отдельный экземпляр контракта:

const tokenContract = erc20Contract.at(tokenContractAddress);

После создания экземпляра контракта мы можем получить доступ к функциям контракта, вызвав нужную функцию прямо из JavaScript:

См. API контрактов Web3.js для получения полной информации.

Мы обещаем tokenContract.transfer.sendTransaction использовать его с нашим потоком redux-saga:

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

Подписка на жизненный цикл транзакции Ethereum с использованием каналов Web3.js V1 и redux-saga

eth-hot-wallet использует web3.js v0.2.x и в настоящее время не поддерживает эту функцию. Пример предоставлен другим проектом. Это важная функция, и ее следует широко использовать.

Новая версия Web3.js (V1.0.0) поставляется с API нового контракта, который может информировать нас об изменениях жизненного цикла транзакции.

Введите PromiEvent: генератор комбинированных событий обещания.

web3.eth.sendTransaction({...})
.once('transactionHash', function(hash){ ... })
.once('receipt', function(receipt){ ... })
.on('confirmation', function(number, receipt){ ... })
.on('error', function(error){ ... })
.then(function(receipt){
    //fired once the receipt is mined
});

web3.eth.sendTransaction() вернет объект (обещание), который разрешится после добычи транзакции. Тот же объект позволит нам подписаться на события ‘transactionHash’, ‘receipt’, ‘confirmation’ и ‘error’.

Этот API гораздо информативнее и элегантнее, чем тот, который предоставляется с версией Web3.js 0.2.x. Мы увидим, как мы можем интегрировать его в наше веб-приложение с помощью каналов Saga.js. Мотивация состоит в том, чтобы обновить состояние приложения (хранилище Redux) после обнаружения изменения состояния транзакции.

В следующем примере мы создадим транзакцию «фиксация» для произвольного смарт-контракта и обновим состояние приложения, когда мы получим события ‘transactionHash’, ‘receipt’ и ‘error’.

Нам нужно инициализировать новый канал и разветвить обработчик:

Обработчик перехватит все события канала и вызовет соответствующий создатель действия Redux.

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

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

Полный исходный код этого примера можно найти здесь.

Опрос блокчейна Ethereum и данных о ценах с помощью redux-saga

Есть несколько способов следить за изменениями блокчейна. Можно использовать Web3.js для подписки на события или мы можем сами опросить блокчейн и иметь больший контроль над некоторыми аспектами опроса.

В eth-hot-wallet кошелек периодически опрашивает блокчейн на предмет изменений баланса и Coinmarketcap API на предмет изменения цен.

Этот шаблон redux-saga позволит нам опросить любой источник данных или API:

После того, как действие CHECK_BALANCES замечено сагой по умолчанию, вызывается функция checkAllBalances. Это может закончиться одним из двух возможных результатов: CHECK_BALANCES_SUCCESS или CHECK_BALANCES_ERROR. Каждый из них будет пойман watchPollData(), чтобы ждать X секунд и снова вызвать checkAllBalance. Эта процедура будет продолжаться до тех пор, пока STOP_POLL_BALANCES не будет обнаружен watchPollData. После этого можно возобновить опрос, повторно отправив действие CHECK_BALANCES.

Следите за размером связки

При создании веб-приложений с использованием JavaScript и npm может возникнуть соблазн добавить новые пакеты без анализа увеличения занимаемой площади. Eth-hot-wallet использует webpack-monitor для отображения диаграммы всех зависимостей и различий между каждой сборкой. Это позволяет разработчику четко видеть изменение размера пакета после добавления каждого нового пакета.

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

Webpack-monitor легко интегрируется, и его определенно стоит включить в любое веб-приложение на основе webpack.

Заключение

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

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



Если у вас есть какие-либо вопросы относительно eth-hot-wallet или любой другой связанной темы, не стесняйтесь обращаться ко мне через Twitter или открывать вопрос на GitHub.