Solidity Cheatsheet
Basics
Use this Solidity reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
How to Use This Solidity Cheatsheet
Use this as a syntax reference while you learn Solidity as a programming language for smart contracts. If you already know JavaScript or TypeScript, the surface syntax may feel familiar, but the important differences are storage, gas, visibility, and security. For a broader software engineering foundation, pair this reference with Hack University's JavaScript or TypeScript language courses before building production smart-contract tooling.
File Structure
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "./MyLibrary.sol"; contract MyContract { // state variables, events, modifiers, functions }
- SPDX comment is mandatory (or you get a compiler warning). Use
UNLICENSEDfor proprietary code. pragma soliditypins the compiler version.^0.8.24means>=0.8.24 <0.9.0.- Import paths: bare specifiers resolve via remappings (
remappings.txt/foundry.toml); relative paths resolve from the file's directory.
Contract Declaration
// Plain contract contract Token { } // Abstract contract (has unimplemented functions) abstract contract Base { function transfer(address to, uint amount) external virtual; } // Interface (all external, no state, no constructor) interface IERC20 { function totalSupply() external view returns (uint256); } // Library (stateless helpers, no ether, no storage) library Math { function max(uint a, uint b) internal pure returns (uint) { return a >= b ? a : b; } }
Pragma Directives
pragma solidity ^0.8.24; // caret range pragma solidity >=0.8.0 <0.9.0; // explicit range pragma solidity 0.8.24; // exact version (rarely used) pragma abicoder v2; // default since 0.8.0; enables complex types in ABI pragma experimental SMTChecker; // static analysis (dev only)
Imports
// Named import (preferred — explicit, avoids namespace pollution) import { ERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; // Alias import import { SafeERC20 as S } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; // Wildcard (avoid — imports everything into scope) import * as OZ from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; // Plain import (imports all top-level symbols — avoid) import "@openzeppelin/contracts/access/Ownable.sol";
Contract Size and Deployment
// EIP-170: max 24 576 bytes of deployed bytecode. // Use libraries, proxies, or split contracts if you exceed the limit. // Check size during tests (Foundry): // assertLt(address(myContract).code.length, 24_576);
Global Constants and Units
// Ether units 1 wei == 1 1 gwei == 1e9 1 ether == 1e18 // Time units 1 seconds == 1 1 minutes == 60 1 hours == 3600 1 days == 86400 1 weeks == 604800 // Usage uint256 public constant LOCK_PERIOD = 30 days; uint256 public fee = 0.01 ether;
ABI Encoding Utilities
bytes memory encoded = abi.encode(address(this), uint256(42)); bytes memory packed = abi.encodePacked(msg.sender, block.timestamp); // no padding bytes4 selector = abi.encodeWithSelector(IERC20.transfer.selector, to, amount); bytes memory callData = abi.encodeWithSignature("transfer(address,uint256)", to, amount); // Decode (address a, uint256 n) = abi.decode(encoded, (address, uint256));
abi.encodePackedis not collision-resistant for dynamic types — do not use it as a hash key with multiple variable-length args. Preferabi.encodeinsidekeccak256.
Version-Specific Features (0.8.x)
| Feature | Added in |
|---|---|
| Built-in overflow/underflow checks | 0.8.0 |
immutable keyword | 0.6.5 |
Custom errors (error Foo()) | 0.8.4 |
try/catch | 0.6.0 |
unchecked { } block | 0.8.0 |
using A for B global | 0.8.13 |
User-defined value types (type Foo is uint256) | 0.8.8 |
bytes.concat / string.concat | 0.8.12 |
push() returns reference | 0.6.0 |
Transient storage (tstore/tload) | 0.8.24 (EIP-1153) |
Comments