Підключення криптогаманця — перша точка входу в будь-який 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). Вартість розраховується індивідуально залежно від складності бекенду та кількості гаманців. Отримайте консультацію — ми відповімо протягом дня.







