Zero-to-Hero Full-Stack DApp Development in 10 Minutes

George Mulhearn
Coinmonks
Published in
11 min readJul 9, 2022

--

Welcome!

This guide will aim to provide you with full coverage of the tools and modern technology needed to get started developing full-stack Ethereum (EVM) decentralized apps (dApps) in 2022. Whether it’s your first time, or you want a refresher on a modern DApp stack, this guide is for you!

We will be kick-starting a dApp stack using the following fresh frameworks and technologies:

  • React NextJS — for our front-end development and deployment
  • Typescript — for type safety and cleaner code ;)
  • Hardhat — for our smart contract development, testing, and deployment
  • ChakraUI — as our UI component library (although you can easily swap this out for your preferred library!)

What you need to know

We’ll try to cover everything in this guide, however, there is some prior knowledge that will make your life easier:

  • React — React is the heart of most dApp front-ends, you should be somewhat familiar with the basics of React development.
  • Node — Being familiar with and having node installed is required for this guide. We are using v16.15.x, however other versions should work fine.
  • Basic DApp Understanding — Being familiar with, or having used DApps before will help a lot in your understanding. We also will be assuming that you have MetaMask installed and have a base understanding of it!

What We’ll Be Covering:

— 1. What We’re Building
— 2. Setting up Our Project
— 3. Template Overview
— 4. Running the Template
— 5. Implementing our Own Counter DApp
— 6. Deploying it to the World

1. What We’re Building

We’ll be building the smart contracts, front-end, and blockchain interaction logic for a simple Counter app. Despite being a simple dApp, the skills you’ll pick up can be easily applied to larger projects using the same techniques.

To do this, we’ll be working off a dApp template with all the core technology ready for us to use. This template is flexible enough for us to build any dApp we want from it.

2. Setting Up Our Project

Installations

Let’s get started by first pulling down the template project and opening it up in VS Code (or your IDE of choice).

git clone https://github.com/gmulhearn/dapp-stack-template.git counter-dapp && cd counter-dapp

Next, we’ll need to install the package dependencies for both the hardhat project and the NextJS/front-end project:

cd hardhat && npm install && cd ..
cd nextjs && npm install && cd ..

Now install hardhat, our smart contract development environment:

npm install -g hardhat-shorthand 

Configuration

We need to give hardhat an Ethereum-based wallet to use by inputting a secret mnemonic seed phrase into a .env file within the hardhat directory. First, we need to generate a seed phrase for development. This can be done using bip39 which is already installed in our hardhat project:

node -e 'console.log(require("bip39").generateMnemonic())'

The 12–24 word output from this is your seed phrase which will be used to open your deployment ethereum wallets. If you’re using this seed phrase for a production deployment, it’s very important that you keep this phrase secret!

With that phrase, create a .env file (touch .env) in the hardhat directory of the project and fill it as so:

MNEMONIC="<insert your 12-24 word mnemonic seed phrase>"
Note — file structure in the left explorer may not be up-to-date.

With all that setup complete, let’s get an understanding of this template inside and out.

3. Template Overview

The README.md in the root of the project describes the project and its setup in detail, however, let’s go over it together.

Back-End / Hardhat Development Environment

From the hardhat directory of your project, you’ll have the following directories:

  • contracts — A directory containing all the smart contracts of your project. Currently, there is just one default contract: Greeter.sol.
  • scripts — Scripts to be used by your hardhat client. Currently, the main script is deploy.ts, which contains the instructions for hardhat to deploy your smart contracts to your chosen network.
  • test — Integration tests for hardhat to run, ensuring your contracts work.
  • hardhat.config.ts — Configuration for your hardhat client. We won’t be touching much on this in this guide, however, you can use it to add new deployment chains (we will touch on this later) and much more.

Front-End

Within the nextjs directory is all your front-end code. For the most part, this is a pretty typical NextJS project structure, however, there are a couple of special parts needed for our development ease.

A lot of the front end relies on the data within the root artifacts directory. Within this directory will be the following:

  • hardhat — A directory automatically populated by the deploy.ts script. This directory contains smart contract ABIs which are used by our front-end to connect to and interact with our smart contracts.
  • contractDeployments.json — A file containing information about the project’s contracts and their deployment address for each chain. Currently, this file will just have the default Greeter contract deployment information. Our hardhat deploy script will populate this JSON with updated addresses after each deployment so that we don’t have to worry about manually hard-coding any addresses.
  • typechain — An auto-generated directory created by hardhat at every compile which contains classes and types that your typescript code can use to easily interact with your deployed contracts in a clean and typed fashion.

Within the NextJS project itself, a crucial part of this template is the useDappStatus hook within core/ethereum/ethereum.ts. This is a hook designed to be used and expanded by you as you add more contracts to your application. The hook is used all across the front-end to provide an easy way to interact with smart contracts and with your user’s Ethereum wallet client (MetaMask or WalletConnect).

4. Running the Template

Before we dive into implementing our own Counter dApp, let’s get this template’s default “Greeter” dApp deployed and running.

First, let’s open up 3 separate terminals. In your first terminal, we’ll spin up hardhat’s local chain — a private chain just for your local development:

cd hardhat
hh node

Leave this running, and in your second terminal let’s deploy the default Greeter contract:

cd hardhat
hh run --network localhost scripts/deploy.ts

Leave this terminal open for later. Finally, in your third terminal, let’s start up the NextJS development server:

cd nextjs
npm run dev

Your 3 terminals should now appear something like this:

Our 3 local development terminals

Let’s go check out the dApp’s testing environment in your browser at http://localhost:3000/playground:

Your locally deployed Greeter dApp

Not too shabby! You can test out a contract read request by clicking “Get Greeting”, but we won’t be able to do any write requests until we connect a wallet to the dApp. The easiest way is to connect to MetaMask via the “Connect” button. Since our dApp is currently configured to run on the localhost chain whilst in development, you’ll be prompted in the top right to switch chains and add the localhost chain to your MetaMask.

However, you’ll notice that your MetaMask account has no balance on this test chain, you’ll need to import an account from your local hardhat wallet into MetaMask. To do this, you can run the following to fetch the private key of your project’s hardhat wallet:

cd hardhat
node util/bip39tools.js

Copy this private key and import it into MetaMask like so:

Import your hardhat project wallet’s private key into MetaMask

Now disconnect your current wallet and reconnect with the new imported wallet. Let’s try out the dApp:

Easy enough, now let’s add in our own Counter dApp.

5. Implementing our own Counter dApp

The Smart Contract

Let’s start with making the new smart contract.

Within your hardhat/contracts directory, create a new Counter.sol file with the following contents:

This contract is fairly simple as we only have one unsigned integer (uint256) state to manage: count. This count is private and represents the contract’s current state of the counter.

We have one public read-only (denoted by ‘public view’) function — getCount() which simply returns the count. Finally, we have one public write function increment(), which increments the count state by 1.

Testing it Out

We can test our contract’s functionality by creating new tests within the test directory. Let’s make a new counter.test.ts file in the test directory and give it the following contents:

This test deploys the Counter contract to a local testing environment and performs several checks on the initial state of the counter, as well as the state after an increment. Chai is used to make assertions about the expected value, and the test will fail if the assertions are not correct.

We can then run this test using hh test from the hardhat directory.

Deploying the Contract

Now, let’s update our hardhat/scripts/deploy.ts script to deploy our Counter. For the most part, this is just swapping out the existing Greeter contract for the new Counter types:

Note that updateDeployedContractData is responsible for updating our contractDeployments.json file in our front-end with the new contract address.

Now let’s re-run this script to deploy the new Counter contract:

cd hardhat
hh run --network localhost scripts/deploy.ts

Integrating the Front-End

To integrate interactions with this deployed contract into the front-end, we’ll update the useDappStatus hook we mentioned before. To do this, head into nextjs/core/ethereum/dappAPIs.ts and we can swap out the previous Greeter contract for the Counter.

First, let’s replace the Greeter imports and the interface for our DappAPIs, and then we can update the inside of our getDappAPI function to use the new GreeterContract. Altogether, these updates will appear as so:

Our useDappStatus hook will now return this new version of DappAPIs with an interface to our new counter contract! Now let’s make use of this new interface in our front-end testing environment.

Updating the Front-End

Now head over to the testing page tsx: nextjs/pages/playground/index.tsx.

With the new DApp APIs, we’ll have access to our 2 smart contract functions. They can be accessed as so within the testing page:

const { dappAPI } = useDappStatus()
dappAPI?.counter.getCount()
dappAPI?.counter.increment()

This isn’t a React tutorial, so we won’t focus too much on the front-end, but using these new APIs and following the previous patterns for managing the Greeter contract, we can update our playground page to replace the Greeter states and click handlers to use our new APIs. Your new playground code should be something like so:

Great! Now, let’s see if it works..

Nice work!

6. Deploying it to the World

So, we have it working great locally, how do we get it out to the world?

For this part of the guide, we will focus on deploying to the Avalanche Fuji testnet, however, the steps can be applied to any EVM chain: Ethereum, Ropsten, Polygon, Harmony, Evmos, etc.

Configuration

The template project can quickly switch between target chains through some simple config. In the nextjs directory, two .env files will exist: .env.development and .env.production. Both of these .env files contain an entry for NEXT_PUBLIC_CHAIN_ID, which should be set to the target EVM’s chain ID. In development, we are currently using 31337, which points to our local hardhat chain. And by default, this template’s production config is currently set to use 43113, which points to the Avalanche Fuji testnet.

A full list of EVM chain IDs can be found on chainlist.org.

Next, let’s look into how we configure the chains in the front-end within the nextjs/config/chain.ts file. You’ll see many popular chain configs are already populated in this file (such as the Avalanche testnet). If you wish to add a new chain to this list, you can simply follow the same pattern as other configs. If you’re unsure of the details of your target chain’s config, chainlist.org can be used to gather the necessary fields.

Finally, we’ll need to update our hardhat/hardhat.config.ts such that hardhat knows how to deploy to our production chain. A config field has already been created for the Avalanche Fuji testnet chain under config.networks.avaxTest. If you wish to add another chain, you can again just follow the same pattern as avaxTest, using chain information from chainlist.org.

Getting Tokens and Deploying

We’ll be using the same hardhat wallet to deploy our contracts to Avalanche testnet, so we’ll need to get some tokens first. Most testnets will have a faucet, for Fuji the testnet can be found here. Simply copy in your hardhat address, and request the tokens:

Now let’s deploy! Do this by running the same deploy script, but with the avaxTest target from our hardhat.config.ts file:

cd hardhat
hh run --network avaxTest scripts/deploy.ts

And it’s as simple as that.

Production Front-End

Now, since our .env.production points to the Avalance testnet, our prod NextJS front-end will be pointing to our avax deployed contracts, using its chain config. Let’s kill our old development NextJS app server and fire up our production NextJS app as so:

cd nextjs
npm run build
npm start

Now let’s check it out:

Nice! A bit slower, sure, but that’s testnets for you.. Feel free to experiment and play around with different chains to find one that suits your needs best.

What Next?

That’s it, you’re now a full-stack dApp dev!

This template is all yours now, hack it apart, take hooks and components and use them in your own projects. Although we didn’t have time to dive deeper into solidity code or web3 provider interactions, this guide should give you enough of a foundation to start building your own dApps and take them to the moon 🚀.

Any Questions?

I’m always looking for feedback and always happy to help out the community, so please feel free to reach out!

Twitter: @gtmulhearn

Check me out on GitHub too:

New to trading? Try crypto trading bots or copy trading

--

--