Coding Style
To ensure uniformity across different teams and projects, we follow a specific coding style for Solidity. We use solhint-community for linting Solidity code.
If a partner requests it, we will use the style they prefer.
Below are the basic rules applied to all of our Solidity projects:
Reference: https://github.com/defi-wonderland/solidity-foundry-boilerplate/blob/main/.solhint.json
{
"extends": "solhint:recommended",
"rules": {
"compiler-version": ["warn"],
"quotes": "off",
"func-visibility": ["warn", { "ignoreConstructors": true }],
"no-inline-assembly": "off",
"no-empty-blocks": "off",
"private-vars-leading-underscore": ["warn", { "strict": false }],
"ordering": "warn",
"avoid-low-level-calls": "off",
"named-parameters-mapping": "warn"
}
}
Additional Principles
In addition to Solhint rules, Wonderland employs several additional principles to maintain clean, readable, and maintainable code.
Code Organization
Always separate interfaces from contracts.
Import Syntax:
Always use named imports, to avoid inadvertedly bringing into scope all names defined in a package :
✅ Do:
import {IERC20, ERC20} from '@libraries/ERC20.sol';
❌ Don’t:
import '@libraries/ERC20.sol';
- Minimize imports by grouping related items from a single file.
- Use remappings for clarity and maintainability instead of relative paths.
✅ Do:
import {IERC20, ERC20} from '@libraries/ERC20.sol';
❌ Don’t:
// No remappings, not grouped imports
import {IERC20} from '../../@libraries/ERC20.sol';
import {ERC20} from '../../@libraries/ERC20.sol';
Import Order:
- External Libraries
- Internal Libraries
- Local Interfaces
- Local Contracts
Naming Conventions
Variable Naming
State Variables
- Immutable and Constant Variables: Use
UPPERCASE_SNAKE_CASE
. - Public and External Variables: Use
camelCase
. - Private and Internal Variables: Use
_camelCase
, prefixed with an underscore_
.
Local Variables
- Use
_camelCase
, starting with an underscore_
.
Function Arguments and Return Values
- Function arguments and return value names should use
_camelCase
and always start with an underscore_
.
Interface Naming:
- Interfaces must always start with the letter
I
(e.g.,IUserRegistry
).
Events
- Naming: Events should always be named in the past tense.
- Definition: Always define events in the contract interface.
- Standard: Always emit events when storage or state is changed.
Errors
- Naming: Errors should be prefixed with the contract name and use
CapWords
style. - Definition: Errors must be defined in interfaces whenever possible.
Structs & Enums
- Naming: Structs and Enums should be named using the
CapWords
style - Definition: Always define Structs and Enums in the interface.