Skip to content

Instantly share code, notes, and snippets.

@yaronvel
Created July 10, 2017 16:23
Show Gist options
  • Save yaronvel/ab0c9cb2df6fd781dd666d08ff1986a9 to your computer and use it in GitHub Desktop.
Save yaronvel/ab0c9cb2df6fd781dd666d08ff1986a9 to your computer and use it in GitHub Desktop.

Table of Contents

Introduction

In the dates of June 20th 2017 to June 30th 2017, CoinDash engaged Yaron Velner and Victor Tran from the SmartPool team to perform security audit for their ICO contracts. The audited contracts currently resides in CoinDash private repository. The audited code was timestamped with the hash 0b8fc008894dddc60d1233b84d877b5a76473d32 in the CoinDash repository.

Update: On July 10th CoinDash asked us to review a modified version of their code timestamped with 88788009130eea6e404e23613081c4abe26ae3b5.

Terminology

This audit uses the following terminology. Note that we only rank the likelihood, impact and Severity for bug/security-related issues.

1. Likelihood

How likely a bug is to be encountered or exploited when deployed in practice, as specified by the OWASP risk rating methodology.

2. Impact

The impact a bug would have if exploited, as specified by the OWASP risk rating methodology.

3. Severity

How serious the issue is, derived from Likelihood and Impact as specified by the OWASP risk rating methodology.

Findings

Below is our audit results and recommendations, listed in order of importance.

1. Severe security flaws

We did not find any severe security problems with the code.

2. Architecture and design choices

Overall, the code is clearly written and well modularized. CoinDash team wisely decided to make full use of Open-Zeppelin existing Vested Token module as the core functionality of their token. This decision significantly simplified the code and mitigated the risk for potential bugs.

3. Use of best practices

The contracts employ currently best practices like SafeMath and modifiers. The use of Open-Zeppeling code mitigate recent attacks as the short address attack and approve double spending attack.

However we are concerned about the next three issues:

3.1 Use of old compiler version

  • Likelihood: low
  • Impact: medium

Currently the CoinDash team is using compiler version 0.4.6. We encourage them to use recent 0.4.11 compiler version.

Update: compiler version was changed to 0.4.8. Coindash team should be aware that when compiling with 0.4.11 version, additional warnings occur. In particular, the initialization of constant variables with non-constant function is deprecated in current solidity compiler versions.

3.2 Test regression is not fully automated

  • Likelihood: low
  • Impact: low

Current test regression requires CoinDash team to manually run the tests one by one (otherwise, some of them fail). We recommend them to fully automated the process in order to mitigate potential human errors.

3.3 Open-Zeppelin code was not imported to the repository

  • Likelihood: low
  • Impact: low

Currently, CoinDash team has to (manually) fetch Open-Zeppelin latest code to local disk before deployment. This could give rise to potential human errors that will fetch the wrong code, fetch it to wrong directory, and unexpected changes in Open-Zeppelin code could introduce integration bugs. We recommend CoinDash team to fix an Open-Zeppelin commit hash for their use and put it in their repository. Prior to the deployment of the contract they should manually query Open-Zeppelin github to see if critical changes were done.

4. Medium level bugs

4.1 totalSupply is always 0

  • Likelihood: high
  • Impact: medium

totalSupply is not set in CDTToken constructor. And will remain 0 forever. We also recommend to log the creation of the new tokens as a Transfer event from 0x0 to owner.

Update: totalSupply is properly initialized in the new code.

4.2 Incorrect check of allocated token cap

  • Likelihood: low
  • Impact: medium

The processPurchase function checks if cdtSold >= ALLOC_CROWDSALE before allocating tokens to the contributors, and does not take into account the current purchase amount. This check should be fixed to cdtSold + o_amount >= ALLOC_CROWDSALE.

However, the likelihood of this bug is low as allocating more tokens than ALLOC_CROWDSALE is expected to make transfer function to throw and revoke the contribution. In other words, it is likely impossible to allocate more tokens even in the presence of this buggy checking.

Update: problem was fixed in the new code.

5. Suggestions

5.1 Rename token name "CoinDash Token" to "CoinDash"

Token name usually does not contain "token" (see here).

5.2 Allow token contract to drain its received funds

History suggests that users mistakenly transfer tokens or Ether to token contracts. Consider implementing a drain function like this. We note that this is not a standard at the moment and last minute implementation could introduce new bugs. Hence, we leave it to the CoinDash team to decide if they want to do it or not.

Update: CoinDash has implemented a function that can drain only Ether funds. However, it does not solve the case where tokens are stuck inside the contract. Moreover, the function is not needed, as Ether cannot be deposited into the token contract (all functions are non-payable). Finally, the function makes use of a new modifier, namely, only_owner, instead of using Zeppelin onlyOwner existing modifier. Nevertheless, this is a minor issue with very low chances of producing an actual bug. Hence, it is likely OK to leave this code.

6. Low severity issue and comments

6.1 In CDTToken.sol, the variable creator serves the same purpose as owner variable (which is defined in VestedToken).

Consider removing it.

6.2 Consider having addresses like 0xfd6259c709Be5Ea1a2A6eC9e89FEbfAd4c095778 as constants or c'tor params.

6.3 Use of weeks key word

In allocateTokensWithVestingToTeam you could use 1 years instead of 52 weeks and 1 years / 2 instead of 26 weeks.

6.4 ethReceived variable actually holds the amount of received wei (and not Ether)

Update: variable name was changed to weiReceived.

6.5 event PreBuy is defined but never used

Update: event was removed from code.

6.6 emptyContribuitionPool does not use safe math

It is extremely important to use safe math here in light of a possible bug in processPurchase.

Update: code was fixed to use safe math.

7. Additional Information and Notes

7.1 Tokens are transferable also before ICO ends

Contributers should be aware that tokens are transferable from the moment they are purchased. Even before ICO ends.

7.2 CoinDash immediately controls the received Ether

Contributers should be aware that all contributed Ether are immediately available for CoinDash for any purpose.

7.3 Token distribution

                 Token Distribution
+----------------------+-----------------------------+
|        Holder        |            Token            |
+                      +-----------------------------+
|                      | Quantity   | Percentage (%) |
+----------------------+------------+----------------+
| Team | Liquid Team   |  100000000 |             10 |
+      +---------------+------------+----------------+
|      | Illiquid Team |  100000000 |             10 |
+------+---------------+------------+----------------+
| Company              |  290000000 |             29 |
+----------------------+------------+----------------+
| Bounties             |   10000000 |              1 |
+----------------------+------------+----------------+
| Crowdsale            |  500000000 |             50 |
+----------------------+------------+----------------+
| Total                | 1000000000 |                |
+----------------------+------------+----------------+
                                                                  Vested Token Distribution          
+-------------+--------------------------------------------+--------------------------------------------+----------+--------------+
|             | Address                                    | Granted token                              | Cliff    | Vesting time |
+             +                                            +--------------------------------------------+----------+--------------+
|             |                                            | Quantity  | Percentage to total supply (%) |          |              |
+-------------+--------------------------------------------+-----------+--------------------------------+----------+--------------+
| Liquid Team | 0xfd6259c709Be5Ea1a2A6eC9e89FEbfAd4c095778 |  20000000 |                              2 | 6 months | 1 year       |
+             +--------------------------------------------+-----------+--------------------------------+----------+--------------+
|             | 0xC09544dA6F50441c024ec150eCEDc72De558ce94 |  20000000 |                              2 | 6 months | 1 year       |
+             +--------------------------------------------+-----------+--------------------------------+----------+--------------+
|             | 0xa900191B0542e27A0022a05c45c152DFa98DB026 |  20000000 |                              2 | 6 months | 1 year       |
+             +--------------------------------------------+-----------+--------------------------------+----------+--------------+
|             | 0x05b481E52e1Ca0A21C147016C4df729764615Afb |  20000000 |                              2 | 6 months | 1 year       |
+             +--------------------------------------------+-----------+--------------------------------+----------+--------------+
|             | 0xc6bFce8cEad4EcC595bA227b9527AFA914dD8183 |  20000000 |                              2 | 6 months | 1 year       |
+-------------+--------------------------------------------+-----------+--------------------------------+----------+--------------+
| Company     | Initialized when contract is deployed      | 290000000 |                             29 | 6 months | 1 year       |
+-------------+--------------------------------------------+-----------+--------------------------------+----------+--------------+
|                                                    Total | 390000000 |                             39 |          |              |
+----------------------------------------------------------+-----------+--------------------------------+----------+--------------+

Update: CoinDash team has made following token distribution and vesting token distribution updates:

  1. Allocate 1.25% of total token supply to WINGS DAO participants.
  2. Change all addresses of the team.
  3. Company's token is set to 1 year cliff and no vesting time after the cliff.

The current distribution is presented in the tables below. We note that in the time of writing (10/7/2017), the tables are consistent with CoinDash statement as it appear in their website.

                Token Distribution  
+----------------+----------------------------+
|     Holder     |            Token           |
+                +----------------------------+
|                | Quantity      | Percentage |
+----------------+---------------+------------+
| Liquid contrib |   100,000,000 |        10% |
+----------------+---------------+------------+
| Illiquid team  |   100,000,000 |        10% |
+----------------+---------------+------------+
| Bounty program |    10,000,000 |         1% |
+----------------+---------------+------------+
| Wings          |    12,500,000 |      1.25% |
+----------------+---------------+------------+
| Company        |   290,000,000 |        29% |
+----------------+---------------+------------+
| Crowdsale      |   487,500,000 |     48.75% |
+----------------+---------------+------------+
| Total          | 1,000,000,000 |       100% |
+----------------+---------------+------------+
                                                                  Vested Token Distribution          
+---------+--------------------------------------------+----------------------------------------------+----------+-----------------+
|         |                   Address                  |                 Granted token                | Cliff    | Vesting time    |
+         +                                            +----------------------------------------------+----------+-----------------+
|         |                                            | Quantity    | Percentage to total supply (%) |          |                 |
+---------+--------------------------------------------+-------------+--------------------------------+----------+-----------------+
|   Team  | 0x9c160d7450400b59AA3e7D1a8cc4Bf664859aB4B |  20,000,000 |                              2 | 6 months | 1 year          |
+         +--------------------------------------------+-------------+--------------------------------+----------+-----------------+
|         | 0x97251AA8f0a71b10E90077AebabEd0c1e2626455 |  20,000,000 |                              2 | 6 months | 1 year          |
+         +--------------------------------------------+-------------+--------------------------------+----------+-----------------+
|         | 0xBA361d8b9A6D7CE1603Cf526604ce5431ecc0E76 |  20,000,000 |                              2 | 6 months | 1 year          |
+         +--------------------------------------------+-------------+--------------------------------+----------+-----------------+
|         | 0x0C60180e5F1dEf7Daa947F88bF840dCeF8A27f53 |  20,000,000 |                              2 | 6 months | 1 year          |
+         +--------------------------------------------+-------------+--------------------------------+----------+-----------------+
|         | 0x3f0C1028d5F55CaA11208173D8AE09d42c3ff5B0 |  20,000,000 |                              2 | 6 months | 1 year          |
+---------+--------------------------------------------+-------------+--------------------------------+----------+-----------------+
| Company | Initialized when contract is deployed      | 290,000,000 |                             29 | 1 year   | no vesting time |
+---------+--------------------------------------------+-------------+--------------------------------+----------+-----------------+

7.4 Hard cap of the ICO

40,000 Ether

Update: hard cap is expected to change according to ETH price at the time of ICO.

8 Tests

CoinDash team created tests to check the different behavior among stages in the crowd-sale, and to verify that tokens are correctly allocated to the team and company. Given the relative simplicity of the code, we find testing level adequate in general. However, we do have few concerns.

8.1 Lack of testing for Open-Zeppelin code

We recommend CoinDash team to include Open-Zeppelin tests in their regression. We recall that at least in one incident failing to test Open-Zeppelin supplied code entailed a post ICO redeployment of the token contract (as the developers failed to noticed they changed Open-Zeppelin code).

8.2 Regression is not fully automated

Current test regression requires CoinDash team to manually run the tests one by one (otherwise, some of them fail). We recommend them to fully automate the process in order to mitigate potential human errors.

8.3 Missing coverage

The following cases are not tested:

  1. call to emptyContribuitionPool before end of crowd-sale period, and a call that is done not by the owner.
  2. A call to toggleHalt not by the owner.
  3. Purchasing of tokens after toggleHalt re-enables buying.
  4. Transferring tokens after vesting period is over. Arguably, this is covered by Open-Zeppelin tests. However, we recommend to test it explicitly.
  5. Value of totalSupply.
  6. Trying to exceed maximum token cap.

Update: Tests for items 1,2,3 and 4 were added.

8.4 Minor comments

  1. Instead of assert.equal(1,0,err);, you could use assert(false, err) or assert.fail().
  2. Testing transfer for negative amounts is meaningless, as uint cannot get negative values. -50 is actually 2^256 - 50.

9. Bug bounty

The time of writing, CoinDash did not launch a bug bounty program.

Update: CoinDash is planning to make their repository public and announced a bug bounty program.

10. Conclusion

No severe security issues were found. Prior to the launch of the ICO, CoinDash team should address the issues we raised at Sections 3 and 4, and launch a bug bounty program (for a period of at least one week).

Update: CoinDash team has addressed all the issues we raised for Section 4. Issues from Section 3 were only partially addressed, however the remaining issues are of low likelihood, and we leave the decision of whether they should be addressed to the team. In addition, CoinDash launched a bug bounty program.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment