Coding style and conventions for our Smart Contracts.
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.
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;
}
}