# [ERC7484] スマートアカウントがモジュールを安全に扱う仕組みを理解しよう！

> ERC4337は、コントラクトアカウントの実行フローを標準化し、ERC7579はそれらを構成するモジュールを組み合わせて使える仕組みを標準化しています。

- URL: https://cardene.dev/articles/aad1c1a343ed78caf740
- 公開日: 2025-12-02
- 更新日: 2025-12-02
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

https://amzn.asia/d/gxvJ0Pw

今回は、Smart Account が信頼できるモジュールだけを選び出すためのレジストリの仕組みを提案している**ERC7484**についてまとめていきます！

:::message
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
:::

https://eips.ethereum.org/EIPS/eip-7484

他にも様々なEIP・BIP・SLIP・CAIP・ENSIP・RFC・ACPについてまとめています。

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

## 概要

**ERC4337**は、コントラクトアカウントの実行フローを標準化し、**ERC7579**はそれらを構成するモジュールを組み合わせて使える仕組みを標準化しています。
これにより、多くの開発者が「**モジュール式スマートアカウント（Smart Account）**」向けのモジュールを自由に開発できるようになっています。

:::message
**ERC4337**については以下の記事を参考にしてください。
:::

[\[ERC4337\] プロトコルの変更をせずにAAを実装する仕組みを理解しよう！](/articles/8c97ca7c93c4557ebfc2)

:::message
**ERC7579**については以下の記事を参考にしてください。
:::

[\[ERC7579\] 最小限のモジュラースマートアカウントの仕組みを理解しよう！](/articles/369c641b2ed168637075)

しかし、第三者が作ったモジュールを安全性を確認せずにSmart Accountへ追加すると、攻撃の入り口を広げてしまいます。
そこで**ERC7484**では、モジュールの安全性に関する情報（＝セキュリティに関する証明や評価）を保存し、Smart Accountが利用前に確認できる仕組みとして、**Module Registry**を標準化します。

Smart Accountは、このModule Registryに直接アクセスするのではなく、「**Registry Adapter**」を通して安全に照会します。
Registry Adapterは、Smart AccountとModule Registryの橋渡しをし、Smart Accountがどの種類のRegistryを使う場合でも正しく、安全に照会できるようにします。

また、**ERC7484**では参考実装として、誰の所有にもならずどのSmart Accountも利用できる**Singleton Module Registry**も提供します。
多くのSmart AccountがこのSingletonを使うことで、統一された安全性チェックが期待できますが、強制ではありません。
Smart Accountは、この標準インターフェースに対応する任意のRegistryを利用できます。

## 動機

**ERC4337**と**ERC7579**によって、Smart Accountの仕組みは拡張性が高く、自由度の高いものになりました。
特に**ERC7579**によって、アカウントの機能をモジュールという形で追加できるため、外部開発者も独自のモジュールを作成できます。

しかし、モジュールが誰でも作れてしまうという点は、セキュリティの観点では大きな問題を引き起こします。
信頼できないモジュールをSmart Accountに導入すると、不正操作や資産流出などの危険性が高まります。
この状況に対応するために、Smart Accountがモジュールの「**安全性の証明**」を確認できる仕組みが必要になりました。

その解決策として、**Module Registry**が登場します。Module Registryは、モジュールごとの安全性情報を保持し、Smart Accountが使用前にその情報を取得できます。
ただし、Registryごとに振る舞いや設計が異なるとSmart Account側で個別対応が必要になり、開発者の負担が増えます。
そこで、以下の標準化が重要になります。

#### 標準化される内容

| 標準化対象         | 説明        |
| ----------------- | ----------------------------- |
| Module Registry のインターフェースと必要機能 | Smart AccountがどのRegistryを使う場合でも、同じ方法で安全性情報を照会できるようにします。  |
| **Registry Adapter**の挙動  | Smart AccountがRegistryへアクセスするとき、アーキテクチャや実行フローが違っても同じ手順で扱えるようにします。 |

これにより、Smart AccountがどのRegistryを相手にしても、モジュールの安全性を一貫した方法でチェックでき、モジュール利用時のリスクを減らせます。

さらに参考実装として、誰の所有にもならない**Singleton Module Registry**が提供されます。
多くのSmart Accountがこの1つのRegistryを利用するなら、エコシステム全体で安全性評価を共有でき、統一性のメリットが生まれます。

ただし、Singletonを必ず使う必要はありません。
Smart Accountは標準化されたインターフェースに準拠するRegistryであればどれでも利用できるため、柔軟性と互換性を両立できます。

Smart AccountがModule Registryを利用することで、モジュール導入時のリスクを適切に管理でき、エコシステム全体の安全性と利便性が向上します。

## 仕様

### 用語の意味

仕様の理解のために、文中で使われる主要な用語を整理します。

| 用語            | 説明                                           |
| ------------- | -------------------------------------------- |
| Smart Account | **ERC7579**に準拠したモジュール式スマートアカウント。 |
| Module  | Smart Account に追加できる独立した機能。     |
| Attestation | モジュールに関する安全性などをチェーン上で示す証明情報。 |
| Attester  | Attestation を発行する主体。             |
| Registry  | モジュールに対する Attestation を保持するコントラクト。 |
| Adapter | Smart Account が Registry に問い合わせる際の処理を担当する機能。 |

Smart Accountがモジュールを利用する前に、そのモジュールの安全性が第三者（Attester）によって確認されているかどうかを**Registry**を通して照会する仕組みです。

### シーケンス図

![image.png](/images/qiita-e72fbd5a-3b4a-4e4c-999b-2ca8907c12b3.webp)
https://eips.ethereum.org/EIPS/eip-7484

以下は、モジュールの安全性を確認しながらインストール・実行するまでの流れを表した図です。

図には6つの主要ステップがあります。

1. **AttesterがRegistryに対してモジュールの安全性を証明するAttestationを発行**
    **Registry**はこの情報を保存します。
2. **Smart Account（Adapter を内蔵） がRegistryにモジュールの安全性を確認**
    この段階では、モジュールをインストールする前のチェックです。
3. **Smart Accountがモジュールをインストール**
    ここは任意ですが、一般的にはインストール前の安全性確認を行うことが推奨されます。
4. **モジュール実行前に再度Registryに安全性を確認**
    モジュールを使う直前に、最新の安全性が確保されているかを確認します。
5. **Smart Accountがモジュールを実行**
    実行後にさらにチェックを入れることも可能です。
6. **モジュール実行後の状態に対して再確認**
    **Attesterが後から Attestation を取り消す可能性があるため、実行後の安全性確認もオプションとして設けられています。

Smart Accountは **Registry** がエラー（revert）を返した場合、危険と判断し、取引を中断するべきとしています。

### Registry が備えるべき機能

**Registry**は、Smart Accountがモジュールの安全性を判定するために利用します。
仕様では、**Registry**が必ず備えなければならない機能と、備えることが望ましい機能が明確に定義されています。

#### 必須機能

* **Attester**が本当に `attestation` を作成した本人かどうか確認できること
    例：`msg.sender` を確認する、署名を検証するなど。
* **Attester**が過去に作成した `attestation` を取り消せること
* **Registry**は `attestation` データを保存するか保存先の参照を保存すること

#### 追加が推奨される機能

* **Attestation**に有効期限を設定可能にする
    有効期限切れの場合はチェック時にエラーを返す。
* **Adapter**や外部クライアントが、特定の `attestation` データを読み取れる `view` 関数。

#### check 関数の仕様

**Registry**の中心となる機能が `check` 関数群です。
**Registry**は以下の場合に必ずエラー（revert）を返す必要があります。

| 条件        | 説明                  |
| ------------------------------- | ------------------- |
| **Attester**の数が閾値より少ない場合 | 安全性を満たさないため使用不可。  |
| **Attester**が `attestation` を取り消した場合 | モジュールの安全性が無効になった状態。 |
| **Attester**が重複している、またはソートされていない場合 | 不正データを防ぐため。       |

#### `moduleType` を利用する `check` 関数の仕様

**Registry**内に保存されている `moduleType` が、呼び出し時に与えられた `moduleType` と異なる場合も、エラーを返します。

#### 内部 `attester` を使う `check` 関数

Smart Accountあるいは `msg.sender` 用に Registry 内に attester 情報が保存されている必要があります。

* 保存されていなければ revert。
* Smart Account が指定されていない場合は `msg.sender` の attester を参照。

#### `trustAttesters` 関数の仕様

Smart Account（またはユーザー）は、信頼する `attester` と閾値を**Registry**に登録できます。

* 指定された `attester` リストは重複がなくソートされていなければならない
* `threshold` と `attester` リストを**Registry**に保存する

### `Adapter` が持つべき挙動

Smart Accountは、**Registry**と正しく連携するために `Adapter` を備える必要があります。

##### 必須機能

* モジュール A を初めて呼び出す前（または呼び出し時）に必ず**Registry**に問い合わせる。
* **Registry**が `revert` した場合は危険と判断する。

##### 推奨

* **Registry**が `revert` した場合は取引全体を `revert` する
* モジュールをインストールする時に Registry へのチェックを行う
* モジュールを実行する際にも**Registry**へのチェックを行う

### インターフェース

```js:IERC7484Registry.sol
interface IERC7484Registry {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               Check with internal attester(s)              */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    function check(address module) external view;

    function checkForAccount(address smartAccount, address module) external view;

    function check(address module, uint256 moduleType) external view;

    function checkForAccount(
        address smartAccount,
        address module,
        uint256 moduleType
    )
        external
        view;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   Set internal attester(s)                 */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function trustAttesters(uint8 threshold, address[] calldata attesters) external;


    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*              Check with external attester(s)               */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function check(
        address module,
        address[] calldata attesters,
        uint256 threshold
    )
        external
        view;

    function check(
        address module,
        uint256 moduleType,
        address[] calldata attesters,
        uint256 threshold
    )
        external
        view;
}
```

#### 関数

##### `check`

```javascript
function check(address module) external view;
```

モジュールの安全性を内部 `attester` の設定に基づいて確認する関数。
**Registry**に登録済みの内部 `attester` 情報を使用して、指定されたモジュールが必要な安全性の条件を満たしているか確認します。

**引数**

* `module`
  * チェック対象となるモジュールアドレス。

##### `checkForAccount`

```javascript
function checkForAccount(address smartAccount, address module) external view;
```

特定のSmart Account用に保存されている内部 `attester` を使ってモジュールの安全性を確認する関数。
**Registry**は、`smartAccount` に紐付けて保存された `attester` 情報を使用してモジュールの安全性を検証します。

**引数**

* `smartAccount`
  * `attester` 設定を保持しているSmart Accountのアドレス。
* `module`
  * チェック対象モジュール。

##### `check (module + moduleType)`

```javascript
function check(address module, uint256 moduleType) external view;
```

モジュールの安全性と、登録されている `moduleType` が一致するかを確認する関数。
**Registry**に保存されている `moduleType` が、呼び出し時の値と異なる場合はエラーを返します。

**引数**

* `module`
  * チェック対象モジュール。
* `moduleType`
  * モジュールの種類を表す数値。

##### `checkForAccount (module + moduleType)`

```javascript
function checkForAccount(
    address smartAccount,
    address module,
    uint256 moduleType
) external view;
```

特定Smart Account用の内部 `attester` を使い、`moduleType` も含めてモジュールの安全性を確認する関数。
Smart Accountに保存されている `attester` と `moduleType` 情報に基づいて検証を行います。

**引数**

* `smartAccount`
  * `attester` 設定の保持者。
* `module`
  * チェック対象モジュール。
* `moduleType`
  * モジュールの種類。

##### `trustAttesters`

```javascript
function trustAttesters(uint8 threshold, address[] calldata attesters) external;
```

`msg.sender` が信頼する `attester` と閾値を**Registry**に登録する関数。
`attester` リストがソートされ重複がないか検証し、**Registry**に保存します。

**引数**

* `threshold`
  * 必要とする `attester` 数。
* `attesters`
  * 信頼する `attester` の配列。

##### `check (external attester 指定)`

```javascript
function check(
    address module,
    address[] calldata attesters,
    uint256 threshold
) external view;
```

外部から `attester` リストと閾値を直接指定し、モジュールの安全性を確認する関数。
呼び出し側が `attester` と閾値を指定します。
**Registry**は、指定された `attester` が実際に `attestation` を発行しているか確認します。

**引数**

* `module`
  * チェック対象モジュール。
* `attesters`
  * 検証に使用する `attester` のリスト。
* `threshold`
  * 必要な `attestation` の数。

##### `check (moduleType + external attester)`

```javascript
function check(
    address module,
    uint256 moduleType,
    address[] calldata attesters,
    uint256 threshold
) external view;
```

外部指定 `attester` を使い、かつ `moduleType` 一致も検証する関数。
**Registry**は、指定された `moduleType` が**Registry** に保存されている `moduleType` と一致しているか確認し、不一致の場合は `revert` します。

**引数**

* `module`
  * チェック対象モジュール。
* `moduleType`
  * モジュールの種類。
* `attesters`
  * 使用する `attester` のリスト。
* `threshold`
  * 必要 `attestation` 数。

## 補足

### Attestations（アテステーション）

Attestationは、あるモジュールに関する「**チェーン上の証明**」です。
内容は大きく分けて、セキュリティ、標準準拠、その他の性質などについての主張であり、Smart Accountがモジュールを利用する際の判断材料になります。

#### チェーン上で検証できない情報も扱える意味

多くの主張は、チェーン上だけで検証するのが難しいものです。
例えば以下のようなケースがあります。

* モジュールが特定のストレージスロットにしかアクセスしないかどうかを確認したい
    特に `DELEGATECALL` のようにSmart Accountのストレージに影響を与える操作がある場合、どこに書き込む可能性があるか把握しておくことは非常に重要です。

しかしこれはチェーン上で完全に検証することはほぼ不可能です。
そこで、Attesterがオフチェーンで調査を行い、結果をチェーン上に「**証明**」として残します。

こうすることで、Smart Accountはオフチェーン検証の結果をチェーン上で参照できるようになります。

#### Attestation データの自由度

**ERC7484**は、Attestationのデータ形式を特定の形に制限していません。
データそのものでも、データの参照でも構わない設計になっています。

これにより、以下のように幅広いケースに対応できます。

| 種類              | 内容                                   |
| --------------- | ------------------------------------ |
| 単純なフラグ  | 「**このモジュールは安全です**」という `boolean` のような簡易データ。 |
| 詳細な証明 | 解析結果、外部の検証レポートの参照など。    |
| 実行時の動作を示す複雑なデータ | `runtime` を記録した高度なデータ形式。  |

こうした柔軟性により、どのような監査方法にも対応できます。

### Singleton Registry（単一レジストリ）

Attestationをチェーン上で確認できるようにするには、どこかのコントラクトに記録する必要があります。
**ERC7484**では、参考実装として「**オーナーのいないSingleton Registry**」が提供されています。

これは、すべてのモジュールに対するAttestationを集約する「**単一の情報源**」であり、Smart Accountはここを確認することで安全性を判断できます。

### Singleton Registryを採用する理由

#### セキュリティ向上

1つのレジストリにAttestationが集められることで、次の利点が生まれます。

* 多くのAttesterが同じ場所で主張を行うため、モジュールごとのAttestationが豊富になる
* Smart Accountは複数の**Registry**の信頼性を比較・検証する必要がなくなる
* 多くの `attester` からのチェーン上の主張をまとめて取得でき、`gas` コストを抑えられる

Securityの観点では「**信頼の集中**」による利便性が高くなります。

#### 相互運用性の向上

Singleton Registryを利用することで、モジュールの流動性（liquidity）と互換性が向上します。

* 開発者はモジュールを1つの**Registry**に登録すれば済むため、Attestationの分散が防げる。
* Attesterは過去の監査結果を再利用したり、依存関係をたどった `attestation` を作成しやすくなる。
* バージョン管理や、歴史的な `attestation` の追跡も容易になる。

これにより、エコシステム全体のモジュール利用が滑らかになります。

### Singleton のトレードオフ

便利で強力ですが、いくつかの弱点もあります。

#### 単一障害点

唯一の**Registry**が攻撃されると、Smart Account全体に深刻な影響があります。

最悪ケースとしては、攻撃者が「**信頼されている `attester` のふりをして悪質なモジュールにAttestationを発行する**」ことです。

#### 複数レジストリ方式のメリットもある

複数の**Registry**を併用すれば、次のようなメリットもあります。

* 各**Registry**の変更がすぐに他へ波及しないため、情報の伝播が遅延するが、逆に攻撃者が注目するまでの時間稼ぎになる場合がある。

ただし、この遅延は脆弱性悪用の機会を増やしてしまう場合もあるため、メリットとは一概に言い切れません。

#### Singletonは柔軟設計が必要になる

幅広いケースに対応する必要があるため、Singleton Registryは構造が複雑になりがちです。

* その結果、計算量が増え、`gas` コストが高くなる傾向がある。
* ただし、多数の `attestation` を一度に扱う場合は、複数**Registry**を横断するより安定して効率的。

**ERC7484**の参考実装では `gas` 最適化も考慮されており、大幅に改善可能な余地は少ないとされています。

### Module Types（モジュールの種類）

モジュールには「**タイプ**」を設定することができます。
これは Smart Accountが期待する機能をきちんと持っているかを確認するために重要です。

例として、Smart Accountの「**署名検証ロジック**」を担うモジュールを追加したい場合を考えます。

* そのモジュールが本当に署名検証をできるかどうかは、アカウントの根本的安全性に関わります。
* Attesterが適切な `type` を持つことを確認し、**Registry**に保存しておけば、Smart Accountは間違ったモジュールを採用してしまうリスクを減らせます。

### Registryは `moduleType` の意味を知らなくてよい

**Registry**そのものは「**`type` が何を意味するのか**」を理解している必要はありません。

* `type` の意味はAttesterが判断する。
* **Registry**はその値を保存し、 Smart Accountのチェックに利用できる形で保持するだけでよい。

この分離により、**Registry**を汎用的なデザインに保つことができます。

### Related Work（関連する取り組み）

参考実装の設計は Ethereum Attestation Service（EAS）から大きな影響を受けています。
ただし、**ERC7484** 扱うユースケースは特殊であり、EASをそのまま利用するには不十分でした。

追加で必要だった機能は次の通りです。

| 必要だったもの   | 理由            |
| --------------- | --------------- |
| Smart AccountとModuleの関係に特化したチェック | 一般的な attestation の仕組みだけでは不十分。  |
| `moduleType` の扱い  | モジュール特有の要件を表現する必要がある。    |
| Adapterとの連携前提の処理   | Smart Account 側が Registry をどのように使うか明確にする必要がある。 |

そのため、EAS をベースにしつつも独自実装が必要でした。

## 参考実装

#### `Adapter.sol`

```js:Adapter.sol
contract Adapter {
    IRegistry registry;

    function checkModule(address module) internal {
        // Check module attestation on Registry
        registry.check(module);
    }

    function checkModuleWithModuleTypeAndAttesters(address module, address[] memory attesters, uint256 threshold,  uint16 moduleType) internal {
        // Check list of module attestations on Registry
        registry.check(module, attesters, threshold, moduleType);
    }

}
```

#### `Account.sol`

```js:Account.sol
contract Account is Adapter {
    ...

    // installs a module
    function installModule(
        uint256 moduleTypeId,
        address module,
        bytes calldata initData
    )
        external
        payable
    {
        checkModule(module);
        ...
    }

    // executes a module
    function executeFromExecutor(
        ModeCode mode,
        bytes calldata executionCalldata
    )
        external
        payable
        returns (bytes[] memory returnData)
    {
        checkModule(module);
        ...
    }

    ...
}
```

#### `Registry`

```js:Registry.sol
/**
* @dev this implementation is unoptimized in order to make the reference implementation shorter to read
* @dev some function implementations are missing for brevity
*/
contract Registry is IERC7484Registry {
    ...

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*               Check with internal attester(s)              */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    function check(address module) external view {
        (address[] calldata attesters, uint256 threshold) = _getAttesters(msg.sender);

        uint256 validCount = 0;
        for (uint256 i = 0; i < attesters.length; i++) {
            bool isValid = _check(module, attesters[i]);
            if (isValid) validCount++;
        }
        if (validCount < threshold) revert AttestationThresholdNotMet();
    }

    function checkForAccount(address smartAccount, address module) external view {
        (address[] calldata attesters, uint256 threshold) = _getAttesters(smartAccount);

        ...
    }

    function check(address module, uint256 moduleType) external view {
        (address[] calldata attesters, uint256 threshold) = _getAttesters(msg.sender);

        uint256 validCount = 0;
        for (uint256 i = 0; i < attesters.length; i++) {
            bool isValid = _check(module, attesters[i]);
            if (isValid) validCount++;

            AttestationRecord storage attestation = _getAttestation(module, attester);
            if (attestation.moduleType != moduleType) revert ModuleTypeMismatch();
        }
        if (validCount < threshold) revert AttestationThresholdNotMet();
    }

    function checkForAccount(
        address smartAccount,
        address module,
        uint256 moduleType
    )
        external
        view {
        (address[] calldata attesters, uint256 threshold) = _getAttesters(smartAccount);

        ...
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   Set internal attester(s)                 */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function trustAttesters(uint8 threshold, address[] calldata attesters) external {
        ...
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*              Check with external attester(s)               */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function check(
        address module,
        address[] calldata attesters,
        uint256 threshold
    )
        external
        view
    {
        uint256 validCount = 0;
        for (uint256 i = 0; i < attesters.length; i++) {
            bool isValid = _check(module, attesters[i]);
            if (isValid) validCount++;
        }
        if (validCount < threshold) revert AttestationThresholdNotMet();
    }

    function check(
        address module,
        uint256 moduleType,
        address[] calldata attesters,
        uint256 threshold
    )
        external
        view
    {
        uint256 validCount = 0;
        for (uint256 i = 0; i < attesters.length; i++) {
            bool isValid = _check(module, attesters[i]);
            if (isValid) validCount++;

            AttestationRecord storage attestation = _getAttestation(module, attester);
            if (attestation.moduleType != moduleType) revert ModuleTypeMismatch();
        }
        if (validCount < threshold) revert AttestationThresholdNotMet();
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         Internal                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    function _check(address module, address attester) external view returns (bool isValid){
        AttestationRecord storage attestation = _getAttestation(module, attester);

        uint48 expirationTime = attestation.expirationTime;
        uint48 attestedAt =
            expirationTime != 0 && expirationTime < block.timestamp ? 0 : attestation.time;
        if (attestedAt == 0) return;

        uint48 revokedAt = attestation.revocationTime;
        if (revokedAt != 0) return;

        isValid = true;
    }

    function _getAttestation(
        address module,
        address attester
    )
        internal
        view
        virtual
        returns (AttestationRecord storage)
    {
        return _moduleToAttesterToAttestations[module][attester];
    }

    function _getAttesters(
        address account
    )
        internal
        view
        virtual
        returns (address[] calldata attesters, uint256 threshold)
    {
        ...
    }

    ...
}
```

## 引用

Konrad Kopp (@kopy-kat), zeroknots (@zeroknots), "ERC-7484: Registry Extension for ERC-7579 [DRAFT]," Ethereum Improvement Proposals, no. 7484, August 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7484.

## 最後に

今回は「Smart Account が信頼できるモジュールだけを選び出すためのレジストリの仕組みを提案している**ERC7484**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください！

[Twitter @cardene777](https://twitter.com/cardene777)

他の媒体でも情報発信しているのでぜひ他も見ていってください！

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4
