アルゴリズムとかオーダーとか

仕事で勉強したことなどをまとめてます

ERC-20が抱える問題

ERC-20を拡張したToken Standardの提案がいくつか出てきています。これらの提案が新たにされている背景としてはERC-20のToken Standardは2つの問題を抱えているためです。
今回はこの2つの問題について詳しく説明したいと思います。

1. トランザクション処理の欠如

Tokenを消費して何かのサービスを行うContractを考えた場合、このサービスContractはTokenを受け取ったことをトリガーとして動作する必要があります。しかし、ERC-20の提案ではTokenを転送した際に、転送先Contractへの通知/連携方法を定義していません。

ERC-20で提案されている以下の2つの転送方法についてそれぞれの問題点を説明します。

  1. transfer(address to, uint amount)
  2. approve(address spender, uint amount) + transferFrom(address sender, address self, uint amount)

1.transfer(addres to, uint amount)をつかってContractにTokenを転送した場合そもそも通知の仕組みがないので受信側Contractはtokenを受け取ったことに気づくことができません。一応、Transfer Eventを発行しているのでDappsなどがEventを監視することで間接的に受信側Contractに通知を送ることはできます。

2.approve + transferFromはContractと連携動作するために用意されたものです。前述したとおりtransferを用いてContractにtokenを転送する場合は通知する仕組みがないため、Contractへは一般的に以下の手順で送ることが推奨されています。

  • 送信者はapprove(contract addresss, amount)を呼び出して、受信側Contractに必要な量のtokenの転送許可を与える
  • 送信者は受信側Contractに転送許可を与えたことを通知する
  • 受信側ContractはtransferFrom(sender address, self, amount) を呼び出して、必要な量のtokenを送信者のwalletから引き出す。

この手順に従う場合、サービスContract側がtransferFromを呼び出すため自身に転送されたtoken量を知ることができ、transferFromの成功をトリガーにしてサービス処理を実行することができます。しかし、この手順ではtransactionを複数回発行する必要があります。

以上のことから、トランザクション処理の欠如で発生する問題点とは、tokenを利用したサービスContractとToken Contractが連携するためには2~3回のtransaction発行が必要となり手数料がその分多く消費され、かつEthereumネットワークに必要以上のtransactionが流れてしまうことです。

基本的に新しく出てきたToken Standard提案はこの問題を解決するための拡張を行っています。以下ではどういう形で対応しているのかを簡単に説明します。

  • ERC-223 ではtokenFallbackを定義して、Etherを送ったときと同じようにtokenが送られてきた場合にContractがその通知を受け取れるように提案しています。
  • ERC-777 はERC-223をさらに拡張した提案で、ERC-223と同じようにtokenを転送するときに受信側ContractのtokensReceivedを呼び出して通知します。
  • ERC-827上記2つとは少し違い、approveメソッドの第3引数にbytes _dataを追加することで、approveとtransferFromを1つのtransactionで完結できるようにしています。

もちろん、上記で上げた複数の新しい提案はこの問題についての対応だけを定義したものではなく、より汎用的な拡張を行っています。ですが、これらの提案が出てきた背景としてはやはりトランザクション処理の欠如問題が源泉となっているように思います。

2. approve+transferFromが抱える潜在的な2重送信の問題

この問題はDEXなどのトークン交換システム等でより顕著となります。それ以外のサービスではそこまで大きな問題にはなりません。

問題となるユースケースを以下に述べます。

  1. アリスはapproveを呼び出して、ボブにM tokenの転送許可を与えます。
  2. アリスはボブへの転送許可の数量を N tokenに変更したくなったのでapproveを呼び出して変更します。
  3. ボブはアリスの操作で発行されたApprove Eventを見て、アリスからM tokenを受け取ります。このtransactionは2.の変更transactionより先にブロックへ格納されました。
  4. ボブは再度、アリスが発行したApprove Eventを発見し、さらにN tokenをアリスから受け取りました。

結果として、アリスは本来であればN tokenだけボブに送りたかったのに、M+N tokenをボブに送ってしまいました。

OpenZeppelin/StandardToken.solではこの問題に対応するために、increaseApprove/decreaseApprove関数を定義しています。
が、上記問題に完全に対応はできていないため今後も何かしらの解決策を模索する必要があります。

参考