Skip to content

Create a Smart Contract

Introduction

Creating smart contracts is fundamental to blockchain development. While many frameworks and tools are available, understanding how to write a contract from scratch with just a text editor is essential knowledge.

This tutorial will guide you through creating a basic smart contract that can be used with other tutorials for deployment and integration on Asset Hub.

Prerequisites

Before starting, make sure you have:

  • A text editor of your choice (VS Code, Sublime Text, etc.)
  • Basic understanding of programming concepts
  • Familiarity with the Solidity programming language syntax. For further references, check the official Solidity documentation

Understanding Smart Contract Structure

Let's explore these components before building the contract:

  • SPDX license identifier - a standardized way to declare the license under which your code is released. This helps with legal compliance and is required by the Solidity compiler to avoid warnings
  • Pragma directive - specifies which version of Solidity compiler should be used for your contract
  • Contract declaration - similar to a class in object-oriented programming, it defines the boundaries of your smart contract
  • State variables - data stored directly in the contract that persists between function calls. These represent the contract's "state" on the blockchain
  • Functions - executable code that can read or modify the contract's state variables
  • Events - notification mechanisms that applications can subscribe to in order to track blockchain changes

Create the Smart Contract

In this section, you'll build a simple storage contract step by step. Later, you'll explore each component in more detail to understand what's happening behind the scenes.

This contract will:

  • Store a number
  • Allow updating the stored number
  • Emit an event when the number changes

To build the smart contract, follow the steps below:

  1. Create a new file named Storage.sol

  2. Add the SPDX license identifier at the top of the file:

    // SPDX-License-Identifier: MIT
    

    This line tells users and tools which license governs your code. The MIT license is commonly used for open-source projects. The Solidity compiler requires this line to avoid licensing-related warnings.

  3. Specify the Solidity version you want to use. We'll use a recent stable version:

    pragma solidity ^0.8.19;
    

    The caret ^ means "this version or any compatible newer version." This helps ensure your contract compiles correctly with the intended compiler features.

  4. Create the contract structure:

    contract Storage {
        // Contract code will go here
    }
    

    This defines a contract named "Storage", similar to how you would define a class in other programming languages.

  5. Add the state variables and event:

    contract Storage {
        // State variable to store a number
        uint256 private number;
    
        // Event to notify when the number changes
        event NumberChanged(uint256 newNumber);
    }
    

    Here, you're defining:

    • A state variable named number of type uint256 (unsigned integer with 256 bits), which is marked as private so it can only be accessed via functions within this contract
    • An event named NumberChanged that will be triggered whenever the number changes. The event includes the new value as data
  6. Add the getter and setter functions:

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.19;
    
    contract Storage {
        // State variable to store our number
        uint256 private number;
    
        // Event to notify when the number changes
        event NumberChanged(uint256 newNumber);
    
        // Function to store a new number
        function store(uint256 newNumber) public {
            number = newNumber;
            emit NumberChanged(newNumber);
        }
    
        // Function to retrieve the stored number
        function retrieve() public view returns (uint256) {
            return number;
        }
    }
    

The complete contract should look like this:

Storage.sol
Storage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract Storage {
    // State variable to store our number
    uint256 private number;

    // Event to notify when the number changes
    event NumberChanged(uint256 newNumber);

    // Function to store a new number
    function store(uint256 newNumber) public {
        number = newNumber;
        emit NumberChanged(newNumber);
    }

    // Function to retrieve the stored number
    function retrieve() public view returns (uint256) {
        return number;
    }
}

Understanding the Code

Let's break down the key components of the contract:

  • State Variable

    • uint256 private number - a private variable that can only be accessed through the contract's functions
    • The private keyword prevents direct access from other contracts, but it's important to note that while other contracts cannot read this variable directly, the data itself is still visible on the blockchain and can be read by external tools or applications that interact with the blockchain. "Private" in Solidity doesn't mean the data is encrypted or truly hidden
    • State variables in Solidity are permanent storage on the blockchain, making them different from variables in traditional programming. Every change to a state variable requires a transaction and costs gas (the fee paid for blockchain operations)
  • Event

    • event NumberChanged(uint256 newNumber) - emitted when the stored number changes
    • When triggered, events write data to the blockchain's log, which can be efficiently queried by applications
    • Unlike state variables, events cannot be read by smart contracts, only by external applications
    • Events are much more gas-efficient than storing data when you only need to notify external systems of changes
  • Functions

    • store(uint256 newNumber) - Updates the stored number and emits an event.

      • This function changes the state of the contract and requires a transaction to execute
      • The emit keyword is used to trigger the defined event
    • retrieve() - Returns the current stored number.

      • The view keyword indicates that this function only reads data and doesn't modify the contract's state
      • View functions don't require a transaction and don't cost gas when called externally

    For those new to Solidity, this naming pattern (getter/setter functions) is a common design pattern. Instead of directly accessing state variables, the convention is to use functions to control access and add additional logic if needed.

This basic contract serves as a foundation for learning smart contract development. Real-world contracts often require additional security considerations, more complex logic, and thorough testing before deployment.

For more detailed information about Solidity types, functions, and best practices, refer to the Solidity documentation or this beginner's guide to Solidity.

Where to Go Next

  • Tutorial Test and Deploy with Hardhat


    Learn how to test and deploy the smart contract you created by using Hardhat.

    Get Started

Last update: March 6, 2025
| Created: March 6, 2025