DEV Community

Mario M. Orozco
Mario M. Orozco

Posted on • Updated on

EVM Dapp Starter Kit

  • What are we building? Using hardhat, we will deploy a smart contract to the goerli testnet, this contract creates a token and also is able to send these tokens to other address. For the frontend we will use react, for the interaction with the smart contract we will use Metamask and web3-react. Finally, for the analytics of our dapp we will be using sumer.

Sumer is building an all-in-one solution that helps dapp creators to understand and bring better usability to dapp users. We can already try the first version of sumer and its SDK

  • What do we need?:
  1. Node.js and a code Editor.

Dapp Overview:

Unlike a web application, a decentralized application or Dapp, has its backend running on a decentralized peer-to-peer network such as Ethereum. For dapps running in an EVM-based blockchain, the backend is smart contracts executed by the EVM. This means, that a dapp has the same properties as smart contracts and the blockchain network where it lives.

Dapp Architecture:

The architecture of dapp is still been defined and depends, like any application, on the services that the application should provide. However, there are some main components that a dapp should have:
Dapp Architecture

  • Frontend: It enables the users to interact with the smart contracts through interactive graphical components such as buttons, and icons, among others. Like web applications, this user interface runs on any browser.
  • Wallet: A wallet is a tool or software application that manages the account’s private key and addresses (public keys). Wallets don’t have custody of the account crypto assets. A wallet is only an application that enables the account owner to sign transactions, therefore, interact with the blockchain and the smart contracts living in the network.
  • Node or Node Provider: Enables communication with the blockchain, i.e., reading data or sending transactions. A node will broadcast the transactions and miners will validate the new states that the transactions can produce. Everyone can run a node. Nonetheless, because of the difficulty and costs that running a node could have, Dapps usually rely on a third-party service or Node provider. Every Ethereum client or Node provider implements a JSON-RPC Specification with a uniform set of methods.
  • The Blockchain Network: is the base layer, where the EVM executes the dapp smart contracts and stores the new states in the blockchain.

Let's build our dapp

1.- Smart Contract Deployment / backend

To develop and deployment of our contract we will be using the hardhat development environment. Create a new folder and install hardhat:

mkdir my-dapp && cd my-dapp
mkdir backend && cd backend
npm init
npm install --save-dev hardhat
npm install --save-dev @nomicfoundation/hardhat-toolbox
Enter fullscreen mode Exit fullscreen mode

Once hardhat is installed, we can create a new project with:

npx hardhat
Enter fullscreen mode Exit fullscreen mode

and select: Create an empty hardhat.config.js

Our project structure should look like this:

structure

Now let's create a folder contracts and inside of
it our smart contract: Token.sol

mkdir contracts && cd contracts
touch Token.sol
Enter fullscreen mode Exit fullscreen mode

Paste the token code into the Token.sol file. The contract is full of comments that explains its functionality, kudos to hardhat team! If you wish, you can edit the name and symbol of the token.

token info

We can now compile our Token contract using hardhat:

npx hardhat compile
Enter fullscreen mode Exit fullscreen mode

After compiling our contract we can deploy it to the goerli network. In order to comunicate with the blockhain we will be using the alchemy node provider. To sign the deploy transaction, we will need the private key of our metamask wallet and some goerli eth.

Edit your hardhat.config.js:

require("@nomicfoundation/hardhat-toolbox");

// Go to https://www.alchemyapi.io, sign up, create
// a new App in its dashboard, and replace "KEY" with its key
const ALCHEMY_API_KEY = "KEY";

// Replace this private key with your Goerli account private key
// To export your private key from Metamask, open Metamask and
// go to Account Details > Export Private Key
// Beware: NEVER put real Ether into testing accounts
const GOERLI_PRIVATE_KEY = "YOUR GOERLI PRIVATE KEY";

module.exports = {
  solidity: "0.8.9",
  networks: {
    goerli: {
      url: `https://eth-goerli.alchemyapi.io/v2/${ALCHEMY_API_KEY}`,
      accounts: [GOERLI_PRIVATE_KEY]
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

In order to avoid exposing the api key or private key, we should use env variables, for instance dotenv

Now we need a script that deploys our contract. Let's create a folder scripts, and inside of it, a deploy.js file:

async function main() {
    const [deployer] = await ethers.getSigners();

    console.log("Deploying contracts with the account:", deployer.address);

    console.log("Account balance:", (await deployer.getBalance()).toString());

    const Token = await ethers.getContractFactory("Token");
    const token = await Token.deploy();

    console.log("Token address:", token.address);
}

main()
    .then(() => process.exit(0))
    .catch((error) => {
        console.error(error);
        process.exit(1);
    });
Enter fullscreen mode Exit fullscreen mode

And now everything to deploy your contract to the goerli blockchain network should be set. If we run:

npx hardhat run scripts/deploy.js --network goerli
Enter fullscreen mode Exit fullscreen mode

The following message should be displayed:

Deploying contracts with the account: your wallet account
Account balance: your balance
Token address: the token contract address
Enter fullscreen mode Exit fullscreen mode

Congratulations, you just deployed a smart contract to the goerli network!! If you copy the contract address and go to the goerli etherscan, you will find your deployment there :D. Using the contract address you can also import the tokens to your metamask wallet:

import token

add_token

2.- Frontend

In our project root directory create a new folder frontend using create-react-app, and inside the frontend folder install, ethers, web3-react, and the sumer-sdk.

npx create-react-app frontend
cd frontend
npm i ethers
npm i @web3-react/core @web3-react/injected-connector
npm i sumer-sdk
Enter fullscreen mode Exit fullscreen mode

Our project structure should look like this:

project_structure

In my-app/frontend/src/index.js enable the use of web3-react and sumer-sdk:
Remember to get your key in the sumer app

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

import { Web3ReactProvider } from "@web3-react/core";
import { Sumer } from "sumer-sdk";

// this is a temporary key, get yours in the sumer app 
const dappKey = '04a23d9f-1c7a-414e-b400-847658ef5cd6'

//configure web3-react
const getLibrary = (provider) => {
    const library = Sumer.init({ provider, dappKey })
    return library
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Web3ReactProvider getLibrary={getLibrary}>
    <App />
  </Web3ReactProvider>
);
Enter fullscreen mode Exit fullscreen mode

We also need our deployed contract address, and the contract interface, generated in the compile process. For simplicity just copy /backend/artifacts/contracts/Token.sol/Token.json file into the frontend/src/

In our frontend/src/App.js we can start by connecting our wallet to the goerli testnet:

function ConnectMetamask() {
  const { active, account, chainId, activate, deactivate } = useWeb3React()
  if (!active) {
    return (
      <div >
        <button onClick={() => { activate(injected) }}>Connect Metamask</button>
      </div >
    )
  } else if (chainId === 5) {
    return (
      <div >User Address: {account}
        < button onClick={deactivate} > disconnect</button >
      </div >
    )
  } else {
    return (
      <div >
        {alert("please change to the göerli testnet")}
      </div >
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

We will also need a function that allows call the transfer function of our Token smart contract:

async function sendTokens(to, amount) {

    const contract = Sumer.createWrappedContract(
      CONTRACT_ADDR,
      Token.abi,
      provider.getSigner()
    );

  const tx = await contract.transfer(to, amount)
  await tx.wait()
}
Enter fullscreen mode Exit fullscreen mode

The fully App.js code can be found here

Finally you can start your react app as usual: npm
start

dapp

The whole code can be found here. Thanks for reading this, if you have any question, please reach us out. Happy hacking fren :D


Top comments (1)

Collapse
 
diowagmivs profile image
diowagmivs

Great tutorial!!