Before we deploy our app to production, I wanted to cover the process of creating your own token, since it's become so common to do in the Ethereum ecosystem.
As you probably know, the ICO ("Initial Coin Offering") industry has been booming lately, and it's completely reinventing the way new startups kickstart themselves. In fact, go have a look at Wikipedia's list of highest crowdfunding projects, and you'll notice that blockchain projects absolutely dominate the list.
Even though many of these token projects are often unrealistic and sometimes straight-up scams, it's a very interesting way to take advantage of some of Ethereum's biggest benefits.
By creating an ICO, you'll also learn how to handle money sent to to your contracts, which should come in handy if you want to create some kind of paid decentralised service in the future.
Therefore, for the sake of this chapter, let's imagine that our Tweether DApp uses its own coin – the Tweether Token. We will create two contracts – one for the token itself and one for the token sale (the ICO).
Using an ERC20 library
Ethereum uses a standard called ERC20 to make it easy for developers to create their own tokens. In brief, ERC20 defines a set of rules that your token contract must adhere to in order to be compatible with most Ethereum wallets.
While you can create this contract from scratch using the guidelines given by the standard interface, there are multiple libraries that already do this really well.
OpenZeppelin is a company that has open-sourced some great token contract libraries, which are used by many other reputable projects in the space. Let's inherit from some of OpenZeppelin's contracts so that we don't have to reinvent the wheel again!
Make sure you're still in your Tweether project folder and run:
This will download all of OpenZeppelin's libraries in your
Some words of caution before we start coding: although the simplicity of just using other people's libraries everywhere might seem attractive, it's extremely important to review their code first! This is especially important in the Ethereum ecosystem, where libraries have the possibility to actively move money around and defraud your users. In short – if you don't fully understand what a library contract is doing, you shouldn't use it!
Now that that's out of the way, create a new folder called
token in your
contracts folder, and create a file called
TweetherToken.sol. We're now going to import OpenZeppelin's
StandardToken contract and inherit from it:
Next, we simply need to define three parameters for our token: its name, its symbol and the number of decimals it has.
The name and symbol can be anything you want – since there's no central registry for tokens, you don't even have to worry about them being unique! In this example, we'll choose the name
TWE as the symbol.
When it comes to the number of decimals, many developers choose to use the same amount as the ether currency (
18). However, for simplicity's sake, we will put
0 here, so that 1 TWE is the minimum amount that you can own.
That was easy, huh?
Setting our token supply
For our ERC20 token to be complete, we need to specify how many tokens there are and how they get distributed. While most of the distribution job is going to be up to our ICO contract, the token contract still need to set the initial supply before handing over the reigns.
This is the part where you also get to decide how many of your tokens should be given to the founders, the development team, your strategic partners... etc.
In our case we'll keep things simple, so we'll issue 1 million tokens where 75% of the supply goes to the crowdsale and 25% is kept for the founders (that's us)!
It's worth noting that the creation of ERC20 tokens is in no way determined by proof-of-work like ether and bitcoin. Instead, they are created by completely arbitrary rules set by your contract, and you could in theory create new tokens or reset everyone's balances at any time you want (although keep in mind that people probably wouldn't want to invest in a token that permitted something like that).
Now that we know that, let's start by specifying the amounts given to the founder and to the ICO as state variables (remember that it has to add up to a million):
Then, we create a constructor function where we set the initial values of two variables:
totalSupply_ (note the underscore) and
balances. These are inherited from OpenZeppelin's
StandardToken library and keep track of your token's total supply as well as what addresses own what amount of tokens.
As you can see, we initially give all the tokens to the deployment address (
msg.sender), since we have to give them to someone. This means that, after deploying the token, the founders will actually control 100% of the supply. Don't get too excited though, it won't stay like that for long.
To test what we've done so far, let's create a new migration file called
...and a new integration test file dedicated to our token. Notice that, thanks to the fact that our token library inherit from
StandardToken, we can call a function called
balanceOf to see how many tokens a specific address has.
Creating our token sale
As we mentioned earlier, there's no point in having a token if everything is owned by you anyway. The next step is to create an ICO contract where people can send in ethers and get Tweether tokens in return!
We'll start by creating an empty contract for our ICO:
The first thing we want to do is fix the distribution of tokens. Right after the ICO contract is deployed, we want the token contract to send 75% of our token supply to it. For that, we'll create a new function in our token contract called
As you can see, we're again using our
Owned library so that the
fundICO function can only be accessed by the contract owner. It then uses the inherited
transfer function to send exactly 750000 (the number given by
FOR_ICO) of the sender's tokens to the given address (
Now we simply need to deploy our ICO contract and call that function for the transfer to take place. For that, we'll create a new migration file:
This should now have distributed the tokens for us so that 75% of them are in the
TweetherICO contract, while 25% remain in our personal "owner" account.
If you try to run the previous test again, you'll see that it fails, which is a good thing!
Let's update the test so that it reflects our new distribution, and checks the number of tokens in both our owner account and the ICO contract:
Now that the distribution is working as expected, let's move on to the actual sale process. In order for our ICO contract to send its tokens to other addresses, it needs to be able to access the token contract's
transfer function. We'll therefore import the
TweetherToken contract into the ICO contract and save the deployed instance as a state variable, so that we can access it later.
Our constructor now expects to get the token contract's address as a parameter, so we need to update our latest migration file:
Now the question is: how does our ICO contract know what to do when users send ethers to its address?
For that, we need to use what's known as a fallback function – that is, a function without a name, which is called if no other function is specified. Since we expect to receive ethers on this address, we also need to add the built-in
In this function, we now want to:
Get the amount of money the user has sent (in Wei).
Convert that money to a certain amount of Tweether tokens, based on a rate that we set.
Send the Tweether tokens to the user's address.
The amount of wei (ether's smallest denomination, in case you had forgotten) sent in the transaction can easily be retrieved using
msg.value inside the function. The next step is then to convert this amount to Tweether tokens. For that, we first need to set a conversion rate, which we will make into a public state variable so that everyone can easily verify it. Let's say that 1 ETH gives you 1000 TWE tokens:
Now, in order to convert wei to TWE, we need to first convert the wei to ethers and then multiply the result with 1000.
While performing basic operations with Solidity's own operators works fine, many ICO contracts choose to use OpenZeppelin's
SafeMath library in order to protect themselves from potential integer overflows. This becomes extra important when dealing with money of course, so let's follow the same best practice:
Alright, now we can safely create an internal function called
_getTokenAmount which will handle the conversion from wei to TWE for us:
Finally, we call this function in our fallback function, followed by the token contract's
transfer function to send a certain amount of tokens to their rightful new owner!
Looks good! Now we just need to test it.
In our test, we will simply send a transaction of 1 ETH from a random account to the ICO contract. After the transaction, we should expect the account to have received 1000 TWE, while the ICO contract's balance should have been reduced to 749 000 TWE.
Trying it with MetaMask
While it's always good to test your code, it's often more satisfying to see the results of your work wrapped in a nice UI. Let's see how we can deploy our ICO and get some Tweether tokens into our MetaMask wallet!
We start by running our migrations on the development network so that the new token contracts are uploaded (make sure that you have your local
testrpc instance running in the background again):
When it's done, take note of what address the ICO contract was uploaded to and copy it!
Now head to MetaMask, and send a transaction of 1 ETH to that address. If your MetaMask wallet doesn't have any ethers, remember that you can run
npm run fund-metamask to top it up!
After the transaction has confirmed, you might be confused about why you can't see any tokens in your wallet. It turns out that you need to manually add the token address in MetaMask in order to "register" it – after all, there are so many tokens out there, there's no way MetaMask could list them all by default!
To do this, open the side menu and click on the "Add token" button to get started:
Once you're on the token page, click on "Add custom token" and paste in the token contract's address in the address field.
After confirming that you want to add the token, you should be able to see your TWE balance right next to your ETH balance in the wallet. How cool!
Hopefully, this will have given you enough knowledge about how ERC20 tokens and ICOs work for you to be able to build more advanced token sales in the future.