Ethereumのトークンとは
Ethereum上でトークンとよばれるコントラクトを作成することで独自の暗号通貨を作成することが可能です。 トークンを使うことで、コイン、ポイントなど様々な仮想的な価値をEthereumの仕組みの上で利用することができます。 トークンはEhereumのネットワーク上のアカウント間で自由にやりとりすることが可能です。
トークンコンストラクト
トークンを定義するためのコンストラクトには、幾つかの標準APIが定義されています。
トークンAPIの議論についてはここでされています。
Ethereumのトークンのサンプル実装は、ここにあります。
pragma solidity ^0.4.8; contract tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData); } contract MyToken { /* Public variables of the token */ string public standard = 'Token 0.1'; string public name; string public symbol; uint8 public decimals; uint256 public totalSupply; /* This creates an array with all balances */ mapping (address => uint256) public balanceOf; mapping (address => mapping (address => uint256)) public allowance; /* This generates a public event on the blockchain that will notify clients */ event Transfer(address indexed from, address indexed to, uint256 value); /* This notifies clients about the amount burnt */ event Burn(address indexed from, uint256 value); /* Initializes contract with initial supply tokens to the creator of the contract */ function MyToken( uint256 initialSupply, string tokenName, uint8 decimalUnits, string tokenSymbol ) { balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens totalSupply = initialSupply; // Update total supply name = tokenName; // Set the name for display purposes symbol = tokenSymbol; // Set the symbol for display purposes decimals = decimalUnits; // Amount of decimals for display purposes } /* Send coins */ function transfer(address _to, uint256 _value) { if (_to == 0x0) revert(); // Prevent transfer to 0x0 address. Use burn() instead if (balanceOf[msg.sender] < _value) revert(); // Check if the sender has enough if (balanceOf[_to] + _value < balanceOf[_to]) revert(); // Check for overflows balanceOf[msg.sender] -= _value; // Subtract from the sender balanceOf[_to] += _value; // Add the same to the recipient Transfer(msg.sender, _to, _value); // Notify anyone listening that this transfer took place } /* Allow another contract to spend some tokens in your behalf */ function approve(address _spender, uint256 _value) returns (bool success) { allowance[msg.sender][_spender] = _value; return true; } /* Approve and then communicate the approved contract in a single tx */ function approveAndCall(address _spender, uint256 _value, bytes _extraData) returns (bool success) { tokenRecipient spender = tokenRecipient(_spender); if (approve(_spender, _value)) { spender.receiveApproval(msg.sender, _value, this, _extraData); return true; } } /* A contract attempts to get the coins */ function transferFrom(address _from, address _to, uint256 _value) returns (bool success) { if (_to == 0x0) revert(); // Prevent transfer to 0x0 address. Use burn() instead if (balanceOf[_from] < _value) revert(); // Check if the sender has enough if (balanceOf[_to] + _value < balanceOf[_to]) revert(); // Check for overflows if (_value > allowance[_from][msg.sender]) revert(); // Check allowance balanceOf[_from] -= _value; // Subtract from the sender balanceOf[_to] += _value; // Add the same to the recipient allowance[_from][msg.sender] -= _value; Transfer(_from, _to, _value); return true; } function burn(uint256 _value) returns (bool success) { if (balanceOf[msg.sender] < _value) revert(); // Check if the sender has enough balanceOf[msg.sender] -= _value; // Subtract from the sender totalSupply -= _value; // Updates totalSupply Burn(msg.sender, _value); return true; } function burnFrom(address _from, uint256 _value) returns (bool success) { if (balanceOf[_from] < _value) revert(); // Check if the sender has enough if (_value > allowance[_from][msg.sender]) revert(); // Check allowance balanceOf[_from] -= _value; // Subtract from the sender totalSupply -= _value; // Updates totalSupply Burn(_from, _value); return true; } }
- 上記がサンプル実装のトークンコントラクトのソースです。
- プログラム処理としてはそれほど難しくないため、何となく書いてあることは理解できます。
各構文の理解もしていきたいのですが、今回はこのトークンコントラクトのサンプルソースを使って、新しいトークンをデプロイしてみます。
実行環境
- Ubuntu14.04 on docker
Ethereumのプライベートネットワークを作成する
- トークンは本番ネットワークではなくプライベートネットワークで作成します。
- プライベートネットワークの作成については以下を参照ください。
プライベートネットワーク(node)の起動
プライベートネットワークを起動してコントラクトを作成する準備をします。
コントラクトを作成するトランザクションでマイニングが必要なため予めマイニングをスタートしておきます。
geth \ --datadir /ethereum/eth_private \ --mine \ --nodiscover \ --maxpeers 0 \ --networkid 13 \ --rpc \ --rpcport 8545 \ --rpcaddr "0.0.0.0" \ --rpcapi="db,eth,net,web3,personal,web3" \ --rpccorsdomain "*"
mine
: マイニングを許可する。このオプションを指定するとマイニングが始まります。nodiscover
: Gethはデフォルトで自動的に(同じネットワークID)のEthereumネットワークのノード(Peer)を探し接続を試みます。プライベート・ネットで未知のノードとの接続を避けるため、このオプションを指定することで自動Peer探索機能を無効にします。maxpeers
: ネットワークに接続するノードの最大数(デフォルト25) 0を指定するとネットワークが無効になります。networkid
: ネットワークID(デフォルト1) 1を指定するとグローバルのネットワークに接続されます。- 2,3,4も予約されているようです。(2=Morden (disused), 3=Ropsten)
rpc
: HTTP-RPC serverとして動作を許可するrpcport
: HTTP-RPCで使用するポート番号rpcaddr
: 接続ホストrpcapi
: HTTP-RPCのインタフェースの種類rpccorsdomain
クロスオリジンを許可するリスト
後述するEthereum wallet
でJSON-RPC経由で接続するためにRPCの許可をしています。
送信先のテストアカウントを作成
作成したトークンを送信するためのテストアカウントをコンソール上で作成しておきます。
> personal.newAccount('<任意のパスフレーズ>') "0xe41253c3218ade0650469b87dcb97a3298d3b5d8"
- コンソールからアカウントを作成します。
Ethereum walletのインストール
- Ethereum walletとはEthereumの公式のツールです。Ethereum Walletを使うとウォレットの管理をGUIベースで行うことができます。
- その他にもEthereum walletでは、コントラクトの作成や独自トークンの管理など便利な機能があります。
- 今回はこのEthereum walletを使って独自のトークンを作成&デプロイします。
### インストール
- ダウンロードページから自分にあった環境のツールをダウンロードします。
Ethereum walletの起動(Mac環境)
% /Applications/Ethereum\ Wallet.app/Contents/MacOS/Ethereum\ Wallet --rpc http://localhost:8545
- MacアプリのEthereum walletから先程起動したプライベートノードへ接続します
- 僕は、Geth環境をDocker上に作成しているため、あらかじめDockerで
8545
ポートをフォワーディングしています。
- 僕は、Geth環境をDocker上に作成しているため、あらかじめDockerで
- rpcのセキュリティ警告がでますがOKを押下して進みます。
- (RPCは接続制御ができないため、テスト環境以外では使わない方がいいと思います。)
LAUNCH APPLICATION
を押下します
- ネットワークの接続に成功するとwallet画面が表示されます
- 先程作成したアカウント(coinbaseと送信用)が2つ表示されていれば正しく接続されています。
カスタムトークンをデプロイする
- Ethereum wallet上からカスタムのトークンを作成してみます。
- アプリ上メニューの
CONTRACTS
>DEPLOY NEW CONTRACT
を押下
Deploy contract画面を少しスクロールして
SOLIDITY CONTRACT SOURCE CODE
の部分にサンプルソースをそのまま添付しますしばらくするとコンパイルが完了するので、画面右の
SELECT CONTRACT TO DEPLOY
からMy Token
を選択します
- 作成するトークンの情報を入力します
Initial supply
: 初期のトークン総量。今回は10000トークン発行します。Token name
: トークンの名前です。今回はMyToken
という名前のトークンを発行します。Decimal units
: トークンの小数点以下の桁数を入力します。(下2桁であれば2
と入力する)。今回は2
にします。- Initial supplyが10000でDecimal unitsが2の場合、
100.00
になります。下2桁までいれて合計10000トークンということです。
- Initial supplyが10000でDecimal unitsが2の場合、
Token symbol
: トークンの単位です。今回はmt
としました。(1トークン=1mt)
この辺、ちゃんと理解できていないのですが、SELECT FEEは1トランザクションを処理する時の手数料で、 大きな値を設定するほど、トランザクション処理の時間が短くなるということっぽいです。 今回は、そのまま指定の値で作成します。
全て入力を終えたらDeploy
ボタンを押下します。
- 作成するContractの情報が表示されるので、作成アカウントのパスワードを入力して
SEND TRANSACTION
を押下します。
- wallet画面にもどるので、トランザクションの承認が終わるまで待ちます。
- 承認が終わったら、Contractを作成したアカウントを押下してアカウントの詳細画面へ遷移すると自分が作成したトークン情報が確認できます。
トークンを送信してみる。
- アカウント画面のMyTokenの右にある
Send
ボタンを押下してみます。
- パスワードを入力してトランザクションを送信します。
- 送信相手のアカウント情報を見てみると
30mt
が送られていることが確認できます。