LoginSignup
2
1

More than 5 years have passed since last update.

MyToken発行してみた(開発環境編)

Last updated at Posted at 2018-06-28

Note:記事は執筆時点(2018年6月)の内容です。技術の進歩が早く、今後陳腐化する可能性もあるのでご留意ください。

はじめに

  • ERC20のオリジナルトークンを作ってみよう
  • Solidityでコントラクトを作成して、ローカル環境にデプロイしよう

事前準備

  • 必要なもの

    • Ubuntu
    • Node.js
    • Truffle
    • 開発用エディタ(Visual Studio Code など)
  • 環境構築がまだの方はこちらから↓

Ethereum開発環境構築:Windows編

参考資料

  • 以下の先生の記事を参考しながら、進めます。先生に感謝。

Truffle で始める Ethereum 入門 - ERC20 トークンを作ってみよう

EthereumのERC20 トークンとして社内通貨(風)のものを作ってみます

作業の流れ

  1. プロジェクトフォルダの作成
  2. OpenZeppelinのインストール
  3. Solidityコードの作成
  4. Solidity コードのコンパイル
  5. マイグレーションファイルの作成
  6. コントラクトのデプロイ
  7. デプロイされたコントラクトの確認

【手順1】プロジェクトフォルダの作成

  • シェルで以下コマンドを実行

プロジェクトフォルダの作成

# 作業フォルダ(mntした共有フォルダ)に移動後、以下のコマンドを実行
$ mkdir mycoin
$ cd mycoin

# truffleのinitコマンドでコントラクトの雛形を作成
$ truffle init

# 作成されたフォルダを確認
$ tree -L 2

## 実行結果(例)
.
├── contracts
│   └── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
├── test
├── truffle-config.js
└── truffle.js

3 directories, 4 files

# デフォルト設定でpackage.jsonを作成
$ npm init -f

Note:mycoinの部分を各自変更してください。
例)tooricoin

【手順2】OpenZeppelinのインストール

  • シェルで以下コマンドを実行

OpenZeppelinのインストール

# OpenZeppelinのインストール
$ npm install zeppelin-solidity --save

Note:OpenZeppelinは、ERC20のコントラクトが実装済みです。
コントラクトの中でimportすることで、簡単にERC20のコントラクトを作成できます。

【手順3】Solidityコードの作成

  • contractsフォルダに移動
  • VS CodeでMyCoin.solファイルを作成

Note:MyCoinの部分を各自変更してください。
例)TooriCoin.sol

  • ファイル作成し、エディタで以下コードを貼り付け

Solidityコードの作成(サンプル)

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

contract MyCoin is StandardToken {

    string public name = "MyCoin";
    string public symbol = "MYCO";
    uint public decimals = 18;

    address public owner;
    mapping (address => string) public thanksMessage;
    uint public maxSupply;
    uint public totalSupply;

    constructor(uint _initialSupply, uint _maxSupply) public {
        owner = msg.sender;
        totalSupply = _initialSupply;
        maxSupply = _maxSupply;
        balances[msg.sender] = _initialSupply;
    }

    function addTotalSupply(uint256 _value) public {
        require(owner == msg.sender);
        require(maxSupply >= (totalSupply + _value));

        totalSupply += _value;
        balances[msg.sender] += _value;
    }

    function thanks(address _to, string _message) public {
        transfer(_to, 100e18);
        thanksMessage[_to] = _message;
    }

    function thanksMessage(address _address) public view returns (string) {
        return thanksMessage[_address];
    }

}

Note:コントラクトコードの説明

  • 変数定義の他にconstructorと3つのfunctionを定義しています

  • constructor:コントラクト作成時に呼ばれるコンストラクタ

  • function addTotalSupply(uint256 _value):Coinの発行総数を増やす関数。増加数を引数に与えます。

  • function thanks(address _to, string _message):ありがとうメッセージと一緒にCoinを送信する関数。送信先アドレスとメッセージを引数に与えます。POSTメソットのイメージです。

  • function thanksMessage(address _address):送信されたthanksMessageを参照する関数。送信先アドレスを引数に与えます。GETメソットのイメージです。

  • 今回は自分のTokenを作成したいので、以下のようにカスタマイズ。

Solidityコードの作成(実装例)

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

contract TooriCoin is StandardToken {

    string public name = "TooriCoin";
    string public symbol = "TORI";
    uint public decimals = 18;

    address public owner;
    mapping (address => string) public thanksMessage;
    uint public maxSupply;
    uint public totalSupply;

    constructor(uint _initialSupply, uint _maxSupply) public {
        owner = msg.sender;
        totalSupply = _initialSupply;
        maxSupply = _maxSupply;
        balances[msg.sender] = _initialSupply;
    }

    function addTotalSupply(uint256 _value) public {
        require(owner == msg.sender);
        require(maxSupply >= (totalSupply + _value));

        totalSupply += _value;
        balances[msg.sender] += _value;
    }

    function thanks(address _to, string _message) public {
        transfer(_to, 100e18);
        thanksMessage[_to] = _message;
    }

    function thanksMessage(address _address) public view returns (string) {
        return thanksMessage[_address];
    }

}

Note:変更箇所は以下の通り

  • contract名をMyCoinからTooriCoinに変更

  • nameをMyCoinからTooriCoinに変更

  • symbolをMYCOからTORIに変更

【手順4】Solidity コードのコンパイル

  • シェルで以下コマンドを実行

Solidity コードのコンパイル

# Solidity コードのコンパイル
$ truffle compile
  • 正常にコンパイルされるとbuildフォルダの中にjsonファイルが作成される

コンパイル結果の確認

# コンパイル結果の確認
$ cd build
$ tree -L 2

## 実行結果(例)
.
└── contracts
    ├── BasicToken.json
    ├── ERC20.json
    ├── ERC20Basic.json
    ├── Migrations.json
    ├── MyToken.json
    ├── SafeMath.json
    ├── StandardToken.json
    └── TooriCoin.json

1 directory, 8 files

【手順5】マイグレーションファイルの作成

  • migrationsフォルダに移動
  • VS Codeで2_deploy_MyCoin.jsファイルを作成

Note:MyCoinの部分を各自変更してください。
例)2_deploy_TooriCoin.js

Note:Ethereumでは、デプロイのことをマイグレーションと呼びます。
migrationsフォルダでは、デプロイ内容をjsファイルに定義します。

migrationファイルは[数字]_[名称].jsという形式にする必要があります。
[数字]の順にmigrationが実行されます

  • ファイル作成し、エディタで以下コードを貼り付け

Migrationファイルの作成(サンプル)

2_deploy_MyCoin.js
const MyCoin = artifacts.require('./MyCoin.sol')

module.exports = (deployer) => {
    let initialSupply = 1000000e18
    let maxSupply = 100000000e18
    deployer.deploy(MyCoin, initialSupply, maxSupply, {
        gas: 2000000
    })
}
  • 今回は自分のTokenを作成したいので、以下のようにカスタマイズ。

Migrationファイルの作成(実装例)

2_deploy_TooriCoin.js
const TooriCoin = artifacts.require('./TooriCoin.sol')

module.exports = (deployer) => {
    let initialSupply = 1000000e18
    let maxSupply = 100000000e18
    deployer.deploy(TooriCoin, initialSupply, maxSupply, {
        gas: 2000000
    })
}

Note:変更箇所は以下の通り

  • MyCoinからTooriCoinに変更

【手順6】コントラクトのデプロイ

  • シェルで以下コマンドを実行

エミュレータの起動

# ローカルでのエミュレータの起動
$ truffle develop

// 実行結果(例)
Truffle Develop started at http://127.0.0.1:9545/

Accounts:
(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
(1) 0xf17f52151ebef6c7334fad080c5704d77216b732
(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de

Private Keys:
(0) c87...
(1) ae6...
(2) 0db...
(3) c88...
(4) 388...
(5) 659...
(6) 82d...
(7) aa3...
(8) 0f6...
(9) 8d5...

Mnemonic: candy ...
  • エミュレータ起動後に、truffleのコンソールモードになるので、以下コマンドを実行してデプロイ

コントラクトのデプロイ

// コントラクトのデプロイ
$ truffle(develop)> migrate

// 実行結果(例)
Using network 'develop'.

Running migration: 1_initial_migration.js
  Replacing Migrations...
  ... 0x63fb52c38e0c0a6ffb49344b27f96222178399bae48b7bffe5cb1c4b9d808bd9
  Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network...
  ... 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts...
Running migration: 2_deploy_tooricoin.js
  Deploying TooriCoin...
  ... 0x7b30330b3c0f4f3c9ed0b90761be5ae7da706ea7ddb054bcf27eb854adf31d57
  TooriCoin: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network...
  ... 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts...

Note:migrateコマンドを実行したときに表示されるコントラクトのアドレス(0xで始まるコード)をこのあと使用するので控えておきましょう
例)TooriCoin: 0x345ca3e014aaf5dca488057592ee47305d9b3e10

【手順7】デプロイされたコントラクトの確認

  • truffleコンソールで以下コマンドを実行

コントラクトのインスタンス化

// コントラクトをインスタンス化します
truffle(develop)> contract = TooriCoin.at("<コントラクトのアドレス>")

// 実行結果(例)
[{...}] contractが表示される長いので省略

  • コントラクトの基礎情報を確認してみます

コントラクトの基礎情報確認

// コントラクトの名称を表示
truffle(develop)> contract.name()

// 実行結果(例)
'TooriCoin'

// Tokenの総額を表示
truffle(develop)> contract.totalSupply()

// 実行結果(例)
BigNumber { s: 1, e: 24, c: [ 10000000000 ] }
  • ローカル環境上のアカウントの一覧を表示してみます

アカウント一覧の表示

// アカウント一覧の表示
truffle(develop)> web3.eth.accounts

// 実行結果(例)
[ '0x627306090abab3a6e1400e9345bc60c78a8bef57',
  '0xf17f52151ebef6c7334fad080c5704d77216b732',
  '0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef',
  '0x821aea9a577a9b44299b9c15c88cf3087f3b5544',
  '0x0d1d4e623d10f9fba5db95830f7d3839406c6af2',
  '0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e',
  '0x2191ef87e392377ec08e7c08eb105ef5448eced5',
  '0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5',
  '0x6330a553fc93768f612722bb8c2ec78ac90b3bbc',
  '0x5aeda56215b167893e80b4fe645ba6d5bab767de' ]

Note:ローカル環境上のアカウントはtruffle developコマンド実行時にtruffleが自動的に作成してくれます

  • 各アカウント毎の残高を表示してみます

アカウント毎の残高確認(実行前)

// 0番目のアカウントの残高を表示
truffle(develop)> contract.balanceOf(web3.eth.accounts[0])

// 実行結果(例)
BigNumber { s: 1, e: 24, c: [ 10000000000 ] }

// 1番目のアカウントの残高を表示
truffle(develop)> contract.balanceOf(web3.eth.accounts[1])

// 実行結果(例)
BigNumber { s: 1, e: 0, c: [ 0 ] }
  • 0番目のアカウントから1番目のアカウント(0xf17f52151ebef6c7334fad080c5704d77216b732)に対して、メッセージとTokenを送信してみます

メッセージとTokenの送信

// メッセージとTokenを送信
truffle(develop)> contract.thanks("0xf17f52151ebef6c7334fad080c5704d77216b732", "Thanks!")

// 実行結果(例)
{ tx:
   '0x59aa94f5e629414d5fe64e0a49081783f09033b7dc09e2d8b7feba7fb15bd453',
  receipt:
   { transactionHash:
      '0x59aa94f5e629414d5fe64e0a49081783f09033b7dc09e2d8b7feba7fb15bd453',
     transactionIndex: 0,
     blockHash:
      '0xd699f8e854ab2c79e935229093d9f932d8ebe8ee9b949a77297e781b292a8674',
     blockNumber: 5,
     gasUsed: 73071,
     cumulativeGasUsed: 73071,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x01',
     logsBloom:
      '0x00000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000008000000000000000000010000000080000000000000000000000000000000000000000000000000000000000000000010000000000000000000010000000000000000000000000000000000000000010000000002000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000010000000000000' },
  logs:
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash:
        '0x59aa94f5e629414d5fe64e0a49081783f09033b7dc09e2d8b7feba7fb15bd453',
       blockHash:
        '0xd699f8e854ab2c79e935229093d9f932d8ebe8ee9b949a77297e781b292a8674',
       blockNumber: 5,
       address: '0x345ca3e014aaf5dca488057592ee47305d9b3e10',
       type: 'mined',
       event: 'Transfer',
       args: [Object] } ] }

Note:ローカル環境でテストする場合は、thanks関数の第一引数の0xf17f52151ebef6c7334fad080c5704d77216b732web3.eth.accounts[1]と入力してもOKです。

  • メッセージ送信後の各アカウント毎の残高を表示してみます

アカウント毎の残高確認(実行後)

// 0番目のアカウントの残高を表示
truffle(develop)> contract.balanceOf(web3.eth.accounts[0])

// 実行結果(例)
BigNumber { s: 1, e: 23, c: [ 9999000000 ] }

// 1番目のアカウントの残高を表示
truffle(develop)> contract.balanceOf(web3.eth.accounts[1])

// 実行結果(例)
BigNumber { s: 1, e: 20, c: [ 1000000 ] }
  • メッセージ内容を表示してみます

メッセージ内容の表示

// メッセージ内容の表示
truffle(develop)> contract.thanksMessage(web3.eth.accounts[1])

// 実行結果(例)
'Thanks!'

Note:Tokenだけでなく、メッセージもEthereum上に記録されていることが確認できます

まとめ

  • ローカル環境上でERC20のオリジナルトークンを作ることができました!
  • 次のステップとして、作成したコントラクトをEthereumのテスト環境にデプロイしてみましょう

MyToken発行してみた(テスト環境編)

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1