Практическое введение в web3.js

Добро пожаловать в очередной выпуск серии Learn Solidity. В прошлой статье мы увидели, как реализовать фабричный паттерн. Если вы подписались на эту серию с начала, значит, вы освоили основы и можете приступить к написанию собственных смарт-контрактов.

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

Прежде чем углубляться в детали того, что такое web3.js и как он работает, я хотел бы настроить контекст и начать с ответа на простой вопрос: почему именно web3.js?

Децентрализованное приложение состоит из трех основных компонентов:

  • Внешний интерфейс: принимает входные данные от пользователя и создает запросы для отправки в смарт-контракты.
  • Кошелек: подписывает транзакции и отправляет их в сеть.
  • Смарт-контракты: Здесь вы пишете бизнес-логику децентрализованного приложения.

Теперь вопрос в том, как взаимодействовать со смарт-контрактами из внешнего интерфейса, используя только JavaScript.

До появления web3.js мы могли взаимодействовать со смарт-контрактами только через json-rpc API, предоставляемый узлом Ethereum, который действовал как сервер json-rpc. Это была непростая задача.

Но благодаря web3.js вам больше не нужно беспокоиться о низкоуровневых деталях вызовов JSON-RPC, поскольку он предоставляет абстракцию интерфейса Ethereum json-rpc. Таким образом, вы можете начать взаимодействие с узлом Ethereum, используя простой JavaScript. Проще говоря, web3.js предоставляет API-интерфейсы JSON-RPC как API-интерфейсы JavaScript.

Как работает web3.js

Как мы уже говорили ранее, для взаимодействия с сетью Ethereum нам нужно отправлять вызовы json-rpc на узел Ethereum, что и делает web3.js под капотом. Так как же это сделать?

Чтобы преобразовать код JavaScript в запросы json-rpc, web3.js использует то, что мы называем provider, который является объектом JavaScript, совместимым со спецификацией EIP 1193, и реализует метод request, отвечающий за создание вызов метода Ethereum RPC. Web3.js имеет собственную реализацию спецификации, упомянутой выше, и делает ее доступной в web3.providers, где вы можете получить доступ к трем следующим провайдерам, как указано в документации: HttpProvider, WebsocketProvider и IpcProvider.

Более подробную информацию об этих провайдерах можно найти в документации.

В других проектах также реализована эта спецификация, например MetaMask, который внедряет объект провайдера в браузер под window.ethereum. Старые версии Metamask использовались для внедрения экземпляра web3 в window.web3.

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

let web3 = new Web3(Web3.givenProvider || 'ws://some.local-or-remote.node:8546');

Здесь следует иметь в виду, что для web3.js требуется объект провайдера, настроенный с информацией о кошельке, который будет подписывать транзакцию и отправлять ее в сеть. Этот провайдер будет внедряться в браузер, если вы используете web3 во внешнем интерфейсе, или объект, который вы собираетесь создать самостоятельно, используя websocketprovider или IpcProvider.

Примечание: MetaMask использует Infura в качестве поставщика узлов. Вот почему вам не нужно устанавливать клиент Ethereum на свой компьютер, чтобы иметь возможность взаимодействовать с сетью Ethereum.

Краткий обзор API

web3.js разрешает связь не только с узлами Ethereum, но и с узлами Whisper и Swarm. Поставляется с пятью основными пакетами:

  • web3.eth: Позволяет взаимодействовать с блокчейном Ethereum и смарт-контрактами Ethereum.
  • web3.bzz: Позволяет взаимодействовать с Swarm, децентрализованным хранилищем файлов.
  • web3.shh: разрешает взаимодействие с протоколом Whisper для вещания.
  • web3.utils: Предоставляет служебные функции для децентрализованных приложений Ethereum, такие как преобразование строк в шестнадцатеричные литералы и значений Ether в Wei.
  • web3.*.net: позволяет взаимодействовать с сетевыми свойствами узла Ethereum, такими как идентификатор сети или количество пиров.

Создайте свое первое приложение с помощью web3.js

Теперь, когда у нас есть теория, давайте запачкаем руки и создадим наше первое приложение. В этом примере мы собираемся создать приложение для приветствия, которое хранит строку приветствия по умолчанию и позволяет пользователю обновлять ее. Для кошелька мы будем использовать MetaMask. Вы можете добавить расширение, перейдя по ссылке для скачивания на главной странице их сайта.

1. Создайте контракт и разверните его в сети.

Начните с создания в вашей рабочей области пустого проекта с именем greeting и инициализируйте его с помощью truffle init:

> mkdir greeting
> cd greeting
> truffle init

Я предполагаю, что вы уже установили Truffle. Если у вас его нет, вы можете получить его с помощью следующей команды:

npm install -g truffle

Откройте проект с помощью вашего любимого редактора кода (я использую VS Code). Затем отредактируйте файл truffle-config.js и обновите сети, указав IP-адрес и порт вашей сети Ethereum (для этого вы можете использовать Ganache). Вам также необходимо настроить версию компилятора для использования той версии, которую вы установили.
Если у вас еще нет компилятора Solidity, вы можете установить его с помощью следующей команды:

> npm install -g solc
// check the installed version
> solc --version

Теперь пора создать greeting контракт в каталоге вашего проекта. Введите следующую команду:

> truffle create contract Greeting

Скопируйте и вставьте следующий код:

Мы почти готовы. Нам просто нужно добавить 2_deploy_greeting.js файл миграции в папку migrations:

const Greeting = artifacts.require("Greeting");
module.exports = function (deployer) {
      deployer.deploy(Greeting);
};

Теперь вы можете скомпилировать и развернуть свой смарт-контракт в сети, используя:

> truffle compile
> truffle migrate

2. Подключите клиентскую часть к смарт-контракту.

  • Настроить переднюю часть

Создайте в проекте новую папку с именем client с файлами package.json и index.html:

> mkdir client
> cd client
> npm init -y
> touch index.html

Установите зависимости web3.js и lite-server:

> npm i web3 --save
> npm i lite-server --save-dev //for running a development server

Создайте новую папку с именем src и добавьте два сценария: index.js и utils.js. Вам также необходимо добавить два сценария в файл HTML с помощью тега script вместе со сценарием web3:

<script type="text/javascript" src="node_modules/web3/dist/web3.min.js"></script>
<script type="text/javascript" src="src/utils.js"></script>
<script type="text/javascript" src="src/index.js"></script>
  • Получите экземпляр web3

Если у вас есть web3.js в качестве зависимости в вашем проекте, все, что вам нужно сделать, это создать экземпляр объекта web3, используя экземпляр поставщика, чтобы пользоваться всем, что может предложить web3.

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

Откройте файл utils.js и добавьте эту функцию:

  • Создать экземпляр контракта

Как описано в документации, для создания экземпляра контракта нам понадобится ABI контракта и его адрес. Если вы посмотрите на артефакты в каталоге сборки, вы найдете файл с именем Greeting.json. Если вы откроете его, вы найдете много информации о контракте, включая имя контракта, ABI и т. Д. Если вы прокрутите до конца файла, вы найдете сетевое поле, содержащее идентификатор сетей, в которых Контракт развернут, и соответствующий адрес, который мы будем использовать для создания экземпляра контракта с помощью web3.

Создайте новую папку с именем contracts в папке client и скопируйте и вставьте файл Greeting.json. Вам также необходимо установить jQuery, чтобы иметь возможность читать содержимое файла JSON:

> npm i jquery

Во-первых, нам нужно получить идентификатор сети, к которой подключен MetaMask, используя web3.eth.net.getId().

Примечание. Я предполагаю, что вы уже настроили MetaMask для использования Ganache. Если вы не знаете, как это сделать, следуйте этому руководству.

Затем мы будем использовать возвращенный идентификатор, чтобы получить адрес контракта из файла Greeting.json, который также предоставит нам ABI контракта и создаст экземпляр контракта, используя web3.eth.Contract:

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

После того, как мы создали экземпляр контракта, мы можем начать вызывать его методы, используя myContract.methods.myMethod([arguments]), как описано в документации.

Если вызываемая функция является чистой или доступной только для чтения, вам необходимо использовать:

myContract.methods.myMethod([arguments]).call()

Если вызываемая функция будет изменять состояние (также известное как транзакция), вам нужно будет использовать:

myContract.methods.myMethod([arguments]).send()

Более подробную информацию можно найти в документации.

Вы можете найти полный код на GitHub.

Заключение

Надеюсь, вам понравился этот урок. Если да, то оставайтесь здесь, потому что впереди еще много всего.