Create an Avalanche dApp with Ethers, Metamask and React

Alexander Lechner
Coinmonks
6 min readDec 13, 2021

--

A quick step-by-step guide on how to create a dApp for an Avalanche contract in React.

dApp with basic read and write functionality

This article is part 2 of a series on how to build a dApp on Avalanche. Check out the other parts here:

Used software versions:

  • nodejs: v16.13.0
  • hardhat: 2.7.0
  • ethereum-waffle: 3.4.0
  • ethers: 5.5.1
  • metamask/onboarding: 1.0.1
  • react: 17.0.2

Step 1

We’ll continue with the code from Part 1. Have a look if you didn’t read it yet, or start by checking out the code from this repository: https://github.com/lechneal/solidity-hello-world-contract

$ git clone https://github.com/lechneal/solidity-hello-world-contract my-awesome-contract

In the last tutorial we created a Solidity contract. In this tutorial we’re going to build a dApp. To make a clear distinction we’ll rename the folder to my-awesome-dapp:

$ mv my-awesome-contract my-awesome-dapp

Step 2

Let’s use ReactJS to build the frontend for our dApp. We’ll create the frontend within the hardhat project, in a new folder called frontend:

$ cd my-awesome-dapp
$ npx create-react-app frontend

This creates a dummy react app that we’re going to modify in the upcoming steps. To run the dummy app, go into the frontend folder and run it with npm start:

$ cd frontend
$ npm start
Compiled successfully!
You can now view frontend in the browser.Local: http://localhost:3000

Step 3

In order to interact to with the contract on the Avalanche network, our app needs some contract metadata. We will auto-generate this metadata as part of the contract deploy flow and store it in frontend/src/contracts. So let’s create the required folder:

$ cd ..
$ mkdir -p frontend/src/contracts

Now let’s modify the deploy script, so that the contract metadata is stored in the newly created folder:

https://github.com/lechneal/solidity-hello-world-dapp/blob/main/scripts/deploy.js

Now, let’s go ahead and deploy the contract to the Avalanche Test network:

$ npx hardhat run scripts/deploy.js --network avalancheTest
Deploying contracts with account: 0x1a08594081B5AED71de0c203AC188311a83e7aD7
Account balance: 9644089875000000000
HelloWorld address: 0x64aD192f8371dCa9eD9C52d761bafD001829ce62
Stored address in /Users/username/my-awesome-dapp/scripts/../frontend/src/contracts/helloworld-address.json
Stored artifact in /Users/username/my-awesome-dapp/scripts/../frontend/src/contracts/HelloWorld.json

As you see the deploy script created 2 new files:

Step 4

Now we’re updating the contract metadata every time we deploy the contract. But for the user to interact with the contract, we also need to connect to a wallet.

For our dApp we’re going to support the MetaMask wallet. This means, a user that wants to use our dApp needs to have the MetaMask wallet installed.

Because installing and connecting to a wallet can be cumbersome, we’re going to make this process as simple as possible for the user. We will use the MetaMask Onboarding library, which redirects the user to the right installation page if MetaMask is not yet installed. Furthermore, we will prompt the user to setup MetaMask for Avalanche automatically.

Let’s install the Metamask Onboarding dependency:

$ cd frontend
$ npm install @metamask/onboarding

For the onboarding process we’ll create a dedicated component in frontend/src/components/Onboarding.js:

https://github.com/lechneal/solidity-hello-world-dapp/blob/main/frontend/src/components/Onboarding.js

This component has 4 different states:

  • The user doesn’t have MetaMask installed in the browser: then show a button that links to the MetaMask plugin installation page
  • The user has MetaMask installed, but didn’t yet give the dApp permission to access the account information: then show a button that requests access to MetaMask
  • The user has MetaMask installed and given all permissions, but does not have the right chain (Avalanche) selected: then ask the user to switch to the Avalanche chain
  • The user has given all permissions and is on the correct chain (Avalanche): then show the account and chain information

Now let’s add the onboarding component to our app in frontend/src/App.js:

https://github.com/lechneal/solidity-hello-world-dapp/blob/main/frontend/src/App.js

Run the app with npm start and see the onboarding component in action. Once you connected your MetaMask wallet and switched to the Avalanche chain, it should look like this:

Successfully connected to MetaMask and the Avalanche Test Network

Step 5

Once the user has successfully connected the MetaMask wallet and selected the Avalanche chain, we’re ready to connect to the Avalanche contract. To do that, we’ll implement the onConnected handler of the OnboardingButton.

Let’s update frontend/src/App.js:

https://github.com/lechneal/solidity-hello-world-dapp/blob/main/frontend/src/App.js

To interact with our contract we’re using the ethers.js package. First thing we do after the user is connected, is to create an ethers-provider using the MetaMask wallet implementation window.ethereum. Then we create a contract object based on the address and artifact created in Step 3. We can use the contract object as any other JS object, but behind the scenes ether.js is interacting with the actual contract on the Avalanche network.

Once the contract object is created, we are ready to fetch the latest message of the contract. This can be done by calling the public method message of the contract: await contract.message().
We’re also setting up an interval, to fetch the latest message every 30 seconds.

If we run the app it will look like this:

Step 6

We’re now showing the latest message to the user. The next step is to allow the user to modify the message by creating a transaction on the Avalanche network.

For that, let’s add a new component in frontend/src/components/UpdateForm.js:

https://github.com/lechneal/solidity-hello-world-dapp/blob/main/frontend/src/components/UpdateForm.js

This component either shows the hash of an ongoing transaction, or a simple input form allowing the user to update the message.

Next we will include this component in App.js:

https://github.com/lechneal/solidity-hello-world-dapp/blob/main/frontend/src/App.js

We added the update form to the app and call the updateMessage method when the user clicks on “submit”. Within the update method we first call the contract’s update method:

const tx = await this.state.contract.update(newMessage)

This creates a new transaction that opens a popup in MetaMask and needs to be confirmed (and paid) by the user:

Once the user did confirm the transaction, the Avalanche transaction is submitted and we need to wait until a block including this transaction is mined. We’ll wait for that using the line:

await tx.wait()

Once this is finished, we get a receipt object. This receipt contains a status field, which indicates whether an exception happened or not.

If the transaction was successful, we are fetching the latest message (with a timeout of 1 second). If the transaction was unsuccessful, we display the error message instead.

Step 7

That’s it, our dApp is done. All that’s left to do is to build the App and deploy it.

$ npm run build
> frontend@0.1.0 build
> react-scripts build
Creating an optimized production build...
Compiled successfully.
File sizes after gzip:176.98 KB build/static/js/2.3b7fde82.chunk.js
3.4 KB build/static/js/main.06f52d40.chunk.js
769 B build/static/js/runtime-main.ff5b8ea4.js
292 B build/static/css/main.106baaae.chunk.css
...

This generates the build files in my-awesome-dapp/frontend/build.

Check out the next part of this series: Part 3: Host a decentralised application with IPFS and AWS

Resources & Links:

Join Coinmonks Telegram Channel and Youtube Channel learn about crypto trading and investing

Also, Read

--

--