Сравнение библиотек web3.js и ethers.js
Архитектура и подключение
Архитектурные различия
При создании децентрализованного приложения (dApp) выбор правильной JavaScript-библиотеки для взаимодействия с блокчейном Ethereum имеет решающее значение. Две основные библиотеки, web3.js и ethers.js, решают эту задачу по-разному, что напрямую влияет на структуру вашего кода.
Исторически web3.js использовала монолитный подход. Вы создавали один всемогущий объект web3, который совмещал в себе все: и подключение к сети для чтения данных, и возможность подписывать транзакции с помощью кошелька. Это было удобно для быстрого старта, но могло приводить к путанице в коде, где не всегда было очевидно, какая операция требует только чтения, а какая — подписи пользователя.
В то время как web3.js предоставляет единый инстанцированный объект web3 с методами для взаимодействия с блокчейном, ethers.js разделяет API на две отдельные роли.
Ethers.js, напротив, с самого начала строилась на принципах модульности и разделения ответственности. В ее архитектуре есть два четко разграниченных понятия: Provider и Signer.
- Provider — это ваше окно в мир блокчейна. Он предоставляет доступ только для чтения к данным: получение баланса, чтение информации из смарт-контрактов, просмотр истории транзакций. Провайдер не имеет доступа к приватным ключам и не может создавать транзакции.
- Signer — это абстракция над аккаунтом пользователя. Он наследует все методы
Provider, но дополнительно может подписывать транзакции и сообщения.Signer— это то, что позволяет вашему dApp инициировать операции, изменяющие состояние блокчейна (например, отправку токенов или вызов платной функции контракта).
Такое разделение делает код более предсказуемым и безопасным. Вы всегда точно знаете, какая часть вашего приложения имеет право тратить средства пользователя, а какая — только запрашивать публичную информацию.
Подключение к блокчейну
Первый шаг в любом dApp — установить соединение с узлом Ethereum. Это можно сделать с помощью публичных RPC-сервисов, таких как Infura или Alchemy. Это соединение позволяет вашему приложению читать данные из блокчейна.
В ethers.js для этого используется JsonRpcProvider. Вы просто передаете ему URL вашего RPC-сервиса.
// ethers.js
import { ethers } from "ethers";
// Подключение к основной сети Ethereum через Alchemy
const provider = new ethers.JsonRpcProvider("https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY");
const blockNumber = await provider.getBlockNumber();
console.log("Текущий номер блока:", blockNumber);
В web3.js процесс выглядит похоже. Вы создаете новый экземпляр класса Web3 и передаете ему URL провайдера.
// web3.js
import Web3 from "web3";
// Подключение к основной сети Ethereum через Alchemy
const web3 = new Web3("https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY");
const blockNumber = await web3.eth.getBlockNumber();
console.log("Текущий номер блока:", blockNumber);
Оба этих способа создают соединение только для чтения. Чтобы подписывать транзакции, нужно подключить кошелек.
Интеграция с кошельками
Чтобы dApp мог отправлять транзакции от имени пользователя, ему нужен доступ к кошельку, например, MetaMask. Браузерные кошельки "внедряют" в веб-страницу специальный объект — window.ethereum. Этот объект служит мостом между вашим сайтом и кошельком пользователя.
В ethers.js версии v6 для работы с браузерным кошельком используется BrowserProvider.
// ethers.js
import { ethers } from "ethers";
// 1. Создаем провайдер из объекта, внедренного кошельком
const provider = new ethers.BrowserProvider(window.ethereum);
// 2. Запрашиваем у пользователя разрешение на подключение
// и получаем Signer для подписи транзакций
const signer = await provider.getSigner();
// 3. Теперь можно отправлять транзакции
const tx = await signer.sendTransaction({
to: "0x...", // Адрес получателя
value: ethers.parseEther("0.01") // Сумма в ETH
});
console.log("Транзакция отправлена:", tx.hash);
Обратите внимание на логику: сначала мы создаем Provider для связи с кошельком, а затем получаем из него Signer. Этот Signer и есть объект, представляющий аккаунт пользователя, который может одобрять операции.
В web3.js 4.x процесс немного проще, так как нет явного разделения на провайдера и подписанта. Вы просто передаете window.ethereum в конструктор, и полученный объект web3 может как читать данные, так и запрашивать подпись транзакций.
// web3.js
import Web3 from "web3";
// 1. Создаем экземпляр web3 из объекта кошелька
const web3 = new Web3(window.ethereum);
// 2. Запрашиваем аккаунты
const accounts = await web3.eth.requestAccounts();
const fromAddress = accounts[0];
// 3. Отправляем транзакцию
const txHash = await web3.eth.sendTransaction({
from: fromAddress,
to: "0x...",
value: web3.utils.toWei("0.01", "ether")
});
console.log("Транзакция отправлена:", txHash);
Хотя подход web3.js может показаться более простым, явное разделение на
ProviderиSignerв ethers.js помогает писать более структурированный и безопасный код, четко разграничивая операции чтения и записи в блокчейн.
Теперь, когда вы знаете, как установить соединение, можно переходить к взаимодействию со смарт-контрактами.