bokkypoobah / InvestFeedCrowdsaleAudit

InvestFeed Crowdsale Audit

Home Page:http://www.investfeed.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

InvestFeed Crowdsale Audit

This is an audit of InvestFeed's crowdsale contracts.

No potential vulnerabilities have been identified in the crowdsale and token contracts.

Details of the reviews are below.



Table Of Contents



Updates



Scope

This audit is into the technical aspects of the crowdsale contracts. The primary aim of this audit is to ensure that funds contributed to these contracts are not easily attacked or stolen by third parties. The secondary aim of this audit is that ensure the coded algorithms work as expected. This audit does not guarantee that that the code is bugfree, but intends to highlight any areas of weaknesses.



Limitations

This audit makes no statements or warranties about the viability of the InvestFeed's business proposition, the individuals involved in this business or the regulatory regime for the business model.



Due Diligence

As always, potential participants in any crowdsale are encouraged to perform their due diligence on the business proposition before funding the crowdsale.

Potential participants are also encouraged to only send their funds to the official crowdsale Ethereum address, published on InvestFeed's official communication channel.

Scammers have been publishing phishing address in the forums, twitter and other communication channels, and some go as far as duplicating crowdsale websites. Potential participants should NOT just click on any links received through these messages.

Potential participants should also confirm that the verified source code on EtherScan.io for the published crowdsale address matches the audited source code, and that the deployment parameters are correctly set, including the constant parameters.

Potential participants should note that there is a minimum funding goal in this crowdsale and there are refunds if this minimum funding goal is not reached.

InvestFeed will have to load funds back into the crowdsale contract for investors to withdraw their refunds.

This contract has no mechanism to enforce any vesting of InvestFeed's tokens.



Risks

This crowdfunding contract has a relatively low risk of losing large amounts of ethers in an attack or a bug, as funds contributed by participants are immediately transferred into a multisig wallet.

The flow of funds from this crowdsale contract should be monitored using a script and visually through EtherScan. Should there be any abnormal gaps in the crowdfunding contracts, potential participants should be informed to stop contributing to this crowdsale contract. Most of the funds will be held in the multisig wallet, so any potential losses due to flaws in the crowdsale contract should be minimal.

In the case of the crowdfunding contract allocating an incorrect number of tokens for each contribution, the token numbers can be manually recalculated and a new token contract can be deployed at a new address.



Trustlessness Of The Crowdsale Contract

  • The PricingStrategy can be changed at any point by the owner when the crowdsale is running. Comment in the source code:

    Design choice: no state restrictions on the set, so that we can fix fat finger mistakes.

    A change in the pricing strategy can only be detected by looking for this Crowdsale.setPricingStrategy(...) transaction, and the ETH to token rate changes.

  • The crowdsale end date can be changed by the owner at any point during the crowdsale, to a time later than when the change is made. Comment in the source code:

    Allow crowdsale owner to close early or extend the crowdsale.

    This is useful e.g. for a manual soft cap implementation:

    • after X amount is reached determine manual closing

    This may put the crowdsale to an invalid state, but we trust owners know what they are doing.

    The EndsAtChanged(...) event is logged.

    The crowdsale contract owner can also re-open a closed crowdsale using this parameter, if the crowdsale has not been finalized.

  • Some negative scenarios:

    • An investor may decide to invest near the end of the crowdsale if only a small amount has been contributed by other investors. The crowdsale contract owner may extend the crowdsale closing date to any point in the future.

    • An investor may decide to wait nearer to the end of the crowdsale to invest, but the owners can suddenly close down the crowdsale. They would normally inform their community that they plan to close down the crowdsale prematurely, but this could be 24 hours and not be enough time for this investor to respond.

  • This crowdsale contract moves all investor contributions straight into the crowdsale team's multisig wallet. If the minimum funding goal is not reached, investors will only be able to claim their refunds IF the crowdsale team moves all original funds back from the multisig into the crowdsale contract. See Crowdsale.loadRefund().

  • The upgrade agent can be set by the upgrade master (crowdsale team's account), but accounts have to execute the upgrades themselves, which is a good trustless upgrade

  • Once the crowdsale if finalised, the token contract has the right elements for a trustless token contract



Potential Vulnerabilities

No potential vulnerabilities have been identified in the crowdsale and token contract.



First Review

The MintedEthCappedCrowdsale crowdsale contract is deployed at 0x70791b81028f30ff01d4ad8f83cbffcd2be1b1f3

The variable token points to CrowdsaleToken deployed at 0xafcb18e95b10a18baeaf69baac1ac610df9f7d12

The variable pricingStrategy points to EthTranchePricing deployed at 0x486e49d1622fdfc8ca760fcfc17792753a4beca8

The variable finalizeAgent points to BonusFinalizeAgent deployed at 0xde5bb4b67b64daa2a92df3abf662023f06e599d8

Following are the line counts in each of the contracts:

$ wc -l *
     748 BonusFinalizeAgent.sol
     421 CrowdsaleToken.sol
     452 EthTranchePricing.sol
     772 MintedEthCappedCrowdsale.sol
    2393 total

Some potential issues:



Second Review

Second review of https://github.com/investfeed-corp/feed-token-sale/commit/57cdb3867d4616c41b21e8948ff507730a513e25.

Files available in contracts-secondreview.

Some potential issues:

  • #4 MEDIUM IMPORTANCE - Attribute the source of the source code

    • Fixed in third review.
  • #5 MEDIUM IMPORTANCE - Use acceptOwnership(...) pattern in Owned contract

    • Fixed in third review
  • #6 LOW IMPORTANCE - assert(...) is built-in in Solidity 0.4.11 - https://github.com/investfeed-corp/feed-token-sale/blob/master/CrowdsaleTokenCombined.sol#L22-L24

    • Some change incorporated, and this is not necessary - in fourth review.
  • #7 LOW IMPORTANCE - Use require(...) instead of throw or assert(...) - from https://www.reddit.com/r/ethereum/comments/6llgxv/solidity_0413_released/, "Syntax Checker: Deprecated throw in favour of require(), assert() and revert()"

    • Some changes incorporated, and this is not necessary - in fourth review.
  • #8 LOW IMPORTANCE - The new OpenZeppelin libraries now use balances[msg.sender] = balances[msg.sender].sub(_amount); instead of balances[_to] = safeAdd(balances[_to],_value); style

    Change not incorporated, and not necessary - in fourth review.

  • #9 LOW IMPORTANCE - Decide on 2 or 4 spaces for tabs, have consistent spacing between functions, groups of statements, prettify source so investors can read easily and require less trust

    • Some small areas with inconsistent spacing - in fourth review.


Third Review

Third review of https://github.com/investfeed-corp/feed-token-sale/commit/2007dc6163cc8a2c27cc6c3e35023663b1641214.

Setting up tests.

Some potential issues:

  • #10 MEDIUM IMPORTANCE - Comments from the individual contract files should be left in the combined files to make it more readable

    • Comments have now been left in the combined files - in fourth review.
  • #11 MEDIUM IMPORTANCE - Use the ConsenSys multisig or Ethereum multisig as these are more widely use, unless you have a good reason to use the OpenZeppelin multisig

    • InvestFeed is using the ConsenSys multisig - in fourth review.
  • #12 MEDIUM IMPORTANCE - Developer to review recent changes to the OpenZeppelin and TokenMarket libraries since the contracts were copied, for high priority bugs

    • InvestFeed incorporated changes to StandardToken.sol to remove addApproval(...) and subApproval(...) in the fourth review.


Fourth Review

Fourth review of https://github.com/investfeed-corp/feed-token-sale/commit/68f31e23c40b405275ad1b521fc222ec7cccdde8.

There were some changes to contracts/Crowdsale.sol and contracts/StandardToken.sol which will be reviewed below.

The combined files have been updated to leave the comments from the individual files in place.



Recommendations



Notes

  • If the crowdsale does not reach the minimum funding goal by the end of the crowdsale period, all funds supporting the tokens issued must be moved back into the crowdsale contract before the refund state is activated. This includes the funds that support the tokens created using the preallocate(...) function.

    It is important to get the weiPrice parameter of the preallocate(...) function correct, as noone will be able claim their refunds and the ethers may be trapped in this crowdsale contract.

    Once scenario is where the preallocate(...) function has the weiPrice out by a factor of 10 times. 10 times as much funds that were collected during the preallocation phase will need to be moved back into the crowdsale contract for refunds to be active.

  • The preallocate(...) function can be executed at any time before, during and after the crowdsale, but before finalisation of the crowdsale. Normally this function is used before the crowdsale starts.

  • The preallocate(...) function can only be used to allocate round token amounts and not fractional token amounts. E.g. 10 instead of 10.123456789000000000

  • If CrowdsaleToken.(UpgradeableToken).setUpgradeMaster(...) is called with an invalid new upgrade master, upgrades can be prevented forever

  • The team bonus tokens are created as a percentage on top of the crowdsale tokens. If the team bonus tokens is 10% on top of the crowdsale tokens, the team bonus tokens will end up being 9.090909091% of the totalSupply. Let's say 1,000,000 tokens are raised by the crowdsale. 10% of this is 100,000 tokens. 100,000 / (1,000,000 + 100,000) = 100,000 / 1,100,000 = 9.090909090909091% .

  • There is no mechanism to transfer out any other ERC20 tokens from the crowdsale or token contracts. See for example https://github.com/openanx/OpenANXToken/blob/master/contracts/OpenANXToken.sol#L451-L458.



Crowdsale And Token Contracts Overview

  • This token contract is of moderate complexity
  • The code has been tested for the normal ERC20 use cases
    • Deployment, with correct symbol(), name(), decimals() and totalSupply()
    • transfer(...) from one account to another
    • approve(...) and transferFrom(...) from one account to another
    • While the transfer(...) and transferFrom(...) uses safe maths, there are checks so the function is able to return true and false instead of throwing an error
  • transfer(...) and transferFrom(...) is only enabled when the crowdsale is finalised, when either the funds raised matches the cap, or the current time is beyond the crowdsale end date
  • transferOwnership(...) has acceptOwnership() to prevent errorneous transfers of ownership of the token contract
  • ETH contributed to the crowdsale contract is immediately moved to a separate wallet
  • ETH cannot be trapped in the token contract as the default function () payable is not implemented
  • Check potential division by zero
  • All numbers used are uint (which is uint256), with the exception of decimals, reducing the risk of errors from type conversions
  • Areas with potential overflow errors in transfer(...) and transferFrom(...) have the logic to prevent overflows
  • Areas with potential underflow errors in transfer(...) and transferFrom(...) have the logic to prevent underflows
  • Function and event names are differentiated by case - function names begin with a lowercase character and event names begin with an uppercase character
  • The default function will NOT receive contributions during the crowdsale phase and mint tokens. Users have to execute a specific function to contribute to the crowdsale contract
  • The testing has been done using geth v1.6.5-stable-cf87713d/darwin-amd64/go1.8.3 and solc 0.4.11+commit.68ef5810.Darwin.appleclang instead of one of the testing frameworks and JavaScript VMs to simulate the live environment as closely as possible
  • The test scripts can be found in test/01_test1.sh
  • The test results can be found in test/test1results.txt for the results and test/test1output.txt for the full output
  • There is a switch to pause and then restart the contract being able to receive contributions
  • The transfer(...) call is the last statements in the control flow of investInternal(...) to prevent the hijacking of the control flow
  • The token contract does not implement the check for the number of bytes sent to functions to reject errors from the short address attack. This technique is now NOT recommended
  • This contract implement a modified approve(...) functions to mitigate the risk of double spending by requiring the account to set a non-zero approval limit to 0 before modifying this limit


Code Review

The *Combined.sol files are from the third review, and was used to compile the individual files to be code-reviewed in the fourth review.

The deployment will be based on contracts-fourthreview/MasterCombined.sol.

The script contracts/generateMyMasterCombined.sh was used to generate contracts/MyMasterCombined.sh.

The differences between MasterCombined.sol and MyMasterCombined.sol follows, and confirms that the individual .sol files have been correctly merged into MasterCombined.sol:

$ diff MyMasterCombined.sol ../contracts-fourthreview/MasterCombined.sol 
2c2
< 
---
> // Thanks to OpenZeppeline & TokenMarket for the awesome Libraries.
21,22d20
< pragma solidity ^0.4.11;
< 
24,28d21
< /**
<  * @title Ownable
<  * @dev The Ownable contract has an owner address, and provides basic authorization control 
<  * functions, this simplifies the implementation of "user permissions". 
<  */
33,36d25
<   /** 
<    * @dev The Ownable constructor sets the original `owner` of the contract to the sender
<    * account.
<    */
40,44d28
< 
< 
<   /**
<    * @dev Throws if called by any account other than the owner. 
<    */
49,53d32
< 
<   /**
<    * @dev Allows the current owner to transfer control of the contract to a newOwner.
<    * @param _newOwner The address to transfer ownership to. 
<    */
63c42
< 
---
>   
65,70c44
< pragma solidity ^0.4.11;
< /**
<  * @title ERC20Basic
<  * @dev Simpler version of ERC20 interface
<  * @dev see https://github.com/ethereum/EIPs/issues/20
<  */
---
> 
76,81c50,51
< }pragma solidity ^0.4.11;
< import './ERC20Basic.sol';
< /**
<  * @title ERC20 interface
<  * @dev see https://github.com/ethereum/EIPs/issues/20
<  */
---
> }
> 
88d57
< pragma solidity ^0.4.11;
90,94d58
< import './ERC20.sol';
< 
< /**
<  * A token that defines fractional units as decimals.
<  */
98,102d61
< pragma solidity ^0.4.11;
< 
< import './ERC20.sol';
< import './SafeMathLib.sol';
< 
104,109d62
< /**
<  * Standard ERC20 token with Short Hand Attack and approve() race condition mitigation.
<  *
<  * Based on code by FirstBlood:
<  * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
<  */
178d130
< pragma solidity ^0.4.11;
194,198d145
< pragma solidity ^0.4.11;
< 
< import './ERC20.sol';
< import './StandardToken.sol';
< import "./UpgradeAgent.sol";
331,335d277
< pragma solidity ^0.4.11;
< 
< import './Ownable.sol';
< import './ERC20.sol';
< 
423,427d364
< pragma solidity ^0.4.11;
< import './ERC20.sol';
< import './Ownable.sol';
< import './StandardToken.sol';
< import "./SafeMathLib.sol";
483,489d419
< pragma solidity ^0.4.11;
< 
< import './StandardToken.sol';
< import "./UpgradeableToken.sol";
< import "./ReleasableToken.sol";
< import "./MintableToken.sol";
< 
580d509
< pragma solidity ^0.4.11;
606d534
< pragma solidity ^0.4.11;
639,641d566
< pragma solidity ^0.4.11;
< 
< import './Ownable.sol';
678,685d602
< pragma solidity ^0.4.11;
< 
< import "./SafeMathLib.sol";
< import "./Haltable.sol";
< import "./PricingStrategy.sol";
< import "./FinalizeAgent.sol";
< import "./FractionalERC20.sol";
< 
1229,1233d1145
< pragma solidity ^0.4.11;
< 
< import "./Crowdsale.sol";
< import "./CrowdsaleToken.sol";
< import "./SafeMathLib.sol";
1317,1320d1228
< pragma solidity ^0.4.11;
< 
< import "./Crowdsale.sol";
< import "./MintableToken.sol";
1357d1264
< pragma solidity ^0.4.11;
1359,1367c1266,1270
< import "./PricingStrategy.sol";
< import "./Crowdsale.sol";
< import "./SafeMathLib.sol";
< import './Ownable.sol';
< 
< /// @dev Tranche based pricing with special support for pre-ico deals.
< ///      Implementing "first price" tranches, meaning, that if byers order is
< ///      covering more than one tranche, the price of the lowest tranche will apply
< ///      to the whole order.
---
> /** Tranche based pricing with special support for pre-ico deals.
>  *      Implementing "first price" tranches, meaning, that if byers order is
>  *      covering more than one tranche, the price of the lowest tranche will apply
>  *      to the whole order.
>  */
1513c1416
< }
---
> }
\ No newline at end of file


References



Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd for InvestFeed Jul 12 2017. The MIT Licence.

About

InvestFeed Crowdsale Audit

http://www.investfeed.com


Languages

Language:Shell 68.1%Language:JavaScript 31.9%