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: Introduction to Solidity Development using Hardhat

In this hands-on lab, you'll dive deep into Ethereum blockchain development using Hardhat and Solidity. You'll engage with key elements like contracts, variables, functions, and unit testing. Through hands-on exercises, you'll create and test a simple contract, understand how variables are used to store and handle data, learn how to manipulate function visibility, and explore unique features of Solidity variables such as Ethereum address types. This lab offers a solid stepping stone to confidently develop robust and secure smart contracts.

Labs

Path Info

Level
Clock icon Beginner
Duration
Clock icon 1h 39m
Published
Clock icon Aug 18, 2023

Contact sales

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

Table of Contents

  1. Challenge

    Introduction

    Welcome to "Guided: Introduction to Solidity Development using Hardhat."

    In this hands-on session, you'll embark on the journey of constructing a simple Solidity contract, enabling you to grasp the essential syntax and semantics of the Solidity language.

    Solidity is a high-level, statically-typed programming language used for creating smart contracts on the Ethereum blockchain. These smart contracts are self-executing agreements embedded in code and are hosted on the Ethereum Virtual Machine (EVM), a decentralized runtime environment that executes these contracts.

    The EVM is an essential component of the Ethereum network as it provides security and execution isolation to the smart contracts. It is completely sandboxed from the network, file system, and other processes of the host computer system.

    Throughout your exploration, you'll be utilizing the Hardhat development environment. Hardhat is a development environment commonly used for Solidity development. It offers features for writing, compiling, debugging, and deploying your smart contracts and decentralized applications (dApps) within your local development environment. By providing an EVM tailored for development, Hardhat greatly streamlines the process of developing, deploying, and testing smart contracts in Solidity, making it a favored tool among Ethereum developers.

    To facilitate a seamless learning experience, Hardhat has been pre-installed in the current environment. However, if you're interested in setting it up in your own workspace, you can follow the instructions provided at https://hardhat.org/hardhat-runner/docs/getting-started#installation.

    When ready, click the Next step > button below.

  2. Challenge

    Building your First Contract

    In the Hardhat development environment, Solidity contract source files are written in files that reside within the contracts directory and have a .sol file extension. While Hardhat provides a conducive environment for developing and testing these contracts, the actual transformation of the contract code into EVM bytecode, which is the format executed on the Ethereum blockchain, is handled by the Solidity compiler.

    A Solidity source file begins with a pragma statement, a directive for the Solidity compiler indicating which version of Solidity is compatible with the code. This step is crucial because the Solidity compiler, although separate from Hardhat, can exhibit differences in behavior across versions due to its semantic versioning system. The pragma statement helps to ensure that the smart contract will not accidentally be compiled with a newer, potentially incompatible compiler. In addition to the pragma statement, another line often found at the top of Solidity files is the SPDX-License-Identifier, such as // SPDX-License-Identifier: MIT. This indicates the license under which the file is distributed. While not mandatory for the contract to function, it's highly recommended for open-source projects and is often required by tooling that interacts with Solidity code. If not provided Hardhat will throw a warning message when trying to compile the contract. Following these directives, the contract is declared using the contract keyword, followed by the contract's name. A contract in Solidity can be seen as analogous to a class in object-oriented programming languages. It serves as the primary building block of Ethereum applications — at its simplest, a single contract is a collection of code (its functions) and data (its state) that resides at a specific address on the Ethereum blockchain. In the following steps, you will delve deeper into the specifics of Solidity, learning to declare variables and define functions within your contract. This will provide you with the foundational knowledge needed to start creating your own fully-functional smart contracts.

    When ready, click the Next step > button below.

  3. Challenge

    Using Variables in Solidity for State and Data Management

    In Solidity, variables play a critical role in storing and manipulating data within contracts. They accommodate a variety of data types, from primitive values to more complex user-defined structures.

    Being a statically-typed language, Solidity demands that each variable's type be explicitly declared at its creation. This means the type of data a variable can hold is defined at compile-time, not at runtime. This static typing helps to catch errors early during development, as mismatches between declared and assigned types will trigger compiler errors.

    Solidity provides several primitive data types like string, bool, and integers (uint, int).

    Solidity offers a variety of primitive data types, such as string, bool, and integers. It's important to note that integers in Solidity come in two forms: unsigned (uint) and signed (int). Unsigned integers are always positive or zero, while signed integers can be negative, zero, or positive. Be careful when dealing with these types, as they have distinct properties and potential pitfalls, particularly regarding overflow and underflow conditions. More complex types, such as arrays ([]) and structs, are also supported. Arrays store collections of homogeneous data, while structs enable creation of complex data types bundling variables of various types. Selecting suitable variable types is vital for efficient and secure contracts. Moreover, it's important to grasp the cost implications of different variable types.

    In Solidity, variables fall into two categories - state variables and local variables.

    State variables, like the ones defined above, are declared outside any function within the contract. They represent the contract's state and are stored persistently on the Ethereum blockchain, preserving their values across transactions and function calls. However, this permanence comes with a cost. This cost is referred to as gas, which is Ethereum's unit of computational work. While efficient state variable management is key to optimizing contracts, an in-depth discussion of gas exceeds this lab's scope.

    Local variables, contrastingly, exist only within a function's scope. They are temporary, residing in memory and not on the blockchain. Their values reset every time the function is called, and manipulating them doesn't incur gas costs like state variables.

    Once ready, click the Next step > button below to explore functions and memory variables.

  4. Challenge

    Designing Functions for Dynamic Contract Operations

    Functions are central to smart contract programming in Solidity. A function is a reusable piece of code that can be invoked from anywhere within a contract if visibility and access modifiers (like public, private, etc.) allow it. Functions can take arguments, execute specific operations, and return results. Additionally, depending on the access modifier, functions can be called externally by account holders interacting with the contract on the blockchain.

    In Solidity, functions are declared with the function keyword, followed by the function name. The arguments are defined within parentheses (), followed by any function modifiers, and then the body of the function, where the logic is written, is enclosed within curly braces {}. The _age parameter is of type uint, which is a value type in Solidity. Value types such as uint or bool create a new copy when they're assigned to another variable or passed as arguments to a function, so they don't reference the original variables or memory locations. Conversely, when a function accepts a reference type, like a string or an array, the parameter must be marked with a data location keyword: memory or calldata. These keywords dictate where the data for these reference types is stored during the function execution. Memory denotes that the data is temporarily held in memory and will be discarded once the function call ends, while calldata is read-only, more gas-efficient, and primarily used for data passed by external calls made into the contract.

    In addition to these data location keywords, Solidity also provides function modifiers of view and pure.

    The pure modifier ensures the function will not read from or write to the contract's state.

    On the other hand, the view modifier ensures the function will not modify the contract's state. Also, observe how the return type(s) of the function are declared. A function can return more than one type. In subsequent steps, you will explore how these returned values can be consumed by the calling function.

    With your grasp of Solidity's fundamental elements like variables and functions, you're now prepared to immerse yourself in the unique aspects of blockchain development. To facilitate this process, you'll be engaging with Hardhat unit tests, an invaluable resource for investigating, validating, and testing the operations of your smart contracts.

    When you are ready, click the Next step > button below.

  5. Challenge

    Leveraging Hardhat for Unit Testing Blockchain Specifics in Solidity Contracts

    Hardhat unit testing serves as an integral component in blockchain development, particularly due to the immutable nature of smart contracts deployed on the Ethereum blockchain. Once deployed, these contracts cannot be modified, which underscores the critical need for testing prior to deployment. By writing and executing unit tests using Hardhat, developers can ensure the reliability and correctness of their smart contracts' code. These unit tests systematically verify the behavior of individual contract functions, validate contract logic, and help identify potential bugs or errors early in the development process. Hardhat's testing framework allows developers to simulate blockchain interactions, deploy contracts to a local development network, and validate contract functionality within a controlled environment. This introduction explores the benefits of using Hardhat for unit testing in blockchain development, enabling developers to confidently build robust and secure smart contracts.

    Hardhat offers many helpers to test your smart contracts. One such feature is a local test Ethereum network. Launching this command fires up the local Ethereum network and creates a series of accounts for testing purposes. While the details of accounts is a bit beyond the scope of this lab, it's important to understand that the Ethereum network accommodates two distinct types of accounts. The first type is an Externally Owned Account, which is accessible by anyone possessing the private key of the account. The second type is a Contract Account, which is responsible for storing the specifics of a smart contract. To deepen your understanding of accounts, you may find this documentation useful: https://ethereum.org/en/developers/docs/accounts/

    You can stop the running network by placing focus into the Terminal window and pressing the Ctrl+c keys.

    To unit test your smart contract, you need to deploy it to the Ethereum network and retrieve a reference to the created contract account. A Hardhat unit test is able to use this local test network for deployment. Hardhat also extends the ethers.js library with functionalities that aid interaction with the Ethereum network, such as the deployContract method that deploys this contract to the local network. Now, you can start writing unit tests against the deployed contract, such as verifying that the setAge function works correctly. > Notice the call to the age variable. This is actually a call to a getter function that the solidity compiler created for you, implicitly exposing the age variable as public. If you prefer the variable to be private, you can mark it as private.

    You have now created your first unit test. The above unit test is an example of interacting with a Contract Account that is being referenced by the firstContract variable.

    To interact with an Externally Owned Account, the Hardhat-ethers plugin provides the getSigners() method. Scrolling up in the Terminal window, you'll see all of the details for the owner account, including its address. You'll also see that there are 19 other accounts added to the local test Ethereum network.

    With this introduction to working with Ethereum accounts, you're ready to explore Solidity-specific variables.

    When ready, click the Next step > button below to explore address and mapping variables.

  6. Challenge

    Utilizing Address and Mapping Types in Solidity

    In the Ethereum ecosystem, address and mapping are two versatile variable types. The address type can hold the unique identifiers of both Externally Owned Accounts (EOA) and Contract Accounts, facilitating efficient interactions with users and contracts within the Ethereum network. When deploying a contract to the network, a unique type of transaction is initiated. This transaction must be initiated by an Externally Owned Account (EOA). The constructor function, which is executed only once upon contract deployment, is used to initialize state variables. Ethereum transactions provide access to a special global variable, msg, which contains details about the transaction. For instance, msg.sender represents the address of the EOA initiating the current call. You can utilize this owner address to control who can change the state of the contract. For example, you may want to allow only the contract owner to change the name variable. You can enforce this rule by checking if msg.sender is equal to owner: Alternatively, Solidity provides the require function to enforce conditions. Unlike the if statement, a require function will stop execution and revert all changes if its condition is not met: Another key type of Solidity is mapping, which allows you to store structured data much like a hash table or dictionary. For example, you can create a mapping of addresses to names: The combination of address and mapping types enable developers to create engaging decentralized applications, from simple token contracts to complex voting systems, Decentralized Autonomous Organizations (DAOs) and more. These types allow developers to manage complex data relationships in a robust and gas-efficient way, crucial for the computational environment of Ethereum.

    When ready, click the Next step > below.

  7. Challenge

    Next Steps

    Congratulations on completing this Introduction to Solidity Development using Hardhat.

    You've taken a significant step forward in your blockchain journey. Don't stop here—continue experimenting with this lab and explore the vast possibilities this knowledge unlocks.

    Some ideas are to:

    • Enhance the contract by adding a getMyName() function that returns the name that is mapped to the calling account.
    • Create unit tests around the address and mapping functions created in the previous step

    As you become comfortable with Solidity syntax and learn to build and test smart contracts using Hardhat, you'll be ready to tackle more intricate concepts. Up next, delve deeper into Solidity's syntax and learn how to deploy your smart contract to a network.

    Remember, learning is a journey, not a race. Each step you take brings you closer to becoming an accomplished blockchain developer.

    The best to you as you continue your exciting journey into Blockchain training and Solidity contract development! We look forward to seeing what you will create.

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.