Crowdsale Contracts

In addition to understanding how a crowdsale works, learn how to implement the ERC20Mintable, Crowdsale, and MintedCrowdsale contracts that allow for full crowdsale functionality with fungible tokens.

By the end of this post, readers will be able to:

  • Detail some considerations to take into account when launching tokens via a crowdsale.
  • Create a smart contract for a mintable token by using the OpenZeppelin ERC20Mintable contract.
  • Construct an ERC-20 token crowdsale by using the OpenZeppelin Crowdsale and MintedCrowdsale contracts.
  • Use a single deployer contract to create multiple contracts on a blockchain that are distinct but related.

When we create and deploy a real-world blockchain token, minting tokens that comply with ERC-20 is only the first step. The next challenge is to distribute the tokens to other blockchain participants.

Crowdsale

A crowdsale is defined as a method of funding a project through the sale of digital tokens that give the buyers the right to participate in the idea that the sale is funding. Essentially, a crowdsale allows investors to send cryptocurrency to a smart contract and receive tokens in return

For information about related crowdsale functions, refer to the OpenZeppelin crowdsale documentation and the GitHub pages for ERC20 Mintable.sol, Crowdsale.sol, and MintedCrowdsale.sol.

For what purposes might projects running on a blockchain platform use the funds that they raise during a crowdsale? Some possibilities include:

  • Marketing funds
  • Payments to developers
  • Product development
  • Product production
  • Any other initial operating costs

Important factors to consider when developing tokens for a crowdsale include:

  • The price and rate configuration of the tokens, which include the following:
    • Whether to offer the tokens at a fixed price.
    • Whether to cap, or limit, the total number of released tokens.
    • Whether to cap the total number of tokens that a single individual can buy.
  • How to send tokens to crowdsale investors.
  • The time frame associated with the sale—that is, when the crowdsale will start and when it will end.
  • Whether to distribute the funds that get raised by selling tokens during or after the crowdsale.
  • Whether to have a refund policy if you don’t successfully reach the ultimate goal of the project.

When implementing a crowdsale, you must decide how to release tokens to the participants in the sale.

  • This process of releasing tokens is known as token emission. We normally do this in one of three ways:
    • The crowdsale contract owns a specified number of tokens and transfers ownership of them as users purchase them.
    • The crowdsale contract dynamically mints new tokens as they get purchased.
    • The crowdsale contract has access to a wallet from which it can transfer ownership of tokens as they get purchased.

Preparing a Token for a Crowdsale

We’ll streamline the crowdsale creation process by creating a smart contract that can automatically mint tokens when a user sends it ether. Anyone who wants to to purchase the ArcadeToken in the crowdsale can send ether to the contract from their account address. Then, the contract will automatically mint and send tokens to them in return.

We create the initial ArcadeToken contract by importing the ERC20 and ERC20Detailed contracts, as the following code shows:

pragma solidity ^0.5.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v2.5.0/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v2.5.0/contracts/token/ERC20/ERC20Detailed.sol";

To provide our contract with all the functionality that it needs for a crowdsale, we’ll now import one more contract from the OpenZeppelin library: ERC20Mintable.

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v2.5.0/contracts/token/ERC20/ERC20Mintable.sol";

The complete code should appear as follows:

pragma solidity ^0.5.0;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v2.5.0/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v2.5.0/contracts/token/ERC20/ERC20Detailed.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v2.5.0/contracts/token/ERC20/ERC20Mintable.sol";

contract ArcadeToken is ERC20, ERC20Detailed, ERC20Mintable {
    constructor(
        string memory name,
        string memory symbol,
        uint initial_supply
    )
        ERC20Detailed(name, symbol, 18)
        public
    {
        mint(msg.sender, initial_supply);
    }
}

Manage Crowdsale Functionality

In addition to having the ArcadeToken contract that handles the initial minting, we’ll create a contract named ArcadeTokenCrowdsale to oversee the crowdsale functionality.

We’ll also create one more contract in addition to the ArcadeToken and ArcadeTokenCrowdsale contracts. This contract will be able to create, configure, and deploy both our ArcadeToken contract and our ArcadeTokenCrowdsale contract. We’ll name this deployer contract ArcadeTokenCrowdsaleDeployer.

During deployment, ArcadeTokenCrowdsaleDeployer will create the other two contracts and temporarily assume both the contract owner and minter roles. After ArcadeTokenCrowdsaleDeployer successfully sets up our crowdsale, it will transfer the owner and minter roles to ArcadeTokenCrowdsale.

We should compile and deploy the contracts in conjunction with Ganache and MetaMask.

  • It’s best to have three addresses loaded into MetaMask: one for the deployment and two to act as crowdsale participants.

The following code showcases the ArcadeTokenCrowdsale Contract in conjunction with the ArcadeTokenCrowdsaleDeployer Contract:

pragma solidity ^0.5.0;

import "./ArcadeTokenMintable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v2.5.0/contracts/crowdsale/Crowdsale.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v2.5.0/contracts/crowdsale/emission/MintedCrowdsale.sol";

contract ArcadeTokenCrowdsale is Crowdsale, MintedCrowdsale {
    constructor(
        uint rate,
        address payable wallet,
        ArcadeToken token
    )
        Crowdsale(rate, wallet, token)
        public
    {
        // constructor body can stay empty
    }
}

contract ArcadeTokenCrowdsaleDeployer {
    address public arcade_token_address;
    address public arcade_crowdsale_address;

    constructor(
        string memory name,
        string memory symbol,
        address payable wallet
    )
        public
    {
        ArcadeToken token = new ArcadeToken(name, symbol, 0);
        arcade_token_address = address(token);

        ArcadeTokenCrowdsale arcade_crowdsale = new ArcadeTokenCrowdsale(1, wallet, token);
        arcade_crowdsale_address = address(arcade_crowdsale);

        token.addMinter(arcade_crowdsale_address);
        token.renounceMinter();
    }
}

Deploying the ArcadeToken Crowdsale

At this point, we should have launched Ganache and loaded several accounts into MetaMask. Additionally, ensure you’ve opened and compiled the complete versions of the contracts in Remix.

Begin the deployment demonstration by navigating to the Deploy & Run Transactions pane in the Remix IDE.

Make sure that you select Injected Web3 as the environment and choose one of the MetaMask account addresses. The selected wallet will be the beneficiary of the sale—that is, the owner of the contract.

When you click the transact button, MetaMask opens a dialog box that requires you to confirm the transaction.

Deploy contract in Remix
Deploy contract in Remix

Per the code, the ArcadeTokenCrowdsaleDeployer contract created two contracts, each with an associated address. The arcade_token_address is associated with the ArcadeToken contract, and the arcade_crowdsale_address is associated with the ArcadeTokenCrowdsale contract.

By using the addresses provided for those contracts, we were able to link the on-chain contracts with the Solidity code that we wrote to define the functionality for those contracts.

Until next time, here’s a twitter thread summary of this post:

Subscribe to jackofcrypto
Receive the latest updates directly to your inbox.
Verification
This entry has been permanently stored onchain and signed by its creator.