Smart Contract Audits Solidity

how to find critical bugs in code4rena contests

I have recently tried my luck with code4rena, where you can earn extra income by finding bugs in Solidity contracts. At first I didn’t find any bugs, only low priority QA issues. However, after a few audits I have improved my process and submitted some critical issues.

My process

Read the contest details

Understand the project. Is this an AMM or NFT project? Try to get an overview what the project is about and what are its features. This way you can later understand how the .sol files translate these ideas into machine code. You can verify Solidity functions that convey the idea of a feature description.

Browse the repository for more details

The Github repository could contain extra details, like UML diagrams of contracts, or some extra documentation.

Verify important contracts

Contracts with most lines of code are the ones with most probability to contain bugs. Important contracts are also that handle funds, access control, or upgradeability.

You should focus more time on these critical contracts. From QuickSwap competition:

In here you can see that AlgebraPool and DataStorage contracts have the most logic. It makes sense that these contracts have the biggest probability of bugs.

There are also Factory and Deployer contracts, which can contain issues about access control or invalid deployment.

Clone the repo and do the static analysis

You need 2 extensions: juanblanco.solidity and tintinweb.solidity-visual-auditor. Navigating the code can be difficult, because Solidity is not supported very well in vscode. tintinweb.solidity-visual-auditor contains “find all references” feature, which is very handy when vscode cannot find Solidity symbols by itself.

Static analysis information can be found here. From this repo you can run echidna fuzzying tests in the Docker image. Recent projects use Foundry, which already includes powerful tools like fuzzying out of the box.

Read the Discord chat for tips

Discord chat can have some clues about where to focus your attention. Other wardens might be too anxious to wait for the contest to finish to submit their findings. You can make use of this and read about their findings.

One time a sponsor actually linked to a valid gas report:

Read the discord only once a day, otherwise it can get too distracting.

Go through the code

This is the most time consuming and rewarding process.

Go through library functions

Library contracts are usually self-contained and can contain critical functionality. These could include transfers or fee calculations.

You can set // @audit checkpoints where you think there might be issues and come back to it later. Check Jackson Kelley video about his process.

Go through the bigger contracts line by line and verify risky logic

  • external calls
  • ownership
  • logic errors

There are many more. You need to have experience to spot possible issues. Here is my personal list of common vulnerabilities. When I get stuck I sometimes go over this list and see if it could help me find issues in the current audit.

Write down bookmarks for the second reading

If you notice any issues, bookmark them with // @audit. You can then come back to these bookmarks in the second run and verify them.

Do a second reading

If in the first run you superficially verified some logic that might be vulnerable, then in the second run you actually verify them and write the report.

Unclog your mind

If I am stuck, then I have found 2 useful ways to unclog my mind and find new possible attack vectors.

Go through similar audits

There are always similar projects that have launched before and have audits available already. You can go through these and maybe find some issues that are relevant to your current project.

If you are auditing AMM, you could read the QuickSwap v3 audits. You could browse famous auditor companies like OpenZeppelin. Try to find audit that matches the category of the current project.

Read through similar code4rena reports

You can search for audits for the same category in this Github repository.

What if you are not sure if it’s an issue?

You can search through previous code4rena reports, and see if this issue has been reported before. This way you can copy some parts of the previous report as proof of your current issue.

For example, the ArtGobblers contest used VRF as the random provider. There seemed to be sketchy code, but I didn’t know how to compose it into a report.

I then searched through all of the previous code4arena reports with my product, and found a similar issue about VRF. In the end it contributed to my personal high severity issue report.

Verify that the issue is real

Sometimes the code can look weird and you think there is an issue. First thing I would do is check whether the project already has a test case for this issue.

For instance, one contest had this computeAddress function.

function computeAddress(address token0, address token1) internal view returns (address pool) {
  pool = address(uint256(keccak256(abi.encodePacked(hex'ff', poolDeployer, keccak256(abi.encode(token0, token1)), POOL_INIT_CODE_HASH))));

Could it be that the contract address overlaps if token0 and token1 are switched?

If you check the tests, then you can see that they are already invalidating this issue:

const create2Address = getCreate2Address(poolDeployer.address, tokens, poolBytecode)
const create = factory.createPool(tokens[0], tokens[1])

await expect(create)
  .to.emit(factory, 'Pool')

// You cannot create a pool with same tokens. The address calculation is correct.
await expect(factory.createPool(tokens[0], tokens[1]))
await expect(factory.createPool(tokens[1], tokens[0]))

If there are no tests, then you can write your own and submit that as PoC.

Write the issues down to a Notion page

I like to write down all of my findings to a Notion page. Then when it comes to submitting, I can copy them over. Notion uses markdown, so the formatting is same as in code4rena.

Sometimes I find that the issue is invalid. Then I strikethrough it from the list.

Submit the issues

On the last day, leave a few hours to submit your findings. For each finding, read it for the last time to check that it’s still valid. I have realised on the last minute that my finding is actually invalid, and have omitted the report.

There is no benefit in submitting non-valid report. On the contrary, it could lead to lowering your reputation in the community.

Try to create a compact report that contains all relevant information and nothing else. If possible, add a proof of concept with your test code. Keep the report professional – don’t bother sponsors with irrelevant information.

Search previous issues and compare

If you don’t find any issues, you can search through all of the previous contests with audit-hero. There you will find all code4rena and Sherlock reports in searchable format. If your project uses proxies, you can search for previous issues that contain “proxy”. If your project is an AMM, you can search for previous findings that contain the word “swap”. You could possibly find similar issues in the current contest.