Chapter 8-2: ERC20準拠のトークン作成

ERC20準拠のトーク

ERC20とは、イーサリアム上のトークンを標準化する仕様のことです。

ERC20に準拠するトークンをERC20準拠のトークンと呼びます。

ERC20に準拠することで、異なるトークン同士でのやり取りが簡単になり、ERC20対応のウォレットでの取り扱いが可能となります。

詳しくはこちらを参照してください。

ERC20 Token Standard - The Ethereum Wiki

プロジェクト作成

$ mkdir dapps-token
$ cd dapps-token
$ truffle init

OpenZeppelinのインストール

OpenZeppelinは、Solidity言語でセキュアにスマートコントラクトを開発できるオープンソースフレームワークです。

$ npm init -f
$ npm install zeppelin-solidity

トークコントラクトの作成

contracts/DappsToken.solファイルを作成し、トークコントラクトの実装を行います。

pragma solidity ^0.4.18;
import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol";


contract DappsToken is StandardToken {
  string public name = "DappsToken";
  string public symbol = "DTKN";
  uint public decimals = 18;

  function DappsToken(uint initialSupply) public {
    totalSupply_ = initialSupply;
    balances[msg.sender] = initialSupply;
  }
}

dapps-token/DappsToken.sol at master · akifumi/dapps-token · GitHub

デプロイ時に動作するスクリプトを記述します。

migrations/2_deploy_dapps_token.jsファイルを作成します。

var DappsToken = artifacts.require("./DappsToken.sol");

module.exports = function(deployer) {
    var initialSupply = 1000;
    deployer.deploy(DappsToken, initialSupply);
};

dapps-token/2_deploy_dapps_token.js at master · akifumi/dapps-token · GitHub

テストコードの作成

tests/DappsToken.jsファイルを作成します。

var DappsToken = artifacts.require("./DappsToken.sol");

contract('DappsToken', function(accounts) {

  it("should put 1000 DappsToken in the first account", function() {
    return DappsToken.deployed().then(function(instance) {
      return instance.balanceOf.call(accounts[0]);
    }).then(function(balance) {
      assert.equal(balance.valueOf(), 1000, "1000 wasn't in the first account");
    });
  });
});

dapps-token/DappsToken.js at master · akifumi/dapps-token · GitHub

テストを実行します。

$ truffle develop
truffle(develop)> test

migrateコマンドでdevelopネットワークにデプロイし、設定した名前などを確認しましょう。

truffle(develop)> migrate
truffle(develop)> dappsToken = DappsToken.at(DappsToken.address)
truffle(develop)> dappsToken.name()
'DappsToken'
truffle(develop)> dappsToken.symbol()
'DTKN'
truffle(develop)> dappsToken.totalSupply()
{ [String: '1000'] s: 1, e: 3, c: [ 1000 ] }

アカウント別の発行量を確認します。

アカウントの1番目は発行者なので、トークンを全額保持しています。

アカウントの2番目は保持量が0です。

truffle(develop)> dappsToken.balanceOf(web3.eth.accounts[0])
{ [String: '1000'] s: 1, e: 3, c: [ 1000 ] }
truffle(develop)> dappsToken.balanceOf(web3.eth.accounts[1])
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }

送金してみましょう。

送金完了後に各アカウントが所持するトークン数を確認すると、トークンが正常に動作していることがわかります。

truffle(develop)> dappsToken.transfer(web3.eth.accounts[1], 100)
{ tx: '0xf001aa4460728b5b75b96e7afdc72e739d5a53cf71dffc4cb6323b83d1d5b2d0',
  receipt:
   { transactionHash: '0xf001aa4460728b5b75b96e7afdc72e739d5a53cf71dffc4cb6323b83d1d5b2d0',
     transactionIndex: 0,
     blockHash: '0x933600dadc8888729d6d538a27944088e37859b2d931af5f5e1a19a9f15e780f',
     blockNumber: 13,
     gasUsed: 51519,
     cumulativeGasUsed: 51519,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x01',
     logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000008000000000000000000010000000080000000000000000000000000000000000000000000000000000000000000000010000000000000000000010000000000000000000000000000000000000000010000000002000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000010000000000000' },
  logs:
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash: '0xf001aa4460728b5b75b96e7afdc72e739d5a53cf71dffc4cb6323b83d1d5b2d0',
       blockHash: '0x933600dadc8888729d6d538a27944088e37859b2d931af5f5e1a19a9f15e780f',
       blockNumber: 13,
       address: '0x345ca3e014aaf5dca488057592ee47305d9b3e10',
       type: 'mined',
       event: 'Transfer',
       args: [Object] } ] }
truffle(develop)> dappsToken.balanceOf(web3.eth.accounts[0])
{ [String: '900'] s: 1, e: 2, c: [ 900 ] }
truffle(develop)> dappsToken.balanceOf(web3.eth.accounts[1])
{ [String: '100'] s: 1, e: 2, c: [ 100 ] }