Creating a Token

If you have not already, please make sure you have the required software.

We deal with tokens all the time in our day-to-day life, such as:

  • coins (or money in general)
  • shares on a stock market
  • credit card rewards points
  • voter registrations

In each case we want a thing (think: token) which:

  • cannot be copied or counterfeitted
  • has specific rules governing transferring ownership (of possibly forbidding transfer)
  • only the legitimate owner has access to use

Which are properties a blockchain-based system, like Ethereum, provides.


Creating Your First Application

1. Download and Unzip the Demo Project

Download the demo project and unzip it onto your computer, then navigate to that folder inside a terminal.

2. Try It Out, Run Your Application Locally on the Testnet

The ethers-build toolchain includes the standard Ethers container and can serve it locally as a normal webserver with your app embedded inside it.

/Users/ethers/my-app> ethers-build serve

3. Browse the Application

Now in your browser, navigate to the local running ethers.io container.

Play around with it a bit, to get an idea of how it works.


Exploring

Here are the list of files downloaded from the demo project.

  • FreeTestToken.sol - The smart contract that manages our token
  • deploy-token.js - The deployment script; it compiles the contract source (FreeTestToken.sol) and deploys it (with no arguments). More complex contracts may require more complex deployment scripts
  • test-token.js - The tests for the FreeTestToken contract
  • index.html - The frontend HTML application
  • package.json - This is a standard NPM project, so we manage dependencies and scripts using the NPM tools
  • dashboard-v0.2.* - Demo Framework library; you shouldn’t need to change this

Lets Give the Test Cases a Try

Install all the node modules needed by the tests:

/Users/ethers/my-app> npm install

Run the tests:

/Users/ethers/my-app> npm test

This is the quickest and easiest way to change and add functionality to a smart contract. As you modify the smart contract, update and add test cases to test-token.js and then run npm test. This creates a virtual blockchain in memory and runs your testcases against it.

Lets add some debugging to the FreeTestToken contract. Update the mint function to the following:

function mint() returns (bool success) {
    //! "Minting"
    //! msg.sender
    _balances[msg.sender] += 1;
    _totalSupply += 1;
    return true;
}

And run npm test again. You should see some additional lines in the output:

//! Debug(line = 23, type = string):  Minting
//! Debug(line = 24, type = address):  0xe26C5C346F45753C78c6B47e548313B0bd050B9A

The test cases will automatically use a compiler which has been modified to inject debug statements into your contract. When compiled for deployment, since these are only in comments, they will be ignored.


Try Out Deployment

Ethers provides a hosting service ethers.space, which allows small (under 5MB) applications to be deployed and hosted using the ethers-build toolchain.

1. Create a Git Repository and Add the Project Files

The ethers-build toolchain requires a git repository for managing hosted applications. This enables meaningful diffs against what is published, what is local and the contents of prepared Slugs.

/Users/ethers/my-app> git init
Initialized empty Git repository in /Users/ethers/my-app/.git/

/Users/ethers/my-app> git add *.html *.js *.css

/Users/ethers/my-app> git commit -m 'Initial code drop.'

2. Setup an ethers.space Account

The hosting provided by Ethers does not require any sign-up or usernames. Instead it is managed by a standard Ethereum account which signs data for uploading. Your application will be located a address.ethers.space. Applications sizes must be 5MB or less.

# This command will require a password and will generate ./account.json
/Users/ethers/my-app> ethers-build init
Do NOT lose or forget this password. It cannot be reset.
New Account Password: ******
Confirm Password: ******
Encrypting Account... (this may take a few seconds)
Account successfully created. Keep this file SAFE. Do NOT check it into source control

3. Prepare Your Application

For deploying to ethers.space, your application is bundled into a single Slug file, which will be signed when uploaded (or optionally signed earlier for deferred deployments).

# This command bundles up your application (tracked by git) into a Slug
/Users/ethers/my-app> ethers-build prepare
Adding:
    dashboard-v0.2.css
    dashboard-v0.2.js
    deploy-token.js
    ethers-app-v0.3.js
    index.html
    test-token.js
WARNING!
   [ you may ignore these for now ]

4. Publish Your Application to ethers.space

/Users/ethers/my-app> ethers-build publish unsigned.slug
Account Password (./account.json): ******
Application URLs:
  Testnet: https://testnet.ethers.io/#!/app-link/0xc7cc5c382e60ecc2c33ddaedfcc9601acfa1d3bd.ethers.space
  Mainnet: https://ethers.io/#!/app-link/0xc7cc5c382e60ecc2c33ddaedfcc9601acfa1d3bd.ethers.space
Successfully deployed!

Your Application is now LIVE on the internet for all to enjoy, on both the Ropsten testnet and the Ethereum mainnet at the URLs in the publish messages.


Modifying the Contract

1. Only Allow the Token Owner to Mint New Tokens

Change the mint() function to the following:

function mint() returns (bool success) {
    require(msg.sender == _owner);
    _balances[msg.sender] += 1;
    _totalSupply += 1;
    return true;
}

2. Get Some Testnet Ether

From the Ethers testnet faucet, import your /account.json by clicking the gear in the lower-right corner.

Once you have funded your account with some testnet ether, you will be able to proceed to deploy contracts on testnet.

3. Deploy the New Contract

/Users/ethers/my-app> ethers-build deploy deploy-token.js --testnet --account account.json --gas-price 100
Sign Transaction:
    Network:       testnet
    From:          0xC7cc5C382e60ecC2C33dDAEdFcc9601ACFa1d3bD
    Gas Price:     100.0 Gwei
    Gas Limit:     1500000
    Value:         0.0 ether
    Data:          1300 bytes
Account Password (testnet:account.json): ******
Deployed: FreeTestToken (./FreeTestToken.sol)
    Transaction Hash: 0x3f6449dcc1fefb55d24d7a3f2e2ca9899f9a61f49c7d2808223348fb75a236ec
    Contract Address: 0x972015EEC839Fe2c1e65374Cee516d68058dEd16
    Bytecode:         0x6060604052341561000f57600080fd5b6104f68061001e6000396000f300606060405236156100a15763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde0381146100a6578063095ea7b3146101305780631249c58b1461016657806318160ddd1461017957806323b872dd1461019e578063313ce567146101c65780634e8c2927146101ef57806370a082311461020457806395d89b4114610223578063a9059cbb14610236575b600080fd5b34156100b157600080fd5b6100b9610258565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100f55780820151838201526020016100dd565b50505050905090810190601f1680156101225780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b341561013b57600080fd5b610152600160a060020a036004351660243561028f565b604051901515815260200160405180910390f35b341561017157600080fd5b6101526102c0565b341561018457600080fd5b61018c6102ec565b60405190815260200160405180910390f35b34156101a957600080fd5b610152600160a060020a03600435811690602435166044356102f2565b34156101d157600080fd5b6101d96103c6565b60405160ff909116815260200160405180910390f35b34156101fa57600080fd5b6102026103cb565b005b341561020f57600080fd5b61018c600160a060020a03600435166103f5565b341561022e57600080fd5b6100b9610410565b341561024157600080fd5b610152600160a060020a0360043516602435610447565b60408051908101604052600f81527f46726565205465737420546f6b656e0000000000000000000000000000000000602082015281565b600160a060020a03338116600090815260026020908152604080832093861683529290522081905560015b92915050565b600160a060020a0333166000908152600160208190526040909120805482019055600380548201905590565b60035490565b600160a060020a0383166000908152600160205260408120548290108061033f5750600160a060020a03808516600090815260026020908152604080832033909416835292905220548290105b806103645750600160a060020a03831660009081526001602052604090205482018290105b15610371575060006103bf565b50600160a060020a0380841660009081526001602081815260408084208054879003905560028252808420338616855282528084208054879003905593861683528190529190208054830190555b9392505050565b600081565b6000805473ffffffffffffffffffffffffffffffffffffffff191633600160a060020a0316179055565b600160a060020a031660009081526001602052604090205490565b60408051908101604052600381527f4654540000000000000000000000000000000000000000000000000000000000602082015281565b600160a060020a033316600090815260016020526040812054829010806104885750600160a060020a03831660009081526001602052604090205482018290105b15610495575060006102ba565b50600160a060020a033381166000908152600160205260408082208054859003905591841681529081208054830190556102ba5600a165627a7a72305820cc7edc339980de5f0caad583721aaa317fb9714e31ffb407dacc44532feccff40029
    Arguments:        0x
    Interface:        [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"amount","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"mint","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"totalSupply","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"FreeToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]

4. Update the Application Frontend

Modify the index.html where we specify and update the contract address to the new address from the above deployment. (e.g. 0x972015EEC839Fe2c1e65374Cee516d68058dEd16)

<script type="text/javascript">
   var address = '0x972015EEC839Fe2c1e65374Cee516d68058dEd16';

5. Refresh your Application

If you refresh your application in your web browser, you should now be running the latest contract, in which only the owner account (the ./account.json) may mint new tokens.

You may use the Ethers import feature to import the account.json into your browser by clicking the gear in the lower-right hand corner of the ethers.io website.


Exercises

  • Remove mint entirely and have the constructor create a fixed total supply, allocated to the owner