rspace-online/src/encryptid/eip6963.ts

95 lines
2.7 KiB
TypeScript

/**
* EIP-6963 Multi-Provider Discovery
*
* Discovers all injected browser wallets (MetaMask, Rainbow, etc.)
* via the standardized EIP-6963 event protocol. Zero dependencies.
*
* @see https://eips.ethereum.org/EIPS/eip-6963
*/
// ============================================================================
// TYPES
// ============================================================================
export interface EIP6963ProviderInfo {
uuid: string;
name: string;
icon: string;
rdns: string;
}
export interface EIP1193Provider {
request(args: { method: string; params?: any[] }): Promise<any>;
on?(event: string, handler: (...args: any[]) => void): void;
removeListener?(event: string, handler: (...args: any[]) => void): void;
}
export interface EIP6963ProviderDetail {
info: EIP6963ProviderInfo;
provider: EIP1193Provider;
}
interface EIP6963AnnounceProviderEvent extends Event {
detail: EIP6963ProviderDetail;
}
// ============================================================================
// WALLET PROVIDER DISCOVERY
// ============================================================================
export class WalletProviderDiscovery {
private providers = new Map<string, EIP6963ProviderDetail>();
private listeners = new Set<(providers: EIP6963ProviderDetail[]) => void>();
private listening = false;
private handler: ((e: Event) => void) | null = null;
start(): void {
if (this.listening) return;
this.listening = true;
this.handler = (e: Event) => {
const detail = (e as EIP6963AnnounceProviderEvent).detail;
if (!detail?.info?.uuid || !detail?.provider) return;
this.providers.set(detail.info.uuid, detail);
this.notify();
};
window.addEventListener('eip6963:announceProvider', this.handler);
window.dispatchEvent(new Event('eip6963:requestProvider'));
}
stop(): void {
if (!this.listening || !this.handler) return;
window.removeEventListener('eip6963:announceProvider', this.handler);
this.handler = null;
this.listening = false;
}
getProviders(): EIP6963ProviderDetail[] {
return [...this.providers.values()];
}
getProvider(uuid: string): EIP6963ProviderDetail | undefined {
return this.providers.get(uuid);
}
getProviderByRdns(rdns: string): EIP6963ProviderDetail | undefined {
for (const detail of this.providers.values()) {
if (detail.info.rdns === rdns) return detail;
}
return undefined;
}
onProvidersChanged(cb: (providers: EIP6963ProviderDetail[]) => void): () => void {
this.listeners.add(cb);
return () => this.listeners.delete(cb);
}
private notify(): void {
const list = this.getProviders();
for (const cb of this.listeners) {
try { cb(list); } catch {}
}
}
}