Solidity Cheat Sheet
Contract structure
Every file starts with a license and a pragma; a contract is the unit of deployment.
| Syntax | Meaning |
|---|---|
// SPDX-License-Identifier: MIT | License comment the compiler expects on line 1 |
pragma solidity ^0.8.0; | Compiler version the file is written for |
contract Counter { ... } | Declare a contract (state + functions) |
constructor(uint start) { count = start; } | Runs once, at deployment |
import "./Token.sol"; | Import another file |
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | Import a library package |
interface IToken { function balanceOf(address a) external view returns (uint); } | Declare an interface (no bodies) |
library Math { function min(uint a, uint b) internal pure returns (uint) { ... } } | A library of reusable functions |
Value types
Integers have fixed sizes and no decimals; 0.8 reverts on overflow.
| Type | What it holds |
|---|---|
uint256 / uint | Unsigned integer, 0 to 2^256 - 1 (uint is uint256) |
uint8, uint16, ... uint128 | Smaller unsigned integers, in 8-bit steps |
int256 / int | Signed integer (negative allowed) |
bool | true or false |
address | 20-byte account or contract address |
address payable | Address that can receive Ether via transfer/send |
bytes32, bytes1... | Fixed-size byte arrays |
enum Status { Open, Closed } | Named set of constants, stored as uint8 |
1 ether, 1 gwei, 1 wei | Ether units: 1 ether = 10^18 wei |
1 days, 2 hours, 30 minutes | Time units, in seconds |
Reference types & data location
Arrays, strings, bytes, structs, and mappings live in storage, memory, or calldata.
| Syntax | Meaning |
|---|---|
string memory name | Dynamic UTF-8 string (a temporary copy) |
bytes memory data | Dynamic byte array |
uint[] public scores; | Dynamic array in storage |
uint[3] fixed; | Fixed-size array of 3 |
uint[] memory tmp = new uint[](5); | Allocate a memory array |
scores.push(42); | Append to a storage array |
scores.pop(); | Remove the last element |
scores.length | Number of elements |
storage | Persistent, on-chain, expensive to write |
memory | Temporary, lives for one call |
calldata | Read-only external function input, cheapest |
Mappings & structs
A mapping is a hash table with no length and no iteration; a struct groups fields.
| Syntax | Meaning |
|---|---|
mapping(address => uint) public balances; | Key-value store, every key exists (defaults to 0) |
balances[msg.sender] += 1; | Read/write by key |
mapping(address => mapping(address => uint)) allowance; | Nested mapping |
struct User { string name; uint age; bool active; } | Define a struct |
User memory u = User("Ada", 36, true); | Create a struct in memory |
User memory u = User({name: "Ada", age: 36, active: true}); | Named-field creation |
users[msg.sender] = u; | Store a struct in a mapping |
users[msg.sender].age = 37; | Update one field in storage |
delete users[msg.sender]; | Reset to default values |
Functions & visibility
Every function states who can call it and whether it reads or writes state.
| Syntax | Meaning |
|---|---|
function add(uint a, uint b) public pure returns (uint) { return a + b; } | A function with parameters and a return value |
public | Callable from anywhere (inside and outside) |
external | Callable only from outside the contract |
internal | This contract and contracts that inherit it |
private | This contract only |
view | Reads state, never writes it |
pure | Reads no state at all |
payable | Can receive Ether with the call |
returns (uint sum, bool ok) | Multiple named return values |
(uint s, bool ok) = f(); | Destructure multiple returns |
uint public count; | Public state variable gets an automatic getter count() |
Modifiers, constants & inheritance
Reuse checks with modifiers; fix values with constant and immutable.
| Syntax | Meaning |
|---|---|
modifier onlyOwner() { require(msg.sender == owner, "Not owner"); _; } | Define a modifier (_ = run the function body) |
function withdraw() public onlyOwner { ... } | Apply a modifier |
uint public constant MAX = 100; | Compile-time constant |
address public immutable owner; | Set once in the constructor, then fixed |
contract Token is ERC20, Ownable { ... } | Inherit from other contracts |
function f() public virtual { ... } | Allow overriding |
function f() public override { ... } | Override a parent function |
super.f(); | Call the parent's implementation |
abstract contract Base { function f() public virtual; } | Contract with unimplemented functions |
Control flow
The usual C-family statements; no switch, and loops cost gas per iteration.
| Syntax | Meaning |
|---|---|
if (x > 5) { ... } else if (x > 2) { ... } else { ... } | Conditional branches |
for (uint i = 0; i < n; i++) { ... } | Counted loop |
while (x < 10) { x++; } | Loop while a condition holds |
do { ... } while (cond); | Runs at least once |
break; / continue; | Leave the loop / skip to the next iteration |
x > 0 ? a : b | Ternary expression |
a / b | Integer division (drops the remainder) |
a % b | Remainder |
a ** 2 | Exponentiation |
unchecked { x++; } | Skip overflow checks (saves gas, use with care) |
Errors: require, revert, assert
A failed check undoes the whole transaction and refunds unused gas.
| Syntax | Meaning |
|---|---|
require(amount > 0, "Amount must be positive"); | Validate input or state; revert with a message |
revert("Not allowed"); | Abort unconditionally |
error Insufficient(uint available, uint requested); | Declare a custom error (cheaper than strings) |
revert Insufficient(balance, amount); | Revert with a custom error |
assert(total == a + b); | Check an invariant that must never fail |
try token.transfer(to, amt) returns (bool ok) { ... } catch { ... } | Handle a failing external call |
Events
Events write logs off-chain apps can subscribe to; they are not readable from contracts.
| Syntax | Meaning |
|---|---|
event Transfer(address indexed from, address indexed to, uint value); | Declare an event |
emit Transfer(msg.sender, to, amount); | Emit it |
indexed | Filterable parameter (up to 3 per event) |
event Log(string message); | Any ABI type can be logged |
Ether, addresses & global variables
Transaction context comes from msg, block, and tx.
| Syntax | Meaning |
|---|---|
msg.sender | Address that called this function |
msg.value | Wei sent with the call (needs payable) |
block.timestamp | Current block time (seconds since epoch) |
block.number | Current block height |
tx.origin | The externally owned account that started the tx (avoid for auth) |
address(this).balance | This contract's Ether balance |
payable(to).transfer(1 ether); | Send Ether, reverts on failure |
(bool ok, ) = to.call{value: amt}(""); | Low-level send, returns success flag |
receive() external payable {} | Runs on a plain Ether transfer |
fallback() external payable {} | Runs when no function matches |
keccak256(abi.encodePacked(a, b)) | Hash values |
abi.encode(x), abi.decode(data, (uint)) | Encode / decode ABI data |
Every piece of Solidity syntax you reach for, on one page. This Solidity cheat sheet is a quick reference for the smart contract language of Ethereum and every EVM chain - declaring a contract, choosing types, storing data in mappings and structs, writing functions with the right visibility and mutability, and guarding them with require, modifiers, and events.
The syntax here is Solidity 0.8, which checks arithmetic overflow by default and works with Remix, Hardhat, and Foundry. Copy what you need, or try it live in the Solidity playground - write a contract, compile it, and run it on an EVM in your browser.