GUTS Token Sale Audit

Similar documents
QIIBEE Security Audit

SECURITY AUDIT REPORT

SmartDec icumulate.io Smart Contracts Security Analysis

FXY TOKEN SMART CONTRACT AUDIT RESULTS FOR FIXY NETWORK LTD

kasko2go Token Contract Audit

Table of contents. Abstract. Disclaimer. Scope. Procedure. AS-IS overview. Audit overview. Conclusion. Appendix A. Automated tools reports 12

FanChain Contract Audit

ICO smart contracts Documentation

Ethereum. Smart Contracts Programming Model

Security Audit of FuzeX Smart Contract This report is public. ChainSecurity Ltd. January 11, 2018

DISTRIBUTION PLAN. Operation of EMMARES smart contract. EMA Token Allocation

Pillar Token Code Review

Gnosis Safe Documentation. Gnosis

Bob s Repair Contract Audit

Secure Token Development and Deployment. Dmitry Khovratovich and Mikhail Vladimirov, University of Luxembourg and ABDK Consulting

TABLE OF CONTENTS 1.0 TOKEN SALE SUMMARY INTRODUCTION HOW TO BUY LION HOW TO BUY LION WITH METAMASK

Guide to a Successful Wanchain Token Contribution

Privacy-Enabled NFTs: User-Mintable, Non-Fungible Tokens With Private Off-Chain Data

Vladimir Groshev. COO, Project Coordinator.

ICO Review: Raiden Network (RDN)

HowtobuyHUMToken. Table of Contents. Beforeproceedingwiththepurchase Pre-saleguideusingMyEtherWallet Pre-saleguideusingMetamask

Learn Blockchain Programming. Ali Dorri

Smart Contract Security Audit Report. Loopring Protocol Smart Contract version 2

HOW TO PARTICIPATE IN VESTARIN PRE-ICO & ICO with ETHERIUM

PARTICIPATING IN PODONE s ICO

Ethereum Computation Market Documentation

ICO Review: Etherparty (FUEL)

TOKEN PAPER.

Kibo Contract Audit. Prepared by Hosho July 17th, Report Version: 2.0. Copyright 2018 Hosho Group Inc.

Three-Dimensional Scalable Blockchain. Tokenomics draft v. 0.3 (En)

Lecture 10. A2 - will post tonight - due in two weeks

How to Invest in the Gizer Token Sale. A guide for contributing to the Initial Offering of GZR Tokens

GENESIS VISION NETWORK

0xcert - Your ID, degree, artwork or house. 0xcert-ified on the blockchain.

MCFT: Multi-Class Fungible Token

Active Planning Committee John Lindsay, Patent Attorney Tony Schuman, Investment Advisor Todd Russell, Gov t Contract Opportunities

An Analysis of Atomic Swaps on and between Ethereum Blockchains Research Project I

FLIP Token (FLP) How to Participate in the FLIP Token (FLP) Sale Event. 1 Disclaimer 2. 2 What You Will Need 2

Technical Overview. Version: 1.0 Date:

How to buy LIVE Token with Ethereum and Bitcoin step by step

02 Features of C#, Part 1. Jerry Nixon Microsoft Developer Evangelist Daren May President & Co-founder, Crank211

TABLE OF CONTENTS 1.0 TOKEN SALE SUMMARY INTRODUCTION HOW TO BUY LION HOW TO BUY LION WITH METAMASK

Mobilink-Network Partial List of Partners

Wanchain Hackathon Handbook San Jose

Announcements. Lab Friday, 1-2:30 and 3-4:30 in Boot your laptop and start Forte, if you brought your laptop

POA Bridge. Security Assessment. Cris Neckar SECUREWARE.IO

CS107 Handout 37 Spring 2007 May 25, 2007 Introduction to Inheritance

Design Book of TRON Architecture

CS18000: Problem Solving And Object-Oriented Programming

Implementing and Mechanically Verifying Smart Contracts

Exceptions and Continuations. Lecture #19: More Special Effects Exceptions and OOP. Approach II: Non-Standard Return. Approach I: Do Nothing

Mobilink-Network Partial List of Partners

Knowledge Platform TOKEN SALE. GUIDELINE (MetaMask & MyEtherWallet)

The Decaf Language. 1 Lexical considerations

Assertions, pre/postconditions

hashload.io white paper v0.3 subject to change

MYETHERWALLET GUIDE 1

I BCS-031 BACHELOR OF COMPUTER APPLICATIONS (BCA) (Revised) Term-End Examination. June, 2015 BCS-031 : PROGRAMMING IN C ++

a new cryptocurrency STK GLOBAL PAYMENTS USER GUIDE USER GUIDE: PARTICIPATING IN IN STK STK TOKEN TOKEN SALE USING SALE MYETHERWALLET

UNIT 3 ARRAYS, RECURSION, AND COMPLEXITY CHAPTER 11 CLASSES CONTINUED

Written by John Bell for CS 342, Spring 2018

Technical White Paper of. MOAC Mother of All Chains. June 8 th, 2017

1 Shyam sir JAVA Notes

Absolute C++ Walter Savitch

1) RED MegaWatt Tokens 2) RED Platform 3) RED Franchise

INX Tokenomics I

Who wants to be a millionaire? A class in creating your own cryptocurrency

A Java Framework for Smart Contracts

AP COMPUTER SCIENCE JAVA CONCEPTS IV: RESERVED WORDS

The Object Class. java.lang.object. Important Methods In Object. Mark Allen Weiss Copyright 2000

SOLUTION ARCHITECTURE AND TECHNICAL OVERVIEW. Decentralized platform for coordination and administration of healthcare and benefits

VIRTUAL FUNCTIONS Chapter 10

Technical Specifications for Platform Development

Ethereum: 30 Tips & Tricks

MyEtherWallet Step by Step Tutorial

Token Sale. Participation guide

cchannel Generalized State Channel Specification

CS 251: Bitcoin and Cryptocurrencies Fall 2016

Wormhole: A Smart Contract Solution for Bitcoin Cash

Animal Classes. Door Classes. Some Maze Classes. Class Diagrams. Nesting Variants to Refine Contracts. Common Functionality in Abstract Classes

OpenbankIT: a banking platform for e- money management based on blockchain technology

Fundamentals. Fundamentals. Fundamentals. We build up instructions from three types of materials

Set Up and Maintain Sales Tools

CONDITION CONTROLLED LOOPS. Introduction to Programming - Python

DOWNLOAD PDF CORE JAVA APTITUDE QUESTIONS AND ANSWERS

Beerchain. Creating the beer-based cryptocurrency. Yellowpaper version 0.3, 3/11/2018

Inheritance (Part 5) Odds and ends

Snapshot Best Practices: Continuous Integration

DECENTRALIZED CLOUD STORAGE OF VALUABLE DATA ON BLOCKCHAIN

Declarative Static Analysis of Smart Contracts

Wanchain Documentation

OOPS Viva Questions. Object is termed as an instance of a class, and it has its own state, behavior and identity.

Application Container Cloud

Last updated: July 7th, 2008 Microsoft Security Software Advisor Fee Initiative Guide ("SSA Program Guide")

Box Competitive Sheet January 2014

Chapter 5 Object-Oriented Programming

Final Presentation Master s Thesis: Identification of Programming Patterns in Solidity

How Can I See My ENJ? 15. Acquiring Ether (ETH) 16

For 100% Result Oriented IGNOU Coaching and Project Training Call CPD TM : ,

ICO Review: Current Media (CRNC)

Transcription:

GUTS Token Sale Audit AUTHOR: MATTHEW DI FERRANTE 2017-10-22

Audited Material Summary The audit consists of the following contracts: GetCrowdsale.sol GetFinalizeAgent.sol GetPreCrowdsale.sol GetPreFinalizeAgent.sol GetPrePricingStrategy.sol GetPricingStrategy.sol GetToken.sol GetWhitelist.sol The git commit hash of the reviewed files is cec35f217108f60eb50a6c607245c4494c546293. Description The GUTS Token sale is implemented through TokenMarket s ICO contracts. The main crowdsale logic for these contracts is inherited from Crowdsale.sol + MintedTokenCappedCrowdsale.sol, both GetCrowdsale.sol and GetPreCrowdsale.sol extend the functionality and set some state variables. The Presale and Crowdsale are both structured to use the same token, but different smart contracts (GetPreCrowdsale and GetCrowdsale respectively). When the presale finishes, a finalization agent set when GetCrowdsale.sol is deployed calls logpresaleresults to migrate the results of the presale into the main Crowdsale. The TokenMarket contracts have been used in a variety of other ICOs and have been previously audited: Civic Storj Monaco DENT Bitquence InsureX See the following repository for a breakdown of the TokenMarket contracts: https://github.com/tokenmarketnet/ico This audit focuses on GUTS specific usage of the TokenMarket tokens. Author: Matthew Di Ferrante 2

Security summary The contracts are correctly constructed have no major security issues that pose a threat to users or their balances. GetCrowdsale.sol GetCrowdsale is an implementation of MintedTokenCappedCrowdsale from the TokenMarket contracts, and inherits from it directly: 1 contract GetCrowdsale is MintedTokenCappedCrowdsale Security note The only recommendation I have here is, due to the presale being a different contract, the invest should not be available until logpresaleresults has been called, to ensure that there are no numerical conflicts if it s done during the Crowdsale, and also ensuring Crowdsale participants can see how much was raised in the presale through the contract before investing. Constructor 1 function GetCrowdsale( 2 uint _locktime, FinalizeAgent _presalefinalizeagent, 3 address _token, PricingStrategy _pricingstrategy, address _multisigwallet, 4 uint _start, uint _end, uint _minimumfundinggoal, uint _maximumsellabletokens) 5 6 MintedTokenCappedCrowdsale(_token, _pricingstrategy, _multisigwallet, 7 _start, _end, _minimumfundinggoal, _maximumsellabletokens) 8 { 9 require(_presalefinalizeagent.issane()); 10 require(_locktime > 0); 11 locktime = _locktime; 12 presalefinalizeagent = _presalefinalizeagent; 13 } Author: Matthew Di Ferrante 3

The constructor passes variables through to parent constructor of MintedTokenCappedCrowdsale, and does sanity checking on the presale agent and lock time variables, and commits the presale agent to storage. logpresaleresults 1 function logpresaleresults(uint tokenamount, uint weiamount) returns ( bool) { 2 3 require(msg.sender == address(presalefinalizeagent)); 4 weiraised = weiraised.plus(weiamount); 5 tokenssold = tokenssold.plus(tokenamount); 6 presaleweiraised = presaleweiraised.plus(weiamount); 7 8 PresaleUpdated(weiAmount, tokenamount); 9 return true; 10 } The logpresaleresults function records presale token and ether allocation in the crowdsale contract and emits a PresaleUpdated event. It can only be called by presalefinalizeagent. All arithmetic operations use SafeMath. preallocate 1 function preallocate(address receiver, uint fulltokens, uint weiprice) public onlyowner { 2 3 uint tokenamount = fulltokens * 10**token.decimals(); 4 uint weiamount = weiprice * fulltokens; // This can be also 0, we give out tokens for free 5 6 weiraised = weiraised.plus(weiamount); 7 tokenssold = tokenssold.plus(tokenamount); 8 9 presaleweiraised = presaleweiraised.plus(weiamount); 10 11 investedamountof[receiver] = investedamountof[receiver].plus( weiamount); Author: Matthew Di Ferrante 4

12 tokenamountof[receiver] = tokenamountof[receiver].plus(tokenamount ); 13 14 assigntokens(receiver, tokenamount); 15 16 // Tell us invest was success 17 Invested(receiver, weiamount, tokenamount, 0); 18 } The preallocate function preallocates tokens to an address, and does some accounting to keep the weiraised, tokenssold and presaleweiraised variables consistent. The investedamountof and tokenamountof maps for the receiver are also updated for the number of wei raised and number of tokens allocated, respectively. The tokens are assigned by calling the internal function assigntokens, and on success an Invested event is emitted. Note: The tokenamount and weiamount calculations do not use SafeMath. setearlyparicipants 1 function setearlyparicipantwhitelist(address addr, bool status) onlyowner { 2 // We don t need this function, we have external whitelist 3 revert(); The setearlyparticipants function is unused due to the whitelist functionality, therefore Crowdsale.sol s implementation is overridden here with a revert(). The function can only be called by the owner of GetCrowdsale, but it does nothing either way. assigntokens 1 function assigntokens(address receiver, uint tokenamount) private { 2 MintableToken mintabletoken = MintableToken(token); 3 mintabletoken.mint(receiver, tokenamount); The assigntokens function allocates an amount of tokens to an address. It is a private function and cannot be called directly, and is only ever called by the preallocate function. Author: Matthew Di Ferrante 5

This function assumes token implements a MintableToken interface and typecasts the more generic token variable which is a FractionalERC20 type as defined in Crowdsale.sol. finalize 1 function finalize() public instate(state.success) onlyowner stopinemergency { 2 require(now > endsat + locktime); 3 super.finalize(); The finalize function ensures that the current time is past the crowdsale end date + the lock time, and calls Crowdsale.sol s parent implementation of finalize. This function can only be called by the owner of GetCrowdsale, and cannot be called if the contract is halted. This function can only succeed if the crowdsale is in the State.Success stage. Default Function 1 function() payable { 2 invest(msg.sender); 3 } The default function in this contract is merely a passthrough to Crowdsale.sol s invest function, passing msg.sender as the argument. GetToken.sol The GetToken contract is a very simple initializer for the underlying CrowdsaleToken + BurnableToken implementation: 1 contract GetToken is CrowdsaleToken, BurnableToken { 2 function GetToken() CrowdsaleToken( 3 "Guaranteed Entrance Token", 4 "GET", 5 0, // We don t want to have initial supply 6 18, Author: Matthew Di Ferrante 6

7 true // Mintable 8 ) 9 {} 10 } It takes no arguments and simply passes some hardcoded variables to the inherited CrowdsaleToken constructor. The full inheritance chain makes GetToken contain the following functionality: ReleasableToken: ERC20 + transfer freeze / unfreeze functionality, transfers frozen by default MintableToken: ERC20 + mint functionality, where a mintagent can create new tokens, with minting permanently disabled once the tokens are released BurnableToken: ERC20 + burn functionality, which allows a token holder (contract or account) to burn their own tokens UpgradeableToken: ERC20 + upgrade functionality, where an upgrade agent can set a new revision for the token contract and users can opt-in to have their balances transferred to the new contract. Security note The inheritance hierarchy of the TokenMarket contracts is non-trivial - any additional function overrides should be triple checked in case the function is implemented by more than one parent, as solidity s super call order is somewhat unintuitive. GetPreCrowdsale.sol GetPreCrowdsale inherits from MintedTokenCappedCrowdsale, just like GetCrowdsale, but lacks any additional functions beyond the override function to setearlyparticipantswhitelist. 1 contract GetPreCrowdsale is MintedTokenCappedCrowdsale Constructor 1 function GetPreCrowdsale( 2 address _token, PricingStrategy _pricingstrategy, address _multisigwallet, 3 uint _start, uint _end, uint _maximumsellabletokens) Author: Matthew Di Ferrante 7

4 MintedTokenCappedCrowdsale(_token, _pricingstrategy, _multisigwallet, 5 _start, _end, 0, _maximumsellabletokens) 6 { 7 } The constructor for GetPreCrowdsale simply passes all of its arguments to the parent constructor of MintedTokenCappedCrowdsale, and implements no additional logic. Default Function Just like in GetCrowdsale, the default function for the presale is simply a msg.sender passthrough to invest, and is the only way to participate in the sale. GetWhitelist.sol The GetWhitelist contract is the only contract that is mostly written from scratch, inheriting only Ownable from Zeppelin and using SafeMath as a library: 1 contract GetWhitelist is Ownable It implements both whitelisting functionality and tranche allowances per investor. Constructor 1 function GetWhitelist(uint _presalecap, uint _tier1cap, uint _tier2cap, uint _tier3cap, uint _tier4cap) { 2 presalecap = _presalecap; 3 tier1cap = _tier1cap; 4 tier2cap = _tier2cap; 5 tier3cap = _tier3cap; 6 tier4cap = _tier4cap; 7 } The constructor simply stores the supplied caps to their respective storage variables. Author: Matthew Di Ferrante 8

isgetwhitelist 1 function isgetwhitelist() constant returns (bool) { 2 return true; 3 } The isgetwhitelist function is used by calling contracts to check whether an address implements the GetWhitelist interface. acceptbatched 1 function acceptbatched(address[] _addresses, bool _isearly) onlywhitelister { 2 // trying to save up some gas here 3 uint _presalecap; 4 if (_isearly) { 5 _presalecap = presalecap; 6 } else { 7 _presalecap = 0; 8 } 9 for (uint i=0; i<_addresses.length; i++) { 10 entries[_addresses[i]] = WhitelistInfo( 11 _presalecap, 12 tier1cap, 13 tier2cap, 14 tier3cap, 15 tier4cap, 16 true 17 ); 18 } 19 NewBatch(); 20 } The acceptbatched function takes a list of addresses and a boolean specifying whether the addresses are allowed to participate in the crowdsale, and initializes the structure for each address in the entries map with the default caps. It emits a NewBatch event when successful. This function can only be called by an address in the set of whitelisters. accept Author: Matthew Di Ferrante 9

1 function accept(address _address, bool _isearly) onlywhitelister { 2 require(!entries[_address].iswhitelisted); 3 uint _presalecap; 4 if (_isearly) { 5 _presalecap = presalecap; 6 } else { 7 _presalecap = 0; 8 } 9 entries[_address] = WhitelistInfo(_presaleCap, tier1cap, tier2cap, tier3cap, tier4cap, true); 10 NewEntry(_address); 11 } The accept function is single-address version of acceptbatch, but otherwise functionally equivalent other than refusing to run if the address is already whitelisted. It can only be called by an address in the set of whitelisters. subtractamount 1 function subtractamount(address _address, uint _tier, uint _amount) onlywhitelister { 2 require(_amount > 0); 3 require(entries[_address].iswhitelisted); 4 if (_tier == 0) { 5 entries[_address].presaleamount = entries[_address]. presaleamount.minus(_amount); 6 EdittedEntry(_address, 0); 7 return; 8 }else if (_tier == 1) { 9 entries[_address].tier1amount = entries[_address].tier1amount. minus(_amount); 10 EdittedEntry(_address, 1); 11 return; 12 }else if (_tier == 2) { 13 entries[_address].tier2amount = entries[_address].tier2amount. minus(_amount); 14 EdittedEntry(_address, 2); 15 return; 16 }else if (_tier == 3) { Author: Matthew Di Ferrante 10

17 entries[_address].tier3amount = entries[_address].tier3amount. minus(_amount); 18 EdittedEntry(_address, 3); 19 return; 20 }else if (_tier == 4) { 21 entries[_address].tier4amount = entries[_address].tier4amount. minus(_amount); 22 EdittedEntry(_address, 4); 23 return; 2 25 revert(); 26 } The subtractamount function ensures that an address is in the whitelist (otherwise it throws), and subtracts their allowance for the specified tranche accordingly. Due to the SafeMath usage underflows cause the contract to throw. If the tranche is beyond 4 it will also throw. It can only be called by an address in the set of whitelisters. setwhitelister 1 function setwhitelister(address _whitelister, bool _iswhitelister) onlyowner { 2 whitelisters[_whitelister] = _iswhitelister; 3 WhitelisterChange(_whitelister, _iswhitelister); The setwhitelister function allows the contract owner to add or remove an address from the set of whitelisters. It can only be called by the contract owner. setcaps 1 function setcaps(uint _presalecap, uint _tier1cap, uint _tier2cap, uint _tier3cap, uint _tier4cap) onlyowner { 2 presalecap = _presalecap; 3 tier1cap = _tier1cap; 4 tier2cap = _tier2cap; 5 tier3cap = _tier3cap; 6 tier4cap = _tier4cap; Author: Matthew Di Ferrante 11

7 } The setcaps function allows the contract owner to set or update the tranche caps for the crowdsales. It can only be called by the contract owner. Default Function 1 function() payable { 2 revert(); 3 } The default function simply throws, to prevent payment to this contract. GetPricingStrategy.sol The GetPricingStrategy contract sets the pricing mechanism for GetCrowdsale. It implements a tranche based pricing strategy, inheriting from EthTranchePricing: 1 contract GetPricingStrategy is EthTranchePricing It also checks any incoming investor addresses against a whitelist and throws if the investor is not whitelisted. Constructor 1 function GetPricingStrategy(GetWhitelist _whitelist, uint[] _tranches) EthTranchePricing(_tranches) { 2 assert(_whitelist.isgetwhitelist()); 3 whitelist = _whitelist; The constructor takes a GetWhitelist contract address that it uses ensure purchasing addresses are whitelisted, and enforces tiered caps for each investing address. The parent constructor for EthTrancePricing is called with the list of tranches as an argument. Author: Matthew Di Ferrante 12

ispresalepurchase 1 function ispresalepurchase(address purchaser) public constant returns (bool) { 2 return false; 3 } The ispresalepurchase function returns false, as the tranche pricing strategy is only for the main Crowdsale. setcrowdsale 1 function setcrowdsale(address _crowdsale) onlyowner { 2 require(_crowdsale!= 0); 3 crowdsale = _crowdsale; The setcrowdsale function allows the contract owner to set the address of the crowdsale. The function sanity checks that the supplied address is not 0. issane 1 function issane(address _crowdsale) public constant returns (bool) { 2 return crowdsale == _crowdsale; 3 } The issane function returns true if the supplied address matches the address set as the crowdsale in the storage state, and false otherwise. getcurrenttrancheindex 1 function getcurrenttrancheindex(uint weiraised) public constant returns (uint) { 2 uint i; 3 4 for(i=0; i < tranches.length; i++) { 5 if(weiraised < tranches[i].amount) { 6 return i-1; 7 } Author: Matthew Di Ferrante 13

8 } 9 } The getcurrenttrancheindex function iterates through the tranches supplied at deployment time and returns the last tranche that closes the weiraised amount. Security note The counter i in this function can underflow in case weiraised is 0 at Crowdsale time. calculateprice 1 function calculateprice(uint value, uint weiraised, uint tokenssold, address msgsender, uint decimals) public constant returns (uint) { 2 require(msg.sender == crowdsale); 3 uint amount; 4 bool isearly; 5 bool iswhitelisted; 6 uint trancheindex = getcurrenttrancheindex(weiraised); 7 whitelist.subtractamount(msgsender, trancheindex + 1, value); 8 9 uint multiplier = 10 ** decimals; 10 return value.times(multiplier) / tranches[trancheindex].price; 11 } The calculateprice function is used by Crowdsale.sol to calculate the tokens received for an investment. Based on the amount of wei raised so far, it retrieves the corresponding tranche and subtracts the amount from the sender s allowance in that tranche. It then returns weiinvested*10^18 / current_tranche_price as the amount of tokens to allocate. Security note The division by tranche price does not use SafeMath. isearly, iswhitelisted and amount are not used and should be removed for code clarity. Author: Matthew Di Ferrante 14

Default Function The default function in this contract simply throws. GetPrePricingStrategy.sol The GetPrePricingStrategy contract is almost the same as the GetPricingStrategy contract, except for it implements a flat pricing mechanism instead of tranche pricing: 1 contract GetPrePricingStrategy is FlatPricing, Ownable In the interest of brevity I will only analyze the functions that are not functionally equivalent to GetPricingStrategy. Constructor 1 function GetPrePricingStrategy(GetWhitelist _whitelist, uint _onetokeninwei) FlatPricing(_oneTokenInWei) { 2 assert(_whitelist.isgetwhitelist()); 3 whitelist = _whitelist; The constructor simply assigns the whitelist like in GetPricingStrategy, and calls the parent constructor FlatPricing, taking an argument for the amount one token should cost, denominated in wei. calculateprice 1 function calculateprice(uint value, uint weiraised, uint tokenssold, address msgsender, uint decimals) public constant returns (uint) { 2 // only precrowdsale can call this 3 require(msg.sender == precrowdsale); 4 // 0 is the presale tier. 5 whitelist.subtractamount(msgsender, 0, value); 6 return super.calculateprice(value, weiraised, tokenssold, msgsender, decimals); 7 } Author: Matthew Di Ferrante 15

The calculateprice function, just like in GetPriceStrategy, subtracts allowance for the sender from the whitelist, and then defers the price calculation to the parent calculateprice implementation in FlatPricing, which simply returns: weiinvested*10^18 / token_cost_in_wei GetFinalizeAgent.sol The GetFinalizeAgent contract extends a FinalizeAgent interface which mints reserve tokens and finalizes the crowdsale, releasing the tokens and making them available for transfer and use.. 1 contract GetFinalizeAgent is FinalizeAgent Constructor 1 function GetFinalizeAgent(CrowdsaleToken _token, Crowdsale _crowdsale, 2 address _usergrowthmultisig, address _stabilitymultisig, address _bountymultisig) { 3 token = _token; 4 crowdsale = _crowdsale; 5 if(address(crowdsale) == 0) { 6 revert(); 7 } 8 9 require(_usergrowthmultisig!= 0); 10 require(_stabilitymultisig!= 0); 11 require(_bountymultisig!= 0); 12 13 usergrowthmultisig = _usergrowthmultisig; 14 stabilitymultisig = _stabilitymultisig; 15 bountymultisig = _bountymultisig; 16 } The constructor does some sanity checking on arguments and assigns them to their respective storage variables. issane Author: Matthew Di Ferrante 16

1 function issane() public constant returns (bool) { 2 return (token.mintagents(address(this)) == true) && (token. releaseagent() == address(this)); 3 } The issane function returns true if the GetFinalizeAgent is one of the token s mintagents and also set as the token s releaseagent. finalizecrowdsale 1 function finalizecrowdsale() { 2 if(msg.sender!= address(crowdsale)) { 3 revert(); 5 6 uint tokenssold = crowdsale.tokenssold(); 7 uint decimals = token.decimals(); 8 9 // maximum digits here (10 + 18 + 12) 10 token.mint(usergrowthmultisig, tokenssold.times(73170731707) / 100000000000); 11 12 token.mint(stabilitymultisig, 12600000 * (10**decimals)); 13 token.mint(bountymultisig, 1800000 * (10**decimals)); 14 15 // Make token transferable 16 token.releasetokentransfer(); 17 } The finalizecrowdsale function mints tokens for user growth, stability and bounty multisigs, and releases the tokens, disabling minting. Security note Would be better to have constant variables instead of magic numbers hardcoded inline for token issuance. Default Function Author: Matthew Di Ferrante 17

1 function() payable { 2 revert(); 3 } The default function just prevents payments to this contract. GetPreFinalizeAgent.sol The GetPreFinalizeAgent contract is the same functionally as GetFinalizeAgent, except it is meant to finalize the presale. It inherits from FinalizeAgent and Ownable: 1 contract GetPreFinalizeAgent is FinalizeAgent, Ownable Constructor 1 function GetPreFinalizeAgent(GetCrowdsale _precrowdsale) { 2 3 if(address(_precrowdsale) == 0) { 4 revert(); 5 } 6 precrowdsale = _precrowdsale; 7 8 } The constructor only assigns the crowdsale address to the storage variable afterr ensuring it isn t 0. setcrowdsale 1 function setcrowdsale(getcrowdsale _crowdsale) onlyowner { 2 require(address(_crowdsale)!= 0); 3 crowdsale = _crowdsale; The setcrowdsale function allows the contract owner to set the address for the crowdsale contract. Author: Matthew Di Ferrante 18

issane 1 function issane() public constant returns (bool) { 2 // cannot check crowdsale yet since it is not set. 3 return true; The issane function is a dummy function that always returns true. finalizecrowdsale 1 function finalizecrowdsale() { 2 if(msg.sender!= address(precrowdsale)) { 3 revert(); 5 6 // log the results to the main crowdsale 7 uint tokenssold = precrowdsale.tokenssold(); 8 uint weiraised = precrowdsale.weiraised(); 9 if (!crowdsale.logpresaleresults(tokenssold, weiraised)) { 10 revert(); 11 } 12 } The finalizecrowdsale function finalizes the presale by retrieving the tokens sold and wei raised from the presale contract and calling logpresaleresults on the crowdsale contract, to migrate the accounting over. It can only be called by the presale contract. Default Function 1 function() payable { 2 revert(); 3 } The default function prevents any ether from being sent to this contract. Author: Matthew Di Ferrante 19

Disclaimer This audit concerns only the correctness of the Smart Contracts listed, and is not to be taken as an endorsement of the platform, team, or company. Audit Attestation This audit has been signed by the key provided on https://keybase.io/mattdf - and the signature is available on https://github.com/mattdf/audits/ Author: Matthew Di Ferrante 20