Интеграция фронтенда с RainbowKit
Написать Connect Wallet кнопку с нуля — потерять несколько дней на edge cases: поддержка 15+ кошельков, deep linking для mobile, QR-коды, автоматическое переподключение, обработка disconnect. RainbowKit решает всё это в 30 строках конфигурации поверх wagmi.
Установка и базовая конфигурация
npm install @rainbow-me/rainbowkit wagmi viem @tanstack/react-query
// app/providers.tsx
import "@rainbow-me/rainbowkit/styles.css";
import { RainbowKitProvider, getDefaultConfig } from "@rainbow-me/rainbowkit";
import { WagmiProvider } from "wagmi";
import { mainnet, polygon, arbitrum } from "wagmi/chains";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const config = getDefaultConfig({
appName: "My dApp",
projectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID!, // обязательно
chains: [mainnet, polygon, arbitrum],
});
const queryClient = new QueryClient();
export function Providers({ children }) {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider>{children}</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
);
}
WalletConnect Project ID получаем на cloud.walletconnect.com — бесплатный tier достаточен для большинства проектов.
ConnectButton: кастомизация
Стандартная кнопка <ConnectButton /> подходит для прототипов. В production почти всегда нужен кастомный вид:
import { ConnectButton } from "@rainbow-me/rainbowkit";
export function CustomConnectButton() {
return (
<ConnectButton.Custom>
{({ account, chain, openAccountModal, openChainModal, openConnectModal, mounted }) => {
const ready = mounted;
const connected = ready && account && chain;
return (
<div {...(!ready && { "aria-hidden": true, style: { opacity: 0 } })}>
{!connected ? (
<button onClick={openConnectModal}>Подключить кошелёк</button>
) : chain.unsupported ? (
<button onClick={openChainModal}>Неверная сеть</button>
) : (
<div>
<button onClick={openChainModal}>{chain.name}</button>
<button onClick={openAccountModal}>
{account.displayBalance} · {account.displayName}
</button>
</div>
)}
</div>
);
}}
</ConnectButton.Custom>
);
}
Темизация
RainbowKit поддерживает три встроенные темы (lightTheme, darkTheme, midnightTheme) с возможностью переопределения через theme prop:
import { lightTheme } from "@rainbow-me/rainbowkit";
<RainbowKitProvider
theme={lightTheme({
accentColor: "#6366f1", // indigo-500
accentColorForeground: "white",
borderRadius: "medium",
fontStack: "system",
})}
>
Для динамического переключения тёмной/светлой темы передаём вычисленное значение из контекста или next-themes.
Кастомные кошельки и порядок отображения
По умолчанию RainbowKit показывает кошельки в своём порядке. Для кастомного списка:
import {
connectorsForWallets,
metaMaskWallet,
coinbaseWallet,
walletConnectWallet,
injectedWallet,
} from "@rainbow-me/rainbowkit/wallets";
const connectors = connectorsForWallets(
[
{
groupName: "Рекомендуемые",
wallets: [metaMaskWallet, coinbaseWallet],
},
{
groupName: "Другие",
wallets: [walletConnectWallet, injectedWallet],
},
],
{ appName: "My dApp", projectId: "..." }
);
Можно добавить кастомный кошелёк (например, Safe или Rabby) через интерфейс Wallet из пакета.
Authentication: SIWE (Sign-In with Ethereum)
RainbowKit имеет встроенную поддержку EIP-4361 (Sign-In with Ethereum) — пользователь подписывает сообщение вместо пароля:
import { RainbowKitAuthenticationProvider, createAuthenticationAdapter } from "@rainbow-me/rainbowkit";
import { SiweMessage } from "siwe";
const authAdapter = createAuthenticationAdapter({
getNonce: async () => {
const res = await fetch("/api/auth/nonce");
return res.text();
},
createMessage: ({ nonce, address, chainId }) =>
new SiweMessage({
domain: window.location.host,
address,
statement: "Sign in to My dApp",
uri: window.location.origin,
version: "1",
chainId,
nonce,
}),
getMessageBody: ({ message }) => message.prepareMessage(),
verify: async ({ message, signature }) => {
const res = await fetch("/api/auth/verify", {
method: "POST",
body: JSON.stringify({ message, signature }),
});
return res.ok;
},
signOut: () => fetch("/api/auth/logout", { method: "POST" }),
});
Типичные проблемы
SSR / hydration — RainbowKit использует window, что ломает SSR. В Next.js App Router оборачиваем Providers в client component ("use client"). Для Pages Router — dynamic(() => import('./Providers'), { ssr: false }) если проблема сохраняется.
Mobile deep linking — работает из коробки для MetaMask Mobile и Coinbase Wallet через WalletConnect v2. Проверяем, что projectId правильно настроен в WalletConnect Cloud с доменом приложения.
Множественные RainbowKit экземпляры — если RainbowKitProvider рендерится несколько раз (ошибка в архитектуре), получаем конфликты. Provider должен быть ровно один, как можно выше в дереве компонентов.







