Solidity Cheatsheet
Variables and Visibility
Use this Solidity reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Variable Kinds
| Kind | Location | Persists? | Declared where |
|---|---|---|---|
| State variable | contract storage | yes (on-chain) | top level of contract |
| Local variable | memory / stack | no (per call) | inside function body |
| Global / built-in | EVM context | n/a | anywhere |
State Variables
contract Vault { // Basic declarations uint256 public totalSupply; // auto-getter address private owner; bool internal paused; // Constant (compile-time, no storage slot) uint256 public constant MAX_SUPPLY = 1_000_000 * 1e18; // Immutable (set once in constructor, stored in bytecode) address public immutable token; constructor(address _token) { token = _token; // only assignment allowed here owner = msg.sender; } }
Visibility Specifiers
| Specifier | External calls | Derived contracts | Same contract |
|---|---|---|---|
public | yes (auto-getter for state vars) | yes | yes |
external | yes | no (must use this.f()) | no |
internal | no | yes | yes |
private | no | no | yes |
privatedoes not hide data. All storage is readable on-chain viaeth_getStorageAt. It only prevents Solidity-level access from other contracts.
contract Base { uint256 public a = 1; // external + internal uint256 internal b = 2; // internal only uint256 private c = 3; // this contract only function getC() external view returns (uint256) { return c; } } contract Child is Base { function getB() external view returns (uint256) { return b; } // OK // function getC() ... { return c; } // compile error }
constant vs immutable
// constant — value known at compile time; no storage, no SLOAD uint256 public constant FEE_BPS = 30; string public constant NAME = "MyToken"; bytes32 public constant ROLE = keccak256("ADMIN_ROLE"); // immutable — set in constructor; stored in code (not storage) // cheaper reads than storage, more flexible than constant address public immutable factory; uint256 public immutable deployBlock; constructor(address _factory) { factory = _factory; deployBlock = block.number; } // Immutables cannot be read inside the constructor before assignment
Data Locations
Every reference-type variable (array, bytes, string, struct) must declare a location.
| Location | Cost | Use case |
|---|---|---|
storage | most expensive (SLOAD/SSTORE) | state variables |
memory | cheap (RAM per call) | local variables, return values |
calldata | cheapest (read-only) | external function parameters |
transient (0.8.24) | medium (EIP-1153, cleared after tx) | reentrancy locks, temp state |
function process( uint256[] calldata ids, // cheapest — read-only, no copy string memory name // copied into memory ) external returns (uint256[] memory result) { result = new uint256[](ids.length); // memory array uint256[] storage stored = items; // pointer to storage for (uint i; i < ids.length; ++i) { result[i] = stored[ids[i]]; } }
Assigning a
storagepointer to a local variable gives you a reference — mutations write through to storage.
Global Variables and Context
Block
block.chainid // uint256 — EIP-155 chain ID block.coinbase // address payable — current validator block.difficulty // uint256 — deprecated post-merge; use block.prevrandao block.prevrandao // uint256 — beacon chain randomness (EIP-4399, 0.8.18+) block.gaslimit // uint256 block.number // uint256 — current block number block.timestamp // uint256 — seconds since unix epoch (±15 s accuracy) block.basefee // uint256 — base fee in wei (EIP-1559, 0.8.7+) block.blobbasefee // uint256 — EIP-4844 blob base fee (0.8.24+)
Transaction and Message
msg.sender // address — immediate caller (EOA or contract) msg.value // uint256 — wei sent with this call msg.data // bytes calldata — full calldata msg.sig // bytes4 — first 4 bytes of calldata (function selector) tx.origin // address — original EOA that started the transaction tx.gasprice // uint256 — gas price in wei gasleft() // uint256 — remaining gas
Do not use
tx.originfor authorization — it is vulnerable to phishing via malicious contracts.
Cryptography and Math
keccak256(bytes memory input) returns (bytes32) sha256(bytes memory input) returns (bytes32) ripemd160(bytes memory input) returns (bytes20) ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address) addmod(uint x, uint y, uint k) returns (uint) // (x + y) % k, no overflow mulmod(uint x, uint y, uint k) returns (uint) // (x * y) % k, arbitrary precision
Address and Contract Utilities
address(this) // this contract's address address(this).balance // wei balance selfdestruct(payable(addr)) // DEPRECATED — send ether + destroy (EIP-6049) // Cancun: no longer destroys storage/code
Type Information
type(uint256).min type(uint256).max type(int8).min // -128 type(MyContract).creationCode // bytes type(MyContract).runtimeCode // bytes type(IMyInterface).interfaceId // bytes4 — EIP-165
Transient Storage (0.8.24 / EIP-1153)
// Declared with `transient` keyword — cleared at end of transaction uint256 transient private _entered; modifier nonReentrant() { require(_entered == 0, "reentrant"); _entered = 1; _; _entered = 0; // optional — auto-cleared anyway after tx }
Shadowing and Scope Gotchas
uint256 x = 10; // state variable function foo() public { uint256 x = 20; // local — shadows state var (compiler warning since 0.6) // Use `this` or rename to avoid confusion } // Variable declarations are block-scoped (0.5+) for (uint i; i < 10; ++i) { uint256 val = i * 2; // val is scoped to loop body } // val is not accessible here