Skip to content

bokkypoobah/FunFairCrowdsaleContractAudit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FunFair Crowdsale Contract Audit

Report status: Work in progress. The smart contract code has some minor issues. Further testing is being conducted to confirm that there are no other side effects.

Bok Consulting Pty Ltd was requested to audit the smart contracts for the upcoming FunFair Token Presale contracts within a day of the crowdsale.

The smart contracts covered in this audit in the original request are:


Live Crowdsale Contract

As listed on FunFair's website, new version of FunFairSale has been published at 0x55c44fbad82686afb0ca41cefb8d086cb937b2e6 with current settings:

  • saleTime: 1209600
  • deadline: 1498154048 "Thu, 22 Jun 2017 17:54:08 UTC"
  • startTime: 1498140000 "Thu, 22 Jun 2017 14:00:00 UTC"
  • owner: 0x18250eaf72bbaa0237a662b9b85ebd8fa0cf128f
  • capAmount: 30690851057299820000000 (30690.85105729982 ETH)

This contract address has been published on FunFair's Slack as the crowdfunding contract.

The differences between these two contracts follow:

$ diff -b FunFairSale-new.sol FunFairSale.sol 
8d7
< 
49,50c48,50
<     uint public deadline = 1499436000;
<     uint public startTime = 1498140000;
---
>     uint public deadline;
>     uint public startTime = 123123; //set actual time here
>     uint public saleTime = 14 days;
53c53,55
<     function FunFairSale() {}
---
>     function FunFairSale() {
>         deadline = startTime + saleTime;
>     }
60a63,64
>         // cap is immutable once the sale starts
>         if (this.balance > 0) throw;
66,68c70,72
< 
<         if (this.balance > capAmount) {
<             deadline = block.timestamp - 1;
---
>         if (this.balance >= capAmount) throw;
>         if (this.balance + msg.value >= capAmount) {
>             deadline = block.timestamp;
74,76d77
< 
<         //testing return value doesn't do anything here
<         //but it stops a compiler warning
79a81
>     // for testing
81c83
<         if (block.timestamp >= startTime) throw;
---
>       if (_deadline < _startTime) throw;

As of Fri, 23 Jun 2017 00:59:30 UTC, the following funds were raised at this contract address:

  • 34,778.830690504502596672 Ether ~ $11,147,658.60 @ $320.53/ETH
  • 19.99 Aragon ~ $54.81
  • 13,975,230 BAT ~ $2,465,020.84
  • 63,108.15461481 Golem ~ $37,296.46
  • 69,000 Guppy ~ $24,583.87
  • 50 ICONOMI ~ $240.90
  • 98.10095511 REP ~ $2,937.85
  • 10,000 SNGLS ~ $1,903.72
  • 29,886.745 SwarmCity ~ $71,449.05
  • 51,031.64 WINGS ~ $26,473.94


Live Token Contract

As discussed on https://funfair.slack.com, the same version of the Token contract has been published at 0xBbB1BD2D741F05E144E6C4517676a15554fD4B8D with current settings:


Update Jun 29 2017

This audit is referenced in FunFair Token Contract Audit by Peter Vessenes.



Table of contents



Terminology

This audit uses the following terminonology. Note that we only rank the likelihood, impact and severity for bug and/or security related issues.

Likelihood

How likely a bug is to be encountered or exploited when deployed in practice, as specified by the OWASP Risk Rating Methodology.

Impact

The impact a bug would have if exploited, as specified by the OWASP Risk Rating Methodology.

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

From the preliminary results, there are no severe security issues in the FunFairSale contract. The token contracts are currently being tested.


2. Architecture And Design Choices

2.1 Bug - Double Declaration Of Token.owner

Likelihood: Low

Impact: Low

owner is declared in the Token contract, and is also inherited through the Finalizable contract that inherits owner in the Owned class.

The side effects is unknown, but an example of this occurred with the double declaration of totalSupply in the RAREPeperiumToken resulting in totalSupply being reported as 115792089237316195423570985008687907853269984665640564039457583907913129639936 as can be seen the Total Supply field.

In this contract, it seems that Token.owner is never used, so there may be no side effects from this double declaration.

Deploying the following code in Remix will result in the variable owned being set to a value like 0x000000000000000000000000ca35b7d915458ef540ade6068dfe2f44e8fa733c, and function getOwned() returning 0x0000000000000000000000000000000000000000000000000000000000000000:

pragma solidity ^0.4.11;

contract Owned {
    address public owned;
    
    function Owned() {
        owned = msg.sender;
    }
}

contract Test is Owned {
    address owned;

    function getOwned() constant returns (address){
        return owned;
    }
}

2.2 FunFairSale.setStartTime(...) Allows The Crowdsale Parameters To Be Modified

The FunFairSale.setStartTime(...) with the comment // for testing allows the contract owner to set the startTime and deadline variables to any arbitrary time, as long as deadline is after startTime.

This will allow the owner to set the deadline to a time prior to now, allowing the owner to withdraw all held funds from this contract.

If the contract balance is zero, the owner is able to execute the launch(...) function that will enable the owner to set capAmount to a new cap.


2.3 FunFairSale.() Double Counts msg.value

msg.value is included in this.balance in the comparison if (this.balance + msg.value >= capAmount) { and will result in the cap be triggered by the total contributions being below the desired cap value.

Deploying the following code in Remix, setting Value to 10 and executing test will result in the variable thebalance to be set to 20 as this.balance includes the ethers sent in msg.value:

pragma solidity ^0.4.11;

contract Test {
    uint public thebalance;

    function test() payable {
        thebalance = this.balance + msg.value;
    }
}

3. Use Of Best Practices

3.1 Replace owner.call.value(...)() With owner.transfer(...)

The owner.call.value(...) external call provides the destination address with sufficient gas to trigger code execution and should be replaced with owner.transfer(...). In this case, the destination address is under the control of the contract owner so the likelihood of this call being exploited is low.


3.2 Recent Solidity Version

The statement pragma ^0.4.4 in the source code should be updated to pragma ^4.1.11 so the latest stable compiler with recent bug fixes is checked for before deployment. The deployed contracts have all been compiled with Solidity v0.4.11+commit.68ef5810, so there is no impact from the use of pragma ^0.4.4 in the source code anyway.


4. Comments And Suggestions


5. Additional Information And Notes

Further comments on the code can be found in FunFairSale.md and TokenControllerLedger.md.


6. Tests

See test/README.md for details on the testing of these contracts.


7. References


8. Conclusion

From the preliminary results, there are no severe security issues in the FunFairSale contract. The token contracts are currently being tested.

The FunFairSale.setStartTime(...) function should be removed as this removes the need for presale participants to trust the contract owner not to manipulate the token presale contract parameters.

There is the double counting of the msg.value in the capAmount check, and this will bring forward the sale end date/time prematurely. In the live contract, this bug will not apply as the cap




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

About

FunFair Crowdsale Contract Audit

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published