[ERC2470] 複数ブロックチェーン上に同じアドレスのコントラクトをデプロイできるFactoryコントラクトの仕組みを理解しよう！

# はじめに

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

https://amzn.asia/d/gxvJ0Pw

今回は、複数のブロックチェーン上に同じアドレスでコントラクトをデプロイできる、`CREATE2`を使用したFactoryコントラクトの仕組みを提案している**ERC2470**についてまとめていきます！

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

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

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

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

# 概要

DApps（分散型アプリケーション）の中には、どのブロックチェーン上でも同一のアドレスで動作するコントラクト（シングルトン）を必要とするケースがあります。
例えば、**ERC1820**や**ERC2429**のように、複数のプロジェクトが共通のインターフェースやレジストリとして参照するグローバルな基盤コントラクトにおいて特に重要です。
これらコントラクトは、アドレスが固定であることが前提となっており、各チェーンで同じアドレスでデプロイされる必要があります。

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

https://qiita.com/cardene/items/81744cc4b3f81da70949

**ERC2470**では、任意のチェーン上で誰でも同一のアドレスにコントラクトをデプロイできるようにするパーミッションレスな`CREATE2`ファクトリーの標準化を提案しています。
このファクトリーは、コントラクトのバイトコードとソルト（`salt`）に基づき、決定論的な（＝同じ条件であれば常に同じ）アドレスにコントラクトをデプロイします。

:::note info
`CREATE2`については以下を参考にしてください。
:::

https://github.com/cardene777/smart-contract/blob/develop/docs/create2.md

このファクトリーのデプロイには「Nick’s method」と呼ばれる手法が用いられており、一度限り使用される鍵の存在しないアカウントを使ってトランザクションを生成する方法です。
これにより、秘密鍵が存在しないことが保証されつつ、あらゆるチェーン上で同じアドレスにファクトリーを配置できます。

開発者はこのファクトリーを利用することで、**ERC1820**などのようにアドレスの一貫性が求められるコントラクトを、開発チェーンやテストネット、メインネットを問わず同じアドレスでデプロイすることができます。
これにより、開発環境の整合性が保たれ、コードの再利用性や相互運用性が向上します。

# 動機

**ERC2470**ha、シングルトンコントラクトの再利用性を高めることを目的としています。
ファクトリーを利用することで、誰でも同じ方法でシングルトンを展開できるようになり、コードの再利用やデプロイ作業の簡素化が可能になります。
これは特に、複数のチェーンで同一アドレスを保証したいプロジェクトにとって有用です。

# 仕様

**ERC2470 Singleton Factory** と呼ばれるコントラクトについて提案されています。
このコントラクトは、CREATE2 命令（**EIP1014**）を利用して、事前に予測可能なアドレス（決定論的アドレス）にコントラクトをデプロイするための仕組みを提供します。

このファクトリー自体も「Nick’s Method」と呼ばれる特殊な手法によって、どのチェーンでも常に同じアドレスにデプロイされます。
この方法では、使い捨てのデプロイメントアカウントを使用し、その秘密鍵が存在しないことが保証されているため、セキュアかつ一貫性のある環境が実現されます。
ご指摘ありがとうございます。より自然で正確な技術文書として読めるよう、以下のように文章を修正します。

## デプロイ済みファクトリーの情報

* 共通アドレス（全チェーンで同じ）

  ```
  0xce0042B868300000d44A59004Da54A005ffdcf9f
  ```

* デプロイに使用された単発アカウント（秘密鍵なし）

  ```
  0xBb6e024b9cFFACB947A71991E386681B1Cd1477D
  ```

* 必要送金額：0.0247 ETH（ガス代と安全マージンを含む）

* デプロイメントトランザクションハッシュ

  ```
  0x803351deb6d745e91545a6a3e1c0ea3e9a6a02a1a4193b70edfcd2f40f71a01c
  ```

## `deploy`

```javascript
function deploy(bytes memory _initCode, bytes32 _salt)
    public
    returns (address payable createdContract)
```

任意の初期化コードを使って、決定論的アドレスにコントラクトをデプロイする関数。
この関数は、`_initCode` と `_salt` を用いて `CREATE2` 命令を内部で呼び出し、コントラクトをデプロイします。
アドレスはこれらの値とファクトリーのアドレスに基づいて計算されるため、同じ値を使えばどのチェーンでも同じアドレスにデプロイされます。

**引数**

* `_initCode`
    * デプロイ対象となるコントラクトの初期化コード。
* `_salt`
    * デプロイ先アドレスを固定化するための32バイトの任意値。

**戻り値**

* `createdContract`
    * デプロイされたコントラクトのアドレス。

## SingletonFactory コントラクト本体

```javascript
contract SingletonFactory {
    function deploy(bytes memory _initCode, bytes32 _salt)
        public
        returns (address payable createdContract)
    {
        assembly {
            createdContract := create2(0, add(_initCode, 0x20), mload(_initCode), _salt)
        }
    }
}
```

このファクトリーを利用することで、**EIP1820**や**EIP2429**のような特定のアドレスに存在することが求められるコントラクトを、誰でも、どのネットワーク上でも同じアドレスでデプロイできます。
これはクロスチェーンDAppsや標準化されたインフラ構築において非常に重要な技術的基盤となります。

# 補足

**SingletonFactory**は、あえて `create2` によるデプロイ時に `value`（ETHの送金額）を指定できないように設計されています。
これは、チェーンによって異なる残高状態が生成されるのを防ぐためです。
例えば、あるチェーンではコントラクトがETHを持っていて、別のチェーンでは持っていないといった差異が生じると、同一アドレスでも状態が異なることになります。

また、このファクトリーは任意の `salt`（ソルト）をユーザーが指定できるようになっており、アドレスの一部に任意の文字列（バニティアドレス）を含めるような用途も可能になっています。
特に指定がなければ、ソルトには `bytes(0)` を使用すれば問題ありません。

注意点として、このファクトリーからデプロイされるコントラクトのコンストラクタで `msg.sender` を使用してはいけません。
`msg.sender` はデプロイ元アドレスを示すため、すべてのコントラクトが同じファクトリーからデプロイされると、所有者や初期化ロジックが意図せず統一されてしまう可能性があります。
そのため、初期状態はすべてコンストラクタ引数として渡すか、明示的な初期化関数を使う必要があります。

なお、生成されるアドレスは以下の式によりオンチェーンで計算可能です。

```
address(keccak256(0xff ++ factory_address ++ salt ++ keccak256(init_code))[12:])
```

具体的には以下のようになります。

```
address(keccak256(bytes1(0xff), 0xce0042B868300000d44A59004Da54A005ffdcf9f, _salt, keccak256(_code)) << 96)
```

JavaScriptの場合は、ethereumjs-utilライブラリの [`generateAddress2`](https://github.com/ethereumjs/ethereumjs-util/blob/master/docs/README.md#const-generateaddress2) 関数を使うことで同様の計算ができます。

# セキュリティ

**SingletonFactory**を利用してデプロイされるコントラクトの中には、すべてのチェーンでのデプロイが適さないものや、チェーンごとに異なるアドレスが求められるケースがあります。
そのような場合には、**EIP1344**を使用してコンストラクタ内でチェーンIDを確認し、適切な動作を行うように設計することで安全性を確保できます。

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

https://qiita.com/cardene/items/c54870930dd0039f9558

特に、ウォレットと関連するアカウントコントラクトは「ユーザーにとってのシングルトン」として機能しますが、それが正しくチェーンIDを認識して動作するようにするためには、**EIP1191**に従ってチェーンIDの指定を行うべきです。

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

https://qiita.com/cardene/items/7db8090642e0fc3c5649

繰り返しになりますが、ファクトリーによるデプロイではコンストラクタで `msg.sender`を使用してはいけません。
`msg.sender`を使用すると、ファクトリー自身がすべてのコントラクトの所有者または管理者になってしまい、意図せず管理者になるリスクがあります。
代わりに、所有者などの情報はコンストラクタの引数で明示的に渡すべきです。

# 引用

Ricardo Guilherme Schmidt (@3esmit), "ERC-2470: Singleton Factory [DRAFT]," Ethereum Improvement Proposals, no. 2470, January 2020. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2470.

# 最後に

今回は「複数のブロックチェーン上に同じアドレスでコントラクトをデプロイできる、`CREATE2`を使用したFactoryコントラクトの仕組みを提案している**ERC2470**」についてまとめてきました！
いかがだったでしょうか？

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