Code Style
Crane enforces a strict set of conventions to keep large Diamond codebases consistent and auditable.
Section Headers
Major sections use 78-character blocks:
/* -------------------------------------------------------------------------- */
/* Section Name */
/* -------------------------------------------------------------------------- */
Subsections use the shorter form:
/* ------ Feature Name ------ */
Imports
Group in this order:
- External libraries (
@openzeppelin,@solady). - Crane interfaces (
@crane/contracts/interfaces/...). - Crane contracts (
@crane/contracts/...). - Test utilities (only in test files).
Use the defined remappings:
@crane/@solady/@openzeppelin/forge-std/
Function Order
Within each contract or library:
- Constructor
- Receive / Fallback
- External
- Public
- Internal
- Private
Naming
| Element | Convention | Example |
|---|---|---|
| Storage access | _layoutStruct() | _layoutStruct(), _layoutStruct(bytes32) |
| Initialization | _initialize(...) | _initialize(address owner_) |
| Internal state functions | _functionName(...) | _isOperator(address) |
| Guard functions | _onlyXxx(...) | _onlyOperator() |
| Modifiers | onlyXxx | onlyOperator |
| Storage parameter | layoutStruct | Storage storage layoutStruct |
| All parameters | trailing underscore | owner_, amount_ |
Parameters always end with _ to prevent shadowing of state or storage variables.
Storage Slot Names
Hierarchical and deterministic:
- Crane internals:
crane.{domain}.{feature} - ERC standards:
eip.erc.{number} - Protocols:
protocols.{category}.{name}.{version}.{concern}
Example:
bytes32 internal constant STORAGE_SLOT =
keccak256(abi.encode("crane.access.operable"));
Compilation Rules
viaIRandvia_irmust remain disabled.- Stack-too-deep errors are resolved by grouping parameters and intermediate values into
structtypes passed bymemoryorcalldata. - Optimizer runs are set to 1 to respect contract size limits under the Diamond pattern.
Reference
See contracts/StyleGuide.sol for the canonical template.