Интеграция кошелька с WalletConnect
WalletConnect v2 — это не просто "добавить кнопку Connect Wallet". Протокол построен на relay-серверах Walletconnect Cloud, использует собственный JSON-RPC поверх WebSocket, и требует понимания сессионного управления, чтобы не получить broken UX при переключении сетей или дисконнекте.
Как это работает под капотом
WalletConnect v2 использует Sign API и Auth API поверх своего relay протокола. Пара ключей (topic + symmetric key) создаётся при инициализации сессии, QR-код кодирует URI формата wc:topic@2?relay-protocol=irn&symKey=.... Кошелёк (MetaMask Mobile, Trust, Rainbow) сканирует QR, устанавливает зашифрованный канал через relay.walletconnect.com.
Для dApp разработки напрямую с WalletConnect SDK работать не нужно — это делает wagmi + @web3modal/wagmi (или ConnectKit, RainbowKit).
Интеграция через wagmi v2 + Web3Modal
// config.ts
import { createConfig, http } from 'wagmi'
import { mainnet, polygon, arbitrum } from 'wagmi/chains'
import { walletConnect, injected, coinbaseWallet } from 'wagmi/connectors'
export const config = createConfig({
chains: [mainnet, polygon, arbitrum],
connectors: [
injected(),
walletConnect({ projectId: process.env.NEXT_PUBLIC_WC_PROJECT_ID! }),
coinbaseWallet({ appName: 'Your App' }),
],
transports: {
[mainnet.id]: http(),
[polygon.id]: http(),
[arbitrum.id]: http(),
},
})
projectId получается на cloud.walletconnect.com — без него соединение работает только в dev через публичный relay, в production упадёт с rate limit.
Управление сессией
Критичный момент, который часто игнорируют: WalletConnect сессии персистентны. Пользователь закрыл вкладку, открыл снова — сессия должна восстановиться без нового QR. wagmi обрабатывает это автоматически через localStorage, но нужно правильно инициализировать WagmiProvider до любого использования хуков:
// app/providers.tsx
'use client'
import { WagmiProvider } from 'wagmi'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { config } from './config'
const queryClient = new QueryClient()
export function Providers({ children }: { children: React.ReactNode }) {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</WagmiProvider>
)
}
Переключение сетей
wallet_switchEthereumChain — стандартный RPC метод. Если сеть не добавлена в кошелёк, нужен wallet_addEthereumChain. wagmi это абстрагирует через useSwitchChain, но поведение отличается по кошелькам: MetaMask показывает popup, WalletConnect-подключённые мобильные кошельки могут игнорировать запрос или требовать ручного подтверждения в приложении.
Распространённые проблемы
Hydration mismatch в Next.js — useAccount() возвращает разное состояние на сервере и клиенте. Решение: ssr: false для компонентов с wallet state, или useEffect для чтения состояния только на клиенте.
Mobile deep links — на iOS/Android WalletConnect должен открыть кошелёк через universal link. Web3Modal обрабатывает это, но если пишешь кастомный UI — нужно передавать redirect параметр при инициализации сессии.
Session expiry — сессии живут 7 дней по умолчанию. Нужно обрабатывать session_expire событие и показывать пользователю предложение переподключиться.
Работа занимает 2–3 дня: настройка wagmi config, интеграция Web3Modal или RainbowKit, тестирование на реальных мобильных кошельках (MetaMask Mobile, Trust Wallet), обработка edge cases с network switching и session persistence.







