[ERC7573] 2つのブロックチェーン間で安全にトークンを送付する仕組みを理解しよう！

# はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は、2つの異なるブロックチェーンで安全にトークンの送付を実行するインターフェースを提案している**ERC7573**についてまとめていきます！

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

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

他にも様々なEIPについてまとめています。

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

# 概要

この規格では、2つのブロックチェーン間で安全な**delivery-versus-payment**（DVP）を実行するためトランザクションスキームのインターフェースを提案をしています。
DVPとは、クロスチェーン取引で中間者を必要とせず、片方のブロックチェーンが状態を持たない「**復号オラクル**」と安全にやり取りできます。

:::note info
### 復号オラクル
ブロックチェーン上のコントラクトが、第三者の介入なしに信頼性のある方法で暗号化されたデータを復号できる仕組みです。

復号オラクルは、暗号化されたデータを復号するための鍵を保持しています。
コントラクトが復号オラクルにアクセスすることで、必要なタイミングで適切な鍵を取得して暗号化されたデータを復号することができます。

また、コントラクトと復号オラクルの間の通信は、信頼性とセキュリティを担保するように設計されています。
通常、復号オラクルは状態を持たない（stateless）ため、一度に複数の要求を処理しながらも、それぞれの要求に対して適切な鍵を提供します。
これにより、コントラクトは復号オラクルを信頼して暗号化されたデータの復号を行うことができ、2つのブロックチェーン間の取引が安全に実行されます。
:::

このスキームは、各ブロックチェーン上にコントラクトを配置し、片方のコントラクトは「**アセットチェーン**」として**ILockingContract**インターフェースを実装し、もう片方のコントラクトは「**ペイメントチェーン**」として**IDecryptionContract**インターフェースを実装します。

- **ILockingContract**:
    - **アセットチェーン**上にあるこのコントラクトは、鍵が提示されるまでトークン（例：資産）をロックします。
    - 鍵は2つの値のいずれかに暗号化されます。

- **IDecryptionContract**:
    - **ペイメントチェーン**上にあるこのコントラクトは、復号オラクルを通じて、トークン送付（例：支払い）の成功または失敗に応じて2つの鍵のいずれかを復号します。
    - 状態を持たない復号オラクルが**IDecryptionContract**が稼働するチェーンに接続されており、復号を行います。

### 具体的な流れ

- **資産のロック**
    - **アセットチェーン**ン上の**ILockingContract**は、特定の鍵が提示されるまで資産をロックします。
- **支払いの確認**
    - **ペイメントチェーン**上の**IDecryptionContract**は、支払いが成功した場合に特定の鍵を復号して失敗した場合には別の鍵を復号します。
- **鍵の交換**
    - 支払いの成否に基づいて、復号された鍵が資産チェーンの**ILockingContract**に提示され、資産のロックが解除されるかどうかが決定されます。

このスキームにより、2つのブロックチェーン間での安全な交換が実現され、第三者の介入を必要とせずに信頼性の高いトランザクションの実行が可能になります。

# 動機

金融取引と分散型台帳技術（DLT）の分野では、ハッシュリンクコントラクト（HLC）というコンセプトに注目がある待っています。
このコンセプトは、アセットチェーンとペイメントシステムが分離されている場合に、デリバリー・バーサス・ペイメント（DvP）の課題を解決するのに役立つ可能性があります。

### 既存の解決策の課題
現在提案されている解決策の多くは、以下のような問題を抱えています。
- **APIベースの相互作用メカニズム**
    - アセットチェーンとペイメントシステムの間の通信を行うにAPIが使用されますが、これにはオーバーヘッドが発生します。
- **複雑で問題のあるタイムロック**
    - タイムロックメカニズムを使用してトランザクションの安全性を確保しますが、複雑で問題が発生しやすいです。

### 提案されるプロトコル
ここで提案されるプロトコルは、より少ないオーバーヘッドで安全なDvPを実現することを目指しています。
特に、ステートを持たないオラクルを使用することで、システムの複雑さを軽減しつつ安全なトランザクションの実行を可能にします。

- **ステートを持たないオラクル**
    - ステートを持たないオラクルは、一度に複数のリクエストを処理し、それぞれのリクエストに対して適切な鍵を提供することができます。
    - これにより、アセットチェーンとペイメントチェーン間の安全な鍵のやり取りが可能になり、トランザクションが信頼性高く実行されます。

このプロトコルにより、複雑なタイムロックや高オーバーヘッドのAPIベースのメカニズムを避けつつ、安全なDvPを実現することができ以下のように機能します。

1. アセットチェーン上のスマートコントラクトが資産をロックします。
2. ペイメントチェーン上のスマートコントラクトが支払いの成功または失敗に応じて鍵を復号します。
3. 復号された鍵がアセットチェーンのスマートコントラクトに提示され、資産のロックが解除されます。

# 仕様

## メソッド

### ロックを実行するチェーン上のコントラクト（アセットチェーンなど）

以下のメソッドは、ロッキングを実装するコントラクトの機能です。

### メソッドとその機能

#### `transfer`の開始：inceptTransfer

```js
function inceptTransfer(bytes32 id, int amount, address from, string memory keyEncryptedSeller) external;
```

資産の買い手がトークンの送付を開始する関数。
- **パラメータ**
    - `id`
        - 取引の識別子。
    - `amount`
        - 送付するトークンの量。
    - `from`
        - 資産の送付元アドレス。
    - `keyEncryptedSeller`
        - 送付元がトークンを再請求するために使用する暗号化された鍵。
- **イベント**
    - `TransferIncepted`イベントを発行します。

#### `transfer`の確認：confirmTransfer**

```js
function confirmTransfer(bytes32 id, int amount, address to, string memory keyEncryptedBuyer) external;
```

資産の送付元がトークンの送付を確認する関数。
- **パラメータ**
    - `id`
        - `transfer`の識別子。
    - `amount`
        - 送付するトークンの量。
    - `to`
        - 資産の買い手アドレス。
    - `keyEncryptedBuyer`
        - 買い手がトークンを請求するために使用する暗号化された鍵。
- **イベント**
    - `TransferConfirmed` イベントを発行します。

`confirmTransfer`の呼び出しで指定された`transfer`の詳細（`id`, `amount`, `from`, `to`）が、以前に`inceptTransfer`で呼び出されたものと一致して保有トークン量が十分であれば、対応するトークンがロックされ（`from` からコントラクトに`transfer`され）、`TransferConfirmed`イベントが発行されます。

#### トークンの移転：transferWithKey

```js
function transferWithKey(bytes32 id, string memory key) external;
```

`transfer`に関連するトークンの買い手または売り手が実行する関数。
- **パラメータ**
    - `id`
        - `transfer`の識別子。
    - `key`
        - 暗号化された鍵の復号結果。

買い手（`to`）が呼び出して`key` が keyEncryptedBuyer`と一致する場合、ロックされたトークンが買い手（`to`）に`transfer`され、`TokenClaimed`イベントが発行されます。
売り手（`from`）が呼び出して`key`が`keyEncryptedSeller`と一致する場合、ロックされたトークンが売り手（`from`）に`transfer`され、`TokenReclaimed`イベントが発行されます。

### ILockingContractインターフェース

```js
interface ILockingContract {
    event TransferIncepted(bytes32 id, int amount, address from, address to, string keyEncryptedSeller);
    event TransferConfirmed(bytes32 id, int amount, address from, address to, string keyEncryptedBuyer);
    event TokenClaimed(bytes32 id, string key);
    event TokenReclaimed(bytes32 id, string key);

    function inceptTransfer(bytes32 id, int amount, address from, string memory keyEncryptedSeller) external;
    function confirmTransfer(bytes32 id, int amount, address to, string memory keyEncryptedBuyer) external;
    function transferWithKey(bytes32 id, string memory key) external;
}
```


### 条件付きの復号を実行するチェーン上のコントラクト（支払いチェーンなど）

以下のメソッドは、条件付き復号を実装するコントラクトの機能です。

### メソッドとその機能

#### `transfer`の開始：inceptTransfer

```js
function inceptTransfer(bytes32 id, int amount, address from, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;
```

支払いの受取アドレスが｀transfer`を開始する関数。
- **パラメータ**
    - `id`
        - 取引の識別子。
    - `amount`
        - 支払い金額。
    - `from`
        - 支払い送信者のアドレス（受取人のアドレスは`msg.sender`）。
    - `keyEncryptedSuccess`
        - 支払いが成功した場合に復号される鍵の暗号化。
    - `keyEncryptedFailure`
        - 支払いが失敗した場合に復号される鍵の暗号化。
- **イベント**
    - `PaymentTransferIncepted`イベントを発行します。

#### 支払いと復号：transferAndDecrypt

```js
function transferAndDecrypt(bytes32 id, int amount, address to, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;
```

支払い送信者が支払い移転`transfer`を完了させる関数。
- **パラメータ**
    - `id`
        - 取引の識別子。
    - `amount`
        - 支払い金額。
    - `to`
        - 支払い受取人のアドレス（送信者のアドレスは暗黙的に`msg.sender`）。
    - `keyEncryptedSuccess`
        - 支払いが成功した場合に復号される鍵の暗号化。
    - `keyEncryptedFailure`
        - 支払いが失敗した場合に復号される鍵の暗号化。
- **イベント**
    - `TransferKeyRequested`イベントおよび`TransferKeyReleased`イベントを発行します。
    -鍵の復号結果は支払いの成功または失敗に基づきます。

このメソッドは、以前の`inceptTransfer`呼び出しで指定された値（`id`, `amount`, `from`, `to`, `keyEncryptedSuccess`, `keyEncryptedFailure`）と一致しない場合、鍵の復号や支払い`transfer`を行いません。

#### 取引のキャンセル：cancelAndDecrypt

```js
function cancelAndDecrypt(bytes32 id, address from, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;
```

支払いの受取アドレスが支払い`transfer`をキャンセルする関数。
- **パラメータ**
    - `id`
        - 取引の識別子。
    - `from`
        - 支払い送信者のアドレス。
    - `keyEncryptedSuccess`
        - 支払いが成功した場合に復号される鍵の暗号化。
    - `keyEncryptedFailure`
        - 支払いが失敗した場合に復号される鍵の暗号化。

このメソッドは、以前の`inceptTransfer`呼び出しの正確な引数と一致する場合にのみ、特定の支払い`transfer`をキャンセルします。

### IDecryptionContractインターフェース

```js
interface IDecryptionContract {
    event TransferIncepted(bytes32 id, int amount, address from, address to, string keyEncryptedSuccess, string keyEncryptedFailure);
    event TransferKeyRequested(bytes32 id, string encryptedKey);
    event TransferKeyReleased(bytes32 id, bool success, string key);

    function inceptTransfer(bytes32 id, int amount, address from, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;
    function transferAndDecrypt(bytes32 id, int amount, address to, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;
    function cancelAndDecrypt(bytes32 id, address from, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;
}
```

## 暗号化と復号化

このシステムでは、2つのスマートコントラクト間の連携は鍵（key）と暗号化された鍵（encryptedKey）を使用して行われます。

暗号化は、復号オラクルがサポートする限り、複数の暗号化方法をサポートできます。
暗号化方式は自由に選べますが、双方が同じ方式を使用する必要があります。
暗号化は、復号オラクルの公開鍵を使用して行われます。
この公開鍵は、取引に関わる双方（資産の買い手と売り手）に知られています。
また、取引に関わる双方は、**keyEncryptedBuyer**（買い手の暗号化された鍵）および**keyEncryptedSeller**（売り手の暗号化された鍵）の文字列が有効な形式であることを確認します。

## 支払いのシーケンス図
2つのコントラクトのやりとりについて以下のシーケンス図にまとめられています。

![DvP-Seq-Diag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570269/444b5cf7-ab83-db41-5e04-7341ee929156.png)
引用: https://eips.ethereum.org/EIPS/eip-7573#sequence-diagram-of-delivery-versus-payment

このシーケンス図は、資産チェーンと支払いチェーン間での安全なデリバリー・バーサス・ペイメント（DvP）プロセスを示しています。

### 登場人物
- **Seller of Asset**
    - 資産の売り手。
- **Buyer of Asset**
    - 資産の買い手。
- **Asset Contract**
    - 資産チェーン上のロッキングコントラクト（`ILockingContract`）。
- **Payment Contract**
    - 支払いチェーン上の条件付き復号コントラクト（`IDecryptionContract`）。
- **Payment Operator**
    - 復号オラクル。

1. **暗号化の準備**
    - 売り手と買い手がそれぞれ、自分の鍵を復号オラクルの公開鍵で暗号化します。
    - `encrypt B` (買い手の鍵を暗号化)
    - `encrypt S` (売り手の鍵を暗号化)

2. **取引の開始**
    - **Buyer**
        - `inceptTransfer(id, amount, from, E(S))`
    - 買い手が資産の`transfer`を開始します。
    - `TransferIncepted`イベントが発行され、`E(S)`が保存されます。

    - **Payment Contract**
        - `inceptTransfer(id, amount, from, E(B), E(S))`
    - アセットチェーン上のロッキングコントラクトに、取引を開始するためのメソッドを呼び出します。
    - `TransferIncepted`イベントが発行され、`E(B)`と`E(S)`が保存されます。

3. **取引の確認**
    - **Seller**
        - `confirmTransfer(id, to, E(B))`
    - 売り手が資産の`transfer`を確認します。
    - `TransferConfirmed`イベントが発行され、トークンがロックされます。

4. **支払いのキャンセル（オプション）**
    - **Payment Contract**: `cancelAndDecrypt(id, amount, to, E(B), E(S))`
    - 支払いが開始されなかった場合、受取アドレスが支払いをキャンセルします。
    - `TransferKeyRequested`イベントが発行され、復号オラクルが`E(K)`を復号します。
    - `TransferKeyReleased`イベントが発行され、売り手の鍵`S`が公開されます。

5. **支払いの完了**
    - **Payment Contract**: `transferAndDecrypt(id, amount, to, E(B), E(S))`
    - 支払い送信者が支払いを完了させます。
    - `TransferKeyRequested`イベントが発行され、復号オラクルが`E(K)`を復号します。
    - 支払いが成功した場合、`E(B)`を復号し、`K = B`（買い手の鍵）が取得されます。
    - 支払いが失敗した場合、`E(S)`を復号し、`K = S`（売り手の鍵）が取得されます。
    - `TransferKeyReleased`イベントが発行されます。

6. **資産の`transfer**
    - **Buyer**
        - `transferWithKey(id, B)`
    - 買い手が鍵`B`を使ってロックされたトークンを請求します。
    - `TokenClaimed`イベントが発行され、資産が買い手に`transfer`されます。
    
    - **Seller**
        - `transferWithKey(id, S)`
    - 売り手が鍵`S`を使ってロックされたトークンを再請求します。
    - `TokenReclaimed`イベントが発行され、資産が売り手に戻されます。

# 補足

このプロトコルは、効率的で無駄のない方法を目指しています。

### プロトコルのポイント

- **取引の識別子（id）**
    - 取引は一意の識別子（id）に関連付けられます。
    - この識別子は、取引当事者間の追加のやり取りによって生成されることが望ましいです。

- **鍵と暗号化された鍵（key と encryptedKey）**
    - `key`および`encryptedKey`引数は文字列です。
    - これにより、さまざまな暗号化方式を柔軟に使用できます。

- **暗号化/復号方式**
    - 暗号化方式や復号方式は、暗号化された鍵（`encryptedKey`）の内容から推測できるようにするべきです。

# 引用

Christian Fries (@cfries), Peter Kohl-Landgraf (@pekola), "ERC-7573: Conditional-upon-Transfer-Decryption for DvP [DRAFT]," Ethereum Improvement Proposals, no. 7573, December 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7573.

# 最後に

今回は「2つの異なるブロックチェーンで安全にトークンの送付を実行するインターフェースを提案している**ERC7573**」についてまとめてきました！
いかがだったでしょうか？

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

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

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

https://chaldene.net/

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

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