ReactJS and Metamask integration

Do repost and rate:

The last time I start learning some react and METAMASK integration for my side project. After that, I prepare a basic example of this integration.

The main functionality of this example is:

  • The connecting site to metamask 
  • Detect network 
  • Detect account and network change

In further parts we will need some react library:

  • react-bootstrap
  • bootstrap
  • @metamask/detect-provider
  • web3

To install these dependencies use the command:

yarn add web3 @metamask/detect-provider bootstrap react-bootstrap  

In this tutorial, I want to prepare a simple react js application integrate with a cryptocurrency wallet. To create an application a use ReactJS and react-bootstrap.

All tutorial parts will be stored on GitHub repository: @Driblinho/0x-react-tutorial.

To create an application I use facebook/create-react-app starter

npx create-react-app 0x-react-tutorial cd 0x-react-tutorial

In further parts of the tutorial, I try to explain the functioning of the application.

 

Part 1 - Prepare a simple template for an application.

To check locally working application you can clone it from the repository and go to branch part-1-template:

git clone https://github.com/Driblinho/0x-react-tutorialgit checkout --track origin/part-1-templateyarn install?

To run app execute:

yarn start

In this part, I create a simple layout using a bootstrap component and some basic functionality. The layout you can check in src/App.js. Functionality create at this moment is SignIn and SignOut method bind to navbar buttons and changing isLogged state. Another component that is useful in the next part of the tutorial is Alert for users displayed in the right corner. I create a Message component using the Alert component from react-bootstrap:

  {props.head}    

{props.body}

For store message I create state :

 const [messages, setMessage] = useState([{...}])

In this state, I store objects with message and color variant of message.

{    head : "User Rejected Request",     body: 'Please connect to MetaMask.',     variant: 'info'}

Inside App template, all message is displayed on top of the layout using simple CSS code.

{ messages.map((item,i) => ( )) }

You can see how the app work at that point of tutorial on the gif below:    

Part 2 - Integrate Metamask witch application.

In this part of the tutorial, I prepare integration with metamask. The main functionality in this part are:

  • Connect app witch metamask
  • Detect network change
  • Detect account change

To check the app from part two you must change branch and run the application:  

git checkout --track origin/part-2-metamaskyay start

 

Part 2.1 Metamask connect

Before start interact with the metamask app check that has access to the provider by using a detector from @metamask/detect-provider

const provider = await detectEthereumProvider()

by checking provider variable inside if statement can detect metamask. To connect metamask with the app and get the user address I execute method ConnectWallet() inside SignIn when method return address was displayed message for the user.  

const SignIn = async () => {      //Detect Provider      const provider = await detectEthereumProvider()      const web3 = new Web3(provider)      if(!provider) {        setMessage(messages => [...messages, {head : "Wallet not found", body: `Please install MetaMask!`, variant: 'warning'}])      } else {        const address = await ConnectWallet()        if (address)          setMessage(messages =>[...messages, {head : "User Login", body: `addres: ${address}`, variant: 'success'}])      }        }

All connect logic is inside the below method:

const ConnectWallet = async () => {    console.log("Try Connect");    try {      await window.ethereum.enable();      const id = await window.ethereum.request({ method: 'eth_chainId' })      setCurrentChainID(() => parseInt(id, 16))      const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' })      setIsLogged(true)      setCurrentAccount(accounts[0])      return accounts[0]    } catch(err) {        if (err.code === 4001) {          // EIP-1193 userRejectedRequest error          // If this happens, the user rejected the connection request.          console.log('Please connect to MetaMask.')          setMessage(messages =>[...messages, {head : "User Rejected Request", body: 'Please connect to MetaMask.', variant: 'info'}])        } else if(err.code === -32002) {          console.log('Please unlock MetaMask.')          setMessage(messages =>[...messages, {head : "User Request Pending", body: 'Please unlock MetaMask and try agin.', variant: 'info'}])        } else {          console.error(err);          setMessage(messages =>[...messages, {head : "Error", body: err.message, variant: 'info'}])        }    }      }

 

MetaMask injects a global API into websites visited by its users at window.ethereum. This API allows websites to request users' Ethereum accounts, read data from blockchains the user is connected to, and suggest that the user sign messages and transactions. Ethereum Provider API

   

ConnectWallet method use injected window.ethereum inside try...catch statement to enable wallet next using ethereum.request and methods eth_chainId,eth_requestAccounts application save in state chainID and user account address. Application inside catch has simple error management. App display custom message for error code 4001 and -32002 otherwise presents standard error message.

  • 4001 - User rejected the connection request
  • -32002 - Metamask was locked by password

 

Part 2.2 Detect network change

In this section, I describe how applications manage used networks. For represent, chain in-app was created component Chain.

const Chain = (props) => {    const chainId = props.chainId    let chainLogo    let variant    let chainName    switch (chainId) {      case 1: //ETH          chainLogo = ChainLogo.eth          variant = "light"          chainName = "Ethereum Network"        break;      case 56: //BNB          chainLogo = ChainLogo.bnb          variant = "secondary"          chainName = "Binance Smart Chain"        break;      case 128: //HT          chainLogo = ChainLogo.ht          variant = "light"          chainName = "Heco"        break;      case 100: //xDai          chainLogo = ChainLogo.xdai          variant = "light"            chainName = "xDai Stable Chain"        break;      case 137: //Polygon          chainLogo = ChainLogo.polygon          variant = "light"          chainName = "Polygon Network"        break;      default: // Unknown network          chainLogo = ChainLogo.unknown          variant = "light"          chainName = "Unknown network?"        break;    }    return(                  {chainName}                }      >                  )  }

A component represents networks by id:

  • ETH - 1
  • BNB - 56
  • HT(Heco) - 128
  • xDai - 100
  • Polygon - 137

To detect chain is used event chainChanged inside react hook useEffect.

useEffect(() => {    ...    window.ethereum.on('chainChanged', (_chainId) => {      console.log(_chainId);      setCurrentChainID(() => parseInt(_chainId, 16))    });  }, []);

When the event was fired update currentChainID state witch was used by Chain component to display the proper chain logo. 119db249ec66d1775fc878b4f92865a5c421e57a2de994ed420e9ce01a10dd03.png

Below gif example of a working application:

550dc23183e400d51b08d1d26eedf0dee858cf6fdffec9c86456f6ade67b7be2.gif

Future

In the future part of the tutorial, I plan to present some backend integration with metamask.

Ty for reading.

Referrals: 

Instant cross-chain crypto swaps ETH, BSC, HECO

Trade 24/7 Stocks, Crypto, and Forex on Morpher chain - Free 50 MPH

Maiar EGLD, BNB, ETH Wallet

CoinList - pre-sales auctions

Ern free CHSB - SwissBorg

Participate in Bifrost vsKSM #Mintdrop and win a huge $BNC airdrop.

Regulation and Society adoption

Ждем новостей

Нет новых страниц

Следующая новость