https://github.com/clemlak/solidity-style-guide
https://github.com/clemlak/solidity-style-guide
Last synced: 5 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/clemlak/solidity-style-guide
- Owner: clemlak
- License: gpl-3.0
- Created: 2024-12-12T11:56:41.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-01-14T07:41:39.000Z (over 1 year ago)
- Last Synced: 2025-02-07T22:49:49.704Z (over 1 year ago)
- Size: 25.4 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Solidity Style Guide
## Introduction
This is my personal attempt to write a cool style guide for [Solidity](https://soliditylang.org/), all the recommendations that you will read in this guide are purely personal and opinionated, have fun reading!
## Definitions
### Prefer "free definitions" when possible
Variables, functions and events can be defined outside of a `contract` or a `library`, this makes them easily accessible and reusable in other places.
### Follow naming conventions
Naming conventions for variables where defined to quickly understand what they are used for.
```solidity
// Constants should be in uppercase
uint256 constant MAX_SUPPLY = 1e25;
// Variables should be in camelCase
uint256 totalSupply = 1e24;
// Functions should be in camelCase
function totalSupply() public view returns (uint256) {
return totalSupply;
}
// Events should be in PascalCase
event Transfer(address indexed from, address indexed to, uint256 value);
// Structs should be in PascalCase
struct Token {
uint256 totalSupply;
}
// Enums should be in PascalCase
enum UserRole { None, Sender, Recipient }
// Modifiers should be in camelCase
modifier onlyOwner() {
// ...
_;
}
// Errors should be in PascalCase
error OnlyOwner();
// Interfaces should be in PascalCase
interface IRouter {
// ...
}
// Libraries should be in PascalCase
library MathLibrary {
// ...
}
// Contracts should be in PascalCase
contract Token {
// ...
}
```
## Imports
### Always use named imports
Using named imports is cleaner and helps quickly figuring out where imports come from.
```solidity
// This is bad
import "Foo.sol";
// This is good
import { IFoo } from "Fool.sol";
```
### Highlight module imports using a special character
Module imports can be highlighted using a special character, this makes it easier to distinguish them from other imports.
```solidity
import { IFoo } from "@foo/IFool.sol";
```
### Use absolute paths for imports
Relative paths require some brain power to figure out where the file is located, using absolute paths is cleaner and easier to understand.
```solidity
// This is bad
import { IFoo } from "../../interfaces/IFoo.sol";
// This is good
import { IFoo } from "src/interfaces/IFoo.sol";
```
### Order imports
Imports should be ordered in the following way:
1. Modules or libraries (external packages)
2. Local files
```solidity
import { IFoo } from "@foo/IFoo.sol";
import { IBar } from "src/interfaces/IBar.sol";
```
## Errors
### Use custom revert errors with require
`require` now accepts custom revert errors, this is a great improvement as strings are expensive to store onchain.
```solidity
// This is bad
require(msg.sender == owner, "Only owner can call this function");
// This is good
require(msg.sender == owner, OnlyOwner());
```
### Use explicit error names
Error names should be clear enough to explain what went wrong.
```solidity
// This is bad
error WrongAddress();
// This is good
error OnlyOwner();
```
### Use error parameters to provide details
Errors might be reused multiple times in the same function, using parameters will help understand what went wrong.
```solidity
// Let's say we have users with different roles
enum UserRole { None, Sender, Recipient }
// And we revert if the user has the wrong role
error WrongUserRole(address user, UserRole expected, UserRole actual);
// This function reuses the same error twice, providing details helps understand where the error comes from
function transfer(address from, address to) public {
require(getRole[from] == UserRole.Sender, WrongUserRole(from, UserRole.Sender, getRole[from]));
require(getRole[to] == UserRole.Recipient, WrongUserRole(to, UserRole.Recipient, getRole[to]));
}
```
## Comments
### Use NatSpec
Use `///` for single line comments, and `/** ... */` for multi-line comments.
```solidity
/// @notice This is a single line comment
/**
* @notice This is a multi-line comment, you can write
* as much as you want here.
*/
```