Solidity

On this page 7

Solidity is a statically typed, contract-oriented programming language used to write smart contracts that compile to bytecode for the Ethereum Virtual Machine (EVM). It is the dominant language for smart contracts on Ethereum and on EVM-compatible networks such as layer 2 rollups and many independent chains.

Its syntax resembles JavaScript, C++ and Java, but its execution model is very different: every operation costs gas, storage is permanent and expensive, and deployed code is normally immutable. In crypto & blockchain engineering, writing Solidity well therefore means thinking about security and cost as much as about functionality.

How Solidity code becomes a running contract

A Solidity source file declares one or more contracts, which work like classes with persistent state. The solc compiler turns them into two artifacts: EVM bytecode that is deployed on chain and an ABI (application binary interface) that describes functions and events so wallets and applications can call them.

Deployment is a transaction that runs the constructor once and stores the resulting runtime bytecode at a new address. After that, users and other contracts interact through external function calls, each executed by every validating node, which is why results must be fully deterministic.

The main building blocks of a contract are summarized below.

ElementPurposeTypical example
State variablesPersistent data in contract storageToken balances mapping
FunctionsLogic callable internally or externallytransfer, approve, withdraw
ModifiersReusable checks around functionsonlyOwner access control
EventsCheap logs read by off-chain softwareTransfer event for indexers
Custom errorsGas-efficient revert reasonsInsufficientBalance error
Interfaces and librariesTyped calls and shared codeIERC20 interface, math library
Core language elements and their purpose

Types, data locations and visibility

Solidity is statically typed: every variable has a declared type such as uint256, address, bool, bytes32 or a mapping. Since version 0.8, arithmetic on integers reverts on overflow and underflow by default, which removed a whole class of bugs that earlier code handled with external math libraries.

Reference types must state a data location, and the choice has a direct effect on gas. Writing a new storage slot costs about 20,000 gas, while memory and calldata are far cheaper because they disappear after the call.

LocationLifetimeRelative cost
storagePermanent on chainHighest, especially new writes
memoryDuration of one callModerate, grows with size
calldataRead-only call inputLowest for external inputs
transient storageOne transaction onlyLow, used for locks
Data locations compared

Functions declare visibility (public, external, internal or private) and a state mutability (view, pure or payable). Private does not mean secret: all contract storage is publicly readable on chain, so passwords or unrevealed values must never be stored in plain form.

Solidity compared with other smart contract languages

Solidity is not the only option, and teams sometimes choose an alternative for auditability or platform reasons. Vyper also targets the EVM, while Rust and Move serve other virtual machines.

LanguageTarget platformDistinctive trait
SolidityEVM chainsLargest ecosystem, inheritance, rich features
VyperEVM chainsPython-like, deliberately minimal
YulEVM chainsLow-level intermediate language for optimization
RustSolana and other non-EVM chainsGeneral language with platform frameworks
MoveAptos and SuiResource types that cannot be copied
Smart contract languages and their main traits

The decisive advantage of Solidity is its ecosystem: audited libraries such as OpenZeppelin, development frameworks such as Hardhat and Foundry, static analyzers, and a large pool of auditors. Its feature richness, including multiple inheritance and inline assembly, also gives developers more ways to introduce subtle errors.

Security pitfalls specific to Solidity

Most costly incidents come from a short list of recurring mistakes. The language enforces types, but it cannot prevent logic that lets an attacker re-enter a function, bypass access control or manipulate a price source.

VulnerabilityCauseStandard defense
Reentrancy attackExternal call before state updateChecks-effects-interactions, reentrancy guard
Missing access controlUnprotected admin functionsRole checks and ownership patterns
Oracle manipulationSpot price from a thin poolTime-weighted or external oracle prices
Unchecked call resultsLow-level call failure ignoredCheck return values or use safe wrappers
tx.origin authenticationUsing origin instead of senderAuthenticate with msg.sender
Storage collisionsBad layout in upgradeable proxiesStandard proxy storage slots
Common vulnerabilities and standard defenses

A professional workflow combines unit and fuzz testing, static analysis, and an independent smart contract audit before deployment. For high-value logic, teams add formal verification of critical invariants, such as total supply always equaling the sum of balances.

Writing gas-efficient and maintainable code

Gas optimization in Solidity is mostly about touching storage less. Packing several small variables into one 32-byte slot, caching storage values in memory inside loops, using immutable and constant for fixed values, and replacing revert strings with custom errors all reduce cost without changing behavior.

  • Pin the compiler version with a fixed pragma for production code.
  • Reuse audited libraries instead of reimplementing token standards.
  • Avoid unbounded loops over user-controlled arrays, which can exceed block gas limits.
  • Emit events for every state change that off-chain systems need to track.
  • Plan upgradeability deliberately, because proxies add power and risk.

Maintainability matters because contracts are read far more often than they are written. Clear NatSpec comments, small single-purpose functions and explicit invariants make audits faster and cheaper. Optimizations that save a few hundred gas but obscure the logic are rarely worth it, because every hour an auditor spends untangling clever code raises the chance that a real flaw goes unnoticed. Teams also track compiler releases, since new versions change defaults, add features such as transient storage and occasionally fix compiler bugs that affect specific code patterns.

Understanding it simply

Solidity is the language programmers use to write the rules of blockchain applications, such as how a token moves or how a loan is repaid. Once these rules are published on the blockchain, anyone can use them and nobody can quietly change them.

That permanence is both the strength and the danger. A normal app can be patched overnight, but a mistake in a deployed contract may stay there and be exploited. Careful testing and review matter more than speed, and every step the program takes costs a small fee.

Applied in practice

A small team builds a staking contract in Solidity that lets members lock a community token and earn rewards. They start from audited OpenZeppelin components for the token interface and access control, and they write the reward logic themselves.

During fuzz testing, the team finds that the withdraw function sends tokens before updating the stored balance, which would allow a reentrancy attack through a malicious token callback. They reorder the code to follow checks-effects-interactions and add a reentrancy guard. They also pack three configuration values into one storage slot, cutting the gas cost of each stake by roughly a fifth in their tests.

After an external audit with only minor findings, the contract goes live on a layer 2 network. The fixed ordering and guard prevent the flaw that testing exposed, and users pay low fees for routine staking.