ERC-20トークンを爆速で作ってみる
ERC-20とは
Ethereum上で発行できるトークンの標準規格です。
Truffle
トリュフです。
Ethereumのフレームワークで手軽にトークンが作れます。
まずはnpm経由でインストールします。
npm install -g truffle
次に任意のディレクトリ内でtruffleを初期化します。
truffle init
以下のように表示されたら成功です。
OpenZeppelin
OpenZeppelinはスマートコントラクトのフレームワークで手軽にスマートコントラクトを書くことができます。
OpenZeppelinのZeppelin Solidityを利用します。
まずはプロジェクト内でpackage.jsonを生成します。
npm init -f
次にモジュールをインストールします
npm install truffle-hdwallet-provider --save
これで準備は完了です。
solidityファイルの作成
token/contracts
以下に.sol
のファイルを作成します。(今回はkj3104.sol)
zeppelin-solidity/contracts/examples/SimpleToken.solを参考に書いていきます。
pragma solidity ^0.4.18; import "zeppelin-solidity/contracts/token/ERC20/StandardToken.sol"; contract kj3104 is StandardToken { string public constant name = "kj3104"; // 通貨の名前 Bitcoin, Ethereumなど string public constant symbol = "XKJ"; // 通貨シンボル BTC, ETHなど uint8 public constant decimals = 18; // 少数以下の桁数 // migration時に初期発行量を決めれるようにする。 function kj3104(uint256 _initialSupply) public { totalSupply_ = _initialSupply; balances[msg.sender] = _initialSupply; Transfer(0x0, msg.sender, _initialSupply); } }
これでコントラクトコードの完成です。
次にこのコードをコンパイルしましょう。
コマンドラインで以下を実行します。
truffle compile
すると、build/contracts
以下にズラズラとファイルが生成されます。
今回作成したkj3014.sol
に対応するコンパイル後のファイルはkj3104.json
です。
次にmigrationを書きます。
ファイル名は[数字]_[トークン名]_migration.js
とします。
今回は2_kj3104_migration.js
となります。
初期化時に生成される1_initial_migration.js
を参考にして記述します。
const kj3104 = artifacts.require('./kj3104.sol') module.exports = (deployer) => { const initialSupply = 1000000e18 deployer.deploy(kj3104, initialSupply) }
これで完了です。
デプロイ
デプロイします。
今回はテストネット等は使わずにローカルでのみ動かします。
コマンドラインで以下を実行します。
truffle develop
するとアカウントとプライベートキー、ニーモニックが表示され、対話型のコンソールになります。
まずはmigrate
と入力しましょう。
先程作成したmigrationファイルを利用してコントラクトコードをデプロイします。
これでデプロイの完了です。
コントラクトコードを編集後、または対話コンソール再起動後
migrate
をすると以下のようなエラーが出てしまいます。
Error: Attempting to run transaction which calls a contract function, but recipient address 0x8cdaf0cd259887258bc13a92c0a6da92698644c0 is not a contract address
この場合はmigrate --reset
と入力しましょう。
動かす
実際にコンソールから動かします。
まずはコントラクトを変数に入れます。
truffle(develop)> token = kj3104.at(kj3104.address)
こうすることで、 tokenから様々な情報が取れるようになります。
truffle(develop)> token.name() 'kj3104' truffle(develop)> token.symbol() 'XKJ'
アカウント一覧はweb3.eth.accounts
から取得できます。
truffle(develop)> web3.eth.accounts [ '0x627306090abab3a6e1400e9345bc60c78a8bef57', '0xf17f52151ebef6c7334fad080c5704d77216b732', '0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef', '0x821aea9a577a9b44299b9c15c88cf3087f3b5544', '0x0d1d4e623d10f9fba5db95830f7d3839406c6af2', '0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e', '0x2191ef87e392377ec08e7c08eb105ef5448eced5', '0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5', '0x6330a553fc93768f612722bb8c2ec78ac90b3bbc', '0x5aeda56215b167893e80b4fe645ba6d5bab767de' ]
最後に送金をします。
0x627306090abab3a6e1400e9345bc60c78a8bef57
から0xf17f52151ebef6c7334fad080c5704d77216b732
に100XKJを送金します。
truffle(develop)> token.transfer(web3.eth.accounts[1], 100e18) { tx: '0x58147cfec997910d11bdab81d79abc4573b4bf50e1cd6b14b281fc2fa5118a7b', receipt: { transactionHash: '0x58147cfec997910d11bdab81d79abc4573b4bf50e1cd6b14b281fc2fa5118a7b', transactionIndex: 0, blockHash: '0xa3c03f135dc87ffef92c58e303bc22975d7162e72b1399ea0c28f5d8024e4def', blockNumber: 5, gasUsed: 51925, cumulativeGasUsed: 51925, contractAddress: null, logs: [ [Object] ], status: '0x01', logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000008000000000000000000010000000080000000000000000000000000000000000000000000000000000000000000000010000000000000000000010000000000000000000000000000000000000000010000000002000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000010000000000000' }, logs: [ { logIndex: 0, transactionIndex: 0, transactionHash: '0x58147cfec997910d11bdab81d79abc4573b4bf50e1cd6b14b281fc2fa5118a7b', blockHash: '0xa3c03f135dc87ffef92c58e303bc22975d7162e72b1399ea0c28f5d8024e4def', blockNumber: 5, address: '0x345ca3e014aaf5dca488057592ee47305d9b3e10', type: 'mined', event: 'Transfer', args: [Object] } ] }
送金されているか残高を見ます。
truffle(develop)> token.balanceOf(web3.eth.accounts[0]) { [String: '9.999e+23'] s: 1, e: 23, c: [ 9999000000 ] } truffle(develop)> token.balanceOf(web3.eth.accounts[1]) { [String: '100000000000000000000'] s: 1, e: 20, c: [ 1000000 ] }
これで送金ができました!
おまけ
中央銀行的な発想で追加発行ができるようにします。
コントラクトコードに、addTotalSupply
を追加し、totalSupply_
及びownerの残高
に追加します。
以下がコードです。
contract kj3104 is StandardToken { string public constant name = "kj3104"; // 通貨の名前 Bitcoin, Ethereumなど string public constant symbol = "XKJ"; // 通貨シンボル BTC, ETHなど uint8 public constant decimals = 18; // 少数以下の桁数 address public owner; // オーナーのアドレスを初期化時に持つ function kj3104(uint256 _initialSupply) public { owner = msg.sender; // オーナーの代入 totalSupply_ = _initialSupply; balances[msg.sender] = _initialSupply; Transfer(0x0, msg.sender, _initialSupply); } function addTotalSupply(uint256 _value) public { require(owner == msg.sender); // オーナーでないと実行できない totalSupply_ += _value; balances[msg.sender] += _value; } }
これで追加発行機能を実装できました。
最後に
Open Zeppelinは実は知らなくて前まで結構面倒くさいなあと思いながら書いてました。
ぜひ使ってみてください
これからトークンや仮想通貨、トークンエコノミーなど乱立する時代になってくると思います。
一時期流行ったVALUのような感覚で自分自身をトークン化して価値をつけるというのも面白いですね。