This document outlines the standards and best practices for Solidity development at Bayat.
- Follow the Solidity Style Guide
- Use a consistent version pragma statement at the top of each file
- Maximum line length should be 120 characters
- Use 4 spaces for indentation, not tabs
- Files should be encoded in UTF-8
- Files should end with a newline
- Use spaces around operators
- No trailing whitespace
- Use
// SPDX-License-Identifier: <LICENSE>
at the top of each file
-
Contracts and Libraries:
- Use PascalCase for contract, library, and interface names (e.g.,
ERC20Token
,SafeMath
) - Be descriptive and avoid abbreviations
- Interfaces should be prefixed with "I" (e.g.,
IERC20
)
- Use PascalCase for contract, library, and interface names (e.g.,
-
Functions:
- Use camelCase for function names (e.g.,
transferFrom
,balanceOf
) - Use descriptive names that accurately reflect behavior
- Private/internal functions should be prefixed with an underscore (e.g.,
_transfer
) - Event functions should use PascalCase (e.g.,
Transfer
,Approval
)
- Use camelCase for function names (e.g.,
-
Variables:
- Use camelCase for variable names (e.g.,
tokenBalance
,ownerAddress
) - Use meaningful names that reflect the purpose or meaning
- Constants should use SNAKE_CASE (e.g.,
MAX_UINT
,TOKEN_DECIMALS
) - Private/internal state variables should be prefixed with an underscore (e.g.,
_balances
)
- Use camelCase for variable names (e.g.,
-
Modifiers:
- Use camelCase for modifier names (e.g.,
onlyOwner
,nonReentrant
) - Modifier names should describe the restriction or behavior they enforce
- Use camelCase for modifier names (e.g.,
-
Events:
- Use PascalCase for event names (e.g.,
Transfer
,OwnershipTransferred
) - Event names should typically be verbs in past tense as they record actions that have occurred
- Use PascalCase for event names (e.g.,
-
Enums and Structs:
- Use PascalCase for enum and struct names
- Enum values should be in ALL_CAPS
-
File Structure:
- One contract/library per file, unless closely related
- Follow a standard order for contract elements:
- Pragma statements
- Import statements
- Interfaces
- Libraries
- Contracts (ordered from base to most derived)
- Within a contract, follow this order:
- Type declarations (structs, enums)
- State variables
- Events
- Modifiers
- Constructor
- Fallback and receive functions
- External functions
- Public functions
- Internal functions
- Private functions
-
Import Statements:
- Group imports by source (e.g., standard libraries, external libraries, local imports)
- Use explicit imports (e.g.,
import {Symbol} from "filename"
) when only importing specific symbols
-
Access Control:
- Implement proper access control with modifiers
- Use OpenZeppelin's
Ownable
or role-based access control when appropriate - Always check authorization before executing sensitive operations
-
Reentrancy Protection:
- Implement reentrancy guards for external calls
- Follow the checks-effects-interactions pattern
- Consider using OpenZeppelin's
ReentrancyGuard
-
Integer Arithmetic:
- Use SafeMath or Solidity 0.8.x built-in overflow/underflow protection
- Be aware of potential overflow/underflow in arithmetic operations
- Consider using OpenZeppelin's
SafeMath
for Solidity < 0.8.0
-
Gas Optimization:
- Be mindful of gas costs in loops and data storage
- Use
memory
instead ofstorage
when appropriate - Prefer
calldata
for function parameters in external functions
-
Avoid Common Vulnerabilities:
- Protect against front-running and transaction ordering attacks
- Be cautious with
delegatecall
and understand its security implications - Avoid timestamp manipulation vulnerabilities
-
Error Handling:
- Use custom errors (Solidity 0.8.4+) or revert with clear error messages
- Fail early and loudly
- Validate all inputs and preconditions
-
Contract Upgradeability:
- If using upgradeable contracts, follow a well-established pattern (e.g., proxy patterns)
- Document upgradeability intentions and mechanisms
- Consider using OpenZeppelin Upgrades library
-
External Calls:
- Always check return values from external calls
- Implement proper error handling for external calls
- Be aware of potential callback issues
- Use
try/catch
for external calls in Solidity 0.6.0+
-
Function Visibility:
- Use the most restrictive visibility possible
- Mark functions as
external
when they are only called from outside the contract - Mark functions as
internal
orprivate
when they are only called from within the contract
-
Code Comments:
- Use NatSpec format for function and contract documentation
- Document all public and external functions
- Example format:
/// @title A title that should describe the contract/interface /// @author The name of the author /// @notice Explain to an end user what this does /// @dev Explain to a developer any extra details contract MyContract { /// @notice Explain to an end user what this function does /// @dev Explain to a developer any extra details /// @param user The address of the user /// @return balances The token balance of the user function getBalance(address user) external view returns (uint256 balances) { // Implementation } }
-
Contract Documentation:
- Document the purpose of each contract
- Document inheritance relationships
- Document the expected behavior and assumptions
- Document any known limitations or risks
-
Unit Testing:
- Write comprehensive unit tests for all contract functionality
- Use a framework such as Hardhat, Truffle, or Foundry
- Test both success and failure scenarios
- Ensure code coverage of at least 95%
-
Integration Testing:
- Test interactions between different contracts
- Test the contract in realistic scenarios
- Simulate real-world usage patterns
-
Gas Optimization Testing:
- Monitor gas usage for all functions
- Establish gas usage baselines and track changes
- Create gas usage reports for key functions
-
Deployment Process:
- Document the deployment procedure for each contract
- Create deployment scripts for reproducible deployments
- Verify contract source code on block explorers
-
Environment Management:
- Maintain separate configurations for different environments (testnet, mainnet)
- Use environment-specific addresses and parameters
- Document the addresses of deployed contracts
-
Code Review Process:
- All code should undergo peer review before deployment
- Use a consistent code review checklist
- Consider formal verification for critical contracts
-
External Audits:
- Engage external auditors for critical contracts
- Address all identified issues
- Document the audit process and results
-
Version Management:
- Use semantic versioning for contract releases
- Document changes between versions
- Maintain backward compatibility when possible
-
Contract Updates:
- Document the upgrade strategy (proxy pattern, new deployment, etc.)
- Ensure proper testing of upgrade procedures
- Have a roll-back plan for failed upgrades
-
Library Usage:
- Prefer established, audited libraries (e.g., OpenZeppelin)
- Document all external dependencies
- Specify exact versions for dependencies
- Understand the code you're importing
-
Version Pinning:
- Pin compiler versions to specific releases
- Specify exact versions for imported contracts
- Update dependencies to fix known vulnerabilities
-
Recommended Tools:
- Development Framework: Hardhat, Foundry, or Truffle
- Linting: Solhint or Ethlint
- Testing: Mocha, Chai, Waffle
- Static Analysis: Slither, MythX
- Gas Analysis: Hardhat Gas Reporter
-
Local Development:
- Use a local blockchain (e.g., Hardhat Network, Ganache)
- Set up a consistent development environment
- Use automated deployment scripts
-
Network Selection:
- Consider gas costs, transaction speed, and security when selecting a blockchain
- Document supported networks
- Handle network-specific quirks and limitations
-
Gas Optimization:
- Optimize contracts for the target blockchain's gas model
- Be aware of network-specific gas pricing mechanisms
- Document expected gas costs for key operations
-
Automated Testing:
- Run tests on every commit
- Run gas usage analysis on every commit
- Run static analysis tools automatically
-
Deployment Automation:
- Automate deployments to test networks
- Create verification scripts for deployed contracts
-
Emergency Plans:
- Have a documented plan for responding to vulnerabilities
- Implement circuit breakers or pause mechanisms for critical functions
- Define roles and responsibilities during emergencies
-
Monitoring:
- Monitor contract activity for unusual patterns
- Set up alerts for critical events
- Regularly check contract balances and state