Smart-Contract-Auditing-Checklist
My checklist to smart contract auditing.
-
Read specification and documentation of project
-
Use a Visualizer to inspect the contracts in the protocol like Surya.
-
Manual analyzes
-
Gas Optimization checks
- Cache read variables in memory
- Use
calldata
instead ofmemory
if not modifying the function parameter passed - Don't call
view
function inside of another function - Use
++i
instead ofi++
(gas consumption orderi+=1
>i=i+1
>i++
>++i
). Same for--i
. - Use
unchecked
to not check for integer overflow and underflow if not required - Use
constant
andimmutable
for variables that don't change - Use
revert
instead ofrequire
- Create custom errors rather than
revert()
/require()
strings to save gas - Put
require
statements on top in a function - Use
indexed
if less than three arguments are there in events for faster access - Use
!= 0
instead of> 0
for unsigned integer comparison -
internal
functions not called by the contract should be removed - Cache array length outside of loop
- Use
bytes
instead ofstring
. Bytes constants are more efficient than string constants - Use external function modifier.
- Use full 256 bit types unless packing with other variables.
- Splitting
require
statements that use && saves gas. - State variables can be packed into fewer storage slots.
- Use scratch space for keccak.
- No Need to Allocate Unused Variable.
- Use basis points for ratios.
- Skip initializing default values.
- Non-strict inequalities are cheaper than strict ones
- Usage of
uint8
may increase gas cost - Use bytesN instead of bytes[]
- Inline a modifier that’s only used once.
- Inverting the condition of an if-else-statement wastes gas.
- Consider having short revert strings.
-
Informational checks
- Document variables, structs, functions, modifiers, events, contract purpose using NatSpec.
- NatSpec comments should be increased in contracts.
- Check undocumented parameters
- Events emitted for critical state changes for tracking in off-chain.
- Check return values of
approve()
in ERC20 implementations - Use the latest version of OpenZeppelin from dependencies
- Missing error
message
in require statement, also check whether it is relevant. - Follow solidity naming conventions
- Use of
bytes.concat()
instead ofabi.encodePacked()
- Mixed use of
require
andrevert
- Remove unused imports
-
Low severity issue checks
-
abi.encode()
instead ofabi.encodePacked()
for dynamic types when passing tokeccak256()
- Check the modifiers whether any state changes happening.
- New version of Solidity
- Using non-vulnerable version of Openzeppelin dependencies
- Zero address check
- Race condition on ERC20 approval
- Risk of Renounce Ownership in Ownable contracts
- Any hardcoded addresses - causes no future updates
- Whether any critical Address Changes (Should Use Two-step Procedure)
- Use
Ownable2StepUpgradeable
instead ofOwnableUpgradeable
contract -
solmate
'sSafeTransferLib
doesn't check whether the ERC20 contract exists - Check loss of precision due to rounding.
- Monitoring the third party dependencies.
- Direct usage of
ecrecover
allows signature malleability (use OpenZeppelin's ECDSA library) - Hardcoding chainID is error-prone
-
-
Medium severity issue checks
- Check for integer underflow and overflow
- Verify
transfer
andtransferFrom
return values - UsesafeERC20
wrappers - Check the parameter orderings
- Avoid using extcodesize to check for Externally Owned Accounts
- Missing function arguments verification
- Using
transfer
orsend
function to send eth to contract address? - instead usecall
to send data or value - Centralization risk, whether only one owner has access to major functions?
- Must approve 0 first
-
High severity issue checks
- First pool depositor front-running
- Check for possible re-entrancy - add OZ re-entrancy guard
- Input Validations - Use SafeMath
- Error Handlings - Check error code revert if necessary
- Any timestamp dependance for state changes
- EIP-4626 Inflation Attack
- Gas Grieving Attack
- Unexpected Callback
- Risk of using the
safe
functions of ERC token contracts while executingReceiver
functions.
-
-
Look over the project's tests + code coverage and look deeper at areas lacking coverage
-
Do another review from the perspective of every actor in the threat model
-
Run static analyzers (Slither) and linting tools(solhint) on the project to validate teh security and style guide
-
Run symbolic execution tools (Manticore, Mythril, Halmos) for detecting vulnerabilities