Estimated time: 6 minutes read

Best practices in Solidity are essential for developing secure and efficient smart contracts. Various criteria are addressed, and the use of the Solhint tool is introduced, a Solidity linter that automates the checking of certain rules.

What are the best practices in Solidity?

Best practices in Solidity are a set of recommended rules, criteria, and programming patterns for developing secure and reliable smart contracts.

Since smart contracts are inherently immutable and often involve managing some type of crypto asset, it’s essential to ensure a good initial design.

How to comply with best practices in Solidity?

The criteria are very broad and generally depend on the type of smart contract being developed. Moreover, with the evolution of blockchain development, it is expected that they will change and adapt over time.

However, there is a basic set of best practices that could serve as a starting point for a deeper analysis.

1. Follow a style guide when writing source code

This involves coding contracts according to style conventions accepted by the community. For example, the official Solidity style guide can be reviewed.

2. Control of compiler versions

Define the minimum version of the compiler at the beginning of the contract using the “pragma” directive to prevent incompatibilities and avoid attacks from older versions of Solidity.

3. Optimization of gas consumption

This means programming smart contracts following guidelines that reduce gas consumption, both in deployment and execution.

However, it is essential to find a balance between clean, maintainable code that also optimizes gas consumption.

My article on gas optimization in Solidity explores several common techniques.

4. Error handling
  • Use require, revert, and assert to validate external conditions or results during calls to other contracts using call, delegatecall, and staticcall.
  • Return Custom Errors (available since Solidity 0.8) to notify external parties of errors and facilitate their handling from DApps and calling contracts.
  • Manage exceptions in try/catch blocks when it is necessary to interrupt the propagation of errors.
5. Use of events

Register actions of interest during the execution of the contract using events to trace its behavior with minimal gas expenditure.

6. Integration of reputable contract libraries

Reuse open-source contracts that have been audited and offer community-backed guarantees, such as those provided by OpenZeppelin.

7. Access Control

Develop access control policies that restrict permissions in contract calls. Numerous alternatives exist, such as the Ownable or AccessControl contracts from OpenZeppelin, to limit certain functions to administrators or authorized users.

8. Security in Ether handling

In my article on how to send Ether from a smart contract, it concludes that the current consensus is to use the call function and prevent potential reentrancy attacks through programming patterns that modify the state before making calls to external contracts (Checks-Effects-Interactions) and using ReentrancyGuard.

9. Protection against common attacks

In a subsequent article, I will address the most common errors, design patterns to avoid them, and their detection through vulnerability analysis tools.

10. Plan for contract upgrades

To correct errors or incorporate new features, design the contract with future upgrades in mind. Some of the main contract upgrade patterns can be followed: proxy pattern, eternal storage, data separation, dispatcher, diamond…

It is also advisable to use trusted third-party libraries to support the implementation of the chosen pattern. An example would be Proxies from OpenZeppelin.

11. Intensive testing

There are numerous ways to detect and correct errors before deploying contracts in production: unit testing, static analysis, dynamic analysis, mutation testing, fuzzy testing…

The final step could involve security audits performed by third parties or launching bug bounty programs to attract the community of security-focused developers.

Practical use case: the Solhint tool

As seen, there are numerous criteria and patterns that form the core of best practices in programming smart contracts in Solidity.

While ensuring their implementation is initially the programmer’s responsibility, tools exist to automate compliance with specific rules, helping to detect possible errors.

One of those tools is Solhint, an open-source Solidity linter that allows configuring a set of rules to validate compliance in our smart contracts of interest.

The rules are categorized into four sections and have been programmed based on the criteria and demands of the developer community: best practices, style guide, gas consumption, and security.

While there is a default configuration with recommended rules, it is always possible to customize it according to the needs of each case. For example, the following “.solhint.json” configuration file could be added to the recommended rule set to include some changes and new rules:

{
  "extends": "solhint:recommended",
  "rules": {
    "func-visibility": ["warn",{"ignoreConstructors":true}],
    "max-states-count": ["off"],
    "func-param-name-mixedcase": "warn",
    "modifier-name-mixedcase": "warn",
    "gas-calldata-parameters": "warn",
    "gas-increment-by-one": "warn",
    "gas-length-in-loops": "warn",
    "gas-named-return-values": "warn",
    "gas-small-strings": "warn",
    "gas-struct-packing": "warn"
  }
} 

To check the rules, the command can be invoked as follows:

yarn solhint 'contracts/**/*.sol'

Another alternative is to integrate Solhint directly into Hardhat.

To achieve this, you need to install the package “@nomiclabs/hardhat-solhint”, import it in the “hardhat.config.js” file, and run the following command:

yarn hardhat check

Conclusion: Programming secure and reliable Smart Contracts

Programming Smart Contracts is not just about implementing a specific business logic or protocol on the blockchain. Given their immutable nature and the management of valuable digital assets, it is essential to follow a set of rules and criteria to ensure, as much as possible, the security and efficiency of the deployed code, generating trust among the developer and user community.

The set of best practices encompasses various aspects, from style conventions in source code writing to optimizations in gas consumption, secure Ether transfers, and intensive testing.

To support and assist developers in their implementation, there are many auxiliary tools. In this article, Solhint, a Solidity linter that automates the verification of certain rules and common criteria in Smart Contract coding, has been reviewed.


Do you regularly follow best practices and criteria in your Smart Contract programming? Do you have any guide you can share? Do you use any tools that make the work easier? I invite you to share your experiences.

Contact me if you are looking for a Smart Contract developer accustomed to following best practices in their development. I can collaborate on your project.