見出し画像

ERC-20のapprove問題を解決する3つのパターン

これは、「DeFiにみる2020年のERC-20実装」の後編にあたる記事です。前編を未読の方はそちらからどうぞ。

DeFiへの預け入れとapprove問題

ERC-20における「トークンの送信」とは下図のように、ERC-20のtransferFrom関数を使って実現します。

画像1

例えばレンディングのためにCompoundにERC-20を貸し出す際には、ERC-20をレンディングコントラクトへただ送信するだけでは、DeFi機能のトリガーにはならず、事実上のGOXをすることとなります。

そのため、DeFiコントラクト側に用意されているdeposit機能を使い、内部トランザクションによってDeFiコントラクトへの送信を実行します。このとき、下図のようにDeFiコントラクト側にはAliceのトークンを自由に送信する権利などあるはずもないので失敗します。

画像3

そこで、ERC-20にはapprove関数が用意されており、事前に一定額を指定することで、特定のアカウントが自らのトークンを自由に譲渡してもよいという委任の機能を実現しています。

画像3

このapproveによって、DeFiコントラクトへトークンを預けることができるようになりましたが、approve/depositと2つのトランザクションを実行する必要があり、UX上の課題となっています。特にERC-20ではapproveの上限額を設定することから、何度もこのapprove関数を実行することになります。これを本記事ではapprove問題と呼びます。

ERC-223/ERC-777あるいはonReceived Hookパターン

ERC-223 Token Standardでは、このapproveのためのトランザクションを明確に問題として取り上げ、tokenFallback関数を譲渡先コントラクトにHookとして実行させることで解決を図っています。これ以後、本記事では同様のコンセプトをonReceived Hookと呼びます。

ERC-223自体は後発で同じくERC-20の改善を目指したERC-777に取って代わっています。ERC-777ではonReceived HookとしてtokensReceived関数が追加されています。

トークン送信のトランザクションを検知したERC-20から内部トランザクションを用いてDeFiコントラクトのonReceived Hookを実行し、DeFiコントラクトのonReceived Hook内部でdeposit機能を実行します。これにより、Aliceは事前approveを必要とせず、トークン送信のGOXを避けることができます。

画像4

ERC-777はERC-20の互換を保ったままapprove問題を改善したトークンですが、2020年自体ではあまり普及しておりません。特にDeFiエコシステムではERC-777を意識したものは少なく、ERC-20の互換があるせいでERC-777を考慮しないシステムにおいては脆弱性の原因になることがあります。2020年4月にUniswap V1で、ERC-777で明確な脆弱性があり、トークン流出事件が起こりました。tokensReceived関数と逆のコンセプトで送信する側がHookとして実行するtokensToSend関数を悪用したもので、再代入(re-entrancy)攻撃が行えるようになっていました。

もちろんこの脆弱性についてERC-777が問題というわけではありませんが、現在のスタンダードがERC-20である以上、余計な問題を避けるべく利用されていない印象があります。

ERC-20互換ではあるもののHookを呼び出す関数をtransferAndCallとして明確にわけるコンセプトであるERC-677ERC-1363があります。まだまだ議論中のようですし、新しい関数であるため既存のDeFiプロダクトに組み入れられることはないでしょう。

余談ではありますが、このonReceived HookはERC-777と同時期に提案されノンファンジブルトークン(NFT)の標準仕様であるERC-721(ERC-1155も同様)にも導入されています。ERC-721では、トークンの送信に、transferFromとsafeTransferFromと明確に分け、safeTransferFromではHook関数を呼び出すことを規定しています。このHook関数により意図しないコントラクトへの送付を避けることが目的ではありましたが、depositやstakingにも利用可能なようです。

REVVトークンの発行機能であるanimocabrands/ethereum-contracts-nft_stakingではonReserved HookであるonERC1155Receivedの中にstaking処理を含ませています。つまり、approve/depositの流れを踏むことなく、stakingコントラクトへ直接safeTransferFromを用いてNFTを送付することでstakingが可能です。

   function onERC1155Received(
      address, /*operator*/
      address from,
      uint256 id,
      uint256, /*value*/
      bytes calldata /*data*/
  ) external virtual override returns (bytes4) {
      _stakeNft(id, from);
      return _ERC1155_RECEIVED;
  } 

このように、現時点ではFT送信では避けられ気味なonReceived Hookはありますが、NFT送信には標準的なものになっていくかもしれません

EIP-2612 permit / Signed approvalパターン

EIP-712を中心とした議論により、署名を利用したメタトランザクションが活発に議論されています。

そもそもイーサリアムにおけるアカウントの証明はデジタル署名によって行われています。Aliceがトランザクションを作成する際には、実行するデータに対してAliceの署名鍵で署名することでAliceがトランザクションの作成者であることを証明しています。メタトランザクションでは、Aliceは署名だけを行い、Bobがトランザクションを作成することで、イーサリアム上でAliceの同意を得たトランザクションを実行する事ができます。

EIP-2612: permit – 712-signed approvalsでは、ERC-20におけるapproveを署名によって置き換えるpermit関数を提案しています。

まず、AliceはDeFiコントラクトへの委任情報に署名し、メタトランザクション実行者のBobに署名を渡します。BobはAliceに変わってapproveを実現するpermitを実行します。permit上でAliceのapproveが可能になったので、DeFiコントラクトは内部トランザクションによってtransferFrom関数を実行することができます。

画像6

EIP-2612では、前述のonReserved Hookパターンを

So far, many of these proposals have seen very little adoption, and the ones that have been adopted (such as ERC-777), introduce a lot of additional functionality, causing unexpected behavior in mainstream contracts.

と明確に否定しています。ERC-20としての挙動を変えることなく、別関数として用途を限定したpermit関数は適切に既存の問題点を解決しにいっていると言えます。このpermit関数は、DAIを始め、Uniswapでも対応しており、EIP-2612で標準化を目指していることからBobに対するインセンティブ設計によっては今後スタンダードになりうる仕様なのではないでしょうか。

Self-depositパターン

DEVは、DEV Protocolの報酬として設計されたERC-20トークンです。通常、DeFiコントラクトへdepositする際には、DeFiコントラクト側にdeposit関数が存在します。それは、DeFiプロトコルは様々なERC-20トークンを受け入れるため、汎用的に使えるERC-20標準関数だけでコントラクトを実現するためです。

Self-depositパターンでは、ERC-20自体に、Deposit機能を持たせます。ERC-20コントラクトに、直接deposit関数を実装し、その内部トランザクションによってDeFiコントラクトのdeposit関数を実行します。

画像5

このパターンでは、非常に単純な方法でapprove問題を解決していますが、DeFiコントラクトの内部を十分に把握している必要があります。したがってUniswap等の汎用的なプロトコルには適用しずらく、用途は限定的になるでしょう。

このSelf-depositパターンは現時点ではそれらしいEIPも見当たりません。実装方法の標準がないためDeFi等でデファクトになるのは難しいかもしれません。しかしながら、ERC-20の他機能に影響を与えているわけではないため、内部のエコシステムを構築するにあたっては十分検討に値する実装方法だと思います。

おわりに

前編となる「DeFiにみる2020年のERC-20実装」と本記事を通して、DeFiに狂乱した2020年8月におけるERC-20の実装とapprove問題について解説しました。

記事を書いている最中に、埋もれていたERCを発見したり、全く思い浮かんでなかったアプローチを発見し理解に頭を悩ませたりと多様性に驚かされました。また、調査から含めると1週間ほどで2記事を書いたのですが、書いてる最中に話題の中心となるプロトコルが変遷していき心が折れそうでした。
まだまだDeFiの熱狂は止まらないと思います。値動きだけでなく、各プロトコルにおける工夫点を眺めてみるのもよいのではないでしょうか。

認知していない仕様や参考にすべき実装がまだまだ存在すると思います。取り上げてほしい実装や本文中に間違いや気になる点がありましたら、お気軽に Twitter @rmanzoku まで連絡いただけると幸いです。

投げERC-20歓迎しています。
rmanzoku.eth (0xd868711BD9a2C6F1548F5f4737f71DA67d821090)

投げトークンの送り先はこちら。 rmanzoku.eth (0xd868711BD9a2C6F1548F5f4737f71DA67d821090)