Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Smart Contracts  ›  Lesson

Solidity Basics

Solidity 15 minA Solidity contract declares state variables, a constructor and functions, and uses require checks on msg.sender and msg.value to enforce who may do what.

Solidity Basics

The last lesson described the bicycle escrow in words. On Ethereum and the other EVM chains, contracts like it are most often written in Solidity, a typed language with curly braces that looks familiar if you know JavaScript, Java or C. (Vyper, a Python-like language, compiles to the same EVM, and Rust is common on Solana.) Here is the escrow in full.

The rule

State stores it, functions change it, require guards it.

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

contract BikeEscrow {
    address public buyer;
    address payable public seller;
    bool public released;

    constructor(address payable _seller) payable {
        require(msg.value > 0, "send the payment");
        buyer = msg.sender;
        seller = _seller;
    }

    function release() external {
        require(msg.sender == buyer, "only the buyer");
        require(!released, "already released");
        released = true;
        (bool ok, ) = seller.call{value: address(this).balance}("");
        require(ok, "payment failed");
    }
}

Read it from the top:

  • pragma pins the compiler version, because the language's rules change between versions.
  • State variables (buyer, seller, released) live in the contract's storage on the chain. Marking them public makes Solidity generate a getter function that anyone can call to read each one.
  • The constructor runs once, at deployment. payable lets it receive coins. msg.value is the amount sent with the call, and msg.sender is the address that sent it, which here is Asha.
  • release is external, so transactions from outside can call it. Its require lines are guards: if a condition is false, the whole call reverts with that message.
  • seller.call{value: …}("") sends the contract's entire balance to Ravi, and the last require reverts everything if that transfer fails.

Before any of this runs on a chain, the Solidity source is compiled into EVM bytecode, and it is that bytecode which is deployed and executed by every node. Development tools such as Remix, Hardhat and Foundry compile, test and deploy contracts, usually on a local or test network first, where mistakes cost nothing.

Notice that released = true comes before the payment. Update your own state first, then interact with other addresses. This ordering closes a well-known class of bugs in which the receiving address calls back into the contract before its state has been updated. This escrow sends its whole balance in one go, so little could go wrong here, but in contracts that pay out from a shared pool, the wrong order has let attackers withdraw again and again. Make the habit automatic.

The shortcut

Read every function as "who, what, then what": who may call it (the msg.sender checks), what must be true (the require lines), then what state changes and what gets sent.

Ravi tries to call releaseStep 1 of 4
  1. Who is calling?

    msg.sender is Ravi's address, not the buyer's.

Drills

Answer fast — trust the rule.

quick drill

Inside the constructor, what is msg.sender?

quick drill

What does require(!released, "already released") prevent?

quick drill

What does marking buyer as public do?

quick drill

Why does release set released = true before sending the coins?

quick drill

Which keyword lets the constructor receive coins when the contract is deployed?

Remember

  • State stores it, functions change it, require guards it.
  • Shortcut: read each function as who, what, then what: caller checks, conditions, then state changes and payments.
  • Trap: update state before sending coins, and remember that a reverted call still costs gas.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainThree calls to BikeEscrow

Walk through three moments in BikeEscrow's life: Asha deploys it with a payment, Ravi calls release, then Asha calls release. For each, give msg.sender, the value of released afterwards, and what happens to the coins.