# [ERC7985] クロスチェーンメッセージのキャンセル・タイムアウト・リトライを制御するGateway Attributesの仕組みを理解しよう！

> 今回は「ERC7985によるクロスチェーンメッセージングのメッセージ制御属性」についてまとめてきました！いかがだったでしょうか？

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

## はじめに

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

https://amzn.asia/d/gxvJ0Pw

今回は、クロスチェーンメッセージングにおけるキャンセル、タイムアウト、リトライ、依存関係、配信制御のための標準属性を定義している**ERC7985**についてまとめていきます！

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

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

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

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

### 概要

**ERC7985**とは、**ERC7786**クロスチェーンメッセージングゲートウェイにおいて、メッセージのライフサイクル、順序、配信要件を予測可能に制御するための標準属性を定義した規格のことです。

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

[\[ERC7786\] クロスチェーン通信を標準化する仕組みを理解しよう！](/articles/485e08da098ad3a6dfba)

#### 主要な特徴

| 特徴 | 説明 |
|------|------|
| キャンセル制御 | 送信後のメッセージをキャンセル可能にする |
| タイムアウト設定 | 配信期限を設定して無期限の保留状態を防止 |
| リトライポリシー | 配信失敗時の再試行動作を標準化 |
| 依存関係管理 | メッセージ間の順序保証を実現 |
| ガス制御 | 最小ガス量を指定して配信失敗を防止 |
| 配信タイミング | 配信可能な時間ウィンドウを指定 |

:::message
**ERC7786**は、クロスチェーンメッセージングのための拡張可能な属性システムを導入した規格です。
**ERC7985**は、そのERC7786を拡張して具体的なメッセージ制御属性を標準化しています。
:::

### 動機

**ERC7786**は拡張可能な属性システムを導入しましたが、属性の標準化は後続の仕様に委ねられていました。
クロスチェーンアプリケーションが成熟するにつれて、メッセージ制御のための一貫したパターンが必要不可欠な要件として浮上しています。

#### 標準化が必要な理由

| 課題 | 説明 |
|------|------|
| キャンセル | 条件が変更された時にペンディング中のメッセージをキャンセルする必要がある |
| タイムアウト | 自動キャンセルにより無期限の保留状態を防止 |
| リトライロジック | 標準化された失敗処理により信頼性が向上 |
| リバート動作 | ゲートウェイ間で一貫したエラーセマンティクス |
| メッセージ依存関係 | 順序通りに配信する必要がある場合の正しい順序保証 |
| ガス要件 | ガス不足による配信失敗を防止 |
| 配信タイミング | スケジューリングと調整のための配信時刻制御 |

標準化された属性がない場合、各ゲートウェイはこれらの機能を異なる方法で実装することになります。
その結果、エコシステムが断片化し、アプリケーション固有の統合ロジックが必要になってしまいます。

### 仕様

この仕様は、**ERC7786**クロスチェーンメッセージングゲートウェイの標準属性を定義しています。
「配信」（または「deliver」）という言葉は、**ERC7786**での使用法と同様に、宛先チェーンにメッセージを配信するプロセスを指します。

ゲートウェイは属性を独立して実装することができます。
ゲートウェイは実装する各属性のエンコーディングを検証し、エンコーディングが無効な場合はトランザクションをリバートする必要があります。

#### 属性一覧

| 属性 | セレクタ | 説明 |
|------|----------|------|
| `cancellable(bool)` | `0xde986d7f` | メッセージのキャンセル可否 |
| `deliverBefore(uint256)` | `0x3e97d7ee` | 配信期限のタイムスタンプ |
| `deliverAfter(uint256)` | `0x745910eb` | 最早配信時刻のタイムスタンプ |
| `retryPolicy(bytes)` | `0xf002c055` | リトライ動作の定義 |
| `revertBehavior(uint8)` | `0x9e521a77` | 配信失敗時の処理方法 |
| `dependsOn(bytes32[])` | `0xa9fed7b9` | メッセージ依存関係 |
| `minGasLimit(uint256)` | `0x39f87ba1` | 最小ガス制限 |

#### cancellable(bool)

```javascript
// セレクタ: 0xde986d7f = keccak256("cancellable(bool)")の先頭4バイト
bytes4 constant CANCELLABLE_SELECTOR = 0xde986d7f;
```

メッセージが送信後にキャンセル可能かどうかを示す属性です。

##### エンコーディング

属性値はABIエンコードされたブール値です。
未指定の場合、デフォルトは`false`です。

##### 動作

`true`に設定された場合、ゲートウェイは条件や要件の変更によりアプリケーションがペンディングメッセージをキャンセルできるキャンセルメカニズムを提供する必要があります。

#### deliverBefore(uint256)

```javascript
// セレクタ: 0x3e97d7ee = keccak256("deliverBefore(uint256)")の先頭4バイト
bytes4 constant DELIVER_BEFORE_SELECTOR = 0x3e97d7ee;
```

メッセージを配信できなくなる時刻を指定する属性です。

##### エンコーディング

値はABIエンコードされたUnixタイムスタンプです。
未指定の場合、デフォルトは`0`です。

##### 動作

ゲートウェイは、`0`が指定されていない限り、有効期限のタイムスタンプ以降にメッセージを配信してはなりません。
`0`は「有効期限なし」として解釈されます。

#### deliverAfter(uint256)

```javascript
// セレクタ: 0x745910eb = keccak256("deliverAfter(uint256)")の先頭4バイト
bytes4 constant DELIVER_AFTER_SELECTOR = 0x745910eb;
```

メッセージを配信できる最早時刻を指定する属性です。

##### エンコーディング

値はABIエンコードされたUnixタイムスタンプです。
未指定の場合、デフォルトは`0`です。

##### 動作

ゲートウェイは、`0`が指定されていない限り、配信タイムスタンプ以前にメッセージを配信してはなりません。
`0`は「遅延なし」として解釈されます。
`deliverBefore(uint256)`と組み合わせることで、配信時間ウィンドウを作成できます。

```mermaid
gantt
    title 配信時間ウィンドウの例
    dateFormat X
    axisFormat %H:%M

    section メッセージ
    配信不可 :done, 0, 100
    配信可能ウィンドウ :active, 100, 200
    配信不可（期限切れ） :crit, 200, 300
```

上記の図は、`deliverAfter`と`deliverBefore`を組み合わせた配信時間ウィンドウを示しています。
`deliverAfter`で指定した時刻以降、`deliverBefore`で指定した時刻以前の間のみメッセージを配信できます。

#### retryPolicy(bytes)

```javascript
// セレクタ: 0xf002c055 = keccak256("retryPolicy(bytes)")の先頭4バイト
bytes4 constant RETRY_POLICY_SELECTOR = 0xf002c055;
```

配信失敗時のリトライ動作を定義する属性です。

##### エンコーディング

リトライパラメータは`abi.encodePacked(uint16(maxRetries), uint32(retryDelay), uint32(backoffMultiplier))`形式でエンコードされます。

| パラメータ | 型 | 説明 |
|-----------|-----|------|
| `maxRetries` | uint16 | 最大リトライ回数（0はリトライなし） |
| `retryDelay` | uint32 | リトライ間の初期遅延（秒） |
| `backoffMultiplier` | uint32 | 指数バックオフの乗数（ベーシスポイント、10000 = 1倍） |

##### デフォルト値

未指定の場合、デフォルトは`0x`（空バイト）です。
これは無限リトライ、遅延なし、バックオフなし（`maxRetries = 0`、`retryDelay = 0`、`backoffMultiplier = 0`）と同等です。

##### リトライ間隔の計算例

`backoffMultiplier`が20000（2倍）、`retryDelay`が10秒の場合のリトライ間隔は以下のようになります。

| リトライ回数 | 遅延時間 |
|-------------|---------|
| 1回目 | 10秒 |
| 2回目 | 20秒 |
| 3回目 | 40秒 |
| 4回目 | 80秒 |

#### revertBehavior(uint8)

```javascript
// セレクタ: 0x9e521a77 = keccak256("revertBehavior(uint8)")の先頭4バイト
bytes4 constant REVERT_BEHAVIOR_SELECTOR = 0x9e521a77;
```

配信失敗時の処理方法を指定する属性です。

##### エンコーディング

値はABIエンコードされたuint8で、以下の値を取ります。

| 値 | 名称 | 動作 |
|----|------|------|
| 0 | Revert on Failure | 失敗時にメッセージ配信全体をリバート。元の失敗理由を伝播 |
| 1 | Emit-and-Continue | 失敗時に`MessageFailed(bytes32 sendId, string reason)`イベントを発行し、後続のメッセージや操作の配信を継続 |
| 2 | Silent Failure | トランザクションをリバートせず、失敗関連のイベントも発行しない |

##### デフォルト値

未指定の場合、デフォルトは`0`（Revert on Failure）です。

##### 各動作の詳細

以下のフロー図は、各リバート動作の処理フローを示しています。

```mermaid
flowchart TD
    A[メッセージ配信] --> B{配信成功?}
    B -->|成功| C[処理完了]
    B -->|失敗| D{revertBehavior}

    D -->|0: Revert| E[トランザクションリバート]
    E --> F[元のエラー理由を伝播]

    D -->|1: Emit-and-Continue| G[MessageFailedイベント発行]
    G --> H[後続処理を継続]

    D -->|2: Silent| I[何もしない]
    I --> H
```

`Revert on Failure`（値0）は最も厳格なモードで、失敗時にトランザクション全体をリバートします。
`Emit-and-Continue`（値1）は失敗を記録しつつ処理を継続するため、バッチ処理に適しています。
`Silent Failure`（値2）は失敗を完全に無視するため、重要でないメッセージに使用できます。

#### dependsOn(bytes32[])

```javascript
// セレクタ: 0xa9fed7b9 = keccak256("dependsOn(bytes32[])")の先頭4バイト
bytes4 constant DEPENDS_ON_SELECTOR = 0xa9fed7b9;
```

このメッセージより前に配信される必要があるメッセージの依存関係を指定する属性です。

##### エンコーディング

値はメッセージ識別子のABIエンコードされた配列です。

##### 動作

ゲートウェイは、`dependsOn`配列で指定されたすべてのメッセージが正常に配信されるまで、メッセージを配信してはなりません。
未指定または空の場合、メッセージには依存関係がありません。
これにより正しい順序が保証され、順序通りでない配信の問題が防止されます。

##### 使用例

以下の図は、メッセージ依存関係の例を示しています。

```mermaid
graph LR
    A[メッセージA] --> C[メッセージC]
    B[メッセージB] --> C
    C --> D[メッセージD]
```

この例では、メッセージCはメッセージAとBの両方に依存しており、AとBの両方が配信されるまでCは配信されません。
同様に、メッセージDはメッセージCに依存しているため、Cが配信されるまでDは配信されません。

#### minGasLimit(uint256)

```javascript
// セレクタ: 0x39f87ba1 = keccak256("minGasLimit(uint256)")の先頭4バイト
bytes4 constant MIN_GAS_LIMIT_SELECTOR = 0x39f87ba1;
```

メッセージ配信に必要な最小ガス制限を指定する属性です。

##### エンコーディング

値は必要な最小ガス単位を表すABIエンコードされたuint256です。

##### 動作

ゲートウェイはメッセージ配信を試みる前に、少なくともこの量のガスが利用可能であることを確認する必要があります。
未指定の場合、ゲートウェイはデフォルトのガス割り当て戦略を使用することができます。

### 補足

#### 設計の根拠

これらの属性は、最も一般的なクロスチェーンメッセージ制御要件に対応しています。

| カテゴリ | 対応属性 | 目的 |
|----------|----------|------|
| ライフサイクル制御 | `cancellable`、`deliverBefore` | キャンセルとタイムアウトによるメッセージ管理 |
| 配信タイミング | `deliverAfter`、`deliverBefore` | 配信時間ウィンドウの設定 |
| 失敗処理 | `retryPolicy`、`revertBehavior` | リトライポリシーとリバート動作 |
| メッセージ順序 | `dependsOn` | 依存関係チェーンによる順序保証 |
| 配信保証 | `minGasLimit` | 最小ガス要件による配信成功の保証 |

#### リトライポリシーのバイトエンコーディング

リトライポリシーはバイトエンコードされた形式を採用しています。
これにより、追加の属性を必要とせずに拡張可能なパラメータを実現しています。
`abi.encodePacked`を使用することで、データサイズを最小限に抑えながら必要なすべてのパラメータを含めることができます。

#### 依存関係メカニズムの設計

依存関係メカニズムにより、複雑なマルチメッセージワークフローが可能になります。
同時に、単一メッセージのシナリオでは簡潔さが維持されます。
空の配列や未指定の場合は依存関係なしとして扱われるため、シンプルなユースケースでは追加の設定が不要です。

### 後方互換性

この仕様は**ERC7786**を既存の仕様に影響を与えることなく拡張しています。
これらの属性をサポートしていないゲートウェイは、基本仕様の「未知の属性を適切に処理する」という要件に従って通常通り動作します。

### セキュリティ

:::message alert
**依存関係サイクルの検出**
ゲートウェイは、`dependsOn`配列における循環依存関係を検出して拒否する必要があります。
循環依存関係が存在すると、関連するすべてのメッセージが永久に配信されなくなる可能性があります。
:::

### 引用

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

https://ethereum-magicians.org/t/new-erc-attributes-for-message-control-in-erc-7786-gateways/24734

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

## 最後に

今回は「ERC7985によるクロスチェーンメッセージングのメッセージ制御属性」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下の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
