Wallet Contracts on Ethereum

01/19/2020
by   Monika di Angelo, et al.
TU Wien
0

In the area of blockchains, a wallet is anything that manages the access to cryptocurrencies and tokens. Off-chain wallets appear in different forms, from paper wallets to hardware wallets to dedicated wallet apps, while on-chain wallets are realized as smart contracts. Wallet contracts are supposed to increase trust and security by being transparent and by offering features like daily limits, approvals, multiple signatures, and recovery mechanisms. Ethereum is the most prominent platform for both, tokens and smart contracts, and thus also for on-chain wallets. Our work aims at a better understanding of Ethereum on-chain wallets, which represent one of the most frequent types of smart contracts. By analyzing source code, bytecode, and execution traces, we derive usage scenarios and patterns. We discuss several methods for identifying wallet contracts in a semi-automatic manner by looking at the deployed bytecodes and their interaction patterns. We extract blueprints for wallets and thereby compile a ground truth. Furthermore, we differentiate characteristics of wallets in use, and group them into six types. We provide numbers and temporal perspectives regarding the creation and use of wallets. We analyze the data of the Ethereum main chain up to block 8450000, mined on August 30, 2019.

READ FULL TEXT VIEW PDF
POST COMMENT

Comments

There are no comments yet.

Authors

page 1

page 2

page 3

page 4

07/17/2021

Rectifying Administrated ERC20 Tokens

The developers of Ethereum smart contracts often implement administratin...
04/04/2018

Executable Operational Semantics of Solidity

Bitcoin has attracted everyone's attention and interest recently. Ethere...
07/15/2021

Methodology and Analysis of Smart Contracts in Blockchain-Based International Trade Application

Blokchain is used in a variety of applications where trustworthy computi...
06/04/2018

Securify: Practical Security Analysis of Smart Contracts

Permissionless blockchains allow the execution of arbitrary programs (ca...
12/06/2021

Detecting DeFi Securities Violations from Token Smart Contract Code with Random Forest Classification

Decentralized Finance (DeFi) is a system of financial products and servi...
01/29/2018

The Scalability of Trustless Trust

Permission-less blockchains can realise trustless trust, albeit at the c...
11/28/2019

Competitive equilibria between staking and on-chain lending

Proof of Stake (PoS) is a burgeoning Sybil resistance mechanism that aim...
This week in AI

Get the week's most popular data science and artificial intelligence research sent straight to your inbox every Saturday.

1 Introduction

Wallets keep valuables, credentials, and items for access rights (like cash, licenses, credit cards, key cards) in one place, for ease of access and use. On the blockchain, cryptocurrencies play a role similar to cash, while cryptographic tokens are a universal tool for handling rights and assets. Software wallets manage the cryptographic keys required for authorization and implement the protocols for interacting with blockchains in general and smart contracts (on-chain programs) in particular.

On-chain wallets are smart contracts that hold cryptocurrencies and access to tokens and that may offer advanced methods for manipulating the assets. Simply by introducing the role of an ‘owner’ it becomes possible to transfer all assets of an on-chain wallet transparently and securely in a single transaction. More refined methods include multi-signature wallets, which grant access only if sufficiently many owners sign.

Regarding the number of transactions and public availability of data, Ethereum is the major platform for smart contracts, and thus also for tokens and on-chain wallets. This paper investigates the usage and purpose of on-chain wallets on the main chain of Ethereum qualitatively as well as quantitatively. In particular, we address the following questions.

  1. How can deployed wallets be identified from transaction data?

  2. Regarding functionality, which types of wallets are deployed?

  3. When and in which quantities are wallets created, and how many are actually used?

  4. What is the role of wallets in the overall Ethereum smart contract landscape?

Methodologically, we start from the source code of wallets and determine characteristic functions. Then we search the deployed bytecode for variants of the wallets with the same profile. Some wallets can also be detected by their creation history or by the way they interact with other contracts. We group the wallets according to their functionality and collect creation and usage statistics from the blockchain data. Finally, we relate wallets to other frequently occurring contract types.

Regarding their number, on-chain wallets form a substantial part of the smart contracts on the chain. This work thus contributes to a better understanding of what smart contracts on Ethereum are actually used for. Moreover, the collection of wallet features and blueprints may serve as a resource when designing further decentralized trading apps. Our methods for detecting wallets and analyzing their activities may help in accessing the liveliness of on-chain projects. E.g., a temporal view on the use of wallets is more informative than just the number of wallets initially deployed.

Roadmap

Section 2 clarifies terms and presents our methods for bytecode analysis. Section 3 discusses methods for the identification of potential on-chain wallets. Section 4 describes characteristic features of wallets and categorizes them into types. Section 5 analyzes interactions of wallets. Section 7 compares our approach to related work. Finally, section 8 concludes with a summary of our results.

2 Terms, Bytecode Analysis, and Tools

We assume the reader to be familiar with blockchain essentials. For Ethereum specifics, we refer to [1, 2, 3].

2.1 Terms and Data

Ethereum distinguishes between externally owned accounts, often called users, and contract accounts or simply contracts. Accounts are uniquely identified by addresses of 20 bytes. Users can issue transactions (signed data packages) that transfer value to users and contracts, or that call or create contracts. These transactions are recorded on the blockchain. Contracts need to be triggered to become active, either by a transaction from a user or by a call (a message) from another contract. Messages are not recorded on the blockchain, since they are deterministic consequences of the initial transaction. They only exist in the execution environment of the Ethereum Virtual Machine (EVM) and are reflected in the execution trace and potential state changes. We use ‘message’ as a collective term for any (external) transaction or (internal) message.

Unless stated otherwise, statistics refer to the Ethereum main chain up to block 8 450 000 (mined on Aug 30, 2019). We abbreviate factors of 1 000 and 1 000 000 by the letters k and M, respectively.

To a large extent, our analysis is based on the EVM bytecode of deployed contracts. If available we use verified source code from etherscan.io, but relying solely on such contracts would bias the results: in contrast to 18 M successful create operations, there are verified source codes for 70 k addresses (0.4 %) only.

2.2 Code Skeletons

To detect functional similarities between contracts we compare their skeletons. These are obtained from the bytecodes of contracts by replacing meta-data, constructor arguments, and the arguments of push operations uniformly by zeros and by stripping trailing zeros. The rationale is to remove variability that has little impact on the functional behavior, like the swarm hashes added by the Solidity compiler or hard-coded addresses of companion contracts. Skeletons allow us to transfer knowledge gained about one contract to others with the same skeleton. Note that the 18 M contract deployments so far give rise to 252 k distinct bytecodes and just 119 k distinct skeletons. This is still a large number, but manageable by exploiting creation histories and the similarity of skeletons. We are able to relate 6.7 M of these deployments to some source code on etherscan.io, an increase from 0.4 to 37 %.

2.3 Contract Interfaces

Most contracts in the Ethereum universe adhere to the ABI standard [4], which identifies functions by signatures that consist of the first four bytes of the Keccak-256 hash of the function names and the parameter types. Thus, the bytecode of a contract contains instructions to compare the first four bytes of the call data to the signatures of its functions. To understand the implemented interface of a contract, we extract it from the bytecode, and then try to restore the corresponding function headers.

2.3.1 Interface Extraction

We developed a pattern-based tool to extract the interface contained in the bytecode. As ground truth for validation, we used the combination of verified source code, corresponding bytecode, and ABI provided by Etherscan. The signatures extracted by our tool differed from the ground truth in 42 cases. Manual inspection revealed that our tool was correct also in these cases, whereas the ABIs did not faithfully reflect the signatures in the bytecode (e.g. due to compiler optimization or library code).

Before applying the tool to all deployed bytecodes, a few considerations are due. Apart from very few LLL or Vyper contracts, the validation set consists almost exclusively of bytecode generated by the Solidity compiler, covering virtually all its releases (including early versions). Regarding the large group of 9.6 M deployed contracts (220 k codes, 107 k skeletons) generated by the Solidity compiler, it is thus representative.111Deployed code generated by solc can be identified by the first few instructions. It starts with one of the sequences 0x6060604052, 0x6080604052, 0x60806040818152, 0x60806040819052, or 0x60806040908152. In the case of a library, this sequence is prefixed by a PUSH instruction followed by 0x50 or 0x3014.

Another interesting group of deployed contracts consists of 5.2 M short contracts (18 k codes, only 271 skeletons) without entry points. They are mainly contracts for storing gas (gasToken), but also proxies (contracts redirecting calls elsewhere) and contracts involved in attacks. As a last group of deployed contracts, we are left with remaining 595 codes. For them, our tool shows an error rate of 8 %, estimated from a random sample of 60 codes that we manually checked.

2.3.2 Interface Restoration

To understand the purpose of contracts we try to recover the function headers from the signatures. As the signatures are partial hashes of the headers, we use a dictionary of function headers with their 4-byte signatures (collected from various sources), which allows us to obtain a function header for 59 % of the 254 k distinct signatures on the main chain.222

An infinity of possible function headers is mapped to a finite number of signatures, so there is no guarantee that we have recovered the original header. The probability of collisions is low, however. E.g., of the 322 k signatures in our dictionary only 19 appear with a second function header.

Since signatures occur with varying frequencies and codes are deployed in different numbers, this ratio increases to 91 % (or 89 %) when picking a code (or a deployed contract) at random.

2.4 Third Party Tools

We employ the Ethereum client parity in archive mode to obtain the execution traces. PostgreSQL serves as our primary database that stores the messages extracted from the traces as well as information on the contracts. For analyzing contract interactions as graphs, we use the graph database Neo4j. Furthermore, we utilize etherscan.io for information on deployed contracts and matplotlib for plotting.

3 Identifying Potential Wallets

We define a proper wallet to be a contract whose sole purpose is to manage assets. In contrast, contracts that serve other purposes as well beyond managing assets are termed non-wallet contracts. The latter group contains all applications that require Ether or tokens.

Our approach first identifies potential wallet contracts and then checks if the bytecode actually implements a proper wallet. In this section, we discuss four methods to identify potential wallets, of which we utilize the last three in combination for the first step. In section 4 we elaborate on the second step, the check whether they implement a proper wallet.

3.1 Wallets as Recipients of Ether or Tokens

In a broad sense, any address that has sent or received Ether or tokens at some point in time may be called a wallet: on-chain wallet in case of a contract address and off-chain wallet otherwise. Addresses transferring Ether can be easily identified by looking at the senders and receivers of successful messages with an Ether value greater than zero. Token transfers are harder to detect, as the addresses receiving tokens are not directly involved in the transfer.

We identify token holders as the addresses that appear in calls of the methods transfer(address,uint256), transferFrom(address,address,uint256), mint(address,uint256), balanceOf(address) or in events of the type Transfer(address,address,uint256).

only Ether only tokens both neither
contracts 1.5 M 5.0 M 0.3 M 11.1 M
users 33.3 M 14.0 M 23.0 M
Table 1: Accounts having held Ether or tokens

Table 1 lists the number of accounts that ever held Ether or tokens. The number of user accounts that never held Ether or tokens is difficult to assess. According to etherscan.io, the number of addresses in the state was 74.3 M. However, as accounts no longer in use are removed from the state space, it is smaller than the sum of the numbers in the table above.

Limitations. The liberal definition of wallets as senders or receivers of assets gives a first idea of the quantities involved. As we will see below, many on-chain wallets have not yet been used and thus cannot be detected by the above method. Inherently, this method yields many non-wallets, while it misses the high amount of unused proper wallets. Thus, we did not use this method for the further analyses.

3.2 Identifying Wallets by their Interface

Given the source code of a wallet contract, we can use its bytecode and partially restored ABI to identify similar contracts on the chain. Employing the methods described in section 2, we first locate all deployed contracts with identical bytecode or skeleton.

In order to capture variants of the already found wallets, we then look for contracts that implement the same characteristic functions as a given wallet. This is achieved by allowing for some fuzziness regarding additional signatures. For this, the choice of signatures is crucial. One has to avoid using unspecific signatures for the search or being too liberal with additional signatures. This can be achieved by checking the functionality of contracts, e.g. by reading the bytecode or by looking at the interaction patterns of deployed contracts. As we will see, the number of wallet blueprints is small enough to actually read its code.

Limitations. This approach misses contracts that do not adhere to the ABI specification. Moreover, contracts with similar signatures may implement different functionality, and thus may not be related.

3.3 Identifying Wallets by their Factory

Wallets appearing in large quantities are usually deployed by a small number of contracts (so-called factories) or external addresses. Factories can be located either by the same methods as wallets, or by specifically looking for addresses that create many other contracts and by verifying that the latter are indeed wallets. Once the factories are identified, a database query is sufficient to select all wallets created by them.

Limitations. When looking for factories, we may encounter the same problems as for the wallet interfaces. Otherwise, this method is robust as the signatures and the interaction patterns of factories are distinctive. This approach misses wallets not deployed by factories.

3.4 Identifying Wallets by their Name

To detect wallets in a more systematic fashion and to include also less popular ones, we scanned the 70 k source codes on etherscan.io for contracts containing the string ‘wallet‘ or ‘Wallet’ in their name.

Limitations.

This approach is a heuristic that yields false positives and misses wallets named differently. Again, reading the bytecode or looking at the interaction patterns of the deployed contracts is indispensable.

3.5 Combination of Identification Methods

We started with a few known wallets that had Solidity sources. As some wallets are deployed in large quantities, we looked for (their) factories. For some of these, we could also find Solidity sources. These sources served as a test set for a first verification of both, the interface method including skeletons and fuzzing and the factory method. Finally, we scanned all verified source codes for wallets contracts, and used the resulting set of contracts as a starting point for the fuzzed interface method. To this, we added the wallets found by the factory method.

We would like to mention, that – in retrospect – most wallets can be identified uniquely by a small set of functions they implement, often just one function.

Limitations. The combination of the three methods (interface, factory, name) might still miss some wallets when they do not adhere to the ABI specification, are not deployed by a factory, and have non-descript contract names.

4 Classification and Comparison of Wallets

In this section, we base our discussion on the functionalities of wallets. First, we detail our definition of a proper wallet. Then, we determine and compare types of proper wallets.

handles control security life ext.
Type # Found Name

Ether

ERC20

advanced tokens

owner administration

cosigner (2-of-2)

multi signature

third party control

forwarding of assets

flexible transaction

daily limit

time lock

recovery mechanism

safe mode, pause, halt

destroy

update logic

module administration

Simple 9 250 AutoWallet [5]
4 635 BasicWallet [6]
3 634 ConsumerWallet [7]
46 340 SmartWallet [8]
1 436 SpendableWallet [9] (✓)
202 TimelockedWallet [10] (✓)
MultiSig 11 Argent [11]
135 457 BitGo [12]
10 150 Gnosis/ConSensys [13]
96 Ivt [14]
3 391 Lundkvist [15]
995 NiftyWallet [16]
44 235 Parity/Eth/Wood [17]
822 TeambrellaWallet [18] (✓)
131 Unchained Capital [19]
Forwarder 1 087 257 BitGo [20]
2 520 IntermediateWallet [21] (✓)
527 SimpleWallet2 [22]
Controlled 2 488 845 Bittrex [23] (✓)
Update 2 862 Eidoo [24]
3 926 LogicProxyWallet [25]
Smart 4 098 Argent [26]
15 749 Dapper [27]
1 065 Gnosis [28]
Table 2: Characteristics of Wallet Contracts

4.1 Proper Wallet

The main functionality of wallets consists in funding the wallet as well as in submitting, confirming, and executing transactions to transfer Ether and tokens. Some wallets offer additional features. To distinguish proper wallet contracts from non-wallet contracts, we define that optional wallet functions (beyond the transfer of assets) must fall into the categories: administration and control, security mechanisms, lifecycle functions, and extensions.

Whether an implemented function belongs to one of these categories was decided upon reading the code. This was possible due to the heavy code reuse factor for wallets. Employing the technique of skeletons in combination with the fuzzed interface method (cf. sections 2 and 3), we had to examine 631 skeletons that could be grouped into 24 blueprints for wallets.

4.2 Types of Wallets

The identified 24 variants of proper wallets (blueprints) differ in functionality and number of deployments. Based on their features, we assign them to one of six groups.

4.2.1 Simple Wallets

provide little extra functionality beyond handling Ether and tokens. A sample can be found at [8].

4.2.2 MultiSig Wallets

require that out of owners sign a transaction before it is executed. Usually the required number of signatures () is smaller than the total number of owners (), meaning that not all owners have to sign. In most cases, the set of owners and the number of required signatures can be updated.

4.2.3 Forwarder Wallets

forward the assets they receive to some main wallet. They may include owner management. BitGo employs large numbers of forwarder wallets in combination with its variant of a multiSig wallet [12].

4.2.4 Controlled Wallets

can be compared to traditional bank accounts. They are assigned to customers, who can use them as target of transfers, but the control over the account remains with the bank. Withdrawals are executed by the bank on behalf of the customer. This construction allows to comply with legal regulations that may restrict transactions. Regarding the number of deployments, controlled wallets are the most common type.

4.2.5 Update Wallets

provide a mechanism to update their main features at the discretion of the owner. A sample can be found at [25, 24]

4.2.6 Smart Wallets

offer enhanced features like authorization mechanism for arbitrary transactions, recovery mechanisms for lost keys, modular extension of features, or advanced token standards.

4.3 Features of Wallets

Table 2 shows for each identified wallet blueprint its type, number of deployed instances, name, reference to the source or bytecode, as well as an overview of the implemented features as detailed below.

Ether. To handle Ether a wallet has to be able to receive and transfer it. Some wallets are intended for tokens only and thus refuse Ether. But even then well designed wallets provide a withdraw method, since some Ether transfers (like mining rewards and self-destructs) cannot be blocked.

ERC20 tokens. For ERC20 token transfers, the holding address initiates the transfer by sending to the respective token contract the address of the new holder who is not informed about this change. No provisions have to be made to receive such tokens. However, to s(p)end the tokens a wallet needs to provide a way to call a transfer method of the token contract.

Advanced tokens require the recipient to provide particular functions that are called before the actual transfer of the token.

Owner administration enables the transfer of all assets in a wallet to a new owner in one sweep without revealing private keys. With an off-chain wallet, one has to transfer each asset separately or share the private key with the new owner.

MultiSig wallets face a trade-off between flexibility, transaction costs, and transparency. Each Ethereum transaction carries only one signature. To supply more, the wallet either has to be called several times by different owners (incurring multiple transaction fees), or the signatures have to be computed off-chain by a trusted app and supplied as data of a single transaction. A wallet may offer a few fixed multSig actions that are selected transparently via the entry point, or there may be a single entry point that admits the execution of arbitrary calls. The latter case requires a trusted app that composes the low-level call data off-chain in a manner transparent for the owners who are supposed to approve it.

Cosigner is a form of MultiSig where exactly two signatures are required. Moreover, it can be employed for implementing further functionality via another contract that acts as cosigner. This may include multiSig or off-chain signing.

Third party control means that the actual control over the wallet stays with a central authority.

Forwarding wallets are additional addresses for receiving assets that are transferred to a main wallet.

Flexible transactions means that the wallet is able to execute arbitrary calls after adequate authorization.

Daily limits and time locking restrict the access to the assets based on time. Spending more than a daily limit may e.g. require additional authorization. Time locks are useful if assets should be used only at a later point in time, after a vesting period, like after an ICO, for a smart will, or a trust fund.

Recovery mechanisms provision against lost or compromised credentials.

Life cycle management enable wallets to be put into safe mode, paused, or halted. Early wallets were able to self-destruct, which results in the loss of assets sent thereafter. When put on hold, a wallet can still reject transfer attempts.

Update logic enables to switch to a newer version of the wallet logic. This is implemented by means of proxy wallets, which derive their functionality from library code stored elsewhere, and keeps the wallets small and cheap to deploy.

Module administration offers the inclusion or deselection of modules to customize the wallet to user needs. This reprsents a modular and more fine-grained version of update logic.

5 Interaction Analysis

In this section, we examine the usage of wallets, differentiate token holdings, and discuss the role of wallets within the smart contracts landscape.

The 8.45 M blocks of the Ethereum main chain contain 530 M transactions, which gave rise to almost 1 293 M messages and 17.9 M successfully created contracts. About 3.9 M of them (21 %) are wallets. The wallets received 19.2 M and sent 40.5 M calls, with 2 M inter-wallet calls. In total, 57.7 M messages (4.5 %) involve wallets.

5.1 Creation and Usage of Wallets over Time

Figure 1 depicts the number of wallets created per 100 k blocks (about two weeks) as a stack plot, differentiating the wallets according to their later usage: wallets used for tokens as well as Ether, wallets used for only one of them, and unused wallets. (See section 3.1 for a discussion of how to identify token and Ether holders.)

Figure 1: Creation and usage of all wallets.

Of the 3.9 M wallets, 68 % have not been used so far (2.6 M, grey). The other wallets are either used for tokens (529 k, magenta) or for Ether (626 k, cyan), but only a few wallets are used for both (91 k, black).333Initially, we considered also the property of having received a call as a further sign of activity. However, it strongly correlates with the other activities, so we omitted it for the sake of a clearer presentation.

Figure 2: Creation and usage of controlled wallets (above) and forwarder wallets (below).

When comparing the two most common wallet types, controlled and forwarder wallets, we notice a marked difference regarding their usage (Fig. 2). Controlled wallets (2.5 M, upper part) are used for Ether as well as tokens, while forwarder wallets (1.1 M, lower part) are used predominantly for Ether. Both show a large portion of unused wallets (grey), namely 62 % for the controlled and 83 % for the forwarder wallets.

The other types of wallets were deployed in smaller numbers (Fig. 3). For the first two years, only multiSig wallets (yellow) were created. Simple wallets (green) started to appear in the second half of 2017 after block 4.4 M. Update wallets (black) are as recent as block 5.9 M (mid 2018), while smart wallets (brown) start towards the end of 2018 after block 6.5 M. All of them are still being created.

Figure 3: Creation of simple, multiSig, update, and smart wallets.

5.2 Token Holdings

Most wallets are designed for token management. Still, only 0.62 M wallets (16 %) have so far received at least one token, while 3.25 M (84 %) did not. Even though the percentage of wallets without a single token varies with the type, it is always more than 60 %. If wallets do hold tokens, the number of different tokens is small for the majority of them. Less than 3300 wallets each held more than 10 different tokens. Only single wallets held substantial amounts of different tokens over time, the maximum being 705.

6 Wallets in the Landscape of Contracts

Smart contracts may perform their tasks stand-alone or in cooperation with companion contracts, with the number of contracts belonging to one application going up to a million in extreme cases (like for gasTokens or wallets). The landscape is as diverse as the purpose of smart contracts. We find exchanges, markets, wallets, tokens, games, attackers, and all kinds of dApps implementing part of their logic on-chain. Delineating the border between all of these groups, but especially between applications turns out to be difficult. We assume that applications are connected to each other mainly over general services like wallets.

6.1 Graph View

In order to analyze the landscape of smart contracts, their interactions in form of calling each other provide useful information. For this, we build the call graph from the execution trace (as provided by the parity client in archive mode), where the contracts serve as nodes that are connected by an edge whenever the trace lists a call from one contract to another. After removing singletons (i.e. contracts that are called just by users or not all) and reducing multiple edges between two contracts to just one edge, we are left with 10.3 M contracts as nodes and 13.0 M calls as edges. This graph consists of 12.9 k connected components, with the largest one containing virtually all nodes (9.7 M, 94 %), while most components have less than 100 nodes. The high interconnection indicates that applications do not separate naturally.

Proper Wallets. To test the assumption that wallets act as a major connecting element, we additionally remove all contracts from the graph that we identified as wallets. This further reduces the graph by 1.2 M nodes and 2.1 M edges. However, the largest component still consists of 8.5 M nodes (93 %), while the number of components slightly increases to 15.1 k. We conclude that wallets probably contribute to the cohesion of the graph but are not solely responsible for it.

Token holders. If we take any token holder to be a wallet and repeat the analysis, the graph falls apart. The remaining 5.1 M nodes yield 4.4 M graph components, the largest one containing 158 k nodes (3 % of all nodes). Thus, for a liberal definition of wallet, the assumption of wallets serving as cohesive holds true. However, removing all token holders is probably too coarse, as we remove exchanges, markets, applications that employ their own token, and token contracts in general.

7 Comparison to Related Work

Wallets

In their analysis of ERC20 token trading, the authors of [29] take any address holding tokens to be a wallet. They demonstrate that the token trading network shows power-law properties and that it is decentralized, diverse, and mature. Off-chain wallets are compared extensively in [30]. The authors of [31] focus on 2-factor authentication for contract wallets, but do not discuss wallet contracts in detail. The broad analysis of smart contracts by [32] does not focus on wallets, but concludes that most contracts that collect substantial amounts of Ether are wallet contracts.

In this paper, we focus on wallet contracts that implement only characteristic functionality. A major challenge is to identify such proper on-chain wallets.

Ethereum Graph Analysis

Most work focuses on the transfer of assets and network communication on Bitcoin and other cryptocurrency platforms. Regarding Ethereum, [33] examines “whether an attacker can de-anonymize addresses from graph analytics against transactions on the blockchain”. The authors of [34] “leverage graph analysis to characterize three major activities, namely money transfer, contract creation, and contract calls” with the aim to address security issues. Applying network science theory, [35] “find that several transaction features, such as transaction volume, transaction relation, and component structure, exhibit a heavy-tailed property and can be approximated by the power law function.”

Regarding ERC20 tokens on Ethereum, the authors of [29] study the tokens trading network in its entirety with graph analysis and show power-law properties for the degree distribution. Similarly, the authors of [36] measure token networks, which they define as the network of addresses that have owned a specific type of token at any point in time, connected by the transfers of the respective token.

Instead of examining the trading of assets, our investigation focuses on contracts that manage the access to the traded assets, namely wallet contracts. We employ call graphs as they are a suitable abstraction for identifying interaction patterns.

EVM Bytecode Analysis

To detect code clones, the authors of [37] first deduplicate contracts by “removing function unrelated code (e.g., creation code and Swarm code), and tokenizing the code to keep opcodes only”. Then they generate fingerprints of the deduplicated contracts by customized fuzzy hashing and compute pair-wise similarity scores. In another approach to clone detection, the authors of [38, 39] characterize each smart contract by a set of critical high-level semantic properties. Then they detect clones by computing the statistical similarity between the respective property sets.

To detect token systems automatically, the authors of [40] compare the effectiveness of a behavior-based method combining symbolic execution and taint analysis, to a signature-based approach limited to ERC20-compliant tokens. They demonstrated that the latter approach detects 99 % of the tokens in their ground truth data set. For all deployed bytecode, though, it bears a “false positive risk in case of factory contracts or dead code”.

Our method of computing code skeletons is comparable to the first step for detecting similarities by [37]. Instead of their second step of fuzzy hashing though, we rely on the set of function signatures extracted from the bytecode and manual analysis, as our purpose is to identify wallets reliably. Relying on the interface is in line with the results in [40].

Smart Contract Landscape

In their empirical study [41], the authors investigate Ethereum smart contracts by looking at contract creation, interaction, and code reuse. The authors of [42] complement their quantitative analysis of smart contracts by temporal views. Moreover, they identify particular groups of smart contracts based on their activity patterns.

Our contribution also aims at understanding the landscape of smart contract, but concentrates on the specific group of wallet contracts. We argue that wallets are one of the backbones of the landscape keeping the call graph connected.

8 Conclusions

We examined smart contracts that provide a wallet functionality on the Ethereum main chain up to block 8 450 000, mined on August 30, 2019. For a semi-automatic identification of wallet contracts, we discussed methods based on deployed bytecode and interactions. By analyzing source code, bytecode, and execution traces, we derived features and types of wallets in use, and compared their characteristics. Moreover, we provided a quantitative and temporal perspective on the creation and use of identified types of wallets, and discussed their role in the smart contracts landscape.

Identification of wallets. The identification of wallets as recipients of tokens or Ether can be done automatically, but includes many contracts beyond proper wallets. Our method of identifying wallets by name, interface, and ancestry yields blueprints for wallets, which then are used to locate contracts with similar implementations or same deployers. This approach is only semi-automatic, but more reliable.

Blueprints for wallets. Since we manually verify the Solidity source code, our work yields a ground truth of wallets that can be used for evaluating automated tools.

Wallet Features. Features of wallets in use beyond the transfer of assets can be grouped into administration and control, security mechanisms, lifecycle functions, and extensions. By distilling a comprehensive list of features for pure wallets, we are able to separate wallet contracts from non-wallets. Moreover, we could depict actual use cases via the extracted features.

Wallet Types. Wallets can be categorized into the six types simple, multiSig, controlled, forwarder, update, and smart wallet according to the features they provide. MultiSig wallets were the first to appear shortly after the launch of Ethereum, while controlled and forwarder wallets followed in 2017. Update wallets and smart wallets with a modular design are a recent phenomenon starting at the end of 2018. We observe an evolution of features in the wallet types. Still, the multiSig wallet seems popular, either as it is or incorporated into smart wallets.

Usage of Wallets. On-chain wallets are numerous, amounting to 3.9 M contracts (21 % of all contracts). If we discount mayflies (contracts that self-destruct during deployment [42]), the share of wallets even rises to 28 %. Next to gasToken contracts, wallets are the largest application group regarding contract deployments.

Then again, most on-chain wallets (68 %) are not in use yet. They may have been produced on stock for later use. Interestingly, on-chain wallets are used either for tokens or for Ether, but rarely for both. Even though most wallets are designed for token management, only 0.62 M wallets (16 %) have so far received at least one token. Of the few wallets holding tokens, 83 % hold just one type of tokens, while 99.5 % hold at most 10 different types.

Solidity and Code Reuse. On the surface, only 587 wallet addresses (0.02 % of all wallets) have a verified Solidty source code on Etherscan. However, taking into account that most wallets are created by factories whose code may be found, this number rises to 63 %. By exploiting the similarity of code skeletons, we can relate even 83 % of the wallets to publicly available source code.

The 3.9 M wallets correspond to just 1357 distinct deployed bytecodes (631 distinct code skeletons). This homogeneity results from the small number of on- or off-chain factories that generate most of the wallets.

Landscape. Our assumption that wallets act as a cohesive in the graph of executed calls between contracts holds only for a very broad definition of wallets. To dissect the landscape of smart contracts effectively into applications, we may have to identify further contract groups that handle assets.

8.1 Future Work

When aiming at a deeper understanding of the role of dApps and smart contracts, there are still some pieces of the puzzle missing. Our contribution to understanding on-chain wallets may serve as a basis for further research in this direction, as wallets are a major application type. Moreover, as wallets link many dApps, removing them from the overall picture may let other applications stand out clearer. Examples of such applications are markets and exchanges, which also act as a cohesive in the call graph and which still need thorough investigation. Additionally, we can use the number of calls as weights on the edges and apply neighborhood algorithms. First experiments with the latter approach show that it may be effective if we manage to remove some of the major connecting applications.

To determine reliably what smart contracts actually implement, it is still indispensable to analyze bytecode. Adequate tool support for a massive automated semantic code analysis would be helpful to obtain a comprehensive picture of the smart contract ecosystem.

References

Appendix A Wallet Profiles

In this appendix, we detail each identified wallet blueprint with regards to

  • the author(s) if known

  • the location of the Solidity source code that it is based on

  • a brief description of features

  • the function headers used for identifying its instances

  • the deploying factory contract if used

  • subtleties of the detection procedure if other than finding signatures

When specifying the location of source code, we use ES:0x... as an abbreviation for the link https://etherscan.io/address/0x...#code.

a.1 Simple Wallets

AutoWallet

Description: Simple wallet that handles Ether, ERC20 tokens and non-fungible tokens (ERC721). Received Ether is forwarded automatically to the owner of the wallet, but the wallet provides also a sweep function to access Ether that was deposited e.g. as a mining reward or by a self-destruct.

Identification: The wallet can be uniquely identified by the following function:

transferNonFungibleToken(address,address,uint256)

Addresses: So far there is only one bytecode for this contract in use, deployed e.g. at address 0x1991af53e07b548a062a66e8ff3fac5cc9e63b22. Of the 9250 instances on the chain, all but two where deployed by the externally owned account 0x13d0c7ada3f98eec232ed7e57fefc4c300f25095.

BasicWallet

Description: Simple wallet with owner management for Ether, ERC20, and ERC223 tokens.

Identification: The wallet can be uniquely identified by the four functions it implements:

changeOwner(address)
transfer(address,uint256)
transferToken(address,address,uint256)
tokenFallback(address,uint256,bytes)

Addresses: This wallet was deployed 4635 times with two versions of the bytecode (due to different versions of the Solidity compiler) by the externally owned account 0xff3249da62ca5286997f31f458959de9ae2f4dad.

wallets version deployed e.g. at
3180 newer 0xa4db5156d3c581da8ac95632facee7905bc32885
1455 older 0x850c3beae3766e3efcf76ade7cbd6e3e0aec517e

ConsumerWallet

Description: Simple wallet for Ether and ERC20 tokens with various security features, like white-listing of receivers, daily limits (using an oracle for converting tokens to Ether), two factor authentication, and gas management.

Identification: We identify the wallets by checking whether one or two of the following functions are among their signatures:

topUpAvailable()
bulkTransfer(address,address[])

This allows us to identify seven variants of deployed bytecode, which we check manually to make sure that they are indeed the same type of wallet. Most wallets are deployed by on-chain factories that can be found by looking for the characteristic signature

deployWallet(address)

Addresses: Of the seven bytecodes of this wallet, the three most frequent ones have been deployed by four factories, while the less frequent ones have been deployed by one particular externally owned account.

wallets code deployed e.g. at creator
1380 0x20ab867160e73788e0db311f445e67bc596e0ec0 A
1267 0xa8e7213d64e29f6e5e81cb5d6cd48bcdcf722dc4 B
531 0xd883f8a6080ea6c473efc05c8ff3238255ad0e02 C,D
255 0x613e20da62058aa4f8bc2c8b6fddc03e43b89b5a E
144 0xe6510c19c7768ca0937e8f4daf0b16859af9c271 E
53 0x5c76fb5fb117d190beac217bc3568e70f2b6b71d E
4 0x1e7d250a2ac2646125be3823290fbb5d61d57c13 E
creator address user?
A 0x95bebe7bfc6acc186c13d055d0aacc2de5f81502 no
B 0x85bb8a852c29d8f100cb97ecdf4589086d1be2dd no
C 0x5e7a685ed8bd3e9dc24bfd67813e9c26b5891308 no
D 0xb24d47364163f909e64cf2cf7788d22c51cea851 no
E 0xe0731c1a30e6ed0c6e9162eb87fc85e831caf382 yes

SmartWallet

Description: Simple wallet for ERC20 tokens. The older version allows the user to configure a backup account where to transfer the tokens, the newer version implements a time lock (cooling period) for withdrawals.

Identification: The wallet can be identified by the following function:

transferToUserWithdrawalAccount(address,uint256,address,uint256)

The older version additionally contains the function

transferToBackupAccount(address,uint256)

whereas the newer version can be identified e.g. by the additional function

requestWithdraw()

The newer version of the wallet keeps the cooling period in a separate contract called WithdrawalConfigurations, which can be found by looking for the function

withdrawalCoolingPeriod()

Addresses: All wallets of this type have been deployed by externally owned accounts. We find five distinct code skeletons.

wallets version deployed e.g. at creator
37629 older 0x5e63e5f352fa0167b241a9824165b5cf38ee2973 A, B, C, D, E
8700 newer 0x69667ce8641ed03abec2627866543b1126240044 A, B, D, E
7 older 0x0d341e13f9f9bd6e02fa97e249a0a27522b0efb1 F
2 older 0x0c3e4f2961f6b8d62be9353ac2376e6438a9cf20 F
2 older 0x86acc9df62926e62bb6b5dd0e46409be37ffea36 F
creator address user?
A 0x0fa4be05d6c7accdeb1e59f355315ec61c9a6dbb yes
B 0x6bdd15d26ee026c0cb952e3d7fd7535cf7e1ef20 yes
C 0x866f649cd9280d3dfa282372a3f5828839944959 yes
D 0xaa1aeffe8bf1a7470558b31f35cb6ec7faf0679f yes
E 0xb642f8e816f64cf7b022d7521be162cbb7193dd5 yes
F 0x00da955d3e1f31726c0f7511f0593452925a9acd yes

Spendable Wallet

Source: ES:0x35a1700AC75f6e9E096D9A5c90e3221B658096e0

Description: Simple wallet to manage a single ERC20 token as specified on deployment. Owner administration. Emergeny function to withdraw Ether and tokens other than the one the wallet is intended for. A small number of wallets contain the tokenFallback function required by ERC223.

Identification: The wallets of this type can be uniquely identified by looking for bytecode implementing the functions

spend(address,uint256)
claimTokens(address)

Depending on the version, the wallets implement three or four further, less distinctive functions.

All instances of this wallet have been deployed by contracts. These factories can be uniquely identified by looking for bytecode implementing the function

newPaymentAddress(address,address)

Addresses: In total, six versions of bytecode can be found on-chain. The last two in the list below implement the tokenFallback function.

wallets code deployed e.g. at factory
611 0x35a1700ac75f6e9e096d9a5c90e3221b658096e0 0x16e73d276b2163c49db410350bfefd9f48898821
452 0x87f53784494c693d1ea80aafffaf53b547b87df5 0x2048360fef3fcb5858f8e2dbae2d4b8ad2e94c23
366 0x2254f46dedafa2a03f59008456a7400cfadcaf73 0x365443b7b06b86f1f560873de723b6d4fb3927ce
3 0x6bb75a4cfdcee5befd65d898198f43c280631913 0x25f93d0a70c3a9054a9adbae43a9bd67238f0f03
2 0x0a9b4b39a0e8da2855f5f8cc0aa6c203963f17e7 0xcac914780920e425518131557beb856f0ed9688d
2 0x409fd08a982826c2e7c0d7d90c673c7eec0cf922 0x4dafe9f324816a7f5bc8e05befb2579c30cc83d6

Timelocked Wallet

Source: ES:0x5119b5e3a7bff084732a7ec41efed8aa0c4cd6d4

Description: Simple wallet to handle ERC20 tokens and in most cases also Ether. During deployment, the owner and a lock period is fixed. The wallet may receive assets at any time, but only after the lock period the owner may withdraw the assets.

Identification: This type of wallet can be singled out by looking for bytecode that implements the functions

info()
unlockDate()

Most wallets are deployed by factories that can be detected by looking for bytecode implementing the function

newTimeLockedWallet(address,uint256)

Addresses: We list the top creators that created at least 10 wallets. All except the fifth one are factories.

wallets code deployed e.g. at creator
54 0x1b95d18bda9b74cf7f1e74d5929bafef8ec896f7 0x2174e3cea45be4b1d74811ee70f7de16119b7c67
36 0x009dd2460f8b84dde574c429ee4c94a7b65fc143 0x2648c3e6727595e163b9d2f8dd9b1f1ade292ec9
30 0x669acb32e308b1ca7069965f7fe903cbe9d41eb5 0x841f2869bdf55257f66a42e8b1c0eaa4c7733313
24 0xc5a9016bd0a3bf9c4cc56cf35280d2001b2453bb 0xae1500b00dcbc545f0dc3e4cc117a075ec849756
13 0xa0ba4b6b894377f6d4449bc2d1ed5558f0f6dadf 0x293e599c771a81619cf96d766b8fa000830dd6d6
11 0xdd6516bb91aca6879798fdc0c446e09c5bcf2374 0x4b448951de99285467820aa222ac5e807285e094

a.2 MultiSig Wallets

Argent MultiSig Wallet

Author: Julien Niset

Source: https://github.com/argentlabs/argent-contracts/blob/develop/contracts/MultiSigWallet.sol

Description: -out-of- multisig wallet for Ether and ERC20 tokens. The transaction as well as all signatures are computed off-chain. A single call to the wallet is required to execute the multisig transaction, which may be an arbitrary call. The list of owners and the number of required signatures can be modified. The wallet has been deployed only in small numbers, but is worth mentioning because of its clear design.

Identification: The instances of this wallet can be identified by looking for bytecode that implements the function

execute(address,uint256,bytes,bytes)

Addresses: So far, four distinct bytescodes have been deployed at eleven addresses:

0x1975c3586e46abd928b5fb0c61136ad789a18cc4
0x19a5312e13f458e8afe59c2c213b41243285f2fd
0x1b512c29fa62960afb06c292adbe35513f75e2a1
0x3f2d0f18530e6e283e9a8bf0ea4cd15c9e19f4f9
0x4fee588f5f23474cdaf78e17d2feaa2e3234ed78
0xa5c603e1c27a96171487aea0649b01c56248d2e8
0xc022d15ddcf47d3aa3472f92f694ef5cf6549590
0xc672c57301483ff384136f59fed46bb72ab1160f
0xc6a5d95a62a394bb2eda85c0397a951a09eb2d20
0xd60cff99be043d2d2f1c770d7081d9b509c569f3
0xf8ab2f7464f91bdeca50632147c9e0980b6d5c2e

Bitgo MultiSig Wallet

Source: https://github.com/BitGo/eth-multisig-v2

Description: 2-out-of-3 multisig wallet for Ether and ERC20 tokens without owner management. The transaction and one signature are computed off-chain, while the second signature is the one from the message sender. A single call to the wallet is required to execute the multisig transaction, which may be an arbitrary call. Optionally, a second entry point is specialized on token transfers. Some variants of the wallet can create forwarder wallets. There are also restricted forms that lack the possibility for signing general calls.

Identification: We identify the wallets by checking whether one or two of the following functions are among their signatures:

sendMultiSig(address,uint256,bytes,uint256,uint256,bytes)
sendMultiSigToken(address,uint256,address,uint256,uint256,bytes)

Addresses: Wallets of this type have been deployed roughly 135 k times with 105 distinct bytecodes. For bytecodes that occur at least 10 times, the following table lists the number of deployments, the address of one such deployment, and the number of creators. All wallets were created by an externally owned account, with exception of the wallets in the third row below.

wallets code deployed e.g. at creators
134981 0xe0f42a3f573d83452e1c3c9c8d14f4499a415cd4 353
163 0xf738a52a5835caa35351996d45046354271c0eb6 2
72 0x5d3bb8aa930bbc5e552e4adc4c7bc40be1a4429b 1
43 0x3c8640e3a6d57ce9157c1932d8897f5f16408151 1
36 0xe1d31b32f45273146f32c84d923b3eadd2396213 1
10 0xeb99bf5f5d6e284c1c3196871442e328be6631ad 3

Gnosis MultiSig Wallet

Author: Stefan George

Source: https://github.com/Gnosis/MultiSigWallet

Description: -out-of- multisig wallet. Each signature is provided with a separate call. Owners sign arbitrary call data that has been composed off-chain as well as the amount of Ether to send along. May receive Ether and ERC20 tokens, no provisions for advanced token handling. An extended version adds support for daily limits. Most wallets are deployed by factories.

Identification: Wallets of this type can be identified by looking for bytecode that implements at least the functions

changeRequirement(uint256)
confirmTransaction(uint256)
executeTransaction(uint256)
submitTransaction(address,uint256,bytes)

This approach captures several variants, including those with daily limits.

Addresses: Overview of top wallet creators (contracts or users):

wallets creator user?
2497 0x6e95c8e8557abc08b46f3c347ba06f8dc012763f no
1797 0x696dc02ce137f6690c83fa348290e59e70edff28 yes
562 0x7e6ae27256ac2879e87212f9f7b42cb20ea45e37 yes
460 0xed5a90efa30637606ddaf4f4b3d42bb49d79bd4e no
457 0xf20d2ccf9e96f67654a3255ed5d3897c6454b72d yes
447 0x35ef9cfa246decd5e037b98d82f823cff934914d yes
443 0xba95dc6a4f871c4a01f40c0ed421ee07de887819 yes
420 0x3bc31afaf903d05e16e4fd5480affa3e6ed3c9de yes
199 0xa0dbdadcbcc540be9bf4e9a812035eb1289dad73 no
153 0xe74a0a4f3601c6a179298d528d49b56d65314456 yes
79 0x15f91c1936d854e74d6793efffe9f0b1a81098c5 no
76 0xa05cbf902248193c1499eb19e65b87ab295532fa yes
65 0x6efd5665ab4b345a7ebe63c679b651f375dddb7e yes
63 0x4a176d9335f4f8e07e007ac5d3b3e72335cd9bb0 no
50 0x12ff9a987c648c5608b2c2a76f58de74a3bf1987 no

Ivt MultiSig Wallet

Source: ES:0x36d3f1c3ea261ace474829006b6280e176618805

Description: MultiSig wallet with flexible transactions, safe mode, and w/o owner administration.

Identification: The wallet is characterized by the following four functions:

submitTransaction(address,string,string,uint8[],bytes32[],bytes32[])
submitTransactionToken(address,address,string,string,uint8[],bytes32[],bytes32[])
confirmTransaction(address)
activateSafeMode()

Addresses: tbd

Lundkvist MultiSig Wallet

Author: Christian Lundkvist

Source: https://github.com/christianlundkvist/simple-multisig

Description: The wallet aims at being the “smallest possible multisig wallet” w/o owner management. It handles Ether and ERC20 tokens, and supports flexible transactions.

Identification: The wallet is characterized by the following functions:

nonce()
threshold()
ownersArr(uint256)
execute(uint8[],bytes32[],bytes32[],address,uint256,bytes,address,uint256)

and in an older version:

execute(uint8[],bytes32[],bytes32[],address,uint256,bytes)

Addresses: tbd

Nifty MultiSig Wallet

Author: Duncan Cock Foster

Source: ES:0x412Fc2E898a4A89d40bA8c13c7287F75A295D027

Description: This multiSig wallet is copied from Gnosis, but added non-fungible token handling.

Identification: The wallet is characterized by the following three functions:

returnUserAccountAddress()
returnWalletTxCount()
callTx(bytes,address,uint256,bytes)

MasterMultiSig is one of the two helper contracts containg the functions:

transactions(uint256)
confirmations(uint256,address)
isOwner(address)
owners(uint256)
required()
transactionCount()
MAX_OWNER_COUNT()
staticCallContractAddress() -- sufficient to identify contract
user_control_accounts(uint256)
returnUserControlAddress(uint256)
returnIsValidSendingKey(address)
returnStaticContractAddress()
changeUserControlAddress(uint256,address)
addSendingKey(address)
removeSendingKey(address)
changeStaticLocation(address)
recover(bytes32,bytes)
returnTxMessageToSign(bytes,address,uint256,uint256)
addOwner(address)
removeOwner(address)
replaceOwner(address,address)
changeRequirement(uint256)
submitTransaction(address,uint256,bytes)
confirmTransaction(uint256)
revokeConfirmation(uint256)
executeTransaction(uint256)
isConfirmed(uint256)
getConfirmationCount(uint256)
getTransactionCount(bool,bool)
getOwners()
getConfirmations(uint256)
getTransactionIds(uint256,uint256bool,bool)

NiftyStaticCalls is the other helper contract containg the functions:

retAdd()
isValidSignature(bytes32,bytes)
isValidSignature(bytes,bytes)
onERC721Received(address,address,uint256,bytes)
ERC1155_RECEIVED_SIG()
ERC1155_BATCH_RECEIVED_SIG()
ERC1155_RECEIVED_INVALID()
lastData()
lastOperator()
lastId()
lastValue()
onERC1155Received(address,address,uint256,uint256,bytes)
onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)

Addresses: tbd

Parity/Eth/Wood

Author: Gavin Wood

Source: https://github.com/paritytech/parity/blob/4d08e7b0aec46443bf26547b17d10cb302672835/js/src/contracts/snippets/enhanced-wallet.sol

Description: MultiSig wallet with owner management, flexible transactions, and daily limit.

Identification: The wallet is characterized by the following function:

hasConfirmed(bytes32,address)
m_required()
m_numOwners()

Additional functions are:

version() -- Ethereum wallet
revoke(bytes32) -- Ethereum wallet/Parity library
changeOwner(address,address) -- Ethereum wallet/Parity library
addOwner(address) -- Ethereum wallet/Parity library
removeOwner(address) -- Ethereum wallet/Parity library
changeRequirement(uint256) -- Ethereum wallet/Parity library
isOwner(address) -- Ethereum wallet/Parity library/Parity wallet
hasConfirmed(bytes32,address) -- Ethereum wallet/Parity library/Parity wallet
setDailyLimit(uint256) -- Ethereum wallet/Parity library
resetSpentToday() -- Ethereum wallet/Parity library
kill(address) -- Ethereum wallet/Parity library
execute(address,uint256,bytes) -- Ethereum wallet/Parity library
confirm(bytes32) -- Ethereum wallet/Parity library
m_required() -- Ethereum wallet/Parity library/Parity wallet
m_numOwners() -- Ethereum wallet/Parity library/Parity wallet
m_dailyLimit() -- Ethereum wallet/Parity library/Parity wallet
m_spentToday() -- Ethereum wallet/Parity library/Parity wallet
m_lastDay() -- Ethereum wallet/Parity library/Parity wallet
getOwner(uint256) -- Parity library/Parity wallet
initMultiowned(address[],uint256) -- Parity library
initDaylimit(uint256) -- Parity library
initWallet(address[],uint256,uint256) -- Parity library
Deposit(address,uint256) -- extra signature

Addresses: tbd

Teambrella MultiSig Wallet

Source: ES:0x44852FAEFcb42E392f2c55c6df53A50A732Df298

Description: MultiSig wallet with flexible transactions and owner management. In one variant, there is a recovery mechanism.

Identification: The wallet is characterized by the following function:

m_teamId()

The wallet contains the further functions:

m_opNum()
m_owner()
m_cosigners(uint256)
m_cosignersApprovedDisband(uint256)
assignOwner(address[],uint256,address)
changeAllCosigners(uint256,address[],uint256[3],bytes,bytes,bytes)
changeAllCosigners2(uint256,address[],bytes,bytes,bytes,bytes)
transfer(uint256,address[],uint256[],uint256[3],bytes,bytes,bytes)
transfer2(uint256,address[],uint256[],bytes,bytes,bytes,bytes)
approveDisband()
disbandTo(address)

and in a variant also:

rescue(address)

Addresses: tbd

Unchained Capital MultiSig Wallet

Source: https://github.com/unchained-capital/ethereum-multisig

Description: Basic MultiSig wallet with flexible transactions.

Identification: The wallet is characterized by the following five functions:

spendNonce()
unchainedMultisigVersionMajor()
unchainedMultisigVersionMinor()
generateMessageToSign(address,uint256)
spend(address,uint256,uint8,bytes32,bytes32,uint8,bytes32,bytes32)

Addresses: tbd

a.3 Forwarder Wallets

BitGo Forwarder Wallet

Source: https://github.com/BitGo/eth-multisig-v2

Description: The wallet can forward its assets to the parent who created it.

Identification: The wallet is characterized by the following three functions:

parentAddress(),
flushTokens(address),
flush()

Optinal entry points are:

Forwarder()
initialize()
logger()
initialize(address)
feeAddress()
0x7cade34a
updateOwner(address)
changeParent(address)
0x0e18b681
newAdmin()
changeAdmin(address)
changeTarget(address)
admin()
0x813f0f59
0xf4069e83

Addresses: tbd

IntermediateWallet

Source: ES:0x5a01a4A46108794055Fe90DC5dBb8a3823a1c2e6

Description: Simple wallet for Ether and ERC20 tokens with forwarding of assets to hardcoded address.

Identification: The wallet is characterized by the following functions:

owner()
wallet()
transferOwnership(address)
setWallet(address)
retrieveTokens(address,address)

A variant also contains the function:

tokenFallback(address,uint256)

Addresses: tbd

SimpleWallet2

Source: ES:0xcqq2f21e3d752834a38a0f8a68c4cef84df1eb4541

Description: Simple wallet that forwards all its Ether to its owner.

Identification: The wallet is characterized by the following four functions:

owner()
transferOwnership(address)
weiBalance()
claim(address)

Addresses: tbd

a.4 Controlled Wallets

Bittrex

Author: Bittrex

Source: ES:0xa3C1E324CA1ce40db73eD6026c4A177F099B5770

Description: This controlled wallet involves three types of contracts: controller, sweeper, and user wallets. The controller creates wallets and maintains a list of sweepers that are used by the wallets to perform transfers. A separate sweeper can be set for each kind of token or Ether. In practice the so-called default sweeper is used most of the time; it is deployed at the same time as the controller. With a total of 14 addSweeper call, only eight controllers have set a new sweeper so far: three times for each of the OMG, SONM, Tether token, twice for the Binance token and for Ether, and once for the Mithril token.

Figure 4 shows the interaction of controller, (default) sweeper, and user wallets.

1

2

3

4

5

6

7

8

9

10
Figure 4: Bittrex controlled wallet: interactions between controller, sweeper, and wallets.

A user or contract representing e.g. an exchange, , deploys two companion contracts in a single transaction: a controller  and a default sweeper  (1). In further transactions, calls with makeWallet (2). This prompts to deploy wallets  (3). In total almost 2.5 M wallets have been deployed this way. The wallet addresses can be given to customers, who announce them to receive Ether and tokens. The control over the wallets, however, stays with , similar to accounts of traditional banks.

Now suppose Ether or tokens owned by are to be transferred to the destination address . First, calls with changeDestination to store in the controller (4). Destination addresses are changed rarely (so far 65 times for all controllers, in total). Then initiates the transfer by calling the wallet with sweep, passing the token address (0 for Ether) and the amount (5). The wallet asks the controller for the sweeper in charge of the token (6). Next, the wallet performs a delegate call to the sweeper, , handing over token address and the amount (7). The delegate call has the effect that all actions by the sweeper will seem to originate from the wallet even though the code is actually contained in the sweeper. The sweeper calls the controller several times to learn the destination address and to check permissions (8). Then it performs the token transfer or sends the Ether (9). Finally, on successful completion, the sweeper prompts the controller to issue the event LogSweep (10).

Identification: The controllers and default sweepers are detected by a combination of signature and message analysis. A contract, , is a controller if it satisfies the following criteria.

  • During the deployment of  another contract, , is created.

  • The only signatures of  are sweep(address,uint256) and optionally controller().

  • The only contracts created by  are wallets, .

  • The only signatures of  are sweep(address,uint256) and optionally tokenFallback(address,uint256,bytes).

Table 3 lists the addresses of all controllers that have deployed at least ten wallets with their default sweepers.

wallets controller default sweeper
1578470 0xa3c1e324ca1ce40db73ed6026c4a177f099b5770 0xb2233fcec42c588ee71a594d9a25aa695345426c
633644 0x4f01001cf69785d4c37f03fd87398849411ccbba 0x3105d1027fdd1cf6b2d67056b61956249f6fc861
142580 0xedce883162179d4ed5eb9bb2e7dccf494d75b3a0 0x88de41a34871e239c52926f920efb4eefa0f3de3
50869 0x0bd9bf737f70c339db6b87f6a9fa8f6862b30dd6 0x4fff49c5b4691775a13d2bea90b60d1876b6d1c9
32015 0x2754b28227f041a66c46509d5620782bfc4766ef 0x5e85f6cdb466771b870757658593d073b8f3f9c8
10697 0xd8b7c1e952cb3b4ba3ab993096bb8c6be26a17a0 0xf9dd79eef74db6de9efbe9715bc256f76f138005
7563 0x4746809ecb3a8449a61d77246992a33fdd73f61b 0x27304c0dc0d1ade22c315ec633136d1e249df9d4
7550 0xe91eb1fb4b0eae01afa35b99a2c84409f353c49b 0x7460c1d30154c06e2253e6ead49a1bc5f4353bcd
3693 0xecba8b19e058891f581badd5697606097300ab60 0xfcc5b3023797254e9904ea62c9140fe9fb306f10
3350 0x267353a2cc8b329d8ed3a13cee17adf2427fa680 0x3bc8271be786a28c7fc3b731bfd46181eda0b741
3265 0xc2acad3578019495ed7814a612aa0866b7b733e0 0x1f4f8ee88e732f2c1731931d0456ed7ad37478de
2580 0xf6014ba24ddfeb009699ffd5b753487f0b2eddd1 0xa5c283dc4b7457318def37c7254832344ce2f0a7
2400 0x0f81e92e206316e9e6d4d9c57f3921ee60817900 0x1db3d98054b23a2f740a8ae07bbe07d8a8a3ef26
1496 0xe01c5efcc674a72eb690670ed3f63624542ffbc3 0xed61189fa8d62b29d3f5c12c96a1e9672b05df3f
1190 0x6933127b497c83466bf2995bd4e22b1536eec5ad 0x6825398a9d0c8661e5477c01e6185ac56e7f7276
1058 0x357f9afb22a2bb56f8f75ffa36c4d12f3b62ecc5 0xbfe86824d5f428f1efccc6ca4142136e25ef543c
977 0xc8fc145491a928a24f1da88e31e6ff9771e5b59d 0x48ab755bff0a4f82037e339b1cc2c167ddb64cec
887 0xcfdcc1a98172c13ecd625bad384ab6f578f1bb3c 0xf0c85a8e8db7e1e7c550f61e1891a5e0b2cf37c5
600 0x4202b62990c763860ffaf5e4ee935b1459890e25 0x8f16c452e74c8688cd2795f9ab7623afea7accae
383 0x38db3c2244f5de9e102cd844d374ba40f3818af3 0xa9a2514366e3d8b5f13e878d3befb13215c26006
340 0x714853895516168212703896401a343699ea9b1a 0x271e7d6f3e1a8e876521d4c324b7eef890a30a82
325 0xd909ace851399e1d92af958ba57875353504e289 0x48cd9c3eab67c535291250b8e785fb6d43b1dba9
305 0x4d352b1338ea8c7cc70b0e669b99b35db8498a54 0xceb40183b1cb52ed0a7203cf9c468d6e38a3c98b
300 0xb4cbc0c87ab21bc02e37c1432e771f70cd6db5db 0xf55af536a52420a1df21ecff768bab18d80c58b2
228 0xa7ab11e268bf2852f103641133044cea9fe75114 0xd0932b2c8a854565947316080f243ddc4013c74e
212 0xadbe6eacc402ffd3ce0b20a45fa30a1cd7eaa142 0xf5eac2e3b4a3b18ed37b840cdf374f67cc284b7b
209 0x00e8c228e75995eea114631f1e27f458071b70fb 0xf76956a5dba85d8d913ebc382e49d5aa8ea5aaa2
201 0x6658d2c231232d1f945380c18009de4f58dcb690 0xca6d9f429fe7d85bd27e8c1b1d7f30082127fa35
150 0x2c164b1e756744183c14aa683e316a61e597ff52 0x183b0087bc7b85cc393b844b0432c97d37da695e
141 0x69e6030616d9b1fdaab8c05ab147382b2ac23af0 0x7e90d82fd51e81fbb8e94a977273733fd53e49f5
135 0x9d44d0855aec425c4f9e82cc58c5c0955e335aeb 0xd0547cbc83b386ca23506e9ae8936614ed7664b4
119 0xeb818c6a48ccd60a8078aaa20997cc3cb2538c9e 0x8e7abaf1316a0edb985e494f572fdf148e8a7e93
117 0x6f68736ede3b8263d2f769b148a4d410cf44d392 0xaf51ebbf24042ef8928ce72911ee7214318e1bf5
107 0xb824643b483bb0726401072b0e66e29f9e70e8cf 0x78f523a649114e0cf7991b3d267c344a490a5eea
71 0xc227fc68da6efa32cd6710fcd4bc5ae3041d1e86 0x286b0bad77b3b817998b3040c79d2864744ff010
66 0xf0833b48c6b342437da4a2017fbbf4fd1a3c9682 0x16cd93bc5752a490c7d12443d50a2b9ae21904e1
62 0x7c9338bc675fd0c513b31438f5418be947911f8c 0x5f0375956b17b236b3208a86dc40dd20a69ef9cb
60 0x2081ca8a6156b4b7e0a9473754a8d97a18a71f88 0x68578231c5c4c431dc847e8ee8456148990137f2
60 0x721a6f3e7f66efe60645a7135a6f5d5fd1ab523b 0x8640f5c3726f86fe14d3a7b1a7ae2c9ba48c5afc
50 0x945ef56694081994cd0a0275b39542a2521a4f67 0x3eb119d8c52fae8947e1b8440c97eb98150b7fa5
40 0xe030fc55a27b2d1d84f34336fca3a276a6ddf0d4 0xd7fe8940357eb32341a5e89d0aad49f65ee9b965
35 0x6cb0754da2843d3bea24638cb32dcd92b73b2eda 0x2208fcba966b93b47211faf6ac44840b228395ee
35 0xe4460cc335dda80b22e21510a63de14bf46b098a 0xb98b445e9054aeab56e387e84dde7659bdcd6972
31 0x127925fec603720409ce8fad7688abbc859598f9 0xc99ba12c5a7c0a71ae22c156dccf021880c8a3a9
25 0x26fb44ddad061d7cd5dd2f7b2b3a38145e6db0af 0xc29fb1d8c40804ac5c2b20e2c471c2902f9715de
24 0x1e73119561eb749f65b227acd16f5d9b64eddda6 0x1bce24e05eb30dd118a1f7a958b52d78100aa304
19 0x3c861c1db7bffd094a1f8dc9646860eaf91ad5d9 0xfd0c3dbfb9972303d38b445e84327ccb550dd000
16 0xb0db51bb47305a496c0757348c893cbc4559d8b4 0xd729dbef8ca6ac183b32e864657310765c56c799
15 0x539faf9c0a455d12e8a6334344be270e679f0269 0x60b8f00ae2a5eb41341791c41ef7247505fd3944
14 0xa1df420345bda29622281ad713bb22fa8b03c97b 0x1c8cf8b563fa6ea9e82c78798bce69691db04753
11 0xd7d4449e2439eaca8a3d78324fb520d8cb7e22a3 0xdc93b68926b626e36d56550079084f765ff127d0
Table 3: Number of wallets deployed by controllers, with the corresponding default sweepers.

a.5 Update Wallets

Eidoo Update Wallet

Source: ES:0x0409b14cac8065e4972839f9dafabb20cef72662

Description: The wallet can be updated, manage Ether and ERC20 tokens, and place orders.

Identification: The wallet is characterized by the following functions:

owner_()
exchange_()
tokenBalances_(address)
logic_()
birthBlock_()
depositEther()
depositERC20Token(address,uint256)
updateBalance(address,uint256,bool)
updateExchange(address)
updateLogic(uint256)
verifyOrder(address,uint256,uint256,address)
withdraw(address,uint256)
balanceOf(address)

The helper contract WalletLogic contains the functions:

owner_()
exchange_()
tokenBalances_(address)
deposit(address,uint256)
updateBalance(address,uint256,bool)
verifyOrder(address,uint256,uint256,address)
withdraw(address,uint256)
safeTransfer(address,address,uint256)
safeTransferFrom(address,address,address,uint256)
safeApprove(address,address,uint256)

Addresses: tbd

LogicProxyWallet

Source: ES:0x5d4a945271fb3e16481bf6ce0bad5f6b2e9d13db

Description: This wallet can execute flexible transactions, as well as change the owner and the version of the implementation.

Identification: The wallet is characterized by the following functions:

execute(address,bytes,uint256,uint256)
owner()
setOwner(address)
isAuth(address)
registry()

The helper contract registry contains the functions:

proxies(address)
build()
build(address)
record(address,address)
logicProxiesStatic(address)
logicProxies(address)
logic(address)
logicStatic(adress)
enableStaticLogic(address)
enableLogic(address)
disableLogic(address)
getAddress(string)
setAddress(string,address)

Addresses: tbd

a.6 Smart Wallets

Argent Smart Wallet

Author: Julien Niset

Source: https://github.com/argentlabs/argent-contracts/tree/develop/contracts/wallet/

Description: Modular wallet where the base wallet manages the modules that are entitled to call the wallet, and authorized modules may execute any transaction.

Identification: The wallet is characterized by the following function:

init(address,address[])

and contains the further functions:

implementation()
owner()
authorised(address)
enabled(bytes4)
modules()
authoriseModule(address,bool)
enableStaticCall(address,bytes4)
setOwner(address)
invoke(address,uint256,bytes)

The deploying factory is identified by the function:

createWallet(address,address[],string)

and contains the further functions:

moduleRegistry()
walletImplementation()
ensManager()
ensResolver()
changeModuleRegistry(address)
changeWalletImplementation(address)
changeENSManager(address)
changeENSResolver(address)
init(address)
getENSReverseRegistrar()
addManager(address)
getENSRegistry()
revokeManager(address)
ADDR_REVERSE_NODE()
owner()
resolveEns(bytes32)
changeOwner(address)
managers(address)

Addresses: tbd

Dapper Smart Wallet

Source: https://github.com/dapperlabs/dapper-contracts

Description: A wallet suited for Ether, ERC20 and advanced tokens with cosigner functionality, flexible transactions, and a recovery mechanism. The multiSig functionality employs signed messages based on ERC191 for confirmation support.

Identification: The wallet is characterized by the following function:

invoke0(bytes)

and contains the further functions:

EIP191_VERSION_DATA()
EIP191_PREFIX()
VERSION()
COMPOSITE_PLACEHOLDER()
AUTH_VERSION_INCREMENTOR()
authVersion()
authorizations(uint256)
nonces(address)
delegates(bytes4)
initialized()
init(address,uint256,address)
setDelegate(bytes4,address)
setAuthorized(address,uint256)
emergencyRecovery(address,uint256)
recoveryAddress(address)
setRecoveryAddress(address)
recoverGas(uint256,address[])
isValidSignature(bytes32,bytes)
supportsInterface(bytes4)
invoke1CosignerSends(uint8,bytes32,bytes32,uint256,address,bytes)
invoke1SignerSends(uint8,bytes32,bytes32,bytes)
invoke2(uint8[2],bytes32[2],bytes32[2],uint256,address,bytes)
onERC721Received(address,uint256,bytes)
onERC721Received(address,address,uint256,bytes)
tokenFallback(address,uint256,bytes)
ERC223_ID()

Its factory is identified by:

deployFullWallet(address,address,uint256)

and contains the further functions:

reclaimEther()
cloneWalletAddress() -- also a unique identifier
deployCloneWallet(address,address,uint256)
deployCloneWallet2(address,address,uint256,bytes32)
deployFullWallet2(address,address,uint256,bytes32)

Addresses: tbd

Gnosis

Author: Stefan George, Richard Meissner, Ricardo Guilherme Schmidt

Source: https://github.com/gnosis/safe-contracts/blob/development/contracts/GnosisSafe.sol

Description: A modular multiSig wallet with flexible transactions for Ether, ERC20 and advanced tokens with daily limit and recovery mechanism.

Identification: The wallet is characterized by the following function:

approvedHashes(address,bytes32)

and contians the further functions:

NAME()
VERSION()
DOMAIN_SEPARATOR_TYPEHASH()
SAFE_TX_TYPEHASH()
SAFE_MSG_TYPEHASH()
nonce()
domainSeparator()
signedMessages(bytes32)

Addresses: tbd