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

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

ERC-777 新しいToken標準の提案

Ethereumの開発者コミュニティーでは常に新しい提案が発表されています。Token Contractの標準としては現状EIP20が主流ですが、この標準規格も問題がないわけではなく、常にそれらの問題を解決するための新しいToken標準が提案されています。

今回は比較的新しい提案であるERC-777について調べてみたことをまとめました。

github.com

簡単な要約

トークコントラクト用の標準インタフェースを作成します。

この標準の公式リポジトリは、jacquesd/eip777にあります。

抽象

この規格は、トークン契約と対話する新しい方法を定義しています。この標準では、契約書や正規アドレスがトークンを受け取ったときに、古い契約と互換性を保つためにEIP-820を利用して通知します。

動機

この規格は、広く使われているERC-20トークン標準を改善しようとしています。この規格の主な利点は次のとおりです。

  1. Etherと同じ概念を使用してTokenをsend(dest, value, data)で送信されます。
  2. tokensReceivedは、トークンが受信されたときにこのコードがトリガされるように、あらゆる契約や通常のアドレスで定義できます。これにより、ERC-20標準で必要なダブルコール(たぶん、aprove + transferFromのことだと思う)が回避されます。
  3. Token Contract Addressがブラックリストに登録されている場合はthrowするtokensReceived関数を登録するで、Contractと通常のアドレスの両方が、受け取るトークンを制御して拒否することができます。
  4. トークンホルダーは、トークンを管理できるオペレーターを"authorize"および"revoke"することができます。これらのオペレータは、一般的に、交換機、cheque processまたは自動課金システムのような検証された契約になるだろう。
  5. すべてのトークトランザクションには、ユーザ(送信者)とオペレータがそれぞれ受信者にデータを渡すために自由に使用するuserDataバイトフィールドとoperatorData(オペレータが取引する場合)が含まれています。
  6. これは、tokensReceived関数を含まないウォレットと下位互換性のある方法で使用できます。

仕様

IToken (Token Contract)

interface EIP777 {
    function name() public constant returns (string);
    function symbol() public constant returns (string);
    function granularity() public constant returns (uint256);
    function totalSupply() public constant returns (uint256);
    function balanceOf(address owner) public constant returns (uint256);

    function send(address to, uint256 value) public;
    function send(address to, uint256 value, bytes userData) public;

    function authorizeOperator(address operator) public;
    function revokeOperator(address operator) public;
    function isOperatorFor(address operator, address tokenHolder) public constant returns (bool);
    function operatorSend(address from, address to, uint256 value, bytes userData, bytes operatorData) public;

    event Sent(address indexed from, address indexed to, uint256 value, address indexed operator, bytes userData, bytes operatorData);
    event Minted(address indexed to, uint256 amount, address indexed operator, bytes operatorData);
    event Burnt(address indexed from, uint256 value);
    event AuthorizedOperator(address indexed operator, address indexed tokenHolder);
    event RevokedOperator(address indexed operator, address indexed tokenHolder);
}

token-contractは、Ierc777インタフェースをEIP-820を介して登録しなければならない。(MUST)
基本単位トークンは10 ^ 18でなければなりません。(MUST)

Methods

気になった個所だけ翻訳しています。

granularity
分割できないトークンの最小部分を返します。トークンの発行、転送、または焼却は、この値の倍数でなければなりません。この値の倍数ではないバランスをもたらす操作は無効であるとみなされTransactionをエラーにしなければならない(MUST)。

Tokenのほとんどは分割できなければいけない(SHOULD)。すなわち、この関数は分割を許可しないという正当な理由がない限り1を返すべきである。

注:granularity1以上でなければなりません。

returns: Tokenの分割不能な最小単位。

send

function send(address to, uint256 value) public
function send(address to, uint256 value, bytes userData) public

toアドレスに数量valueのTokenを送ります。

このメソッドはSentイベントを発生させなければいけません。MUST
このメソッドはtoが通常のアドレスかContractかどうかにかかわらず、EIP-820ルックアップで返されたITokenRecipientの実装addressに対してtokensReceivedメソッドを呼び出さなければいけません。MUST

toがContractで、EIP-820ルックアップによってtokenReceivedを実装されていないことが示された場合はこのメソッドはエラーを返さないといけません。MUST

このメソッドは次の場合エラーを返さなければいけない:

  • msg.senderの口座残高に十分なtokenがない
  • toがtokenを受け取る準備のできていないContractだった場合。具体的には、ITokenRecipientインターフェイスを実装するEIP-820経由でアドレス(自分自身または別のもの)が登録されていない*1Contract、またはソースコードのハッシュがこのコードの付録にリストされているホワイトリストに記載されたコードに含まれていない場合。

parameters

  • to: tokens recipient
  • value: amount of tokens transferred
  • userData: information attached to the transaction by the sender

operatorSend

function operatorSend(address from, address to, uint256 value, bytes userData, bytes operatorData) public

fromのアドレスからtoのアドレスに数量valueのtokenを送ります。

msg.sender はMUST 承認されたオペレーターもしくは、from アドレスの所有者でなければいけません。

このメソッドはSentイベントを発生させなければいけない。MUST
このメソッドはtoアドレスをEIP-820ルックアップして返されたITokenRecipientの実装addressに対してtokensReceivedメソッドを呼び出さなければいけません。MUST

このメソッドはEIP-820ルックアップがITokenReceipentの実装addressを返さなかった場合は、tokensReceivedを呼び出してはいけません。MUST NOT

このメソッドは次の場合にエラーを返さなければいけない:

  • from の口座残高に十分なtokenがない。
  • to がEIP-820にITokenRecipientインターフェースの実装address(自分自身か他のもの)を登録していないContractだった場合。
  • toがtokenを受け取る準備のできていないContractだった場合。具体的には、ITokenRecipientインターフェイスを実装するEIP-820経由でアドレス(自分自身または別のもの)が登録されていない*2Contract、またはソースコードのハッシュがこのコードの付録にリストされているホワイトリストに記載されたコードに含まれていない場合。
  • msg.sender fromに承認されたオペレータではない場合。

NOTE: fromアドレスは最初にMUST authorizeOperatorをよびだして、このアドレスがfromの代わりにoperatorSendを呼び出せるようにしなければいけません。

parameters

- from: token holder (sender)
- to: tokens recipient
- value: amount of tokens transferred
- userData: 送信者(fromアドレス)によって以前に提供されたトランザクションに付随する情報。
- operatorData: オペレータがトランザクションに付加した情報

NOTE: オペレーターはoperatorDataパラメータを介して自由にデータを渡すことができますが、userDataパラメータは送信者が提供するデータ用に予約されています。送信者は、事前にこのデータをオペレータに提供する必要があります。

ITokenRecipient

受取人はEIP-820レジストリを介してITokenRecipientインタフェースを実装するContract(それ自体または他のもの)を登録することができます。

interface ITokenRecipient {
  function tokensReceived(address from, address to, uint amount, bytes userData, address operator, bytes operatorData) public
}
Methods

tokensReceived

function tokensReceived(address from, address to, uint amount, bytes userData, address operator, bytes operatorData) public;

fromアドレスからtoアドレスへの数量valueのtoken送信を通知します。

Tokenable Contracts Registry

Tokenable Contractsレジストリは、ITokenRecipientをEIP-820経由で登録することなくトークンを受け取ることを希望するコントラクトが登録できる(CAN)レジストリです。これは完全にオプションであり、Contractへトークンを受け取ったときに明示的に通知されないようにするためのものです。
これはほとんどの場合Contractのトークンをロックしますが、ロックされたトークンを防止するための他のメカニズムを備えた特定のContractには有用です。Contractの作成者は、トークンをロックしない、もしくはトークンをロックした結果について理解することを保証しなければならない(MUST)。
私たちはこのレジストリインスタンスを提供し、誰でも自由に登録するためのContractを提出できます。承認されたContractのリストは、付録に表示されています。
トークンContractは、このContractレジストリを使用して、受信Contractがトークンを受け入れるかどうかを確認すべきである(SHOULD)。

根拠

この規格はEIP-223の問題のいくつかを解決し、ERC-20は無制限に承認されたのと同じ方法でトークンを管理できるオペレーター(一般的には契約)を許可することでそれに続き歩歩いていますします。

また、EIP-820を使用すると、Walletの下位互換性が可能となり、プロキシContractを再配備する必要がなくなります。

下位互換性

説明がながいので要約すると、

  • ERC-20との下位互換性は持たせてないけど、共存させることは可能。そのためにtransferはsendに置き換えたりして、ERC-20との混乱を避けている。
  • ERC-20と共存させる場合は、古いERC-20の呼び出しは古いContractからのみ呼び出されるべき。(たぶんすでに稼働しているERC-20Tokenを置き換えた場合のことを想定してるのかな?)
  • ERC-20の実装とはそれぞれ独立して動作させることが可能。(でもbalanceはもちろん共有している)
  • ERC-20実装も持たせる場合は、EIP-820にIerc20を登録する必要がある。
  • ERC-20のインターフェースを通じて呼び出された場合は、唯一transferだけERC-820の動作
  • ERC-20も実装したERC-777Tokenの唯一の違いは、transfer、transferFromが呼び出された時にITokenRecipientの実装addressがEIP-820を介して取得できた場合は、tokenReceivesを呼び出さないといけない。
  • decimalsは()を実装する場合は必ず18を返さないといけない。

以下の表は、EIP-777とERC-20を介してトークンを送信、作成、転送する際にトークン契約が取らなければならないさまざまなアクションをまとめたものです。

EIP-820 to address EIP-777 send/operatorSend and Minting ERC-20 transfer
ITokenRecipient registered regular address Call tokensReceived Call tokensReceived
ITokenRecipient registered whitelisted contract Call tokensReceived Call tokensReceived
ITokenRecipient registered non-whitelisted contract Call tokensReceived Call tokensReceived
ITokenRecipient not registered regular address SHOULD accept SHOULD accept
ITokenRecipient not registered whitelisted contract SHOULD accept SHOULD accept
ITokenRecipient not registered non-whitelisted contract MUST throw SHOULD accept

まとめ

要約にあるように、ERC-20を発展させて、ERC-223のfallbackに関する機能を拡張して整理したToken標準の提案です。
他のToken提案がインターフェースをERC-20にできるだけ揃えるようにしているのに対して、ERC-777はあえて、違う名前にし、ERC-20と共存できるようにしている点が興味ぶかいです。
あと、提案のコメントでtokenの最小単位をいくつにするのがよいのか?について議論されているのも興味深かったです。現状ではたぶんDEXとかを考慮して割り切れないと扱いに困るから桁数はEtherに揃えようって感じになってます。なのでERC-777では桁数自体は18桁で固定され、どうしても最小桁数を変えたいときのためのメソッドが追加されています。
議論や提案内容を見る限りでは、標準化は特に急いでいる感じではないのかなぁと思いました。その理由としてERC-20との橋渡し的な実装方針についてもかかれていたりします。まぁ内部でERC-820という別の提案にも依存していますからね。

ERC-777はERC-820を最大限に活用したToken Contractの提案っていうイメージですね。

*1:原文は does register だけど、実装を見る限りdoes not registerのだと思う

*2:*1と同じ