# Solidity Cheat Sheet: 0.8.x Types, Functions and Errors

Source: https://srvscripts.com/guides/solidity-cheat-sheet/
Updated: 2026-10-09
Publisher: srvScripts (https://srvscripts.com/)

**Short answer:** Start every file with an SPDX licence line and `pragma solidity ^0.8.28;`. Use `uint256`, `address`, `mapping` and `struct` for state, `memory` or `calldata` for function arguments, and `external`, `public`, `internal` or `private` for visibility. Since 0.8.0, arithmetic reverts on overflow. Reject bad input with custom errors (`revert InsufficientBalance(bal, amount)`), log changes with `event`/`emit`, and send ether with `call{value: x}("")` after updating state.

The examples in this Solidity cheat sheet were compiled with solc 0.8.37 and tested with Foundry (forge 1.5.1) on Linux on 9 October 2026. They are teaching examples, not audited code.

## Compiler and file layout

| Command | What it does |
| --- | --- |
| solc --version | Show the compiler version |
| solc --abi --bin -o build/ Vault.sol | Write ABI and bytecode files for each contract |
| solc --optimize --optimize-runs 200 ... | Enable the optimiser; tune runs for deploy cost vs call cost |
| solc --via-ir ... | Compile through the Yul IR pipeline (often fixes “stack too deep”) |
| solc --evm-version cancun ... | Target an older EVM; the default in 0.8.31+ is osaka |
| solc --hashes Vault.sol | Function selectors, e.g. 2e1a7d4d: withdraw(uint256) |
| solc --standard-json < input.json | JSON in and out, as used by build tools |

For build servers and CI: download the static `solc` binary for the exact version from binaries.soliditylang.org (Ubuntu PPA packages were discontinued in 0.8.31) and pin that version, so every build produces the same bytecode. Most projects drive `solc` through Foundry or Hardhat.

```
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;      // 0.8.28+ needed for transient state variables

import {IERC20} from "./IERC20.sol";

contract Vault {
    // state variables, events, errors, modifiers, functions
}
```

## Types and state variables

| Type | Notes | Example |
| --- | --- | --- |
| uint256 / int256 | Default integer types; uint8 to uint256 in steps of 8 | uint256 total; |
| bool | true / false | bool public paused; |
| address / address payable | 20-byte account; only payable can receive ether via call | payable(msg.sender) |
| bytes32 | Fixed-size bytes; cheaper than string for hashes and IDs | bytes32 h = keccak256(data); |
| string / bytes | Dynamic data | string.concat(a, " ", b) |
| mapping(address => uint256) | Key-value store; every key exists with a zero default; not iterable | balances[user] += 1; |
| uint256[] / uint256[3] | Dynamic / fixed array; push(), pop(), length | depositors.push(msg.sender); |
| struct | Group fields; pack small types together to save storage slots | struct Account { uint128 balance; uint64 lastDeposit; } |
| enum | Named states | enum Status { Open, Paused } |
| constant | Fixed at compile time; no storage used | uint256 public constant MAX = 10 ether; |
| immutable | Set once in the constructor; stored in the bytecode | address public immutable owner; |
| transient | Transient storage: cleared at the end of each transaction (0.8.28+, value types only) | bool transient locked; |

Units and globals: `1 ether`, `1 gwei`, `1 days`, `msg.sender`, `msg.value`, `block.timestamp`, `block.number`, `address(this).balance`.

## Functions, visibility and modifiers

| Keyword | Meaning |
| --- | --- |
| external | Callable only from outside (or via this.f()); arguments can use calldata |
| public | Callable from anywhere; public state variables get a getter |
| internal | This contract and contracts that inherit from it |
| private | This contract only. Still readable on-chain by anyone |
| view / pure | Reads state / reads nothing; free when called off-chain |
| payable | Function can receive ether |
| virtual / override | Allow / perform overriding in a child contract |
| receive() external payable | Runs on plain ether transfers with empty calldata |
| fallback() external | Runs when no function matches |

```
modifier onlyOwner() {
    require(msg.sender == owner, NotOwner(msg.sender));   // custom error in require (0.8.27+)
    _;                                                    // the function body runs here
}

function setStatus(Status s) external onlyOwner {
    status = s;
}

function balanceOf(address who) external view returns (uint256) {
    return accounts[who].balance;
}
```

## Data locations: storage, memory and calldata

| Location | Lifetime and cost |
| --- | --- |
| storage | Persistent contract state; the most expensive to write |
| memory | Temporary copy for the duration of the call |
| calldata | Read-only function input; the cheapest choice for external arguments |
| Account storage acct = accounts[msg.sender]; | Reference: changes write to storage |
| Account memory acct = accounts[msg.sender]; | Copy: changes are lost when the function ends |

```
function hash(string calldata s) external pure returns (bytes32) {
    return keccak256(abi.encodePacked(s));
}

function joinNames(string memory a, string memory b) external pure returns (string memory) {
    return string.concat(a, " ", b);
}
```

## Errors, checks and arithmetic

| Syntax | Use it for |
| --- | --- |
| error InsufficientBalance(uint256 available, uint256 requested); | Declare a custom error (cheaper than revert strings) |
| if (x > bal) revert InsufficientBalance(bal, x); | Revert with typed data callers can decode |
| require(cond, "message") / require(cond, MyError()) | Input checks |
| assert(cond) | Internal invariants that should never fail |
| Checked arithmetic | Overflow and underflow revert with Panic(0x11) since 0.8.0 |
| unchecked { ++i; } | Skip the check when overflow is impossible; saves gas |
| try other.f() returns (uint v) { } catch Error(string memory r) { } catch (bytes memory d) { } | Handle a failing external call |

```
function sumTo(uint256 n) external pure returns (uint256 total) {
    for (uint256 i = 1; i  0 && msg.value  bal) revert InsufficientBalance(bal, amount);
    accounts[msg.sender].balance = uint128(bal - amount);             // effects
    (bool ok, ) = payable(msg.sender).call{value: amount}("");       // interactions
    if (!ok) revert TransferFailed();
    emit Withdrawn(msg.sender, amount);
}
```

| Rule | Why |
| --- | --- |
| Checks, effects, interactions | Update balances before calling out, so a re-entering call sees the new state |
| Use call{value: x}("") and check the result | transfer and send are deprecated since 0.8.31 (solc warns) and forward only 2300 gas |
| Never authorise with tx.origin | A malicious contract in the middle can pass the check; use msg.sender |
| Prefer pull over push payments | Let users withdraw instead of looping over recipients |
| Do not rely on block.timestamp for randomness | Block producers can influence it |
| Test reverts and attacks | Write tests that call your contract from a hostile contract |

## Inheritance, interfaces and libraries

```
interface IVault {
    function deposit() external payable;
    function withdraw(uint256 amount) external;
}

library MathLib {
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
}

abstract contract Owned {
    address public immutable owner;
    error NotOwner(address caller);
    constructor() { owner = msg.sender; }
}

contract Vault is IVault, Owned {
    using MathLib for uint256;            // x.min(100)
    function deposit() public payable override { /* ... */ }
    function withdraw(uint256 amount) external override { /* ... */ }
}
```

| Keyword | Meaning |
| --- | --- |
| contract B is A, C | Inheritance; list bases from most basic to most derived |
| abstract contract | Cannot be deployed on its own |
| interface | Function declarations only; all external |
| library + using L for T | Reusable functions called as methods on a type |
| super.f() | Call the next implementation in the inheritance order |

**Official documentation (checked 9 October 2026):** [Solidity 0.8.37 documentation](https://docs.soliditylang.org/en/v0.8.37/) · [Solidity: Cheatsheet](https://docs.soliditylang.org/en/v0.8.37/cheatsheet.html) · [Solidity: Types](https://docs.soliditylang.org/en/v0.8.37/types.html) · [Solidity: Expressions and Control Structures](https://docs.soliditylang.org/en/v0.8.37/control-structures.html) · [Solidity: Security Considerations](https://docs.soliditylang.org/en/v0.8.37/security-considerations.html) · [Solidity: Using the Compiler](https://docs.soliditylang.org/en/v0.8.37/using-the-compiler.html) · [Solidity 0.8.31 release announcement](https://www.soliditylang.org/blog/2025/12/03/solidity-0.8.31-release-announcement/) · [Solidity 0.8.37 release announcement](https://www.soliditylang.org/blog/2026/09/10/solidity-0.8.37-release-announcement/)

## Solidity Cheat Sheet at a glance

In short: A compact Solidity 0.8.x reference covering solc, types, data locations, functions, custom errors, events, inheritance and safe ether transfers.

Solidity Cheat Sheet: what this guide covers.

**Related:** [JavaScript Cheat Sheet: Modern Syntax for Browser and Node](https://srvscripts.com/guides/javascript-cheat-sheet/) · [TypeScript Cheat Sheet: Types, Generics and tsconfig](https://srvscripts.com/guides/typescript-cheat-sheet/) · [Hash Generator (MD5, SHA-1, SHA-256, SHA-512)](https://srvscripts.com/tools/hash-generator/).
