11institutetext: Concordia University

#  TokenHook: Secure ERC-20 smart contract

Reza Rahimian  Jeremy Clark

###### Abstract

ERC-20 is the most prominent Ethereum standard for fungible tokens. Tokens
implementing the ERC-20 interface can interoperate with a large number of
already deployed internet-based services and Ethereum-based smart contracts.
In recent years, security vulnerabilities in ERC-20 have received special
attention due to their widespread use and increased value. We systemize these
vulnerabilities and their applicability to ERC-20 tokens, which has not been
done before. Next, we use our domain expertise to provide a new implementation
of the ERC-20 interface that is freely available in Vyper and Solidity, and
has enhanced security properties and stronger compliance with best practices
compared to the sole surviving reference implementation (from OpenZeppelin) in
the ERC-20 specification. Finally, we use our implementation to study the
effectiveness of seven static analysis tools, designed for general smart
contracts, for identifying ERC-20 specific vulnerabilities. We find large
inconsistencies across the tools and a high number of false positives which
shows there is room for further improvement of these tools.

##  1 Introduction

The Ethereum blockchain [20, 79] allows users to build and deploy
decentralized applications (DApps) that can accept and use its protocol-level
cryptocurrency ETH. Many DApps also issue or use custom tokens. Such tokens
could be financial products, in-house currencies, voting rights for DApp
governance, or other valuable assets. To encourage interoperability with other
DApps and web applications (exchanges, wallets, etc.), the Ethereum community
accepted a popular token standard (specifically for fungible tokens) called
ERC-20 [27]. While numerous ERC-20 extensions or replacements have been
proposed, ERC-20 remains prominent. Of the 2.5M [57] smart contracts on the
Ethereum network, 260K are tokens [70] and 98% of these tokens are ERC-20
[24].

The development of smart contracts has been proven to be error-prone, and as a
result, smart contracts are often riddled with security vulnerabilities. An
early study in 2016 found that 45% of smart contracts at that time had
vulnerabilities [43]. ERC-20 tokens are subset of smart contracts and security
is particularly important given that many tokens have considerable market
capitalization (e.g., USDT, BNB, UNI, DAI, etc.). As tokens can be held by
commercial firms, in addition to individuals, and firms need audited financial
statements in certain circumstances, the correctness of the contract issuing
the tokens is now in the purview of professional auditors. Later, we examine
one static anaylsis tool from a ‘big-four’ auditing firm.

#### Contributions

Ethereum has undergone numerous security attacks that have collectively caused
more than US$100M in financial losses [29, 50, 48, 61, 53, 4]. Although
research has been done on smart contract vulnerabilities in the past [36], we
focus specifically on ERC-20 tokens.

  1. 1.

We study all known vulnerabilities and cross-check their relevance to ERC-20
token contracts, systematizing a comprehensive set of 82 distinct
vulnerabilities and best practices.

  2. 2.

While not strictly a research contribution, we believe that our newly acquired
specialized domain knowledge should be put to use. Thus, we provide a new
ERC-20 implementation, TokenHook, that is open source and freely available in
both Vyper and Solidity.

  3. 3.

TokenHook is positioned to increase software diversity: currently, no Vyper
ERC-20 implementation is considered a reference implementation, and only one
Solidity implementation is actively maintained (OpenZeppelin’s [46]). Relative
to this implementation, TokenHook has enhanced security properties and
stronger compliance with best practices.

  4. 4.

Perhaps of independent interest, we report on differences between Vyper and
Solidity when implementing the same contract.

  5. 5.

We use TokenHook as a benchmark implementation to explore the completeness and
precision of seven auditing tools that are widely used in industry to detect
security vulnerabilities. We conclude that while these tools are better than
nothing, they do not replace the role of a security expert in developing and
reviewing smart contract code.

##  2 Sample of high profile vulnerabilities

In this section, we examine general attack vectors and cross-check their
applicability to ERC-20 tokens. We sample some high profile vulnerabilities,
typically ones that have been exploited in real world ERC-20 tokens[44, 36,
16, 14, 42]. For each, we (i) briefly explain technical details, (ii) the
ability to affect ERC-20 tokens, and (iii) discuss mitigation techniques.
Later we will compile a more comprehensive list of 82 vulnerabilities and best
practices (see Table2), including these, however space will not permit us to
discuss each one at the same level of detail as the ones we highlight in this
section (however we will include a simple statement describing the issue and
the mitigation).

###  2.1 Multiple withdrawal

This ERC-20-specific issue was originally raised in 2017 [75, 34]. It can be
considered as a transaction-ordering [10] or front-running [19] attack. There
are two ERC-20 functions (i.e., Approve() and transferFrom()) that can be used
to authorize a third party for transferring tokens on behalf of someone else.
Using these functions in an undesirable situation (i.e., front-running or
race-condition) can result in allowing a malicious authorized entity to
transfer more tokens than the owner wanted. There are several suggestions to
extend ERC-20 standard (e.g., MonolithDAO [74] and its extension in
OpenZeppelin [46]) by adding new functions (i.e., decreaseApproval() and
increaseApproval()), however, securing transferFrom() method is the effective
one while adhering specifications of the ERC-20 standard [55].

###  2.2 Arithmetic Over/Under Flows.

An integer overflow is a well known issue in many programming languages. For
ERC-20, one notable exploit was in April 2018 that targeted the BEC Token [12]
and resulted in some exchanges (e.g., OKEx, Poloniex, etc.) suspending
deposits and withdrawals of all tokens. Although BEC developers had considered
most of the security measurements, only line 261 was vulnerable [28, 50]. The
attacker was able to pass a combination of input values to transfer large
amount of tokens [54]. It was even larger than the initial supply of the
token, allowing the attacker to take control of token financing and manipulate
the price. In Solidity, integer overflows do not throw an exception at
runtime. This is by design and can be prevented by using the SafeMath library
[47] wherein a+b will be replaced by a.add(b) and throws an exception in the
case of arithmetic overflow. Vyper has built-in support for this issue and no
need to use SafeMath library.

###  2.3 Re-entrancy

One of the most studied vulnerabilities is re-entrancy, which resulted in a
US$50M attack on a DApp (called the DAO) in 2016 and triggered an Ethereum
hard-fork to revert [29]. At first glance, re-entrancy might seem inapplicable
to ERC-20 however any function that changes internal state, such as balances,
need to be checked. Further, some ERC-20 extensions could also be problematic.
One example is ORBT tokens [56] which support token exchange with ETH without
going through a crypto-exchange [62]: an attacker can call the exchange
function to sell the token and get back equivalent in ETH. However, if the ETH
is transferred in a vulnerable way before reaching the end of the function and
updating the balances, control is transferred to the attacker receiving the
funds and the same function could be invoked over and over again within the
limits of a single transaction, draining excessive ETH from the token
contract. This variant of the attack is known as same-function re-entrancy,
but it has three other variants: cross-function, delegated and create-based
[59]. Mutex [77] and CEI [15] techniques can be used to prevent it. In Mutex,
a state variable is used to lock/unlock transferred ETH by the lock owner
(i.e., token contract). The lock variable fails subsequent calls until
finishing the first call and changing requester balance. CEI updates the
requester balance before transferring any fund. All interactions (i.e.,
external calls) happen at the end of the function and prevents recursive
calls. Although CEI does not require a state variable and consumes less Gas,
developers must be careful enough to update balances before external calls.
Mutex is more efficient and blocks cross-function attack at the beginning of
the function regardless of internal update sequences. CEI can also be
considered as a best practice and basic mitigation for the same-function re-
entrancy. We implement a sell() and buy() function in TokenHook for exchanging
between tokens and ETH. sell() allows token holders to exchange tokens for ETH
and buy() accepts ETH by adjusting buyer’s token balance. It is used to buy
and sell tokens at a fixed price (e.g., an initial coin offering (ICO),
prediction market portfolios [7]) independent of crypto-exchanges, which
introduce a delay (for the token to be listed) and fees. Both CEI and Mutex
are used in TokenHook to mitigate two variants of re-entrancy attack.

###  2.4 Unchecked return values

In Solidity, sending ETH to external addresses is supported by three options:
call.value(), transfer(), or send(). The transfer() method reverts all changes
if the external call fails, while the other two return a boolean value and
manual check is required to revert transaction to the initial state [5].
Before the Istanbul hard-fork [1], transfer() was the preferred way of sending
ETH. It mitigates reentry by ensuring ETH recipients would not have enough gas
(i.e., a 2300 limit) to do anything meaningful beyond logging the transfer
when execution control was passed to them. EIP-1884 [35] has increased the gas
cost of some opcodes that causes issues with transfer()111After Istanbul, the
fallback() function consumes more than 2300 Gas if called via transfer() or
send() methods.. This has led to community advice to use call.value() and rely
on one of the above re-entrancy mitigations (i.e., Mutex or CEI) [77, 17].
This issue is addresses in Vyper and there is no need to check return value of
send() function.

###  2.5 Frozen Ether

As ERC-20 tokens can receive and hold ETH, just like a user accounts,
functions need to be defined to withdraw deposited ETH (including unexpected
ETH). If these functions are not defined correctly, an ERC-20 token might hold
ETH with no way of recovering it (cf. Parity Wallet [49]). If necessary,
developers can require multiple signatures to withdraw ETH.

###  2.6 Unprotected Ether Withdrawal

Improper access control may allow unauthorized persons to withdraw ETH from
smart contracts (cf. Rubixi [60]). Therefore, withdrawals must be triggered by
only authorized accounts and ideally multiple parties.

###  2.7 State variable manipulation

The DELEGATECALL opcode enables a DApp to invoke external functions of other
DApps and execute them in the context of calling contract (i.e., the invoked
function can modify the state variables of the caller). This makes it possible
to deploy libraries once and reuse the code in different contracts. However,
the ability to manipulate internal state variables by external functions has
lead to incidents where the entire contract was hijacked (cf. the second hack
of Parity MultiSig Wallet [4]). Preventive techniques is to use Library
keyword in Solidity to force the code to be stateless, where data is passed as
inputs to functions and passed back as outputs and no internal storage is
permitted [23]. There are two types of Library: Embedded and Linked. Embedded
libraries have only internal functions (EVM uses JUMP opcode instead of
DELEGATECALL), in contrast to linked libraries that have public or external
functions (EVM initiate a “message call”). Deployment of linked libraries
generates a unique address on the blockchain while the code of embedded
libraries will be added to the contract’s code [37]. It is recommended to use
Embedded libraries to mitigate this attack.

###  2.8 Balance manipulation

ERC-20 tokens generally receive ETH via a payable function [22] (i.e.,
receive(), fallback(), etc.), however, it is possible to send ETH without
triggering payable functions, for example via selfdestruct() that is initiated
by another contract [25]. This can cause an oversight where ERC-20 may not
properly account for the amount of ETH they have received [68]. For example, A
contract might use ETH balance to calculate exchange rate dynamically. Forcing
ETH by attacker may affect calculations and get lower exchange rate. To
fortify this vulnerability, contract logic should avoid using exact values of
the contract balance and keep track of the known deposited ETH by a new state
variable. Although we use address(this).balance in TokenHook, we do not check
the exact value of it (i.e., address(this).balance == 0.5 ether)—we only check
whether the contract has enough ETH to send out or not. Therefore, there is no
need to use a new state variable and consume more Gas to track contract’s ETH.
However, for developers who need to track it manually, we provide
contractBalance variable. Two complementary functions are also considered to
get current contract balance and check unexpected received ETH (i.e.,
getContractBalance() and unexpectedEther()).

###  2.9 Public visibility

In Solidity, visibility of functions are Public by default and they can be
called by any external user/contract. In the Parity MultiSig Wallet hack [53],
an attacker was able to call public functions and reset the ownership address
of the contract, triggering a $31M USD theft. It is recommended to explicitly
specify visibility of functions instead of default Public visibility.

##  3 A sample of best practices

We highlight a few best practices for developing DApps. Some best practices
are specific to ERC-20, while others are generic for all DApps—in which case,
we discuss their relevance to ERC-20.

###  3.1 Compliance with ERC-20.

According to the ERC-20 specifications, all six methods and two events must be
implemented and are not optional. Tokens that do not implement all methods
(e.g., GNT which does not implement the approve(), allowance() and
transferFrom() functions due to front-running[32]) can cause failed function
calls from other applications. They might also be vulnerable to complex
attacks (e.g., Fake deposit vulnerability[38], Missing return value bug[11]).

###  3.2 External visibility.

Solidity supports two types of function calls: internal and external [21].
Note that functions calls are different than functions visibility (i.e.,
Public, Private, Internal and External) which confusingly uses overlapping
terminology. Internal function calls expect arguments to be in memory and the
EVM copies the arguments to memory. Internal calls use JUMP opcodes instead of
creating an EVM call.222Also known as “message call” when a contract calls a
function of another contract. Conversely, External function calls create an
EVM call and can read arguments directly from the calldata space. This is
cheaper than allocating new memory and designed as a read-only byte-
addressable space where the data parameter of a transaction or call is
held[67]. A best practice is to use external visibility when we expect that
functions will be called externally.

###  3.3 Fail-Safe Mode.

In the case of a detected anomaly or attack on a deployed ERC-20 token, the
functionality of the token can be frozen pending further investigation. For
regulated tokens, the ability for a regulator to issue a ‘cease trade’ order
is also generally required.

###  3.4 Firing events.

In ERC-20 standard, there are two defined events: Approval and Transfer. The
first event logs successful allowance changes by token holders and the second
logs successful token transfers by the transfer() and transferFrom(). These
two events must be fired to notify external application on occurred changes.
The external application (e.g., TokenScope[6]) might use them to detect
inconsistent behaviors, update balances, show UI notifications, or to check
new token approvals. It is a best practice to fire an event for every state
variable change.

###  3.5 Global or Miner controlled variables.

Since malicious miners have the ability to manipulate global Solidity
variables (e.g., block.timestamp, block.number, block.difficulty, etc.), it is
recommended to avoid these variables in ERC-20 tokens.

###  3.6 Proxy contracts.

An ERC-20 token can be deployed with a pair of contracts: a proxy contract
that passes through all the function calls to a second functioning ERC-20
contract[69, 45]. One use of proxy contract is when upgrades are required—a
new functional contract can be deployed and the proxy is modified to point at
the update. Form audit point of view, it is recommended to have non-upgradable
ERC-20 tokens.

###  3.7 DoS with Unexpected revert.

A function that attempts to complete many operations that individually may
revert could deadlock if one operation always fails. For example, transfer()
can throw an exception—if one transfer in a sequence fails, the whole sequence
fails. One standard practice is to account for ETH owed and require
withdrawals through a dedicated function. In TokenHook, ETH is only
transferred to a single party in a single function sell(). It seems overkill
to implement a whole accounting system for this. As a consequence, a seller
that is incapable of receiving ETH (e.g., operating from a contract that is
not payable) will be unable to sell their tokens for ETH. However they can
recover by transferring the tokens to a new address to sell from.

###  3.8 Unprotected SELFDESTRUCT

Another vulnerability stemming from the second Parity wallet attack [4] is
protecting the SELFDESTRUCT opcode which removes a contract from Ethereum. The
self-destruct method is used to kill the contract and its associated storage.
ERC-20 tokens should not contain SELFDESTRUCT opcode unless there is a multi
approval mechanism.

###  3.9 DoS with block gas limit.

The use of loops in contracts is not efficient and requires considerable
amount of Gas to execute. It might also cause DoS attack since blocks has a
Gas limit. If execution of a function exceeds the block gas limit, all
transactions in that block will fail. Hence, it is recommended to not use
loops and rely on mappings variables in ERC-20 tokens.

Figure 1: Architecture of the Ethereum blockchain in layers, including the
interactive environment (i.e., application layer). ERC-20 tokens falls under
the Smart Contracts category in Contract Layer.

##  4 TokenHook

TokenHook is our ERC20-compliant implementation written in Vyper (v. 0.2.8)
and Solidity (v. 0.8.4) 333TokenHook deployed on Rinkeby at
https://bit.ly/33wDENx (Solidity) and https://bit.ly/3dXaaPc (Vyper). Mainnet
at https://bit.ly/35FMbAf (Solidity 0.5.11). It can be customized by
developers, who can refer to each mitigation technique separately and address
specific attacks. The presence of security vulnerability in supplementary
layers (i.e., consensus, data, network. etc.) affect the entire Ethereum
blockchain, not necessarily ERC-20 tokens. Therefore, vulnerabilities in other
layers are assumed to be out of the scope. Required comments have been also
added to clarify the usage of each function. Standard functionalities of the
token (i.e., approve(), transfer(), transferFrom(), etc.) have been unit
tested. A demonstration of token interactions and event triggering can also be
seen on Etherscan.444Etherscan: https://bit.ly/33xHfL2, https://bit.ly/35TimMW
and https://bit.ly/3eFAnAZ

Among the layers of the Ethereum blockchain, ERC-20 tokens fall under the
Contract layer in which DApps are executed. The presence of a security
vulnerability in supplementary layers affect the entire Ethereum blockchain,
not necessarily ERC-20 tokens. Therefore, vulnerabilities in other layers are
assumed to be out of the scope. (e.g., Indistinguishable chains at the data
layer, the 51% attack at the consensus layer, Unlimited nodes creation at
network layer, and Web3.js Arbitrary File Write at application layer).

Moreover, we exclude vulnerabilities identified in now outdated compiler
versions. Examples: Constructor name ambiguity in versions before 0.4.22,
Uninitialized storage pointer in versions before 0.5.0, Function default
visibility in versions before 0.5.0, Typographical error in versions before
0.5.8, Deprecated solidity functions in versions before 0.4.25, Assert
Violation in versions before 0.4.10, Under-priced DoS attack before EIP-150 &
EIP-1884).

###  4.1 Security features

In our research, we developed 82 security vulnerabilities and best practices
for ERC-20. We concentrate here on how TokenHook mitigates these attacks.
While many of these attacks are no doubt very familiar to the reader, our
emphasis is on their relevance to ERC-20.

####  4.1.1 Multiple Withdrawal Attack

Without our counter-measure, an attacker can use a front-running attack [10,
19] to transfer more tokens than what is intended (approved) by the token
holder. We secure the transferFrom() function by tracking transferred tokens
to mitigate the multiple withdrawal attack [55]. Securing the transferFrom()
function is fully compliant with the ERC-20 standard without the need of
introducing new functions such as decreaseApproval() and increaseApproval().

####  4.1.2 Arithmetic Over/Under Flows

In Solidity implementation, we use the SafeMath library in all arithmetic
operations to catch over/under flows. Using it in Vyper is not required due to
built-in checks.

####  4.1.3 Re-entrancy

At first glance, re-entrancy might seem inapplicable to ERC-20. However any
function that changes internal state, such as balances, need to be checked. We
use Checks-Effects-Interactions pattern (CEI) [17] in both Vyper and Solidity
implementations to mitigate same-function re-entrancy attack. Mutual exclusion
(Mutex) [77] is also used to address cross-function re-entrancy attack. Vyper
supports Mutex by adding @nonreentrant(<key>) decorator on a function and we
use noReentrancy modifier in Solidity to apply Mutex. Therefore, both re-
entrancy variants are addressed in TokenHook.

####  4.1.4 Unchecked return values

Unlike built-in support in Vyper, we must check the return value of
call.value() in Solidity to revert failed fund transfers. It mitigates the
unchecked return values attack while making the token contract compatible with
EIP-1884 [35].

####  4.1.5 Frozen Ether

We mitigate this issue by defining a withdraw() function that allows the owner
to transfer all Ether out of the token contract. Otherwise, unexpected Ether
forced onto the token contract (e.g., from another contract running
selfdestruct) will be stuck forever.

####  4.1.6 Unprotected Ether Withdrawal

We enforce authentication before transferring any funds out of the contract to
mitigate unprotected Ether withdrawal. Explicit check is added to the Vyper
code and onlyOwner modifier is used in Solidity implementation. It allows only
owner to call withdraw() function and protects unauthorized Ether withdrawals.

####  4.1.7 State variable manipulation

In the Solidity implementation, we use embedded Library code (for SafeMath) to
avoid external calls and mitigate the state variable manipulation attack. It
also reduces gas costs since calling functions in embedded libraries requires
less gas than external calls.

####  4.1.8 Function visibility

We carefully define the visibility of each function. Most of the functions are
declared as External (e.g., Approve(), Transfer(), etc.) per specifications of
ERC-20 standard.

###  4.2 Best practices and enhancements

We also take into account a number of best practices that have been accepted
by the Ethereum community to proactively prevent known vulnerabilities [13].
Again, we highlight several of these while placing the background details in
the appendix.

####  4.2.1 Compliance with ERC-20

We implement all ERC-20 functions to make it fully compatible with the
standard. Compliance is important for ensuring that other DApps and web apps
(i.e., crypto-wallets, crypto-exchanges, web services, etc.) compose with
TokenHook as expected.

####  4.2.2 External visibility

To improve performance, we apply an external visibility (instead of public
visibility in the standard) for interactive functions (e.g., approve() and
transfer(), etc.). External functions can read arguments directly from non-
persistent calldata instead of allocating persistent memory by the EVM.

####  4.2.3 Fail-Safe Mode

We implement a ‘cease trade’ operation that will freeze the token in the case
of new security threats or new legal requirements (e.g., Liberty Reserve [78]
or TON cryptocurrency [18]). To freeze all functionality of TokenHook, the
owner (or multiple parties) can call the function pause() which sets a lock
variable. All critical methods are either marked with a notPaused modifier (in
Solidity) or explicit check (in Vyper), that will throw exceptions until
functionality is restored using unpause().

####  4.2.4 Firing events

We define nine extra events: Buy, Sell, Received, Withdrawal, Pause, Change,
ChangeOwner, Mint and Burn. The name of each event indicates its function
except Change event which logs any state variable updates. It can be used to
watch for token inconsistent behavior (e.g., via TokenScope [6]) and react
accordingly.

####  4.2.5 Proxy contracts

We choose to make TokenHook non-upgradable so it can be audited, and upgrades
will not introduce new vulnerabilities that did not exist at the time of the
initial audit.

####  4.2.6 Other enhancements

We also follow other best practices such as not using batch processing in
sell() function to avoid DoS with unexpected revert issue, not using miner
controlled variable in conditional statements, and not using SELFDESTRUCT.

###  4.3 Implementing in Vyper vs. Solidity

Although Vyper offers less features than Solidity (e.g., no class inheritance,
modifiers, inline assembly, function/operator overloading, etc. [21]), the
Vyper compiler includes built-in security checks. Table 1 provides a
comparison between the two from the perspective of TokenHook (see [41] for a
broader comparison on vulnerabilities). Security and performance are
advantages of Vyper. However, Vyper may not be a preferred option for
production (“Vyper is beta software, use with care” [76]), most of the
auditing tools only support Solidity,555Vyper support is recently added to
some tools (e.g., Crytic-compile, Manticore and Echidna). Slither integration
is still in progress [3] and Solidity currently enjoys widespread
implementation, developer tools, and developer experience.

Vulnerability (Vul.) or Best Practice (BP.) |  | TokenHook
---
Implementation
Comment
Vyper | Solidity
Arithmetic Over/Under Flows | Vul. | + |  |  | \- Vyper includes built-in checks for over/under flows.
---
\- SafeMath library is required in Solidity to mitigate the attack.
Re-Entrancy | Vul. | + |  |  | \- @nonreentrant decorator places a lock on functions to mitigate the attack.
---
\- noReentrancy modifier is required in Solidity.
Unchecked return values | Vul. | + |  |  | \- It is already addressed in Vyper.
---
\- There is a need in Solidity to check return values explicitly.
Code readability | BP. | + |  |  | \- No inheritance in Vyper enforces simpler design.
---
\- Solidity allows inline assemblies which is riskier and decreases
readability.
Contract complexity | BP. | + |  | \- 300 lines in Vyper have the same functionality as the Solidity with 500 lines.
Auditable | BP. |  | + | \- Most of the auditing tools are able to analyze Solidity contracts.
Compatibility | BP. |  | + |  | \- Majority of the current Ethereum projects are based on Solidity.
---
\- Developers are more familiar with Solidity than Vyper.
Production readiness | BP. |  | + |  | \- Vyper is not as mature as Solidity in terms of stability, documentation, etc.
---
\- Solidity is adapted by a larger development community.

Table 1: Comparison of TokenHook implementation in Vyper and Solidity. The
plus sign can be considered as an advantage. However, both versions of
TokenHook offer the same level of security.

###  4.4 Need for another reference implementation

The authors of the ERC-20 standard reference two sample Solidity
implementations: one that is actively maintained by OpenZeppelin [46] and one
that has been deprecated by ConsenSys [9] (and now refers to the OpenZeppelin
implementation). As expected, the OpenZeppelin template is very popular within
the Solidity developers [58, 80, 52].

OpenZeppelin’s implementation is actually part of a small portfolio of
implementations (ERC20, ERC721, ERC777, and ERC1155). Code reuse across the
four implementations adds complexity for a developer that only wants ERC-20.
This might be the reason for not supporting Vyper in OpenZeppelin’s
implementation. No inheritance in Vyper requires different implementation than
the current object-oriented OpenZeppelin contracts. Further, most audit tools
are not able to import libraries/interfaces from external files (e.g.,
SafeMath.sol, IERC20.sol). By contrast, TokenHook uses a flat layout in a
single file that is specific to ERC-20. It does not use inheritance in
Solidity which allows similar implementation in Vyper.

TokenHook makes other improvements over the OpenZeppelin implementation. For
example, OpenZeppelin introduces two new functions to mitigate the multiple
withdraw attack: increaseAllowance() and decreaseAllowance(). However these
are not part of the ERC-20 standard and are not interoperable with other
applications that expect to use approve() and transferFrom(). TokenHook
secures transferFrom() to prevent the attack (following [55]) and is
interoperable with legacy DApps and web apps. Additionally, TokenHook
mitigates the frozen Ether issue by introducing a withdraw() function, while
ETH forced into the OpenZeppelin implementation is forever unrecoverable. Both
contracts implement a fail-safe mode, however this logic is internal to
TokenHook, while OpenZeppelin requires an external Pausable.sol contract.

Diversity in software is important for robustness and security [30, 31]. For
ERC-20, a variety of implementations will reduce the impact of a single bug in
a single implementation. For example, between 17 March 2017 and 13 July 2017,
OpenZeppelin’s implementation used the wrong interface and affected 130 tokens
[11]. TokenHook increases the diversity of ERC-20 Solidity implementations and
addresses the lack of a reference implementation in Vyper.

˙ EY Token Review Smart Check Securify MythX (Mythril) Contract Guard Slither
Odin Vulnerability or best practice ID SWC Mitigation or recommendation
Security tools 1 100 Function default visibility $\checkmark$ $\checkmark$
$\checkmark$ $\checkmark$ Specifying function visibility, external, public,
internal or private 2 101 Integer Overflow and Underflow $\oplus$ $!$
$\checkmark$ $\checkmark$ $\checkmark$ Utilizing the SafeMath library to
mitigate over/under value assignments 3 102 Outdated Compiler Version
$\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$
$\times$ Using proper Solidity version to protect against compiler attacks 4
103 Floating Pragma $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$
$\checkmark$ Locking the pragma to avoid deployments using outdated compiler
version 5 104 Unchecked Call Return Value $\oplus$ $\checkmark$ $\checkmark$
$\checkmark$ $\oplus$ $\checkmark$ Checking call() return value to prevent
unexpected behavior in DApps 6 105 Unprotected Ether Withdrawal $!$
$\checkmark$ $\checkmark$ $\checkmark$ Authorizing only trusted parties to
trigger ETH withdrawals 7 106 Unprotected SELFDESTRUCT Instruction
$\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ Removing self-destruct
functionality or approving it by multiple parties 8 107 Re-entrancy
$\checkmark$ $\oplus$ $\oplus$ $\oplus$ $\checkmark$ $\checkmark$ Using CEI
and Mutex to mitigate self-function and cross-function attack 9 108 State
variable default visibility $\checkmark$ $\checkmark$ $\checkmark$
$\checkmark$ $\checkmark$ $\checkmark$ Specifying visibility of all variables,
public, private or internal 10 109 Uninitialized Storage Pointer $\checkmark$
$\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$
Initializing variables upon declaration to prevent unexpected storage access
11 110 Assert Violation $\checkmark$ $\checkmark$ $\checkmark$ Using require()
statement to validate inputs, checking efficiency of the code 12 111 Use of
Deprecated Solidity Functions $\checkmark$ $\checkmark$ $\checkmark$
$\checkmark$ $\checkmark$ Using new alternatives functions such as keccak256()
instead of sha3() 13 112 Delegatecall to untrusted callee $\oplus$ $\oplus$
$\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ Calling into trusted
contracts to avoid storage access by malicious contracts 14 113 DoS with
Failed Call $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$
Avoid multiple external calls where one error may fail other transactions 15
114 Transaction Order Dependence $\oplus$ $\checkmark$ $\checkmark$
$\checkmark$ Preventing race conditions by securing approve() or
transferFrom() 16 115 Authorization through tx.origin $\checkmark$
$\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$
Using msg.sender to authorize transaction initiator instead of originator 17
116 Block values as a proxy for time $\checkmark$ $\checkmark$ $\checkmark$
$\checkmark$ $\checkmark$ $\checkmark$ Not using block.timestamp or
block.number to perform functionalities 18 117 Signature Malleability
$\checkmark$ $\checkmark$ Not using signed message hash to avoid signatures
alteration 19 118 Incorrect Constructor Name $\checkmark$ $\checkmark$
$\checkmark$ Using constructor keyword which does not match with contract name
20 119 Shadowing State Variables $\checkmark$ $\checkmark$ $\checkmark$
$\checkmark$ $\checkmark$ Removing any variable ambiguities when inheriting
other contracts 21 120 Weak Sources of Randomness from Chain Attributes
$\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ Using oracles
as source of randomness instead of block.timestamp 22 121 Missing Protection
against Signature Replay Attacks $\checkmark$ $\checkmark$ Storing every
message hash to perform signature verification 23 122 Lack of Proper Signature
Verification $\checkmark$ $\checkmark$ Using alternate verification schemes if
allowing off-chain signing 24 123 Requirement Violation $\checkmark$
$\checkmark$ $\checkmark$ $\checkmark$ Checking the code for allowing only
valid external inputs 25 124 Write to Arbitrary Storage Location $\checkmark$
$\checkmark$ $\checkmark$ $\checkmark$ Controlling write to storage to prevent
storage corruption by attackers 26 125 Incorrect Inheritance Order
$\checkmark$ $\checkmark$ Inheriting from more general to specific when there
are identical functions 27 126 Insufficient Gas Griefing $\checkmark$
$\checkmark$ Allowing trusted forwarders to relay transactions

Table 2: Auditing results of 7 smart contract analysis tools on TokenHook.
$\checkmark$=Passed audit, $\oplus$=False positive, $\times$=Failed audit,
Empty=Not supported audit by the tool, $!$=Informational, $\bigcirc$=Tool
specific audit (No SWC registry), BP=Best practice

˙ EY Token Review Smart Check Securify MythX (Mythril) Contract Guard Slither
Odin Vulnerability or best practice ID SWC Mitigation or recommendation
Security tools 28 127 Arbitrary Jump with Function Type Variable $\checkmark$
$\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ Minimizing use of assembly
in the code 29 128 DoS With Block Gas Limit $\checkmark$ $\checkmark$
$\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ Avoiding
loops across the code that may consume considerable resources 30 129
Typographical Error $\checkmark$ $\checkmark$ Using SafeMath library or
performing checks on any math operation 31 130 Right-To-Left-Override control
character (U+202E) $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$
$\checkmark$ Avoiding U+202E character which forces RTL text rendering 32 131
Presence of unused variables $\checkmark$ $\checkmark$ $\checkmark$
$\checkmark$ $\oplus$ Removing all unused variables to decrease gas
consumption 33 132 Unexpected Ether balance $\checkmark$ $\checkmark$
$\checkmark$ $\checkmark$ $\checkmark$ Avoiding Ether balance check in the
code (e.g., this.balance == 0.24 Ether) 34 133 Hash Collisions With Variable
Length Arguments $\checkmark$ Using abi.encode() instead of abi.encodePacked()
to prevent hash collision 35 134 Message call with hardcoded gas amount
$\oplus$ $\oplus$ $\checkmark$ $\checkmark$ $\checkmark$ Using
.call.value()(””) which is compatible with EIP1884 36 135 Code With No Effects
$\checkmark$ $\checkmark$ Writing unit tests to ensure producing the intended
effects by DApps 37 136 Unencrypted Private Data On-Chain $!$ $\checkmark$
Storing un-encrypted private data off-chain 38 $\bigcirc$ Allowance decreases
upon transfer $\checkmark$ Decreasing allowance in transferFrom() method 39
$\bigcirc$ Allowance function returns an accurate value $\checkmark$ Returning
only value from the mapping instead of internal function logic 40 $\bigcirc$
It is possible to cancel an existing allowance $\checkmark$ $\checkmark$
Possibility of setting allowance to 0 to revoke previous allowances 41
$\bigcirc$ A transfer with an insufficient amount is reverted $\checkmark$
$\checkmark$ Checking balances in transfer() method before updating balances
42 $\bigcirc$ Upon sending funds, the sender’s balance is updated $\checkmark$
Updating balances in transfer() or transferFrom() methods 43 $\bigcirc$ The
Transfer event correctly logged $\checkmark$ Emitting Transfer event in
transfer() or transferFrom() functions 44 $\bigcirc$ Transfer an amount that
is greater than the allowance $\checkmark$ Checking balances in transferFrom()
method before updating balances 45 $\bigcirc$ Risk of short address attack is
minimized $\checkmark$ $\checkmark$ Using recent Solidity version to mitigate
the attack 46 $\bigcirc$ Function names are unique $\checkmark$ $\checkmark$
No function overloading to avoid unexpected behavior 47 $\bigcirc$ Using miner
controlled variables $\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$
$\checkmark$ $\checkmark$ Avoiding block.number, block.timestamp,
block.difficulty, now, etc 48 $\bigcirc$ Use of return in constructor
$\checkmark$ Not using return in contract’s constructor 49 $\bigcirc$ Throwing
exceptions in transfer() and transferFrom() $\checkmark$ $\checkmark$
Returning true after successful execution or raising exception in failures 50
$\bigcirc$ State variables that could be declared constant $\checkmark$ Adding
constant attribute to variables like name, symbol, decimals, etc 51 $\bigcirc$
Tautology or contradiction $\checkmark$ Fixing comparison in the code that are
always true or false 52 $\bigcirc$ Divide before multiply $\checkmark$
Ordering multiplication prior division to avoid integer truncation 53
$\bigcirc$ Unchecked Send $\checkmark$ Ensuring that the return value of
send() is always checked 54 BP Too many digits $\checkmark$ Using scientific
notation to make the code readable and simpler to debug

Table 3: Continuation of Table2.

˙ EY Token Review Smart Check Securify MythX (Mythril) Contract Guard Slither
Odin Vulnerability or best practice ID SWC Mitigation or recommendation
Security tools 55 BP The decreaseAllowance definition follows the standard
$\checkmark$ Defining decreaseAllowance input and output variables as standard
56 BP The increaseAllowance definition follows the standard $\checkmark$
Defining increaseAllowance input and output variables as standard 57 BP
Minimize attack surface $\checkmark$ $\checkmark$ $\checkmark$ Checking
whether all the external functions are necessary or not 58 BP Transfer to the
burn address is reverted $\checkmark$ Reverting transfer to 0x0 due to risk of
total supply reduction 59 BP Source code is decentralized $\checkmark$
$\checkmark$ Not using hard-coded addresses in the code 60 BP Funds can be
held only by user-controlled wallets $!$ Transferring tokens to users to avoid
creating a secondary market 61 BP Code logic is simple to understand
$\checkmark$ $\checkmark$ Avoiding code nesting which makes the code less
intuitive 62 BP All functions are documented $\checkmark$ Using NatSpec format
to explain expected behavior of functions 63 BP The Approval event is
correctly logged $\checkmark$ Emitting Approval event in the approve() method
64 BP Acceptable gas cost of the approve() function $!$ Checking for maximum
50000 gas cost when executing the approve() 65 BP Acceptable gas cost of the
transfer() function $!$ Checking for maximum 60000 gas cost when executing the
transfer() 66 BP Emitting event when state changes $\checkmark$ Emitting
Change event when changing state variable values 67 BP Use of unindexed
arguments $\checkmark$ $\checkmark$ $\checkmark$ Using indexed arguments to
facilitate external tools log searching 68 BP ERC-20 compliance $\checkmark$
$\checkmark$ $\checkmark$ $\checkmark$ $\checkmark$ Implementing all 6
functions and 2 events as specified in EIP-20 69 BP Conformance to naming
conventions $\checkmark$ Following the Solidity naming convention to avoid
confusion 70 BP Token decimal $\checkmark$ Declaring token decimal for
external apps when displaying balances 71 BP Locked money (Freezing ETH)
$\checkmark$ $\checkmark$ $\checkmark$ Implementing withdraw/reject functions
to avoid ETH lost 72 BP Malicious libraries $\checkmark$ Not using modifiable
third-party libraries 73 BP Payable fallback function $\checkmark$
$\checkmark$ Adding either fallback() or receive() function to receive ETH 74
BP Prefer external to public visibility level $\checkmark$ $\checkmark$
Improving the performance by replacing public with external 75 BP Token name
$\checkmark$ Adding a token name variable for external apps 76 BP Error
information in revert condition $\checkmark$ Adding error description in
require()/revert() to clarify the reason 77 BP Complex Fallback $\checkmark$
Logging operations in the fallback() to avoid complex operations 78 BP
Function Order $\checkmark$ Following fallback, external, public, internal and
private order 79 BP Visibility Modifier Order $\checkmark$ Specifying
visibility first and before modifiers in functions 80 BP Non-initialized
return value $\checkmark$ $\checkmark$ Not specifying return for functions
without output 6 81 BP Token symbol $\checkmark$ Adding token symbol variable
for usage of external apps 82 BP Allowance spending is possible $\checkmark$
Ability of token transfer by transferFrom() to transfer tokens on behalf of
another usercalc 99.5% success rate in performed audits by considering ’False
Positives’ and ’Informational’ checks as ’Passed’ (More details in section5)
100% 100% 100% 100% 100% 100% 97%

Table 4: Continuation of Table3.

##  5 Auditing Tools and ERC-20

Finally, we conducted an experiment on code auditing tools using the Solidity
implementation of TokenHook to understand the current state of automated
volunerabiliy testing. Our results illuminate the (in)completeness and error-
rate of such tools on one specific use-case (related work studies, in greater
width and less depth, a variety of use-cases [2]). We did not adapt older
tools that support significantly lower versions of the Solidity compiler
(e.g., Oyente). We concentrated on Solidity as Vyper analysis is currently a
paid services or penciled in for future support (e.g., Slither). The provided
version number is based on the GitHub repository; tools without a version are
web-based and were used in 2020:

  1. 1.

EY Smart Contract & Token Review by Ernst & Young Global Limited [26].

  2. 2.

SmartCheck by SmartDec [65].

  3. 3.

Securify v2.0 by ChainSecurity [71, 72].

  4. 4.

ContractGuard by GuardStrike [33].

  5. 5.

MythX by ConsenSys [8].

  6. 6.

Slither Analyzer v0.6.12 by Crytic [40].

  7. 7.

Odin by Sooho [66].

###  5.1 Analysis of audit results

A total of 82 audits have been conducted by these auditing tools that are
summarized in Tables 2, 3 and 4. Audits include best practices and security
vulnerabilities. To compile the list of 82, we referenced the knowledge-base
of each tool [71, 65, 8, 33, 40], understood each threat, manually mapped the
audit to the corresponding SWC registry [64], and manually determined when
different tools were testing for the same vulnerability or best practice
(which was not always clear from the tools’ own descriptions). Since each tool
employs different methodology to analyze smart contracts (e.g., comparing with
violation patterns, applying a set of rules, using static analysis, etc.),
there are false positives to manually check. Many false positives are not
simply due to old/unmaintained rules but actually require tool improvement. We
provide some examples in this section.

MythX detects Re-entrancy attack in the noReentrancy modifier. In Solidity,
modifiers are not like functions. They are used to add features or apply some
restriction on functions [63]. Using modifiers is a known technique to
implement Mutex and mitigate re-entrancy attack [73]. This is a false positive
and note that other tools have not identified the attack in modifiers.

ContractGuard flags Re-entrancy attack in transfer() function while
countermeasures (based on both CEI and Mutex 2.3) are implemented.

Slither detects two low level call vulnerabilities [39]. This is due to use of
call.value() that is recommend way of transferring ETH after Istanbul hard-
fork (EIP-1884). Therefore, adapting analyzers to new standards can improve
accuracy of the security checks.

SmartCheck recommends not using SafeMath and check explicitly where overflows
might be occurred. We consider this failed audit as false possible whereas
utilizing SafeMath is a known technique to mitigate over/under flows. It also
flags using a private modifier as a vulnerability by mentioning, “miners have
access to all contracts’ data and developers must account for the lack of
privacy in Ethereum”. However private visibility in Solidity concerns object-
oriented inheritance not confidentiality. For actual confidentiality, the best
practice is to encrypt private data or store them off-chain. The tool also
warns against approve() in ERC-20 due to front-running attacks. Despite
EIP-1884, it still recommends using of transfer() method with stipend of 2300
gas. There are other false positives such as SWC-105 and SWC-112 that are
passed by other tools.

Securify detects the Re-entrancy attack due to unrestricted writes in the
noReentrancy modifier [72]. Modifiers are the recommended approach and are not
accessible by users. It also flags Delegatecall to Untrusted Callee (SWC-112)
while there is no usage of delegatecall() in the code. It might be due to use
of SafeMath library which is an embedded library. In Solidity, embedded
libraries are called by JUMP commands instead of delegatecall(). Therefore,
excluding embedded libraries from this check might improve accuracy of the
tool. Similar to SmartCheck, it still recommends to use the transfer() method
instead of call.value().

EY token review considers decreaseAllowance and increaseAllowance as standard
ERC-20 functions and if not implemented, recognizes the code as vulnerable to
a front-running. These two functions are not defined in the ERC-20 standard
[27] and considered only by this tool as mandatory functions. There are other
methods to prevent the attack while adhering ERC-20 specifications (see
Rahimian et al. for a full paper on this attack and the basis of the
mitigation in TokenHook [55]). The tool also falsely detects the Overflow,
mitigated through SafeMath. Another identified issue is Funds can be held only
by user-controlled wallets. The tool warns against any token transfer to
Ethereum addresses that belong to smart contracts. However, interacting with
ERC-20 token by other smart contracts was one of the main motivations of the
standard. It also checks for maximum 50000 gas in approve() and 60000 in
transfer() method. We could not find corresponding SWC registry or standard
recommendation on these limitations and therefore consider them as
informational.

Odin raises Outdated compiler version issue due to locking solidity version to
0.5.11. We have used this version due to its compatibility with other auditing
tools.

| Auditing Tool |
---|---|---
ERC-20 Token |  | EY Token
---
Review
| Smart
---
Check
Securify |  | MythX
---
(Mythril)
| Contract
---
Guard
Slither | Odin |  Total issues
TokenHook | 9 | 11 | 4 | 2 | 10 | 2 | 2 | 40
TUSD | 20 | 11 | 2 | 1 | 14 | 16 | 6 | 70
PAX | 16 | 9 | 6 | 4 | 16 | 13 | 9 | 73
USDC | 17 | 9 | 6 | 5 | 18 | 15 | 10 | 80
INO | 11 | 10 | 14 | 8 | 14 | 24 | 12 | 93
HEDG | 10 | 28 | 11 | 1 | 29 | 24 | 16 | 119
BNB | 13 | 21 | 12 | 13 | 41 | 39 | 3 | 142
MKR | 11 | 27 | 38 | 9 | 16 | 34 | 18 | 153
LINK | 12 | 27 | 38 | 9 | 16 | 34 | 18 | 181
USDT | 12 | 29 | 8 | 17 | 46 | 55 | 30 | 197
LEO | 32 | 25 | 8 | 23 | 70 | 75 | 19 | 252

Table 5: Security flaws detected by seven auditing tools in TokenHook (the
proposal) compared to top 10 ERC-20 tokens by market capitalization in May
2020. TokenHook has the lowest reported security issues (occurrences).

###  5.2 Comparing audits

After manually overriding the false positives, the average percentage of
passed checks for TokenHook reaches to 99.5%. To pass the one missing check
and reach a 100% success rate across all tools, we prepared the same code in
Solidity version 0.8.4, however it cannot be audited anymore with most of the
tools.

We repeated the same auditing process on the top ten tokens based on their
market cap [24]. The result of all these evaluation have been summarized in
Table 5 by considering false positives as failed audits. This provides the
same evaluation conditions across all tokens. Since each tool uses different
analysis methods, number of occurrences are considered for comparisons. For
example, MythX detects two re-entrancy in TokenHook; therefore, two
occurrences are counted instead of one.

As it can be seen in Table 5, TokenHook has the least number of security flaws
(occurrences) compared to other tokens. We stress that detected security
issues for TokenHook are all false positives. We are also up-front that this
metric is not a perfect indication of security. The other tokens may also have
many/all false positives (such an analysis would be interesting future work),
and not all true positives can be exploited [51]. Mainly, we want to show this
measurement as being consistent with our claims around the security of
TokenHook. Had TokenHook, for example, had the highest number of occurrences,
it would be a major red flag.

##  6 Conclusion

98% of tokens on Ethereum today implement ERC-20. While attention has been
paid to the security of Ethereum DApps, threats to tokens can be specific to
ERC-20 functionality. In this paper, we provide a detailed study of ERC-20
security, collecting and deduplicating applicable vulnerabilities and best
practices, examining the ability of seven audit tools. Most importantly, we
provide a concrete implementation of ERC-20 called TokenHook 666Compatible
Solidity version of TokenHook (v. 0.5.11) deployed on Mainnet at
https://bit.ly/35FMbAf and the latest Solidity (v. 0.8.4) on Rinkeby
https://bit.ly/3tI139S. Vyper code at https://bit.ly/3dXaaPc.. It is designed
to be secure against known vulnerabilities, and can serve as a second
reference implementation to provide software diversity. We test it at Solidity
version 0.5.11 (due to the limitation of the audit tools) and also provide it
at version 0.8.4. Vyper implementation is also provided at version 0.2.8 to
make ERC-20 contracts more secure and easier to audit. TokenHook can be used
as template to deploy new ERC-20 tokens (e.g., ICOs, DApps, etc), migrate
current vulnerable deployments, and to benchmark the precision of Ethereum
audit tools.

## References

  * [1] Alex Beregszaszi, A.S.: Hardfork meta: Istanbul. https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1679.md (Dec 2019)
  * [2] di Angelo, M., Salzer, G.: A survey of tools for analyzing ethereum smart contracts. https://publik.tuwien.ac.at/files/publik_278277.pdf (Aug 2019)
  * [3] of Bits, T.: Watch your language: Our first vyper audit. https://blog.trailofbits.com/2019/10/24/watch-your-language-our-first-vyper-audit/ (Oct 2019)
  * [4] Breidenbach, L., Daian, P., Juels, A., Gun Sirer, E.: An in-depth look at the parity multisig bug. https://hackingdistributed.com/2017/07/22/deep-dive-parity-bug/ (Jul 2017)
  * [5] Bulgakov, K.: Three methods to send ether by means of solidity. https://medium.com/daox/three-methods-to-transfer-funds-in-ethereum-by-means-of-solidity-5719944ed6e9 (Feb 2018)
  * [6] Chen, T., Zhang, Z., Li, Z.: Tokenscope: Automatically detecting inconsistent behaviors of cryptocurrency tokens in ethereum. http://www4.comp.polyu.edu.hk/~csxluo/TokenScope.pdf (Nov 2019)
  * [7] Clark, J., Bonneau, J., Miller, A., Kroll, J.A., Felten, E.W., Narayanan, A.: On decentralizing prediction markets and order books. In: WEIS (2014)
  * [8] ConsenSys: Mythx swc coverage. https://mythx.io/swc-coverage/ (Nov 2019)
  * [9] Consensys: Tokens. https://github.com/ConsenSys/Tokens (Jun 2020)
  * [10] Coverdale, C.: Transaction-ordering attacks. https://medium.com/coinmonks/solidity-transaction-ordering-attacks-1193a014884e (Mar 2018)
  * [11] Cremer, L.: Missing return value bug — at least 130 tokens affected. https://medium.com/coinmonks/missing-return-value-bug-at-least-130-tokens-affected-d67bf08521ca (Jun 2018)
  * [12] Deployer, B.: Beautychain (bec). https://etherscan.io/address/0xc5d105e63711398af9bbff092d4b6769c82f793d (Jun 2020)
  * [13] Diligence, C.: Token implementation best practice. https://consensys.github.io/smart-contract-best-practices/tokens/ (Mar 2020)
  * [14] Diligence, C.: Ethereum smart contract security best practices. https://consensys.github.io/smart-contract-best-practices/ (Jan 2021)
  * [15] documentation, E.: Re-entrancy. https://solidity.readthedocs.io/en/latest/security-considerations.html#re-entrancy (Jan 2021)
  * [16] documentation, S.: Security considerations. https://solidity.readthedocs.io/en/latest/security-considerations.html (Jan 2020)
  * [17] Documentation, S.: Checks effects interactions pattern. https://docs.soliditylang.org/en/latest/security-considerations.html#use-the-checks-effects-interactions-pattern (Aug 2020)
  * [18] Durov, P.: What was ton and why it is over. https://telegra.ph/What-Was-TON-And-Why-It-Is-Over-05-12 (May 2020)
  * [19] Eskandari, S., Moosavi, S., Clark, J.: Sok: Transparent dishonesty: front-running attacks on blockchain. International Conference on Financial Cryptography and Data Security 1, 380 (2019)
  * [20] Ethereum: Project repository. https://github.com/ethereum (May 2014)
  * [21] Ethereum: Solidity — solidity documentation. https://solidity.readthedocs.io/en/latest/ (Jan 2020)
  * [22] Ethereum: Receive ether function. https://docs.soliditylang.org/en/latest/contracts.html#receive-ether-function (Jun 2021)
  * [23] Ethereum: Solidity — solidity documentation. https://solidity.readthedocs.io/en/latest/contracts.html?highlight=library#libraries (Jan 2021)
  * [24] EtherScan: Token tracker. https://etherscan.io/tokens?sortcmd=remove&sort=marketcap&order=desc (Apr 2020)
  * [25] solidity-by example.org: Solidity by example. https://solidity-by-example.org/0.6/hacks/self-destruct/ (Apr 2021)
  * [26] EY: Token review. https://review-tool.blockchain.ey.com (Sep 2019)
  * [27] Fabian Vogelsteller, V.B.: Erc-20 token standard. https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md (Nov 2015)
  * [28] Ferreira Torres, C., Schutte, J., State, R.: Osiris: Hunting for integer bugs in ethereum smart contracts. https://dl.acm.org/doi/10.1145/3274694.3274737 (Dec 2018)
  * [29] Finley, K.: A $50 million hack just showed that the dao was all too human — wired. https://www.wired.com/2016/06/50-million-hack-just-showed-dao-human/ (Sep 2016)
  * [30] Forrest, S., Somayaji, A., Ackley, D.H.: Building diverse computer systems. In: Proceedings. The Sixth Workshop on Hot Topics in Operating Systems (Cat. No.97TB100133). pp. 67–72 (1997). https://doi.org/10.1109/HOTOS.1997.595185
  * [31] Forrest, S., Hofmeyr, S.A., Somayaji, A.: Computer immunology. Commun. ACM 40(10), 88–96 (Oct 1997). https://doi.org/10.1145/262793.262811, https://doi.org/10.1145/262793.262811
  * [32] GmbH, G.F.: Golem network token. https://etherscan.io/address/0xa74476443119A942dE498590Fe1f2454d7D4aC0d#code (Nov 2016)
  * [33] GuardStrike: Contractguard knowledge-base. https://contract.guardstrike.com/#/knowledge (Mar 2020)
  * [34] Hale, T.: Resolution on the eip20 api approve / transferfrom multiple withdrawal attack #738. https://github.com/ethereum/EIPs/issues/738 (Oct 2017)
  * [35] Holst Swende, M.: Repricing for trie-size-dependent opcodes. https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1884.md (Mar 2019)
  * [36] Huashan Chen, Marcus Pendleton, L.N., Xu, S.: A survey on ethereum systems security: Vulnerabilities, attacks and defenses. https://arxiv.org/pdf/1908.04507.pdf (Aug 2019)
  * [37] Jain, S.: All you should know about libraries in solidity. https://medium.com/coinmonks/all-you-should-know-about-libraries-in-solidity-dd8bc953eae7 (Sep 2018)
  * [38] Ji, R., He, N., Wu, L., Wang, H.: Deposafe: Demystifying the fake deposit vulnerability. https://arxiv.org/pdf/2006.06419.pdf (Jun 2020)
  * [39] Josselin, F.: Slither – a solidity static analysis framework. https://blog.trailofbits.com/2018/10/19/slither-a-solidity-static-analysis-framework/ (Oct 2018)
  * [40] Josselin, F.: Slither – detector documentation. https://github.com/crytic/slither/wiki/Detector-Documentation#name-reused (Mar 2020)
  * [41] Kaleem, M., Mavridou, A., Laszka, A.: Vyper: A security comparison with solidity based on common vulnerabilities. In: Proceedings of the 2nd Conference on Blockchain Research and Applications for Innovative Networks and Services (BRAINS 2020) (Jun 2020)
  * [42] Lando, G.: Guy lando’s knowledge list. https://github.com/guylando/KnowledgeLists/blob/master/EthereumSmartContracts.md (May 2019)
  * [43] Luu, L., Chu, D.H., Olickel, H., Saxena, P., Hobor, A.: Making smart contracts smarter. https://dl.acm.org/ft_gateway.cfm?id=2978309&ftid=1805715&dwn=1&CFID=86372769&CFTOKEN=b697c89273876526-8CBDF39B-A89A-31D2-F565B24919F796C6 (Oct 2016)
  * [44] Manning, A.: Comprehensive list of known attack vectors and common anti-patterns. https://github.com/sigp/solidity-security-blog (Nov 2019)
  * [45] OpenZeppelin: Proxy patterns. https://blog.openzeppelin.com/proxy-patterns/ (Apr 2018)
  * [46] OpenZeppelin: Contracts. https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol (Jun 2020)
  * [47] OpenZeppelin: Contracts. https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol (Jun 2020)
  * [48] Palladino, S.: The parity wallet hack explained. https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7/ (July 2017)
  * [49] Parity: Security alert. https://www.parity.io/security-alert-2/ (Nov 2018)
  * [50] PeckShield: Alert: New batchoverflow bug in multiple erc20 smart contracts. https://blog.peckshield.com/2018/04/22/batchOverflow/ (Apr 2018)
  * [51] Perez, D., Livshits, B.: Smart contract vulnerabilities: Vulnerable does not imply exploited. https://www.usenix.org/system/files/sec21summer_perez.pdf (Aug 2018)
  * [52] Quintal, J.: Building robust smart contracts with openzeppelin. https://www.trufflesuite.com/tutorials/robust-smart-contracts-with-openzeppelin (Aug 2017)
  * [53] Qureshi, H.: A hacker stole $31m of ether — how it happened, and what it means. https://www.freecodecamp.org/news/a-hacker-stole-31m-of-ether-how-it-happened-and-what-it-means-for-ethereum-9e5dc29e33ce/ (Jul 2017)
  * [54] Rahimian, R.: Overflow attack in ethereum smart contracts. https://blockchain-projects.readthedocs.io/overflow.html (Dec 2018)
  * [55] Rahimian, R., Eskandari, S., Clark, J.: Resolving the multiple withdrawal attack on erc20 tokens. https://arxiv.org/abs/1907.00903 (Jul 2019)
  * [56] Reinno: A new way to own and invest in real estate. https://reinno.io/tokenization.html (Jun 2020)
  * [57] Reporting, A.: Generate meaningful knowledge from ethereum. https://reports.aleth.io/ (Jul 2020)
  * [58] Roan, A.: 7 openzeppelin contracts you should always use. https://medium.com/better-programming/7-openzeppelin-contracts-you-should-always-use-5ba2e7953cc4 (Apr 2020)
  * [59] Rodler, M., Li, W., Karame, G., Davi, L.: Sereum: Protecting existing smart contracts against re-entrancy. https://arxiv.org/pdf/1812.05934.pdf (Dec 2018)
  * [60] Rubixi: Rubixi contract. https://etherscan.io/address/0xe82719202e5965Cf5D9B6673B7503a3b92DE20be#code (Mar 2016)
  * [61] Sedgwick, K.: Myetherwallet servers are hijacked. https://news.bitcoin.com/myetherwallet-servers-are-hijacked-in-dns-attack/ (Apr 2018)
  * [62] Shirshova, N.: The benefits of “buy” and “sell”. https://medium.com/orbise/the-benefits-of-buy-and-sell-token-functions-dcea536aaf7c (Dec 2018)
  * [63] Simon, G.: Solidity modifier tutorial - control functions with modifiers. https://coursetro.com/posts/code/101/Solidity-Modifier-Tutorial---Control-Functions-with-Modifiers (Oct 2017)
  * [64] SmartContractSecurity: Smart contract weakness classification and test cases. https://swcregistry.io/ (Jun 2020)
  * [65] SmartDec: Knowledge-base. https://github.com/smartdec/smartcheck (Sep 2018)
  * [66] Sooho: Verify a smart contract. https://odin.sooho.io/ (Mar 2020)
  * [67] Spagnuolo, F.: Ethereum in depth, part 2. https://blog.openzeppelin.com/ethereum-in-depth-part-2-6339cf6bddb9/ (Jul 2018)
  * [68] Szego, D.: Solidity security patterns - forcing ether to a contract. http://danielszego.blogspot.com/2018/03/solidity-security-patterns-forcing.html (Mar 2018)
  * [69] Tanner, J.: Summary of ethereum upgradeable smart contract r&d — part 1–2018. https://blog.indorse.io/ethereum-upgradeable-smart-contract-strategies-456350d0557c (Mar 2018)
  * [70] Tracker, T.: Erc-20 tokens. https://etherscan.io/tokens (Jul 2021)
  * [71] Tsankov, P.: Securify v2.0. https://github.com/eth-sri/securify2 (Jan 2020)
  * [72] Tsankov, P., Dan, A., Drachsler-Cohen, D., Gervais, A.: Securify: Practical security analysis of smart contracts. https://arxiv.org/pdf/1806.01143.pdf (Aug 2018)
  * [73] Venturo, N., Giordano, F.: Reentrancy guard. https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/ReentrancyGuard.sol (Oct 2017)
  * [74] Vessenes, P.: Monolithdao. https://github.com/MonolithDAO/token/blob/master/src/Token.sol (Apr 2017)
  * [75] Vladimirov, M.: Attack vector on erc20 api (approve/transferfrom methods) and suggested improvements. https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 (Nov 2016)
  * [76] Vyper: Pythonic smart contract language for the evm. https://github.com/vyperlang/vyper (Apr 2021)
  * [77] wikipedia: Mutex. en.wikipedia.org/wiki/Mutual_exclusion (Jan 2019)
  * [78] Wikipedia: Liberty reserve. https://en.wikipedia.org/wiki/Liberty_Reserve (Jun 2020)
  * [79] Wood, G.: Ethereum: a secure decentralised generalised transaction ledger. http://gavwood.com/paper.pdf (Mar 2016)
  * [80] Zalecki, M.: Create and distribute your erc20 token with openzeppelin. https://www.tooploox.com/blog/create-and-distribute-your-erc20-token-with-openzeppelin (Aug 2018)