Skip to main content


Smart Contract Security Checklist

Classification: Restricted

Stage: Publication stage (60)


The Web3 Security Framework Initiative is a collaborative effort to promote the adoption of best practices in web3 security. The initiative aims to minimize the risks associated with security vulnerabilities and hacks, which have become increasingly prevalent in the web3 space. Moreover, projects that demonstrate full compliance with our rigorous guidelines will earn an on-chain certificate recognized by all the AvengerDAO members on the BNB Chain ecosystem.

This document serves as a comprehensive checklist of the critical elements surrounding the secure development of solidity smart contracts.

Item idSecurity CheckCriticalityIs Project Compliant?Comments
1.1To reduce risks of vulnerabilities, audits are required for each major release. The audits should be performed by multiple auditing firms.High
1.2Audits scope should be comprehensive and include business logic correctness, proxy setup, access control, vulnerability findings, etc.High
1.3Following the audits, ensure all issues have been fixed and recommendations have been implemented.High
1.4Ensure your project is part of a bug bounty program. Notable Web3 security bug bounty platforms include Immunefi, Code4rena, Hacken, Bugrap, etc.Medium
2Test Coverage
2.1All non-trivial functions should be tested.High
2.2Business-critical functions should be thoroughly tested against all edge cases.High
2.3Certify the exactitude of the expected behavior of functions and business flows.High
2.4Certify that all scenarios raising exceptions are also tested and that exception management works as expected (eg: matching internal exceptions with customer-facing error code/message).High
2.5Verify the code specifications using formal verification. Tools like Securify and MythX analyze smart contracts for security vulnerabilities, generating detailed reports which are beneficial during contract development. Oyente, another tool, is specifically designed for security analysis of Solidity contracts, hunting common bugs and security issues.Medium
3Solidity Specifics
3.1.1Ensure development teams use security scanning tools. Slither, notably, is a widely-adopted tool for the analysis of smart contracts.High
3.1.2Use a block explorer such as BscScan, to verify all deployed contracts and their implementation.High
3.1.3Verify smart contracts are not using send() or transfer() functions to send infrastructure tokens.Medium
3.2.1Ensure smart contracts do not rely on the immutability of another smart contract, if the latter has a self-destruct or delegate-call mechanism.High
3.3.1Blockchain ledgers are publicly accessible by design. Therefore it is recommended that smart contract data should be classified according to its level of confidentiality. Classify the data into different levels like Public, Confidential, and Highly Confidential based on the information type and its risk level.High
3.3.2Verify the confidentiality framework applied to the decentralized application data complies with regulations around the world. eg: GDPR, PCI-DSS, etc.High
3.3.3Make certain that the crucial business logic of smart contracts does not exclusively depend on data that can be predictable or manipulated by validators, such as block timestamp, block number, block hash, etc. This is an integral measure as predictable validator data can be prone to exploitation in random generators, causing an unjust disadvantage to users. As a countermeasure, it's recommended to employ a truly random source like the industry-standard Chainlink's VRF.High
3.4Complex Data Structure
3.4.1Ensure the size of data stays stable over time so that gas consumption remains stable.Medium
3.4.2Ensure proper validation of data to prevent runtime exceptions such as stack overflow, out of gas, and stack too deep.Medium
3.5.1Certify all decentralized applications' external dependencies are trusted sources.High
3.5.2Ensure such dependencies have been properly tested before integrating them.Medium
3.5.3Smart contract dependencies such as Libraries should be clearly identified and documented.High
3.5.4Ensure dependency versions are clearly specified.Low
3.6Business Logic
3.6.1Ensure that whenever feasible, standard contracts are employed.High
3.6.2Certify that all crucial business flows are documented and comprehensively tested to avoid bugs and corner case exceptions.High
3.6.3Given the existence of front-running possibilities, and the risk of flash loan attacks, use adequate means to secure them.High
3.6.4Ensure the smart contract state is updated correctly when performing key operations such as transfer, deposit, withdraw, lending, etc.High
3.6.5Ensure that timelocks are used in relevant business flows where it makes sense. So that the projects have time to better observe and monitor decentralized applications app behavior and changes. It should be analyzed on a case-by-case basis.Medium
3.7.1Certify that your arithmetic operations are protected against unwanted underflow or overflow.High
3.7.2Verify the inequalities are used when comparing smart contract balance.High
3.7.3Verify the order of magnitude of calculations is correct.High
3.7.4Ensure the order of operations so that results do not lose precision.High
3.7.5Ensure divisions with integers are done safely.High
3.8Input validation
3.8.1Ensure user-defined inputs are sanitized and checked as soon as possible in the smart contract function code.High
3.8.2For input validation, ensure the usage of require or revert.High
3.8.3To prevent privilege escalation and replay attacks, functions utilizing off-chain signed cryptographic signatures for authorization must ensure that the signature is not susceptible to reuse.High
3.8.4Assertions with the assert keyword should be used to evaluate invariants' states.Medium
3.9.1Ensure that the smart contract state is updated before giving the control execution flow to the external unknown smart contract.High
3.9.2Ensure secure mechanisms are in place to prevent same-function and cross-function reentrancy, such as checks, effects, and interactions principles or Reentrancy solutions.High
3.9.3Special attention should be paid when using to the use of the transfer function of ERC721 and ERC1155 tokens to ensure that the data is updated before the transfer operation.High
3.9.4Ensure the transferring assets that delegate the execution flow to other smart contracts is done securely. eg: The ERC721 standard code, which triggers the invocation of the onERC721Received function.High
3.9.5Certify functions with protection against Reentrancy attacks are tested for such scenarios.High
3.10.1Always verify internal and external call return values for unexpected events and define behavior accordingly.High
3.10.2Ensure custom exceptions are created to enhance the exception handling capabilities and code readability.Medium
3.11Gas Consumption
3.11.1Verify that the Dapp smart contract functions are implemented in a manner that gas consumption persists stable over time.High
3.11.2Always provide enough gas when performing a sub-call to another smart contract. The gas calculation should be justified as it may vary over time.High
3.12Denial of Service
3.12.1Ensures proper exception management when transferring crypto assets, such as using try-and-catch blocks.High
3.12.2Avoid using unbounded loops or looping over user-defined parameters without proper controls. If so, ensure the logic execution scale over time with the use of the smart contract.Medium
3.12.3The use of the self-destruct function should be carefully considered as it may lead to the loss of access to tokens, like USDT, held in the contract. This exclusion does not apply to native coins such as BNB. Given the irreversible nature of self-destruction, it is critical to document and test its usage thoroughly prior to implementing it.Low
3.13Monitoring and Alerting
3.13.1Similar to web applications, smart contracts should be monitored as part of the operations of a running decentralized application.High
3.13.2An alerting system should be implemented to detect and alert teams of unexpected behavior.High
3.14Low-Level Calls
3.14.1Ensure proper management of errors in low-level calls as they do not raise exceptions.High
3.14.2Smart contracts should properly validate the response of a low-level call response, as it can be manipulated by the called smart contracts.High
3.14.3Avoid using delegatecall low-level calls, only use them if really necessary and only if the target contract is trusted and secure.Medium
3.15Upgradeable Contracts
3.15.1Ensure the proxy upgradeability has access control and is only actionable with a wallet using a multiple-account solution.High
3.15.2Verify that the proxy and implementation deployment or upgrade process is done in one transaction so that they cannot be front-run.High
3.15.3For initialized implementations, verify that the proxy implementation is initialized.High
3.15.4Certifying the proxy implementation cannot be destroyed. In such a scenario, the proxy contract would not be able to upgrade.High
3.15.5Ensure the upgradeable contract has no overlap between the storage used by the implementation contract and the one used by the proxy.Medium
3.16.1Ensure that the generation of random numbers is executed in a secure manner.High
4.1Smart contracts are fundamentally immutable. Ensure that adequate patterns are used to enable smart contract code upgrading over time and in case of incidents.High
4.2Ensure correct implementation of any ERC standard by referencing the official Ethereum Improvement Proposals (EIPs) site for detailed specifications. Post implementation, draft comprehensive tests for every function, ensuring alignment with the specific ERC standards incorporated. This adherence to official guidelines paired with rigorous testing ensures robust, accurate execution within the smart contract.High
4.3For visibility and state tracking, use events to announce state changes or business actions. This key strategy allows efficient indexing of primary operations such as deposits and withdrawals. This approach, in turn, provides invaluable data for projects to monitor real-time interaction of fund states with the protocol, thereby ensuring optimal transparency and control.High
4.4Ensure that at least the critical business flows have their external and internal dependencies clearly documented. Eg: oracles, liquidity pools, and smart contract standards.Medium
4.5If smart contract addresses require being deterministic, use the appropriate low-level call. Low-level calls aren’t recommended and should be used at your own risk.Low
5Access Control
5.1Verify smart contracts' functions' access follow the least privilege principle.High
5.2Ensure that users only have access to smart contracts they are intended to.High
5.3Certification of the access control on the web application side is aligned with the one existing in the smart contract.High
5.6For better control in large decentralized applications, centralizing the access mechanism is recommended. This eases roles and permissions management, and expedited security concerns handling. However, it also raises risks tied to centralization, like a single failure point or power misuse. This structure demands user's trust, inferring that the central authority will not exploit its control. Each project must precisely balance these efficiency benefits and potential risks in designing their decentralized applications.High
5.7Verify the existence of reentrancy protection for functions modifying smart contract state.High
5.9Certify that critical roles in the decentralized application are not managed by a single user.High
5.10The transaction sender should be validated using the correct means only.High
5.11Access control mechanisms should be thoroughly tested according to specifications and free from vulnerabilities.High
5.12When implementing an off-chain authentication mechanism on smart contracts, ensure the implementation follows a standardized and widely tested one. Drawing from the mature practices of established ecosystems such as PancakeSwap and industry-accepted off-chain protocols like Chainlink ensures robustness and reliability in the project.High
5.13Prevent smart contract roles having elevated privileges (such as mint, transfer, change ownership) to be associated with an External Owner Address (EOA).High
5.14Verify all modifiers' logic are simple and use the correct mechanisms to perform input validation.High
5.15Verify that any change in access control configuration should follow an internal well-defined process.Medium
5.16The access control mechanism of a large decentralized application should be centralized for better control.Low
5.17Describe and document any existing time lock mechanism and its purpose.Low
6Business Logic
6.1Ensure the logic of the smart contract does not assume it cannot receive infrastructure tokens.Medium
6.2Front Running
6.2.1To prevent front-running in a Dapp, and protect users, ensure that one of the following solutions is in place: Preventing time and order to have to influence the outcome of the transaction, limiting the benefits a front-runner could have or using a pre-commit scheme. Pre-commit scheme provides good security against front-running as the actual details of the transaction are hidden during the commit phase. However, it considerably slows down the process as users need to send two transactions (commit and reveal) and it also increases the complexity of the system.Medium
6.3Denial of Service
6.3.1Ensure that Dapp logic cannot be impacted by Dos attacks such as block stuffing, where an attacker prevents other transactions from being validated over a certain period of time.Medium
7Utility Tokens
7.1.1Tokens should adhere to specific, established standards for optimal interoperability. Leveraging widely tested and universally accepted token standards such as ERC20, ERC721, ERC777, ERC1155, and ERC4626 ensures conformity with best practices in the field. For comprehensive reference and understanding, visit this link.High
7.1.2Project administrators should not have high-authority functions to operate user token assets.High
7.1.3Ensure decentralized applications only request user token approval for the exact amount of tokens the user wants to transfer.High
7.1.4The token handling fee should have a reasonable range, rather than potentially being modified arbitrarily by the administrator.Medium
7.2Reflection Token
7.2.1Validate that the rate calculation mechanism of the token is done safely. The token handling fee should have a reasonable range, rather than being arbitrarily specified by the administrator.High
8Code Clarity
8.1Certify the developers are using the recent stable version of the compiler.High
8.2Ensure that modifications to pertinent smart contract state variables activate corresponding events and certify their functionality.Medium
8.3All storage variables should be initialized.Medium
8.4Clearly define the smart contract variables' location as storage, memory, or calldata.Medium
8.5Verify that the smart contracts code makes the distinction between trusted(owned smart contracts) and untrusted (3rd party) smart contracts.Medium
8.6Certify that assembly low-level code is only used if necessary and is properly commented on and documented. For context, it should be used for intricate operations such as direct manipulation of storage/stack, accessing certain storage slots, and modifying memory, which are usually beyond the capability of high-level languages. Moreover, operation-specific assembly code can often be more gas-efficient, making it a necessary choice for optimizing transaction cost in certain scenarios. However, it's important to note that with these enhanced abilities comes increased risk, as assembly allows developers to bypass safety checks normally provided by high-level languages.Low
8.7Certify that unchecked code is clearly commented on following industry standards and documented.Low
8.8For the developer's readability, ensure technical documentation in the contract.Low
8.9Avoid using functions and variables with similar names.Low
8.10Logic should be clear and kept in simple modular contracts and functions.Low
8.11Clean unused variables and functionsLow
8.12The inheritance order for contracts should be defined and documented to prevent bugs using multiple inheritance or shadow functions.Low
8.13Certifying the code annotation matches the code implementation.Low
8.14Verify that the same rules for variable naming are followed throughout all the contracts (e.g. use the same variable name for the same object).
For guidance, here are some standard naming conventions for variable consistency in smart contracts, largely derived from the Solidity Style Guide:
1) Variable Names: Use mixedCase (camelCase) for variable names, function names, and argument names. The first letter should be lowercase, and each new word starts with a capital letter. For example: `uint public totalSupply;` `function checkBalance() public view returns (uint);`
2) Constants: Use UPPERCASE_WITH_UNDERSCORES for constant values. For example: `uint public constant MAX_SUPPLY = 1000000;`
3) State Variable Names: For public state variables that have an automatically generated getter function, use mixedCase. These are treated similarly to function names.
4) Global Variables and Functions: Built-in global variables and functions are lowercase_with_underscores. For example: `block.timestamp`, `msg.sender`.
5) Contract/Interface Names: Use CapWords (PascalCase) for contract and interface names. This means each word begins with a capital letter. For example: `contract CryptoToken `
6) Event Names: Use CapWords (PascalCase) for event names as well.
7) Struct Names: Also use CapWords (PascalCase) for struct names.
8) Mapping Names: If there is a mapping with the key being a name and value referring to a structure, it should be called e.g. `balances` for a balance struct, in plural.
9Education and Training
9.1Provide team members with regular training around smart contract security and best practices.High
9.2Maintain internal documentation of best practices to be followed by team members and new joiners.High
9.3Ensure team members are fully aware of phishing, ice phishing, social engineering attacks, and new techniques of scams.High