Audit Readiness Guide

Ready for an audit? Check out our guide for actionable tips to help you prepare for a web3 security audit.
Lost to web3 hacks in 2023
Lost to smart contract hacks in 2023

Part I – Security Audit Overview

What is a Security Audit?

A smart contract audit provides developers with an in-depth review of their codebase to identify potential vulnerabilities, inefficient code, or poor coding practices. Typically, an audit will also check and identify discrepancies between the documentation (e.g., whitepaper) and the code. A thorough security audit should offer potential fixes and mitigations for such findings.

Security audits are crucial for all applications, but especially for decentralized applications running on public, permissionless blockchains.

Smart contract auditors have extensive experience examining many different types of products, whether they be tokens, staking contracts, DeFi protocols, GameFi, etc. By working with auditors, projects can obtain an external, independent set of eyes to perform a security audit ahead of an all-important product launch.

Smart contract auditors review the codebase architecture, and identify potential issues as well as put forward recommendations to fix the issues found. Often the experience of reviewing many different projects is invaluable to auditors in being able to identify potential security issues.

Audits are typically carried out using a mixture of automated and manual processes to find security issues that could be exploited by malicious actors.

Furthermore, a good smart contract audit will examine the business logic laid out in the project whitepaper and other end-user-facing documentation to ensure that the logic is correctly mapped in the smart contract code.

Audit findings are presented in a report, highlighting potential vulnerabilities and outlining possible solutions.
The process is often iterative, with two-way communication between the auditors and project developers, and an active working relationship will often yield the best results for a security audit.

When should you get an audit?

A smart contract or set of smart contracts is often deployed onto public blockchains such as Ethereum.

Once a smart contract goes live on a public blockchain, it can be accessed by everyone, and unfortunately, this includes malicious/bad actors who will try to take advantage of any vulnerabilities for financial gain.

On a public blockchain, these exploits or hacks cannot be reversed, leading to financial and reputational loss not only for the project but also for the protocol’s users.

Decentralized and permissionless systems come at a cost, and hacks are a constant concern for projects, with over $2.3 billion in exploits in 2023 alone.

Audits from reputable security companies are often beneficial in building trust within a community of users, as well as reassuring investors that the project prioritizes good security.

A smart contract audit is a snapshot in time, meaning audit firms check the codebase for a specific commit. Any changes made to the code after a code audit, or even during a code audit, may introduce new attack vectors that may not be addressed by the audit.

This highlights the importance of good two-way communication between the project and the audit firm.

Projects often upgrade their protocols over time, with the smart contracts or indeed the entire codebase upgraded to a new version. Each time such an implementation takes place, it is best to get a follow-up audit to ensure that the code is safe for users.

How should you prepare for a security audit?

Preparing for an audit requires following common engineering best practices for high-quality project development. This involves developing clean and modularized code, using standard libraries, and conducting thorough testing.Documentation also plays a vital role in the audit process, serving as evidence to support findings and recommendations.

Clean and modularized code simplifies the testing process and issue identification. Standard libraries ensure code consistency and decrease the risk of having a bug. Following best practices in code development can make audits more efficient and effective, improving overall project quality.

Thorough testing, both automatic and manual, detects system issues and bugs. Being well-prepared for an audit allows the auditors to focus on identifying difficult-to-detect issues. Well-written tests decrease the time and cost associated with audits. Ideally, code coverage should cover at least 90% of the codebase. Auditors may also use existing test code to test attack factors.

Documentation provides the evidence required to support audit findings and recommendations. It facilitates action and ensures that the audit team can identify any gaps or deficiencies in the implementation. Adequate documentation also helps the development team in addressing issues and improving project quality.

Although an audit can enhance project quality and security, the development team is ultimately responsible for ensuring high quality. Following best practices in code development, testing, and documentation can streamline the audit process, improve project quality, and ensure a successful audit.

A good resource for writing clean code  →

What does a typical Quantstamp audit look like?

Any audit will begin with engaging an audit company. We have an intake form on our website and will do our best to review requests and reach out to projects as quickly as we can.

Next, Quantstamp engineers will evaluate the project’s codebase to determine the complexity and amount of code.It is critical at this stage to provide the scopers with as much information as possible to accurately assess the codebase.

Our audit engagement form allows projects to supply our engineers with details such as links to code repositories, coding language/tech stack, whitepaper, and other technical documentation.

Upon completion of a scope, we will share a quote for the audit, including a tentative schedule and price. We strongly recommend initiating contact with audit companies with a reasonable lead time before the audit is scheduled to start. Scoping can occur when the code is developed to a substantial level of completion (approximately 85-90%), so it’s better to establish a communication channel ahead of time!

The audit process

At Quantstamp, a minimum of three audit engineers are assigned to every project. While the initial preparation and discussion of the audit is a collaborative process, each auditor conducts their own code review, using a mixture of manual auditing as well as proprietary tooling.

Once each auditor has conducted their reviews, those results will be collated and a preliminary report with findings will be made. The findings are categorized by severity. Our audit team will also share potential ways to fix or mitigate them.

The preliminary findings are shared confidentially with the project. The project is also given a period of time (usually two weeks) to fix vulnerabilities and address the findings contained in the report. Upon completion of fixes, the audit team will conduct a ‘Fix Review,’ to verify the changes that have been made. The original issues are then marked as ‘Fixed,’ ‘Mitigated,’ ‘Acknowledged’ or left as ‘Unresolved.’

The audit report is then updated to its final version and delivered to the project. Often our reports are made public by the project themselves, but public reports can also be viewed (and verified) on our website.

As you can see from the process above, good communication is required between both the audit company and the project to ensure the success and smooth progress of any security audit.

Security consultation, community-driven security efforts

Quantstamp works with many projects on various levels. Security audits can evolve into longer-term security consultation engagements, where we provide resources on a periodic basis.

Other ways to add extra sets of security-minded eyes to a project is to establish bug bounty programs. These also aid community building/engagement efforts while stressing a project’s commitment to security.

Part II – Audit Readiness

1. Project Specification Checklist

Good documentation is essential for a successful audit as it enables auditors to quickly onboard the project and have a reliable reference when needed. Additionally, clear and concise documentation not only helps with the audit process but also allows the wider community to understand and engage with the project. Therefore, investing time and effort into creating comprehensive documentation can benefit the project both during and beyond the audit.
Summarize what your project is intended to do and what features it has (e.g., token, staking). Include appropriate references, files, and documents (e.g., unit tests, requirements, specification, white paper).
State any assumptions, design decisions, and non-standard practices. For example, indicate that there is a trusted owner or you trust external oracles.
If the system is NOT intended to be completely trustless, document who the trusted actors are and what they should be trusted with. What are the expectations of parties? What are the actions that each party can perform?
Document who the main users and stakeholders are. What kind of applications and users will be interacting with the project?
List all outside libraries or resources that your project relies on. State any assumptions for the external contracts or configuration, e.g., “only integrating with ERC20 tokens without the callback functionality (no ERC777)”, or “only integrating with ERC20 tokens with 18 decimals”.
Document the functional and non-functional requirements of the smart contracts.

2. General Code Checklist

Code hygiene and wherever possible implementing best practices is another key feature of great projects. Follow common conventions of the specific language - for example the solidity style guide is outlined here.
Use the latest major compiler version.
Use established and well-tested libraries whenever possible (e.g., OpenZeppelin for Solidity smart contracts) to avoid code clones.
Ensure that the code compiles without any warnings and errors. Provide the exact instructions for building the project and include any implicit dependencies and their versions (e.g., the npm version).
Document all functions inline. Use NatSpec documentation for public and external functions.
Ensure that both code and documentation are in English.
Run the code through a spellchecker.
Run a static analyzer (e.g., Slither for Solidity) and review its output. Although these tools often raise flags for non-issues, they can sometimes catch a low-hanging fruit (e.g., ignored return value).
Ask a friend, an experienced code reviewer, (preferably external to your project) to sanity check your code and to get an early feedback.

3. Solidity Specific Checklist

While gas optimization can improve the efficiency and cost-effectiveness of a smart contract, it can also introduce vulnerabilities if not done carefully. It's important to re-consider gas optimization and only apply it when necessary and beneficial. Additionally, when using lower-level solutions in the code, it's crucial to provide enough comments to ensure its readability and maintainability, reducing the risk of introducing security issues.
Any public function that can be made external should be made external. This is both to save the gas and to reduce the possibility of bugs since external functions cannot be accessed internally.
Avoid using assembly code unless absolutely necessary. The use of assembly increases audit times as it removes Solidity's guardrails and must be checked much more carefully.
Document the use of unchecked. Describe why it is safe to skip arithmetic checks on each code block. Preferably for each operation.
Follow the Checks-Effects-Interactions pattern (possibly with a combination of reentrancy guards) to avoid reentrancies. Treat all asset transfers as “interactions”.

4. Test Checklist

Testing is crucial for developing high-quality projects and reducing bugs. Both happy path and edge cases should be tested to ensure the code can handle different scenarios. While high coverage does not guarantee quality, low coverage suggests low quality. We suggest aiming for at least 80% coverage, with good quality projects aiming for 90+% branch coverage. Prioritizing testing and quality practices can improve code reliability and quality, save time and costs during audits, and allow auditors to focus on complex issues. It's recommended to prioritize testing to ensure the project's success and a successful audit.
Ensure that the code comes with an extensive test suite. Tests help to express your intent and to assure code quality.
Provide step-by-step instructions for running the test suite. Include any necessary information related to the setup and environment.
Have tests for all "happy path" user stories. All tests should be passing.
Test access controls and paths for all the roles, such as owners and non-owners.
Write negative tests. E.g., if users should NOT be able to withdraw within 100 blocks of depositing, then write a test where a user tries to withdraw early and make sure the user's attempt fails.
Measure test coverage (e.g., with solidity-coverage for Solidity). A good rule of thumb is to ensure at least 80% coverage in each category (statements, functions, branches). Note, however, that optimizing for 100% coverage does not automatically imply a high quality test suite.
If you rely on external protocols, implement tests with a mainnet fork so that the integration points are tested.

5. Audit Scoping Checklist

Identify the target date of audit completion and any reasons for such timing (e.g., commitment to investors).
Provide the location of your source code (e.g., GitHub) with the commit hash to be audited and make sure they are accessible to the auditors.
Please be sure to specify files or folders to be audited if it is not the entire repository.
Indicate if the code is currently deemed production-ready by the company. Have all previous reviews been considered and fixes implemented?
Indicate if you need the finalized audit report to be released under your company name, subject to confidentiality terms, or any other special requirements.