Code Layout
Code layout refers to the way that your solidity code is structured and formatted. Proper code layout helps to make your code more readable, maintainable, and easy to understand. With respect to solidity code, here are some guidelines to maintain an ideal code layout throughout your code.
1. Indentation
Using 4 spaces for indentation instead of using a tab is considered a good practice. Refer to the right and wrong snippets that are written ahead to understand better.
pragma solidity >=0.4.0 <0.9.0;
// Right Practice for indentation
contract A {
// …
}
contract B {
// …
}
contract C {
// …
}
pragma solidity >=0.4.0 <0.9.0;
// wrong practice for indentation
contract A {
// …
}
contract B {
// …
}
contract C {
// …
}
2. Limit Line Length to 120 Characters
If a line of code exceeds this limit, consider breaking it up into multiple lines. This makes it easier to read the code even on smaller screens. Refer to the right and wrong snippets written ahead to understand better.
// right approach
thisFunctionCallIsReallyLong(
tempArgument1,
tempArgument2,
tempArgument3
);
// Wrong approaches
thisFunctionCallIsReallyLong(tempArgument1,
tempArgument2,
tempArgument3
);
thisFunctionCallIsReallyLong(tempArgument1,
tempArgument2,
tempArgument3
);
thisFunctionCallIsReallyLong(
tempArgument1, tempArgument2,
tempArgument3
);
3. Curly Braces
Use curly braces to enclose the bodies of functions, control structures, and contracts. Place the opening curly brace on the same line as the declaration. Place the closing curly brace on a new line. Refer to the right and wrong snippets written ahead to understand better.
pragma solidity >=0.4.0 <0.9.0;
// right practice
import “./Owned.sol”;
contract A {
// …
}
pragma solidity >=0.4.0 <0.9.0;
// wrong practice
import “./Owned.sol”;
contract A
{
// …
}
4. Blank Line Between Functions
Add a blank line between the end of a function and the beginning of the next function. Refer to the right and wrong snippets written ahead to understand better.
pragma solidity >=0.6.0 <0.9.0;
// right practice
abstract contract A {
function spam() public virtual pure;
function ham() public virtual pure;
}
contract B is A {
function spam() public pure override {
// …
}
function ham() public pure override {
// …
}
}
pragma solidity >=0.6.0 <0.9.0;
// wrong practice
abstract contract A {
function spam() virtual pure public;
function ham() public virtual pure;
}
contract B is A {
function spam() public pure override {
// …
}
function ham() public pure override {
// …
}
}
5. Blank Line Between Different Blocks of Code
Add a blank line between different blocks of code within a function (e.g. between variable declarations and function calls). Refer to the right and wrong snippets written ahead to understand better.
// right practice
uint256 public jobfirst;
doSomething();
// wrong practice
uint256 public jobfirst;
doSomething();
6. Single Space Between Operators and Operands
Never add spaces while declaration involving special characters like (“[]”) etc. Add single spaces between operators and operands. Refer to the right and wrong snippets written ahead to understand better.
// right practice
unit[] a;
a = 7;
a = 100 / 10;
a += 3 + 4;
a |= c && d;
// wrong practice
unit [] a;
a=7;
a = 100/10;
a += 3+4;
a |= c&&d;
7. No Space Between Reserved Keywords
While using reserved keywords never add spaces in between. Refer to the right and wrong snippets written ahead to understand better.
// right practice
mapping(uint => uint) map;
mapping(address => bool) registeredAddresses;
mapping(uint => mapping(uint => s)) data;
// wrong practice
mapping (uint => uint) map;
mapping( address => bool ) registeredAddresses;
mapping(uint => mapping (uint => s)) data;
8. Imports
Imports should be sorted in alphabetical order. The same import should not be repeated. Use the import “./filename”; syntax for external contract dependencies.
// Good import "./filename1"; import "./filename2"; import "./filename3";
// Bad import "./filename1"; import "./filename1"; import "./filename3";
9. Order of Functions
Functions should be ordered in the following manner:
- Constructor.
- Constant functions.
- Public state-modifying functions.
- Internal state-modifying functions.
- Private state-modifying functions.
// Good
contract Example {
constructor() public { … }
function constantFunc1() public constant returns (…) { … }
function constantFunc2() public constant returns (…) { … }
function publicFunc1() public { … }
function publicFunc2() public { … }
function internalFunc1() internal { … }
function internalFunc2() internal { … }
function privateFunc1() private { … }
function privateFunc2() private { … }
}
// Bad
contract Example {
function internalFunc2() internal { … }
function privateFunc1() private { … }
constructor() public { … }
function constantFunc1() public constant returns (…) { … }
function publicFunc1() public { … }
function internalFunc1() internal { … }
function constantFunc2() public constant returns (…) { … }
function publicFunc2() public { … }
function privateFunc2() private { … }
}
10. Whitespace in Expressions
Use whitespace to increase readability and separate different elements in an expression. Put spaces around binary and ternary operators (e.g. +, -, ? :).
// Good
uint x = (a + b) * c;
uint y = (a > b) ? a : b;
// Bad
uint x=(a+b)*c;
uint y=(a>b)?a:b;
11. Function Declaration
Declare functions using the keyword function, followed by the function name, a list of parameters in parentheses (), and the function body in curly braces {}. Avoid declaring functions with the same name, even if they have different parameters, as this can cause confusion.
// Good
function add(uint a, uint b) public returns (uint) {
return a + b;
}
// Bad
function add(uint a, uint b) {
return a + b;
}
function add(uint a, uint b) public returns (uint) {
return a + b;
}
12. Variable Declarations
Declare variables , followed by the variable name and it’s type. Declare variables as close to their usage as possible, to increase readability. Initialize variables with a default value at declaration if possible.
// Good
function example() public {
uint a = 1;
uint b = 2;
uint c = a + b;
}
// Bad
function example() public {
uint a;
a = 1;
uint b = 2;
uint c = a + b;
}
13. Names to Avoid
Avoid using keywords (e.g. contract, function, etc.) as names for variables, functions, or contracts. Avoid using single-letter names, except for loop indices.
// Good
function addNumbers(uint a, uint b) public returns (uint) { … }
for (uint i = 0; i < 10; i++) { … }
// Bad
function contract(uint a, uint b) public returns (uint) { … }
for (uint x = 0; x < 10; x++) { … }
14. Contracts and Library Names
Name contracts and libraries in a descriptive manner that accurately reflects their purpose. Avoid naming contracts and libraries after their dependencies.
// Good
contract Token { … }
library Math { … }
// Bad
contract ERC20 { … }
library TokenLibrary { … }
Solidity – Style Guide
Solidity is a computer programming language used to create Ethereum smart contracts. These contracts self-execute. The code and the agreements contained therein are enforced by the blockchain network. Solidity is a high-level language, meaning that it is designed to be human-readable and easy to write. It is based on the JavaScript programming language and has a syntax similar to C++. Solidity is a statically-typed language, meaning that variables have a fixed type that must be declared when they are created. It also supports complex data types such as arrays and structs (collections of related variables).
One of the main benefits of Solidity is that it allows developers to build decentralized applications (DApps) on the Ethereum platform. These DApps can be used for a wide range of applications, including supply chain management, voting systems, and financial applications.
In this style guide, we will cover several elements starting with code layout till NatSpec declaration in code, followed by an example for better understanding.