Skip to main content

Integrating with Web3-React

This tutorial is a step-by-step guide on how to integrate multiple wallets such as Coinbase Wallet, Metamask, and Wallet Connect into your dapp using the web3-react library.

To explore a running version of the finished product, fork our CodeSandbox.

Example of a custom modal built with the web3-react library


This guide assumes you have a React application already setup and running. If you are more comfortable jumping straight into code, below is the final working example of a multi-wallet modal integration. We encourage you to fork the sandbox and reconfigure it to suit the needs of your dapp setup.

Prerequisites

Setup Web3-react and Wallet connectors

Step 1: Install ethers and web3-react

Install ethers.js as a required dependency for web3-react. If you are building your dapp with web3.js, you can additionally install the library.

yarn add ethers
yarn add web3 # optional

yarn add @web3-react/core

Step 2: Import and setup Web3ReactProvider

In your index.js file, import the Web3ReactProvider from web3-react and a Web3Provider from ethers.js or web3.js. Define a getLibrary function that returns an instance of the Web3Provider. Wrap the Web3ReactProvider around your app root component to make the provider globally accessible throughout your dapp.

import { Web3ReactProvider } from '@web3-react/core'
import { Web3Provider } from "@ethersproject/providers";

function getLibrary(provider) {
return new Web3Provider(provider);
}

ReactDOM.render(
<Web3ReactProvider getLibrary={getLibrary}>
<App />
</Web3ReactProvider>,
document.getElementById('root')
);

Step 3: Import and instantiate Wallet connectors

Install the wallet connectors of your choice. Here we install Coinbase Wallet, Wallet Connect, and an Injected connector (used to connect with Metamask).

caution

This tutorial uses the latest non-beta version of web3-react, web3-react v6.

While v6 uses the correct Coinbase Wallet SDK version, it still refers to Coinbase Wallet SDK by its previous name, walletlink. Future versions of web3-react will use the updated naming convention.

yarn add @web3-react/walletlink-connector # Coinbase Wallet
yarn add @web3-react/walletconnect-connector # Wallet Connect
yarn add @web3-react/injected-connector # Injected (e.g. Metamask)

In your App.js file, instantiate the connectors to integrate into your dapp. Each connector has its own set of required parameters to pass in, such as a fallback JSON RPC URL or default chain ID.

import { WalletLinkConnector } from "@web3-react/walletlink-connector";
import { WalletConnectConnector } from "@web3-react/walletconnect-connector";
import { InjectedConnector } from "@web3-react/injected-connector";

const CoinbaseWallet = new WalletLinkConnector({
url: `https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`,
appName: "Web3-react Demo",
supportedChainIds: [1, 3, 4, 5, 42],
});

const WalletConnect = new WalletConnectConnector({
rpcUrl: `https://mainnet.infura.io/v3/${process.env.INFURA_KEY}`,
bridge: "https://bridge.walletconnect.org",
qrcode: true,
});

const Injected = new InjectedConnector({
supportedChainIds: [1, 3, 4, 5, 42]
});
info

Seeing errors? Check out the Troubleshooting section below for help.

Connect and disconnect from Wallet

In your App.js file add an import for the useWeb3React hook, which provides a set of methods to activate and deactivate the connection to the wallet of your choice.

import { useWeb3React } from '@web3-react/core'

Inside your App function, add your activate and deactivate methods:

function App() {

const { activate, deactivate } = useWeb3React();
...
}

Then, in your App's HTML template, add a button for each wallet and bind the methods onto your UI components.

<button onClick={() => { activate(CoinbaseWallet) }}>Coinbase Wallet</button>
<button onClick={() => { activate(WalletConnect) }}>Wallet Connect</button>
<button onClick={() => { activate(Injected) }}>Metamask</button>

<button onClick={deactivate}>Disconnect</button>

That's it! You should now be able to seamlessly connect to Coinbase Wallet and other wallets from your dapp.

Access connection, account, network information

To access information about the user's connection status, Ethereum address, and connected network chain ID, you'll need to import additional variables from the useWeb3React hook.

Again, you'll do this by adding the active, chainId, and account methods inside your App function and binding the methods in your HTML template:

/*
active: boolean indicating connection to user’s wallet
account: connected user's public wallet address
chainId: chain id of the currently connected network
*/

function App() {

# add this line
const { active, chainId, account } = useWeb3React();
...

return (
...

# add these 3 lines
<div>Connection Status: {active}</div>
<div>Account: {account}</div>
<div>Network ID: {chainId}</div>
...

);
}

Switch networks or add custom networks

Web3-React does not have built-in support for Ethereum interactions. In order to add or switch networks, you must directly make a request (via EIP-3085 or EIP-3326) to the Web3Provider. This provider is accessible via the library context variable in the useWeb3React hook.

Here is an example of requesting to switch networks and adding the network as a fallback if it is not already present on the user’s wallet:

const { library } = useWeb3React();

// example of switching or adding network with Harmony Mainnet
const switchNetwork = async () => {
try {
await library.provider.request({
method: "wallet_switchEthereumChain",
params: [{ chainId: "0x63564c40" }],
});
} catch (switchError) {
// 4902 error code indicates the chain is missing on the wallet
if (switchError.code === 4902) {
try {
await library.provider.request({
method: "wallet_addEthereumChain",
params: [
{
chainId: "0x63564c40",
rpcUrls: ["https://api.harmony.one"],
chainName: "Harmony Mainnet",
nativeCurrency: { name: "ONE", decimals: 18, symbol: "ONE" },
blockExplorerUrls: ["https://explorer.harmony.one"],
iconUrls: ["https://harmonynews.one/wp-content/uploads/2019/11/slfdjs.png"]
}
],
});
} catch (error) {
console.error(error)
}
}
}
};

To learn more about how to add this functionality, see the demo CodeSandbox.

As with the example above, any Ethereum interactions, such as sending a transaction or making a contract call, can be done by directly sending a request through the library of your choice. An example of of signing and verifying personal signatures can also be found in the demo CodeSandbox. See the signMessage function as a place to start.

Troubleshooting

I run into the following error: Module not found: Error: Can't resolve <'buffer'/'util'/...>

Due to the removal of default polyfills in webpack5, you must install the following utilities:

yarn add buffer
yarn add util
yarn add stream-browserify
yarn add assert

Then, add the following code snippet to your webpack.config.js:

resolve: {
fallback: {
'fs': false,
'stream': require.resolve('stream-browserify'),
'buffer': require.resolve('buffer/'),
'util': require.resolve('util/'),
'assert': require.resolve('assert/'),
},
}

If you are using an application built on create-react-app locally, you must run npm run eject to be able to customize your webpack configuration.

The wallet connection does not persist upon refreshing the browser

Web3Modal provides a built-in option for you to automatically cache the connected provider.

// set cacheProvider parameter as true when instantiating web3modal
const web3Modal = new Web3Modal({
cacheProvider: true, // optional
providerOptions // required
});

// hook to automatically connect to the cached provider
useEffect(() => {
if (web3Modal.cachedProvider) {
connectWallet();
}
}, []);>
I want to give the user the option to "disconnect" from my dapp

Unfortunately, there is no built-in way of disconnecting a user from your dapp - the user may only choose to do so from within their wallet apps. However, you can mimic the behavior by clearing the state and cache of your application when a chooses to disconnect.

const refreshState = () => {
setAccount();
setChainId();
};

const disconnect = async () => {
await web3Modal.clearCachedProvider();
refreshState();
};

<button onClick={disconnect}>Disconnect</button>

Additional Resources

Was this helpful?