Published in


Crowdsales on Ethereum with OpenZeppelin

When crowdfunding your crypto project, it’s important to know which type of crowdsale will suit your needs

When it comes time to implement your crowdsale to distribute your ERC20 token and raise funds, you might be surprised as to how many different types of crowdsales there are. To ensure the greatest amount of security in your crowdsale you’ll no doubt be using OpenZeppelin’s smart contract library, and you may notice the vast hierarchy of contracts and slight variations in different crowdsale contract interfaces. We’ll try and break down the different categories and variations for you.


The contract that any crowdsale you might implement will inherit from is Crowdsale. As described by the documentation, it implements secure crowdfunding logic “in its most fundamental form and can be extended to provide additional functionality”. It defines the ERC20 token to be sold, the wallet the funds are sent to, the selling rate and the amount of wei to be raised by the sale. In its most basic form, when it receives a request to buy tokens it performs some validation of the buyer, then calculates how many tokens the request satisfies and finally delivers those tokens to the buyer and the funds to the defined wallet.

While this contract covers all the fundamental behaviour that’s needed, there are some other desirable qualities that one might want in a crowdsale. For example, it’s possible to have a refundable crowdsale which might be more attractive to an investor, or a minted crowdsale which might be required for your type of token. These types of crowdsale come under various headers in the OpenZeppelin library, and we will go through each of them for you.


A crowdsale in this category will provide a mechanism to define circumstances or conditions under which an investor can buy a token. This tightens the distribution of tokens, and because of this the contracts that we will discuss later under the Distribution header will inherit properties from Validation contracts.


A crowdsale with this type of validation will have a pre-defined limit for total contributions. That is, a cap on how much wei will be accepted in the crowdsale needs to be decided, and this will be the maximum amount of funds you will receive in this crowdfund.


Similar to a CappedCrowdsale, however with a CappedCrowdsale a single person could in theory buy all the tokens available as defined by the cap. With an IndividuallyCappedCrowdsale you can limit an individual’s or a group of individual’s amount of funds they are able to put forward. An advantage of using this might be if you were providing reward tiers depending on amount of tokens bought, since a method is provided to view an individual’s contribution. One thing to note with this contract is that it also inherits Ownable, meaning that only the owner of the crowdsale can decide who gets capped and by how much.


This provides a different angle on validation; instead of limiting the amount of funds you can limit the time in which tokens can be bought in. In a TimedCrowdsale you provide an opening and closing time, and checking whether or not the sale has closed becomes a part of the validation process.


A WhitelistedCrowdsale provides a whitelist and the ability to only accept funds from those who are on this whitelist. Functionality is provided to add both individuals and groups of individuals to the whitelist, as well as remove individuals if needed. Like an IndividuallyCappedCrowdsale, this also inherits Ownable and only allows the owner to decide who gets added to/removed from the whitelist.


The crowdsales that come under this header are concerned with the mechanisms in which tokens are moved between the contract and the investors. This can be restrictions on movement of tokens, or allowance of further movement of tokens.


This extension of the crowdsale contract allows the owner to do extra work after the sale has finished. FinalizableCrowdsale inherits from TimedCrowdsale, so in this context “finished” means when the closing time of the sale has passed. A function finalize() is provided and should be called when the sale hits the closing time, which then carries out the extra work before declaring the sale completely finished, not allowing this extra work to occur again. An example of extra work might be to reset the opening and closing time for the next round of funding, if for example you know that you want another time frame to sell more tokens but at a different rate for latecomers. Again this contract inherits Ownable, so only the owner can call the finalize() function.


Another extension that inherits from TimedCrowdsale, PostDeliveryCrowdsale provides functionality to lock tokens from withdrawal until the sale has finished. This means that the investors funds still go directly to the defined wallet from the basic Crowdsale contract, but they can’t claim their tokens until the crowdsale has ended.


This is a different example of a Validation contract being inherited to tighten the Distribution contract logic. A RefundableCrowdsale allows a funding goal to be defined, and if this goal is not met by the closing time of the sale then the investors will get a refund on their investment. It inherits from TimedCrowdsale to define when a refund would be issued, and inherits from FinalizableCrowdsale to define the enabling of refunds as the final “extra work” to be done by the owner. The investors funds are kept in a separate utility contract called RefundVault, which facilitates either the refunding process or the withdrawal process to the owners fund wallet. This decision is made in the “extra work” function in RefundableCrowdsale.


This category of crowdsale contracts provide contraints on how tokens are introduced to the crowdsale process. That is, where the tokens come from and how they get to buyers. The key difference between Emission and Distribution is that Emission concerns attributes of the tokens themselves, whereas Distribution concerns the overall movement of tokens.


This type of Emission contract defines a wallet from which tokens will come from, and approves an allowance to the crowdsale. While on a high level this sounds similar to a CappedCrowdsale, this is a good example to highlight the difference between Emission and Distribution. In a CappedCrowdsale the “allowance” is derived from the amount of funds to be raised, which is a restriction on the movement of tokens. In an AllowanceCrowdsale the “allowance” is defined directly by the amount of tokens wishing to be sold.


A MintedCrowdsale requires that the ERC20 token to be sold is a MintableToken, meaning that the total supply of a token is not necessarily fixed, and new tokens are introduced by “minting” them and increasing the total supply by the amount of tokens minted. A MintedCrowdsale means that when the crowdsale contract delivers tokens to an investor, the tokens are minted there and then.


As of writing there is only one crowdsale contract under this header, but any contract under this header will ultimately concern the control of the rate at which tokens are sold during the sale.


A crowdsale inheriting this extension will allow the ability to define an initial and final rate to sell tokens at, and will increase the price of the tokens (decrease the rate) linearly with time utilising TimedCrowdsale functionality. A function getCurrentRate() is provided, and when an investor makes a request to buy tokens this should be called to determine the rate at which the order should be fulfilled. This type of crowdsale might be useful if you wish to reward “early-birds” for investing early, and want to market your funding in such a way.

If you would like to arrange a consultation, or would like to hire us to develop a bespoke blockchain solution, visit our website and get in touch.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store


Oxford-based blockchain and zero knowledge consultancy and auditing firm