🐈

Hats Protocolを理解する!!

2024/08/12に公開

はじめに

みなさん、 Hats Protocol というプロトコルを聞いたことがありますか??

https://www.hatsprotocol.xyz/

Hats Protocolについて調べる機会があったのでその結果をブログ記事にまとめました!!

Hats Protocolとは何か?

まずは、 Hats Protocol がどういうプロトコルなのか解説します!

https://docs.hatsprotocol.xyz/

Hats Protocolとは、組織の役割(ロール)や権限をプログラム可能なデジタルグラフに変換し、オンチェーンで管理できるようにするためのプロトコルです!!

特徴は次の点ですね!

AWSIAMロールの考え方に近いかもしれませんね。

サポートしているチェーン一覧は下記から確認できます。

https://docs.hatsprotocol.xyz/using-hats/hats-protocol-supported-chains

テストネットでは Sepolia と Holeskyが対応してそうです。

  • Sepoliaにデプロイされたコントラクト

https://sepolia.etherscan.io/address/0x3bc1A0Ad72417f2d411118085256fC53CBdDd137

  • Holeskyにデプロイされたコントラクト

https://holesky.etherscan.io/address/0x3bc1A0Ad72417f2d411118085256fC53CBdDd137

クイックスタート

まずは、下記手順に従ってサンプル組織ツリーを作ってみます!!

https://docs.hatsprotocol.xyz/using-hats/creating-my-first-hat

1. 新しいツリーを作成する

まず、以下のページにアクセスします!!

https://app.hatsprotocol.xyz/

ロゴやTop of Hatsの名前を入力する必要があるみたいです!!

諸々必要なデータ入力します!

今回はこんなロゴを用意しました!!

全部入力したら Createボタンを押します!!

これで HatがNFTとしてミントされます!!

実際のトランザクションは以下から確認できます!!

https://sepolia.etherscan.io/tx/0x5917ad6d7719aa3ea87c246cda0277505b366db3b32f9425e88bae5f3d161cf1

しばらく待つと以下のような画面に遷移します!!

これでツリーができました!!

2. 最初の子Hatを作成する

続いて子Hatを作成します!!

先ほどの画面の左上の Edit Tree をクリックします!!

子Hatも細かく設定できるみたいですね!!

名前や画像なども決められるみたいです!

その他、帽子を被れるアカウント数の上限値設定、アドレスの一括登録などが可能なんですね。

他にも細かく権限周りを設定することができるみたいです!!

これで子Hatが作成できました!!

クイックスタートはここまでです!!

Hats Protocolの機能を細かく確認していこう!!

Adminにできること

Hats Protocolでは Admin は特別な権限を持ちます。

子Hatの詳細や画像、最大供給量、適格アドレス、トグルアドレスを変更できます(ただし、変更可能な状態のHatに限る)。管理者Hatは、新しい着用者に対して、変更可能なHatや変更不可能なHatを発行でき、変更可能なHatを別のアドレスに移転することも可能みたいです。

各Hatは、その下に直接リンクされたすべてのHatの管理者として機能します。

そして Hatは、EOAのみならずマルチシグなどのコントラクトウォレットやスマートアカウントウォレットにも着用が可能とのことです!

これは面白いですね!!!

これなら柔軟に権限の管理ができそうです!!

他のプロトコルとの連携

以下のページで紹介されている通り、様々なプロトコル・アプリと連携が可能とのことです!!!

https://docs.hatsprotocol.xyz/using-hats/connecting-hats-w-permissions-and-authorities

SafeやSuperfuildなどのブロックチェーン側のプロトコルだけでなく、テレグラムやDiscord、Google Docsとも連携できるみたいですね。

HatsProtocolの機能を使って以下のようなユースケースをさらに強力にできるみたいですね!

  • アカウントとリソース:
    Ethereumアカウントの管理、マルチシグの署名権限、報酬管理
  • コミュニケーションチャンネル:
    共有コミュニケーションチャンネルやアカウントへのアクセス権や投稿権限
  • ガバナンスと投票:
    スマートコントラクトへのオンチェーン権限、提案作成、投票権
  • ワークスペース:
    ワークスペース、ファイル、ドキュメントでの読み取り、レビュー、書き込み権限

トークンゲート機能との連携

Hatで管理できる権限には2種類の権限があります。

  • ハードパワー:
    トークンゲートを通じて提供されるオンチェーンやオフチェーンの明確な権限

  • ソフトパワー:
    会議の進行や特定のドメインでのプロジェクト作業、トークンゲートで管理できないアプリの管理権限

これらの権限をHatとしてブロックチェーン上で作った後にトークンゲートを通じてHatに結びつけることもできるみたいです。

  • トークンゲーティングプラットフォーム:
    Guild、Collab.Land、Lit Protocolなどがトークンゲーティングを提供し、以下のアプリで使用できます:

    • Guild:
      Coordinape、
      Discord、
      Github(プライベートリポジトリのみ)、
      Google Workspace(Docs、Sheets、Slides)、
      Party.Space、
      POAP、
      Rally、
      Telegram、
      Wonderverse
    • Collab.Land:
      Discord、
      Telegram
    • Lit Protocol:
      Gather Town、
      Google Drive、
      Headline、
      IPFS、
      Nowhere、
      Orbis
      Club、
      Shopify、
      WalletChat、
      Wordpress、
      Zoom
  • トークンゲーティングを統合したアプリ:
    Charmverse、Wonderverse、Commonwealth(近日対応予定)など、特定のチャンネルへのアクセスや読み書き権限を提供

  • ERC1155を読み込んでパラメータを変更するツール:
    Snapshot Strategiesを使用し、特定のHatのみがSnapshot提案で投票できるようにしたり、特定のHatに投票権の重みを与えたりする

  • HatsSignerGate:
    Safe multisig署名権限を特定のHatに提供するZodiacモジュール

  • ソーシャルアグリーメントや他のアカウンタビリティメカニズム:
    季節ごとの選挙、ステーキング要件、評判システムなど。トークンゲーティングを通じて明確に権限を付与できない場合でも、そのHatがその権限を持つことを示すためにHatを使うことができます。

    以下のサイトからそれぞれのアプリとどのように統合すれば良いのかまとめられています!!

https://docs.hatsprotocol.xyz/hats-integrations/permissions-and-authorities#guides-for-connecting-authorities-to-hats

承認と適格性: Hatの保持者に必要な条件について

Hatを通じてアクセスできる権限は、個人またはグループの管理者によって付与および取り消しが可能です。また、Hatsモジュールを使用することで、幅広い自動化された適格性やアカウンタビリティの基準に基づいて管理することもできるみたいです。

  • Hatsモジュール

    Hatsモジュール は、役割のためのプログラム可能な拡張機能です。

    モジュールをHatに接続することで、特定の条件に基づいてHat(および関連する権限)の自動付与および取り消しが可能になります。

  • Hatの適格性モジュール

    Hatの適格性モジュールは、どのアドレスがそのHatを着用できるかを決定するアドレスです。

    また、着用者がもはや適格でない場合には、そのHatを取り消すことができます。

    適格性モジュールは、手動で適用することもコントラクトウォレットによる自動トリガーで実行することできるみたいです。

  • 適格性の基準について

    権限の付与の基準については結構いろんなルールを決められるみたいですね。

    • トークン、NFT、アテステーション
      ERC20トークンの残高、ERC721 NFTs、ERC1155 NFTのトークンID、EASアテステーションなど
    • 選挙と許可リスト
      JokeRace、Snapshot、Tallyからの選挙結果、自動任期制限、手動で作成された許可リスト
    • 成果と評判
      バッジ、オンチェーンポイント、Colinks、Gitcoinパスポートスコアなど
    • 前提条件のアクション
      ステーキング、契約の署名、他の役割の保持、サブスクライバーであることなど
    • その他
      複数の基準をAND/ORロジックで組み合わせたり、AIエージェントを導入したり、細かなオンチェーンまたはオフチェーンのトリガーを作成したりすることができます。

    ルールについては開発者が柔軟に決められるみたいですね。
    また、Hatsモジュールを利用することもありみたいですね。

    もちろん、Appからも設定ができます。

    クイックスタートの部分で子Hatを作った時に Revocation & Eligibilityというセクションが出てきたと思いますがそこで設定できるみたいです!!

    利用可能な適格性モジュールはいくつか種類があるみたいで以下のページでリスト化されています!!

https://docs.hatsprotocol.xyz/hats-integrations/eligibility-and-accountability-criteria

技術的に Hats Protocolを細かく確認していこう!!

冒頭にも説明しましたが、Hatsは 譲渡不可能なERC1155ライクなトークンとして発行されます!!

Hats Protocolの主要なロジックは、Hatsの作成、発行、取消、管理となっています。

特定のHatの動作を拡張し、カスタマイズすることも可能みたいです!!

具体的にどんな仕様・機能が提供されているか確認していきます!

Hat Properties

Hatsが持つプロパティを確認していきます!!

ERC1155がベースになっているのでERC1155のNFTに似てますね。

Wearing a Hat

Hatを着用できるかの条件は3つ

Hats Protocolには、isWearerOfHat()という便利な関数があり、これはbalanceOf()をラップして、残高が1であるかどうかをブール値で返すみたいです。

Hat Admins & Hatter Contracts

各帽子の管理者は別の帽子です。つまり、特定の帽子の管理機能を実行する権限は、その管理帽子を着用している人に割り当てられます。

管理帽子を着用しているアカウントは誰が帽子を着用できるか決定することが可能です。

そして管理権限は伝播します。ある帽子のすべての祖先(直接の管理者、その管理者の管理者、など)は、その帽子の管理者として機能できます。

  • 帽子に対するコントロール

    役割 権限
    管理者 新しい帽子を作成する
    着用者に帽子を発行する
    帽子のプロパティを編集する(変更可能な場合)
    帽子を移転する(変更可能な場合)
    対象条件モジュール 対象外のアドレスが帽子を着用するのを防ぐ
    特定の着用者から帽子を剥奪する
    トグルモジュール 帽子をアクティブまたは非アクティブにする ⇒ 全ての着用者がその帽子を失う
  • Hatter Contracts

    管理者として機能するロジックコントラクトは、Hatter Contractsと呼ばれます。これらは、特定のロジックやルールを実装するコントラクトです。Hatter Contractsの管理者は真の管理者ですが、その管理権限をハッターに埋め込まれたロジックに委任しています。


    Hatter Contractsのロジックは、DAOにとって広範なデザイン領域です。


    以下は、Hatterロジックの例です:

    • 帽子の作成
      特定のアドレス(DAOのメンバーなど)に、DAOが管理する帽子を作成する権限を付与します。

    • 帽子の発行
      特定のアドレス(DAOのメンバーなど)に、帽子トークンを発行する権限を付与します。
      上記と組み合わせることで、DAOはメンバーが特定のタイプの帽子を許可なく作成し、着用できるようにすることができます。これは、役割の明確化と理解を促進するために帽子を使用する場合に特に有効です。

  • 着用者の対象条件
    特定の帽子を着用するために、候補者が満たすべき要件を強制します。


    例えば、DAOのメンバーであることや、特定のトークンを保持していることなどです。これは、多くの場合、対象条件モジュールとして実装する方が効果的です。

  • 着用者のステーキング
    特に重要な対象条件の一つに、トークンやDAOシェア、その他の資産を担保としてステーキングすることがあります。


    これは、着用者が帽子に関連する責任を果たさなかったり、義務を遂行しなかった場合に、担保が削減されるリスクがあることを意味します。これも、多くの場合、対象条件モジュールとして実装する方が効果的です。

Hats Trees

すべての帽子が別の帽子を管理者として持つという事実は、すべての帽子が「Hats Trees」の中に存在することを意味します。

このツリー構造が、組織の帽子の基盤を形成します。

特定の帽子ツリーの枝の中では、ツリーの根に近い帽子が、その枝の下位にある帽子に対する管理権限を持っています。

これは、DAO(分散型自律組織)の権限委任の方向性と一致しており、ネットワークの端に権限が委任されるにつれて責任が希薄化する傾向に対抗します。

  • トップハット
    トップハットは、帽子の管理者が必ず別の帽子でなければならないというルールの唯一の例外です。
    トップハットは自分自身を管理者とする帽子です。

    帽子ツリーの根は常にトップハットです。
    通常、DAOは、その運営に関連する帽子のツリーを管理するトップハットを着用します。

  • 帽子ツリーと帽子ID
    各帽子ツリーは最大で15の深さを持ち、各帽子は最大で2^16 = 65,536の子供を持つことができ、このパターンが14回繰り返されます。

    各帽子のIDには、そのツリーのIDとツリー内での位置が含まれます。

Hat IDs

Hat IDは、ツリーの中で帽子がどこに位置しているか、管理者の全枝を含む情報を持つ「アドレス」を作成するためのuint256ビットマップです。
これは、Ethereumのアドレスというよりも、WebやIPアドレスに近いものです。

帽子IDの32バイトは以下のように構成されています:

最初の4バイトはトップハットIDに予約されています。

トップハットIDはHats Protocolの特定のデプロイメント全体で一意であるため、これらを帽子ツリーのトップレベル「ドメイン」と考えることができます。

次の各16ビットのチャンクは、1つの「帽子レベル」を指します。

帽子レベルは合計で15レベルあり、レベル0のトップハットから始まり、レベル14まで続きます。

次のようなHat ID(16進数)を考えてみましょう:

0x0000000f00020005000a00010000000000000000000000000000000000000000

便宜上、IPアドレスのように短縮形に再フォーマットできます:15.2.5.10.1

このIDだけで、この帽子について多くのことがわかります:

Eligibility Modules

Eligibility Modules(適格性モジュール)には、特定の帽子の着用者に関して以下の2つの権限があります。

  • a) 適格性

  • b) 良好な状態にあるかどうか

  • 着用者の適格性
    着用者の適格性 (A) は、特定のアドレスがその帽子を着用する資格があるかどうかを判断します。


    これは、そのアドレスが帽子を着用する前および着用中の両方に適用されます。以下のシナリオを考えてみましょう。

    適格 非適格
    帽子を着用していない場合 帽子をアドレスに発行できる
    現在帽子を着用している場合 帽子を着用し続ける
  • 着用者の状態
    着用者の状態 (B) は、特定のアドレスが良好な状態にあるか、悪い状態にあるかを判断します。


    状態は、Hats.solにオンチェーンで保存され、責任を明確にします。


    例えば、ステーキングロジックを実装しているHatter Contractでは、適格性モジュールによって悪い状態にされた場合、着用者のステークを削減することができます。


    特定の帽子の適格性モジュールによって悪い状態にされたアドレスは、自動的にその帽子の適格性を失います。ただし、非適格であることが必ずしも悪い状態を意味するわけではなく、あるアドレスが非適格であっても、良好な状態である可能性があります。


    任意のアドレスが特定の帽子に対する適格性モジュールとして機能することができます。


    Hats Protocolは、次の2つの種類の適格性モジュールをサポートしています:

    • 機械的適格性
      IHatsEligibilityインターフェースを実装するロジックコントラクトであり、Hats.solコントラクトがHats.balanceOf関数内からcheckWearerStandingを呼び出すことで、着用者の状態を即座に確認できます。事前定義されたトリガーに基づいて即時に帽子を取り消すことが可能です。

    • 人間的適格性
      EOAやガバナンスコントラクト(DAOなど)です。人間的適格性では、帽子を取り消すために、HatsコントラクトにHats.ruleOHatWearerStandingを呼び出して状態を更新する必要があります。

    管理者とは異なり、適格性モジュールは帽子ではなくアドレスとして明示的に設定されます。これは、着用者に対する罰則(ステークの削減など)に影響を与える長くて読みづらい可能性のある取り消し権限の連鎖を避けるためです。

Toggle Modules

Toggle Contractは、帽子のhat.activeステータスをアクティブから非アクティブに切り替える権限を持っています。帽子が非アクティブになると、その帽子の着用者は存在しなくなり(つまり、以前の着用者の残高が0に変更されます)。

任意のアドレスが帽子のトグルとして機能することができます。適格性モジュールと同様に、Hats Protocolは2つのカテゴリのToggle Modulesをサポートしています:

  • 機械的トグル
    IHatsToggleインターフェースを実装するロジックコントラクトであり、Hats.balanceOf関数内からcheckToggleを呼び出すことで、帽子のアクティブステータスを即座に確認し、非アクティブ化(または再アクティブ化)を行います。例えば、「この帽子は年末に期限切れになる」といった事前定義されたロジックに基づいて、即座に非アクティブ化することが可能です。

  • 人間的トグル
    EOAやガバナンスコントラクト(DAOなど)です。帽子を非アクティブ化(または再アクティブ化)するためには、人間的トグルがHatsコントラクトにHats.toggleHatStatusを呼び出して状態を更新する必要があります。

管理者とは異なり、適格性モジュールと同様に、トグルモジュールは帽子ではなく、アドレスとして明示的に設定されます。

Hat Mutability and Editing

場合によっては、帽子の特性が不変であることが、特に着用者にとって、何に同意しているかについて最大限の信頼を提供するために重要です。しかし、この確実性は柔軟性の欠如を意味し、柔軟性はDAOが進化し、様々な役割について学んでいく中で価値を持つことが多いです。このトレードオフを考慮して、Hatsは不変または可変のいずれかで作成することができます。

不変な帽子は、一度作成されると一切変更することができません。

可変な帽子は、作成後に変更することが可能です。変更はその帽子の管理者のみが行えます。

以下の帽子の特性に対する変更が許可されています:

  • 詳細
  • 最大供給量(新しい最大供給量が現在の供給量を下回らない限り)
  • 適格性
  • トグル
  • 可変性(これは一方向の変更です)
  • 画像URI

さらに、可変な帽子は管理者によって異なる着用者に移行することができます。不変な帽子は移行することができません。

  • トップハットの例外
    上記の不変性ルールの唯一の例外は、トップハットです。不変でありながら、自身の詳細と画像URIを変更することが許可されています(ただし、他の特性は変更できません)。

Creating Hats

帽子を作成する者は、その帽子の管理者でなければなりません。言い換えれば、帽子の管理者はHats.createHat関数を呼び出す際のmsg.senderである必要があります。

ただし、管理者が自らの権限をHatter Contractに委任することで、その管理者は、任意のロジックに基づいて他の適格者に帽子を作成させることができます。

トップハット(自分自身が管理者である帽子)を作成するには、特別な関数mintTophatが必要です。

この関数は、新しい帽子を作成し、その帽子を自分自身の管理者として設定し、その後、トークンを_targetにミントします。管理者帽子をまだ持っていないアドレスが帽子を作成したい場合、まず自分自身を着用者としてトップハットを作成する必要があります。

DAOが一度に多くの帽子を作成したい場合、特に全体の帽子ツリーを一度に作成する場合に、バッチ作成が役立ちます。これは、DAOやワーキンググループの初期構造をセットアップする際(例:帽子のテンプレートから)や、既存の帽子構造をテンプレートからフォークする際に特に有用です。

複数の帽子をバッチ作成するために、DAOはHats.batchCreateHats()関数を呼び出すことができます。この関数は配列を引数として受け取り、そこから複数の帽子を構築します。これらの帽子が同じ帽子ツリーの一部である限り(すなわち、既存の帽子または新たに作成された帽子が管理者である場合)、一度にすべての帽子を作成することが可能です。

Minting Hats

帽子のトークンをミントできるのは、その帽子の管理者だけです。

帽子をミントするには以下の条件を満たす必要があります:

  • バッチミント
    管理者はHats.batchMintHatsを呼び出して、複数の帽子を一度にミントすることも可能です。これにより、同じ帽子を複数の着用者にミントしたり、複数の帽子を一度にミントしたり、さらには新しく作成した帽子ツリー全体をミントすることもできます。

Transfering Hats

HatはERC1155ライクなトークンとして発行されるみたいですが、別のアカウントに移転できるのはその帽子の管理者だけのようです。

これは、帽子に関連する権限と責任が、着用者に委任されているものであり、所有されているものではないためです。

そのため、安全な転送(受信者がERC1155に対応しているかを確認する転送)や、受信者にデータを渡すためのon1155ReceivedonERC1155BatchReceivedフックは不要です。

このため、Hats Protocolでは、標準のERC1155転送機能であるsafeTransferFromおよびsafeBatchTransferFromは無効化され、常にエラーが返されます。同様に、トークンの承認は必要なく、setApprovalForAllも常にエラーが返されます。

  • ERC1155互換性
    代替として、帽子は管理者によってHats.transferHatを通じて移転され、ERC1155標準イベントTransferSingleが発行されます。移転の受信者は既にその帽子を着用しておらず、帽子を着用する資格がある必要があります。

トップハット(常に自分自身を移転できるもの)を除き、移転可能なのは、変更可能かつアクティブな帽子のみです。

Renouncing Hats

帽子の着用者は、Hats.renounceHatを通じて自分の帽子を「脱ぐ」ことができます。

これにより、その帽子のトークンは焼却され、元の着用者から関連する権限と責任が取り消されますが、その着用者が不良な立場に置かれることはありません。

Batch Actions

バッチ作成やバッチミントに加えて、Hats.solの関数を一連の処理としてまとめて一つのトランザクションで実行することができます。

これは、Hats.solが継承しているMulticallableによって可能になっています。

この機能は、支払い不要のmulticall関数をコントラクトに追加します。これにより、EOAはコントラクトに対して複数の呼び出しを一括で行うことができ、これまでスマートコントラクトでしか利用できなかった便利なバッチ処理が可能になります。

Hat Image URIs

他のNFTと同様に、ハットには画像があります。
特定のハットの画像は、次のロジックに従って決定されます。

ERC1155 との互換性

Hats Protocolは、ERC1155インターフェースに完全に準拠しています

ERC1155標準で求められるすべての外部関数がHats Protocolによって公開されており、これによりハットは既存のトークンゲートアプリケーションとすぐに連携できます。

ただし、Hats ProtocolはERC1155標準に完全に準拠しているわけではありません。ハットは所有者(つまり「着用者」)によって移転できないため、安全な移転やERC1155TokenReceiverロジックの必要性はほとんどありません。

Hats Protocolを利用する開発者は、たとえば、ハットのミントや移転において、onERC1155Receivedへの呼び出しが含まれないことに注意する必要があります。

Coreコントラクトを見ていこう!!

ではここからは Hats Protocolのコア機能が実装されているスマートコントラクトを確認していきたいと思います!!

コア機能を提供しているコントラクトは以下の4つです。

そしてインターフェース用のファイルとして以下の4つが存在します!

ここからはそれぞれ見ていこうと思います!!

Hats.sol

ソースコード

Hatsは、DAOに特化した取り消し可能かつプログラム可能な役割を表しており、これらは非譲渡のERC-1155に似たトークンとして実装されています。

このHats.solは、指定されたブロックチェーン上で全てのHatsを管理するマルチテナントコントラクトです。

ERC1155インターフェースを完全に実装しているものの、ERC1155標準には完全には準拠していません。

ステート変数

  • name
    コントラクトの名前(通常はバージョンを含む)

    string public name;
    
  • lastTopHatId

    最後に作成されたトップハットのIDの最初の4バイト

    uint32 public lastTopHatId;
    
  • baseImageURI
    画像URIが指定されていないハットトークンのためのフォールバック画像URI

    string public baseImageURI;
    
  • _hats
    ハットとハットIDの内部マッピング。
    ハットIDの仕組みについては、HatsIdUtilities.solを参照

    mapping(uint256 => Hat) internal _hats;
    
  • badStandings
    特定のハットの着用者が不良状態にあることを示すマッピング。
    外部のコントラクトで、ペナルティを課すために使用される。

    mapping(uint256 => mapping(address => bool)) public badStandings;
    

関数

  • mintTopHat
    自身が管理者であるハット、つまり「トップハット」を作成し、ミントする関数。トップハットには適格性やトグルがない。

    function mintTopHat(
      address _target, 
      string calldata _details, 
      string calldata _imageURI
    ) public returns (uint256 topHatId);
    
  • createHat
    新しいハットを作成する関数。
    msg.sender_adminハットを着用している必要がある。新しいHat構造体を初期化するが、トークンはミントされない。

    function createHat(
        uint256 _admin,
        string calldata _details,
        uint32 _maxSupply,
        address _eligibility,
        address _toggle,
        bool _mutable,
        string calldata _imageURI
    ) public returns (uint256 newHatId);
    
  • batchCreateHats
    複数のハットを一括で作成する関数。
    msg.senderはそれぞれのハットの管理者である必要がある。

    function batchCreateHats(
        uint256[] calldata _admins,
        string[] calldata _details,
        uint32[] calldata _maxSupplies,
        address[] memory _eligibilityModules,
        address[] memory _toggleModules,
        bool[] calldata _mutables,
        string[] calldata _imageURIs
    ) public returns (bool success);
    
  • getNextId
    次の子ハットのIDを取得する関数。lastHatIdはインクリメントされない。

    function getNextId(uint256 _admin) public view returns (uint256 nextId);
    
  • mintHat
    適格な受領者にハットのERC1155に似たトークンをミントし、受領者がそのハットを「着用」する関数。

    function mintHat(
      uint256 _hatId, 
      address _wearer
    ) public returns (bool success);
    
  • batchMintHats
    複数のハットを一括でミントする関数。msg.senderはそれぞれのハットの管理者である必要がある。

    function batchMintHats(
      uint256[] calldata _hatIds, 
      address[] calldata _wearers
    ) public returns (bool success);
    
  • setHatStatus
    ハットの状態をアクティブから非アクティブ、またはその逆に切り替える関数。

    msg.senderはそのハットのトグルとして設定されている必要がある。

    function setHatStatus(
      uint256 _hatId, 
      bool _newStatus
    ) external returns (bool toggled);
    
  • checkHatStatus
    ハットのトグルモジュールをチェックし、返された状態を処理する関数。ストレージ内のハットの状態を変更する可能性がある。

    function checkHatStatus(uint256 _hatId) public returns (bool toggled);
    
  • setHatWearerStatus
    ハットの適格性モジュールが報告する着用者の状態を報告し、falseであればそのハットを取り消す関数。
    取り消された場合、着用者のハットはバーンされる。

    function setHatWearerStatus(
      uint256 _hatId, 
      address _wearer, 
      bool _eligible, 
      bool _standing
    ) external returns (bool updated);
    
  • checkHatWearerStatus
    ハットの適格性モジュールに着用者の状態を報告するように要求し、falseであればそのハットを取り消す関数。

    取り消された場合、着用者のハットはバーンされる。

    function checkHatWearerStatus(
      uint256 _hatId, 
      address _wearer
    ) public returns (bool updated);
    
  • renounceHat
    ハットを「放棄」する関数。msg.senderのハットをバーンする。

    function renounceHat(uint256 _hatId) external;
    
  • transferHat
    ハットを一つの着用者から他の適格な着用者へ移す関数。
    ハットは可変である必要があり、管理者によって転送が開始される必要がある。

    function transferHat(
      uint256 _hatId, 
      address _from, 
      address _to
    ) public;
    
  • makeHatImmutable
    可変ハットを不変に設定する関数。hat.configの2番目のビットを0に設定する。

    function makeHatImmutable(uint256 _hatId) external;
    
  • changeHatDetails
    ハットの詳細を変更する関数。ハットは可変である必要があるが、トップハットは例外。

    function changeHatDetails(
      uint256 _hatId, 
      string calldata _newDetails
    ) external;
    
  • changeHatEligibility
    ハットの適格性モジュールを変更する関数。ハットは可変である必要がある。

    function changeHatEligibility(
      uint256 _hatId, 
      address _newEligibility
    ) external;
    
  • changeHatToggle
    ハットのトグルモジュールを変更する関数。ハットは可変である必要がある。

    function changeHatToggle(
      uint256 _hatId, 
      address _newToggle
    ) external;
    
  • changeHatImageURI
    ハットの画像URIを変更する関数。ハットは可変である必要があり、トップハットは例外。

    function changeHatImageURI(uint256 _hatId, string calldata _newImageURI) external;
    
  • changeHatMaxSupply
    ハットの最大供給量を変更する関数。ハットは可変である必要があり、新しい最大供給量は現在の供給量より少なくできない。

    function changeHatMaxSupply(
      uint256 _hatId, 
      uint32 _newMaxSupply
    ) external;
    
  • requestLinkTopHatToTree
    ハットツリーを親ツリーにリンクするためのリクエストを送信する関数。

    function requestLinkTopHatToTree(
      uint32 _topHatDomain, 
      uint256 _requestedAdminHat
    ) external;
    
  • approveLinkTopHatToTree
    ハットツリーを親ツリーにリンクするリクエストを承認する関数。
    リンク先の適格性やトグルモジュールを追加し、メタデータを変更するオプションがある。

    function approveLinkTopHatToTree(
      uint32 _topHatDomain,
      uint256 _newAdminHat,
      address _eligibility,
      address _toggle,
      string calldata _details,
      string calldata _imageURI
    ) external;
    
  • unlinkTopHatFromTree
    親ツリーとのリンクを解除し、トグルと適格性を削除する関数。画像URIはbaseImageURIにリセットされる。

    function unlinkTopHatFromTree(uint32 _topHatDomain) external;
    
  • viewHat
    指定されたハットIDに対応するハットのメタデータを返す関数。

    ハットIDの仕組みについてはHatsIdUtilities.solを参照。

    function viewHat(uint256 _hatId) public view returns (
        uint256 id,
        uint256 admin,
        string memory details,
        uint32 maxSupply,
        address eligibility,
        address toggle,
        bool mutable,
        string memory imageURI,
        uint32 supply,
        bool active
    );
    
  • balanceOf
    特定のアドレスが所有する特定のハットの数を返す関数。

    function balanceOf(
      address _wearer, 
      uint256 _hatId
    ) public view override returns (uint256 balance);
    
  • ownerOf
    現在の所有者のリストを返す関数。着用者のみを対象とし、最大20の結果を返す。ページネーションのサポートを計画。

    function ownerOf(uint256 _hatId) public view returns (address[] memory owners);
    
  • isWearerOfHat
    指定されたアドレスが指定されたハットを着用しているかどうかを返す関数。

    function isWearerOfHat(
      address _wearer, 
      uint256 _hatId
    ) public view returns (bool isWearer);
    
  • isActive
    ハットがアクティブかどうかを確認する関数。

    function isActive(uint256 _hatId) public view returns (bool active);
    
  • isInGoodStanding
    ハットの着用者が不良状態でないかを確認する関数。

    function isInGoodStanding(
      uint256 _hatId, 
      address _wearer
    ) public view returns (bool good);
    
  • isAdminOfHat
    指定されたアドレスが特定のハットの管理者であるかどうかを確認する関数。

    _hatIdの管理者が_wearerの所有する他のハットである場合、真を返す。

    function isAdminOfHat(
      address _wearer, 
      uint256 _hatId
    ) public view returns (bool isAdmin);
    
  • getImageURIForHat
    ハットの画像URIを取得する関数。
    画像URIが設定されていない場合はbaseImageURIを返す。

    function getImageURIForHat(uint256 _hatId) public view returns (string memory uri);
    
  • uri
    ハットトークンのERC-1155標準準拠のURIメソッド。

    function uri(uint256 _hatId) public view override returns (string memory);
    
  • supportsInterface
    特定のインターフェースをサポートしているかどうかを確認する関数。

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155) returns (bool);
    
  • _beforeTokenTransfer
    トークンの転送前に実行される内部関数。

    function _beforeTokenTransfer(
      address operator, 
      address from, 
      address to, 
      uint256[] memory ids, 
      uint256[] memory amounts, 
      bytes memory data
    ) internal virtual override;
    

構造体

Hatという構造体が定義されています。

struct Hat {
  address eligibility; // 適格性モジュールのアドレス
  uint32 maxSupply; // 最大供給量
  uint32 supply; // 現在の供給量
  uint16 lastHatId; // 最後のハットID
  address toggle; // トグルモジュールのアドレス
  uint96 config; // 構成データ
  string details; // ハットの詳細
  string imageURI; // ハットの画像URI
}

HatsEvents.sol

ソースコード

このコントラクトでは各種イベントが定義されています。

  • HatCreated
    新しいハットが作成された時に発行されるイベント

    event HatCreated(
      uint256 id, 
      string details, 
      uint32 maxSupply, 
      address eligibility, 
      address toggle, 
      bool mutable_, 
      string imageURI
    );
    
  • WearerStandingChanged
    ハットを着用している人のステータスが更新された時に発行されるイベント

    適格性(Eligibility)は含まれていません。適格性の真偽は適格性モジュールによって管理され、トランザクションなしで変更されることがあるためです。

    event WearerStandingChanged(
      uint256 hatId, 
      address wearer, 
      bool wearerStanding
    );
    
  • HatStatusChanged
    ハットのステータスが更新された時に発行されるイベント

    event HatStatusChanged(uint256 hatId, bool newStatus);
    
  • HatDetailsChanged
    ハットの詳細が更新された時に発行されるイベント

    event HatDetailsChanged(uint256 hatId, string newDetails);
    
  • HatEligibilityChanged
    ハットの適格性モジュールが更新された時に発行されるイベント

    event HatEligibilityChanged(uint256 hatId, address newEligibility);
    
  • HatToggleChanged
    ハットのトグルモジュールが更新された時に発行されるイベント

    event HatToggleChanged(uint256 hatId, address newToggle);
    
  • HatMutabilityChanged
    ハットの可変性が更新された時に発行されるイベント

    event HatMutabilityChanged(uint256 hatId);
    
  • HatMaxSupplyChanged
    ハットの最大供給量が更新された時に発行されるイベント

    event HatMaxSupplyChanged(uint256 hatId, uint32 newMaxSupply);
    
  • HatImageURIChanged
    ハットの画像URIが更新された時に発行されるイベント

    event HatImageURIChanged(uint256 hatId, string newImageURI);
    
  • TopHatLinkRequested
    トッパーハットのリンクがその管理者によってリクエストされた時に発行されるイベント

    event TopHatLinkRequested(uint32 domain, uint256 newAdmin);
    
  • TopHatLinked
    トッパーハットが別のツリーにリンクされた時に発行されるイベント

    event TopHatLinked(uint32 domain, uint256 newAdmin);
    

HatsErrors.sol

ソースコード

このファイルではHatsProtocolで利用するカスタムエラーが定義されています。

  • NotAdmin
    ユーザーが hatId に対してアクションを試みたが、その hatId の管理者ハットのいずれも着用していない場合に発生するエラーです。

    approveLinkTopHatToTreerelinkTopHatToTree などの操作で発生する可能性があります。

    error NotAdmin(address user, uint256 hatId);
    
  • NotHatWearer
    指定されたハットの着用者でないアカウントとして、またはそのアカウントのためにアクションを実行しようとした場合に発生するエラーです。

    error NotHatWearer();
    
  • NotAdminOrWearer
    指定されたハットの管理者または着用者である必要があるアクションを試みた場合に発生するエラーです。

    error NotAdminOrWearer();
    
  • AllHatsWorn
    hatId をミントしようとしたが、その hatId の最大供給量が達成されている場合に発生するエラーです。

    error AllHatsWorn(uint256 hatId);
    
  • MaxLevelsReached
    レベル14のハットを管理者として持つハットを作成しようとした場合に発生するエラーです。

    error MaxLevelsReached();
    
  • InvalidHatId
    試みたハットIDに中間レベルが空である場合に発生するエラーです。

    error InvalidHatId();
    
  • AlreadyWearingHat
    既にそのハットを着用している着用者に対して hatId をミントしようとした場合に発生するエラーです。

    error AlreadyWearingHat(address wearer, uint256 hatId);
    
  • HatDoesNotExist
    存在しないハットをミントしようとした場合に発生するエラーです。

    error HatDoesNotExist(uint256 hatId);
    
  • HatNotActive
    アクティブでないハットをミントまたは転送しようとした場合に発生するエラーです。

    error HatNotActive();
    
  • NotEligible
    適格でない着用者に対してハットをミントまたは転送しようとした場合に発生するエラーです。

    error NotEligible();
    
  • NotHatsToggle
    ハットのステータスを確認または設定しようとしたが、そのアカウントがそのハットのトグルモジュールでない場合に発生するエラーです。

    error NotHatsToggle();
    
  • NotHatsEligibility
    ハットの着用者のステータスを確認または設定しようとしたが、そのアカウントがそのハットの適格性モジュールでない場合に発生するエラーです。

    error NotHatsEligibility();
    
  • BatchArrayLengthMismatch
    バッチ関数に渡す配列の引数の長さが一致しない場合に発生するエラーです。

    error BatchArrayLengthMismatch();
    
  • Immutable
    変更または転送が不可能なハットを試みた場合に発生するエラーです。

    error Immutable();
    
  • NewMaxSupplyTooLow
    ハットの maxSupply を現在の供給量よりも低い値に変更しようとした場合に発生するエラーです。

    error NewMaxSupplyTooLow();
    
  • CircularLinkage
    トッパーハットを新しい管理者にリンクしようとしたが、そのトッパーハットが新しい管理者の管理下にある場合に発生するエラーです。

    error CircularLinkage();
    
  • CrossTreeLinkage
    トッパーハットを別のツリーにリンクまたは再リンクしようとした場合に発生するエラーです。

    error CrossTreeLinkage();
    
  • LinkageNotRequested
    トッパーハットのリンクがリクエストなしで試みられた場合に発生するエラーです。

    error LinkageNotRequested();
    
  • InvalidUnlink
    着用者が存在しないトッパーハットのリンク解除を試みた場合に発生するエラーです。これにより、リンク解除がトッパーハットを壊すことはありません。

    error InvalidUnlink();
    
  • ZeroAddress
    ハットの適格性またはトグルモジュールをゼロアドレスに変更しようとした場合に発生するエラーです。

    error ZeroAddress();
    
  • StringTooLong
    ハットの詳細や画像URIを7000バイト(約7000文字)を超える文字列に変更しようとした場合に発生するエラーです。これにより、管理者がハットの詳細や画像URIを長くしすぎて読み込みがブロックのガス制限を超えることを防ぎます。

    error StringTooLong();
    

HatsUtillities.sol

ソースコード

このコントラクトではHatsProtocolで使える便利な共通メソッドや変数が実装されています。

ステート変数

  • linkedTreeRequests
    他のツリーの管理者ハットにリンクを要求するトッパーハットのマッピング

    リクエストが新しい管理者によって承認されるとリンクが行われます。

    mapping(uint32 => uint256) public linkedTreeRequests;
    
  • linkedTreeAdmins
    他のツリーの管理者ハットに承認されてリンクされたトッパーハットのマッピング。ハットツリーを別のツリーに接ぎ木するために使用します。

    ツリーはトッパーハットを介してのみ別のツリーにリンクできます。

    mapping(uint32 => uint256) public linkedTreeAdmins;
    
  • TOPHAT_ADDRESS_SPACE
    ハットIDはアドレスとして機能します。指定されたハットのIDは、そのハットツリー内での位置を表します:レベル、管理者、管理者の管理者(など、トッパーハットまで上昇)。最上位レベルは4バイトで構成され、すべてのトッパーハットを参照します。下の各レベルは16ビットで構成され、最大65,536個の子ハットを含むことができます。uint256 は4バイトのトッパーハットアドレスのスペースを持ち、((256 - 32) / 16) = 14レベルの委任をサポートし、各レベルの管理者は65,536個の異なる子ハットのスペースを持ちます。ハットツリーは単一のトッパーハットで構成され、最大14レベルの深さがあります。

    uint256 internal constant TOPHAT_ADDRESS_SPACE = 32;
    
  • LOWER_LEVEL_ADDRESS_SPACE
    トッパーハットの下にある各レベルのアドレススペースのビット数です。

    uint256 internal constant LOWER_LEVEL_ADDRESS_SPACE = 16;
    
  • MAX_LEVELS
    トッパーハットの下の最大レベル数、つまりツリーの最大深さです。

    計算式は (256 - TOPHAT_ADDRESS_SPACE) / LOWER_LEVEL_ADDRESS_SPACE です。

    uint256 internal constant MAX_LEVELS = 14;
    

関数

  • buildHatId
    指定された管理者の下に新しいハットの有効なIDを構築します。

    管理者がすでに MAX_LEVELS に達している場合は、リバートします。

    /**
      * @param _admin 新しい帽子の管理者のID
      * @param _newHat 新しい帽子のID
      * @return id 構築された帽子のID
      */
    function buildHatId(
      uint256 _admin, 
      uint16 _newHat
    ) public pure returns (uint256 id);
    
  • getHatLevel
    指定されたハットがそのハットツリー内でのレベルを識別します。

    /**
     * @param _hatId 調べる帽子のID
     * @return level 帽子のツリー内でのレベル
     */
    function getHatLevel(uint256 _hatId) public view returns (uint32 level);
    
  • getLocalHatLevel
    指定されたハットがそのローカルハットツリー内でのレベルを識別します。

    getHatLevel と似ていますが、リンクされたツリーは考慮しません。

    /**
     * @param _hatId 調べる帽子のID
     * @return level ローカルツリー内での帽子のレベル
     */
    function getLocalHatLevel(uint256 _hatId) public pure returns (uint32 level);
    
  • isTopHat
    ハットがトッパーハットであるかどうかを確認します。

    /**
     * @param _hatId 調べる帽子のID
     * @return _isTopHat 帽子がトップハットであるかどうか
     */
    function isTopHat(uint256 _hatId) public view returns (bool _isTopHat);
    
  • isLocalTopHat
    ハットがそのローカルハットツリー内でトッパーハットであるかどうかを確認します。

    isTopHat と似ていますが、リンクされたツリーは考慮しません。

    /**
     * @param _hatId 調べる帽子のID
     * @return _isLocalTopHat 帽子がローカルツリーのトップハットであるかどうか
     */
    function isLocalTopHat(uint256 _hatId) public pure returns (bool _isLocalTopHat);
    
  • isValidHatId
    ハットIDが有効かどうかを確認します。

    /**
     * @param _hatId 調べる帽子のID
     * @return validHatId 帽子のIDが有効であるかどうか
     */
    function isValidHatId(uint256 _hatId) public pure returns (bool validHatId);
    
  • getAdminAtLevel
    指定されたハットの指定レベルの管理者ハットのIDを取得します。

    この関数は、linkedTreeAdmin ポインタをたどって、別のツリーにあるハットを探します。

    /**
     * @param _hatId 調べる帽子のID
     * @param _level 調べるレベル
     * @return admin 指定レベルの管理者の帽子ID
     */
    function getAdminAtLevel(
      uint256 _hatId, 
      uint32 _level
    ) public view returns (uint256 admin);
    
  • getAdminAtLocalLevel
    指定されたハットがそのツリー内での指定レベルの管理者ハットのIDを取得します。

    /**
     * @param _hatId 調べる帽子のID
     * @param _level 調べるレベル
     * @return admin ローカルツリー内で指定レベルの管理者の帽子ID
     */
    function getAdminAtLocalLevel(
      uint256 _hatId, 
      uint32 _level
    ) public pure returns (uint256 admin);
    
  • getTopHatDomain
    指定されたハットのトッパーハットドメインを取得します。

    ドメインはハットIDの最初の4バイトに格納されている、ハットツリーの識別子です。

    /**
     * @param _hatId 調べる帽子のID
     * @return domain 帽子のトップハットドメイン
     */
    function getTopHatDomain(uint256 _hatId) public pure returns (uint32 domain);
    
  • getTippyTopHatDomain
    最も高い親トッパーハット、いわゆる「ティッピートッパーハット」のドメインを取得します。

    /**
     * @param _topHatDomain 調べるトップハットドメイン
     * @return domain 最高の親トップハットのドメイン
     */
    function getTippyTopHatDomain(uint32 _topHatDomain) public view returns (uint32 domain);
    
  • noCircularLinkage
    ツリーの循環リンクがないかをチェックします。

    /**
     * @param _topHatDomain リンクするツリーのドメイン
     * @param _linkedAdmin リンク先の管理者の帽子ID
     * @return notCircular 円環状リンクが見つからなかった場合にtrue
     */
    function noCircularLinkage(
      uint32 _topHatDomain, 
      uint256 _linkedAdmin
    ) public view returns (bool notCircular);
    
  • sameTippyTopHatDomain
    トッパーハットドメインとそのポテンシャルリンク管理者が同じツリーから来ていること、つまり同じティッピートッパーハットドメインを持っていることを確認します。

    /**
     * @param _topHatDomain リンクするトップハットのドメイン
     * @param _newAdminHat 新しいリンク先の管理者の帽子ID
     * @return sameDomain トップハットドメインと新しい管理者のドメインが同じかどうか
     */
    function sameTippyTopHatDomain(
      uint32 _topHatDomain, 
      uint256 _newAdminHat
    ) public view returns (bool sameDomain);
    

SDKを見ていこう!!

Coreコントラクトを細かく確認したので次は SDK についての細かく確認していきましょう!!

公式ドキュメントでは以下のページで確認できます!!

https://docs.hatsprotocol.xyz/for-developers/v1-sdk

読み取り系のメソッド

  • viewHat
    帽子のプロパティを取得します。

    const hat = await hatsClient.viewHat(hatId);
    

    取得できるプロパティは以下の通り

    {
      details: string;
      maxSupply: number;
      supply: number;
      eligibility: Address;
      toggle: Address;
      imageUri: string;
      numChildren: number;
      mutable: boolean;
      active: boolean;
    }
    
  • isWearerOfHat
    特定の帽子を着用しているかどうかをチェックします。

    const isWearer = await hatsClient.isWearerOfHat({
      wearer,
      hatId,
    })
    
  • isAdminOfHat
    特定の帽子の管理者であるかどうかをチェックします。

    const isAdmin = await hatsClient.isAdminOfHat({
      user,
      hatId,
    });
    
  • isActive
    帽子がアクティブかどうかをチェックします。

    const isActive = await hatsClient.isActive(hatId);
    
  • isInGoodStanding
    特定の帽子の着用者が「良好な状態」にあるかどうかをチェックします。

    const isGoodStanding = await hatsClient.isInGoodStanding({
      wearer,
      hatId,
    });
    
  • isEligible
    特定の帽子に対してアドレスが適格であるかどうかをチェックします。

    const isEligible = await hatsClient.isEligible({
      wearer,
      hatId,
    });
    
  • predictHatId
    まだ作成されていない帽子のIDを予測します。

    const hatId = await hatsClient.predictHatId(admin);
    
  • getTreesCount
    存在するツリーの数を取得します。

    const numTrees = await hatsClient.getTreesCount();
    
  • getLinkageRequest

    ツリーのリンクリクエストを取得します。

    const requestedAdminHat = await hatsClient.getLinkageRequest(topHatDomain);
    
  • getLinkedTreeAdmin
    リンクされたツリーの管理者を取得します(TopperHatがリンクされている帽子)。

    const adminHat = await hatsClient.getLinkedTreeAdmin(topHatDomain);
    
  • getHatLevel
    帽子のレベルを取得します。ツリーがリンクされている場合、レベルはグローバルツリー(すべてのリンクツリーを含む)で計算されます。

    const level = await hatsClient.getHatLevel(hatId);
    
  • getLocalHatLevel
    ローカルツリー内での帽子のレベルを取得します(リンクされたツリーを考慮しません)。

    const level = await hatsClient.getLocalHatLevel(hatId);
    
  • getTopHatDomain
    帽子のツリードメインを取得します。

    const domain = await hatsClient.getTopHatDomain(hatId);
    
  • getTippyTopHatDomain
    指定されたツリーが含まれるグローバルツリーのトッパーハット(「ティッピートッパーハット」)のツリードメインを取得します。

    const domain = await hatsClient.getTippyTopHatDomain(topHatDomain);
    
  • getAdmin
    帽子の直接の管理者を取得します。

    const admin = await hatsClient.getAdmin(hatId);
    
  • getChildrenHats
    帽子の子供の帽子を取得します。

    const children = await hatsClient.getChildrenHats(hatId);
    

書き込み系のメソッド

続いてSDKに用意されている書き込み系の処理を見ていきましょう!!

  • mintTopHat
    新しいトップハットを作成する(新しいツリーを作成する)。

    const mintTopHatResult = await hatsClient.mintTopHat({
      account,
      target,
      details,
      imageURI,
    });
    
  • createHat
    ハットを作成する。

    const createHatResult = await hatsClient.createHat({
      account,
      admin,
      details,
      maxSupply,    //ハットの最大着用者数。
      eligibility,  // ハットの適格性アドレス(ゼロアドレスは無効)。
      toggle,       // ハットのトグルアドレス(ゼロアドレスは無効)。
      mutable,      // ハットを変更可能にする場合はtrue、そうでない場合はfalse。
      imageURI,     // 任意のハットの画像URI。
    });
    
  • batchCreateHats
    複数のハットを作成する。

    const batchCreateHatsResult = await hatsClient.batchCreateHats({
      account,
      admins,
      details,
      maxSupplies,
      eligibilityModules,
      toggleModules,
      mutables,
      imageURIs,
    });
    
  • ハットをミントする

    const mintHatResult = await hatsClient.mintHat({
      account,
      hatId,
      wearer,
    });
    
  • batchMintHats
    複数のハットをミント(発行)する。

    const batchMintHatsResult = await hatsClient.batchMintHats({
      account,
      hatIds,
      wearers,
    });
    
  • setHatStatus
    ハットのステータスをアクティブ/非アクティブに設定する。

    const setHatStatusResult = await hatsClient.setHatStatus({
      account,
      hatId,
      newStatus,
    });
    
  • checkHatStatus
    トグルモジュールを呼び出してハットのステータスを確認し、必要に応じてステータスを更新する。

    const checkHatStatusResult = await hatsClient.checkHatStatus({
      account,
      hatId,
    });
    
  • setHatWearerStatus
    ハットの着用者のステータスを設定する。

    const setHatWearerStatusResult = await hatsClient.setHatWearerStatus({
      account,
      hatId,
      wearer,
      eligible,
      standing,
    });
    
  • checkHatWearerStatus
    ハットの着用者のステータスを確認し、必要に応じて更新する。

    const checkHatWearerStatusResult = await hatsClient.checkHatWearerStatus({
      account,
      hatId,
      wearer,
    });
    
  • transferHat
    ハットを別のユーザーに譲渡する。

    const transferHatResult = await hatsClient.transferHat({
      account,
      hatId,
      from,
      to,
    });
    
  • renounceHat
    ユーザーが自分のハットを放棄する。

    const renounceHatResult = await hatsClient.renounceHat({
      account,
      hatId,
      wearer,
    });
    
  • changeHatDetails
    ハットの詳細を変更する。

    const changeHatDetailsResult = await hatsClient.changeHatDetails({
      account,
      hatId,
      newDetails,
    });
    
  • changeHatEligibility
    ハットの適格性モジュールを変更する。

    const changeHatEligibilityResult = await hatsClient.changeHatEligibility({
      account,
      hatId,
      newEligibility,
    });
    
  • changeHatToggle
    ハットのトグルモジュールを変更する。

    const changeHatToggleResult = await hatsClient.changeHatToggle({
      account,
      hatId,
      newToggle,
    });
    
  • changeHatMutable
    ハットの変更可能フラグを更新する。

    const changeHatMutableResult = await hatsClient.changeHatMutable({
      account,
      hatId,
      newMutable,
    });
    
  • changeHatImageURI
    ハットの画像URIを更新する。

    const changeHatImageURIResult = await hatsClient.changeHatImageURI({
      account,
      hatId,
      newImageURI,
    });
    
  • changeHatName
    ハットの名前を変更する。

    const changeHatNameResult = await hatsClient.changeHatName({
      account,
      hatId,
      newName,
    });
    
  • setHatStatus
    ハットのステータスを直接設定する。

    const setHatStatusResult = await hatsClient.setHatStatus({
      account,
      hatId,
      wearer,
      eligible,
      standing,
    });     
    
  • revokeHatWearer
    特定の着用者からハットを取り上げる。

    const renounceHatResult = await hatsClient.renounceHat({
      account,
      hatId,
    });
    

MuitiCall

一括で複数のトランザクションを実行することもできます!!

const multicallResult = await hatsClient.multicall({
    account,
    calls,
});

callsに実行させたいトランザクションのデータを詰めます。

{
  account: Account | Address;
  calls: {
    functionName: string;
    callData: Hex;
  }[];
}

例えば以下のように用意します。

const mintTopHatCallData = await hatsClient.mintTopHatCallData({
    target,
    details,
    imageURI,
});

const createHatCallData = await hatsClient.createHatCallData({
    admin,
    details,
    maxSupply,
    eligibility,
    toggle,
    mutable,
    imageURI,
});

const mintHatCallData = await hatsClient.mintHatCallData({
    hatId,
    wearer,
});

const multiCallResult = await hatsClient.multicall({
    account,
    calls: [
      mintTopHatCallData, 
      createHatCallData, 
      mintHatCallData
    ],
});

multicallPreFlightCheck というマルチコール用のシミュレート関数があります。

await hatsClient.multicallPreFlightCheck({
  account,
  calls,
});

ClaimHat

Hat関連で便利な関数がいくつか用意されています。

  • accountCanClaim
    アカウントが特定のハットを請求できるかどうかを確認します。

    const canClaim = await hatsClient.accountCanClaim({
      hatId,
      account,
    });
    
  • canClaimForAccount
    特定のアカウントの代わりにハットを請求できるかどうかを確認します。

    const canClaimFor = await hatsClient.canClaimForAccount({
      hatId,
      account,
    });
    
  • claimHat
    呼び出し元のアカウントのためにハットを請求します。

    const claimHatResult = await hatsClient.claimHat({
      account,
      hatId,
    });
    
  • claimHatFor
    選択されたアカウントの代わりにハットを請求します。

    const claimHatForResult = await hatsClient.claimHatFor({
      account,
      hatId,
      wearer,
    });
    
  • multiClaimHatFor
    複数のアカウントの代わりにハットを請求します。

    const claimHatForResult = await hatsClient.multiClaimHatFor({
      account,
      hatId,
      wearers,
    });
    

便利な機能

他にもSDKには便利な機能がいくつか用意されています!!

  • hatIdDecimalToHex
    ハットIDを10進数から16進数に変換します。

    import { hatIdDecimalToHex } from "@hatsprotocol/sdk-v1-core";
    
    const hatIdHex = hatIdDecimalToHex(hatId);
    
  • hatIdHexToDecimal
    ハットIDを16進数から10進数に変換します。

    import { hatIdHexToDecimal } from "@hatsprotocol/sdk-v1-core";
    
    const hatIdDecimal = hatIdHexToDecimal(hatId);
    
  • treeIdDecimalToHex
    ツリーIDを10進数から16進数に変換します。ツリーIDはハットIDの最初の4バイトです。

    import { treeIdDecimalToHex } from "@hatsprotocol/sdk-v1-core";
    
    const treeIdHex = treeIdDecimalToHex(treeId);
    
  • treeIdHexToDecimal
    ツリーIDを16進数から10進数に変換します。ツリーIDはハットIDの最初の4バイトです。

    import { treeIdHexToDecimal } from "@hatsprotocol/sdk-v1-core";
    
    const treeIdDecimal = treeIdHexToDecimal(treeId);
    
  • treeIdToTopHatId
    ツリーIDをトップハットIDに変換します。ツリーIDはハットIDの最初の4バイトです。

    import { treeIdToTopHatId } from "@hatsprotocol/sdk-v1-core";
    
    const tophatId = treeIdToTopHatId(treeId);
    
  • hatIdToTreeId
    ハットIDをツリーIDに変換します。ツリーIDはハットIDの最初の4バイトです。

    import { hatIdToTreeId } from "@hatsprotocol/sdk-v1-core";
    
    const treeId = hatIdToTreeId(hatId);
    
  • hatIdDecimalToIp
    IP形式は、見栄えの良いハットID形式として使用されることがあります。

    例えば、16進数IDが 0x00000001000a0002000000000000000000000000000000000000000000000000 であるハットは、IP形式で 1.10.2 となります。各レベルはドットで区切られ、ゼロを除いて10進数として表示されます。

    import { hatIdDecimalToIp } from "@hatsprotocol/sdk-v1-core";
    
    const hatIdIp = hatIdDecimalToIp(hatId);
    
  • hatIdIpToDecimal
    ハットIDをIP形式から10進数形式に変換します。

    import { hatIdIpToDecimal } from "@hatsprotocol/sdk-v1-core";
    
    const hatIdDecimal = hatIdIpToDecimal(hatId);
    

Subgraph用のSDKについて

HatsProtocolでは SubGraphも用意されています!!

既に用意されているサブグラフのエンドポイントは以下の通りです!!

https://docs.hatsprotocol.xyz/for-developers/v1-subgraphs

詳しい使い方は以下のドキュメントから確認ができます!!

https://docs.hatsprotocol.xyz/for-developers/v1-sdk/subgraph/getting-started

https://docs.hatsprotocol.xyz/for-developers/v1-sdk/subgraph/fetching-hats

https://docs.hatsprotocol.xyz/for-developers/v1-sdk/subgraph/fetching-wearers

https://docs.hatsprotocol.xyz/for-developers/v1-sdk/subgraph/fetching-trees

Sepolia の場合は以下がエンドポイントのようですね

https://api.studio.thegraph.com/query/55784/hats-v1-sepolia/version/latest

Hatsや着用者、ツリー情報の情報を取得することが可能みたいです。

取得できるデータの種類については、下記サイトで確認ができます!!

https://docs.hatsprotocol.xyz/for-developers/v1-sdk/subgraph/types

  • SDKインスタンスの生成例

    import {HatsSubgraphClient} from "@hatsprotocol/sdk-v1-subgraph";
    import {optimism, sepolia} from "viem/chains";
    
    // Subgraph用のインスタンスを生成
    const hatsSubgraphClient = new HatsSubgraphClient({
      config: {
        [sepolia.id]: {
          endpoint:
            "https://api.studio.thegraph.com/query/55784/hats-v1-sepolia/version/latest",
        },
        [optimism.id]: {
          endpoint:
            "https://api.studio.thegraph.com/query/55784/hats-v1-optimism/version/latest",
        },
      },
    });
    
  • SDKインスタンスの使用例

    上記で生成したインスタンスは次のように使うことができます!

    // hatの情報を取得する。
    const hat = await hatsSubgraphClient.getHat({
      chainId: 10, // optimism
      hatId: BigInt(
        "0x0000000100020001000100000000000000000000000000000000000000000000"
      ),
      props: {
        maxSupply: true, // get the maximum amount of wearers for the hat
        wearers: {
          // get the hat's wearers
          props: {}, // for each wearer, include only its ID (address)
        },
        events: {
          // get the hat's events
          props: {
            transactionID: true, // for each event, include the transaction ID
          },
          filters: {
            first: 10, // fetch only the latest 10 events
          },
        },
      },
    });
    
    console.log("hat:", hat);
    

Hats モジュール

Hatsモジュールとは、Eligibilityモジュール、Toggleモジュール、またはHatterコントラクトとして機能する任意のコントラクトを指します。

モジュールは、Hats Protocolの動作をカスタマイズ、自動化、拡張するもので、他のプロトコルやアプリケーションとのアダプターや統合ポイントとしても機能します。

ある意味で、モジュールはHats Protocolの生命線です。

デザインの幅は広く、組織や協調のためのあらゆる構成要素を作り出す可能性に満ちています。

開発者がHatsモジュールを扱うには、主に二つの方法があります。

  • 既存のモジュールと連携する方法

    Modules SDK を使います!!

    • 必要なライブラリをインストールする方法

      yarn add @hatsprotocol/modules-sdk viem
      
    • セットアップ

      以下のようにセットアップするようです。

      Subgraph用のSDKとほぼ同じですね!

      import { HatsModulesClient } from "@hatsprotocol/modules-sdk";
      
      const hatsModulesClient = new HatsModulesClient({
          publicClient,
          walletClient,
      });
      
    • HatsModule SDKが提供している機能をみていこう!

      • prepare

        この関数は、モジュールレジストリからデータを取得します。

        https://github.com/Hats-Protocol/modules-registry

        このステップは、クライアントを使用できるようにするために必要です。

        さらに、この関数はオプションでレジストリを入力として受け取ることができ、ユーザーのキャッシュをサポートします。もしレジストリが提供された場合、クライアントはレジストリからデータを取得する代わりに、提供されたモジュールを使用します。

        await hatsModulesClient.prepare();
        
      • getModules

        使用可能なモジュール一覧を取得するメソッド

        const modules = hatsModulesClient.getAllModules();
        
      • getModuleById

        モジュールIDを指定してモジュールを取得するメソッド

        const module = hatsModulesClient.getModuleById(moduleId);
        
      • getModuleByImplementation

        implementationアドレスを指定してモジュールを取得するメソッド

        const module = hatsModulesClient.getModuleByImplementation(address);
        
      • getModuleByInstance

        こちらもアドレスを取得してモジュールを取得するメソッドらしい

        const module = await hatsModulesClient.getModuleByInstance(address);
        
      • getModulesByInstances

        const modules = await hatsModulesClient.getModulesByInstances(addresses);
        
      • createNewInstance

        新しいモジュールインスタンスを作成します。

        /**
         *
        * @param {Account | Address} account - Viemアカウント(JSON-RPCアカウントの場合はアドレス、その他のタイプの場合はアカウント)。
        * @param {string} moduleId - モジュールID(実装アドレス)。
        * @param {bigint} hatId - モジュールが作成される帽子ID。
        * @param {unknown[]} immutableArgs - モジュールの不変引数。引数はModuleオブジェクト内の順序と同じでなければなりません。
        * @param {unknown[]} mutableArgs - モジュールの可変引数。引数はModuleオブジェクト内の順序と同じでなければなりません。
        * @param {bigint} [saltNonce] - オプションのソルトナンス。提供されない場合はランダムに生成されます。
        * @return {Object} - レスポンスオブジェクト。
        * @return {string} status - トランザクションが成功した場合は"success"、リバートした場合は"reverted"。
        * @return {string} transactionHash - トランザクションのハッシュ。
        * @return {string} newInstance - 成功した場合、新しいモジュールインスタンスのアドレス。
        */
        const createInstanceResult = await hatsModulesClient.createNewInstan(
          {
            account,
            moduleId,
            hatId,
            immutableArgs,
            mutableArgs,
            saltNonce,
          });
        
      • batchCreateNewInstances

        まとめて複数のモジュールを作るメソッドです。

        /**
         *
         * @param {Account | Address} account - Viemアカウント(JSON-RPCアカウントの場合はアドレス、その他のタイプの場合はアカウント)。
         * @param {string[]} moduleIds - モジュールID(実装アドレス)。
         * @param {bigint[]} hatIds - モジュールが作成される帽子ID。
         * @param {unknown[][]} immutableArgsArray - 各モジュールの不変引数。モジュールごとに、引数はModuleオブジェクト内の順序と同じでなければなりません。
         * @param {unknown[][]} mutableArgsArray - 各モジュールの可変引数。モジュールごとに、引数はModuleオブジェクト内の順序と同じでなければなりません。
         * @param {bigint[]} [saltNonces] - オプションのソルトナンス。提供されない場合はランダムに生成されます。
         * @return {Object} - レスポンスオブジェクト。
         * @return {string} status - トランザクションが成功した場合は"success"、リバートした場合は"reverted"。
         * @return {string} transactionHash - トランザクションのハッシュ。
         * @return {string[]} newInstances - 成功した場合、新しいモジュールインスタンスのアドレス。
         */
        const createInstancesResult = await hatsModulesClient.batchCreateNewInstances(
          {
            account,
            moduleIds,
            hatIds,
            immutableArgsArray,
            mutableArgsArray,
            saltNonces
          });
        
      • predictHatsModuleAddress

        作成引数を使用して、モジュールのアドレスを予測します。

        /**
         *
         * @param {string} moduleId - モジュールID。
         * @param {bigint} hatId - インスタンス作成関数に提供されたターゲットの帽子ID。
         * @param {unknown[]} immutableArgs - インスタンス作成関数に提供されたモジュールの不変引数。
         * @param {bigint} saltNonce - 使用するソルトナンス。
         * @return {string} - 予測されたモジュールアドレス。
         */
        const predictedAddress = await hatsModulesClient.predictHatsModuleAddress(
          {
            moduleId,
            hatId,
            immutableArgs,
            saltNonce,
          });
        
      • createEligibilitiesChain

        新しい適格性モジュールを作成するメソッド

        /**
         * @param {Account | Address} account - Viemアカウント(JSON-RPCアカウントの場合はAddress、それ以外はAccount)。
        * @param {bigint} hatId - モジュールが作成される対象の帽子ID。
        * @param {number} numClauses - 論理結合節の数。
        * @param {number[]} clausesLengths - 各節の長さ。
        * @param {string[]} modules - 提供された各節に対応する順序でチェーン化するモジュールインスタンスの配列。
        * @param {bigint} [saltNonce] - オプションのソルトナンス。指定されない場合はランダムに生成されます。
        * @return {Object} - トランザクション結果と新しいチェーンモジュールインスタンスのアドレス。
        */
        const createInstanceResult = await hatsModulesClient.createEligibilitiesChain(
          {
            account,
            hatId,
            numClauses,
            clausesLengths,
            modules,
            saltNonce,
        });
        
      • createTogglesChain

        新しいトグルモジュールを作成するメソッド

        /**
          * @param {Account | Address} account - Viemアカウント(JSON-RPCアカウントの場合はAddress、それ以外はAccount)。
          * @param {bigint} hatId - モジュールが作成される対象の帽子ID。
          * @param {number} numClauses - 論理結合節の数。
          * @param {number[]} clausesLengths - 各節の長さ。
          * @param {string[]} modules - 提供された各節に対応する順序でチェーン化するモジュールインスタンスの配列。
          * @param {bigint} [saltNonce] - オプションのソルトナンス。指定されない場合はランダムに生成されます。
          * @return {Object} - トランザクション結果と新しいチェーンモジュールインスタンスのアドレス。
          */
        const createInstanceResult = await hatsModulesClient.createTogglesChain(
          {
            account,
            hatId,
            numClauses,
            clausesLengths,
            modules,
            saltNonce,
          });
        
      • getRulesets

        モジュールインスタンスのルールセットを取得するメソッド

        /**
         * @param {string} address - インスタンスのアドレス。
        * @return {Ruleset[] | undefined} - モジュールのルールセット、または指定されたアドレスがモジュールでない場合はundefined。
        */
        const rulesets = await hatsModulesClient.getRulesets(address);
        
      • getRulesetsBatched

        複数のモジュールインスタンスのルールセットを取得するメソッド

        /**
         * @param {string[]} addresses - インスタンスのアドレスの配列。
        * @return {(Ruleset[] | undefined)[]} - 各モジュールインスタンスのルールセット、または指定されたアドレスがモジュールでない場合はundefined。
        */
        const rulesets = await hatsModulesClient.getRulesetsBatched(addresses);
        
      • isChain

        モジュールインスタンスがモジュールチェーンかどうかを確認するメソッド

        /**
         * @param {string} address - インスタンスのアドレス。
        * @return {boolean} - インスタンスがチェーンであればtrue、そうでなければfalse。
        */
        const isChain = await hatsModulesClient.isChain(address);
        
      • isChainBatched

        複数のモジュールインスタンスがモジュールチェーンかどうかを確認するメソッド

        /**
         * @param {string[]} addresses - インスタンスのアドレスの配列。
        * @return {boolean[]} - 各インスタンスがチェーンであればtrue、そうでなければfalse。
        */
        const isChainBatched = await hatsModulesClient.isChainBatched(addresses);
        
      • isModuleDeployed

        モジュールが既にデプロイされているかどうかを確認するメソッド

        /**
         * @param {string} moduleId - モジュールのID。
        * @param {bigint} hatId - インスタンス作成関数に提供されたターゲットの帽子ID。
        * @param {unknown[]} immutableArgs - インスタンス作成関数に提供されたモジュールの不変引数。
        * @param {bigint} saltNonce - 使用するソルトナンス。
        * @return {boolean} - モジュールがデプロイされていれば true、そうでなければ false。
        */
        const isDeployed = await hatsModulesClient.isModuleDeployed(
          {
            moduleId,
            hatId,
            immutableArgs,
            saltNonce,
          });
        
      • getInstanceParameters

        モジュールインスタンスのライブパラメータを取得するメソッド

        /**
         * @param {string} instance - インスタンスのアドレス。
        * @return {object[]} - 各パラメータの情報を含むオブジェクトの配列
        */
        const module = await hatsModulesClient.getInstanceParameters(instance);
        
      • callInstanceWriteFunction

        モジュールの書き込み関数を呼び出すメソッド。


        モジュールのオブジェクトの customRoleswriteFunctions プロパティを使用して、モジュールのすべての書き込み関数をプログラム的に取得し、各関数を呼び出すために必要な入力引数やロール(Hats)を取得します。

        /**
         * @param {Account | Address} account - Viemアカウント(JSON-RPCアカウント用のAddressまたはその他のタイプのAccount)。
        * @param {string} moduleId - モジュールのID(実装アドレス)。
        * @param {Address} instance - インスタンスのアドレス。
        * @param {WriteFunction} func - 呼び出す関数をWriteFunctionタイプのオブジェクトとして提供します。
        * @param {unknown[]} args - 関数に渡す入力引数。
        */
        const res = await hatsModulesClient.callInstanceWriteFunction(
          {
            account,
            moduleId,
            instance,
            func,
            args,
          });
        
  • 新しいモジュールを構築する方法

    下記を参考にして新しくモジュールを作ることになります!!

    https://docs.hatsprotocol.xyz/for-developers/hats-modules/building-hats-modules

    • Hatsモジュールの内部構造

      通常、HatsモジュールはHatsModule.solコントラクトを継承します。

      https://github.com/Hats-Protocol/hats-module/blob/main/src/HatsModule.sol

      • HotModule.sol

        • 新しいHatsモジュールコントラクトに必要な基本的なテンプレートを提供します。
        • HatsModuleFactory.solとの互換性を持たせます。これにより、ユーザーは指定されたモジュールの新しいインスタンスを最も簡単かつ安価にデプロイできます。
        • モジュールレジストリとの互換性を持たせ、ユーザーがモジュールを見つけやすくし、Hatsのフロントエンドに統合することができます。


      これは抽象コントラクトであり、特定のユースケースに対応するためにモジュールが拡張できる汎用的な構造を提供します。


      HatsModule.solを継承することは、HatsModuleFactoryを介してデプロイ可能であること、モジュールレジストリにリストされること、レジストリを使用するアプリケーションにネイティブに表示されるために必要です。

      ただし、Hats Protocol全般と互換性を持たせるためには必須ではありません。これに関する要件については、EligibilityモジュールとToggleモジュールのドキュメントを参照してください。

      • HotModule.solの主な機能

        HatsModule.solの主な機能は、モジュールをHatsModuleFactoryを介して構成しデプロイできるようにすることです。通常、モジュールが関連付けられる新しいハットごとに、そのモジュールの新しいインスタンスが必要になるため、デプロイの際にガス効率が重要です。さらに、モジュールはその生涯の間に何度も呼び出されることが多いため、実行時のガス効率も重要です。


        これらの理由から、HatsModule.solは、イミュータブルな引数をサポートする最小限のプロキシ(クローン)コントラクトとして構成されています。これはEIP-1167標準に類似しており、ガス効率の高いLibClone.solライブラリを実装しています。


        HatsModule.solの動作に関する詳細は、以下のページを参照してください。

      • 拡張機能

        HatsModule.solには、一般的なモジュールタイプの出発点として役立ついくつかの標準的な拡張機能があります。

        • HatsEligibilityModule.sol: IHatsEligibility.solを実装
        • HatsToggleModule.sol: IHatsToggle.solを実装
    • 新しいモジュールを作る方法

      • はじめに
        hats-module-templateリポジトリを使えば、新しいモジュールの構築を簡単に始められます。このリポジトリには、次の内容が含まれています:

        • Hatsに関連する設定がされた初期化済みのFoundryプロジェクト
        • 初期依存関係として追加されたforge-stdとhats-module
        • スタート用のモジュールコントラクトのひな形
        • テストとデプロイ用のファイルテンプレート
        • Forgeテストとガスコストの差分を確認するためのGithub CIワークフロー


        エリジビリティモジュールを作成するには、HatsModuleを継承し、さらにIHatsEligibilityインターフェースを実装するHatsEligibilityModuleコントラクトをインポートして継承します:

        import { HatsEligibilityModule } from "hats-module/HatsModule.sol";
        

        同様に、トグルモジュールの場合は、HatsModuleを継承し、さらにIHatsToggleインターフェースを実装するHatsToggleModuleコントラクトをインポートして継承します:

        import { HatsToggleModule } from "hats-module/HatsModule.sol";
        
      • モジュールインスタンスのデプロイ方法

        HatsModuleを継承したすべてのコントラクトは、HatsModuleFactoryを介して最小限のプロキシクローンとしてデプロイできます。HatsModuleFactoryでは、次の操作が可能です。


        • 単一のモジュールインスタンスを作成
        • 複数のモジュールインスタンスを一括作成
        • モジュールインスタンスのアドレスを予測
        • モジュールインスタンスが既にデプロイされているかを確認


        これらの関数はHatsModuleFactoryコントラクトで直接呼び出すことができ、またModules SDKを介して簡単に新しいモジュールインスタンスをデプロイすることもできます。

      • createHatsModule

        function createHatsModule(
          address _implementation,
          uint256 _hatId,
          bytes calldata _otherImmutableArgs,
          bytes calldata _initData
        ) public returns (address _instance)
        

        新しいモジュールのデプロイとセットアップが完了すると、次のイベントが発行され、新しいインスタンスのアドレスが含まれます。

        event HatsModuleFactory_ModuleDeployed(
          address implementation, 
          address instance, 
          uint256 hatId, 
          bytes otherImmutableArgs, 
          bytes initData
        );
        
      • batchCreateHatsModule

        batchCreateHatsModule関数は、createHatsModule関数を使用して複数のインスタンスを作成します。


        必要な作成パラメータは配列として渡され、それぞれの配列の長さは作成するモジュールの数と同じである必要があります。各モジュールに対して、createHatsModule関数が同じインデックスの配列エントリで呼び出されます。

        function batchCreateHatsModule(
          address[] calldata _implementations,
          uint256[] calldata _hatIds,
          bytes[] calldata _otherImmutableArgsArray,
          bytes[] calldata _initDataArray
        ) public returns (bool success)
        
      • getHatsModuleAddress

        getHatsModuleAddress関数は、モジュールインスタンスが作成される前に、そのアドレスを予測します。

        function getHatsModuleAddress(
          address _implementation, 
          uint256 _hatId, 
          bytes calldata _otherImmutableArgs
        ) public view returns (address)
        
      • deployed

        deployed関数は、特定のモジュールインスタンスがデプロイされているかどうかを確認します。

        function deployed(
          address _implementation, 
          uint256 _hatId, 
          bytes calldata _otherImmutableArgs
        ) public view returns (bool)
        
      • HatsModuleFactoryのアドレス

        どのネットワークでもアドレスは共通して 0xfE661c01891172046feE16D3a57c3Cf456729efA みたいです。

        https://sepolia.etherscan.io/address/0xfe661c01891172046fee16d3a57c3cf456729efa

    • Module Chainsについて

      エリジビリティ条件を複数のモジュールで組み合わせたい場合はどうすればいいでしょうか?例えば、ある人が特定のNFT(例:DAOのメンバーシップを表すもの)を持っていることと、さらに選挙で勝利することが条件である場合です。これこそが、エリジビリティチェーン/トグルチェーンモジュールの目的です。


      HatsEligibilitiesChainは、複数のエリジビリティモジュールを「and」/「or」の論理演算で組み合わせるエリジビリティモジュールです。同様に、HatsTogglesChainは、複数のトグルモジュールを組み合わせるトグルモジュールです。


      これらのモジュールは、いずれも同様の構造を持っています。モジュールは、「and」演算子で結合された論理節の非結合形式でチェーン化されます。例えば、"(module1 && module2) || module3"には、2つの論理節があります。

      • "(module1 && module2)"
      • "module3"


      これらの論理節は、「or」演算子でチェーン化されています。


      • Deriving Wearer Eligibility:

        エリジビリティチェーンモジュールでは、各モジュールのエリジビリティをチェックし、選択された論理演算に基づいて結果を組み合わせることで、着用者のエリジビリティが判定されます。しかし、どのモジュールにおいても着用者が「不良ステータス」にある場合、そのモジュールは「エリジブルではない」および「不良ステータスにある」という結果を返します。

      • Deriving Hat Status:

        トグルチェーンモジュールでは、各モジュールのステータスをチェックし、選択された論理演算に基づいて結果を組み合わせることで、ハットのステータスが判定されます。

    • 新しいエリジビリティ/トグルチェーンモジュールを作成する

      このモジュールは、可変ストレージ変数を使用せず、初期化データも使用しません。以下の不変変数のみが使用され、モジュールインスタンスの作成時に設定されます。


      • 論理節の数
      • 論理節の長さ
      • エリジビリティ/トグルモジュールのリスト


      上記の例を使用して、モジュールのデプロイに使用される不変引数の例は次のとおりです。

      bytes memory otherImmutableArgs = abi.encodePacked(2, [2,1], module1Address, module2Address, module3Address);
      

      このモジュールには、これらの不変変数のための以下のゲッターが含まれています。

      function NUM_CONJUCTION_CLAUSES() public pure returns (uint256)
      
      function CONJUCTION_CLAUSE_LENGTHS() public pure returns (uint256[] memory)
      
      function MODULES() public pure returns (address[] memory)
      

今回はここまでになります!!

読んでいただきありがとうございました!!

参考文献

  1. HatsProtocol 公式サイト
  2. HatsProtocol - Docs
  3. HatsProtocol - App
  4. GitHub - HatsProtocol
  5. GitHub - HatsProtocol/create-hats-app
  6. HatsProtocol - Blog
  7. GitHub - HatsProtocol/v1-subgraphs
  8. GitHub - HatsProtocol/hats-module-template
  9. GitHub - HatsProtocol/Hats Modules Registry
GitHubで編集を提案

Discussion