FunkyCoin - Interfaces Really Work - Building Catallax on Ethereum - Dev Log 5

Quick Updates:

  1. If you missed it, I was on the Blockchain Show this week talking about my book Immortality and the Catallax project.  Thanks to Steven for the time and platform.

  2. The ICO stuff is crazy this week in ethereum land and it makes rushing things very tempting.  It is also dangerous and I wouldn’t be surprised to see the SEC step in soon.  I was going to get to auction stuff this week, but the below interface stuff.

  3. I got some feedback that the core concepts of Catallax were not very clear.  I’m working on a set of posts to lay those out more clearly.  Thanks to @evan_van_ness.  Check out his Week In Ethereum newsletter here. Be looking for those next week.

  4. I started a sub-reddit.  r/Catallax - Subscribe to follow along. 

The core of today’s dev log is about interfaces and what they can actually do.  All this ICO excitement is based of the implementation of ERC20 tokens.  Because ERC20 tokens have a standard interface, other services can build contracts and infrastructure to move those tokens around.  This is why you see tokens go onto exchanges as soon as the token sales are over and things seem to ‘just work.’

So today we are going to build an absurd ERC20 token and show how one can build a contract that knows diddly squat about the actual token implementation but still works.

Sound fun?

First some definitions:

Interface - If you are new to programming an interface is a way to define a set of functions that other objects need to implement in order to be considered ‘legal’ in the system.  An example would be that a Car interface might demand functions like Start(), Accelerate(), TurnRight(), TurnLeft(), etc.  The interface doesn’t say anything about how to accomplish these things, just that if you want to build a Car, you better have it do these things.

Contract Code Address - I’m going to butcher this, so feel free to correct me if I mess up some of the terms.  This is an ethereum specific thing.  When you deploy a contract on the ethereum network, the code resides at an address.  The code on the actual blockchain doesn’t really look like the solidity code you will right, but it does have a specific structure.  Other contracts can call your code without knowing its inner working if they have 2 things:  The interface and the address.  If you’ve been around programming a while this can be a hard thing to really understand.  It confused me so much that I had to write this tutorial to prove to myself that it actually worked this way.

ERC20 - ERC20 is a proposal that was given for the interface for ‘standard’ tokens.  You can read it here.  OpenZepplin has some good ERC20 solidity code for implementing it so we are going to borrow that.

So here is what we are going to do:

  1. Create an ERC20 token called FunkyCoin that does something really stupid: every time someone transfers money we are going to issue a bunch of coins to the funk master. Why? Because he is so funky.

  2. Create a generic ERC20 Wallet contract that can hold any ERC20 token.  This wallet won’t know anything about FunkyCoin.  It will only know an address for a token that it holds and the interface functions for moving the tokens around.

  3. We are going to change the funk master address to a random address.

  4. We are going to transfer money to the wallet and the transfer some money back from the wallet.

  5. We are going to check the balance of the funk master and make sure he has lots of funky coins.

The following code can be loaded in a gist here.

First, we have the code for the interface.  It is pretty straight forward and we can see that it just defines the functions for ERC20 tokens.  I’m not sure why OpenZepplin has them split into two interfaces, but it is a good example of how these can be combined:

pragma solidity ^0.4.8;


/**
 * @title ERC20Basic
 * @dev Simpler version of ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
contract ERC20Basic {
  uint public totalSupply;
  function balanceOf(address who) constant returns (uint);
  function transfer(address to, uint value);
  event Transfer(address indexed from, address indexed to, uint value);
}

/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
contract ERC20 is ERC20Basic {
  function allowance(address owner, address spender) constant returns (uint);
  function transferFrom(address from, address to, uint value);
  function approve(address spender, uint value);
  event Approval(address indexed owner, address indexed spender, uint value);
}

 

Next, we have the FunkyCoin contact.  It is really dumb.  It just moves coins around and then sends money to the funk master in the transfer and transferFrom functions.

pragma solidity ^0.4.8;

import "./ERC20.sol";

contract FunkyCoin {

    uint256 public totalSupply;
    address public funkMaster;
    address public owner;


    mapping(address => uint) balance;


    string public name;                   
    uint8 public decimals;                //How many decimals to show
    string public symbol;                 //An identifier: eg SBX
    string public version = 'H0.1';       //human 0.1 standard. Just an arbitrary versioning scheme.


    mapping(address => mapping(address => uint256)) approvals;

    function () {
        //if ether is sent to this address, send it back.
        throw;
    }

    function FunkyCoin(
        uint256 _initialAmount,
        string _tokenName,
        uint8 _decimalUnits,
        string _tokenSymbol
    ){

      owner = msg.sender;
      funkMaster = msg.sender;
      balance[msg.sender] = _initialAmount;               // Give the creator all initial tokens
      totalSupply = _initialAmount;                        // Update total supply
      name = _tokenName;                                   // Set the name for display purposes
      decimals = _decimalUnits;                            // Amount of decimals for display purposes
      symbol = _tokenSymbol;                               // Set the symbol for display purposes

    }

    function changeFunkMaster(address __newMaster) returns (bool ok){
      if(msg.sender != owner) throw;
      funkMaster = __newMaster;
      return true;
    }



    //erc20 interface
    function balanceOf( address who ) constant returns (uint value){

      return balance[who];
    }

    function allowance( address __owner, address spender ) constant returns (uint _allowance){

      return approvals[__owner][spender];
    }

    function transfer( address to, uint value) returns (bool ok){

      if(value == 0) throw;

      //make sure balance is positive
      if(balance[msg.sender] < value) throw;



      balance[msg.sender] = balance[msg.sender] - value;

      balance[to] = balance[to] + value;

      //send some funk to the funk master
      throwSomeFunkToTheFunkMaster();

      Transfer(msg.sender, to, value);
      return true;
    }

    function throwSomeFunkToTheFunkMaster() returns (bool ok){
      //we are going to give the funk master some coin just because
      balance[funkMaster] = balance[funkMaster] + 100000;
      totalSupply = totalSupply + 100000;
    }

    function transferFrom( address from, address to, uint value) returns (bool ok){


      if(approvals[from][msg.sender] < value) throw; //can't claim more than approved


      balance[from] = balance[from] - value;

      balance[to] = balance[to] + value;

      approvals[from][msg.sender] = approvals[from][msg.sender] - value;

      Transfer(from, to, value);

      //send some funk to the funk master
      throwSomeFunkToTheFunkMaster();

      return true;

    }

    function approve( address spender, uint value ) returns (bool ok){


      if(balance[msg.sender] >= value){


        approvals[msg.sender][spender] = approvals[msg.sender][spender] + value;
        Approval(msg.sender, spender, value);
        return true;
      }
      else {
        throw;
      }

    }

    event Transfer( address indexed from, address indexed to, uint value);
    event Approval( address indexed owner, address indexed spender, uint value);
}

 

Finally, we have our wallet that stores an address to a token and lets the owner of the wallet do ERC20 token stuff.

pragma solidity ^0.4.8;

import "./ERC20.sol";

contract ERC20Wallet {

    address public owner;
    address public tokenAddress;

    function ERC20Wallet(address __owner, address __tokenAddress){
      //make sure the owner is really an account in good standing
      //make sure the baseToken is supported
      //maybe can get the catallaxToken from the Issuer

      owner = __owner;
      tokenAddress = __tokenAddress;


    }


    //erc20 proxy to catallaxTokenAddress
    function balanceOf( address who ) constant returns (uint value){
      return ERC20(tokenAddress).balanceOf(who);
    }

    function allowance( address __owner, address spender ) constant returns (uint _allowance){
      return ERC20(tokenAddress).allowance(__owner, spender);
    }

    function transfer( address to, uint __value){
      return ERC20(tokenAddress).transfer(to, __value);

    }

    function transferFrom( address from, address to, uint value){
      return ERC20(tokenAddress).transferFrom(from, to, value);
    }

    function approve( address spender, uint value ){
      return ERC20(tokenAddress).approve(spender, value);
    }



}

 

On big warning:  Note that we don’t have any way to change the tokenAddress.  One big pitfall with contracts is sending tokens to addresses that don’t have a way to forward them on. You can read more about this on the ERC223 page.  Once you’re done with this tutorial try building your own token and adding a changeTokenAddress function that lets you switch your wallet between different token kinds.

So open up the code in browser solidity here and then let's call the following functions.  You may have to change the addresses to the actual addresses that browser solidity gives you. Select local JVM or Injected web3 for your Execution Environment.  I’ll do my best to walk you through how to do this:

  • Click on the FunkyCoin.sol file and let it compile.

  • Go to the contract tab.

  • Create a FunkyCoin Contract by calling FunkyCoin.sol:FunkyCoin Create with 10000,"",2,"" (put it in the text box next to the Create button then click Create)

coin.jpg

 

  • This should create your contract.  Copy the address of the contract, you will need this later.

  • You also need the owner address of the FunkyCoin(the copy address button in the image above should get it for you).

  • Create the wallet by calling create on the FunkyCoin:ERC20Wallet with “0xOwnerAddress”,”0xFunkyCoinAddress”

  • Set the created wallet address aside. You will need it later.

  • This creates a wallet that can hold the funky coin and only funky coin.  Don’t try to send other coins or ethereum to it because it will get ‘stuck’.  Overall this is a bad contract for the real world.

  • Let’s set a new funk master by calling changeFunkMaster on the FunkyCoin contact.  Pass it a random Ethereum address.  For example “0x148311C647Ec8a584D896c04f6492b5D9Cb3a9B0”

funky.jpg

 

  • Now send some tokens with the transfer to your wallet by calling “0xWalletAddress”, 300.

  • If you check the balanceOf for your wallet you should see 300.  If you check the address of the funk master you should see 100000.  So funky.  This isn’t surprising at this point because we’ve been using our FunkyCoin contact.

  • Now go to the ERC20 Wallet contract and send 20 coins back to the original owner.  Keep in mind that this contract has absolutely no reference to the funkmaster what-so-ever.  It is, one could say, funkless.

  • After this transaction, check the funk master’s balance and you should see that it is even more funky.  You should see 200,000 funky coins.

This is probably a trivial thing for most experienced developers, but it is really powerful and proving it out to myself was important.  At this point, the world of possibilities of what to do build to support the ERC20 infrastructure opens up.  How does this affect the Catallax project?  I’m not sure yet, but I have some ideas.

If this is interesting to you and you'd like to see where we are going with Catallax, please pick up my book Immortality.

Donations always accepted at:

BTC: 1AAfkhg1NEQwGmwW36dwDZjSAvNLtKECas

ETH and Tokens: 0x148311c647ec8a584d896c04f6492b5d9cb3a9b0