Introduction to Solidity

What is Solidity?

Solidity is the primary programming language for writing smart contracts on Ethereum and other EVM-compatible blockchains. It is statically typed, object-oriented, and compiles to bytecode that runs on the Ethereum Virtual Machine (EVM). This page introduces core concepts using the diagrams below.

1. Basics: Contract Structure, Pragma, and Constructors

A Solidity contract is defined with the contract keyword. The pragma directive specifies the compiler version; Solidity compiles to EVM bytecode. State variables are stored on the blockchain. The constructor runs once at deployment; functions are the entry points for contract logic.

Solidity basics: pragma, contract, state variables, constructor, and functions

Basics: Pragma and version, contract structure, state variables (e.g. uint256, address), constructor, and functions (e.g. setNumber, getNumber, resetNumber with access control).

2. Variables and Storage

Solidity has several variable kinds: state variables (stored on-chain), immutable (set only in the constructor), constant (fixed at compile time), and local (temporary, discarded after the function returns). Data location matters: memory is temporary and modifiable; storage is a reference to on-chain data; calldata is read-only for external function arguments. Global variables like msg.sender and block.timestamp provide blockchain context.

Solidity variables: state, immutable, constant, memory, storage, local, global

Variables and storage: State, immutable, constant, memory, storage, local, and global variables with code examples.

3. Functions

Functions can have access modifiers: private (only inside the contract), internal (contract and derived contracts), external (only from outside), and public (anywhere). view functions read state but do not modify it; pure functions neither read nor modify state. payable functions can receive Ether. Functions declare return types and can use modifiers to run checks before or after execution.

Solidity functions: access modifiers, view, pure, payable, return values, modifiers

Functions: Access modifiers (private, internal, external, public), view/pure, payable, return values, and function modifiers (e.g. onlyOwner).

4. Events

Events are declared with the event keyword and allow logging to the blockchain. Parameters can be indexed for efficient filtering. Functions trigger events with emit. Events are useful for off-chain listeners (e.g. updating UIs) and as a cheap form of historical data. They cannot be used in view or pure functions because they alter state (logs).

Solidity events: declaration, indexed, emit, use cases and limitations

Events: Declaring events, indexing for fast retrieval, emitting from functions, and use cases (logging, UI updates, cheap storage).

5. Structs, Enums, and Mappings

Structs define custom types with multiple fields. Enums restrict a variable to a fixed set of named values. Mappings are key-value stores; they are not iterable and have no length. For ordered or countable data, keep a separate counter or array. The diagram shows an order system using an enum for status, a struct for order data, and a mapping keyed by order ID.

Solidity structs, enums, mappings: Order example with OrderStatus enum, Order struct, orders mapping

Structs, enums, and mappings: Enum for order status, struct for order data, mapping for orders, and a counter for the next order ID.

6. Conditionals and Loops

require(condition, "message") reverts the transaction if the condition fails. if/else works like in JavaScript or Java. for loops are common; using ++i instead of i++ can save gas. while loops are possible but can be costly if not bounded. The example shows require for validation, if/else for branching, and for/while for iteration.

Solidity conditionals and loops: require, if/else, for, while

Conditionals and loops: require for validation, if/else for logic, for loops (with gas tip: prefer ++i), and while loops (use with care).

7. Gas Optimization

Gas is the unit of cost on Ethereum. Optimizations include: using calldata for external function arguments (read-only, no copy to memory), pre-increment (++i) in loops to save gas vs post-increment, loading storage into memory when you read a value multiple times to avoid repeated storage reads, and caching array elements in local variables inside loops to reduce repeated accesses.

Solidity gas optimization: calldata, pre-increment, loading to memory, caching

Gas optimization: calldata for external args, ++i in loops, loading storage to memory, and caching array elements.

8. Inheritance and Override

Use import to bring in other contracts or libraries (e.g. OpenZeppelin). Inheritance is expressed with is: contract Child is Parent { }. Parent constructors are invoked in the child constructor by naming the parent and passing arguments. Functions marked virtual in a parent can be overriden in the child; use super.functionName() to call the parent implementation. Override order (e.g. in multiple inheritance) is right-to-left, with the most base-like contract on the left.

Solidity inheritance: import, is keyword, constructor chaining, override and super

Inheritance: import, is for inheritance, parent constructor calls, override and super for virtual functions.

Next steps: Use the Transaction Signing page to compile and deploy Solidity code, or explore the Consensus Mechanisms section to submit transactions to a testnet.