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:
ERC20Mintable
contract.Crowdsale
and MintedCrowdsale
contracts.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.
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:
Important factors to consider when developing tokens for a crowdsale include:
When implementing a crowdsale, you must decide how to release tokens to the participants in the sale.
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);
}
}
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.
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();
}
}
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.
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: