$npx -y skills add Aboudjem/solidity-style-guide --skill skillApply the Aboudjem/solidity-style-guide rules to Solidity code — review, rewrite, or audit for naming, layout, formatting, NatSpec, custom errors, ERC-7201 storage, gas patterns, and Foundry test structure. Trigger when the user asks to "review Solidity style", "apply the style g
| 1 | # Solidity Style Guide — Claude Code Skill |
| 2 | |
| 3 | Use this skill whenever you are reviewing or writing Solidity, Foundry tests, or related configuration. It codifies the rules in [Aboudjem/solidity-style-guide](https://github.com/Aboudjem/solidity-style-guide) targeting **Solidity 0.8.34**. |
| 4 | |
| 5 | ## When to invoke |
| 6 | |
| 7 | Trigger automatically on: |
| 8 | |
| 9 | - `.sol` files in the workspace |
| 10 | - `foundry.toml`, `remappings.txt`, `.solhint.json` present |
| 11 | - User says: _review my contract_, _clean up this Solidity_, _apply the style guide_, _is this gas-optimal?_, _make this audit-ready_ |
| 12 | |
| 13 | ## Output contract |
| 14 | |
| 15 | 1. **Produce a checklist** of violations grouped by category (layout → naming → formatting → NatSpec → best practices → tests → gas → security). |
| 16 | 2. **Quote the offending snippet** with file path and line number. |
| 17 | 3. **Propose a minimal diff** that makes it compliant. Preserve behavior; style changes only unless asked. |
| 18 | 4. **Cite the rule** inline, e.g., `[§Best Practices > Using Custom Errors Over Require]`. |
| 19 | 5. **Stop before applying** unless the user asked for an auto-fix. |
| 20 | |
| 21 | ## Hard rules (block the review on violation) |
| 22 | |
| 23 | ### Files & layout |
| 24 | |
| 25 | - SPDX license identifier on every `.sol` file |
| 26 | - One contract / interface / library per file; filename matches the core type |
| 27 | - Top-level order: pragmas → imports → events → errors → interfaces → libraries → contracts |
| 28 | - Inside a contract: type declarations → state vars → events → errors → modifiers → functions |
| 29 | - Function order: `constructor` → `receive` → `fallback` → `external` → `public` → `internal` → `private` |
| 30 | - Within each visibility group, put `view` then `pure` last |
| 31 | |
| 32 | ### Imports |
| 33 | |
| 34 | - **Named imports only**: `import {X} from "./X.sol";` |
| 35 | - Sort by path length within groups; blank line between external and internal |
| 36 | - No wildcard imports |
| 37 | |
| 38 | ### Pragma |
| 39 | |
| 40 | - Applications: pin to a single version — `pragma solidity 0.8.34;` |
| 41 | - Libraries / mixins: open range — `pragma solidity ^0.8.20;` |
| 42 | - Never `^0.8.0 ^0.9.0` or other multi-constraint forms |
| 43 | |
| 44 | ### Types |
| 45 | |
| 46 | - Always explicit: `uint256`, `int256`, `bytes1` — never `uint`, `int`, `byte` |
| 47 | - `bool` booleans, not `uint` flags |
| 48 | - Prefer `bytes` over `string` when non-human-readable |
| 49 | |
| 50 | ### Naming |
| 51 | |
| 52 | | Element | Style | Notes | |
| 53 | | ----------------------------------------- | --------------------------- | ----------------------- | |
| 54 | | Contract / Library / Interface | `PascalCase` | Interfaces prefixed `I` | |
| 55 | | Struct / Event / Enum / custom Error | `PascalCase` | Events in past tense | |
| 56 | | Function / modifier / variable / argument | `camelCase` | | |
| 57 | | Public constant | `SNAKE_UPPER_CASE` | | |
| 58 | | Private / internal constant | `_SNAKE_UPPER_CASE` | Leading `_` | |
| 59 | | Non-external fn / state var | `_leadingUnderscore` | | |
| 60 | | Avoid | `l`, `O`, `I` single-letter | Visually ambiguous | |
| 61 | |
| 62 | ### Formatting |
| 63 | |
| 64 | - 4-space indent, spaces (no tabs) |
| 65 | - Max line length **120** chars |
| 66 | - Strings in double quotes |
| 67 | - One space around binary operators; no space inside parens / brackets |
| 68 | - `mapping(K => V)` — no space after `mapping` |
| 69 | - `uint[]` — no space before `[]` |
| 70 | - Braces on same line as declaration; `else` on the same line as the closing brace |
| 71 | - Long signature: each arg on its own line, closing `)` and `{` on their own lines |
| 72 | |
| 73 | ### Best practices |
| 74 | |
| 75 | - Prefer custom errors. Use `require(cond, CustomError(arg1, arg2))` when on Solidity ≥ 0.8.26 (via-ir) or ≥ 0.8.27 (legacy). Otherwise `if (!cond) revert CustomError(...);`. |
| 76 | - If a `require` string message is unavoidable, keep it under 32 bytes. |
| 77 | - `calldata` for read-only array / struct params on `external` functions. |
| 78 | - Cache `.length` before the loop header. |
| 79 | - Prefer **named returns** for functions with ≥ 2 return values. |
| 80 | - Prefer **named arguments** in calls, events, errors with ≥ 3 parameters. |
| 81 | - **Named parameters in mappings**: `mapping(address user => mapping(address asset => uint256 amount))`. |
| 82 | - Interact with external contracts through typed interfaces; if using `call`, use `abi.encodeWithSelector`. |
| 83 | - For upgradeable contracts, use **ERC-7201 namespaced storage** with `@custom:storage-location erc7201:<namespace>`. |
| 84 | - Events in past tense: `OwnerUpdated`, `FundsDeposited`. |
| 85 | - Avoid inline assembly unless there is no high-level alter |