Skip to main content

mipd eip6963工具封装

DEMO

alt text

Site

https://github.com/wevm/mipd

代码分析

这段代码定义了一组用于管理和处理 EIP-1193 提供者(Provider)的类型和函数。EIP-1193 是一个以太坊标准,用于定义与区块链交互的提供者接口。这些提供者通常是钱包应用程序,如 MetaMask、Coinbase Wallet 等。

以下是代码的详细分析:

1. 导出类型和函数

export type { DefaultRegister, EIP1193Provider, Rdns, Register, ResolvedRegister } from './register.js';

export { createStore, type Listener, type Store } from './store.js';

export type { EIP6963AnnounceProviderEvent, EIP6963ProviderDetail, EIP6963ProviderInfo, EIP6963RequestProviderEvent } from './types.js';

export {
type AnnounceProviderParameters,
type AnnounceProviderReturnType,
announceProvider,
type RequestProvidersParameters,
type RequestProvidersReturnType,
requestProviders,
} from './utils.js';

这些导出语句将其他模块中的类型和函数重新导出,以便在其他地方使用。具体来说:

  • register.js 中导出的类型包括 DefaultRegister, EIP1193Provider, Rdns, Register, ResolvedRegister
  • store.js 中导出的函数和类型包括 createStore, Listener, Store
  • types.js 中导出的类型包括 EIP6963AnnounceProviderEvent, EIP6963ProviderDetail, EIP6963ProviderInfo, EIP6963RequestProviderEvent
  • utils.js 中导出的函数和类型包括 announceProvider, requestProviders 及其相关类型。

2. 定义和扩展 Register 接口

export interface Register {}

export type DefaultRegister = {
provider: import('viem').EIP1193Provider;
rdns: 'com.coinbase' | 'com.enkrypt' | 'io.metamask' | 'io.zerion';
};

export type ResolvedRegister = {
provider: Register extends {
provider: infer provider extends DefaultRegister['provider'];
}
? provider
: DefaultRegister['provider'];
rdns: Register extends { rdns: infer rdns extends string } ? rdns : DefaultRegister['rdns'] | (string & {}); // loose autocomplete
};

export type EIP1193Provider = ResolvedRegister['provider'];
export type Rdns = ResolvedRegister['rdns'];

这些类型定义了一个 Register 接口和一些相关的类型:

  • DefaultRegister 定义了默认的注册类型,包括 providerrdns(反向域名表示)。
  • ResolvedRegister 通过条件类型从 Register 接口中推导出 providerrdns 的类型。
  • EIP1193ProviderRdns 是从 ResolvedRegister 中提取的类型。

3. 创建和管理存储

export function createStore(): Store {
const listeners: Set<Listener> = new Set();
let providerDetails: readonly EIP6963ProviderDetail[] = [];

const request = () =>
requestProviders((providerDetail) => {
if (providerDetails.some(({ info }) => info.uuid === providerDetail.info.uuid)) return;

providerDetails = [...providerDetails, providerDetail];
listeners.forEach((listener) => listener(providerDetails, { added: [providerDetail] }));
});
let unwatch = request();

return {
_listeners() {
return listeners;
},
clear() {
listeners.forEach((listener) => listener([], { removed: [...providerDetails] }));
providerDetails = [];
},
destroy() {
this.clear();
listeners.clear();
unwatch?.();
},
findProvider({ rdns }) {
return providerDetails.find((providerDetail) => providerDetail.info.rdns === rdns);
},
getProviders() {
return providerDetails;
},
reset() {
this.clear();
unwatch?.();
unwatch = request();
},
subscribe(listener, { emitImmediately } = {}) {
listeners.add(listener);
if (emitImmediately) listener(providerDetails, { added: providerDetails });
return () => listeners.delete(listener);
},
};
}

createStore 函数创建了一个存储对象,用于管理提供者详情和监听器。存储对象包含以下方法:

  • _listeners: 返回当前的监听器集合。
  • clear: 清除所有提供者详情,并通知所有监听器。
  • destroy: 销毁存储,包括清除所有详情和监听器。
  • findProvider: 根据 rdns 查找特定的提供者详情。
  • getProviders: 返回所有提供者详情。
  • reset: 重置存储,并重新请求提供者详情。
  • subscribe: 订阅提供者详情的变化,并返回一个取消订阅的函数。

4. 定义事件和实用函数

export interface EIP6963ProviderDetail<TProvider = EIP1193Provider, TRdns extends string = Rdns> {
info: EIP6963ProviderInfo<TRdns>;
provider: TProvider;
}

export interface EIP6963ProviderInfo<TRdns extends string = Rdns> {
icon: `data:image/${string}`;
name: string;
rdns: TRdns;
uuid: string;
}

export interface EIP6963AnnounceProviderEvent<TProvider = EIP1193Provider> extends CustomEvent<EIP6963ProviderDetail<TProvider>> {
type: 'eip6963:announceProvider';
}

export interface EIP6963RequestProviderEvent extends Event {
type: 'eip6963:requestProvider';
}

这些接口定义了 EIP-6963 事件和提供者详情的结构:

  • EIP6963ProviderDetail 包含提供者信息和提供者实例。
  • EIP6963ProviderInfo 包含提供者的元数据。
  • EIP6963AnnounceProviderEventEIP6963RequestProviderEvent 定义了相应的事件类型。
export function announceProvider(detail: AnnounceProviderParameters): AnnounceProviderReturnType {
const event: CustomEvent<EIP6963ProviderDetail> = new CustomEvent('eip6963:announceProvider', { detail: Object.freeze(detail) });

window.dispatchEvent(event);

const handler = () => window.dispatchEvent(event);
window.addEventListener('eip6963:requestProvider', handler);
return () => window.removeEventListener('eip6963:requestProvider', handler);
}

export function requestProviders(listener: RequestProvidersParameters): RequestProvidersReturnType {
if (typeof window === 'undefined') return;
const handler = (event: EIP6963AnnounceProviderEvent) => listener(event.detail);

window.addEventListener('eip6963:announceProvider', handler);

window.dispatchEvent(new CustomEvent('eip6963:requestProvider'));

return () => window.removeEventListener('eip6963:announceProvider', handler);
}

announceProviderrequestProviders 是两个用于处理提供者事件的实用函数:

  • announceProvider 用于宣布一个新的提供者,触发 eip6963:announceProvider 事件,并监听 eip6963:requestProvider 事件。
  • requestProviders 用于请求提供者详情,监听 eip6963:announceProvider 事件,并触发 eip6963:requestProvider 事件。

5. 扩展全局事件映射

declare global {
interface WindowEventMap {
'eip6963:announceProvider': EIP6963AnnounceProviderEvent;
'eip6963:requestProvider': EIP6963RequestProviderEvent;
}
}

这段代码扩展了全局 WindowEventMap 接口,以便在 TypeScript 中能够正确识别 eip6963:announceProvidereip6963:requestProvider 事件。

总结

这段代码通过定义类型、接口和实用函数,提供了一套完整的机制来管理和处理 EIP-1193 提供者。这些提供者通常是区块链钱包,代码中的机制允许应用程序宣布、请求和管理这些提供者的详情。