Взаимодействие со смарт-контрактами с использованием Web3.js (часть I)

Платформа Web3.JS позволяет разработчикам взаимодействовать с Ethereum смарт-контрактами, используя Javascript Node.js. Фреймворк состоит из модулей с определенными функциями:

  • web3-eth предназначен для блокчейна и смарт-контрактов.
  • web3-shh предназначен для протокола шепота, для связи p2p и широковещательной передачи.
  • web3-bzz - это протокол роя, децентрализованное хранилище файлов.
  • web3-utils содержит полезные вспомогательные функции для разработчиков DApp (децентрализованных приложений).

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

Начиная

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

  • Node.js - его необходимо установить для конкретной используемой операционной системы. Настоятельно рекомендуется использовать версию LTS (доступны версии для Linux, macOS и Windows).
  • Web3.js. Установите Web3.js с помощью npm или yarn из папки проекта консоли терминала.
  • Подключение к узлу Ethereum - для этого требуется либо локальный узел (например, Ganache), либо подключение к действующему узлу в сети (например, Infura). Тем, кто хочет протестировать в сети, рекомендую использовать шлюз Infura.

Объект Web3

Объект web3 - это главный класс фреймворка. Для вызова любой функции необходимо использовать объект web3.

web3.<name of function or call>

Сначала необходимо создать новый экземпляр объекта. В приглашении узла на консоли терминала:

> const Web3 = require('web3')

Теперь, когда мы создали экземпляр объекта, мы должны создать поставщика, который создает экземпляр объекта Web3, который подключается к сети Ethereum. Есть несколько типов сетей.

(Обратите внимание, что это заглавная буква "W" для провайдера Web3)

  • Основная сеть Ethereum или основная сеть (активный блокчейн, используемый для ETH)
  • Тестовые сети (например, Кован, Ринкеби, Ропстен, Гёрли)
  • Провайдеры Web3 (например, с использованием порта 7545 на локальном хосте или удаленном сервере)
  • Внедренный Web3 (например, Infura Gateway)

В этом примере будет использоваться конечная точка Infura. Это URL-адрес, предоставляемый Infura при создании проекта. Это должно быть создано до того, как будет выдан URL-адрес.

Примечание. Указанный URL-адрес является лишь примером и не должен использоваться в реальной производственной или тестовой среде.

> const web3 = new Web3('https://ropsten.infura.io/v3/76162cfy074u522fa49be7ca11cc9a33')

Когда вы вызываете объект Web3, он возвращает функциональные возможности объекта. Вот фрагмент возвращенных результатов (см. Снимок экрана):

> Web3

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

Это показывает содержимое модулей библиотеки. В блокчейне Ethereum используются функции и поддерживаемые единицы (например, wei). Это то, чему должны следовать разработчики, чтобы взаимодействовать с блокчейном. Вы не можете отправлять транзакции, если эти соглашения не соблюдаются должным образом, поэтому они похожи на правила, касающиеся транзакций для смарт-контрактов. Разработчики могут ссылаться на них при написании заявлений.

Работа с аккаунтами Ethereum

Одно из основных применений Web3.js - работа с учетными записями. Допустим, мы хотим создать новую учетную запись в блокчейне Ethereum. Мы можем сделать это, выполнив команду, и возвращенный результат будет полностью функциональной учетной записью, которую может использовать пользователь, с публичным адресом и закрытым ключом.

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

> web3.eth.accounts.create();
{
    address: "0xb8CE9ab6943e1eCED004cDe8e3bBed6568c2Fv01",
    privateKey: "0x348ce564d427a3311b6546bbcff9390d69395b06ed6c486954e971d860fe8709",
    signTransaction: function(tx){...},
    sign: function(data){...},
    encrypt: function(password){...}
}

Вы создаете учетную запись с адресом Ethereum:

0xb8CE9ab6943e1eCED004cDe8e3bBed6568c2Fv01

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

У учетной записи также есть закрытый ключ. Это очень важно, потому что закрытый ключ - это то, что обеспечивает авторизацию пользователя для учетной записи.

0x348ce564d427a3311b6546bbcff9390d69395b06ed6c486954e971d860fe8709

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

Точно так же вы можете получить адрес из закрытого ключа с помощью функции privateKeyToAccount ().

> web3.eth.accounts.privateKeyToAccount('0x348ce564d427a3311b6546bbcff9390d69395b06ed6c486954e971d860fe8709');
{
    address: '0xb8CE9ab6943e1eCED004cDe8e3bBed6568c2Fv01',
    privateKey: '0x348ce564d427a3311b6546bbcff9390d69395b06ed6c486954e971d860fe8709',
    signTransaction: function(tx){...},
    sign: function(data){...},
    encrypt: function(password){...}
}

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

Запрос блокчейна

Разработчики могут использовать пакет web3-eth для запроса информации из цепочки блоков. Это не потребует каких-либо затрат на использование газа, потому что эти вызовы не изменяют состояние. Они просто считывают данные, а не записывают данные в цепочку блоков.

Чтобы получить баланс со счета, используйте функцию getBalance () с адресом в качестве параметра.

> web3.eth.getBalance('0x6e35A20a740bC7288bdec5d4E138a253D4A72660') .then(console.log)
Promise { <pending> }
> 5984521207000000000

Баланс счета возвращается в wei, что является наименьшим номиналом эфира. Есть еще один способ получить баланс в ETH или эфире, но для этого требуется вызов функции web.utils. Ниже приводится пример:

> web3.eth.getBalance('0x6e35A20a740bC7288bdec5d4E138a253D4A72660', (call, wei) => { balance = web3.utils.fromWei(wei, 'ether')})
Promise { <pending> }
> balance
'5.984521207'

Как видите, для этого требуется использование оператора с вызовом функции, которая переводит результат getBalance в переменный баланс с преобразованием из wei в эфир. Результат - 5,98, выраженный в эфире.

Выполнение транзакции

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

Используемые функции будут взяты из библиотеки EthereumJS. Прежде чем продолжить, убедитесь, что ethereumjs-tx установлен.

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

Вот следующий код для app.js:

Примечание. Это только пример. Закрытые ключи не раскрываются в демонстрационных целях.

const Tx = require('ethereumjs-tx').Transaction
const Web3 = require('web3')
const web3 = new Web3('<endpoint>')
const account1 = '<address 1>'
const account2 = '<address 2>'
const privateKey1 = Buffer.from('<private key 1>', 'hex')
const privateKey2 = Buffer.from('<private key 2>', 'hex')
web3.eth.getTransactionCount(account1, (err, txCount) => {
// Build a transaction
const txObject = {
     nonce: web3.utils.toHex(txCount),
     to: account2,
     value: web3.utils.toHex(web3.utils.toWei('1', 'ether')),
     gasLimit: web3.utils.toHex(21000),
     gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei'))
}
// Sign the transaction
const tx = new Tx(txObject, { chain: 'ropsten' })
tx.sign(privateKey1)
const serializedTransaction = tx.serialize()
const raw = '0x' + serializedTransaction.toString('hex')
// Broadcast the transaction
web3.eth.sendSignedTransaction(raw, (err, txHash) => {
     console.log('txHash: ', txHash)
     console.log(err)
    })
})

Приложение будет переводить сумму в 1 эфир (1 ETH) с учетной записи пользователя 1 на учетную запись 2. В сделке учитывается стоимость газа в 10 gwei и лимит 21000 wei. Одноразовый номер указывает значение счетчика транзакций. Эти значения необходимо преобразовать в шестнадцатеричные, поэтому мы используем функцию web3.utils.toHex ().

На самом деле создание транзакции состоит из 3 частей.

Сначала мы строим транзакцию, используя следующую структуру данных:

     nonce: web3.utils.toHex(txCount),
     to: account2,
     value: web3.utils.toHex(web3.utils.toWei('1', 'ether')),
     gasLimit: web3.utils.toHex(21000),
     gasPrice: web3.utils.toHex(web3.utils.toWei('10', 'gwei'))

Это наш объект транзакции, который будет отправлен в блокчейн Ethereum.

Затем транзакция должна быть подписана отправляющим ее пользователем account1.

tx.sign(privateKey1)

В функцию tx.sign () передается значение закрытого ключа пользователя. Это авторизует транзакцию с момента ее подписания.

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

В конце был добавлен консольный журнал, чтобы мы могли видеть возвращаемый результат, что важно (будет объяснено позже).

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

$ node app.js
txHash:  0x92c0c7d98b0a13f157ed6e4d6aaf28c4525c55c354a3792e097b91c2fafc8e80

Здесь важен результат, потому что он покажет, была ли транзакция обработана успешно. Если вы получили значение txHash, значит, это успех. В противном случае в коде есть ошибки, которые необходимо исправить.

Чтобы проверить транзакцию, откройте обозреватель цепочки блоков для сети провайдера, которую вы использовали (например, Ethereum). Посмотрите на хеш-значение транзакции, и он вернет детали транзакции.

Синопсис

Web3.js предоставляет разработчикам приложений возможность создавать DApps и интерфейсы. Это способ обеспечить функциональность внешнего интерфейса в сети, которая может взаимодействовать со смарт-контрактами и блокчейном Ethereum.

Продолжение следует… (см. Часть II)