Audit & Report by Authio
White Circle LeftWhite Circle Right

Block Array Live Contract Audit

Client
Block Array
Published
January 19, 2018
Status
FINALIZED
Auditor
Alexander Wade
Authenticity

The audited contracts can be found in the PoA Network’s ico-wizard-audit github repository: https://github.com/poanetwork/ico-wizard-audit.

The version used for this audit is commit 0e68d6b676c3799b4c951862829f04b7557d2bc0.

The main contract for the crowdsale itself is located in 007_MintedTokenCappedCrowdsaleExt.sol. The token contract is located in 003_CrowdsaleTokenExt.sol. The finalization agent contract is located in 009_ReservedTokensFinalizeAgent.sol.

Disclaimer

This document reflects the understanding of security flaws and vulnerabilities as they are known to the Authio team, and as they relate to the reviewed project. This document makes no statements on the viability of the project, the safety of its contracts, or the potential of this project for investment. The Authio team was brought in to assess the state of live contracts, and has no control over either the state of these contracts or the actions of the groups involved in the management of these contracts.

1. Overview

This document serves as the official audit report of a crowdsale contract created and published through PoA Network’s ICO Wizard, and used and controlled by Block Array Corporation. Briefly, Block Array is a platform seeking to use blockchain technology to create systems from protocol layer to front-end that facilitate business and consumer adoption of blockchain technology.

The project audited was launched via PoA Network’s ICO Wizard, an application which allows for the simple creation of modular and customizable crowdsale contracts without the need for any coding knowledge. This is achieved through an advanced templating system where users of the ICO Wizard are able to select features they would like to use in the crowdsale via the Wizard, which then pieces together contract templates to create the desired crowdsale.

The project audited is Block Array’s token sale contract. Unlike most projects, Authio was contacted to begin the auditing process when the contract was already live, and the crowdsale completed. The contracts had already reached a certain state when the Authio team was introduced to them, meaning that some of the content of the contracts was irrelevant to the goal of this audit.

The objective of this audit was to closely examine the crowdsale finalize function, and whether it was safe to use it to unlock the transfer of tokens. The audit was performed on the entire set of contracts. However, as the contract was live and in an advanced state, the scope of this report includes only the finalize function as well as an in-depth analysis of the finalize function and the results of running it. An informal private report will be generated for the PoA Network team detailing findings covering the entirety of the contracts (as well as covering a complete run-through of the contracts, as opposed to starting from the end of the crowdsale).

2. Introduction

2.1 Authenticity

The audited contracts can be found in the PoA Network’s ico-wizard-audit github repository: https://github.com/poanetwork/ico-wizard-audit.

The version used for this audit is commit 0e68d6b676c3799b4c951862829f04b7557d2bc0.

The main contract for the crowdsale itself is located in 007_MintedTokenCappedCrowdsaleExt.sol. The token contract is located in 003_CrowdsaleTokenExt.sol. The finalization agent contract is located in 009_ReservedTokensFinalizeAgent.sol.

2.2 Scope

While every file in the above-mentioned repository was carefully examined, the scope of this report addresses only the contracts in the states they were in when Authio was contacted to conduct an audit. This state is, broadly:

1. The crowdsale getState function returns State.Success, indicating a completed crowdsale and halting additional purchases.

2. The crowdsale finalize function has not yet been called, meaning the token release function has not been called, halting token transfers.

3. A total of 54406432930609771417285772 tokens (18 decimals) have been sold, just under the maximum cap of 54406500000000003000000000 tokens (18 decimals).

4. A total of 34003500000000000000000000 tokens (18 decimals) have been reserved by the Block Array team for address 0xd8ec5f137d45273f60065985b6a5b766aa978855.

5. The token is not released for transfers, nor is the token in an un-mintable state.

2.3 Methodology

The methodology of this audit is different than a standard audit. Because contracts are already live and in an advanced state, changes cannot be made to the code. The objective of this audit is to work with both the PoA Network and Block Array teams to assess the safety of finalizing the crowdsale in the live contracts.

2.4 Disclaimer

This document reflects the understanding of security flaws and vulnerabilities as they are known to the Authio team, and as they relate to the reviewed project. This document makes no statements on the viability of the project, the safety of its contracts, or the potential of this project for investment. The Authio team was brought in to assess the state of live contracts, and has no control over either the state of these contracts or the actions of the groups involved in the management of these contracts.

3. Findings

3.1 General

The templating system used to deploy the Block Array contracts contained a mesh of complicated contracts, pieced together and deployed with a handful of complimentary interactions. During review of their code, the templated contracts used were found to have a handful of vulnerabilities. However, only the vulnerabilities which affect the live state of the contract are included in this report, meaning that while these contracts should not be used again for a crowdsale, the state they have reached means that they have bypassed issues found in the templated contracts.

The Authio team would like to reiterate and clarify: the contracts used for the crowdsale should be considered unsafe. However, it is important to note that the live contracts in the Block Array crowdsale have been secured through the actions and cooperation of the PoA Network and Block Array teams. We would like to thank both of these teams for their hard work and diligence in ensuring the security of the live contracts. The following sections will explain both the contracts themselves, as well as the process of finalization and what it entails.

3.2 Contract Explanation

3.2.1 Function - Crowdsale

MintedTokenCappedCrowdsaleExt.sol: This contract houses the majority of the logic for the crowdsale itself. Users buy tokens by calling various buy functions. Upon successful purchase, the crowdsale mints tokens through the token contract. Raised funds are sent directly to the team’s multisignature wallet during the purchasing process.

FlatPricingExt.sol: This contract houses the logic dictating token purchase price. Block Array’s crowdsale used a static, but updatable pricing model.

3.2.2 Function - Token

CrowdsaleTokenExt.sol: This contract dictates logic controlling the token itself. The token is ERC-20 compatible, and features a few different functions. It is mintable, as tokens are generated during the crowdsale (but locked after finalization). It is releasable, as tokens cannot be transferred until the crowdsale is finalized. It also features an upgrade mechanism, through which the Block Array team can propose token contract upgrades or fixes.

3.2.3 Function - Finalization

ReservedTokensFinalizeAgent.sol: This contract serves to dictate the logic of the crowdsale finalization process. The crowdsale was made with a set number of reserved tokens, which are generated by this contract at the end of the crowdsale process. Additionally, this contract also releases the tokens to be transferred.

3.3 Analysis - Finalization Process

This section is a technical explanation of the state changes that will occur during the finalization process, and will explain the effects this process will have on the token and crowdsale. Crowdsale finalization was simulated on a testing network to ensure that all state changes are known exactly. Finalization is initiated when the crowdsale’s owner address calls the crowdsale’s finalize function. The owner of the crowdsale is address 0x75D6a12BbA56441259483243b9c6ABA1a171c410, which Authio has verified to be under Block Array’s control.

3.3.1 Current State of the Live Contracts

The current state of the live contracts was observed and recorded directly from the main network. The state, as it pertains to crowdsale finalization, is as follows:

Contract:Function/Field:Input:Value:Type:
MintedTokenCappedCrowdsaleExtgetStateNoneState.SuccessState enum
MintedTokenCappedCrowdsaleExthaltedNoneFALSEbool
MintedTokenCappedCrowdsaleExtfinalizedNoneFALSEbool
MintedTokenCappedCrowdsaleExtownerNone0x75d6a12bba56441259483243b9c6aba1a171c410address
MintedTokenCappedCrowdsaleExtfinalizeAgentNone0x766e51c940b9656e34b91041ca8afa00b7e9ed71address
ReservedTokensFinalizeAgentcrowdsaleNone0x3D5fb1E9d2F15D9ae5d7f4af4825FDEf03dE9685address
MintedTokenCappedCrowdsaleExttokensSoldNone54406432930609771417285772uint256
ReservedTokensFinalizeAgenttokenNone0xa5f8fc0921880cb7342368bd128eb8050442b1a1address
CrowdsaleTokenExtreservedTokensDestinationLenNone1uint256
CrowdsaleTokenExtreservedTokensDestinations00xd8ec5f137d45273f60065985b6a5b766aa978855address
CrowdsaleTokenExtreservedTokensList0xd8ec5f137d45273f60065985b6a5b766aa978855(34003500000000000000000000,0,0)tuple
CrowdsaleTokenExtgetReservedTokensListValInPercentageUnit0xd8ec5f137d45273f60065985b6a5b766aa9788550uint256
CrowdsaleTokenExtgetReservedTokensListValInPercentageDecimals0xd8ec5f137d45273f60065985b6a5b766aa9788550uint256
CrowdsaleTokenExtgetReservedTokensListValInTokens0xd8ec5f137d45273f60065985b6a5b766aa97885534003500000000000000000000uint256
CrowdsaleTokenExtmintAgents0x766e51c940b9656e34b91041ca8afa00b7e9ed71TRUEbool
CrowdsaleTokenExtmintingFinishedNoneFALSEbool
CrowdsaleTokenExttotalSupplyNone54406432930609771417285772uint256
CrowdsaleTokenExtbalanceOf0xd8ec5f137d45273f60065985b6a5b766aa9788550uint256
CrowdsaleTokenExtreleaseAgentNone0x766e51c940b9656e34b91041ca8afa00b7e9ed71address
CrowdsaleTokenExtreleasedNoneFALSEbool

3.3.2 MintedTokenCappedCrowdsaleExt Function: finalize

The finalization process begins when the crowdsale owner address calls finalize. In order to allocate reserved functions and unlock the token, MintedTokenCappedCrowdsaleExt.finalize() must also be able to call ReservedTokenFinalizeAgent.finalizeCrowdsale(). The state guards in  MintedTokenCappedCrowdsaleExt.finalize() are:

Contract:Function/Field:Input:Value:Type:
MintedTokenCappedCrowdsaleExtfinalizedNoneFALSEbool
MintedTokenCappedCrowdsaleExtfinalizeAgentNone0x766e51c940b9656e34b91041ca8afa00b7e9ed71address
MintedTokenCappedCrowdsaleExtgetStateNoneState.SuccessState enum
MintedTokenCappedCrowdsaleExtownerNonemsg.senderaddress
MintedTokenCappedCrowdsaleExthaltedNoneFALSEbool

From the above section, we see that A, B, C, and E will pass. Then, MintedTokenCappedCrowdsaleExt.finalize() will pass if the sender is the crowdsale contract owner, address 0x75d6a12bba56441259483243b9c6aba1a171c410. The Authio team has verified that Block Array is in control of this address.

Once state guards are passed, MintedTokenCappedCrowdsaleExt.finalized is set to true.

3.3.3 ReservedTokensFinalizeAgent Function: finalizeCrowdsale

From the crowdsale contract, ReservedTokensFinalizeAgent.finalizeCrowdsale() is called. In order to create the crowdsale’s reserved tokens, ReservedTokensFinalizeAgent must be able to call CrowdsaleTokenExt.mint(address, uint). In order to release tokens for transfer, ReservedTokensFinalizeAgent must be able to call CrowdsaleTokenExt.releaseTokenTransfer(). The state guards for this are:

Contract:Function/Field:Input:Value:Value Type:
ReservedTokensFinalizeAgentcrowdsaleNonemsg.senderaddress
CrowdsaleTokenExtmintAgents0x766e51c940b9656e34b91041ca8afa00b7e9ed71TRUEbool
CrowdsaleTokenExtmintingFinishedNoneFALSEbool
CrowdsaleTokenExtreleaseAgentNone0x766e51c940b9656e34b91041ca8afa00b7e9ed71address

From the above sections, we see that A, B, C, and D are true. Then, ReservedTokensFinalizeAgent.finalizeCrowdsale() will pass if the loops in its body do not throw.The first loop iterates once, from uint8 j = 0 to j = 1. In order for the loop to pass with the appropriate state changes, the following must be true:

Contract:Function/Field:Input:Value:Value Type:
CrowdsaleTokenExtreservedTokensDestinations00xd8ec5f137d45273f60065985b6a5b766aa978855address
CrowdsaleTokenExtgetReservedTokensListValInPercentageUnit0xd8ec5f137d45273f60065985b6a5b766aa9788550uint256
CrowdsaleTokenExtgetReservedTokensListValInPercentageDecimals0xd8ec5f137d45273f60065985b6a5b766aa9788550uint256

From the above sections, we see that A, B, and C are true. The second loop iterates once as well, from uint8 i = 0 to i = 1. In order for the loop to pass and the correct reserve tokens to be created, the following must be true:

Contract:Function/Field:Input:Value:Value Type:
CrowdsaleTokenExtgetReservedTokensListValInTokens0xd8ec5f137d45273f60065985b6a5b766aa97885534003500000000000000000000uint256

From the above sections, we see that A is true. The function is now able to call CrowdsaleTokenExt.mint(0xd8ec5f137d45273f60065985b6a5b766aa978855, 34003500000000000000000000), and CrowdsaleTokenExt.releaseTokenTransfer().

No state changes occur within the ReservedTokensFinalizeAgent contract.

3.3.4 CrowdsaleTokenExt Function: mint

From the ReservedTokensFinalizeAgent contract, CrowdsaleTokenExt.mint(0xd8ec5f137d45273f60065985b6a5b766aa978855, 34003500000000000000000000) is called. The state guards for this function were discussed in the previous section, where it was determined that they would pass.

As a result, CrowdsaleTokenExt.totalSupply is set to 88409932930609771417285772, and
CrowdsaleTokenExt.balanceOf(0xd8ec5f137d45273f60065985b6a5b766aa978855) is set to 34003500000000000000000000.

3.3.5 CrowdsaleTokenExt Function: releaseTokenTransfer

From the ReservedTokensFinalizeAgent contract, CrowdsaleTokenExt.mint(0xd8ec5f137d45273f60065985b6a5b766aa978855, 34003500000000000000000000) is called. The state guards for this function were discussed in the previous section, where it was determined that they would pass.

As a result, CrowdsaleTokenExt.totalSupply is set to 88409932930609771417285772, and
CrowdsaleTokenExt.balanceOf(0xd8ec5f137d45273f60065985b6a5b766aa978855) is set to 34003500000000000000000000.

3.3.6 State Changes Observed

Following finalization described above, the following state changes are observed:

Contract:Function/Field:Input:Previous:Current:
CrowdsaleTokenExtmintingFinishedNoneFALSETRUE
CrowdsaleTokenExtreleasedNoneFALSETRUE
CrowdsaleTokenExtbalanceOf0xd8ec5f137d45273f60065985b6a5b766aa978855034003500000000000000000000
CrowdsaleTokenExttotalSupplyNone5440643293060977141728577288409932930609771417285772
MintedTokenCappedCrowdsaleExtfinalizedNoneFALSETRUE

3.4: Effects of Observed State Changes

Following finalization, the changes made in the contracts’ states allow some functions, and guard against others. The following is an overview of functions now allowed and disallowed, following the state changes described above.

3.4.1 CrowdsaleTokenExt.released

With CrowdsaleTokenExt.released set to true, the following changes are observed:

Contract:State Guard:Input:New Behavior:Allows/Disallows:Function/Field:
CrowdsaleTokenExtcanTransferaddressPassesallowsCrowdsaleTokenExt.transfer
CrowdsaleTokenExtcanTransferaddressPassesallowsCrowdsaleTokenExt.transferFrom
CrowdsaleTokenExtinReleaseStatebool (false)FailsdisallowsCrowdsaleTokenExt.setReleaseAgent
CrowdsaleTokenExtinReleaseStatebool (false)FailsdisallowsCrowdsaleTokenExt.setTransferAgent
CrowdsaleTokenExtcanUpgradeNoneReturns trueallowsCrowdsaleTokenExt.setUpgradeAgent

3.4.2 CrowdsaleTokenExt.mintingFinished

With CrowdsaleTokenExt.mintingFinished set to true, the following changes are observed:

Contract:State Guard:Input:New Behavior:Allows/Disallows:Function/Field:
CrowdsaleTokenExtcanTransferaddressPassesallowsCrowdsaleTokenExt.transfer
CrowdsaleTokenExtcanTransferaddressPassesallowsCrowdsaleTokenExt.transferFrom
CrowdsaleTokenExtinReleaseStatebool (false)FailsdisallowsCrowdsaleTokenExt.setReleaseAgent
CrowdsaleTokenExtinReleaseStatebool (false)FailsdisallowsCrowdsaleTokenExt.setTransferAgent
CrowdsaleTokenExtcanUpgradeNoneReturns trueallowsCrowdsaleTokenExt.setUpgradeAgent

3.4.3 MintedTokenCappedCrowdsaleExt.finalized

With MintedTokenCappedCrowdsaleExt.finalized set to true, the following changes are observed:

Contract:State Guard:Input:New Behavior:Allows/Disallows:Function/Field:
MintedTokenCappedCrowdsalefinalizeNonefailsdisallowsCrowdsale refinalization
MintedTokenCappedCrowdsalesetStartsAtuintfailsdisallowsSetting Crowdsale start time
MintedTokenCappedCrowdsalesetEndsAtuintfailsdisallowsSetting Crowdsale end time
MintedTokenCappedCrowdsalegetStateNonereturns State.FinalizeddisallowsPurchase and refund functions
MintedTokenCappedCrowdsalesetMaximumSellableTokensuintfailsdisallowsSetting Crowdsale sellable tokens

4. Documents & Resources

4.1 Project Codebase

The current Block Array crowdsale and token contract code can be found in the PoA Network’s ico-wizard-audit github repository:

https://github.com/poanetwork/ico-wizard-audit

5. Conclusion

The Authio team would like to thank both PoA Network and Block Array for their assistance in securing the live contracts. While the templated contracts used for the crowdsale contain vulnerabilities and should not be used again, the cooperation of these groups made it possible to secure the finalization of the crowdsale, such that the tokens purchased during the crowdsale are able to be released without unwanted consequence. The Authio team recommends that Block Array finalize the crowdsale as soon as they are able to do so.