The Definitive Guide To Building A FullStack dApp
Tags: react, web3, tutorial, beginners
Published: 2022-03-08 19:46:36

_by author [Uma Victor](https://blog.openreplay.com/authors/uma-victor)_

You probably clicked on this tutorial because you have dipped your toes into the exciting world of web3, looked at some intro resources on what web3 is, and have decided to take the next step in becoming a blockchain developer. 
In this tutorial, we will explore building a complete dApp on the Ethereum network from scratch.


## Overview

For the application we’ll be building, we want users that sign up to the dApp, to be able to view a list of learning resources, vote on the resources they like the most, and add their own resources to the dApp. We will start the tutorial by setting up our development environment with Hardhat, which is a development environment that allows us to build smart contracts on Ethereum easily.

After setting up our environment, we’ll build our smart contract in solidity, test that all methods are working in our terminal, deploy the contract, and connect it to our React frontend.
This is what our finished demo looks like:

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646437898033_Addresource.png)



![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646437876241_demo.png)

## Setting up our development environment

Let’s set up our development with Hardhat. We’ll use the [instructions](https://hardhat.org/getting-started/) from the hardhat official documentation to set up our project

**Installing Hardhat**
First, navigate to the directory you would like to build your project in, create an empty directory

```bash
mkdir resourcedapp
cd resourcedapp
```


Make sure you are in the `resourcedapp` directory, then initialize the empty directory with the `npm init` command and follow the instructions on the terminal.
Now let’s install Hardhat and other Hardhat plugin dependencies that will be useful as we follow along in the tutorial.

```bash
npm install --save-dev hardhat @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai
```


> It might take a while for everything to be installed because of some Ethereum Javascript dependencies.

Once everything is installed, in our terminal, run the command:

```bash
npx hardhat
```

This is what we get in our terminal after running the command:

![Hardhat project setup](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1645316123784_npxhardhat.png)


Select `Create a basic sample project`, leave the default hardhat config root as it is, then select `yes` for “Do you want to add a .gitignore” and we can see that our project has been created successfully. let’s take a look at our project structure in the next section.


## Project Structure

We have everything ready to go in building our contract, but before that, let’s examine our file structure.

![file structure](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1645316683723_filestructure.png)


In our contract folder, we have the default `Greeter.sol` file that comes from setting up a sample project. We will be deleting it though as we will be creating our contract file for this tutorial where we will be coding our contract.
In the Script folder, we have a `sample-script.js` file which can be looked at as our deploy script, because it contains code to compile and deploy the contract we write.
In the `test` folder, we have a `sample-test.js` file to run our test and make sure everything is running fine before deploying the contract.
Our `hardhat.config.js` contains hardhat configurations for our project. Configurations like which account to deploy, which version of solidity is used in our contract, and other configurations that help in smooth dApp development.


## Coding our smart contract

In the previous section we looked at the file structure, and now it’s time to begin writing our contract code.
The first thing we do is delete the `greeter.sol` file in the `contracts` folder and create a new file called `Resource.sol`, as this is  where we will be writing our smart contract functionalities. Before jumping into the code, let’s look at the functionalities we want to achieve in the smart contract:


- Add a new resource - To do this we will need an `addResource` function, that when invoked will create a new resource and add it to our array of resources.
- List all of our resources - To do this, we will need a function `getResources` to list all our resources.
- Vote on a resource - We need a `voteResource` function which we will pass in a particular resource `id` and vote on it.
- Get a particular resource - We need a `getResource` function that returns a particular resource.


> Solidity is an object-oriented language, if you’re familiar with Javascript or Python you won’t have much problem programming in it.

 
I’ll be pasting the whole contract code in the `Resource.sol` file we created earlier and i’ll break it down bit by bit so you see what the contract does.

```solidity 
//Resource.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0; // Solidity files have to start with this pragma.
contract ResourceShare {
    struct Resource {
        uint8 id;
        address creator;
        string title;
        string url;
        string description;
        uint8 total_votes;
    }
    mapping(uint256 => Resource) public resources;
    event savingsEvent(uint256 indexed _resourceId);
    uint8 public numResource;
    constructor() {
        numResource = 0;
        addResource(
            "freecodecamp",
            "https://www.freecodecamp.org/",
            "Learn to code"
        );
    }
    function addResource(
        string memory title,
        string memory url,
        string memory description
    ) public {
        Resource storage resource = resources[numResource];
        resource.creator = msg.sender;
        resource.total_votes = 0;
        resources[numResource] = Resource(
            numResource,
            resource.creator,
            title,
            url,
            description,
            resource.total_votes
        );
        numResource++;
    }
    //return a particular resource
    function getResource(uint256 resourceId)
        public
        view
        returns (Resource memory)
    {
        return resources[resourceId];
    }
    //return the array of resources
    function getResources() public view returns (Resource[] memory) {
        Resource\[] memory id = new Resource[\](numResource);
        for (uint256 i = 0; i < numResource; i++) {
            Resource storage resource = resources[i];
            id[i] = resource;
        }
        return id;
    }
    // Vote a resource
    function voteResource(uint256 resourceId) public {
        Resource storage resource = resources[resourceId];
        resource.total_votes++;
    }
}
```
    

**Contract Structure**

```solidity 
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0; // Solidity files have to start with this pragma.
contract ResourceShare {

}
```
    

Solidity contracts generally start with specifying which version of solidity our contract is written in. The `pragma` keyword is what instructs solidity of the version we are using, in our case version `0.8.0`.  Next, we name our contract `ResourceShare` with the curly brace after. All we will be doing has to be in the curly braces. 

**Resource Struct**
A `struct` in solidity is just like classes in other languages. It is used to define custom types for an entity and the attributes it might have.

```solidity
struct Resource {
    address creator;
    string title;
    string url;
    string description;
    uint8 total_votes;
}
```



In our case we have a resource `struct` with the following attributes:

- id - unique id for a particular resource shared
- creator - the creator of the resource shared
- title - the title of our resource
- url - the url for the resource we are sharing
- description - the description of the resource
- total_votes - the total votes the resource receives

Now that we have our `Resource struct` defined, let’s map each of our Resource and code the functionalities for the contract.

**Add a Resource**


```solidity
// Resource.sol
    mapping(uint256 => Resource) public resources;
    uint8 public numResource;
    constructor() {
        numResource = 0;
        addResource(
            "freecodecamp",
            "https://www.freecodecamp.org/",
            "Learn to code"
        );
    }
    function addResource(
        string memory title,
        string memory url,
        string memory description
    ) public {
        Resource storage resource = resources[numResource]; //create new instance of our resource object.
        resource.creator = msg.sender;
        resource.total_votes = 0;
        resources[numResource] = Resource(
            numResource,
            resource.creator,
            title,
            url,
            description,
            resource.total_votes
        );
        numResource++;
    }
```
    

The first line of the code in the sample above is a mapping in solidity which is like an object in Javascript used in storing data in a key-value pair format or like a hash map in some other language.  

```solidity
mapping(uint256 => Resource) public resources;
```

In this line, we map solidity inbuilt type `uint256` to our `Resource struct` and set to public the resources array. We create a `numResource` variable, which we will use to refer to the `id` of a resource we have in our resources array


**Note 1:** In solidity, using a `public` keyword means that the specified data can be called by anybody or any contract. 


**Note 2:** The `resources` array can be populated by different resources in the image of the `Resource struct`  we defined.  

Our `addResource` function accepts three parameters `title`, `url`, and `description`. In solidity, we have to specify the type of parameters we pass into the function, and the `memory` keyword to store parameters temporarily in state memory.

Next, we create a new instance of our resource object in our solidity contract storage using the `storage` keyword. This will allow us to change the contract state directly.  What we do next is set the value of what a particular resource we want to share will have. 
We set the creator of the resource to always be the `msg.sender`, which in solidity is the person calling the functions in our contract or the person connected to our contract, and the `total_votes` to be zero initially. Next, we set all the values of the resource we want to share, including the arguments the user creating the resource will provide and increment `numResource` each time the function is called.


> We can see a constructor function in the code.  The constructor function is called every time we run our contract. 

**Get all Resources**
In the previous section, we wrote the function to add a new resource. Let’s look at how to get a particular resource, then all resources in this section.

```solidity
//Resource.sol
    //return a particular resource
    function getResource(uint256 resourceId) public view returns (Resource memory) {
        return resources[resourceId];
    }
    //return the array of resources
    function getResources() public view returns (Resource[] memory) {
        Resource\[] memory id = new Resource[\](numResource);
        for (uint256 i = 0; i < numResource; i++) {
            Resource storage resource = resources[i];
            id[i] = resource;
        }
        return id;
    }
```
    

In the code above, the first function `getResource` accepts `resourceId` as a parameter used to target a particular resource, then returns it.  The `view` syntax indicates we are not making any changes to the contract state, and only viewing or querying state data. The `returns` syntax tells us the type of data we are returning, in our case a type of our `Resource struct`.
The second function `getResources` loops over all the resources in the array and returns them.

**Voting a resource**
We will make a provision for a voting function, so the user can also vote a particular resource they love.

```solidity
//Resource.sol
    // Vote a resource
    function voteResource(uint256 resourceId) public {
        Resource storage resource = resources[resourceId];
        resource.total_votes++;
    }
```


This function just targets a particular resource in the contract storage and increments the total votes each time the `voteResource` function is called.


## Deploying our contract

We are done coding our contract, it’s time to deploy it!. In this section, we will deploy the contract twice. First, we will create a local node on our machine and deploy the contract locally, then later on we will deploy the contract live to the polygon matic test network, where anyone in the world can view the contract and the transactions that happen on it. Now let’s begin.

**Deploying our contract locally**
To deploy our contract locally to a local node network provided by `hardhat`, let’s start running the node by running the command:

```bash
npx hardhat node
```

After running this command, Hardhat provides us with 20 accounts each with their wallet account ID and a private key. We will be using those to connect to MetaMask later on.
Each account is funded with fake 100ETH that we can use to carry out operations and pay gas fees in the dApp we are building. Here is what our terminal looks like:


![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646170522474_hardhataccounts.png)


As you can see from the image, the port our local network is running on: http://127.0.0.1:8545/.
Navigate to your `hardhat.config.js` and add this network configuration.

```solidity
//hardhat.config.js
 module.exports = {
  <------>
  solidity: "0.8.4",
  networks: {
    hardhat: {
      chainId: 31337
    }
  }
};
```


In our script folder, rename the `sample-script.js` file to `deploy.js` as this is where we will write the script for deploying our smart contract. Tweak the `deploy.js` file to look like this:

```javascript
// deploy.js
const hre = require("hardhat");
async function main() {
  // If this script is run directly using `node` you may want to call compile
  // manually to make sure everything is compiled
  // await hre.run('compile');
  // We get the contract to deploy
  const ResourceShare = await hre.ethers.getContractFactory("ResourceShare");
  const resourceshare = await ResourceShare.deploy();
  await resourceshare.deployed();
  console.log("resourceshare deployed to:", resourceshare.address);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });
```
    

Now to finally deploy our contract we run the command

```bash
npx hardhat run --network localhost scripts/deploy.js
```

When we run the above command, Hardhat automatically creates an artifacts folder at the root of our directory. The artifact folder is very important if we want to interact with the smart contract we just deployed and connect to our frontend. 
This is what we get in  our terminal once we have a successful deployment:

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646171663320_deploy.png)


we can also see in the terminal tab where we started our node:

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646171755073_deployedcontract.png)


Above we can see different information about our deployed contract, including the contract address, the account from the 20 accounts our contract was deployed from, and gas fees used to deploy our contract.

Now that we have a successful deployment, let’s install and connect our [metamask](https://metamask.io/) wallet to our account so we can interact with the frontend application we will be creating soon.


## Connecting to Metamask

I’ll like for us to concentrate on the most important things, so I’ll be linking you to a [guide](https://www.geeksforgeeks.org/how-to-install-and-use-metamask-on-google-chrome/) to install and set up your metamask wallet so we can focus on the important stuff of connecting our contract to metamask.
Now that you  have your metamask wallet installed, let’s connect to our Hardhat local network and import the account we deployed our contract from. Follow these steps:


1. Click on the metamask icon on the extension tab and sign in to metamask. After signing in, you will be automatically directed to your Ethereum mainnet account.
2. Click on the network dropdown and click on the “Add Network” button.
![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646172990296_ethereummainet.png)

3. Fill in the fields with the following information and save.
![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646173383023_harhdatnetwork.png)

4. Make sure you are now on the Hardhat network you just added, then click on the circular icon in the top right corner.
![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646173738154_importacct.png)

5. Go to your terminal tab where you started the Hardhat node and were provided with 20 accounts. Look for the first account, which is the account your contract was deployed from, then copy and paste it into the field that asks you to paste your private key.
![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646173873727_privatekey.png)


Click on Import and you’ll see the balance for the account you imported.

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646174044482_fundedacct.png)


The balance is no longer 10000Eth as we saw from our terminal because we have used a bit of Eth to pay gas fees for deploying the contract.

Now that we have everything set up, it’s time to build our frontend and integrate it with our contract so the user can perform operations from our UI.


## Building our Frontend

In the last section, we looked at how to set up our metamask wallet and import our account. Now is the time to build our frontend and interact with the contract.

We will use `create-react-app` to spin off a frontend at the root folder of our application.

```bash
npx create-react-app frontend
```

Now that we have our frontend application set up, let’s navigate to our `App.js` file in the `src` folder and begin writing some code!.
Before jumping into some code, I’ll like to discuss how our frontend connects to our smart contract and the general structure our frontend will follow. 

When building a dApp, there are helpful libraries that make it possible for us to query the blockchain for some data or make changes to a contract state in the blockchain. Examples of such libraries are [web3.js](https://web3js.readthedocs.io/en/v1.7.0/getting-started.html), and [ethers.js](https://docs.ethers.io/v5/) which are the most popular. Without these libraries, interacting with our UI will be such a pain. In our case, we are using the `ethers.js` library which we have already installed when starting this tutorial, and that’s why we’ll be importing it in our `app.js`  file.

**Frontend structure**
We are building a resource sharing dApp, so our React frontend will have two components:

- `ListResources` - This is a component of a particular resource we share in our application. It will contain all the information of the resource we share.
- `CreateResource` - This component contains a form, so we can add a new resource to our app.

These two components will be imported into our `App.js` file. 

Let’s look at what our `App.js` looks like:

```javascript
// App.js
import './App.css'
import ResourceArtifact from '../src/artifact/contracts/Resource.sol/ResourceShare.json'
import { ethers } from 'ethers'
import ListResources from './components/ListResources'
import CreateResource from './components/CreateResource'
import { useEffect, useState } from 'react'
const resourceAddress = '0x5FbDB2315678afecb367f032d93F642f64180aa3'
function App() {
  const [resourceData, setResourceData] = useState([])
  const [toggleModal, setToggleModal] = useState(false)
  const [contract, setContract] = useState()
  async function requestAccount() {
    await window.ethereum.request({ method: 'eth_requestAccounts' })
  }
  function addResource() {
    setToggleModal(!toggleModal)
  }
  const provider = new ethers.providers.Web3Provider(window.ethereum)
  const signer = provider.getSigner()
  async function _intializeContract(init) {
    // We first initialize ethers by creating a provider using window.ethereum
    // When, we initialize the contract using that provider and the token's
    // artifact. You can do this same thing with your contracts.
    const contract = new ethers.Contract(
      resourceAddress,
      ResourceArtifact.abi,
      init,
    )
    return contract
  }
  useEffect(() => {
    // in this case, we only care to query the contract when signed in
    if (typeof window.ethereum !== 'undefined') {
      (async function getResourcesCount() {
        await requestAccount()
        const contract = await _intializeContract(signer)
        const resourcedata = await contract.getResources()
        const resources = [...resourcedata]
        setContract(contract)
        setResourceData(resources)
      })()
    }
  }, [])
  return (
    <>
      <header>
        <button onClick={addResource}>Add a resource</button>
      </header>
      <main>
        <CreateResource toggleModal={toggleModal} contract={contract} />
        <section className="resources">
          {resourceData.map((resource, id) => {
            return (
              <div key={id}>
                <ListResources resource={resource} contract={contract} />
              </div>
            )
          })}
        </section>
      </main>
    </>
  )
}
export default App
```
    

let’s analyze our `App.js` file bit by bit starting with the first 8 lines:

```javascript
import './App.css'
import ResourceArtifact from '../src/artifact/contracts/Resource.sol/ResourceShare.json'
import { ethers } from 'ethers'
import ListResources from './components/ListResources'
import CreateResource from './components/CreateResource'
import { useEffect, useState } from 'react'
const resourceAddress = '0x5FbDB2315678afecb367f032d93F642f64180aa3'
```


Above, we imported the ethers.js library we talked about earlier, our components, our contract articfact file, and our contract address. 


> To connect and interact with our contract, it’s a must to have the contract address and the ABI file which can be found in our artifact folder. The ABI file contains important information about our contract like the methods to call in our contract.


```javascript
const [resourceData, setResourceData] = useState([])
  const [toggleModal, setToggleModal] = useState(false)
  const [contract, setContract] = useState()
  async function requestAccount() {
    await window.ethereum.request({ method: 'eth_requestAccounts' })
  }
```

Here is our application state. 

- The `resourceData` state will store the resource array containing all the resources. 
- The `toggleModal` state to hold state to decide if our modal is open or not. 
- The `contract` state so we can store the contract and pass it as a prop, so we can call the contract methods from other components.

Then we have the `requestAccount` function that calls the `eth_requestAccounts` method on the ethereum window object. When this method is called, the user is prompted to sign into their metamask wallet on the browser.


```javascript
const provider = new ethers.providers.Web3Provider(window.ethereum)
  const signer = provider.getSigner()
  async function _intializeContract(init) {
    // We first initialize ethers by creating a provider using window.ethereum
    // When, we initialize the contract using that provider and the token's
    // artifact. You can do this same thing with your contracts.
    const contract = new ethers.Contract(
      resourceAddress,
      ResourceArtifact.abi,
      init,
    )
    return contract
  }
  useEffect(() => {
    // in this case, we only care to query the contract when signed in
    if (typeof window.ethereum !== 'undefined') {
      (async function getResources() {
        await requestAccount()
        const contract = await _intializeContract(signer)
        const resourcedata = await contract.getResources()
        const resources = [...resourcedata]
        setContract(contract)
        setResourceData(resources)
      })()
    }
  }, [])
```


In the code above, we have an `*_intializeContract*` function that initializes our contract with the ethers.js library. For us to initialize the contract, we need to create a contract variable that uses the `Contract` method from Ethers library, which accepts three parameters: 

- The address. 
- The `ResourceShare` contract artifact ABI
- The signer account that we get using `window.ethereum` as our provider.

Then we return the contract. We will see how the _intializeContract function would be used later. 
In our React `useEffect` hook, we call the `getResources` function in an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE), that calls the `requestAccount()` function prompting the user to sign in with their Metamask, then we initialize our contract into a `contract` variable and call the `getResources` method in our contract, and set our `contract` and `resourceData` state.


```javascript
return (
    <>
      <header>
        <button onClick={addResource}>Add a resource</button>
      </header>
      <main>
        <CreateResource toggleModal={toggleModal} contract={contract} />
        <section className="resources">
          {resourceData.map((resource, id) => {
            return (
              <div key={id}>
                <ListResources resource={resource} contract={contract} />
              </div>
            )
          })}
        </section>
      </main>
    </>
  )
```


Here we return some markup of what we will display in our UI. In our header, we only have an “Add a resource” button, when clicked will call the `addResource` function which toggles our modal and reveals a form for us to create and add a new resource.
In the `main` tag, we have the `CreateResource` component, then we loop through our `resourceData` array and pass in the resource object into our `ListResources` component as a prop. We also pass in the contract as a prop in the two components so we can call the contract methods in the two components.

**List resource Component**
We looped through the resource array state in our `App.js` component and supplied the object prop to our `ListResources` component. Let’s look at what our `ListResources` looks like:


```javascript
function ListResources({ resource, contract }) {
 async function vote(id) {
  await contract.voteResource(id)
  }
  return (
    <div className="project">
      <h2>{resource.title}</h2>{' '}
      <span className="creator">{resource.creator}</span>
      <h3>description:</h3>
      <p>{resource.description}</p>
      <h4>Link:<a href={resource.url}>{resource.url}</a></h4>
      <h4>Votes: {resource.total_votes}</h4>
      <button
        onClick={(id) => vote(resource.id)}
      >
        Vote
      </button>
    </div>
  )
}
export default ListResources
```


In this component, we just accept the `resource` and `contract` prop, list display all the data in our resource object. When we click on the button we call a `vote` function that accepts the resource ID and calls the `voteResource` method in our contract incrementing the `total_votes` count by 1.

**Create Resource Components**
Our create resource components is a form modal with input fields, to add a new resource.

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646437925832_Addresource.png)



```javascript
import React, { useState } from 'react'

function CreateResource({ toggleModal, contract }) {
  const [title, setTitle] = useState('')
  const [description, setDescription] = useState('')
  const [url, setUrl] = useState('')
  const handleSubmit = (event) => {
    event.preventDefault()
    contract.addResource(title, url, description)
  }
  return (
    <div>
      {toggleModal === true && (
        <div className="addresource">
          <form onSubmit={handleSubmit}>
            <label>
              Enter resource title:
              <input
                type="text"
                value={title}
                onChange={(e) => setTitle(e.target.value)}
              />
            </label>
            <label>
              Enter resource url:
              <input
                type="text"
                value={url}
                onChange={(e) => setUrl(e.target.value)}
              />
            </label>
            <label>
              Enter resource description:
              <input
                type="text"
                value={description}
                onChange={(e) => setDescription(e.target.value)}
              />
            </label>
            <input type="submit" className="submit" />
          </form>
        </div>
      )}
    </div>
  )
}
export default CreateResource
```
    

When the `toggleModal` state is `true`, this component renders conditionally. We have a state for the resource `title`, `description`, and `url`, and we set the state to the input value whenever our input changes. The `handleSubmit` function is invoked when the form is submitted, and our `addResource` method is called from the contract. 

## Open Source Session Replay
Debugging a web application in production may be challenging and time-consuming. [OpenReplay](https://github.com/openreplay/openreplay) is an Open-source alternative to FullStory, LogRocket and Hotjar. It allows you to monitor and replay everything your users do and shows how your app behaves for every issue.
It’s like having your browser’s inspector open while looking over your user’s shoulder.
OpenReplay is the only open-source alternative currently available.

![OpenReplay](https://raw.githubusercontent.com/openreplay/openreplay/main/static/replayer.png)

Happy debugging, for modern frontend teams - [Start monitoring your web app for free](https://github.com/openreplay/openreplay).


## Deploying our contract live on a test network

In the last section, we looked at how to connect our frontend to our smart contract. In this section, we will look at how to deploy our smart contract to a live test network for everyone to see. The network we will be deploying to is the Ropsten Ethereum test network, which allows us to deploy our contract and testing it out before deploying it to the Ethereum mainnet. 

First, we have to click on the metamask extension icon, then click the network dropdown and select the `Ropsten test network`. We need a way to interact with the Ropsten test network without running a local Ethereum node on our machine, and there are quite a few services that allow us to do that, one of them being [Infura](https://infura.io/). To use the Ropsten network Ethereum node provided by Infura, we need to create an account and sign in. When signed in, click on “create a new project”

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646408953537_createnewproject.png)


After clicking, you’ll be prompted by a modal asking for the project name.

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646409087399_createproject.png)


We can name our project whatever we like and click the create button. In our project dashboard, we can see our project details and the endpoints we will be using.

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646409439468_ropstenendpoint.png)


Click on the endpoint dropdown and select Ropsten network. Now we have our project ID and the Ropsten endpoint which we will need to connect to the Ropsten network. Let’s configure Hardhat to deploy to the network. In our `hardhat.config.js`, we now have:

```javascript
module.exports = {
  paths: {
    artifacts: './frontend/src/artifact',
  },
  solidity: "0.8.4",
  networks: {
    hardhat: {
      chainId: 31337
    },
    ropsten: {
      url: "https://ropsten.infura.io/v3/ca9b0c1b342b44658282a52daaf1be25",
      accounts: [`0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80`]
    }
  }
```


We have added a new configuration to our networks. The Ropsten network configuration requires a `URL` which is our ropsten endpoint gotten from Infura, and an `account` which is the private key of the Ropsten wallet account we selected on metamask. 

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646414950128_acctdetails.png)


To get the private key of the account, click on account details, then on “export private key”

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646415019777_exportprivate.png)


Type in your metamask password and click confirm, then you can copy the private key and past it in your hardhat configuration. Just make sure you prefix it with `0x` as seen in our Ropsten configuration


> In a real-world use case where you’ll  be deploying to the Ethereum mainnet, make sure the private keys are private and are stored where you can only access to prevent loss of funds. You can store it in an `env` file if you'd like.

We are now set to deploy the contract on the Ropsten network. All we need to do now is fund our Ropsten test network account and run the Hardhat deploy command.  To fund our account, we need to paste our Ropsten testnet wallet account into a Ropsten [faucet site](https://faucet.egorfine.com/) that sends us free Ether.

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646415892607_sendeth.png)


Wait a bit, and you will see the free Ether sent to you

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646415941867_recievedether.png)


Now we can run the deploy command:

```bash
npx hardhat run --network ropsten scripts/deploy.js
```

and our contract is now deployed live on the Ropsten network and you can check it out on [Etherscan](https://etherscan.io/), a site that allows you to explore the contract you just deployed.

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646416182946_ropsten+deploy.png)


To explore our contract on Etherscan, copy the account the contract is deployed to, from the terminal and paste it on Etherscan.

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646416528741_pasteconad.png)


Click on the search icon and you will see information about the contract we deployed.

![](https://paper-attachments.dropbox.com/s_9CF3CC11C77A821A3112A939FE83884F4A011DDD08D97BE23B75B49468DC0888_1646416596331_etherscan.png)


Yay!. We have concluded the tutorial and you can find the source code [here](https://github.com/uma-victor1/fullstack-dApp-tutorial).


## Conclusion

Finally, we are done with this tutorial. We learned how to build a dApp from start to finish, connect the smart contract and deploy it on a live test network, while exploring tools like Infura and Etherscan. I hope this tutorial gets you up and running building dApps on the Ethereum blockchain.