Coding style and conventions for our Smart Contracts.

Table of contents

Coding

We follow (or at least we try to) some principles when coding smart contract:

Also it is 100% recommended to read these article about previous Solidity hacks and security considerations, gas usage, and some usage of the ABI encode functions.

Scaffold

Contracts must respect the following structure:

/// License
// SPDX-License-Identifier: MIT

/// Pragmas
pragma solidity  ^0.8.0;
pragma experimental ABIEncoderV2;

/**
* Imports.
* We put first external dependencies and then after a new line all the local imports 
* from closer path to further path (../../../import > ../../import > ../import > /import)
*/
import "@openzeppelin/contracts/token/ERC20.sol";
import "@openzeppelin/contracts/token/ERC721.sol";

import "../../libs/String.sol";
import "../commons//OwnableInitializable.sol";
import "./contract.sol";

/// Start the contract after two lines. The contract name must be in PascalCase
contract MyContract {
		/// usings
		using String for string;
		
		/// Variables (storage layout). Every variable should have the visibility
		/// defined: public, private, etc.
		/// Custom types: structs in PascalCase. Each struct must be separated by one
		/// blank new line
		struct MyStruct {
				bytes32 id;
				string metadata;
		}
		
		struct MyOtherStruct {
				bytes32 id;
				address owner;
				string metadata;
    }
		
		/// mappings & arrays. Camelcase. No need of a blank new line.
		mapping(bytes32 => string) public myMapping;
		address[] public myAddresses;

		/// Predefined types. Public > private. No need of a blank new line.
		address public owner;
		uint256 private counter;
	
		/// Events. PascalCase
		event OwnerSet(address indexed _owner);
		
		/// Constructor if needed.
		constructor(address _owner) {
			owner = _owner;

			emit OwnerSet(_owner);
		}
		
		/// Modifiers
		modifier onlyOwner() {
        require(
            msg.sender == owner,
            "MyContract#onlyOwner: CALLER_IS_NOT_OWNER"
        );
        _;
    }

	/// Functions: We define calls (writes to storage) first, and later the 
	/// reads (views and pure functions)
	/// Also, we follow the order for each section like 
	/// external > public > internal > private
	/// Writes
	function doA() external {
  }

	function doB() public {
  }

	function _doB() internal {
  }
	
	/// Reads
	function getTrue() public pure returns(bool) {
		return true
  }

	function getOwner() public view returns(address) {
		return owner;
  }	
}