【第7回】Ethereumの全体像を理解する - 独自トークンとは

こんにちは、えたろうです。


少しだけ易しいMastering Bitcoin」を一通り読んだ方は、Bitcoinの仕組みはだいたい理解できたかと思います。

Bitcoinでブロックチェーンの基本を理解した後、次のステップはやはりEthereumの理解ですよね。


  • 「Bitcoinの仕組みはだいたい分かった!ブロックチェーンすげぇ!」という方
  • 「Ethereumでスマートコントラクトが実現する云々」「Ethereum上で Dappsを作る云々」というのはよく聞くけど、実際Ethereumってどう動いてるの?という方


を対象にして懇切丁寧に書いて行きます。


第7回では「Ethereum上でトークンを発行する仕組みと、よく聞くERC〇〇とは何かを理解する。その上で実際のDapps開発のイメージを掴む」ところまでを目標にします。


Ethereum上でトークンを発行するとは



Ethereum上でトークンを発行するとは「アドレスとその残高記録・管理するプログラムをコントラクトアカウントとしてEthereum上に作成すること」を指します。

上図のように、トークン保有者のAddressとそのトークン残高(Balance)を 連想配列 (key => valueを対応させて保存できるデータ型)に保存したものをトークンの台帳とします。

誰がいくら持っているかが記録されているDataBaseみたいなものですね。


このトークンの台帳は、コントラクトアカウントのStorage rootに保存されます。(正確にはマークルパトリシアツリーで要約されて保存されます)

また、CodeHashにこの連想配列のデータを参照・編集するためのプログラムが書かれています。

このようなトークンを管理するコントラクトアカウントのことを「トークンコントラクト」と言います。

このトークンコントラクトを作成することで「Etherum上でトークンを発行する」のです。

このように存在しているトークンコントラクトに対して、ユーザーである外部アカウントがMessage callトランザクションを発行し、コントラクトのプログラム( 送金する関数や、自分の残高を参照する関数などのトークンに関する処理を行う関数が存在すると考えてください)を実行することで、トークンコントラクトのStorage rootにある連想配列が書き換わり、それがイーサリアムブロックチェーンの中の一つのアカウントステートとして記録されるのです。

こうして「トークンが誰から誰にいくら送られた」などの状態遷移を実現しています。



Etherum上でトークンを発行するということの大体のイメージは掴めたでしょうか?

この記事の後半で、実際にどのような関数が動作しているのかまで詳しく見ていきます。


トークンの規格とは



これまで見てきて分かる通り、Ethereum上のトークンは誰でも独自のものをいくらでも作ることができます。

すなわち、Etherum上にトークンはめちゃめちゃ沢山作られ得るもので、現実に星の数ほどのトークンがEthereum上に存在します。


ここでウォレットについて考えてみましょう。


Ethereumを管理するのに使用するwalletで有名なMy ether walletでは、BitcoinやLiskなどの他の通貨を管理することはできません。

これは、それぞれの通貨の残高参照の仕方、送金の仕方が全く異なるからです。


例えば、残高参照一つとっても、BitcoinはフルブロックチェーンデータからUTXOを掻き集めて来る事で残高を確認しますが、EthereumはEOAアカウントのBalanceを返すeth. getBalance関数を叩くなど仕様が違いますね。


様々な通貨のそれぞれ異なる処理様式を、個別に実装して、複数の通貨に対応しているウォレットも数多くありますが、通貨ごとに個別に残高照会機能や送金機能を実装していては、通貨の数を増やすには限界がありますよね。


このように全く違う処理で動く通貨が無数に作られ始めると、それらを全て一元管理するウォレットを作るのがクソ面倒になります。(一元管理できないとユーザーは面倒すぎて誰も色んな通貨を使おうとは思わないでしょう)


それを解決するために「Ethereum上で発行するトークンは全てこのような処理様式にしよう!」というトークン規格が定められています。


以下に具体例で説明していきます。


まず、トークンの規格が定められていない場合は、

上の図のように、ウォレットは新しいトークンに対応するたびに新しい処理を実装しなくてはなりません。


一方で、「残高照会する関数はこの名前の関数!」「送金する関数はこの名前!」などの規格が定められていれば、

このように、1パターンの処理を実装するだけで良いので、初めから「その規格に従ったトークンならどんなトークンにでも対応可能なウォレット」を作ることができるようになるのです。


その他にも取引所など、規格を定めておくことで色々なことが簡略化できるため、トークン規格が定められています。



トークン規格 ERC20



最もpopularなEthereumトークン規格が ERC20という規格です。

現在のWebであらゆる通信の規格を定めたRequest For Comment :RFCというものがありますが、ERCというのは Ethereal Request For Commentの略称です。つまり、Ethereum上の様々な通信・処理における規格を定めたものですね。


もともとEIP (Ethereum Improvement Proposal)というイーサリアム改善提案の20個目,

EIP20で提案された規格であるので、ERC20として規定されています。


ERC20という規格では以下の表のような関数とEventを持つことが決められています

Eventとは関数の実行に付随させることができるもので、トランザクションの実行によって生成されるReceiptのlog部分に、指定したlogを残させるように記述する関数修飾子です。

※詳細はhttps://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.mdで見れます。



上記の表にあるようにERC20規格は、トークンの基本情報を確認する関数などを一通り持っています。

中でもERC20の特徴なのが、トークンを送信する方法が2つ存在する点です。


まず一つ目が 「transfer()関数による送信」です。
これはトークンコントラクトに対するMessage Callトランザクションによってこのtransfer()関数を実行したアカウントから、指定したアドレスのアカウントに直接送金する方法です。
トークンの保持者が自分で誰かにトークンを送信する処理ですね。

しかし、この方法では外部アカウントへトークン送信をする場合は問題ないのですが、コントラクトを動作させるのにトークンが必要な場合などにコントラクトアカウントに対してはこの方法で送信するとトークンが消失してしまいます。

これは、プログラムを実行しようとするアカウントからMessage Callトランザクションを受け取って自身のプログラムを実行するコントラクトアカウントはそのプログラム内で「トークンがこれまでに実行者から支払われたか」をわざわざ確認することは出来ない設計になっているからです。


そこで、このような場合のトークン送信に使われるのが、二つ目の送信方法である「approve()関数とtransferFrom()関数による送信」です。


ERC20を用いているDappsを例にすると、これらの関数は以下のように使われます。

多くのERC20トークンはDapps内で使用できるアプリ内ポイントのような役割を担います。


アプリ内ポイントを使ってアプリ内で使用する場合を考えます。

LINEツムツムでいうと、星を1個消費して一回プレイできるみたいなイメージです。

Dappsにおいてこの時の処理は図にあるように以下の手順で行われます。

サービスを提供するプログラムを「Service Contract (SC)」とします。


① まずユーザーがトークンコントラクトに対してMessage Callトランザクションを送り、「Service Contractが自身の残高を一定使用できるようにするapprove()関数」を実行します。(これによってService Contractに指定した額のallowance が付与された事になります)


② その後ユーザーは、Service Contract に対してMessage Callトランザクションを送り、そのプログラムを実行させてサービスを利用しようとします。


③ ②の命令を受け取ったService  Contractはトークンコントラクトに対して 「ユーザーの残高から自身の残高に一定トークンを送るtransferFrom()関数」を実行し、それが正常に実行されてからプログラムを実行します。

(ユーザーは自分の残高よりも多い額をallowance に設定することが出来るため、実行が失敗することもあります)


④ユーザーはサービスを利用できました。


このようにDapps内の様々な処理に伴ってこのトークンコントラクトにある関数が実行され、トークンがアプリ内ポイントのように振舞うようになっています。


トークン開発手順



実際にEthereum上にトークンを作る手順を見ていきましょう。

ERC20トークンの発行を例に見ていきます。


①開発準備・事前知識


(1)Ethereumクライアント

Ethereum上にトークンを発行・アプリケーションを作成するためには、当然Ethereumネットワークに接続していなくてはならない、つまりEthereumネットワークのノードにならなければなりません。

ノードになるためのソフトウェアがクライアントです。

このクライアントソフトによってノードを立て、そこからEthereumネットワーク上にプログラムをデプロイします。


Bitcoinでは公式のクライアントはBitcoin Core (Satoshiクライアント)のみでしたが、Ethereumでは多種多様な言語で実装されたクライアントが存在します。


ex.) 

geth (go-ethereum) :最もpopularなEthereumクライアント。Go言語で実装されている。 

parity:2番人気のEthereumクライアント。Rust言語で実装されている。



(2)プログラム記述言語

Ethereum上にデプロイするプログラムはEVMで実行可能なEthereum Byte Codeでなければいけませんが、これは人間が扱うには不向きな言語でした。

そのため、人間様に適した文法で記述できる高級言語を使用してプログラムを書き、それをEthereum Byte Codeに変換してからEVMに実行させます。


ex.)

solidity : Ethereum用のプログラムを記述するのに最もpopularなJavaScript に似た文法を持つプログラム言語

viper : Pythonに似た文法を持つプログラム言語



(3)開発支援ライブラリ

プログラムを書くといっても、一から書くには開発者も大変なので、ある程度の雛形を用意してくれる開発支援ライブラリが存在します。


ex.)

truffle(トリュフ) :コマンド一つでディレクトリの雛形を作ってくれたり、コンパイル(コードの変換)やデプロイが可能なライブラリ

OpenZeppelin:ERC20トークンを生成するプログラムコードなどの雛形を提供してくれるライブラリ



(4)メインネットとテストネット

Ethereumのブロックチェーン(メインネット)に一度デプロイしてしまった、つまり一度作成してしまったコントラクトアカウントのプログラムを書き換えることは非常に難しいです。


つまり、開発者からすると、書いたプログラムをすぐに本番Ethereumブロックチェーンにデプロイするのには大きなリスクがあります。

そのため、Ethereumには開発したプログラムをテストする用に以下の3つのテストネットが用意されています。


Ropsten テストネット:PoSをコンセンサスアルゴリズムに動く最もPopularなテスト用Ethereumネットワーク

Kovan テストネット: PoAをコンセンサスアルゴリズムに動くテスト用Ethereumネットワーク

Rinkeby テストネット: PoAをコンセンサスアルゴリズムに動くテスト用Ethereumネットワーク


テストネット内で試験的に使用するEtherは自由に手に入れることができるので、開発者は気軽にアプリケーションの試験運用をすることができます。



Ethereum上のアプリケーション開発に関わるこれら4つをまとめると、開発のイメージは以下のようになります。




②ERC20トークン開発



独自ERC20トークンの発行は以下の手順で行われます。


1. 

truffleのインストールとディレクトリの雛形作成、OpenZeppelinのインストールで開発環境を整えます。



2.

専用プログラム言語(ここではsolidity)でERC20を発行する以下のようなプログラムを書きます。 

ここでは、OpenZeppelinからStandardToken.solというERC20を作成する雛形となるプログラムを継承して、自身のトークンコントラクトを作成するだけです。


この時にトークンの名前(name)とシンボル(symbol)、小数点以下いくつの桁数まで使用するか(decimals)を設定します。

とても小さい単位まで表現する必要があるトークンはdecimalsを高く設定するなど、decimalsはトークンの用途によって決めるべき値になります。

また、トークンの名前やシンボルを中央で管理するシステムなどはないので、他のトークンと被ってしまう事もあり得ます。


コンストラクタ(このトークンコントラクトが作成された時に一番最初に実行される関数と思ってもらえれば)としてDappsToken関数が書かれており、これによって最初にこのトークンの発行上限(totalSupply_)が決定され、発行したトークンを全てこの関数を実行したアカウントのものとするようになっています。



3.  

デプロイの準備として、「truffleを使ってコードをコンパイル」「マイグレーションファイルの作成(正確にはここでトークンの総発行量を指定)」をし、truffleを使ってEthereumのネットワーク(最初はテストネット)にデプロイします。



このような手順で、Ethereumネットワーク上にERC20規格で決められた関数を持った新たなトークンコントラクトが作成されます。


※ここではざっくりどんなイメージかだけを説明したので、実際にやってみたい方は

こちらの解説を参考にしてやってみて下さい。


その他の代表的なトークン規格



Ethereumのトークン規格はEIP(Ethereum Improvement Proposal)でいくつも提案されており、今も様々な新しいトークン規格が提案され、議論されています。


その中でも現在代表的なものは、以下の3つです。


(1) ERC223

ERC20の進化系のようなトークン規格です。


ERC20から進化した点は主に以下の2つです。


ERC20規格では、誤ってEOAアカウントAddressではなく、コントラクトアカウントAddressにトークンを送信してしまった場合に、それを止める手段が存在せず、大量のトークンがこのミスによって無くなってしまっているという現状があります。

これを解決するために、ERC20トークンの規格に、「もしトークンを受け取れないアカウントのAddressに送金処理がされた場合には、その処理を取りやめてトークンを送り主に返す」tokenFallback()関数が追加されています。


上述した通り、ERC20ではapprove()関数で一度ユーザーがサービスコントラクトにトークンの使用を許可してから、サービスコントラクトがtransferFrom()でトークンを自分に送るという2ステップを踏んでいましたが、これが面倒だということで、これら2つの関数 + allowance関数を廃止し、「transfer()関数で送金」というシンプルな構造に変わっています。


この規格の関数とイベントの詳細は

https://github.com/ethereum/EIPs/issues/223

で確認できます。


(2) ERC721

トークンそれぞれに固有の特性を持たせることができる規格です。

この規格でEtaro tokenを発行したとすると「えたろうが持っている10Etaro token」と「かずくんが持っている10Etaro token」は違うものであるということになります。(通貨というよりはモノに近いです)

このERC721のような特性を持つトークンを 代替不可能トークン(Non Fungible Token:NFT)と言います。

ブロックチェーンゲームなどでは、様々なパラメータを持つキャラクターがこのNFTによって固有の値を持ったトークンとして使われています。


具体的には

それぞれのトークンに_tokenIdという固有の識別値が付いており、各トークンがMetaデータを保持することができます。


この特性に対応する

  • 指定した_tokenIdのトークンの所有者のアドレスを返すownerOf()関数
  • 指定したオーナーが所持している_index番目のトークンIDを返却するtokenOfOwnerByIndex()関数
  • 指定した_tokenIdのメタデータを取得するtokenMetadata()関数

などの関数が規格に追加されており、


最も有名なブロックチェーンゲームであるCryptoKittiesでいうと、tokenMetadata()関数で生年月日や体重などの猫のプロフィール情報を取得、ownerOf()関数によって飼い主のアカウント情報を取得できることになります。


この規格の関数とイベントの詳細は

https://github.com/ethereum/eips/issues/721

で確認できます。


(3) ERC1400


証券(Security)トークンのための規格です。

昨今、証券をトークン化するという動きが活発になってきた中で証券トークンを作る際の規格であるERC1400が提案されています。


まず証券には「法的な取引規制に従わなければ証券でない」ため、証券をトークン化するとなると、これまでのトークンのように勝手に誰にでも送れるような設計ではなく、適切に送っても良い相手なのかを判断した上でトークンを送るような設計にする必要があります。


また、証券は、例えば株式で言えば、同じA社の株式でも優先的な条件がついている優先株とそうでない劣後株があるように、「同じ株式でもそれぞれに特性を持たせる」必要があります。(このような証券の特性による区分を金融ではトランシェと言います)

一方で、A社の優先株は一つではなく、「A社の優先株という種類の株がいくつもある」という状況になっています。


この証券をトークン化しようとする時、同じA社の株式(トークン)の中でも優先株、劣後株という個別の特性を持っている「ERC721のようなNon Fungibleな特性」がある一方で、

A社の優先株というトークンで見るとそれ自体は「ERC20のようなFungible (代替可能、つまりえたろうの持ってるトークンとかずくんの持ってるトークンは全く同じものであるトークン)な特性」を持っています。


そのため、これに対応できるような「Partially Fungible Token (部分的に代替可能なトークン)」として設計する必要があります。


これらの条件を満たすように様々な関数・イベントを持たせた規格がERC1400であり、現在活発に議論がされているところです。


この規格の関数・イベントの詳細は

https://github.com/ethereum/EIPs/issues/1411

で確認できます。




第7回では「Ethereum上でトークンを発行する仕組みと、よく聞くERC〇〇とは何かを理解する。その上で実際のDapps開発のイメージを掴む」ところまでを詳しく見ていきました。


Etherumでトークンを発行する仕組みと、そもそもなぜERC〇〇というトークン規格が必要でそれぞれのトークン規格が何かまでを理解できたかと思います。


次回は少し間が空いてしまうかもしれませんが「Dapps作ると何が嬉しいの?Dappsが実現する未来」について詳しく書いていきたいと思います。


0コメント

  • 1000 / 1000