A JavaScript journey: Web3 app
Tags: react, web3, solidity, ethereum
Published: 2022-03-27 14:47:33

The application we are building is a survey application where users receive cryptocurrency in return for their participation. This will be a truncated version of the actual application, but enough so that you can get a basic introduction to smart contracts.

The broad tech stack for this application is as follows: JavaScript (ReactJS, NodeJS, ExpressJS), SQL and Solidity. It also makes use of a JavaScript library called SurveyJS. Other tools were used, but for now we will just focus on the bare bones. 

#Step 1: Create React App
Open a terminal (preferably already within an IDE) and enter:

```
npx create-react-app myWeb3Dapp
```

`myWeb3Dapp` is the name of the app's root folder. Once you have done this, remove all of the files except for `App.css`, `App.js`, `index.js` and `index.css`


#Step 2: Setup directories and install tools
I like to organise the folder structure in advance where possible as it helps to give a clear minded view of the application's architecture.

Since we are also going to be using `Hardhat` as our Ethereum development environment, now is a good time to install that too. Hardhat will create a mock Ethereum blockchain upon which we can simulate transactions.

First, head to the root directory and enter:

```
npm install --save-dev hardhat 
```

We can also set up our Ethereum environment here by entering:

```
npx hardhat
```

then choose:

```
Create a basic sample project
```

This will create a file called `hardhat.config.js` and create two new folders in your root directory:

```
scripts
contracts
```

Open `hardhat.config.js`, delete what exists and update it with the following (Your Solidity version might be higher than this by the time you read this):

```js
require("@nomiclabs/hardhat-waffle");
const {task} = require("hardhat/config");
require("dotenv").config()

task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();

  for (const account of accounts) {
    console.log(account.address);
  }
});

module.exports = {
  paths: {
    artifacts: "./src/artifacts",
  },

  networks: {
    hardhat: {
      chainId: 1337
    },
  },
  solidity: {
    version: "0.8.6",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200
      }
    }
  },
};
```

Next we need to install two more libraries which are called by `require` in the file above:

```
npm install @nomiclabs/hardhat-waffle dotenv
```

Next we need to install `ethers` which is a JavaScript library that will allow our application to communication with the Ethereum blockchain.

```
npm install ethers
```

#Step 3: Write smart contracts
In this section we will build the smart contract using Solidity. We need to write two smart contracts - one which represents our 'CTK' token and another which represents the 'Owner' of the tokens, which effectively plays the role of a bank in that it holds and releases the tokens subject to approval.

Navigate to the `contracts` folder, delete the file called `greeter.sol` and create two new files:

```
touch CryptocracyToken.sol Owner.sol
```

Inside CryptocracyToken.sol update the code with the following:

```solidity
pragma solidity ^0.8.6;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract CryptocracyToken is IERC20, ERC20 {

    constructor(address holder, string memory name, string memory symbol)
    public ERC20(name, symbol) {
        _mint(holder, 100000 * (10 ** 18));
    }
}
```

Inside Owner.sol update the code with the following:
```solidity
pragma solidity ^0.8.6;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract Owner {

    function approveTokenSpend(IERC20 token, address spender, uint256 amount)
    public {
        token.approve(spender, amount);
    }

    function withdrawToken(IERC20 token, address recipient, uint256 amount)
    public {
        token.transfer(msg.sender, amount);
    }
}
```

#Step 4: Front-end

##Create client directories
Navigate to the `src` folder and create three directories:

```
mkdir 
components 
pages 
stylesheets
```

##Create homepage file
Navigate to the `pages` folder and type the following to create your homepage file.

```
touch home-page.js
```

Open the file and update it with the following code:

```js
import React from "react";
import HomePageHero from "../components/home-page-hero";
import Navbar from "../components/navbar";

const HomePage = () => {
    return (
        <>
            <Navbar/>
            <HomePageHero/>
        </>
    );
}

export default HomePage
```

As you can see, our home page will consist of two components. Hypothetically we can reuse these components anywhere else on our site.

##Create our first two components

Navigate to the `components` directory and create two new files:

```
touch navbar.js home-page-hero.js global-button.js
```

Update them with the following code (ignore any errors for now):

**Navbar:**
```js
import {useEffect, useState} from "react";
import {Link} from "react-router-dom";
import '../stylesheets/navbar.css'

const Navbar = () => {

    const [clicker, setClicker] = useState(false);
    const [button, setButton] = useState(true);

    const handleClick = () => setClicker(!clicker);
    const closeMobileMenu = () => setClicker(false);
    const showButton = () => {
        if (window.innerWidth <= 960) {
            setButton(false);
        } else {
            setButton(true);
        }
    };

    useEffect(() => {
        showButton();
    }, []);

    window.addEventListener("resize", showButton);

    return (
        <>
            <nav className="navbar">
                <div className="navbar-container">
                    <Link to="/" className="navbar-logo"
                          onClick={closeMobileMenu}>Cryptocracy</Link>
                    <div className="menu-icon" onClick={handleClick}>
                        <i className={clicker ? "fas fa-times" : "fas" +
                            " fa-bars"}/>
                    </div>
                </div>
            </nav>
        </>
    );
}

export default Navbar
```


**HomePageHero**

```js

import {Link} from "react-router-dom";
import {GlobalButton} from "./global-button";
import '../stylesheets/home-page-hero.css'

const HomePageHero = () => {
    return (
        <div>
            <div className="hero-container">
                <div className="title-container">
                    <h2>We dont just value your opinion, we reward it.</h2>
                </div>
                <div className="subtitle-container">
                    <p>Complete Surveys, Quizzes and Polls for Crypto Rewards</p>
                </div>
                <div className="hero-btns">
                    <GlobalButton className="btns"
                                  buttonStyle="btn--outline"
                                  buttonSize="btn--large">
                        <Link to="/surveys">Earn Crypto Now!</Link>
                    </GlobalButton>
                </div>
            </div>
        </div>
    );
}

export default HomePageHero
```

**GlobalButton**

```js
import React from "react";
import { Link } from "react-router-dom";
import '../stylesheets/global-button.css'

const STYLES = ["btn--primary", "btn--outline"];
const SIZES  = ["btn--medium", "btn--large"];

const GlobalButton = ({children, type, onClick, buttonStyle, buttonSize}) => {
    const checkButtonStyle = STYLES.includes(buttonStyle) ? buttonStyle : STYLES[0];
    const checkButtonSize = SIZES.includes(buttonSize) ? buttonSize : SIZES[0]

    return (
        <Link to="#" className="btn-mobile">
            <button
                className={`btn ${checkButtonStyle} ${checkButtonSize}`}
                onClick={onClick}
                type={type}
            >
                {children}
            </button>
        </Link>
    )
};

export default GlobalButton
```

then navigate to the stylesheets folder and type the following into the terminal

```
touch home-page-hero.css navbar.css global-button.css
```
and update them with the following:

**home-page-hero.css**
```css
.hero-container {
    height: 100vh;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    #box-shadow: inset 0 0 0 1000px rgba(205, 168, 168, 0.2);
    background-color: #ffffff;
    object-fit: contain;
}

.title-container > h2 {
    color: #000000;
    font-size: 3rem;
    font-family:  'Arvo', serif;
    font-weight: bold;
}

.title-container {
    display: flex;
    margin-top: -20vh!important;
    margin-bottom: 0!important;
    max-width: 50vw;
    text-align: center;
}

.subtitle-container > p {
    font-size: 1.7rem;
    font-family: 'Arvo', serif;
    font-weight: bold;
    color: #000000;
    text-align: center;
}

.hero-btns {
    margin-top: 32px;
}
.btn--outline {
    border: 1px solid #5b3926;
}
.btn--primary {
    border: 1px solid #5b3926;
    #background-color: #fff8ee;
}
.btn--medium {
    border: 1px solid #5b3926;
    color: #000000;
}
#btn-logout {
    display: none;
}
#btn-login {
    display: none;
}
a {
    text-decoration: none;
    color: #000000;
}
@media screen and (max-width: 991px) {
    .hero-container > h1 {
        font-size: 70px;
        margin-top: -150px;
    }
}
@media screen and (max-width: 768px) {
    .hero-container > h1 {
        font-size: 50px;
        margin-top: -100px;
    }

    .hero-container > p {
        font-size: 30px;
    }

    .btn-mobile {
        display: block;
        text-decoration: none;
    }

    .btn {
        width: 100%;
    }
}
```


**navbar.css**

```css
.navbar {
    #background: linear-gradient(90deg, rgb(28, 27, 27) 0%, rgb(26, 23, 23) 100%);
    background-color: #ffffff;
    height: 100px;
    display: flex;
    justify-content: center!important;
    align-items: center;
    font-size: 1.2rem;
    position: sticky;
    top: 0;
    z-index: 999;
    width: 100%;
    #box-shadow: 2px 2px 6px 0px rgba(0, 0, 0, 0.3);
}

.navbar-container {
    display: flex;
    height: 80px;
    #width: 100%;
    flex-direction: column;
    flex-wrap: wrap;
    align-content: center;
}

.navbar-logo {
    color: #000000;
    font-family: 'Libre Barcode 39 Text', cursive;
    cursor: pointer;
    text-decoration: none;
    font-size: 4rem;
    display: flex;
    align-items: flex-start;
}

.nav-menu {
    display: grid;
    grid-template-columns: repeat(4, auto);
    grid-gap: 10px;
    list-style: none;
    text-align: center;
    width: 60vw;
    justify-content: end;
    margin-right: 2rem;
}

.nav-links {
    color: #000000;
    display: flex;
    align-items: center;
    text-decoration: none;
    padding: 0.5rem 1rem;
    height: 100%;
    font-size: 1.4rem;
}

.nav-links:hover {
    border-bottom: 4px solid #000000;
    transition: all 0.2s ease-out;
}

.fa-bars {
    color: #000000;
}

.nav-links-mobile {
    display: none;
}

.menu-icon {
    display: none;
}

@media screen and (max-width: 960px) {
    .NavbarItems {
        position: relative;
    }

    .nav-menu {
        display: flex;
        flex-direction: column;
        width: 100%;
        height: 90vh;
        position: absolute;
        top: 80px;
        left: -100%;
        opacity: 1;
        transition: all 0.5s ease;
    }

    .nav-menu.active {
        background: #242222;
        left: 0;
        opacity: 1;
        transition: all 0.5s ease;
        z-index: 1;
    }

    .nav-links {
        text-align: center;
        padding: 2rem;
        width: 100%;
        display: table;
    }

    .nav-links:hover {
        background-color: #fff;
        color: #242424;
        border-radius: 0;
    }

    .navbar-logo {
        position: absolute;
        top: 0;
        left: 0;
        transform: translate(25%, 50%);
    }

    .menu-icon {
        display: block;
        position: absolute;
        top: 0;
        right: 0;
        transform: translate(-100%, 60%);
        font-size: 1.8rem;
        cursor: pointer;
    }

    .fa-times {
        color: #fff;
        font-size: 2rem;
    }

    .nav-links-mobile {
        display: block;
        text-align: center;
        margin: 2rem auto;
        border-radius: 4px;
        width: 80%;
        text-decoration: none;
        font-size: 1.5rem;
        background-color: transparent;
        color: #ec0000;
        padding: 14px 20px;
        border: 1px solid #fff;
        transition: all 0.3s ease-out;
    }

    .nav-links-mobile:hover {
        background: #fff;
        color: #c94444;
        transition: 250ms;
    }
}
```

**global-button.css**

```css
:root {
    --primary: #fff;
}
.btn {
    padding: 8px 20px;
    border-radius: 2px;
    #outline: none;
    #border: none;
    cursor: pointer;
}
.btn--primary {
    color: #242424;
    border: 1px solid #000000;
}
.btn--outline {
    background-color: transparent;
    color: #000000;
    padding: 8px 20px;
    border: 1px solid #000000;
    transition: all 0.3s ease-out;
}
.btn--medium {
    padding: 8px 20px;
    font-size: 20px;
}
.btn--large {
    padding: 8px 20px;
    font-size: 20px;
}
.btn--medium:hover, .btn--large:hover {
    background-color: #fff;
    color: #242424;
    transition: all 0.3s ease-out;


}
```

##Setting up the App.js file**
Delete everything in the `App.js` file and replace it with the code below. We will be updating this file throughout so keep it open.

```js
import React, {useMemo, useState} from "react";
import {HashRouter as Router, Routes, Route} from "react-router-dom";

import './App.css'
import HomePage from './pages/home-page'

const App = () => {
   
    return(
        <>
            <Router>
                <Routes>
                    <Route exact path='/' element={<HomePage/>} replace/>
                </Routes>
            </Router>
        </>
    )
}

export default App
```

Also, go to `index.js` and remove the following line:

```
import reportWebVitals from './reportWebVitals';
```

Then, in the terminal, run

```
npm start
```

You should see this: It doesn't look like much, but remember most of what we have done so far is the behind the scenes work.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kthxbt3v9zal7e4d94vo.png)


##Create the dashboard
Navigate to the `pages` folder and create a new file:
```
touch dashboard-page.js
```

update this file with the following code:

```js
import Navbar from "./components/navbar";

export default function DashboardPage(){
    return (
        <>
            <Navbar/>
            <DashboardPageHero/>
        </>
    );
}
```

then navigate to the `components` folder and create a new file:

```
touch dashboard-page-hero.js
```

Update that file with the following code:

```js
import image from '../surveytilecover.gif'
export default function DashboardPageHero() {
    return (
        <>
            <div className="dashboardPageContainer">
                <div className="titleContainer">
                    <h1>Surveys available</h1>
                </div>
                <div className="surveyContainer">
                    <CardItem src={image}
                              id="surveys"
                              text="Which party will you vote for? (50 CTK)"
                              label="Politics"
                              path="/survey"
                    />
                </div>
            </div>
        </>
    );
}
```

Also, add the following line to `App.js`:

```js
<Route exact path='/surveys' element={<DashboardPage/>} replace/>
```

So `App.js` would now look like the following:

```js
import {HashRouter as Router, Routes, Route} from "react-router-dom";

import './App.css'
import HomePage from './pages/home-page'

const App = () => {
    return(
        <>
            <Router>
                <Routes>
                    <Route exact path='/' element={<HomePage/>} replace/>
                    <Route exact path='/surveys' element={<DashboardPage/>} replace/>
                </Routes>
            </Router>
        </>
    )
}
export default App
```

then create a new file in the `components` folder called `card-item` which will represent our survey tile on the dashboard page hero:

```
touch card-item.js
```

which you should update with this code:

```js
import { Link } from "react-router-dom"
export default function CardItem(props) {
    return (
        <>
            <div className="cards__item">
                <Link className="cards__item___link" to={props.path}>
                    <figure className="cards__item___pic-wrap" data-category={props.label}>
                        <img
                             alt="DemocracyImage"
                             className="cards__item__img"
                             src={props.src}
                        />
                    </figure>
                    <div className="cards__item__info">
                        <h5 className="cards__item__text">{props.text}</h5>
                    </div>
                </Link>
            </div>
        </>
    );
}
```

##Adding a survey
As mentioned earlier, we will be using JavaScript library SurveyJS to add a survey to our app. 

**Install Survey-React**

```
npm install survey-react
```

Create a new folder in the client folder:

```
mkdir surveys
```

Navigate to this folder and create two files:

```
touch survey-control.js survey-questions.js
```

Update each with the following code:

**survey-control.js**

```js
import React, {useCallback, useState} from "react";
import {Link} from "react-router-dom";
import * as Survey from "survey-react";

import {GlobalButton} from "../components/global-button";
import {SurveyQuestions} from "./survey-questions"

export const SurveyControl = () => {

    const [showPage, setShowPage] = useState(true);
    const OnCompletePage = useCallback(() => {
        setShowPage(!showPage);
    }, [showPage]);

    const SetFinalPage = ({}) => {
        return (
            <main>
                <h1>Thank you for taking this survey. You have earned 50 CTK!</h1>
                <GlobalButton
                    className="btns"
                    buttonStyle="btn--primary"
                    buttonSize="btn--large">
                    <Link to="/surveys">Back to Dashboard</Link>
                </GlobalButton>
            </main>
        );
    };

    const survey = new Survey.Model(SurveyQuestions);

    return (
        <div>{
            showPage ?
                <Survey.Survey
                    showCompletedPage={false}
                    onComplete={OnCompletePage}
                    model={survey}
                />
                : <SetFinalPage/>
        }</div>
    );
};
```

**survey-questions.js**
```js
import React from "react";
import * as Survey from "survey-react";

Survey.StylesManager.applyTheme("modern");

export const SurveyQuestions = {
    "pages": [
        {
            "elements": [
                {
                    "type": "radiogroup",
                    "name": "Party I am most likely to vote for",
                    "title": "Please select the political party youre most likely to vote for",
                    "isRequired": true,
                    "hasNone": true,
                    "colCount": 1,
                    "choices": [
                        "Red Party",
                        "Blue Party",
                        "Yellow Party",
                        "Green Party",
                        "Orange Party"
                    ]
                }
            ]
        }
    ],
    "showTitle": false,
    "isAllRowRequired": true,
};
```

The survey should look something like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/611mody66k732die3nsq.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pyrvlkc06sodk763hr4p.png)

You should also update **App.js** at this point with the following code:

```js
import React from "react";
import {HashRouter as Router, Routes, Route} from "react-router-dom";

import './App.css'
import HomePage from './pages/home-page'
import DashboardPage from "./pages/dashboard-page";
import {SurveyControl} from "./surveys/survey-control";

const App = () => {
    return(
        <>
            <Router>
                <Routes>
                    <Route exact path='/' element={<HomePage/>} replace/>
                    <Route exact path='/surveys' element={<DashboardPage/>} replace/>
                    <Route exact path='/survey' element={<SurveyControl/>} replace/>
                </Routes>
            </Router>
        </>
    )
}

export default App
```




We now have a basic front end set up with the ability to complete a survey. The next step is connecting to the Ethereum blockchain and claiming your hard earned crypto tokens.

To do this, we will use a tool called Hardhat and a JavaScript library called Ethers.js.

Remember that we have already created our token in an earlier post. Now we need to create a way for that to be shared amongst users who complete our survey.

First, in the `scripts` folder, create two new files:

```
touch deploy-token.js deploy-owner.js
```

Then update them with the following code:

**deploy-owner.js**

```js
const hre = require("hardhat");

async function main() {

    const [deployer] = await hre.ethers.getSigners();
    console.log("Deploying contracts with the account:", deployer.address);

    const Owner = await hre.ethers.getContractFactory("Owner");
    const owner = await Owner.deploy();
    await owner.deployed();
    console.log("Owner deployed to:", owner.address);
}

main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });
```

**deploy-token.js**

```js
const hre = require("hardhat");

async function main() {

    let ownerAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";
    const [deployer] = await hre.ethers.getSigners();
    console.log("Deploying contracts with the account:", deployer.address);

    const CryptocracyToken = await hre.ethers.getContractFactory("CryptocracyToken");
    const cryptocracyToken = await CryptocracyToken.deploy(ownerAddress, "CryptocracyToken", "CTK");

    await cryptocracyToken.deployed();
    console.log("CTK deployed to:", cryptocracyToken.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);
    });

```

Then, navigate to the `components` folder and create a new file, which will allow us to check our Metamask wallet balance and withdraw tokens.

```
touch token-utility.js
```
Update this file with the following code:

```js
import React, {useState} from "react";
import {ethers} from "ethers";
import Card from "react-bootstrap/Card";
import Button from "react-bootstrap/Button";
import WalletBalanceDisplay from "./wallet-balance-display";

const TokenUtility = (props) => {

    const tokenAddress = "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512";
    const tokenOwnerAddress = "0x5FbDB2315678afecb367f032d93F642f64180aa3";

    const [withdrawalAmount, setWithdrawalAmount] = useState();
    const [showWalletBalance, setShowWalletBalance] = useState(false);
    const [newWalletBalance, updateNewWalletBalance] = useState();

    const getWalletBalance = async () => {
        if (typeof window.ethereum !== "undefined") {
            const [account] = await window.ethereum.request({method: "eth_requestAccounts"});
            const provider = new ethers.providers.Web3Provider(window.ethereum);
            const contract = new ethers.Contract(tokenAddress, props.tokenContract.abi, provider);
            const walletBalance = await contract.balanceOf(account);
            updateNewWalletBalance(walletBalance.toString());
            setShowWalletBalance(true);
        }
    };

    const withdrawToken = async () => {
        if (typeof window.ethereum !== "undefined") {
            const account = await window.ethereum.request({method: "eth_requestAccounts"});
            const provider = new ethers.providers.Web3Provider(window.ethereum);
            const signer = provider.getSigner();
            const ownerContract = new ethers.Contract(tokenOwnerAddress, props.ownerContract.abi, signer);
            let approveAllowance = await ownerContract.approveTokenSpend(tokenAddress, account[0], withdrawalAmount);
            await approveAllowance.wait();
            let withdraw = await ownerContract.withdrawToken(tokenAddress, account[0], withdrawalAmount);
            await withdraw.wait();
        }
    };

    return (
        <div>
            <Card>
                <Card.Body>
                    <Card.Subtitle>Withdraw to Your Wallet
                    </Card.Subtitle><br/>
                    <div className="d-grid gap-2">
                        <input
                            onChange={e => setWithdrawalAmount(e.target.value)}
                            placeholder="Enter Amount"/>
                        <Button onClick={withdrawToken}>Withdraw</Button>
                        <Button onClick={getWalletBalance} variant="warning">Current
                            wallet balance</Button>
                        {showWalletBalance ? <WalletBalanceDisplay
                            balance={newWalletBalance}/> : null}
                    </div>
                </Card.Body>
            </Card>
        </div>
    );
};

export default TokenUtility;
```

And also create a file called `wallet-balance-display.js` 

```
touch wallet-balance-display.js
```

and update it with the following code:

```js
import Alert from "react-bootstrap/Alert"

const WalletBalanceDisplay = ({ balance }) => {
    return (
        <div>
            <Alert variant="info"> Wallet balance: {balance}</Alert>
        </div>
    )
}

export default WalletBalanceDisplay
```

We also need to create a withdrawal container. Navigate to the components folder and type:
```
touch withdrawal-container.js
```
Update it with the following code:

```js
import {Col, Container, Row} from "react-bootstrap";
import TokenUtility from "./token-utlity";
import CryptocracyToken from '../artifacts/contracts/CryptocracyToken.sol/CryptocracyToken.json'
import Owner from '../artifacts/contracts/Owner.sol/Owner.json'

export default function WithdrawalContainer() {
    const Token = CryptocracyToken;
    const TokenHolder = Owner;

    return (
        <>
            <div className="withdrawal-container">
                <Container>
                    <Row className="justify-content-md-center">
                        <Col>
                            <TokenUtility tokenContract={Token} ownerContract={TokenHolder}/>
                        </Col>
                    </Row>
                </Container>
            </div>
        </>
    );
}
```

You might see some errors at the top of the file because we haven't yet compiled our smart contracts yet. To do this, navigate to the source folder and type:

```
npm install @openzeppelin/contracts
```
which will install the Open Zeppelin library. Then type:
```
npx hardhat compile
```

This will compile the smart contracts and create a new folder in your `src` folder called `artifacts`. Your errors should now disappear.

Next, we need to get our mock Ethereum blockchain running. In another terminal window/tab:

```
npx hardhat node
```


You must leave this window open and not use it for any further commands. This is now continuously running. In another terminal window/tab and from the project root (not src), type:

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

You should see this in response:

```
Deploying contracts with the account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Owner deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
```

then type:

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

to which you should see the following in response:

```
Deploying contracts with the account: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
CTK deployed to: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
```

Run the app:

```
npm start
```

Now, you need to import an account to Metamask, and the best choice here is the second account that appears in the Hardhat node. You shouldn't choose the first account because that is the account that is responsible for deploying the two smart contracts in our application. Find out how to import an account here:

https://metamask.zendesk.com/hc/en-us/articles/360015489331-How-to-import-an-Account

You will also need to import our custom CTK token to Metamask, which can be done by following the guide here:

https://metamask.zendesk.com/hc/en-us/articles/360015489031-How-to-add-unlisted-tokens-custom-tokens-in-MetaMask#h_01FWH492CHY60HWPC28RW0872H

Once complete, your Metamask should look something like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zf73drx99d8wkxd0jwka.png)

Now, when you click the "Current wallet balance" button you should see this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/siebggscoxulpqajkr8r.png)

And if you enter "50" in the input box and click the "Withdraw" button. You will see a FIRST Metamask confirmation box. Once you click "Confirm" you will see another confirmation box appear (which looks almost identical) - this is INTENDED because of our Owner/Approval setup in our smart contracts:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/35mmaullmtncpj3ejrf2.png)

If you then click the "Current wallet balance" button again you will see that our balance is updated:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t4wnxaaqtjjipgo83wm8.png)

If you check this amount in Metamask, you will also see our balance has updated (but it will be in long decimal format):

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4prj6pvjzja6vtnd5z8o.png)

**Summary**
In this series of blogs I have given a brief example of how to create a Web3 application using the Ethereum blockchain. The full application I developed was a lot bigger and more detailed. But hopefully this is at least an introduction of how to get started if you are interested becoming a Web3 developer.