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

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

ERC-20拡張提案でありOpenZeppelinにいち早く導入されたERC-827

今回は番号からわかる通り2018/02現在一番新しい(よね?)ERC-20の拡張提案であるERC-827を紹介します。
github.com

簡単な要約

標準インタフェースERC20をトークン用に拡張し、transferとapproveメソッド内でcallの実行を可能にする。

抽象

この標準は、トークンを転送するための基本的な機能を提供するだけでなく、トークンを承認して、他のチェーン上の第三者が使うことができるようにします。また、transferやapprove時にコールを実行することもできます。

動機

ERC20インタフェースのこの拡張により、Ethereum上のトークンは、walletから分散型交換に至るまで、他のアプリケーションで再利用できます。ERC20トークン標準は広く受け入れられていますが、価値の移転しか許されません。Ethereumユーザーはトランザクションの価値とデータを転送できます。このERC20トークン標準の拡張により、ERC20トークンでも同じことができます。

私はコミュニティで提案されている多くの新しい基準を見てきました。現在のERC20標準を改善する方法は、元の標準と完全に互換性があり、新しい方法を追加する拡張機能ですが、私が提案している新しい機能は、ドキュメントを数えて100行未満のコードです。

各機能を使用するタイミング

  • approve:おそらくあなたが必要とするもの、おそらく唯一のものは、受信者契約が認証された/承認された残高を使用することができるからです。ベストプラクティスは、送信者の許容量を確認してから、transferFromメソッドを使用して処理します。
  • transfer:転送される残高が正しいことを確認する方法はありません。この機能は、値の転送をチェックする必要がない場合に便利です。
  • transferFrom:転送と同じです。転送されたトークンの量を確認する必要がなく、承認済みの残高を使いたい場合にのみ便利です。

仕様

ERC-827で新しく追加されてる部分だけ抜粋します。ERC-827は非常にシンプルな提案で以下の3つのメソッドのみが追加されています。

ERC827メソッド

transfer - ERC827

_dataパラメータで_toの関数を実行する。関数が正常終了した場合は_value量のトークンを_toに転送し、Transferイベントを発生させなければならない(MUST)。

_toアドレスへの呼び出しが失敗した場合、または_from口座残高に十分なトークンがない場合は、関数はrevertすべきです(SHOULD)。
ERC20転送メソッドは、_to.call(_data)の前に呼び出されます。

(注)_toアドレスはトークンアドレス自体を指定できません。
注意0の値の転送は、通常の転送として扱われなければならず、転送イベントを発生させなければならない(MUST)。

重要な注意事項: このメソッドをパラメーターとして転送された値を受け取るフォールバック関数で使用しないでください。フォールバック関数で転送された値の量を確認する方法はありません。

  function transfer(address _to, uint256 _value, bytes _data) public returns (bool) {
    require(_to != address(this));
    require(super.transfer(_to, _value));
    require(_to.call(_data));
    return true;
  }
transferFrom - ERC827

_dataパラメータで_toの関数を実行します。関数が正常終了した場合、_value量のトークンを_fromから_toに転送し、Transferイベントを発生させなければなりません(MUST)。

transferFromメソッドは、引き出しワークフローに使用され、機能の実行後に契約がトークンを転送できるようにします。
ERC20のtransferFromメソッドは、_to.call(_data)の前に呼び出されます。
これは、例えば、契約があなたのためにトークンを転送すること、および/またはサブカードで料金を請求するために使用できます。
_toアドレスへの呼び出しが失敗した場合、または_fromからmsg.senderへの承認済みの残高が転送を実行するのに十分でない場合は、関数を元にrevertしなければいけません(SHOULD)。

(注)_toアドレスはトークンアドレス自体を指定できません。
注意: 0の値の転送は、通常の転送として扱われ、転送イベントを発生させなければならない(MUST)。

重要な注意事項: このメソッドをパラメーターとして転送された値を受け取るフォールバック関数で使用しないでください。フォールバック関数で転送された値の量を確認する方法はありません。

  function transferFrom(address _from, address _to, uint256 _value, bytes _data) public returns (bool) {
    require(_to != address(this));
    require(super.transferFrom(_from, _to, _value));
    require(_to.call(_data));
    return true;
  }
approve - ERC827

_dataパラメーターを使用して_spenderの関数を実行します。関数が正常に終了すると、_spenderは_value分までアカウントから何回も引き出す​​ことができます。この関数を再度呼び出すと、現在のallowanceが_valueで上書きされます。

クライアントは、同じ消費者の別の値に設定する前に、最初に手当を0に設定するようにユーザインタフェースを作成してください(SHOULD)。
ERC20のapproveメソッドは、_spender.call(_data)の前に呼び出されます。
_spenderアドレスへの呼び出しが失敗した場合、関数は元に戻すべきです。
THOUGH すでに展開されたContractとの下位互換性を保つために、Contract自体がそれを強制すべきではありません

(注)_spenderアドレスにはトークンアドレス自身を指定してはいけません。

  function approve(address _spender, uint256 _value, bytes _data) public returns (bool) {
    require(_spender != address(this));
    require(super.approve(_spender, _value));
    require(_spender.call(_data));
    return true;
  }

まとめ

ERC-827はapprove, transfer, transferFromに第3引数としてbytes _dataを追加しただけの非常にシンプルな提案です。ですが、この拡張によってERC-20 Tokenがethereumのtransactionと同等の機能を持つことを可能にしています。
拡張部分が少なく、シンプルでテストがしやすいためOpenZeppelinでもすぐに参照実装を提供できたんだと思います。

transferとtransferFromの重要な注意事項で忠告のあるフォールバック関数というのは多分ERC-223のtokenFallback関数みたいなものを指していると思われます。tokenFallback関数は直接呼び出すこともできるので、tokenFallbackに渡されたamountは実際に転送されたamountと一致しているとは限りません。(そもそも転送されてない場合もある)
この辺のamountの検証についてはμRaidenでも利用しているERC-712などを参考にした検証機能を実装するといいかもしれませんね。