[001.3] Creating Your Own Token

Today we will create our own DailyToken contract according to the official ERC20 Token Standard. This will allow our token to be used in the token wallet applications. We will deploy our token with Truffle and, for the first time, use *listen* for blockchain events.

Subscribe now

Creating Your Own Token [09.06.2018]

Scout App for monitoring

The ERC20 Token Standard defines the interface that a Token contract must implement.

This is the interface defined by ERC20.

contract ERC20Interface {
    function totalSupply() public constant returns (uint);
    function balanceOf(address tokenOwner) public constant returns (uint balance);
    function allowance(address tokenOwner, address spender) public constant returns (uint remaining);
    function transfer(address to, uint tokens) public returns (bool success);
    function approve(address spender, uint tokens) public returns (bool success);
    function transferFrom(address from, address to, uint tokens) public returns (bool success);

    event Transfer(address indexed from, address indexed to, uint tokens);
    event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
 }

Basic functions

Let’s start implementing this interface step by step. First we define the essential fields owner, totalSupply, balances and the events Transfer and Approval. This is pretty straightforward.

In the constructor we set the total supply of tokens, the owner, and the smart contract; to start, we establish that all the coins belong to the owner. This smart contract will use the totalSupply defined during contract creation, and there’s no way to create additional tokens after deployment.

The requirement for the function totalSupply can be solved by using the public keyword during the definition of the totalSupply field.

The public keyword automatically exposes a getter function also called totalSupply that can be called publicly. For keeping track of balances we need a mapping. This will map addresses to numbers: the user accounts to their balances.

contract DailyToken {
        address public owner;
        uint256 public totalSupply;
        mapping(address => uint256) balances;
      event Transfer(address indexed from, address indexed to, uint tokens);
      event Approval(address indexed tokenOwner, address indexed spender, uint tokens);

        function DailyToken(uint256 supply, address _owner){
              totalSupply = supply;
              owner = _owner;
          balances[owner] = totalSupply;
}

The transfer function accepts two parameters: the recipient and the amount to send.

The amount to be sent will be deducted from the balance of the function caller, msg.sender.

Before we deduct the value from the caller’s balance, first we must confirm that they have enough funds to transfer by using the assert statement. If the assertion is satisfied, we deduct the funds from the sender. Then we try adding the funds to the receiver in a new variable result that has the same type (uint256) as the balances we just mapped to these addresses.

We must assert that the balance of the receiver has increased after the transfer.

This is a check against overflow errors. In the end, we generate a Transfer event before the function returns.

function transfer(address _to, uint256 _value) returns (bool) {
    assert(_value <= balances[msg.sender]);
    balances[msg.sender] = balances[msg.sender] - _value;
    uint256 result = balances[_to] + value;
    assert(result >= balances[_to]);
    balances[_to] = result;
    Transfer(msg.sender, _to, _value);
    return true;
  }

Finally, we have the balanceOf getter function, which returns the balance for a given address.

The implementation so far can perform the basic functionalities of tokens: hold balances and transfer tokens. This is nothing we haven’t seen before. However, there are a few more functions that provide more advanced functionalities, so we’ll look at those next.

  function balanceOf(address _owner) constant returns (uint256 balance) {
    return balances[_owner];
  }
}

Allowance Functions

The ERC20 introduces an allowance mechanism. This set of functions allows the account owner to provide specific allowances to many different accounts.

To accomplish this in our smart contract we must map the provider’s address to a set of different accounts, each with specific allowance value. Essentially, we need to keep a balance book for each separate account.

  mapping (address => mapping (address => uint256)) allowed;
  function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
    return allowed[_owner][_spender];
  }

For this we will use a mapping of addresses to nested mappings of allowances. Every nested allowance mapping will be address => uint256. We also need a getter function for this mapping called allowance.

To give someone an allowance we use the approve function. We only need to add a record in the *allowed *mapping.

function approve(address _spender, uint256 _value) returns (bool) {
    allowed[msg.sender][_spender] = _value;
    Approval(msg.sender, _spender, _value);
    return true;
  }

However ,if we leave it like this, there is a hidden bug in the code where the spender can spend more money than he has been allowed. Imagine the following scenario:

Alice makes an allowance to Bob to spend N coins. Then she changes her mind and wants to decrease the allowance from N to M coins. If Bob has already spent the N coins before Alice makes the change to M coins, Bob will be able to spend a total of N+M coins. There is no easy way for Alice to make sure this didn’t happen without checking all transactions on the blockchain.

That is why we will add a require statement before the first line in the function.

function approve(address _spender, uint256 _value) returns (bool) {
    require((_value == 0) || (allowed[msg.sender][_spender] == 0));
    allowed[msg.sender][_spender] = _value;
    Approval(msg.sender, _spender, _value);
    return true;
  }

This requires the allowance value to be 0 or the previous allowance for the spender’s account to be 0. Given our previous scenario, Alice will have to set the allowance from N to 0, check how much money Bob has already spent, then create a new allowance of M tokens or no allowance at all.

Next up is the transferFrom function. This one will be used by spenders to spend coins from their allowances.

function transferFrom(address _from, address _to, uint256 _value) returns (bool) {
    var _allowance = allowed[_from][msg.sender];
    assert(_value <= _allowance);
    allowed[_from][msg.sender] = _allowance - _value;
    uint256 _result = balances[_to] + _value;
    assert(_result >= balances[_to]);
    balances[_to] = _result;
    assert(_value <= balances[_from]);
    balances[_from] = balances[_from] - _value);
    Transfer(_from, _to, _value);
    return true;
  }

It accepts three parameters, the address _from(source) and _to(target) and value.

First we get the remaining allowance and make sure that it’s greater than the value to be transfered.

Then we subtract this value from the allowance and add it to the recipient’s balance. Last, we need to subtract the value from the original owner’s total balance. During the execution of the function if any of the assert statements fail, all previously executed commands will be rolled back and the entire transaction will fail. Now that our contract is finished, let’s deploy it with Truffle.

First we put our code in the DailyToken.sol file in the contracts directory.

Then we alter the migration file called 2_deploy_contracts.js located in the migrations folder. We import our smart contract just like the other contracts, but in the deploy function we need to pass two additional arguments for our smart contract.

var ConvertLib = artifacts.require("./ConvertLib.sol");
var MetaCoin = artifacts.require("./MetaCoin.sol");


module.exports = function(deployer) {
  deployer.deploy(ConvertLib);
  deployer.link(ConvertLib, MetaCoin);
  deployer.deploy(MetaCoin);
  deployer.deploy(DailyToken, 10000000, ‘0x627306090abab3a6e1400e9345bc60c78a8bef57’);
};

These extra parameters will be passed to the constructor of our contract. In our case we need the total supply and the address of the contract’s owner.

I used an address from the 10 default accounts that appear in the terminal after running:

>truffle develop

Deployment

Now on to deployment. Let’s start fresh by deleting the build directory.

> rm -rf build

Compile our contracts:

> truffle compile

Deploy:

  1. In a separate terminal run: > truffle develop

  2. In the first terminal run: > truffle migrate

Let’s interact with our DailyToken using the console.

Check the output of the truffle migrate command, you will see the address where DailyToken is deployed. Mine is 0xf204a4ef082f5c04bb89f7d5e6568b796096735a.

I can that instance of the DailyToken with:

var dailyToken = DailyToken.at(‘0xf204a4ef082f5c04bb89f7d5e6568b796096735a’);

To be sure, let’s check the owner of this instance.

dailyToken.owner.call()

In my case this matches the argument I added to the constructor in the migration file:

‘0x627306090abab3a6e1400e9345bc60c78a8bef57’

Check the total supply

dailyToken.totalSupply.call();

Finally let’s check the owner’s balance:

daily.balanceOf.call('0x627306090abab3a6e1400e9345bc60c78a8bef57');

Now name two accounts: parent and child. We’ll use the owner’s account as parent since that’s where all the coins are. Let’s create an allowance to the child account of 100 coins.

var parent = ‘0x627306090abab3a6e1400e9345bc60c78a8bef57’;

var child = web3.eth.accounts[1];

While creating the allowance, an event called Approval will be generated. We can listen for that event in another terminal window. Open another terminal into the same folder. Then run truffle develop.

This second terminal will connect to the same network at localhost:9545

Get a handle for the deployed smart contract.

var daily = DailyToken.at(‘0xf204a4ef082f5c04bb89f7d5e6568b796096735a’);

var event = daily.Approval({fromBlock: 0, toBlock: 'latest'})

The event accepts a filter argument. In this case we want all events from first to last block.

Set up the actual listener: '0x627306090abab3a6e1400e9345bc60c78a8bef57'

> event.watch(function(error,response){
console.log("Approval event");
console.log(“Approval from: “ + response.args.tokenOwner + “ to: “ + response.args.spender + “ of “ + response.args.tokens + “ coins”);
});

When you run this event watcher it will return any previous events as well, because we specifically said listen for all events from block 0 to the latest one.

Now create the allowance call in the first terminal.

daily.approve(child, 100, {from: parent})

Notice in the listener terminal the generated Approve event:


> Approval from: 0x627306090abab3a6e1400e9345bc60c78a8bef57 to: 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e of 100 coins

Conclusion

Today we deployed our custom smart contract and interacted with all it’s functions via terminal. Also we listened to it’s events from another blockchain node. This is very much inline with the async architecture of technologies like NodeJS and gives us an idea on how real-world applications can be built.

Resources

ERC20 token standard

Truffle documentation

Scout App for monitoring