Connect dApp to MetaMask Wallet using Ethers.js
Connect your decentralized application to any desired network using MetaMask and Ethers.js
Originally published at surajondev.com
Introduction
A DApp, which stands for decentralized application, uses a smart contract to run on a peer-to-peer (P2P) blockchain network. To interact with a blockchain, users need to connect their crypto wallet to the dApp.
MetaMask is the most popular crypto wallet out there. It runs as a browser extension on the popular browser. You can also download its mobile application for Android and iOS. It is one of the most secure and trusted wallets to use. Almost every popular dApp has support for MetaMask. So, having support for MetaMask for any dApp is a plus point.
Today, we are going to learn about the following things:
- Connecting dApp to MetaMask
- Extracting Accounts from MetaMask
- Switching between different Networks for instance from Polygon to Avalanche
You can follow me on Twitter(@surajondev) to get notified for such posts in the future.
Let's get started to build the application with the above features.
Environment Setup
We are going to use React for building our frontend. You can install React with the below command:
command:
npx create-react-app connect-metamask
After installing React, delete all the unnecessary files and code.
As for the dependencies, we just need one library, ethers. Ethers will be helpful in interacting with our wallet. Install it with the below command:
command:
npm i ethers
Note: To run the above commands, you need to have node.js pre-installed.
Now, that everything is set up, let's write some code.
App.js
We are going to implement all our features only in the App.js
file. As it will be easy to understand the code in one place.
Imports
At the top, we need to import the necessary file and library that we are going to use. As for imports, we have the following:
import "./styles.css"; // styling the component using CSS
import { useState } from "react"; // storing data in the state
import { ethers } from "ethers"; // interacting with wallet
Return Statement
In the file, we need to define a functional component, where all the magic will happen. At the top, we have to define all the states for storing data.
export default function App() {
const [publicKey, setPublickey] = useState();
const [network, setNetwork] = useState();
const [chainId, setChainId] = useState();
const [msg, setMsg] = useState();
return()
}
As for the UI, it will go into the return code block.
return (
<div className="App">
<h1>Connect MetaMask</h1>
<button onClick={connectButton}>Connect Wallet</button>
<br />
<button className="btn" onClick={() => swithcNetwork(137)}>
Connect Polygon
</button>
<br />
<button className="btn" onClick={() => swithcNetwork(43114)}>
Connect Avalanche
</button>
<p>Public Key: {publicKey}</p>
<p>Network: {network}</p>
<p>Chain ID : {chainId}</p>
{msg && <p>{msg}</p>}
</div>
);
It will result in the below output:
Note: React will give errors as we haven't defined the function used for the onClick event for the buttons. The above screenshot is of complemented project.
We are having the following components in the return section of the application:
Connect Wallet: On clicking this button,
connectButton
function will invoke. This will connect our dApp to the MetaMask.Connect Polygon/Avalanche: This button will invoke the
switchNetwork()
function for changing the network to Polygon/Avalanche.Network Details: When the user successfully connects to the MetaMask. The Public key, Chain ID of the network, and name of the network will be displayed.
Msg: If any error occurs, such as MetaMask is not installed. This will display the error to the user.
The return statement has been implemented quite well. Let's write code for all the functions used above.
Connect Wallet Button
This function will make a request to the MetaMask for the connection. Before that, we will check whether MetaMask is installed or not.
Here is the code for connect wallet button:
const connectButton = async () => {
const { ethereum } = window;
if (ethereum.isMetaMask) {
const provider = new ethers.providers.Web3Provider(ethereum);
const accounts = await provider.send("eth_requestAccounts", []);
const { name, chainId } = await provider.getNetwork();
setNetwork(name);
setChainId(chainId);
setPublickey(accounts[0]);
} else {
setMsg("Install MetaMask");
}
};
At the top, we have extracted the ethereum object from the window. This object has information related to blockchain interaction. When MetaMask is installed, it injects its data into this object. That's why, it become one of the important objects while dealing with MetaMask and blockchain.
With the object, ethereum.isMetaMask
, we are checking for the MetaMask. It returns true
if MetaMask is installed and false
otherwise. We are running all the code only if MetaMask is installed otherwise, it will throw a message to Install MetaMask
.
A Provider in ethers is a read-only abstraction to access the blockchain data. To access data we have used the ethers.providers.Web3Provider()
function with extracted ethereum
object from the window as the argument. With provider.send()
function, we are requesting the account from the MetaMask and storing them in array format in the accounts
variable.
provider.getNetwork
provides us with the network details. Form that we are extracting the name and chainId of the network. The network here will be the default from the MetaMask. After this, we are setting the state with the available data to display to the user.
Switch Network Button
The second and third button is for switching between Polygon and Avalanche network.
const swithcNetwork = async (chainId) => {
try {
await window.ethereum.request({
method: "wallet_addEthereumChain",
params: [avlNetwork[`${chainId}`]]
});
setNetwork(avlNetwork[`${chainId}`].chainName);
setChainId(chainId);
} catch (error) {
setMsg(error);
}
};
wallet_addEthereumChain
method will add the network to the MetaMask and switch to that network. This function takes an argument chainId
to change the network to that matching network. Every network is associated with a chainId and it's unique for every network. We have try-catch block for setting msg
, if any error occurs.
The params contain information regarding the network such as chainId, rpcUrls, nativeCurrency, and others. I have stored the network information in an object format in the variable avlNetwork
.
const avlNetwork = {
137: {
chainId: `0x${Number(137).toString(16)}`,
rpcUrls: ["https://rpc-mainnet.matic.network/"],
chainName: "Polygon Mainnet",
nativeCurrency: {
name: "MATIC",
symbol: "MATIC",
decimals: 18
},
blockExplorerUrls: ["https://polygonscan.com/"]
},
43114: {
chainId: `0x${Number(43114).toString(16)}`,
rpcUrls: ["https://api.avax.network/ext/bc/C/rpc"],
chainName: "Avalanche C-Chain",
nativeCurrency: {
name: "Avalanche",
symbol: "AVAX",
decimals: 18
},
blockExplorerUrls: ["https://snowtrace.io/"]
}
};
There is a lot of information regarding the network to which we are switching. You can get all these information for any network from ChainList and ChainList - JSON. I have used the chainId as the name for each object so that we can access the network information by just passing the chainId.
MetaMask accepts chainId in Hexadecimal format with the prefix 0x
. We have converted the chainId of every network into the hexadecimal with the toString(16)
function, 16 for hexadecimal.
Demo
Now the project has been completed. It's time to test the application. If you click on Connect Wallet
, it will connect our dApp to the MetaMask and provide us with details.
Now, you are eligible to switch to a different network. Click on Connect Polygon
to switch to the Polygon Mainnet. This will pop a message on the MetaMask wallet, requesting permission to switch to the Polygon Mainnet.
After clicking the Switch Network
, you will be switched to the Polygon Mainnet. You will be able to see the details of the current network in the application.
I have created a codesandbox for these projects. You can see the code and the live working of the project here.
Connect With Me
Conclusion
Connecting your dApp to Wallet is an important step in building a blockchain-based application. There are various methods to achieve these features. I have explained one such here. In the future, I might discuss using other libraries to do it more effectively with less code. For that, You can follow me to get notified.
I hope, this article has helped you in connecting your dApp to the wallet. Thanks for reading the blog post.