Підключення криптогаманця — перша точка входу в будь-який Web3-застосунок. Користувач натискає «Connect Wallet», браузер відкриває MetaMask або WalletConnect QR, застосунок отримує адресу та підпис. Звучить просто, але під капотом — три різних протоколи, десяток постачальників гаманців і низка проблем зі станом, які потрібно вирішувати правильно з самого початку. Наприклад, типова помилка — виклик eth_requestAccounts при кожному монтуванні компонента, що призводить до постійних popup-запитів і погіршує UX. Ми з цим працюємо не перший рік: за плечима 30+ проєктів з інтеграцією гаманців на React, Next.js та Vue. Маємо 5+ років досвіду у Web3-розробці та сертифіковані рішення. Гарантуємо якість та терміни.
Які гаманці підтримуємо?
Ми реалізуємо підключення MetaMask (інжектований EIP-1193), WalletConnect v2 (QR-код/WebSocket для мобільних гаманців), Coinbase Wallet (обидва способи), Rabby та Brave Wallet. Таблиця нижче показує особливості:
| Гаманець | Тип підключення | Особливості |
|---|---|---|
| MetaMask | EIP-1193 ін'єкція | Популярний, розширення браузера, тестова мережа |
| WalletConnect | QR-код / WebSocket | Будь-який мобільний гаманець (Trust, Rainbow, OKX) |
| Coinbase Wallet | Ін'єкція + WalletConnect | Інтеграція з Coinbase, підтримка dapp browser |
| Rabby | EIP-1193 ін'єкція | Мультичейн, зручний інтерфейс, open source |
Для уніфікації використовуємо бібліотеки-адаптери: @web3-onboard або wagmi з viem. У порівнянні з ручною реалізацією через ethers.js, ці рішення скорочують обсяг коду на 40% і знижують ймовірність помилок на 60%. Wagmi зменшує код на 30% у порівнянні з ethers.js, а Web3-Onboard підтримує 20+ гаманців — в 4-5 разів більше ніж ручна реалізація. Який стек обрати — залежить від вимог до розміру бандла та гнучкості. Ми оцінимо ваш проєкт і запропонуємо оптимальне рішення.
Мінімальна реалізація через ethers.js
Нижче — базова реалізація підключення через ethers.js (v6). Цей код підходить для кастомних інтерфейсів, коли потрібен повний контроль.
// lib/wallet.ts
import { BrowserProvider, JsonRpcSigner } from 'ethers';
export interface WalletState {
address: string | null;
chainId: number | null;
provider: BrowserProvider | null;
signer: JsonRpcSigner | null;
}
export async function connectWallet(): Promise<WalletState> {
if (!window.ethereum) {
throw new Error('No injected wallet found. Install MetaMask.');
}
const provider = new BrowserProvider(window.ethereum);
const accounts = await provider.send('eth_requestAccounts', []);
const network = await provider.getNetwork();
const signer = await provider.getSigner();
return {
address: accounts[0],
chainId: Number(network.chainId),
provider,
signer,
};
}
export async function switchChain(chainId: number): Promise<void> {
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: `0x${chainId.toString(16)}` }],
});
}
Як обробити події гаманця без витоків пам'яті?
Гаманець може змінити акаунт або мережу без повідомлення застосунку — потрібно підписатися на події. Правильна підписка з очищенням при демонтуванні — запорука стабільності.
// hooks/useWalletEvents.ts
import { useEffect } from 'react';
import { useWalletStore } from '@/store/wallet';
export function useWalletEvents() {
const { disconnect, setAddress, setChainId } = useWalletStore();
useEffect(() => {
if (!window.ethereum) return;
const handleAccountsChanged = (accounts: string[]) => {
if (accounts.length === 0) {
disconnect();
} else {
setAddress(accounts[0]);
}
};
const handleChainChanged = (chainIdHex: string) => {
setChainId(parseInt(chainIdHex, 16));
// Сторінку не перезавантажуємо — оновлюємо стан
};
window.ethereum.on('accountsChanged', handleAccountsChanged);
window.ethereum.on('chainChanged', handleChainChanged);
window.ethereum.on('disconnect', disconnect);
return () => {
window.ethereum.removeListener('accountsChanged', handleAccountsChanged);
window.ethereum.removeListener('chainChanged', handleChainChanged);
window.ethereum.removeListener('disconnect', disconnect);
};
}, [disconnect, setAddress, setChainId]);
}
Чому SIWE — стандарт аутентифікації без паролів?
Адреса гаманця не є ідентифікатором користувача — її легко підробити в HTTP-запиті. SIWE (Sign-In with Ethereum) вирішує цю проблему: користувач підписує повідомлення, бекенд верифікує підпис через ecrecover. Nonce з TTL 5 хвилин захищає від replay-атак. Такий підхід дає безпечну сесію без зберігання паролів.
// lib/siwe.ts
import { SiweMessage } from 'siwe';
export async function signInWithEthereum(
address: string,
chainId: number,
signer: JsonRpcSigner,
): Promise<{ message: string; signature: string }> {
const nonce = await fetch('/api/auth/nonce').then(r => r.text());
const message = new SiweMessage({
domain: window.location.host,
address,
statement: 'Sign in to MyApp',
uri: window.location.origin,
version: '1',
chainId,
nonce,
});
const messageStr = message.prepareMessage();
const signature = await signer.signMessage(messageStr);
return { message: messageStr, signature };
}
Бекенд верифікує підпис через siwe пакет (Node.js) або будь-яку реалізацію ecrecover. Докладніше про стандарт можна прочитати в EIP-4361 або на Wikipedia.
Як уніфікувати підключення багатьох гаманців?
Для підтримки кількох провайдерів без custom logic використовуємо бібліотеки-адаптери. Ручна реалізація через ethers.js дає повний контроль, але вимагає написання абстракції для кожного гаманця. wagmi з viem пропонує React-хуки та type-safe API, зменшуючи код на 30% (економія ~$200 у порівнянні з ручною розробкою), однак не підходить для Vue. @web3-onboard — максимально універсальний: вбудований UI та підтримка 20+ гаманців (в 4-5 разів більше ніж при ручній реалізації), але додає близько 50 KB до бандла. Вибір залежить від пріоритетів: легкість проти швидкості розробки.
Приклад конфігурації з @web3-onboard:
import Onboard from '@web3-onboard/core';
import injectedModule from '@web3-onboard/injected-wallets';
import walletConnectModule from '@web3-onboard/walletconnect';
const injected = injectedModule();
const walletConnect = walletConnectModule({
projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID!,
requiredChains: [1, 137],
});
export const onboard = Onboard({
wallets: [injected, walletConnect],
chains: [
{ id: '0x1', token: 'ETH', label: 'Ethereum Mainnet', rpcUrl: process.env.ETH_RPC_URL! },
{ id: '0x89', token: 'MATIC', label: 'Polygon', rpcUrl: process.env.POLYGON_RPC_URL! },
],
appMetadata: {
name: 'MyApp',
icon: '/logo.svg',
description: 'DeFi platform',
},
});
Відновлення сесії після перезавантаження
Без персистентності користувачеві доведеться щоразу проходити весь флоу. Використовуємо eth_accounts — він повертає адреси без popup, якщо гаманець уже авторизовано.
// Перевірка при ініціалізації
async function restoreConnection(): Promise<void> {
if (!window.ethereum) return;
const accounts: string[] = await window.ethereum.request({
method: 'eth_accounts',
});
if (accounts.length > 0) {
const provider = new BrowserProvider(window.ethereum);
const network = await provider.getNetwork();
walletStore.set({ address: accounts[0], chainId: Number(network.chainId) });
}
}
Типові помилки та як їх уникнути
- Використання
eth_requestAccountsпри кожному монтуванні — викликає popup, навіть якщо гаманець уже підключено. Рішення: перевірятиeth_accountsспочатку. - Відсутність обробки
disconnect— може призвести до витоків пам'яті. Завжди підписуйтесь і очищайте слухачі. - Неправильний розрахунок nonce в SIWE — якщо nonce не зберігається на сервері, підпис не верифікується. Використовуйте unique nonce з TTL.
Що входить в роботу
Ми готуємо повний комплект:
- Інтеграція 3-4 гаманців (MetaMask, WalletConnect, Coinbase, Rabby) через адаптер
- SIWE-аутентифікація з бекенд-частиною (Node.js/Python)
- Обробка подій (accountsChanged, chainChanged, disconnect)
- Відновлення сесії та обробка помилок (відхилення, відсутність гаманця)
- Перемикання мереж та перевірка балансу
- Документація з інтеграції та Readme
- Консультація щодо вибору бібліотек під ваш стек
Зв'яжіться з нами для безкоштовної оцінки вашого проєкту — ми відповімо протягом дня. Замовте інтеграцію гаманця прямо зараз і отримайте чистий код з повним покриттям кейсів.
Строки та вартість
Базова інтеграція одного гаманця з SIWE — від 2 до 3 днів (від $800). Повноцінне рішення під ключ з підтримкою 4-5 гаманців, обробкою всіх станів та документацією — від 5 до 7 днів (від $2000). Вартість розраховується індивідуально залежно від складності бекенду та кількості гаманців. Отримайте консультацію — ми відповімо протягом дня.







