Deploying a Simple Token
I was recently asked to help create a simple ERC20 token for a fellow meetup organizer, for her to learn more about how Ethereum tokens are created, deployed, and used.
Helping other people learn new things — especially in the crypto ecosystem — is what I love best, so I took this opportunity to put together a nice tight lil repo which makes it as easy as possible for someone to deploy a token, and know exactly what’s going on along the way.
TLDR: https://github.com/decentorganization/simple-token
This is called simple-token
for a reason: it’s super simple. It is a base-standard ERC20 token with a fixed supply of tokens, created at token the token’s initialization, and given to the address who deploys the contract. There are no administrative functions in the token (for minting or burning, for example — this contract doesn’t support those functions). It’s very basic, but a good starting point for understanding how a token works and deploying one.
Let’s walk through it.
Prereqs
Install the necessary dependencies, namely git
and yarn
.
Then clone down the repo with
$ git clone https://github.com/decentorganization/simple-token
and install the dependencies with
$ yarn install
Config
The project uses environment variables for configuration options, such as the token’s name, symbol, decimals, and total supply.
We use the dotenv
package to manage environment variables (which was installed via yarn install
above), which means that we need a .env
file in the project. It’s not included by default upon cloning the project down, so use the .env.example
file to create one for yourself
$ cp .env.example .env
Open up .env and change the values to whatever you see fit. I recommend keeping the number of decimals at 18
, as this will provide the best experience when interacting with the rest of the Ethereum Token ecosystem.
Code
Start off in ./contracts/SimpleToken.sol
. Notice how the contract inherits from ERC20
and ERC20Detailed
. These two contracts are provided by the wonderful openzeppelin-solidity
project, of which I have copied the relevant files into this project.
The constructor, which is executed one time — upon contract deployment — expect 4 arguments to be passed in: name
, symbol
, decimals
, and totalSupply
.
The SimpleToken
's constructor then, in turn, calls the constructor of its inherited ERC20Detailed
contract, passing in name
, symbol
, and decimals
. Then the constructor executes the single line of custom code in this project (lol): _mint(msg.sender, _totalSupply)
.
That line calls the _mint(address, uint)
function which lives in ./contracts/openzeppelin/contracts/token/ERC20/ERC20.sol
(it’s from openzeppelin), using msg.sender
of the transaction as the recipient of the new tokens, and the passed-in totalSupply
as the total number of tokens to create.
I highly encourage the interested reader to start digging into the ERC20
and ERC20Detailed
contracts that live in ./contracts/openzeppelin/contracts/tokens/ERC20/
directory, as this is where 100% of the ERC20 spec for SimpleToken.sol
is implemented. When dealing with immutable code, it’s best to use code that has been heavily audited and accepted by the community, which is the goal of openzeppelin: to be a source for trusted solidity implementations of common contract patterns.
Deploy
So how do we pass these 4 variables into the contract upon deployment? Simple — we use truffle
for that (also installed from yarn install
above).
The truffle
tooling provides an easy way to deploy contracts to various Ethereum networks, through the truffle migrate
command.
Head into ./migrations/2_deploy_simple_token.js
and notice how the deployer
object has a function called deploy
which takes n
number of arguments, with argument 1
being a reference to the contract to deploy, and arguments 2
through n
being whatever n-1
variables we want to pass in to the contract’s constructor.
As mentioned above, we’re using environment variables for the name
, symbol
, decimals
, and totalSupply
, so all we have to do is use dotenv
to pull them from our environment and set them in the deploy function. That is as simple as referencing them using the syntax: process.env.ENV_VAR_NAME
.
This project is not currently set up for deployment onto any “real” networks, but works very well for deploying onto a local blockchain that can be started using the truffle
toolset.
Check out the Local Development section of the README to learn more about how to start a local blockchain, migrate contracts onto it, then connect to it with Metamask to examine the token and interact with it.
Next Steps
When you’re comfortable with the codebase and deploying it locally, the next step would be to deploy this contract onto a real public network, such as Ropsten, Rinkeby, Görli, or (gasp) MAINNET.
Left as an exercise for the reader, you’ll need to modify ./truffle-config.js
to “set up” these networks. If you’re not running a node on one of these public networks, you’ll need to connect to an existing node to broadcast your contract transaction, and will need a funded Ethereum account to do so. Getting all of this set up will require changes to the codebase.
Hint —
This will come in handy: https://infura.io/
So will this: https://github.com/trufflesuite/truffle-hdwallet-provider
Disclaimer and P.S.
This is meant to be an educational exercise. Deploy code at your own risk. Yadda yadda.
The astute developer will have noticed that there are no tests in this project, which is a big no-no. Check out the test-suite
branch to see my progress on getting all of the relevant openzeppelin-solidity
tests copied into this project. There’s a silly issue with node
or BigNumber.js
or the new version of truffle
or the newly-released web3 1.0
or SOMETHING that’s not letting the tests execute properly. I’m tired of trying to debug it, and pull requests to fix this will be gratefully accepted :)