QuillAudits Smart Contract Audit Check List

The increased adoption of smart contracts demands strong security guarantees. Unfortunately, it is challenging to create smart contracts that are free of security bugs. As a consequence, critical vulnerabilities in smart contracts are discovered and exploited every few months.

Why is Security Audit Necessary?

Not all smart contracts are as “smart” as we think they are. Security is a critical issue in the case of smart contracts. Recent hacks of smart contracts escalated the matter. An audit from trustful third party is the most ingenuous way to identify bugs, vulnerabilities and security flaws in smart contracts which might have remained unnoticed at production level and if your smart contract is ready to deploy this will be the last chance to save your project from becoming another victim of crypto hacks because of irreversible nature of smart contracts.

Some common bugs in smart contracts that got funds worth millions of dollars stolen :-

External Calls — Every external contract call is a risk (make sure all the internal work (state condition) is complete before calling external functions)

Timestamp Dependence (If the contract function can tolerate a 15-second drift in time, it is safe to use block.timestamp)

Storage injection vulnerability in NEO Smart Contracts (which allows anyone to change the token’s total supply limit by transferring their own tokens to an unspecified address.)

We at QuillAudits, try our best to keep us most up to date with latest security practices. I am writing this blog to share our checklist and framework to audit every contract. This checklist can be applied to any smart contract but we use other strategies to ensure the security of smart contract based on the business logic of contract.

These are basic checks to undertake with any smart contract :-

To ensure your code is easily followable by auditors, team members, automated tools , and the wider community, you should follow style guide based on Solium’s standards. Having a set and automatically enforced style guide will additionally make it easier to spot erroneous code.

1. Correct Functions Visibility:-

Functions in solidity can have four visibility specifiers: public, external, internal or private, with public being the default . State variables can be public, internal or private, with internal being the default. Explicitly specifying the visibility of functions and state variables is a security best practice.

Absent specifiers can be dangerous especially in the case of functions where the default is public accessibility. If such a function has critical logic then it can be triggered from any external address to potentially misuse the contract. The first hack on the Parity multisign wallet exploited such missing function visibility specifiers leading to the attacker stealing $31M worth of Ether.

2. Data Storage :-

In solidity data can be stored in memory which is non-persistent and less expensive or in storage which is persistent and very expensive.While writing smart contracts one should properly analyze that where the data should be stored.By default state variables and local variables are stored in storage and function parameters are stored in memory.

3. Prevent overflow and underflow:-

An overflow is when a number gets incremented above its maximum value. Solidity can handle up to 256 bit numbers (up to ²²⁵⁶-1), so incrementing by 1 would result into 0.

Likewise, in the inverse case, when the number is unsigned, decrementing will underflow the number, resulting in the maximum possible value.

Underflow and overflow can be prevented by using SafeMath library to perform math operations in smart contracts.

4. External Calls — Every external contract call is a risk:-

External calls to untrusted contracts can bring certain risks and errors. External calls may execute malicious code in that contract or any other contract that it depends upon. As such, every external call should be treated as a potential security risk. When it is not possible, or undesirable to remove external calls, use the recommendations.

5. Check for re-enterancy and ensure state committed before external call.

The Reentrancy attack, probably the most famous Ethereum vulnerability, surprised everyone when discovered for the first time. It was first unveiled during a multi-million dollar heist which led to a hard fork of Ethereum. Reentrancy occurs when external contract calls are allowed to make new calls to the calling contract before the initial execution is complete. For a function, this means that the contract state may change in the middle of its execution as a result of a call to an untrusted contract or the use of a low level function with an external address.

Loss: estimated at 3.5M ETH (~50M USD at the time)

6. Don’t delegatecall to untrusted code

The delegatecall function is used to call functions from other contracts as if they belong to the caller contract. Thus the caller may change the state of the calling address. This may be insecure.

7. Save Gas on smart contracts

Saving gas is necessary to build an efficient smart contract. It is one of the main issues that the developers face because not all of them know how to do it correctly. Auditors at QuillAudits understands well which instructions consume more gas and how we can avoid or minimize them.

8. Timestamp Dependence

If the contract function can tolerate a 15-second drift in time, it is safe to use block.timestamp

9. Compiler warnings

All the compiler warnings are serious issue sometimes developer ignore warnings and deploy contract without considering them as a big threat to their smart contract, we recommend necessary action to be taken to remove all the warnings.

10. Ownership of the deployed contract

It is very important to provide ownership to a contract at the time of deployment or a restriction to function calls else attacker may call those function or transfer ownership function before you or if you are required to give ownership of a contract later, most famous bug of this kind is oyster-pearl because ownership of smart contract was open attacker transfer ownership to himself and able to mint tokens of worth ~$300,000.

11. Oracle calls

Blockchains cannot access data outside their network. An oracle is a data feed provided by third party service designed for use in smart contracts on the blockchain.

Oracles are third party services which are not part of the blockchain consensus mechanism. The main challenge with oracles is that people need to trust these sources of information.

12. Lock pragmas to specific compiler version:

pragma solidity ^0.4.4; this is bad

pragma solidity 0.4.4; this is good

13. Security Tools

After manual and unit testing , your smart contract undergoes automation testing that is done using many open source security tools.

Static and Dynamic Analysis:

Test Coverage:

Linters:

We at QuillAudits use multiple in-house automated tools in addition to tools listed, to secure your smart contract and to find whether your smart contract can fulfil your business requirements. apart from automated tools your smart contract code goes under multiple testing phases like static testing which is done manually by our expert audit team thereafter smart contract comes under unit testing which is done using truffle, test suite is prepared for each and every function in your smart contract to know whether your function is capable of handling overflow, underflow condition, reflected variable in that function should maintain their value properly, then Solidity-coverage is used to know how much our test cases are penetrating your smart contract functions, final report after reviewed at multiple level is delivered to client including all the possible suggestions and severity issues raised during audit.