title | author | version |
---|---|---|
Solidity Style Guide DAppSpec |
Et. Al. |
2022.07.14 |
-
1.1 Alias: When you access a primitive type you should work directly on its value.
uint
int
-
Always perfer the explicit type
-
1.2 Explicit: When you access a primitive type you should work on its explicit value.
uint256
int256
-
/**
* @param explicitTypes
* @summary enforces `explicitTypes` to be `true`,
* @example Example: unit = unit256
*/
explicitTypes: 'always',
In some codebases, you’ll also see attempts to produce large, visually salient geometries as separators, like:
/*--------------------------------------------------------------------------*/
Please don’t do this in new code.
Normal conventions should be legible. Use more deeply qualified positions if your code is hard to navigate.
Example1
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
Layout contract elements in the following order 2
Contracts
-
Pragma statements
-
Import statements
-
Interfaces
-
Libraries
-
Contracts
Inside each contract, library or interface, use the following order:
Note
constructor SHOULD be specified to be above modifiers
contract, library or interface
-
Type declarations
-
State variables
-
Events
-
Modifiers
-
Functions
For constructor functions on inherited contracts whose bases require arguments, it is recommended to drop the base constructors onto new lines in the same manner as modifiers if the function declaration is long or hard to read.
contract A is B, C, D {
uint x;
constructor(uint param1, uint param2, uint param3, uint param4, uint param5)
B(param1)
C(param2, param3)
D(param4) {
x = param5;
}
}
contract A is B, C, D {
uint x;
constructor(uint param1, uint param2, uint param3, uint param4, uint param5)
B(param1)
C(param2, param3)
D(param4)
{
// do something with param5
x = param5;
}
}
------ fail-constructor.sol
++++++ pass-constructor.sol
@@ -1,10 +1,12 @@
contract A is B, C, D {
uint x;
constructor(uint param1, uint param2, uint param3, uint param4, uint param5)
B(param1)
C(param2, param3)
! D(param4)
! {
! // do something with param5
x = param5;
}
}
The modifier order for a function should be:
-
Visibility
-
Mutability
-
Virtual
-
Override
-
Custom modifiers
// fail-function-order.sol
function balance(uint256 from) public override view returns (uint256) {
return balanceOf[from];
}
function shutdown() onlyOwner public {
selfdestruct(owner);
}
// pass-function-order.sol
function balance(uint256 from) public view override returns (uint256) {
return balanceOf[from];
}
function shutdown() public onlyOwner {
selfdestruct(owner);
}
------ fail-function-order.sol
++++++ pass-function-order.sol
@@ -1,7 +1,7 @@
-function balance(uint256 from) public override view returns (uint256) {
+function balance(uint256 from) public view override returns (uint256) {
return balanceOf[from];
}
-function shutdown() onlyOwner public {
+function shutdown() public onlyOwner {
selfdestruct(owner);
}
Don’t include a whitespace in the receive and fallback functions:
Source | Output |
---|---|
// Correct
+ receive() external payable {
//
}
// Incorrect
- fallback () external {
//
}
|