How to change network in metamask using react js

26.8k views Asked by At

I am developing my first Dapp, I am using metamask and web3 for this. As far now, I am able to get my wallet balance and connect account to metamask. Now I am trying switch between two networks, I am using handleChainChanged, also I am passing chainId and Networkversion but, it is giving me error. I am uncertain about returning anything from changeNetwork function or I only have to pass chainId and Networkversion.

import { useStoreApi } from "./storeApi";
import { useState } from "react";
import useWeb3 from "./useWeb3";
import { Button, TextField } from "@material-ui/core";

import "./App.css";

function App() {
  const { balance, address, message, setAddress, setBalance } = useStoreApi();
  const web3 = useWeb3();

  // get user account on button click
  const getUserAccount = async () => {
    if (window.ethereum) {
      try {
        await window.ethereum.enable();
        web3.eth.getAccounts().then((accounts) => {
          setAddress(accounts[0]);
          updateBalance(accounts[0]);
          console.log(accounts);
        });
      } catch (error) {
        console.error(error);
      }
    } else {
      alert("Metamask extensions not detected!");
    }
    web3.eth.getChainId().then(console.log);
  };

  const updateBalance = async (fromAddress) => {
    await web3.eth.getBalance(fromAddress).then((value) => {
      setBalance(web3.utils.fromWei(value, "ether"));
    });
  };

  const changeNetwork = async () => {
    if (window.ethereum) {
      try {
        await window.ethereum.enable();
        window.ethereum._handleChainChanged({
          chainId: 0x1,
          networkVersion: 1,
        });
      } catch (error) {
        console.error(error);
      }
    }
  };

  return (
    <div className="App">
      <header className="App-header">
        {address ? (
          <>
            <p> Balance: {balance} </p>
          </>
        ) : null}
        <Button
          onClick={() => getUserAccount()}
          variant="contained"
          color="primary"
        >
          Connect your account
        </Button>
        <Button onClick={changeNetwork} variant="contained" color="primary">
          Switch to mainnet ethereum
        </Button>

      </header>
    </div>
  );
}

export default App;

4

There are 4 answers

0
Siddharth On

You can use wallet_switchEthereumChain method of RPC API of Metamask

Visit: https://docs.metamask.io/guide/rpc-api.html#wallet-switchethereumchain

0
Lee Ming On
export async function switchToNetwork({
    library,
    chainId,
}: SwitchNetworkArguments): Promise<null | void> {
    if (!library?.provider?.request) {
        return
    }
    const formattedChainId = hexStripZeros(
        BigNumber.from(chainId).toHexString(),
    )
    try {
        await library.provider.request({
            method: 'wallet_switchEthereumChain',
            params: [{ chainId: formattedChainId }],
        })
    } catch (error) {
        // 4902 is the error code for attempting to switch to an unrecognized chainId
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        if ((error as any).code === 4902) {
            const info = CHAIN_INFO[chainId]

            await library.provider.request({
                method: 'wallet_addEthereumChain',
                params: [
                    {
                        chainId: formattedChainId,
                        chainName: info.label,
                        rpcUrls: [info.addNetworkInfo.rpcUrl],
                        nativeCurrency: info.addNetworkInfo.nativeCurrency,
                        blockExplorerUrls: [info.explorer],
                    },
                ],
            })
            // metamask (only known implementer) automatically switches after a network is added
            // the second call is done here because that behavior is not a part of the spec and cannot be relied upon in the future
            // metamask's behavior when switching to the current network is just to return null (a no-op)
            try {
                await library.provider.request({
                    method: 'wallet_switchEthereumChain',
                    params: [{ chainId: formattedChainId }],
                })
            } catch (error) {
                console.debug(
                    'Added network but could not switch chains',
                    error,
                )
            }
        } else {
            throw error
        }
    }
}
0
Zia On
  const changeNetwork = async () => {
if (window.ethereum) {
  try {
    await window.ethereum.request({
    method: 'wallet_switchEthereumChain',
      params: [{ chainId: Web3.utils.toHex(chainId) }],
    });
    });
  } catch (error) {
    console.error(error);
  }
}
changeNetwork()
0
Nagibaba On

What if the user doesn't have the required network added? Here is an expanded version which tries to switch, otherwise add the network to MetaMask:

const chainId = 137 // Polygon Mainnet

if (window.ethereum.networkVersion !== chainId) {
      try {
        await window.ethereum.request({
          method: 'wallet_switchEthereumChain',
          params: [{ chainId: web3.utils.toHex(chainId) }]
        });
      } catch (err) {
          // This error code indicates that the chain has not been added to MetaMask
        if (err.code === 4902) {
          await window.ethereum.request({
            method: 'wallet_addEthereumChain',
            params: [
              {
                chainName: 'Polygon Mainnet',
                chainId: web3.utils.toHex(chainId),
                nativeCurrency: { name: 'MATIC', decimals: 18, symbol: 'MATIC' },
                rpcUrls: ['https://polygon-rpc.com/']
              }
            ]
          });
        }
      }
    }