ERC-20トークンコントラクトはどのように動いているのか
Ethereumの現在の主流のトークンコントラクトであるERC20について、特徴と機能、仕組みを見ていきます。
Ethereum Wikiと以下のポストをまとめました。
ERC20 Token Standard - The Ethereum Wiki
Understanding ERC-20 token contracts – Jim McDonald – Medium
What is ERC-20 and What Does it Mean for Ethereum? | Investopedia
トークンコントラクトとは何か、開発者はどう扱うのか、などに役立てばと思います。
コントラクトの基礎については、こちらのアカウントのところを読んでいただければと思います。
ERC20は、Ethereumのトークンコントラクト用に、共通機能を持つインターフェースとして作られました。今ほとんどの流通しているトークンはERC20です。
このERC-20は、ウォレットで異なるトークンでも残高を一覧で確認できたり、取引所がトークンコントラクトのアドレスだけでトークンを上場させることができるなど、多くの構造的な利点があります。
目次
トークンコントラクトとは何か
まずそもそもトークンコントラクトとは、スマートコントラクトの一種で、「アカウントのアドレスとそれらの残高の対応表」を持ったスマートコントラクトです。
この残高は、コントラクトの作成者が定義した値で、リアルな所有物を表す場合もあれば、金銭的な価値や、ホルダーの評判を示す値の場合もあります。これらの残高の単位をトークンと呼びます。つまり残高が1であれば1トークン所有している、と同義になります。
あるアカウントから違うアカウントへトークンが送られるとき、トークンコントラクトは、それら2つのアカウントの残高を更新します。例えば、画像でいうと0x2299…のアドレスから0x1f59…のアドレスへ10トークン送ったとします。するとトークンコントラクトによって、残高は以下のように更新されます。
トークンの合計の流通量は多くする、もしくは少なくするという操作ができます。(トークンコントラクトでそれらの操作を許可するか定義できます。)
まず合計の流通量を多くするには、新しいトークンを発行し(鋳造し)多くすることができます。例えば、「100トークンをアカウント0x4ba5…に鋳造した」とすると、以下のように残高が更新されます。
また合計の流通量は「バーン」(燃やす)ことによって少なくすることができます。例えば、「アカウント0x4919…の50トークンをバーンした」とすると、以下のように残高が更新されます。
バーン以外の方法は、秘密鍵がわからないアドレス(いわゆるThe 0 address)にトークンを送ることです。このやり方は、トークンが使えなくなるという点ではバーンと同じ意味になりますが、存在するトークンの合計量は変化しません。例えば0x93f1…というアドレスで50トークンを 0アドレスに送り、トークンを潰すと、残高は以下のように更新されます。(合計のトークン量は変わっていないことがわかります。しかし実際の流通量は少なくなります。)
単純なトークンコントラクトは、上のようなアドレスと残高の対応表の情報を持ちます。「分割」などの複雑な機能を持つトークンコントラクトは、より便利になります。
ERC-20 トークンコントラクトのパラメータ
ERC-20 トークンコントラクトは、「コントラクトのアドレス」「トークンの合計流通量」によって定義されますが、他にもオプショナルな機能が多くあり、ユーザは細かな設定ができます。トークンの名前、トークンのシンボル、小数以下の桁数などです。これらは後ほど説明します。
ちなみに、トークンコントラクトには中央集権型の登録所はないので、名前やシンボルがかぶったりする可能性があることに注意です。
トークンコントラクトの name の部分は、トークンコントラクトの名前(正式名称的な部分)で、例えば “My token”などです。
長さに制限はありませんが、ウォレットアプリなどで切り捨てられる可能性もあるので、短くするのが良いでしょう。
次に symbol の部分は、シンボルを示し、上のトークンであれば頭文字をとって、”MYT” などがよいでしょう。株で言うティッカーシンボルのようなもので、こちらも長さに制限はありませんが、3,4文字のトークンが普通です。
decimals の部分は、わりと混乱しやすい部分ですが、そこまで難しくはありません。どの程度トークンを分割できるようにするか?という設定をする部分です。(小数点以下が、0~18個になるような設定ができます。18以上も設定ができます。)
このdecimalsがある理由は、Ethereumは小数を扱わず、すべて整数で処理されるためです。
では分割が使われないケース、使われるケースを見てみます。
まず分割が必要ないケースです。例えば、ライセンストークンがあったとしましょう。
トークンコントラクトはソフトウェア・ライセンスの割当を示します。
ライセンストークンを持っているユーザは、そのソフトにアクセスができます。ここでは、ライセンスが0.7個などと小数のライセンスを持っていても意味がありませんね。1.6個なども同様です。
なので、コントラクトの作成者は、「小数以下の桁数を表す」decimals を 0 に設定します。
数名がライセンストークンを持っている状況を想定すると、以下のような残高になるでしょう。
上では100個のライセンスがあるのがわかります。誰かがライセンスを買ったら、そのアカウントにライセンストークンが送られ(残高が変更され)るイメージです。そしてこの残高表を見れば、ライセンスを持っているアカウントかどうか見て確認することができます。
次に分割が必要なケースを考えてみます。例えばゴールドトークンというのがあったとして、物理的な金の所有権を意味するトークンだとします。
トークンの作成者は、金1kg=1トークンとしたいとします。しかし1kg未満のグラム単位でトークンをやり取りしてもらいたいと考えた場合、Ethereumは整数しかサポートしないため、このままではできません。そこで decimalsを3に設定します。(こうするとトークン数*10の3乗となります)
そして何人かがトークンを持っていると想定したとき、対応表は以下のようになります。
しかし、実際には、decimals が 3 に設定されているため、以下のように単位kgとして見ることができます。
decimals は、人に合わせるための部分と言われて、人にどんなふうに残高を見せるかを設定する部分といえます。なのでゴールドトークンはコントラクト内部の計算では decimals を使うことはなく、Kgの単位で計算がされます。
この分割によって、細かいトークンまで扱うことができて、多くのトークンは decimals を 18 に設定しています。
まとめ
・1トークンが現実世界の何か1つを表すとき、 decimals を 0 に
・小数以下の桁が決まってるとき、decimals をその桁数に
・どちらでもないとき、細かくトークンを使えるように decimalsを18に
totalsupply はERC20トークンコントラクトを定義する最後の部分で、必須のパラメータです。ERC20の仕様には明確にかかれていませんが、totalsupplyはシンプルで、totalsupplyは残高の合計とイコールとなります。
ERC-20トークンコントラクトの関数
ERC20トークンコントラクトには、残高をみたり、設定した条件になったら送金をしたりと色々な関数があります。例えば以下のような感じです。
balance0f( )関数は、与えられたアドレスの持つトークンを返します。
トークンを送る方法は2つあり、1つは transfer( )関数です。メッセージ送信者から他のアドレスに直接トークンを送ります。
transfer( )関数は、外部アカウントに送る分にはよいですが、スマートコントラクト内の関数にトークンを送るときには機能しません。
これはスマコンが走っているとき、資金を送金する元のアクセスの詳細にアクセスはせず、コントラクトをコールしているユーザがコントラクトを走らせるための資金を払っているためです。
Doer というコントラクトがあるとしましょう。 Doerは、doSomething( )という10 Do トークンで動くような関数を持つとします。AくんがdoSomething( )をコールしたくて 50 Doトークンを持っているとします。
では実際にどのようにdoSomething( ) を動かすためにDoerにトークンを送れば良いのでしょうか。
ここで、approve( )とtransferForm( )の2つの関数が必要になってきます。
まずはじめのステップは、トークンホルダーが自分用にもう1つのアドレスをつくり(通常はスマートコントラクトで行います)、一定数のトークンを格納します。ここで新しいアドレスに送られたトークンは、allowance(割当)と呼ばれます。トークンホルダーは approve( )を使うことでこの情報を得ることができます。
上の写真で2行目の「0x1f59…」がAくんのアドレスだとすると、 0xd8f0…のアドレスにあるコントラクト Doer に、Aくんアカウントから25トークン送ってもいいよと許可している状態になります。
一度allowanceが作られると、スマートコントラクトが割当数のトークンを、ユーザの割当(図でいうAllowance)から使います。(これはコントラクトの動作の一部として使われます。)
この結果、Aくんは doSomething()関数をコールすることができ、この関数は、transferFrom()という関数を使い、10 DoトークンをAくんのアカウントから使うことで、動作を実行します。もしAくんが10 Doトークンを持っていない場合(つまりAllowanceが10未満のとき)は、doSomething()関数は動きません。
allowance()関数は、送信できる割当トークンの数を返します。ここで重要なのは、割当は、残高以上になることがある、ということです。図のように0x2299…のアカウントは500トークンを送れることになっていますが、さらに上のほうの図にあるように、90トークンしか持っていません。
allowance()関数を使うコントラクトは、トークン数を計算する際にホルダーの残高も考慮する必要があります。
ERC20トークンコントラクトのプログラム実行(Event)
ERC-20ではコントラクトが定められた入力がされたときに実行するプログラム(イベント)が2つ定義されています。1つ目のイベントは Transfer( )で、これはどのアカウントからどのアカウントへ送られたというトークンの動きの情報を出力します。2つ目のイベントはApproval( )で、トークンの承認の情報を出力します。これらは残高をトラッキングする、もしくは割当の変化をトラッキングするのに使われます。
新しく作られたトークンは The 0 addressとともにTransfer( )イベントを出力します。
トークンがバーンされる際は、出力されるイベントはないので、バーンをしたい場合、トークンをthe 0 addressに送り、実質バーンすることが多いです。(発生イベントがなく処理が楽なため、こちらを選ぶことが一般的ということです。)
最後に
ERC-20は、トークンコントラクトの土台となっていますが、欠点がないわけではありません。そこでERC-223の提案は、安全対策や追加機能をいれていますが、ERC20との互換性はありません。今あるトークンコントラクトはERC20を引き続きサポートしながら、ERC223提案も同時におっていく必要があります。
BitcoinとLitecoin、ライトニングチャネルのAtomic Swapに成功
Lightning Labsの開発チームは、テストネットのビットコインとライトコインをライトニングチャネルで交換することに成功しました。(このような異なるチェーンでの通貨のやり取りはアトミックスワップと呼ばれます。)
トランザクションはブロックチェーン上に刻まれず、コインの所有者を変えることに成功したことになります。
ライトコインの創始者のチャーリー・リーはBitcoin Magazineに対し以下のように答えています。
「以前実施したアトミックスワップは、オンチェーンであり、ブロックチェーンによる遅延や高い手数料などの制約がありました。」
「オフチェーンのアトミックスワップは、オンチェーンのアトミックスワップよりも簡単で、手数料も低く、プライバシー的にも優れています。」
ライトニングネットワークは、ビットコイン上の「セカンドレイヤーの支払い」ネットワークとして期待されていて、またライトコインなどの「ビットコインからフォークした他の暗号通貨」へのデプロイは比較的カンタンです。
もしライトニングネットワークが異なるチェーン上で実装されると、これらのチェーンは相互にリンクし合うので、ネットワーク上に「あるコインから別のコインに転送してくれる」ようなノードが1つでもあれば、「ビットコインを送り、それと同価値のライトコインを相手側が受け取る」というようなことが可能です。
リーはこのブログポストで、この可能性を感じ、自分の地位を投げ打ってでもSegwitのソフトフォークを支援するようになった、と説明しています。
テストについて
テストはローカルマシンで実施され、そのマシン内に2つのノード(名前はAliceとBob)が建てられました。BitcoinとLitecoin両方のチェーンを監視できるように設定され、固定レートで「テストネットのLitecoinをAliceからBobに送り、テストネットのBitcoinをBobからAliceに送る」ようなライトニングチャネルを作りました。テストの環境下ですが成功し、Lightning Labsは今日ブログとビデオを公開し詳細を説明しています。
ノードが今日の取引所のようになり、通貨交換の役割を果たすようになる可能性もあり良いレートを競争しあうようになります。またそのような交換ノードが、支払いのプロセッサとして機能する可能性もあります。
つまりビットコインしか受け付けない店やサイトで、ライトコインが簡単に使えるなどです。またAからBにビットコインを送るのに、途中ライトコインを経由し、安く早くビットコイン送信が可能になります。
これからも開発が楽しみです。
参考:
https://bitcoinmagazine.com/articles/lightning-network-now-supports-transactions-across-blockchains/
https://blog.lightning.engineering/announcement/2017/11/16/ln-swap.html
Parityライブラリ自己破壊、何が起きたか、どう防げたか
Parityのバグについて昨日、凍結された資金を持つPolkadotの見解を書きました。
そして今日、Parity側の見解がでました。
以下になります。
ーーー
11月6日 02:33:47 (UTC)にParityマルチシグウォレットの「ライブラリ」スマートコントラクトコードに脆弱性が匿名ユーザによって発見されました。
このユーザは脆弱性を利用し、自らをライブラリコントラクトのオーナーとなったのちち、このコンポーネントを破棄しました。Parityのマルチシグウォレットはこのコンポーネントに依存しているため、合計513,774.16 Ether(およそ190億円)および他のトークンを保持する587個のウォレットがブロックされました。ライブラリコンポーネントを破棄した後、ユーザ名「devops199」と名乗るアカウントはgithubにこの内容をあげました。https://github.com/paritytech/parity/issues/6995
パリティウォレット(UI)の他のすべての機能には、同様の脆弱性はありません。(
スタンダードのアカウント、非マルチシグアカウントにもありません)
影響を受けたユーザには連絡しており、まだ届いていない場合はcommunity@parity.ioまでご連絡ください。この問題が、プロジェクト・資金の将来に対して不安を抱かせてることを認識していて、実行可能な策を模索する努力をしています。
悪用が行われて以来、チーム全体で多くの議論や分析を行ってきました。この記事では、問題に関連する要因を明らかにし、質問や苦情への対応を書いていきます。
ウォレットのライブラリは監査されていなかったのか?
オリジナルの "Foundation" マルチシグウォレットコードは、Ethereum Foundationの開発チーム(パリティ・テクノロジーズ)とコミュニティのメンバーによって創られ、監査されました。そして多くレビューを受けました。
このコードには今回対象となったセキュリティ問題はありません。そして、パリティチームによって、ウォレットが作成されるたびにネットワークに展開される軽量のstubスマートコントラクトに再編されました。ちなみにこれには、一度だけ展開されたライブラリスマートコントラクトなどウォレットのロジックの大部分を含みます。
正式な監査はありませんでしたが、7月19日のバグと資金の回収もあり、このコントラクトは社内外に多くのレビューを受けていました。
事件の前に何が起きたか?
監査された元のスマートコントラクトの状態に近づけるため、できるだけ変更を加えないようにしていました。しかしこれは、ライブラリコントラクトが通常のウォレットと同じ機能を持ち初期化が必要であることを意味し、よってウォレットを消去するために設計された元のself-destruct機能(自己破壊機能)もまだ含まれたままでした。
2017年7月19日の攻撃の後、2017年7月20日にライブラリコントラクトを修正し、再度デプロイしました。
8月に、Github上のcontributorである、アカウント名 "3esmit”は、デプロイのときにinitWalletが呼び出されるべきようにコード変更をすべきと勧めました。
したがって、私たちはこの提案された拡張をライブラリコントラクトに実施し、
構築時にinitWalletを呼び出すことによって自動的に初期化するようにしました。
この推奨を拡張だと解釈し、変更されたコードは定期的なアップデートのときに展開されることになりました。
11月6日03:25:21 PM + UTCに、 'devops199'は7月に導入されたコントラクト内にあった未初期化オーナーを見つけ、それを初期化し、自分をオーナーとして設定しました。その後、devops199はライブラリコントラクトを消し去りました。
どのようにすれば防げたのか?
この悪用を避けることができた2つの方法があります。
たとえ誰かが所有権を持っていたとしても、もしコントラクトコードに自らを消す機能(suicideやkill)が含まれていなければ、何もすることができなかったでしょう。 kill機能は、元の監査済みコントラクトの残りの部分でした。もう1つの方法は、3esmitによって提案されたことを、コード変更と再デプロイによって自動的に、または7月に導入されたコントラクトに手動で、すぐに実施されていたら、防げていたでしょう。
パリティ・テクノロジーズは、当社が作成するスマートコントラクトについて正式な監査を、外部に定期的に依頼しています。たとえば、当社のKYCサービス「PICOPS」および当社が支援するICOの販売契約には、厳しい監査要件があります。
しかし、より多くの監査を行うだけでなく、セキュリティを実現するためには、デプロイ、監視、およびテストのための、より後半で正式な手順とツールが必要であると考えています。エコシステム全体としては、特にコントラクトの数や複雑さが増した場合に、同様の問題が再発するのを防ぐために、上のような手続きやツールがすぐにでも必要であると考えます。
パリティ・テクノロジーズは、凍結された資金を開放するために何をしているか?
深刻に状況を後悔しており、既存のEIP、また新しいEIPの提案に懸命に取り組んでいます。これらの改善提案は今後、ブロックされた資金の救済措置として一般的なケースに対応できるでしょう。
そのような改善案がいつ実行されるかについてのタイムラインはありません。私たちはコミュニティの意向に従い、他のプロトコル改善のような定期的なEIPプロセスを進めます。パリティ・テクノロジーズは、提案に関する開発を多く実施し、Ethereum Foundationチームおよび更なるプロトコル層開発のためのコミュニティと建設的に協力します。
他に実施する予定の事項は?
・最初のステップとして、適切なセキュリティと操作手順が確立されていると感じるまで、マルチシグマウォレットを展開する機能を削除して、これが再び起こらないようにします。
パリティウォレットUIは、安全であるとみなされるグノーシス、WHG、またはその他の複数のシグネチャウォレットを引き続きサポートします。
Parity Walletを使用して、事前に展開されたマルチシグウォレットを見たり、使用したりすることができます。
他のコントラクトと同様に、マルチシグコントラクトを手動で導入することも可能ですが、マルチシグ固有の統合された方法はありません。
・ウォレットではなく、ウォレットがおいてあるクロームの中間インフラストラクチャーに、注力していきます。この意味で、ウォレットはパリティを拡張できる「ユーザーレベル」のソフトウェアになります。
・我々は、秘密管理、鍵生成とパスワード管理、署名と自動更新を含む、既存のすべての機密コードの、フルスタック外部セキュリティ監査を委託しています。
・私たちは内部的にプロセスと手順を見直すことに多大な努力とリソースを投入し、具体的には業務セキュリティに専念するチームを作っていきます。
このチームは必要に応じて拡張され、リソースを自由に使います。チームは、パリティ・テクノロジーズの提供する重要な部分のレビューとメンテナンスを担当します。
必要なコントラクトのデプロイが、このリポジトリ内のコード変更とレビュープロセスに適切にリンクされていることを確認し、そのためのツールを作成するための取り組みをサポートします。
例えば:
・航空宇宙や医療などのように、各コントラクトごとに、デプロイのチェックリストをつくる
・デプロイされたコントラクトについては、リポジトリ内の最新のレビュー済みバージョンと比較して正しいか常に監視する
などです。
・私たちは、社内で努力するだけでなく、次のような外部のヘルプやリソースを探していきます。
・正式な検証や証明支援など、他のスマートコントラクト言語やツールの研究開発サポート
・ツール、言語研究、およびテストに焦点を当てたリサーチチームとの開発関係。
次世代の資産管理のセットを創るチームの作成。
セキュアなストレージとリカバリのためのツールを提供するマルチシグネチャ、タイムロック、デッドマンスイッチ用のボールトセーフなコントラクト。
・バグバウンティプログラムを拡張。(すべてのソフトウェアをオープンソースのソフトウェアとして提供しています)
パリティ・テクノロジーズは、エテリアムの技術開発の先駆者であり続けるよう努力し、コミュニティにとって安全で便利な技術を開発するために尽力します。
ーーー
まだあまりタイムラインなども不明確なようですね。
ただこれらの改善が、今後のEthereumおよびクリプト界隈の新たな技術を生み出してくれると良いです。
原文:
A Postmortem on the Parity Multi-Sig Library Self-Destruct – Parity Technologies