State of the Contracts

There were a total of 535,741 warnings of 50 types (shown in the below illustrations) across the 25,000 contracts. There were about a thousand contracts with zero warnings (ignoring the contracts that ran into internal compiler errors). The median number of warnings per contract was 13. There were five contracts which had the maximum number of 256 warnings ( solc interestingly has a separate warning declaring that the maximum number of 256 warnings have been reached when it stops processing further).

Types of solc warnings seen on the 25,000 contracts.

Types of solc warnings seen on the 25,000 contracts (continued).

The below two charts show frequency of the 50 warning types aggregated across all contracts and unique occurrences per contract.

As we can observe from the above charts, the most common warnings are those of types 1, 2, 3, 19, 20 and 27.

Keyword constructor

Warning type 1 is about using the contract name for the constructor function which, since solc version 0.4.22, has been deprecated by the constructor() keyword. As discussed in Part 1, the reason is that the use of constructor keyword is immune to any changes in the name of the contract itself. But in the old-style, if the name of the contract is changed and the developer then forgets to update the name of the constructor function, it would become a normal callable function. In either case, if the constructor performed some privileged operations then this misnaming would allow anyone to misuse the constructor logic, such as that exploited in the Rubixi contract [2].

It is understandable that we see many warnings of this type because version 0.4.22 was released only in April 2018.

Event emit

Warning type 2 is about invoking events without the emit prefix. Events allow the use of EVM logging facilities, which in turn can be used to trigger JavaScript callbacks in a dapp UI which listens for these events [3]. Without the emit prefix, the earlier syntax for generating an event looked very similar to a function call with parameters.

Example contract showing the syntax to emit an event.

To differentiate the generation of events from function calls, in version 0.4.21 solc added the emit keyword for specifying event generation (usage shown in above code snippet). This improves readability and prevents any errors if there are contract functions with similar names. Prior to emit , the best practise to prevent such mix-ups was to prefix the event name with Log and use capitalisation [4].

Again, it is understandable that we see many warnings of this type because version 0.4.21 was released only in March 2018.

Deprecated throw

Warning type 3 is about throw() being deprecated by revert() , assert() and require() . As mentioned in the Solidity release notes for version 0.4.21 [5], throw keyword creates the impression that exceptions are a feature of Solidity, while in reality, it only supports state-reversion. Solidity does not have the capability to throw and catch exceptions.

Default public

Warning type 19 is about missing visibility specifier for functions (defaults to public). As discussed in Part 1, 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 multisig wallet exploited such missing function visibility specifiers leading to the attacker stealing $31M worth of Ether [6].

Unused parameter

Warning type 20 is about unused function parameter. As discussed in Part 1, an unused function parameter might not cause immediate harm but could be an indicator of some missing logic which in turn could leave the contract vulnerable.

Modifier pure

Warning type 27 is about adding the pure modifier to a function. Adding this modifier to a function prevents it from writing or reading contract state. If a function is not operating on any storage state then the compiler suggests this maximum restrictiveness to be explicitly declared. This would prevent any unintended state modifications within the function in future.

When we plot the warnings per contract in a chronological order from March 2016 to May 2018, we see the below trend. Notice the spikes where contracts exceed 256 warnings.

The trend line appears to be headed down but that is likely an artifact of running a newer and stricter compiler version on older contracts. Ideally, one should use the same compiler version as indicated in the contract pragma to observe the generated warnings and then infer how many of them were ignored.

These were the common warning types but I believe that the more interesting ones, from a vulnerability likelihood perspective, are some of the lower frequency ones such as types 18, 21, 22, 23, 34, 35, 36, 37, 40, 44 and 48. It will be interesting to investigate some notable contracts with these warnings to determine if they are indicative of vulnerabilities or simply red herrings.