Future

Cover image for Solidity Basics (Part 1) — Variables, Functions & Your First Real Contract
Ribhav
Ribhav

Posted on • Edited on • Originally published at Medium

Solidity Basics (Part 1) — Variables, Functions & Your First Real Contract

After a short two‑day pause in the 60‑Day Web3 journey, it’s time to hit play again and kick off the next phase with our first steps into Solidity. For the last 25 days, we’ve treated smart contracts like mysterious vending machines: you put in a transaction, and something happens on-chain. Today we finally lift the lid and start reading the language those vending machines are written in: Solidity.

This is Day 26, the start of Phase 3: Development in the 60‑Day Web3 journey. The goal for today is not to become a Solidity expert. The goal is to understand the basic building blocks — variables and functions — and then ship a tiny but real contract to Sepolia: a Web3 Journey Logger.


1. What is Solidity, really?

Solidity is a high-level, contract‑oriented programming language used to write smart contracts that run on Ethereum and other EVM-compatible chains like Arbitrum, Optimism, and Polygon. Once compiled, your Solidity code becomes bytecode that lives at a specific address on-chain and is executed by every node that processes your transaction.

If you’ve seen JavaScript, C++, or TypeScript, Solidity will look familiar: curly braces, functions, variables, if conditions. But there are two crucial differences: you’re programming money and state, not just UI, and every operation costs gas while the code you deploy is mostly permanent.

That’s why starting with the basics — how data is stored and how users interact with that data — is so important.


2. Variables: the contract’s on-chain memory

Think of a smart contract as a tiny on-chain application with its own private database. Variables are the named boxes where this contract stores data.

In Solidity, you must always declare both the type and the name of each variable because the compiler wants to know exactly what will be stored where.

2.1 Types of variables

At a high level, there are three levels of variables:

  • State variables

    • Stored permanently in the contract’s storage on the blockchain.
    • Persist between function calls and transactions.
    • Example: the contract’s owner address, a token balance mapping, or a counter.
  • Local variables

    • Declared inside a function.
    • Exist only while that function is running, then disappear.
    • Example: uint256 sum = a + b; inside a function.
  • Global variables

    • Built-in helpers provided by the EVM.
    • Examples: msg.sender for the caller, block.timestamp for the current block’s timestamp, and block.number for the current block number.

In this first step, the focus is on state variables, since they form your contract’s on-chain memory.

2.2 Common data types you’ll actually use

Here are the basic types you’ll see in almost every contract:

  • bool

    • Stores true or false.
    • Example: bool public completed;
  • uint256

    • Unsigned integer (0 and positive numbers).
    • Commonly used for amounts, IDs, counters, timestamps.
    • Example: uint256 public dayNumber;
  • address

    • Stores an Ethereum address, either a user or another contract.
    • Example: address public owner;
  • string

    • Stores text data.
    • More expensive than numbers in terms of gas, so used only when needed.
    • Example: string public note;

There are many more types such as int, bytes, mapping, struct, and arrays, but these four are enough to get started.


3. Functions: how users talk to your contract

If variables are the contract’s memory, functions are the doors and buttons users can press to read or update that memory.

Every time someone calls a function via a transaction or a UI like a dApp, the EVM executes the function’s logic step by step.

3.1 Function anatomy

A typical Solidity function looks like this:

function setDay(uint256 _day) public {
    dayNumber = _day;
}
Enter fullscreen mode Exit fullscreen mode

In this example, setDay is the function name, uint256 _day is the input parameter, public is the visibility specifier, and the body between braces updates the dayNumber state variable.

3.2 Visibility (who can call this?)

Visibility controls who can call a function and from where:

  • public

    • Anyone, including other contracts, can call this function.
    • A public function is part of the contract’s external interface automatically.
  • external

    • Intended to be called from outside the contract.
    • Slightly more gas‑efficient for pure external calls.

Other options like internal and private are used for helper functions and will appear later as contracts become more modular.
Note: setEntry is marked public but usually called externally; external could be slightly cheaper.

3.3 State mutability (what does this function do to state?)

Solidity requires you to be explicit about how a function interacts with state:

  • view

    • Can read state variables but cannot modify them.
    • Does not cost gas when called off-chain via tools like Etherscan or a dApp.
  • pure

    • Cannot read or modify state.
    • Works only with its inputs and local variables.

Example:

function getDay() public view returns (uint256) {
    return dayNumber;
}

function add(uint256 a, uint256 b) public pure returns (uint256) {
    return a + b;
}
Enter fullscreen mode Exit fullscreen mode

4. Your first real contract: Web3 Journey Logger

Instead of another generic “Simple Storage” example, this article builds a Web3 Journey Logger contract that ties directly into a learning challenge.

The contract will:

  • Store a name.
  • Store the current learning day number.
  • Store a short note about the day.

This small contract is enough to show how variables and functions come together in a real, personal use case.

4.1 What the contract should do

The Web3 Journey Logger has a few core behaviors:

  • When deployed, it remembers who deployed it as the owner.
  • It allows updating the current dayNumber and note for the latest entry.
  • It lets anyone read the stored values for name, day number, and note.

These requirements map cleanly to a handful of state variables and two or three functions.

4.2 Full contract code

Here is a complete version of the Web3 Journey Logger contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Web3JourneyLogger {
    // --- State variables ---

    // Address of the person who deployed the contract
    address public owner;

    // Name or handle of the learner
    string public name;

    // Current day in the learning journey
    uint256 public dayNumber;

    // Short note for the current day
    string public note;

    // --- Constructor ---

    constructor(string memory _name) {
        owner = msg.sender;
        name = _name;
    }

    // --- Core functions ---

    // Update the current day and note (only owner can call)
    function setEntry(uint256 _dayNumber, string calldata _note) public {
        require(msg.sender == owner, "Not owner");
        dayNumber = _dayNumber;
        note = _note;
    }

    // Helper to read all data in one call
    function getEntry()
        public
        view
        returns (
            string memory _name,
            uint256 _day,
            string memory _note
        )
    {
        return (name, dayNumber, note);
    }
}
Enter fullscreen mode Exit fullscreen mode

This minimal contract demonstrates state variables, a constructor, a state‑changing function with a simple access control check, and a view function that returns multiple values.


5. Step‑by‑step: deploy to Sepolia with Remix

To make this more than theory, the contract is deployed on the Sepolia testnet using Remix and MetaMask.

5.1 Setup the wallet

A wallet such as MetaMask is needed to sign and send transactions:

  • The wallet must be switched to the Sepolia test network.
  • A small amount of test ETH can be requested from a Sepolia faucet to cover deployment gas.

This setup mirrors real mainnet deployment without risking real funds.
You can follow these steps!

5.2 Open Remix and add the contract

Remix is a browser-based IDE for Solidity:

  • Visit https://remix.ethereum.org in a browser.
  • In the file explorer, create a new file named Web3JourneyLogger.sol.
  • Paste the complete contract code into this file.

Remix automatically saves the file and makes it available to the Solidity compiler.

5.3 Compile the contract

Compiling turns Solidity into bytecode that can be deployed:

  • Open the Solidity Compiler tab in Remix.
  • Select a compiler version matching the pragma, such as 0.8.20.
  • Click Compile Web3JourneyLogger.sol.

If any errors appear, Remix highlights the problematic lines so they can be corrected before trying again.

5.4 Deploy to Sepolia

Once the contract compiles, it can be deployed to the testnet:

  • Open the Deploy & Run Transactions tab.
  • Set Environment to Injected Provider – MetaMask so Remix uses the wallet’s network.
  • Confirm that MetaMask is on the Sepolia network.
  • Ensure Web3JourneyLogger is selected in the contract dropdown.
  • In the constructor field, pass a name string, for example "Ribhav".
  • Click Deploy and confirm the transaction in MetaMask.

After mining, Remix shows a deployed contract instance and the transaction can also be viewed on Sepolia Etherscan using the transaction hash.

5.5 Interact with the contract

The deployed contract can now be read and updated from Remix:

  • Under Deployed Contracts, expand the Web3JourneyLogger instance.
  • Call the generated getters like owner, name, dayNumber, and note to see current values.
  • Use setEntry to set a new day number and note, then read them back again using either the individual getters or getEntry().

By repeating this daily, the contract becomes a small on-chain journal of a Web3 learning journey.


6. Why this matters for developers

Every DeFi protocol, NFT marketplace, or DAO is ultimately just a more complex arrangement of variables and functions like the ones introduced here.

Understanding how state is stored, how functions expose or protect that state, and how contracts are deployed to a network is the foundation of secure smart contract development and auditing.

In the next steps of the journey, these basics expand into arrays, mappings, structs, access control patterns, and local development tools like Hardhat and Foundry, but they all build on the same core ideas introduced in this first Solidity article.


Further reading



Top comments (0)