Інтеграція фронтенду з Ethers.js

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Інтеграція фронтенду з Ethers.js
Простий
~2-3 дні
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1306
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1218
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    920
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1147
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    610
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    885

Інтеграція фронтенда з Ethers.js

Ethers.js v6 сломав зворотну сумісність з v5 в кількох критичних місцях: BigNumber замінений на нативний bigint, providers.Web3Provider перейменований у BrowserProvider, змінилось API для отримання signer. Якщо підключаєте бібліотеку до існуючого проекту — перевіріть версію в package.json до початку роботи.

Підключення гаманця

Сучасний підхід — wagmi + viem для React проектів, або rainbowkit/web3modal для готового UI підключення. Але якщо задача саме «чистий ethers.js без абстракцій»:

import { BrowserProvider, Contract, parseEther, formatEther } from 'ethers';

async function connectWallet() {
  if (!window.ethereum) throw new Error('No wallet detected');
  
  const provider = new BrowserProvider(window.ethereum);
  await provider.send('eth_requestAccounts', []);
  const signer = await provider.getSigner();
  const address = await signer.getAddress();
  const network = await provider.getNetwork();
  
  return { provider, signer, address, chainId: network.chainId };
}

Обробка подій зміни аккаунту та мережі:

window.ethereum.on('accountsChanged', (accounts: string[]) => {
  if (accounts.length === 0) {
    // Користувач відключив гаманець
    setConnected(false);
  } else {
    setAddress(accounts[0]);
  }
});

window.ethereum.on('chainChanged', (chainId: string) => {
  // chainId приходить як hex string
  window.location.reload(); // простійший спосіб пересоздати provider
});

Робота з контрактами

const ERC20_ABI = [
  'function balanceOf(address owner) view returns (uint256)',
  'function transfer(address to, uint256 amount) returns (bool)',
  'function approve(address spender, uint256 amount) returns (bool)',
  'function allowance(address owner, address spender) view returns (uint256)',
  'event Transfer(address indexed from, address indexed to, uint256 value)',
];

const contract = new Contract(TOKEN_ADDRESS, ERC20_ABI, signer);

// Читання (безплатно)
const balance = await contract.balanceOf(userAddress);
console.log(formatEther(balance)); // для 18 decimals

// Запис (трансакція)
const tx = await contract.transfer(recipientAddress, parseEther('1.0'));
const receipt = await tx.wait(); // чекаємо підтвердження
console.log('Mined in block:', receipt.blockNumber);

Оцінка газу та переопределення

// Оцінити газ до відправки
const gasEstimate = await contract.transfer.estimateGas(recipient, amount);
const gasLimit = gasEstimate * 120n / 100n; // +20% буфер

// Відправити з кастомними параметрами газу
const tx = await contract.transfer(recipient, amount, {
  gasLimit,
  maxFeePerGas: parseUnits('30', 'gwei'),
  maxPriorityFeePerGas: parseUnits('2', 'gwei'),
});

Підписання повідомлень

EIP-712 (typed data) — для підписів з human-readable контекстом:

const domain = {
  name: 'MyDapp',
  version: '1',
  chainId: 1,
  verifyingContract: CONTRACT_ADDRESS,
};

const types = {
  Order: [
    { name: 'seller', type: 'address' },
    { name: 'tokenId', type: 'uint256' },
    { name: 'price', type: 'uint256' },
    { name: 'deadline', type: 'uint256' },
  ],
};

const value = { seller: address, tokenId: 42n, price: parseEther('1'), deadline: BigInt(Math.floor(Date.now()/1000) + 3600) };

const signature = await signer.signTypedData(domain, types, value);

Верифікація на бекенді через ethers.verifyTypedData(domain, types, value, signature).

Типічні проблеми

bigint серіалізація в JSON: нативний bigint не сериализуется через JSON.stringify. Конвертуйте в string до відправки на бекенд або в state: balance.toString().

Multiple injected providers: якщо встановлені MetaMask та Rabby одночасно, window.ethereum може бути будь-яким з них. EIP-6963 вирішує це через window.addEventListener('eip6963:announceProvider', ...) — всі гаманці анонсують себе, користувач вибирає явно.

Read-only provider: для читання даних без гаманця використовуйте JsonRpcProvider з Alchemy/Infura ключем замість BrowserProvider. Не варто вимагати підключення гаманця для перегляду даних.

Орієнтири по строкам

Базова інтеграція (connect/disconnect, read contract, send tx) — 1 день. З EIP-712 підписами, multi-chain підтримкою та обробкою всіх edge cases — 2-3 дні.