# Manual Review Checklist — Solidity / EVM Walk this for **every** contract that moves value. Each item: what to look for → how to confirm (Foundry test / Slither detector) → fix. Tools catch the known patterns; this catches the logic bugs they can't. ## 1. Reentrancy (SWC-107) - [ ] External call (`call`, `transfer`, ERC-777 hooks, ERC-721 `onERC...Received`, arbitrary token) **before** state updates? - [ ] Cross-function / read-only reentrancy: a view used by another protocol mid-call? - **Confirm:** Slither `reentrancy-eth`/`reentrancy-no-eth`; write an attacker contract test that re-enters in its `receive()`. - **Fix:** Checks-Effects-Interactions order; `nonReentrant` (OpenZeppelin `ReentrancyGuard`); pull-over-push payments. ("OZ" = OpenZeppelin throughout.) ## 2. Access control (SWC-105/106/115) - [ ] Every state-changing/admin function gated (`onlyOwner`, roles, custom modifier)? - [ ] `initialize()` on upgradeable contracts protected against re-init and front-running? - [ ] No `tx.origin` for auth (phishable) — use `msg.sender`. - [ ] `selfdestruct` / `delegatecall` reachable only by trusted roles? - **Confirm:** a `test_RevertWhen_*` with `vm.prank(attacker)` + `vm.expectRevert` for each guard. - **Fix:** OZ `Ownable2Step` / `AccessControl`; `initializer` modifier; remove `tx.origin`. ## 3. Oracle / price manipulation (DeFi #1 exploit class) - [ ] Price from spot `getReserves()` / a single AMM pool? (flash-loan manipulable) - [ ] Using Chainlink: checked `updatedAt` staleness, `answeredInRound`, min/max bounds, L2 sequencer uptime? - **Confirm:** fork test that manipulates the pool within one tx and asserts your protocol stays solvent. - **Fix:** TWAP / Chainlink with staleness+deviation checks; never trust spot for pricing. ## 4. Arithmetic & rounding (SWC-101) - [ ] Solidity ^0.8 (built-in checked math) — and any `unchecked{}` block justified? - [ ] Division before multiplication (precision loss)? Rounding always in protocol's favor? - [ ] Share-inflation / first-depositor attack on ERC-4626-style vaults? - **Confirm:** `testFuzz_*` over amounts; invariant `assertGe(assets, shares-implied)`. - **Fix:** mulDiv (OZ `Math.mulDiv`); virtual shares/offset for vaults; explicit rounding direction. ## 5. Unchecked external calls / return values (SWC-104) - [ ] Return value of low-level `call`/`send` and ERC-20 `transfer`/`transferFrom` checked? - [ ] Non-standard ERC-20s (no return, fee-on-transfer, rebasing) handled? - **Confirm:** Slither `unchecked-transfer`, `unchecked-lowlevel`. - **Fix:** OZ `SafeERC20`; measure balance delta for fee-on-transfer; require success. ## 6. delegatecall / proxy storage (SWC-112) - [ ] Storage layout identical across implementation upgrades (no reordered/removed vars)? - [ ] No `delegatecall` to user-supplied address; implementation can't be re-initialized/self-destructed? - **Confirm:** Slither `controlled-delegatecall`, `unprotected-upgrade`; storage-layout diff between versions. - **Fix:** OZ `UUPS`/`Transparent` proxies + storage gaps; `_disableInitializers()` in constructor. ## 7. Front-running / MEV / ordering (SWC-114) - [ ] Approve race (ERC-20 `approve` from non-zero to non-zero)? - [ ] Slippage / deadline params on swaps and mints? Commit-reveal where needed? - **Fix:** `increaseAllowance`/`permit`; enforce `minOut` + `deadline`; commit-reveal for sensitive ordering. ## 8. Randomness (SWC-120) - [ ] Any `block.timestamp`/`blockhash`/`prevrandao` used as randomness for value? - **Fix:** Chainlink VRF; never on-chain pseudo-randomness for payouts. ## 9. Denial of service (SWC-113/128) - [ ] Unbounded loops over user-growable arrays? Push payments that can revert and brick the contract? - [ ] Single external dependency whose revert blocks all users? - **Fix:** pull payments; bounded iteration / pagination; isolate failures. ## 10. Token / standard pitfalls - [ ] ERC-20: decimals assumptions, fee-on-transfer, rebasing, missing return. - [ ] ERC-721/1155: safe-transfer reentrancy hooks; approval scope. - [ ] Permit (EIP-2612): replay, deadline, signature malleability. ## 11. General hygiene - [ ] `pragma` pinned (`pragma solidity 0.8.26;` not `^`)? Latest stable solc? - [ ] Events emitted for every state-changing action (off-chain monitoring)? - [ ] No leftover `console.log` / test backdoors / hardcoded addresses? - [ ] Pausability + emergency withdraw for value-holding contracts? - [ ] Invariants written for every conservation law (total supply, solvency, accounting)? ## Severity triage (impact × likelihood) - **Critical/High** → direct loss/lock of funds, unauthorized mint/withdraw, broken access control. **Blocks deploy.** - **Medium** → loss under specific conditions, griefing, precision drift. - **Low/Info** → best-practice, gas, style. Cross-check real-world findings on **Solodit** (https://solodit.xyz/) for the contract type you're shipping (vault, AMM, staking, bridge, governance).