This guide is based on the Solidity style guide that can be found here: https://github.com/ethereum/solidity/blob/v0.5.1/docs/style-guide.rst. It mostly follows the guide line but with slight changes and more specific restrictions.
This guide is intended to provide coding conventions for writing solidity code. This guide should be thought of as an evolving document that will change over time as useful conventions are found and old conventions are rendered obsolete.
Use 2 spaces per indentation level.
Spaces are the preferred indentation method.
Mixing tabs and spaces must be avoided.
Each smart contract should be in its own file.
Maximum line length is 100 characters.
Yes
thisFunctionCallIsReallyLong(
longArgument1,
longArgument2,
longArgument3
);
shortFunctionCall(arg1);
No
thisFunctionCallIsReallyLong(longArgument1,
longArgument2,
longArgument3
);
thisFunctionCallIsReallyLong(longArgument1,
longArgument2,
longArgument3
);
thisFunctionCallIsReallyLong(
longArgument1, longArgument2,
longArgument3
);
thisFunctionCallIsReallyLong(
longArgument1,
longArgument2,
longArgument3
);
thisFunctionCallIsReallyLong(
longArgument1,
longArgument2,
longArgument3);
Yes
thisIsALongNestedMapping[being][set][to_some_value] = someFunction(
argument1,
argument2,
argument3,
argument4
);
No
thisIsALongNestedMapping[being][set][to_some_value] = someFunction(argument1,
argument2,
argument3,
argument4);
Yes
event ShortOneArg(
address _sender
);
event LongAndLotsOfArgs(
address _sender,
address _recipient,
uint256 _publicKey,
uint256 _amount,
bytes32[] _options
);
emit LongAndLotsOfArgs(
sender,
recipient,
publicKey,
amount,
options
);
emit ShortOneArg(sender);
No
event ShortOneArg(address _sender);
event LongAndLotsOfArgs(address _sender,
address _recipient,
uint256 _publicKey,
uint256 _amount,
bytes32[] _options);
emit LongAndLotsOfArgs(sender,
recipient,
publicKey,
amount,
options);
UTF-8 or ASCII encoding is preferred.
Import statements must always be placed at the top of the file.
Functions and declarations must be grouped according to their visibility and ordered:
- constructor
- fallback function (if exists)
- external
- public
- internal
- private
Within a grouping, place the view
and pure
functions last.
Yes
pragma solidity >=0.4.0 <0.6.0;
contract A
{
using SafeMath for uint256;
uint256 someVariable;
event SomeEvent(
uint256 _arg1
);
modifier SomeModifier(
uint256 _arg1
)
{
// some check
_;
}
constructor()
public
{
// ...
}
function()
external
{
// ...
}
// External functions
// ...
// External functions that are view
// ...
// External functions that are pure
// ...
// Public functions
// ...
// Internal functions
// ...
// Private functions
// ...
}
No
pragma solidity >=0.4.0 <0.6.0;
contract A
{
// External functions
// ...
function()
external
{
// ...
}
// Private functions
// ...
// Public functions
// ...
constructor()
public
{
// ...
}
// Internal functions
// ...
}
Avoid extraneous whitespace in the following situations:
Yes
spam(ham[1], Coin({ name: "ham" }));
No
spam( ham[ 1 ], Coin( { name: "ham" } ) );
More than one space around an assignment or other operator to align with another:
Yes
x = 1;
y = 2;
long_variable = 3;
No
x = 1;
y = 2;
long_variable = 3;
Control Structures
Yes
pragma solidity >=0.4.0 <0.6.0;
contract Coin
{
struct Bank
{
address owner;
uint balance;
}
}
No
pragma solidity >=0.4.0 <0.6.0;
contract Coin {
struct Bank {
address owner;
uint balance;
}
}
The same recommendations apply to the control structures if
, else
, while
,
and for
.
Additionally there must be a single space between the control structures
if
, while
, and for
and the parenthetic block representing the
conditional, as well as a single space between the conditional parenthetic
block and the opening brace.
Yes
if (...)
{
...
}
No
if (...) {
...
}
while(...){
}
for (...) {
...;}
For control structures whose body contains a single statement, omitting the braces is NOT ok in any condition.
Yes
if (x < 10)
{
x += 1;
}
No
if (x < 10)
x += 1;
if (x < 10)
someArray.push(Coin({
name: 'spam',
value: 42
}));
For if
blocks which have an else
or else if
clause, the else
must be
placed on the same line as the if
's closing brace. This is an exception compared
to the rules of other block-like structures.
Yes
if (x < 3)
{
x += 1;
}
else if (x > 7)
{
x -= 1;
}
else
{
x = 5;
}
if (x < 3)
{
x += 1;
}
else
{
x -= 1;
}
No
if (x < 3) {
x += 1;
} else {
x -= 1;
}
if (x < 3)
x += 1;
else
x -= 1;
For every function declarations, it is recommended to drop each argument onto it's own line at the same indentation level as the function body. The closing parenthesis and opening bracket must be placed on their own line as well at the same indentation level as the function declaration.
Yes
function thisFunctionHasNoArguments()
public
{
doSomething();
}
function thisFunctionHasAnArgument(
address _a
)
public
{
doSomething();
}
function thisFunctionHasLotsOfArguments(
address _a,
address _b,
address _c,
address _d,
address _e,
address _f
)
public
{
doSomething();
}
No
function thisFunctionHasNoArguments() public
{
doSomething();
}
function thisFunctionHasAnArgument(address _a) public {
doSomething();
}
function thisFunctionHasLotsOfArguments(address _a, address _b, address _c,
address _d, address _e, address _f) public {
doSomething();
}
function thisFunctionHasLotsOfArguments(address _a,
address _b,
address _c,
address _d,
address _e,
address _f) public {
doSomething();
}
function thisFunctionHasLotsOfArguments(
address _a,
address _b,
address _c,
address _d,
address _e,
address _f) public {
doSomething();
}
If a function declaration has modifiers, then each modifier must be dropped to its own line.
Yes
function thisFunctionNameIsReallyLong(
address _x,
address _y,
address _z
)
public
onlyowner
priced
returns (address)
{
doSomething();
}
function thisFunctionNameIsReallyLong(
address _x,
address _y,
address _z,
)
public
onlyowner
priced
returns (address)
{
doSomething();
}
No
function thisFunctionNameIsReallyLong(address _x, address _y, address _z)
public
onlyowner
priced
returns (address) {
doSomething();
}
function thisFunctionNameIsReallyLong(address _x, address _y, address _z)
public onlyowner priced returns (address)
{
doSomething();
}
function thisFunctionNameIsReallyLong(address _x, address _y, address _z)
public
onlyowner
priced
returns (address) {
doSomething();
}
Multiline output parameters and return statements must follow the same style.
Yes
function thisFunctionNameIsReallyLong(
address _a,
address _b,
address _c
)
public
returns (
address someAddressName,
uint256 LongArgument,
uint256 Argument
)
{
doSomething()
return (
veryLongReturnArg1,
veryLongReturnArg2,
veryLongReturnArg3
);
}
No
function thisFunctionNameIsReallyLong(
address _a,
address _b,
address _c
)
public
returns (address someAddressName,
uint256 LongArgument,
uint256 Argument)
{
doSomething()
return (veryLongReturnArg1,
veryLongReturnArg1,
veryLongReturnArg1);
}
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.
Yes
pragma solidity >=0.4.0 <0.6.0;
// Base contracts just to make this compile
contract B {
constructor(
uint
)
public
{
}
}
contract C {
constructor(
uint,
uint
)
public
{
}
}
contract D {
constructor(
uint
)
public
{
}
}
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)
public
{
// do something with param5
x = _param5;
}
}
No
pragma solidity >=0.4.0 <0.6.0;
// Base contracts just to make this compile
contract B {
constructor(uint) public {
}
}
contract C {
constructor(uint, uint) public {
}
}
contract D {
constructor(uint) public {
}
}
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)
public
{
x = _param5;
}
}
contract X is B, C, D {
uint x;
constructor(uint _param1, uint _param2, uint _param3, uint _param4, uint _param5)
B(_param1)
C(_param2, _param3)
D(_param4)
public {
x = _param5;
}
In variable declarations, do not separate the keyword mapping
from its
type by a space. Do not separate any nested mapping
keyword from its type by
whitespace.
Yes
mapping(uint => uint) map;
mapping(address => bool) registeredAddresses;
mapping(uint => mapping(bool => Data[])) public data;
mapping(uint => mapping(uint => s)) data;
No
mapping (uint => uint) map;
mapping( address => bool ) registeredAddresses;
mapping (uint => mapping (bool => Data[])) public data;
mapping(uint => mapping (uint => s)) data;
Declarations of array variables must not have a space between the type and the brackets.
Yes
uint[] x;
No
uint [] x;
- Strings must be quoted with double-quotes instead of single-quotes.
Yes
str = "foo";
str = "Hamlet says, 'To be or not to be...'";
No
str = 'bar';
str = '"Be yourself; everyone else is already taken." -Oscar Wilde';
- Surround operators with a single space on either side.
Yes
x = 3;
x = 100 / 10;
x += 3 + 4;
x |= y && z;
No
x=3;
x = 100/10;
x += 3+4;
x |= y&&z;
- Operators with a higher priority than others can exclude surrounding whitespace in order to denote precedence. This is meant to allow for improved readability for complex statement. You should always use the same amount of whitespace on either side of an operator:
Yes
x = 2**3 + 5;
x = 2*y + 3*z;
x = (a+b) * (a-b);
No
x = 2** 3 + 5;
x = y+z;
x +=1;
Layout contract elements in the following order:
- Pragma statements
- Import statements
- Interfaces
- Libraries
- Contract
Inside each contract, library or interface, use the following order:
- Library declarations (
using
statements) - Constant variables
- Type declarations
- State variables
- Events
- Modifiers
- Functions
To avoid confusion, the following names will be used to refer to different naming styles.
b
(single lowercase letter)B
(single uppercase letter)lowercase
lower_case_with_underscores
UPPERCASE
UPPER_CASE_WITH_UNDERSCORES
CapitalizedWords
(or CapWords)mixedCase
(differs from CapitalizedWords by initial lowercase character!)Capitalized_Words_With_Underscores
_underscoreMixedCase
When using initialisms in CapWords, capitalize all the letters of the initialisms. Thus HTTPServerError is better than HttpServerError. When using initialisms is mixedCase, capitalize all the letters of the initialisms, except keep the first one lower case if it is the beginning of the name. Thus xmlHTTPRequest is better than XMLHTTPRequest.
l
- Lowercase letter elO
- Uppercase letter ohI
- Uppercase letter eye
Never use any of these for single letter variable names. They are often indistinguishable from the numerals one and zero.
- Contracts and libraries must be named using the CapWords style. Examples:
SimpleToken
,SmartBank
,CertificateHashRepository
,Player
,Congress
,Owned
.
As shown in the example below, if the contract name is Congress
and the library name is Owned
, then their associated filenames should be congress.sol
and owned.sol
.
Yes
pragma solidity >=0.4.0 <0.6.0;
// owned.sol
contract Owned
{
address public owner;
constructor()
public
{
owner = msg.sender;
}
modifier onlyOwner
{
require(msg.sender == owner);
_;
}
function transferOwnership(
address _newOwner
)
public
onlyOwner
{
owner = _newOwner;
}
}
// congress.sol
import "./Owned.sol";
contract Congress is
Owned,
TokenRecipient
{
//...
}
No
pragma solidity >=0.4.0 <0.6.0;
// owned.sol
contract owned
{
address public owner;
constructor()
public
{
owner = msg.sender;
}
modifier onlyOwner
{
require(msg.sender == owner);
_;
}
function transferOwnership(
address _newOwner
)
public
onlyOwner
{
owner = _newOwner;
}
}
// Congress.sol
import "./owned.sol";
contract Congress is
owned,
tokenRecipient
{
//...
}
Structs must be named using the CapWords style. Examples: MyCoin
, Position
, PositionXY
.
Events must be named using the CapWords style. Examples: Deposit
, Transfer
, Approval
, BeforeTransfer
, AfterTransfer
.
Functions other than constructors must use mixedCase. Examples: getBalance
, transfer
, verifyOwner
, addMember
, changeOwner
.
If a function is private
or internal
function should use _underscoreMixedCase. Examples: _calculateBalance
, _doTransfer
.
Function arguments must use _underscoreMixedCase. Examples: _initialSupply
, _account
, _recipientAddress
, _senderAddress
, _newOwner
.
When writing library functions that operate on a custom struct, the struct
should be the first argument and should always be named self
.
Use mixedCase. Examples: totalSupply
, remainingSupply
, balancesOf
, creatorAddress
, isPreSale
, tokenExchangeRate
.
Constants must be named with all capital letters with underscores separating
words. Examples: MAX_BLOCKS
, TOKEN_NAME
, TOKEN_TICKER
, CONTRACT_VERSION
.
Use mixedCase. Examples: onlyBy
, onlyAfter
, onlyDuringThePreSale
.
Enums, in the style of simple type declarations, must be named using the CapWords style. Examples: TokenGroup
, Frame
, HashStyle
, CharacterLocation
.