- Lab
- Core Tech

Guided: Building a Web3 DApp for an EVM Smart Contract - Part 1
In this guided code lab, you'll continue your journey through the lifecycle of a smart contract on the Ethereum blockchain. Starting with the deployment of a contract, you'll then seamlessly transition into constructing a DApp using the ethers.js library, enabling you to establish a connection to your deployed contract. As you delve deeper, you'll experience the intricacies of invoking contract functions and efficiently querying events, ensuring you gain a robust understanding of integrating blockchain functionalities into modern applications.

Path Info
Table of Contents
-
Challenge
Introduction
Welcome to the Guided: Building a Web3 DApp for an EVM Smart Contract Lab
In this lab, you'll delve into deploying and interacting with a smart contract using a JavaScript UI. By leveraging the ethers.js library, you'll develop a decentralized application (DApp). Vanilla JavaScript has been chosen so you can concentrate on the intricacies of ethers.js without getting sidetracked by other frameworks. However, for the purposes of this lab environment you'll employ a Node.js Express server to host the
ethers.js
file locally. Its primary function is to serve this file along with a configuration file.You'll be working with the
Tickets.sol
smart contract, which is a straightforward contract that allows users to claim a ticket. While its development is detailed in other labs, this session won't focus on its specifics. Even if you're new to Solidity development, you should navigate this lab comfortably. But, you might come across a few terms or concepts that are new to you. If you ever feel lost, it might be beneficial to complete the Solidity labs first before continuing with this one.To kick off:
Once set up, inspect the current state of your application by opening this link: {{localhost:3000}}.This DApp keeps things simple with a title, status message, and two buttons. The left
Claim Ticket
button activates when the selected account is able to claim its ticket. Soon, you'll integrate theConnect
button on the right, a staple in many Web3 DApps, enabling users to securely connect their Web3 account to the Ethereum network.In many Web3 DApps, third-party browser plugins like MetaMask are employed for secure account connections. However, to keep this lab simple you'll link directly to test accounts from HardHat's local Ethereum network, bypassing the need for any plugins.
Throughout the lab, you will spot commented-out code. This showcases where the logic for this lab environment deviates from an application that depends on the plugin.
Ready to dive in? Click the Next steps > to get started!
-
Challenge
Compiling the `Tickets` Contract
Let's start by compiling your contracts. While contracts are usually compiled during unit tests, as shown in the Solidity labs, you can also use the following HardHat command to directly compile all
.sol
files within the/contracts
directory. After the compilation, the build artifacts will be available in theartifacts
directory.In the FILETREE on the right, navigate to
/artifacts/contracts
. This contains directories corresponding to each.sol
file from the/contracts
directory. For example, you'll see directories for theTickets.sol
andOwnable.sol
contract files.Expanding on the
Tickets.sol
directory, you'll see several.json
files. These are the build artifacts for every contract within your/contracts/Tickets.sol
file, such asSafeMath
andTickets
.Opening the
Tickets.json
file, you'll find a property labeled"abi"
, which stands for Application Binary Interface. This ABI is crucial as it serves as a guide to help your Web3 DApp understand the contract's public functions.To manage the DApp's contract configuration, the file
/dapp/public/config.js
has been created. This file features aconfig
object, which includes several properties, one of which isContractABI
. Additionally, in theconfig.js
file you'll find theHardHatNetworkURL
. This serves as the endpoint for the HardHat node that was initiated earlier in this lab environment. For local development purposes, this value is typically set tohttp://localhost:8545
.In the next step you will see how to populate the
ContractAddress
.When you are ready, click the Next Steps > to deploy this contract and retrieve its contract address.
-
Challenge
Deploying the `Tickets` Contract
The contract has been compiled and is now ready for deployment to the HardHat local test node. While you are deploying to this network specifically, the process will remain relatively consistent, whether on the HardHat local node, testnet, or mainnet.
To deploy a contract you require Ether (ETH). On the mainnet you'd purchase ETH, but on a testnet "faucet" services offer test ETH. However, the HardHat local node streamlines the deployment process across all network types by creating 20 test accounts, each loaded with 10,000 test ETH.
The first step in deploying using HardHat is crafting a deployment script in the
scripts
directory. For deploying to other networks besideslocalhost
, HardHat requires additional configurations in thehardhat.config.js
file. This includes specifying the account's private key meant for deployment and ensuring sufficient gas is available for contract deployment. You can read more about deploying to a live network in the HardHat documentation.Click Next steps > when you're set to start crafting your Web3 DApp.
-
Challenge
Instantiate a Read-Only Connection
After successfully compiling and deploying your contract to the network and transferring the contract's ABI and address to the
config.js
file, you're now ready to develop the Web3 DApp.First, navigate to and open the
dapp/public/index.html
file. You previously saw the simple interface. Additionally, you will notice the inclusion of application logic via a script tag that referencesapp.js
.Proceed to open
dapp/public/app.js
. At the top of this file, the ethers.js library is imported. This library will facilitate the json-rpc communication between your application and the Ethereum network. Subsequent to the ethers.js import, you'll find the import statement for theconfig.js
that contains the key contract details previously mentioned.Following those imports, you'll see four variables declared that will be pivotal for maintaining a connection to the Ethereum network:
- The
provider
is paramount, entrusted with the responsibility of overseeing all communications with the Ethereum network. - The
account
variable denotes the Externally Owned Account (EOA). This represents an account underpinned by a private key, essential for signing transactions sent to the network. - The
contractByProvider
variable will provide a read-only interface to theTickets
contract. - Conversely,
contractBySigner
will be more dynamic, having both read and write capabilities for theTickets
contract since it leverages anaccount
to sign transactions that modify the contract. Adjacent to this modification, you'll find a comment labeled "Side Note". This section highlights one of the differences between connecting to a local network and leveraging third-party plugins, such as MetaMask. Switching over to your applications tab, refresh the page and you should see the text20 tickets available
or the specific ticket count you set in the deployment script.
Congratulations! You've just executed your first blockchain call. Technically, it's your second because the deployment process also constitutes a call.
Click Next step > when ready to instantiate a
contractBySigner
. - The
-
Challenge
Instantiate a Read/Write Connection
In the previous step you successfully created a read-only instance of the
Tickets
contract, enabling the invocation of aview
function. TheTickets
contract also permits an account owner to claim a ticket. However, to utilize this feature you require a contract instance with read and write permissions to the Ethereum network. This is only feasible with an Externally Owned Account (EOA), which you can obtain using thegetSigner()
method provided by theethers
library.The
Connect
button is prevalent in many Web3 DApps and typically initiates the plugin to prompt the user for their signer account. Since this lab is not utilizing a plugin, you'll need to mimic this account connection process and prompt the user to supply a public key from the HardHat node.The mimicing code for this button can be found within the
document.getElementById('connectAccount')
event listener. As highlighted in theSide Note
comment, when leveraging a browser plug-in, invokingprovider.getSigner()
suffices. The plug-in would then prompt users to log in.In this test DApp, users will be asked to supply the public key for the desired account. A list of available public keys from the HardHat local node is accessible in the Terminal tab where you initialized the
npx hardhat node
. Each key is prefixed byAccount #xx
and starts with0x
, as illustrated below:Account #19: 0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199 ``` To evaluate the newly integrated "Connect" functionality, first retrieve an account public key from the **Terminal** as previously described. Transition back to your application's tab and refresh the page to load the updated code. Upon clicking the `Connect` button and inputting the public key, you should observe the **status** is now encouraging you to claim a ticket alongside an activated `Claim Ticket` button. Once satisfied, proceed by selecting Next step **>**.
-
Challenge
Next Steps
Congratulations on completing Part 1 of the Guided: Building a Web3 DApp for an EVM Smart Contract.
In this lab, you compiled and deployed your
Tickets
contract to the local test network, and you configured your Web3 DApp so that it can interact with that contract. You have made great progress in building your ticketing DApp, but there is still more work to accomplish. Part 2 of this lab will delve deeper into the complete ticketing experience. You'll explore how to invoke theclaimTicket()
function and harness theTicketClaimed
event triggered by that call. Additionally, we'll delve into methods for searching the network logs for this event.We look forward to seeing you in Part 2 of this lab.
What's a lab?
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Provided environment for hands-on practice
We will provide the credentials and environment necessary for you to practice right within your browser.
Guided walkthrough
Follow along with the author’s guided walkthrough and build something new in your provided environment!
Did you know?
On average, you retain 75% more of your learning if you get time for practice.