Три кита ethers.js: Provider, Signer, Contract
Три главных класса ethers.js — Provider, Signer, Contract — и чем отличаются версии v5 и v6.
ethers.js — библиотека-«переводчик» между JavaScript и блокчейном: кодирует вызовы, подписывает транзакции, разбирает ответы и события.
Вся работа с ethers.js держится на трёх классах. Поймёте их роли — поймёте библиотеку целиком.
Три кита
- Provider — соединение с сетью для чтения (мы разбирали его в разделе про провайдеры).
- Signer — аккаунт, умеющий подписывать (для записи и подписи сообщений).
- Contract — типобезопасная обёртка над контрактом: вы зовёте методы как обычные JS-функции, а ethers под капотом кодирует/декодирует данные по ABI.
Связь простая: Contract создаётся из адреса, ABI и runner'а (Provider или Signer). Runner определяет, что контракт умеет: с Provider — только читать, с Signer — ещё и писать.
import { Contract, BrowserProvider } from "ethers";
const provider = new BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const abi = [ /* описание функций контракта */ ];
const address = "0xКонтракт";
// для чтения
const reader = new Contract(address, abi, provider);
// для записи
const writer = new Contract(address, abi, signer);v5 против v6: что поменялось
В 2023 году вышла ethers v6 с несовместимыми изменениями. Туториалы в сети часто на v5 — важно различать:
| v5 | v6 |
ethers.providers.Web3Provider | BrowserProvider |
ethers.utils.parseEther | parseEther (из корня) |
числа — BigNumber (свой класс) | числа — нативный bigint |
contract.functions... | прямые методы |
provider.getSigner() синхронный | getSigner() возвращает Promise |
Самое заметное для фронта — числа. В v5 был громоздкий BigNumber со своими методами .add(), .mul(). В v6 ethers перешёл на встроенный в JS bigint — это упрощает арифметику, но требует понимать его правила (об этом отдельный урок).
Как работает под капотом
Когда вы вызываете contract.balanceOf(addr), ethers находит в ABI функцию balanceOf, вычисляет её селектор (первые 4 байта от keccak256 сигнатуры), кодирует аргумент по правилам ABI-кодирования и отправляет это как eth_call через runner. Ответ-hex декодируется обратно в JS-значение по типу из ABI. Вся «магия» Contract — это автоматический ABI-кодек поверх Provider/Signer.
Частые ошибки
- Мешать примеры v5 и v6. Скопированный код из старого туториала не запустится; сверяйте версию.
- Забывать про Promise у getSigner() в v6. Нужен
await. - Считать BigNumber и bigint одним и тем же. В v6 это нативный bigint с другим API.
Итоги
- Три кита: Provider (чтение), Signer (подпись), Contract (обёртка по ABI).
- Contract = адрес + ABI + runner; runner решает, читать или писать.
- v6 использует нативный bigint и убрал namespace utils/providers — следите за версией примеров.