EIP-6963 enables dapps to discover multiple wallet providers and wallets to announce themselves without conflicts.
Overview
Traditional wallet injection (window.ethereum) creates conflicts when multiple wallets are installed. EIP-6963 solves this by:
- Dapps: Subscribe to wallet announcements, discover all available wallets
- Wallets: Announce themselves with metadata (name, icon, identifier)
Dapp Usage
Subscribe to Announcements
import * as EIP6963 from '@voltaire/provider/eip6963';
const unsubscribe = EIP6963.subscribe((providers) => {
console.log(`Found ${providers.length} wallets`);
for (const { info, provider } of providers) {
console.log(`- ${info.name} (${info.rdns})`);
}
});
// Cleanup when done
unsubscribe();
The listener is called immediately with current providers, then again whenever new providers announce.
Find Specific Provider
import * as EIP6963 from '@voltaire/provider/eip6963';
// Start discovery
const unsubscribe = EIP6963.subscribe(() => {});
// Find MetaMask by reverse DNS
const metamask = EIP6963.findProvider({ rdns: 'io.metamask' });
if (metamask) {
const accounts = await metamask.provider.request({
method: 'eth_requestAccounts'
});
console.log('Connected:', accounts[0]);
}
unsubscribe();
Get Current Providers
import * as EIP6963 from '@voltaire/provider/eip6963';
// Start discovery
const unsubscribe = EIP6963.subscribe(() => {});
// Get snapshot of all providers
const providers = EIP6963.getProviders();
console.log(providers.map(p => p.info.name));
unsubscribe();
Wallet Usage
For wallet developers: announce your provider to dapps.
import * as EIP6963 from '@voltaire/provider/eip6963';
const unsubscribe = EIP6963.announce({
info: {
uuid: crypto.randomUUID(),
name: "My Wallet",
icon: "data:image/svg+xml;base64,PHN2Zy...",
rdns: "com.mywallet"
},
provider: myEIP1193Provider
});
// On extension unload
unsubscribe();
The wallet automatically re-announces when dapps request providers.
Types
ProviderInfo
Wallet metadata:
type ProviderInfo = Readonly<{
uuid: string; // UUIDv4 unique to session
name: string; // Human-readable name
icon: string; // Data URI (>=96x96px)
rdns: string; // Reverse DNS (e.g., "io.metamask")
}>;
ProviderDetail
Complete announcement:
type ProviderDetail = Readonly<{
info: ProviderInfo;
provider: EIP1193Provider;
}>;
Constructors
Create validated, frozen objects:
import * as EIP6963 from '@voltaire/provider/eip6963';
const info = EIP6963.ProviderInfo({
uuid: "350670db-19fa-4704-a166-e52e178b59d2",
name: "Example Wallet",
icon: "data:image/svg+xml;base64,PHN2Zy...",
rdns: "com.example.wallet"
});
console.log(Object.isFrozen(info)); // true
Environment Detection
EIP-6963 only works in browsers. Use getPlatform() to check:
import * as EIP6963 from '@voltaire/provider/eip6963';
const platform = EIP6963.getPlatform();
// 'browser' | 'node' | 'bun' | 'worker' | 'unknown'
if (platform === 'browser') {
// Safe to use EIP-6963
}
Error Handling
All errors extend EIP6963Error:
import * as EIP6963 from '@voltaire/provider/eip6963';
try {
EIP6963.subscribe(() => {});
} catch (error) {
if (error instanceof EIP6963.UnsupportedEnvironmentError) {
console.log(`Not supported: ${error.platform}`);
}
}
Error Types
| Error | Code | When |
|---|
UnsupportedEnvironmentError | UNSUPPORTED_ENVIRONMENT | Not in browser |
InvalidUuidError | INVALID_UUID | UUID not v4 format |
InvalidRdnsError | INVALID_RDNS | RDNS not valid format |
InvalidIconError | INVALID_ICON | Icon not data URI |
InvalidProviderError | INVALID_PROVIDER | No request() method |
MissingFieldError | MISSING_FIELD | Required field missing |
InvalidArgumentError | INVALID_ARGUMENT | Bad function argument |
Security
Icon XSS Prevention: Always render wallet icons via <img src={icon}> elements.
Never inject icon content directly into the DOM, as malicious SVG icons could contain scripts.
Common RDNS Values
| Wallet | RDNS |
|---|
| MetaMask | io.metamask |
| Coinbase Wallet | com.coinbase.wallet |
| Rainbow | me.rainbow |
| Trust Wallet | com.trustwallet.app |
| Rabby | io.rabby |
API Reference
Dapp Functions
| Function | Description |
|---|
subscribe(listener) | Subscribe to announcements, returns unsubscribe |
getProviders() | Get current providers snapshot |
findProvider({ rdns }) | Find provider by RDNS |
Wallet Functions
| Function | Description |
|---|
announce({ info, provider }) | Announce provider, returns unsubscribe |
Utilities
| Function | Description |
|---|
getPlatform() | Detect runtime environment |
ProviderInfo(input) | Create validated ProviderInfo |
ProviderDetail(input) | Create validated ProviderDetail |
See Also