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.
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 { ... }
Order of layout
Order of layout refers to the recommended order in which different elements of a solidity contract should be organized. It is important to follow a consistent order of layout in order to make the code more readable and easier to understand. This order might vary slightly for different programming languages. This order consists of several optional and mandatory pointers. We've tried to cover almost all (both mandatory/optional) elements as per their order of occurrences in the solidity code.
1. Pragma Statement
A pragma statement is a directive that specifies the version of Solidity that the contract is compatible with. It is important to include a pragma statement at the beginning of your contract to ensure that it will be compiled and run correctly on the Ethereum Virtual Machine (EVM).
2. Import Statements
Import statements are used to include code from other files or libraries in your contract. While using any predefined functionality, import statements are required. This can be useful for including commonly used functions or for sharing code between contracts.
3. Contract and Library Definitions
A contract is a self-contained piece of code that can be deployed on the Ethereum blockchain. It defines the functions and variables that make up the contract, as well as the logic for how it will behave. Whereas a library is a special type of contract that cannot be deployed on its own but can be used by other contracts. It is used to encapsulate common code that can be shared between contracts.
4. Global Variables
Declare any global variables at the beginning of the contract. It is good practice to group related variables together and to declare constants first, followed by variables that will be modified during the execution of the contract.
5. Constructor
The constructor is a special function that is executed when the contract is deployed. It is used to initialize the contract and set any initial values for variables. The constructor should be placed immediately after the global variables.
6. Fallback Function
The fallback function is a special function that is executed whenever the contract receives an external call that does not match any of the other functions. It is used to handle unexpected or invalid calls to the contract. The fallback function should be placed immediately after the constructor.
7. Variable Declarations
Variables are used to store data in a contract. In Solidity, variables must be declared with a type, such as uint256 for unsigned integers or address for Ethereum addresses. Here these variables are different from global variables, as they will only have scope in the contract they are getting initialized or declared.
8. Public and External Function Definitions
Declare all public and external functions next. Public functions can be called by any contract or external actor, while external functions can only be called by other contracts. It is good practice to group related functions together and to place functions that are more frequently used towards the top.
9. Internal Functions
Declare any internal functions next. Internal functions can only be called by other functions within the same contract and are useful for encapsulating complex logic or for sharing code between functions.
10. Private Functions
Declare any private functions last. Private functions can only be called by other functions within the same contract and are useful for encapsulating sensitive logic or for sharing code between functions in a way that is not visible to external actors.
11. Events
Declare any events after the functions. Events are used to trigger log entries on the blockchain that can be used for logging or for triggering external actions. An event is declared like a function, but with the "event" keyword and no function body. It can have parameters, which can be of any type except for mappings and dynamically sized arrays.
Naming Convention
A naming convention is a set of rules for choosing names for variables, functions, and other important entities in your code. With respect to solidity code, here are some guidelines for the naming convention while writing your code.
- Use CamelCase for naming variables and functions (e.g. helloGeeks)
- Use PascalCase for contract and struct names.
- Use descriptive, lowercase names for variables and functions (e.g. totalSupply instead of ts).
- Use a leading underscore for private variables (e.g. _privateVariable).
- Use a leading is or has for boolean variables (e.g. isActive or hasValue).
- Use descriptive and meaningful names for constants, and use ALL_CAPS for naming them.
- Avoid abbreviations and single-letter names, except for common abbreviations like "id" and "num".
- Avoid using reserved words as names.
- Use descriptive and meaningful names for events, and prefix the name with Log.
- Use descriptive and meaningful names for functions, and indicate their purpose in the name.
- Use descriptive and meaningful names for function arguments, and indicate the purpose of the argument in the name.
- Use meaningful names for local and state variables, and indicate their purpose in the name
- Use descriptive and meaningful names for modifiers, and indicate their purpose in the name.
- Use descriptive and meaningful names for enums, and indicate their purpose in the name.
Refer to the code snippet attached ahead for reference.
contract MyContract {
// Constants
uint256 public constant MIN_VALUE = 10;
uint256 public constant MAX_VALUE = 100;
// Variables
uint256 public totalSum;
address public owner;
mapping(address => uint256) public balances;
...
NatSpec
NatSpec (Natural Language Specification) is a system for documenting solidity code in a way that is easy for humans to understand. NatSpec comments are written in Markdown format and can be accessed through the Ethereum NatSpec Standard JSON Interface. To add single-line NatSpec documentation to your Solidity code, use double-slash comments ('//') followed by the NatSpec tag and the documentation text. And for adding multiple comments ("/**.....*/") Here's an example to refer to while writing comments.
/**
@notice Description of the function
@param Parameter1 Description of parameter1
@param Parameter2 Description of parameter2
@return Description of the return value
*/
Below is the solidity code to demonstrate how to comment using the NatSpec format:
Solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.6 <0.9.0;
/// @title A contract for demonstrate NatSpec format
/// @author Jitendra Kumar
/// @notice For now, this contract just show how to comment using NatSpec format
contract helloGeeks {
/// @notice Return an initialized string
/// @return A string helloGeeks
function renderHelloGeeksFun () public pure returns (string memory) {
return 'helloGeeks';
}
}
Explanation:
- With reference to the attached snippet, we can see the code layout used here and can verify the order of layout (i.e. Pragma statement followed by Contract and finally Function definitions). Check whether the naming convention guidelines are also followed or not and NatSpec declaration of comments is included or so.
- This is a simple Solidity contract that defines a single function called "renderHelloGeeksFun". The function has no input parameters and returns a string. The "pragma solidity" line at the top of the contract specifies the version of Solidity that the contract is compatible with. In this case, the contract is compatible with any version of Solidity between 0.8.6 and the latest version.
- The "pure" keyword in the function declaration indicates that the function does not modify the contract's state and does not have any external side effects. This makes the function cheaper to execute because it does not require any resources beyond the computation of its return value.
- The "returns" clause specifies the type and name of the value that the function returns. In this case, the function returns a string called "string" and the data location is "memory" for this string.
- The function body consists of a single return statement that returns the string "helloGeeks". Overall, this contract defines a simple function that returns a fixed string when it is called. It does not do anything else.
Similar Reads
Solidity Tutorial
Solidity tutorial is designed for those who want to learn Solidity programming language and for experienced Solidity developers looking to gain a deeper understanding of the language. The following Solidity tutorial explains the basic and advanced concepts of Solidity programming language and provid
6 min read
Solidity Basics
Introduction to Solidity
Solidity is a brand-new programming language created by Ethereum which is the second-largest market of cryptocurrency by capitalization, released in the year 2015 and led by Christian Reitwiessner. Some key features of solidity are listed below: Solidity is a high-level programming language designed
5 min read
Setting Up Smart Contract Development Environment
A development environment is an environment in which all the resources and tools are available which are used to develop a program or software product. Here, an attempt to create a development environment that is a collection of the processes and tools that are used to develop smart contracts.There
5 min read
Solidity - Basic Syntax
Solidity is a programming language specifically designed for developing smart contracts on the Ethereum blockchain. It is a high-level, statically-typed language with syntax and features similar to those of JavaScript, C++, and Python. Solidity is used to write self-executing smart contracts that ca
5 min read
"Hello World" Smart Contract in Remix-IDE
What do you mean by Smart Contract? Smart contracts are self-executing contracts. The term was coined by Nick in 1994. Smart contracts are very different from traditional software programs. They are immutable once deployed on the blockchain. It was because of Ethereum the term smart contract became
4 min read
Solidity - Comments
Comments are an important aspect of programming as they help in providing clarity and understanding to the code. They allow developers to document the code and explain its purpose, making it easier for others to read and maintain the code. Solidity, being a programming language, also supports the us
4 min read
Solidity - Types
Solidity is a statically typed language, which implies that the type of each of the variables should be specified. Data types allow the compiler to check the correct usage of the variables. The declared types have some default values called Zero-State, for example for bool the default value is False
4 min read
Reference & Mapping Types in Solidity
Solidity - Strings
Solidity is syntactically similar to JavaScript, C++, and Python. So it uses similar language structures to those languages. Strings in Solidity is a data type used to represent/store a set of characters. Examples: "Hii" // Valid string "Hello World" // Valid string "2022" // Valid string In Solidi
3 min read
Solidity - Arrays
Arrays are data structures that store the fixed collection of elements of the same data types in which each and every element has a specific location called index. Instead of creating numerous individual variables of the same type, we just declare one array of the required size and store the element
6 min read
Solidity - Enums and Structs
Enums are the way of creating user-defined data types, it is usually used to provide names for integral constants which makes the contract better for maintenance and reading. Enums restrict the variable with one of a few predefined values, these values of the enumerated list are called enums. Option
3 min read
Solidity - Mappings
Mapping in Solidity acts like a hash table or dictionary in any other language. These are used to store the data in the form of key-value pairs, a key can be any of the built-in data types but reference types are not allowed while the value can be of any type. Mappings are mostly used to associate t
4 min read
Solidity - Conversions
Solidity is a programming language that is used to write smart contracts for the Ethereum blockchain. One important concept in Solidity is conversions, which allow you to change the type of a variable or expression. The article focuses on discussing three types of conversions in Solidity. The follow
6 min read
Solidity - Ether Units
In the world of Ethereum smart contracts, understanding how Ether (ETH) and its subunits work is crucial. Solidity is the programming language used to write these smart contracts, and it interacts directly with Ether, the cryptocurrency of the Ethereum network. This article focuses on discussing Eth
7 min read
Solidity - Special Variables
There exist special variables and functions in solidity which exist in the global namespace and are mainly used to provide information about the blockchain or utility functions. They are of two types: 1) Block and Transaction Properties: Block Transaction Properties block.coinbase (address payable)C
3 min read
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 wri
13 min read
Solidity Functions
Solidity - Functions
A function is basically a group of code that can be reused anywhere in the program, which generally saves the excessive use of memory and decreases the runtime of the program. Creating a function reduces the need of writing the same code over and over again. With the help of functions, a program can
4 min read
Solidity - Function Modifiers
Function behavior can be changed using function modifiers. Function modifier can be used to automatically check the condition prior to executing the function. These can be created for many different use cases. Function modifier can be executed before or after the function executes its code. The modi
8 min read
Solidity - View and Pure Functions
The view functions are read-only function, which ensures that state variables cannot be modified after calling them. If the statements which modify state variables, emitting events, creating other contracts, using selfdestruct method, transferring ethers via calls, Calling a function which is not 'v
2 min read
Solidity - Fall Back Function
The solidity fallback function is executed if none of the other functions match the function identifier or no data was provided with the function call. Only one unnamed function can be assigned to a contract and it is executed whenever the contract receives plain Ether without any data. To receive E
3 min read
Solidity Function Overloading
Function overloading in Solidity lets you specify numerous functions with the same name but varying argument types and numbers.Solidity searches for a function with the same name and parameter types when you call a function with certain parameters. Calls the matching function. Compilation errors occ
1 min read
Mathematical Operations in Solidity
Solidity is a brand-new programming language created by the Ethereum which is the second-largest market of cryptocurrency by capitalization, released in the year 2015 led by Christian Reitwiessner. Ethereum is a decentralized open-source platform based on blockchain domain, used to run smart contrac
6 min read
Solidity Advanced
Solidity - Basics of Contracts
Solidity Contracts are like a class in any other object-oriented programming language. They firmly contain data as state variables and functions which can modify these variables. When a function is called on a different instance (contract), the EVM function call happens and the context is switched i
4 min read
Solidity - Inheritance
Inheritance is one of the most important features of the object-oriented programming language. It is a way of extending the functionality of a program, used to separate the code, reduces the dependency, and increases the re-usability of the existing code. Solidity supports inheritance between smart
6 min read
Solidity - Constructors
A constructor is a special method in any object-oriented programming language which gets called whenever an object of a class is initialized. It is totally different in case of Solidity, Solidity provides a constructor declaration inside the smart contract and it invokes only once when the contract
4 min read
Solidity - Abstract Contract
Abstract contracts are contracts that have at least one function without its implementation or in the case when you don't provide arguments for all of the base contract constructors. Also in the case when we don't intend to create a contract directly we can consider the contract to be abstract. An i
3 min read
Solidity - Basics of Interface
Interfaces are the same as abstract contracts created by using an interface keyword, also known as a pure abstract contract. Interfaces do not have any definition or any state variables, constructors, or any function with implementation, they only contain function declarations i.e. functions in inte
2 min read
Solidity - Libraries
Libraries in solidity are similar to contracts that contain reusable codes. A library has functions that can be called by other contracts. Deploying a common code by creating a library reduces the gas cost. Functions of the library can be called directly when they do not modify the state variables i
4 min read
Solidity - Assembly
Assembly or Assembler language indicates a low-level programming language that can be converted to machine code by using assembler. Assembly language is tied to either physical or a virtual machine as their implementation is an instruction set, and these instructions tell the CPU to do that fundamen
4 min read
What are Events in Solidity?
Solidity Events are the same as events in any other programming language. An event is an inheritable member of the contract, which stores the arguments passed in the transaction logs when emitted. Generally, events are used to inform the calling application about the current state of the contract, w
2 min read
Solidity - Error Handling
Solidity has many functions for error handling. Errors can occur at compile time or runtime. Solidity is compiled to byte code and there a syntax error check happens at compile-time, while runtime errors are difficult to catch and occurs mainly while executing the contracts. Some of the runtime erro
6 min read
Top 50 Solidity Interview Questions and Answers
Solidity is an object-oriented programming language used to implement smart contracts on blockchain platforms like Ethereum, which generates transaction records in the system. To excel in your journey toward top companies as a Solidity developer, you need to master some important Solidity Interview
15+ min read