了解区块链钱包连接协议的底层原理与实现方式,涵盖 EIP-1193 注入标准、WalletConnect v2 架构、多设备扫码通信机制及消息交互流程。通过理论解析与代码实战,帮助开发者全面理解“连接钱包”背后的协议逻辑,为前端集成奠定坚实基础。
📚 作者:Henry 🧱 系列:《区块链钱包原理与前端集成实践》 · 第 2 篇 👨💻 受众:Web3 开发者 / 区块链学习者 👉 系列持续更新中,建议收藏专栏或关注作者
连接钱包 ≠ 直接读取账户
连接钱包 = 建立一套通信桥梁协议,让 DApp 能通过浏览器或中继服务与钱包交互:
浏览器注入类钱包(如 MetaMask)过去各自定义接口,导致开发者适配成本高。EIP-1193 是一个标准化接口规范,规定了钱包提供者(Provider)的行为。
window.ethereum
对象所有调用遵循统一格式:
await window.ethereum.request({ method: 'eth_requestAccounts' });
方法 | 描述 |
---|---|
eth_requestAccounts |
请求连接钱包地址(触发连接弹窗) |
eth_chainId |
获取当前链 ID |
eth_sendTransaction |
发起交易请求 |
personal_sign / eth_signTypedData_v4 |
发起签名请求 |
wallet_switchEthereumChain |
切换链网络 |
WalletConnect 是一种基于 QR 码 + WebSocket 的钱包连接协议
它让浏览器 DApp ↔️ 手机钱包之间实现交互
对比项 | WalletConnect v1(已废弃) | WalletConnect v2 (主流) |
---|---|---|
通信方式 | 临时 Session | 持久 Session |
多链支持 | ❌ | ✅ |
消息标准 | 自定义 | JSON-RPC |
底层架构 | WebSocket + Bridge | WebSocket + Relay Server |
生命周期控制 | 单一连接 | 多 session、可主动断开 |
项目 ID | 无需 | 必须(由 WalletConnect 控制台申请) |
用户点击“连接钱包”按钮
DApp 调用:
await window.ethereum.request({ method: 'eth_requestAccounts' });
用户在钱包中点击“确认连接”
钱包返回地址,连接成功
const provider = window.ethereum;
if (!provider) {
console.error('请安装钱包插件');
return;
}
const accounts = await provider.request({
method: 'eth_requestAccounts',
});
console.log('连接账户:', accounts[0]);
const chainId = await provider.request({ method: 'eth_chainId' });
console.log('当前链 ID:', parseInt(chainId, 16));
import { BrowserProvider } from 'ethers';
const browserProvider = new BrowserProvider(window.ethereum);
const signer = await browserProvider.getSigner();
const tx = await signer.sendTransaction({
to: '0xabc...',
value: parseEther('0.01'),
});
await tx.wait();
console.log('交易已上链');
安装依赖
pnpm add wagmi viem @walletconnect/ethereum wagmi/connectors
🚨 注意:你需要在 WalletConnect 官方平台(https://cloud.walletconnect.com)注册获取一个 Project ID
📦 配置 connectors
// lib/walletConnect.ts
import { walletConnect } from 'wagmi/connectors'
import { WalletConnectConnector } from '@wagmi/connectors/walletConnect'
import { mainnet } from 'wagmi/chains'
export const walletConnectConnector = walletConnect({
projectId: 'YOUR_PROJECT_ID', // 👉 替换成你的真实 ID
metadata: {
name: 'My DApp',
description: 'DApp 前端连接示例',
url: 'https://mydapp.example',
icons: ['https://mydapp.example/icon.png'],
},
showQrModal: true,
})
⚙️ 创建 wagmi config
// lib/wagmi.ts
import { createConfig, configureChains } from 'wagmi'
import { publicProvider } from 'wagmi/providers/public'
import { walletConnectConnector } from './walletConnect'
import { mainnet } from 'wagmi/chains'
const { publicClient } = configureChains(
[mainnet],
[publicProvider()],
)
export const wagmiConfig = createConfig({
autoConnect: true,
publicClient,
connectors: [walletConnectConnector],
})
🧩 在应用中包裹 Provider
// app/layout.tsx or _app.tsx
import { WagmiProvider } from 'wagmi'
import { wagmiConfig } from '@/lib/wagmi'
export default function App({ children }) {
return (
<WagmiProvider config={wagmiConfig}>
{children}
</WagmiProvider>
)
}
🧪 发起连接 + 获取账户信息
'use client'
import { useConnect, useAccount, useDisconnect } from 'wagmi'
export function WalletConnectButton() {
const { connect, connectors } = useConnect()
const { address, isConnected } = useAccount()
const { disconnect } = useDisconnect()
const walletConnect = connectors.find(c => c.name === 'WalletConnect')
return (
<div>
{isConnected ? (
<>
<p>已连接地址:{address}</p>
<button onClick={() => disconnect()}>断开连接</button>
</>
) : (
<button onClick={() => connect({ connector: walletConnect! })}>
使用 WalletConnect 连接钱包
</button>
)}
</div>
)
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!