EIP-6963 标准
EIP-6963 是对 EIP-1193 的改进,主要解决多钱包插件注入(冲突)的问题,传统 EIP1193 标准是通过 window.ethereum
对象实现 DApp 与钱包的通信,但当用户安装多个钱包插件时,最后加载的钱包会覆盖其他钱包,导致用户无法自主选择使用哪个钱包。EIP-6963 通过引入事件机制 和 标准化接口,实现了多钱包的自动发现和用户选择功能。
JS 实现事件的通信
js
window.addEventListener("ice_event", (event) => {
console.log(event.detail);
});
window.dispatchEvent(
new CustomEvent("ice_event", {
detail: {
name: "ice",
age: 25,
},
})
);
核心概念
事件机制
Dapp
- 先监听
eip6963:announceProvider
, 获取钱包列表 - 主动 dispatch
eip6963:requestProvider
Wallet
- 监听到 Dapp
eip6963:requestProvider
,同步返回eip6963:announceProvider
的事件,包含钱包元信息 - 钱包主动 dispatch
eip6963:announceProvider
的事件,包含钱包完整信息
标准化接口
ts
// 钱包元数据
interface EIP6963ProviderInfo {
uuid: string;
name: string;
icon: string;
rdns: string;
}
// 钱包完整信息
interface EIP6963ProviderDetail {
info: EIP6963ProviderInfo;
provider: EIP1193Provider; // 实现EIP-1193 的 provider 对象
}
实现代码
tsx
"use client";
import { useEffect, useState } from "react";
const HomePage = () => {
const [wallets, setWallets] = useState([]);
const [address, setAddress] = useState("");
useEffect(() => {
const handleAnnounce = (event: CustomEvent<EIP6963ProviderDetail>) => {
const { info, provider } = event.detail;
setWallets((prev) => {
if (prev.some((item) => item.info.uuid === info.uuid)) {
return prev;
}
return [...prev, { info, provider }];
});
};
/** 先监听,后发送*/
// 1. 先监听 announceProvider 事件
window.addEventListener("eip6963:announceProvider", handleAnnounce);
// 2. 在发送 requestProvider 请求
window.dispatchEvent(new CustomEvent("eip6963:requestProvider")); // 钱包内部会监听这个事件,并发送 announceProvider 事件 (同步的)
return () => {
window.removeEventListener("eip6963:announceProvider", handleAnnounce);
};
}, []);
return (
<div>
wallets:
<ul>
{wallets.map((wallet) => (
<li key={wallet.info.uuid}>
{wallet.info.name}{" "}
<button
onClick={() => {
wallet.provider
.request({
method: "eth_requestAccounts",
})
.then((accounts) => {
setAddress(accounts[0]);
});
}}
>
connect
</button>
</li>
))}
</ul>
<h3>address: {address}</h3>
</div>
);
};
export default HomePage;