Featured resource
pluralsight tech forecast
2025 Tech Forecast

Which technologies will dominate in 2025? And what skills do you need to keep up?

Check it out
Hamburger Icon
  • Labs icon Lab
  • Core Tech
Labs

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.

Labs

Path Info

Level
Clock icon Intermediate
Duration
Clock icon 24m
Published
Clock icon Aug 23, 2023

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

Table of Contents

  1. 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 the Connect 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!

  2. 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 the artifacts 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 the Tickets.sol and Ownable.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 as SafeMath and Tickets.

    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 a config object, which includes several properties, one of which is ContractABI. Additionally, in the config.js file you'll find the HardHatNetworkURL. 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 to http://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.

  3. 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 besides localhost, HardHat requires additional configurations in the hardhat.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.

  4. 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 references app.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 the config.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 the Tickets contract.
    • Conversely, contractBySigner will be more dynamic, having both read and write capabilities for the Tickets contract since it leverages an account 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 text 20 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.

  5. 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 a view function. The Tickets 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 the getSigner() method provided by the ethers 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 the Side Note comment, when leveraging a browser plug-in, invoking provider.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 by Account #xx and starts with 0x, 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 **>**.
  6. 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 the claimTicket() function and harness the TicketClaimed 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.

Jeff Hopper is a polyglot solution developer with over 20 years of experience across several business domains. He has enjoyed many of those years focusing on the .Net stack.

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.