连接钱包
连接钱包
本页内容正在整理中,欢迎贡献。
概述
钱包连接是所有 DApp 的入口。现代 DApp 需要支持多种钱包(MetaMask、Coinbase Wallet、WalletConnect 协议钱包等)并提供流畅的用户体验。本文介绍几种主流连接方案的实现方法。
主要内容
方案选择
| 方案 | 支持钱包 | 开发成本 | 推荐场景 |
|---|---|---|---|
| RainbowKit | 20+ | 低 | 新 React 项目首选 |
| ConnectKit | 20+ | 低 | 更简洁的 UI 风格 |
| Web3Modal v3 | 20+ | 中 | 非 React 框架 |
| 原生 window.ethereum | MetaMask 等注入钱包 | 高 | 轻量级场景 |
RainbowKit(推荐)
npm install @rainbow-me/rainbowkit wagmi viem @tanstack/react-query// 完整配置import { getDefaultConfig, RainbowKitProvider } from "@rainbow-me/rainbowkit";import { mainnet, sepolia, optimism, arbitrum, base } from "wagmi/chains";
const config = getDefaultConfig({ appName: "My DApp", projectId: "从 cloud.walletconnect.com 获取", chains: [mainnet, sepolia, optimism, arbitrum, base], // 可选:自定义支持的钱包});// 自定义钱包列表import { metaMaskWallet, coinbaseWallet, walletConnectWallet, rainbowWallet, okxWallet,} from "@rainbow-me/rainbowkit/wallets";import { connectorsForWallets } from "@rainbow-me/rainbowkit";
const connectors = connectorsForWallets( [ { groupName: "推荐", wallets: [metaMaskWallet, coinbaseWallet, rainbowWallet], }, { groupName: "更多", wallets: [walletConnectWallet, okxWallet], }, ], { appName: "My DApp", projectId: "..." });账户状态管理(wagmi Hooks)
import { useAccount, useConnect, useDisconnect, useBalance, useChainId, useSwitchChain,} from "wagmi";
function WalletInfo() { const { address, isConnected, isConnecting, chain } = useAccount(); const { disconnect } = useDisconnect(); const { data: balance } = useBalance({ address }); const chainId = useChainId(); const { switchChain } = useSwitchChain();
if (!isConnected) return <ConnectButton />;
return ( <div> <p>地址: {address}</p> <p>余额: {balance?.formatted} {balance?.symbol}</p> <p>当前网络: {chain?.name}</p> <button onClick={() => switchChain({ chainId: 11155111 })}> 切换到 Sepolia </button> <button onClick={() => disconnect()}>断开连接</button> </div> );}处理网络切换
import { useChainId, useSwitchChain } from "wagmi";import { mainnet } from "wagmi/chains";
function NetworkGuard({ children }: { children: React.ReactNode }) { const chainId = useChainId(); const { switchChain, isPending } = useSwitchChain();
if (chainId !== mainnet.id) { return ( <div> <p>请切换到以太坊主网</p> <button onClick={() => switchChain({ chainId: mainnet.id })} disabled={isPending} > {isPending ? "切换中..." : "切换网络"} </button> </div> ); }
return <>{children}</>;}签名消息(Sign-In with Ethereum)
import { useSignMessage } from "wagmi";
function SignInButton() { const { signMessage, isPending, data: signature } = useSignMessage();
const handleSignIn = () => { signMessage({ message: `登录 My DApp\n\n时间戳: ${Date.now()}\n地址: ${address}`, }); };
return ( <button onClick={handleSignIn} disabled={isPending}> {isPending ? "签名中..." : "用钱包登录"} </button> );}EIP-712 结构化数据签名
import { useSignTypedData } from "wagmi";
const { signTypedData } = useSignTypedData();
signTypedData({ domain: { name: "My DApp", version: "1", chainId: 1, verifyingContract: CONTRACT_ADDRESS, }, types: { Order: [ { name: "buyer", type: "address" }, { name: "amount", type: "uint256" }, { name: "deadline", type: "uint256" }, ], }, primaryType: "Order", message: { buyer: address, amount: parseEther("1.0"), deadline: BigInt(Math.floor(Date.now() / 1000) + 3600), },});最佳实践
- 始终检查网络 —— 确保用户在正确的链上再允许交互
- 优雅处理拒绝 —— 用户拒绝签名时给出清晰提示
- 显示交易状态 —— 展示 pending / success / error 状态
- 支持移动端 —— 确保 WalletConnect 二维码可正常显示
- 缓存连接状态 —— 页面刷新后自动重连