Ethereum入門 〜Mistを使って独自トークンの発行〜


はじめに

前回browser-solidityを使って独自トークンを発行しました。
Ethereum入門 〜独自トークンの発行〜
今回はEthereumの公式ウォレットのMistを使って送金、独自トークン発行までしたいと思います。

Mistインストール・起動

Mistのダンロードはこちらから
https://github.com/ethereum/mist/releases

OSに対応したMistをインストール

起動まではこちらに丁寧な解説あります。
Ethereum <超初心者の方向け>Mistを用いたコントラクト開発入門

この画面になったらLAUNCH APPLICATION を押して起動

送金

アカウント作成

まずはアカウントを2つ作成します。
1つ目に作ったアカウントがEtherbaseとなりマイニングすると報酬がもらえるアカウントになります。

マイニング開始

Develop→マイニングを始める

1つ目に作ったアカウントにEthがどんどん溜まっていきます。

送金

アカウント1からアカウント2へ100Eth送金します。

Toと量を入力して「送る」ボタンを押します。

無事にアカウント2に100Eth送金されました。

トランザクションの確認をすると
ガス、ブロックを確認することが出来ます。

マイニング終了

マイニング終了するためにはコンソールからコマンドを叩きます。
Develop → 開発者用ツールをトグルする → MistUI

以下のコマンドを入力してマイニングを停止します。

web3.miner.stop()

トークンの発行

コントラクト作成

コードはこちら
https://ethereum.org/token

pragma solidity ^0.4.16;

interface tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public; }

contract TokenERC20 {
    // Public variables of the token
    string public name;
    string public symbol;
    uint8 public decimals = 18;
    // 18 decimals is the strongly suggested default, avoid changing it
    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);

    /**
     * Constrctor function
     *
     * Initializes contract with initial supply tokens to the creator of the contract
     */
    function TokenERC20(
        uint256 initialSupply,
        string tokenName,
        string tokenSymbol
    ) public {
        totalSupply = initialSupply * 10 ** uint256(decimals);  // Update total supply with the decimal amount
        balanceOf[msg.sender] = totalSupply;                // Give the creator all initial tokens
        name = tokenName;                                   // Set the name for display purposes
        symbol = tokenSymbol;                               // Set the symbol for display purposes
    }

    /**
     * Internal transfer, only can be called by this contract
     */
    function _transfer(address _from, address _to, uint _value) internal {
        // Prevent transfer to 0x0 address. Use burn() instead
        require(_to != 0x0);
        // Check if the sender has enough
        require(balanceOf[_from] >= _value);
        // Check for overflows
        require(balanceOf[_to] + _value > balanceOf[_to]);
        // Save this for an assertion in the future
        uint previousBalances = balanceOf[_from] + balanceOf[_to];
        // Subtract from the sender
        balanceOf[_from] -= _value;
        // Add the same to the recipient
        balanceOf[_to] += _value;
        Transfer(_from, _to, _value);
        // Asserts are used to use static analysis to find bugs in your code. They should never fail
        assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
    }

    /**
     * Transfer tokens
     *
     * Send `_value` tokens to `_to` from your account
     *
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transfer(address _to, uint256 _value) public {
        _transfer(msg.sender, _to, _value);
    }

    /**
     * Transfer tokens from other address
     *
     * Send `_value` tokens to `_to` on behalf of `_from`
     *
     * @param _from The address of the sender
     * @param _to The address of the recipient
     * @param _value the amount to send
     */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
        require(_value <= allowance[_from][msg.sender]);     // Check allowance
        allowance[_from][msg.sender] -= _value;
        _transfer(_from, _to, _value);
        return true;
    }

    /**
     * Set allowance for other address
     *
     * Allows `_spender` to spend no more than `_value` tokens on your behalf
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     */
    function approve(address _spender, uint256 _value) public
        returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        return true;
    }

    /**
     * Set allowance for other address and notify
     *
     * Allows `_spender` to spend no more than `_value` tokens on your behalf, and then ping the contract about it
     *
     * @param _spender The address authorized to spend
     * @param _value the max amount they can spend
     * @param _extraData some extra information to send to the approved contract
     */
    function approveAndCall(address _spender, uint256 _value, bytes _extraData)
        public
        returns (bool success) {
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            spender.receiveApproval(msg.sender, _value, this, _extraData);
            return true;
        }
    }

    /**
     * Destroy tokens
     *
     * Remove `_value` tokens from the system irreversibly
     *
     * @param _value the amount of money to burn
     */
    function burn(uint256 _value) public returns (bool success) {
        require(balanceOf[msg.sender] >= _value);   // Check if the sender has enough
        balanceOf[msg.sender] -= _value;            // Subtract from the sender
        totalSupply -= _value;                      // Updates totalSupply
        Burn(msg.sender, _value);
        return true;
    }

    /**
     * Destroy tokens from other account
     *
     * Remove `_value` tokens from the system irreversibly on behalf of `_from`.
     *
     * @param _from the address of the sender
     * @param _value the amount of money to burn
     */
    function burnFrom(address _from, uint256 _value) public returns (bool success) {
        require(balanceOf[_from] >= _value);                // Check if the targeted balance is enough
        require(_value <= allowance[_from][msg.sender]);    // Check allowance
        balanceOf[_from] -= _value;                         // Subtract from the targeted balance
        allowance[_from][msg.sender] -= _value;             // Subtract from the sender's allowance
        totalSupply -= _value;                              // Update totalSupply
        Burn(_from, _value);
        return true;
    }
}

コントラクト実行

「Token ERC20」のコントラクト選択し、トークンの名前、トークンシンボルを入力します。今回はOreOreCoinを10000 発行します。

「配置」ボタンを押し、アカウントのパスワードを入力し、コントラクトを実行します。

トランザクションを確認しコントラクトが実行出来ていればOK。
(実行出来ていない場合は、マイニングが実行されているか確認してみてください。)

無事OreOreCoinが10000 OCアカウント2に発行されました。

トークンの送金

アカウント2からアカウント3へトークンを送金してみます。
まずコントラクト内のselect functionでtransferを選択。
toにアカウント3のアドレスを入力し、valuに送る数量を入力します。
単位がweiなので注意!
1000送金したい場合は1000e18と入力します。

実行を押し、アカウントのパスワードを入力してSEND TRANSACTIO!

アカウント2から3へ1000 OC送金出来ました。

トークンのバーン

バーンも同様の手順で
コントラクト内のselect functionでburnを選択。valuを入力し実行。

ちなみにバーンはコントラクトのアドレスに送金することで誰も取り出せなくなるようにしてます。

おわりに

Mistはシンプルで直感的で分かりやすいですね。
gethのインストール等々が不要なのでエンジニア以外も触れやすそうです。

参考にさせて頂きました。

Create your own CRYPTO-CURRENCY with Ethereum
Ethereum <超初心者の方向け>Mistを用いたコントラクト開発入門
EthereumでERC-20トークンを発行してみる