
Learn how to implement EIP-6963 in your web3 dapp for a more seamless connected wallet experience
In May 2023, a group of Ethereum wallet developers came together to establish a new industry standard for connecting with dapps. Before that, the common practice was for wallets to expose an EIP-1193 provider via the window.ethereum
global object in web browsers. This technique worked well in the early days when users typically owned and connected to one wallet.
As the ecosystem grew and users started utilizing multiple wallets at a time, it became difficult for dapp developers to properly manage the process of detecting what wallet a user was connected to or give users the option of selecting which wallet to use when many were installed.
In October 2023, this standard, now known as EIP-6963 or Multi-Wallet Injected Provider Discovery, was accepted. Since then, wallet developers have started introducing EIP-6963 as the default way of discovering wallet providers. MetaMask is no exception, as we’ve ensured that this standard is supported by the MetaMask wallet API and MetaMask SDK.
Additionally, dapps that rely on window.ethereum
are assured continued support. However, we encourage implementing EIP-6963 support into all dapps as the preferred provider discovery mechanism. The easiest way to do this is by integrating with third-party libraries supporting EIP-6963. Visit the MetaMask documentation for a growing list of available libraries.
This tutorial will walk you through the basic steps to implementing EIP-6963 support in your dapp if you decide not to use the available third-party libraries. It uses React and TypeScript however, any JavaScript developer should be able to follow through and implement this in their framework of choice.
The first step to supporting multi-wallet discovery in your dapp is to define all the supported interfaces and types as outlined in the improvement proposal. These interfaces and types provide a structured and standardized way to handle Ethereum wallet providers, facilitating the integration and discovery of multiple Ethereum wallets.
I’ve added comments to help you understand what each interface and type represents. Please refer to the improvement proposal for a more detailed explanation.
The next step is to establish a way to alert your dapp when new wallet connections are detected. Remember, the purpose of EIP-6963 is to enable seamless connection and switching between multiple wallets. In React, we can achieve this with the sample code below.
Here’s a breakdown of the above code sample:
We extend the WindowEventMap
with a custom event named "eip6963:announceProvider," thereby establishing a global event type for announcing the availability of new Ethereum wallet providers.
We initialize an external store, represented by an array of named providers, which is used to keep track of all detected wallet providers. This array stores objects conforming to the EIP6963ProviderDetail
interface, which includes information about the wallet provider and its corresponding Ethereum provider.
We introduce a subscription mechanism through the subscribe
function within the store object. This function listens for the "eip6963:announceProvider" event and updates the external store with the details of any newly announced providers. It ensures that providers are only added if not in the store, avoiding duplicate entries.
The store object provides two key functionalities:
The value
function allows for retrieving the current state of the external store, i.e., the list of detected wallet providers.
The subscribe
function enables components or other parts of the application to subscribe to changes in the store. When a new provider is announced and added to the store, subscribed entities are notified via a callback mechanism, allowing them to react to the updated list of providers.
Next, let’s define a useSyncExternalStore
hook to synchronize the local state with the external store defined in store.tsx above:
Let’s define a React component that uses the useSyncProviders
hook to render a button for each detected wallet provider dynamically:
Here’s a breakdown of the above React component:
We use two state hooks,selectedWallet,
anduserAccount
, to keep track of the currently selected Ethereum wallet provider and the user's account address, respectively.
We use the useSyncProviders
hook to detect each available Ethereum wallet provider dynamically. This hook returns an array of providers, each conforming to the EIP6963ProviderDetail interface that includes the provider's information and Ethereum provider object.
We define thehandleConnect
function that is invoked when a wallet provider button is clicked. This function uses the provider'srequest
method with theeth_requestAccounts
method to prompt the user for account access. If access is granted, the first account address is stored inuserAccount
, and the provider's details are stored inselectedWallet
.
Finally, we render a list of buttons for each detected wallet provider, displaying the provider's name and icon.
With our component defined, the last step is to render this component.
With these few steps, we’ve successfully implemented EIP-6963 support in our dapp on a fundamental level. See below for a visual representation of the functionality we just built. The complete code for the dapp captured in the visual can be found on GitHub.
As we continue to see wider adoption of this standard by wallet developers and third-party connection libraries, we're excited about the various use cases it opens up for the Ethereum community, especially in improving the UX for onboarding new users.
We at MetaMask are eager to collaborate with other wallet builders, dapp developers, and third-party connection libraries to ensure even greater adoption of EIP-6963. For more information on our work to support this standard, please refer to the MetaMask documentation.