Інтеграція кошелька з MetaMask
MetaMask інжектує window.ethereum в сторінку — та прямана робота з провайдером звичайно закінчується. У 2024 році писати window.ethereum.request({ method: 'eth_requestAccounts' }) напрямки — це або прототип, або технічний борг. Правильна інтеграція через wagmi + viem обробляє всі edge cases: кілька кошельків у браузері, зміна мережі, розрив з'єднання, мобільний MetaMask через deeplink.
Стек та підключення
wagmi v2 + viem — стандарт для сучасних dApp. Wagmi управляє станом підключення, автоматичним переподключенням, подіями. Viem — типізований low-level клієнт замість ethers.js.
import { createConfig, http } from 'wagmi'
import { mainnet, base } from 'wagmi/chains'
import { metaMask } from 'wagmi/connectors'
export const config = createConfig({
chains: [mainnet, base],
connectors: [metaMask()],
transports: {
[mainnet.id]: http(),
[base.id]: http(),
},
})
Кнопка підключення:
import { useConnect, useAccount, useDisconnect } from 'wagmi'
function ConnectButton() {
const { address, isConnected } = useAccount()
const { connect, connectors } = useConnect()
const { disconnect } = useDisconnect()
if (isConnected) {
return (
<button onClick={() => disconnect()}>
{address?.slice(0, 6)}...{address?.slice(-4)}
</button>
)
}
const metamask = connectors.find(c => c.id === 'metaMaskSDK')
return (
<button onClick={() => connect({ connector: metamask! })}>
Connect MetaMask
</button>
)
}
Зміна мережі та додавання кастомної мережі
Часта проблема: користувач на Ethereum mainnet, dApp працює на Base. Потрібно запросити переключення, а якщо мережа не додана — додати її.
import { useSwitchChain } from 'wagmi'
function NetworkGuard({ children, requiredChainId }: Props) {
const { chainId } = useAccount()
const { switchChain, isPending } = useSwitchChain()
if (chainId !== requiredChainId) {
return (
<button
onClick={() => switchChain({ chainId: requiredChainId })}
disabled={isPending}
>
Switch to Base
</button>
)
}
return children
}
wagmi автоматично викликає wallet_addEthereumChain якщо wallet_switchEthereumChain повертає помилку 4902 (chain not found).
Підпис повідомлень та транзакції
EIP-712 typed data signing — для структурованих підписів (permit, orders, auth tokens):
import { useSignTypedData } from 'wagmi'
const { signTypedData } = useSignTypedData()
signTypedData({
domain: { name: 'MyApp', version: '1', chainId: 8453 },
types: {
Login: [
{ name: 'address', type: 'address' },
{ name: 'nonce', type: 'string' },
],
},
primaryType: 'Login',
message: { address: userAddress, nonce: sessionNonce },
})
Для SIWE (Sign-In with Ethereum) — бібліотека siwe генерує стандартизоване повідомлення, backend верифікує через SiweMessage.verify().
Обробка помилок
MetaMask повертає специфічні error codes:
-
4001— користувач відхилив запит -
4902— мережа не знайдена -
-32002— запит вже чекає на підтвердження (другий вклик connect поки перший висить) -
-32603— internal JSON-RPC error (зазвичай insufficient gas або revert)
const { error } = useConnect()
useEffect(() => {
if (error?.name === 'UserRejectedRequestError') {
toast('Підключення скасовано')
} else if (error?.name === 'ConnectorAlreadyConnectedError') {
// вже підключено, ігноруємо
}
}, [error])
Mobile deeplink
На мобільних MetaMask відкривається через deeplink metamask://dapp/<your-url>. wagmi MetaMask connector автоматично обробляє це через MetaMask SDK. Для коректної роботи на iOS потрібен HTTPS (не HTTP) та правильно налаштований WagmiProvider на верхньому рівні додатку.







