如果浏览器插件钱包需要向Dapp提供以太坊Provider能力,必须实现EIP1193协议。根据EIP1193协议描述,要求插件钱包将Provider实现注入到window.ethereum。这就导致了一些问题。注入冲突
如果浏览器插件钱包需要向 Dapp 提供以太坊 Provider 能力,必须实现 EIP1193 协议。根据 EIP1193 协议描述,要求插件钱包将 Provider 实现注入到 window.ethereum。 这就导致了一些问题。
window.ethereum 被重复覆盖,最终值取决于插件钱包的加载顺序。window.ethereum, 有些插件钱包会延迟自家 Provider 的注入,甚至freeze window.ethereum对象,使其无法被覆盖。同时,由于 EIP1193 没有定义钱包 Provider 的元数据描述接口,导致 Dapp 无法统一自动解析 Provider 中的特定信息来区分不同钱包。插件钱包的元数据(图标,名称等)如果要正确被显示,就需要钱包开发者手动将这些信息提交给 Dapp 或者 Provider Discovery Library (https://github.com/rainbow-me/rainbowkit/pull/1166),耗时耗力。
EIP-6963(Multi Injected Provider Discovery),就很好地解决了上述这些问题。下面简要概述下该协议的核心内容。
该协议定义了 一个标准化的 EIP6963ProviderInfo 接口,包含了钱包 Provider 的一些相关元数据。
/**
* Represents the assets needed to display a wallet
*/
interface EIP6963ProviderInfo {
uuid:string;
name:string;
icon:string;
rdns:string;
}
io.metamask.wallet该协议定义了一个标准化的 EIP6963ProviderDetail 接口,用于公布钱包 Provider 对象(实现EIP1193规范)和钱包 Provider 的一些相关元数据(实现EIP6963ProviderInfo接口)。
interface EIP6963ProviderDetail {
info: EIP6963ProviderInfo;
provider: EIP1193Provider;
}
该协议引入了一组 window 事件,通过事件实现 Dapp 与钱包 Provider 的双向通信。
Dapp 与钱包 Provider 都需要使用 window.dispatchEvent 函数来触发事件,使用 window.addEventListener 来监听事件。
定义了 EIP6963AnnounceProviderEvent 接口,并且实现该接口的对象必须是CustomEvent 对象。应该使用Object.freeze() 冻结 detail 属性。
// Announce Event dispatched by a Wallet
interface EIP6963AnnounceProviderEvent extends CustomEvent {
type: "eip6963:announceProvider";
detail: EIP6963ProviderDetail;
}
定义了 EIP6963RequestProviderEvent 接口,并且实现该接口的对象必须是 Event 对象。
// Request Event dispatched by a DApp
interface EIP6963RequestProviderEvent extends Event {
type: "eip6963:requestProvider";
}
钱包端
window.addEventListener监听eip6963:requestProvider事件, 当收到该事件时,应该立即通过 window.dispatchEvent 触发EIP6963AnnounceProviderEvent 事件,将钱包的EIP6963ProviderDetail 信息发送给 Dapp。eip6963:requestProvider 事件。所以当钱包加载完成时,应该立即通过 window.dispatchEvent 触发一次 EIP6963AnnounceProviderEvent 。let info: EIP6963ProviderInfo;
let provider: EIP1193Provider;
const announceEvent: EIP6963AnnounceProviderEvent = new CustomEvent(
"eip6963:announceProvider",
{ detail: Object.freeze({ info, provider }) }
);
// The Wallet dispatches an announce event which is heard by
// the DApp code that had run earlier
window.dispatchEvent(announceEvent);
// The Wallet listens to the request events which may be
// dispatched later and re-dispatches the `EIP6963AnnounceProviderEvent`
window.addEventListener("eip6963:requestProvider", () => {
window.dispatchEvent(announceEvent);
});
Dapp端
window.addEventListener 监听 eip6963:announceProvider 事件。并且在页面生命周期内,不得移除该事件监听。eip6963:announceProvider 事件后,Dapp 才可以通过window.dispatchEvent 发送eip6963:requestProvider 事件,向钱包请求 EIP6963ProviderDetail 信息。// The DApp listens to announced providers
window.addEventListener(
"eip6963:announceProvider",
(event: EIP6963AnnounceProviderEvent) => {}
);
// The DApp dispatches a request event which will be heard by
// Wallets' code that had run earlier
window.dispatchEvent(new Event("eip6963:requestProvider"));
如果需要测试钱包是否支持了该协议,可以使用如下 Dapp 测试
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!