Open5

Seaport Protocolについて理解する

ロピタルロピタル

このスクラップではSeaport Protocolについて、つらつらと理解しながら投稿していきます。
もし意見などありましたら、お気軽に投稿ください🙏

Wyvern Protocolや、Seaport Protocolの基本的な内容がわかっていると投稿内容が理解しやすいかもしれません。

ロピタルロピタル

ゾーンの実装例(PauzableZone)をちょっとみてみる

PauzableZoneを読んでみた。ゾーンの実装の一例らしい。

PauzableZoneについての以下の文章を読み解いてみます。

PausableZoneは、すべての注文を承認するシンプルなゾーン実装です。これは、ゾーンとして設定された制限付きオーダーを一時停止するために、 コントローラによって自己破壊されることがあります。制限されたオーダーを一時停止させることができます。

まず、オーダーにはゾーンが指定できるみたいですね。そして、ゾーンはコントローラーによって破壊することができるらしいです。selfdestructすることで、PausableZoneを指定したすべてのオーダーが実行不可能になるとのことです。

一旦の理解

ゾーンの実装をみた感じ、オーダーのキャンセルが制御できたり、注文を処理する際に独自の処理を入れることができるみたいです。

もちろんオーダーの作成者(注文者)自身もオーダーをキャンセルできますが、ゾーンに指定したコントラクトでもキャンセルができるんですね。

制限付き注文とは

文章に出てくる「制限付き注文」は、orderTypeRESTRICTEDを指定した注文みたいです。

  • orderTypeは、2つの異なる好みに応じて、4種類の注文のうちの1つを指定する。
    • FULLは部分的な充填をサポートしないことを示し、PARTIALは注文の何割かを充填することを示す。ただし、各アイテムは指定された端数できれいに割り切れる必要があるという重要な注意点がある(除算余り)。
    • OPENは、どの口座からも注文を出すことができることを示し、RESTRICTEDは、注文者または注文のゾーンが実行することを要求しています。または、ゾーンに対して isValidOrder または isValidOrderIncludingExtraData ビュー関数を呼び出すと、注文が承認されたことを示すマジック値が返されることを示す。

引用元: https://github.com/ProjectOpenSea/seaport/blob/main/docs/SeaportDocumentation.md

RESTRICTEDを指定した場合、オーダーに指定されたゾーンまたは注文者しか実行できないみたいです。例えば、売りオーダーを出したら、そのオーダーを実行することができるのはオーダーに指定されたゾーンか、注文者のみということだと思います。つまり、この場合はPausableZoneを通して実行する必要があるということでしょう。

isValidOrderとは

ついでにisValidOrderが何かわからなかったので調べてみました。

(注文タイプで指定された)「制限付き」注文は、ゾーンまたはオファー側が実行するか、 ゾーンのisValidOrderまたはisValidOrderIncludingExtraDataビュー関数の呼び出しによって示される承認がなければならない。

とのことです。isValidOrderの呼び出し側(SeaportProtocol)を見てみると以下のような処理がありました。

注文が制限された注文タイプであるかどうかを判断し、もしそうであれば、注文者またはゾーンがフルフィラーであるかを確認する。もしそのどちらかがフルフィラーであれば問題なし。もしフルフィラーじゃなければ、isValidOrderを呼び出し、オーダーを実行することを許可されているかどうかを確認しているみたいです。

参照元: https://github.com/ProjectOpenSea/seaport/blob/main/reference/lib/ReferenceZoneInteraction.sol#L37-L61

ロピタルロピタル

コントラクト調べてると referenceというフォルダを見つけたのでなんだろうと思って調査してみました。アセンブリなどを使わずに、読みやすいように書かれているらしいです。めっちゃ優しい...

リファレンスフォルダには、独自のSeaportの実装があり、読みやすく、Seaport.sol.と同等の機能を持つように設計されています。Seaportの多くは、アセンブリと興味深いメモリ管理技術を使用して最適化されており、コードが読みにくく、理解しにくいことが多いため、私たちはリファレンス実装を作成しました。リファレンスは読みやすく、全く同じように動作するはずですが、デプロイされるものではありません。ですから、もしパリティの問題や、リファレンスの実装にバグや脆弱性を発見した場合は、報告してください。

引用元: https://github.com/ProjectOpenSea/seaport/blob/main/docs/Code4rena-Guidelines.md#reference-implementation

ロピタルロピタル

Zoneについてのドキュメントを読んでみる

ドキュメントにはゾーンに関するこのようなユースケースが書かれています。

  • 盗まれた資産の販売を停止する
  • ユーザーの承認を無効にすることなく、緊急時に注文を一時停止する
  • 特定のコレクションから一定時間内に販売可能なNFTの数を制限する
  • 特定のアセットに対して特定のフロアまたはシーリング価格を強制する
  • 外部の価格オラクルに対するその他の任意の呼び出し
  • 有効な注文を完了したユーザーに対する特別なインセンティブを追跡する

世界中の誰もが独自のゾーンを構築し、展開することができ、プロトコルとしてのSeaportの分散化を支援することができます。

なるほど、どのユースケースもなんとなく実装方法が思いついたので理解は大丈夫そう。

例えば、「すべてのアセットは0.1ETH以上で販売されなければならない」という制限を加えた独自のマケプレなどを作成する際に、そのような処理を加えたゾーンを作成することで実現できそうです。

もしくは、ユーザーがコレクションに対して、ゾーンのアドレスを指定できるようなフィールドを設置することで単一のマケプレで、コレクションに紐づくアセットの一括販売停止なども実装できそうです。

とても柔軟な設計になってますね... ゾーンの理解は一旦ここで止めて、次はオークションの実装方法を考えてみます。

ロピタルロピタル

matchOrderの概念を理解する

イングリッシュオークションについて考えていたのですが、どこにも書いていないし、パッと思い浮かばびませんでした。色々調べていると、matchOrdersというを使えばいけるんじゃないかと思ったので調査してみます。

matchOrdersmatchAdvancedOrdersという2つの「match」関数のうちの1つを呼び出す。ここでは、明示的な注文のグループが、どの対価アイテムに適用するかを指定するフルフィルメントのグループと一緒に提供される(「アドバンス」の場合は、標準方式と同様の方法で動作するが、制限付き注文タイプの実行時にゾーン上のisValidOrderIncludingExtraDataビュー関数への呼び出しの一部として提供される任意の extraData引数と同様に、供給分子および分母小数値を通じて部分充填をサポート)。この方法で処理される注文は、明示的な実行者を持たないことに注意。その代わりに、Seaportは単に、各注文における要求の一致を 確実にする。

引用: https://github.com/ProjectOpenSea/seaport/blob/main/docs/SeaportDocumentation.md#order-fulfillment

なんとなく理解。実行者を持たないというのがイングリッシュオークションには必須になってきそうです。なぜなら、もしオークションが終了した場合などは、システムが自動で最高入札額のオーダーを実行する必要があるからです。

fulfillOrderでなぜこれができないかというと、一つのオーダーから自動でミラーのオーダーを作成するためです(参考)。つまり、署名が片方のオーダーにはされていて、もう片方のオーダーは送信者がフルフィラーだというような処理を入れてなりすましを防いるため、送信者がフルフィラーである必要があるわけです。

しかし、二つのオーダーを用意し、どちらにも署名が行われていれば、第三者が実行することができるわけです。