# [ERC7613] calldataで実行先を指定するPuppet Proxyの仕組みを理解しよう！

> **Puppet（パペット）**は、「呼び出されると空のアカウント（Externally Owned Account: EOA のように見える存在）」のように振る舞うコントラクトです。

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

## はじめに

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

https://amzn.asia/d/gxvJ0Pw

今回は、デプロイヤーから呼ばれた場合にのみ、呼び出し時の `calldata` に含めたアドレスへ `delegatecall` することで、固定の実装を持たずに実行ロジックを切り替えられる**Puppet**型プロキシの仕組みを提案している**ERC7613**についてまとめていきます！

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

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

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

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

## 概要

**Puppet（パペット）**は、「**呼び出されると空のアカウント（Externally Owned Account: EOA のように見える存在）**」のように振る舞うコントラクトです。
普段は何もしないうえに、外部に公開された API（= 関数インターフェース）がありません。

ただし例外が1つだけあります。
**Puppet**をデプロイしたアドレス（deployer）から呼ばれたときだけ、**Puppet**は「**呼び出しデータ（`calldata`）に渡されたアドレス**」に対して `delegatecall`（デリゲートコール）を行います。

* **calldata（コールデータ）**
    コントラクト呼び出し時に渡される入力データです。
    どの関数を呼ぶか、引数は何か、などが入っています。
* **delegatecall（デリゲートコール）**
    「**別のコントラクトのコードを実行するが、ステート（ストレージ）や残高などは呼び出し元（ここでは**Puppet**）のものとして扱う**」呼び出し方法です。

この仕組みにより、deployerは「**Puppet自身のコンテキスト（Puppetのストレージ・アドレス・保有資産など）**」の中で、好きなロジックを実行できるようになります。
**Puppet**自体は固定で単純でも、実際に動くロジックは `calldata` で指定した先に置ける、という構造です。

## 動機

#### デプロイヤーの別アカウントとして使える

**Puppet**は deployerと別のアドレスを持つため、資産残高の箱を分けられるのが大きな特徴です。
deployerの「**別口座**」みたいに扱えます。

これにより、プロトコル側で高度な会計・資産管理ができます。
例えば、「**ユーザーごとに専用の入金先アドレス**」を割り当てて、そこに資産を送ってもらう設計が可能になります。

プロトコルの流れは、以下のように整理できます。

1. ユーザーがプロトコルのコントラクトを呼び出します。
2. プロトコルは新しい**Puppet**をデプロイし、その**Puppet**を「**このユーザーに紐づくアドレス**」として扱います。
3. 以後、その**Puppet**アドレスに送られた資産を「**ユーザーの資産**」として扱います。
4. 資産を引き出したり移動したいときは、プロトコルが**Puppet**を呼び出し、**Puppet**に `delegatecall` させて資産移動ロジックを実行します。

さらに、**CREATE2**を使って**Puppet**を「**予測可能なアドレス**」にデプロイできる場合、面白いことができます。

* **CREATE2**
    `salt` と `creation code`（作成コード）から、デプロイ先アドレスが事前に決まるEVMのデプロイ方式です。

例えば、`salt` にユーザーアドレスを使うと、ユーザーごとの**Puppet**アドレスが事前に計算できます。
すると **Puppet**をまだデプロイしていなくても、そのアドレスに先に資金を送れることがあります（アドレス自体は存在するので送金はできます）。
後で**Puppet**を実際にデプロイし、プロトコルが「**ここに入った資産はこのユーザーのもの**」と認識すれば成立します。

#### 承認（`approve`）による入金の代替として使える

多くのDeFiでは、ユーザーがトークンを預ける前に**ERC20**の `approve`（承認） をして、プロトコルが `transferFrom` で引き出す方式が一般的です。
しかし `approve` はUX的にもセキュリティ的にも気を遣う点があります。

**Puppet**を使うと、入金の入口を「**`approve` + `pull`**」から「**単純な `transfer`**」へ寄せられます。
つまり、どんなコントラクトでも、どんなウォレットでも、ユーザーに割り当てられた**Puppet**アドレスへ普通に送金するだけで資金を載せられます。
プロトコルへの承認も、プロトコル呼び出しも必須ではありません。

* 入金は複数回のトランザクションに分けてもよいし、複数の送金元から集めてもよいです。
* 別プロトコルから資金を移すときも、相手が「**任意アドレスへ送金できる**」なら追加の統合が不要です。
* 「**ERC20送金しかできない**」ような機能の限られたウォレットでも入金できます。
* 高機能ウォレットのユーザーも、危険な可能性のある「**中身がよく分からない `calldata`**」に署名する必要が減ります。
    単に `transfer` ならこれまでと同様の操作で済みます。
* **Puppet**に資金が入ったあと、プロトコル側が入金されたことを知るために、誰かがプロトコルを呼ぶ必要があります。
    ここはプロトコル設計次第で、ユーザー本人がやる場合もあれば、第三者が肩代わりできる場合もあります。

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

[\[ERC20\] ERC20を1からわかりやすく解説](/articles/aeefe2d89dd5332c9f43)

* **ガスレス取引（gasless transactions）**
    ユーザーがガス代を直接払わず、第三者（リレイヤーなど）が手数料を肩代わりする形の体験を指します。

また、プロトコルによっては「**入金後に何をするか**」をユーザーが毎回指定しなくてもよかったり、事前に設定しておけたりします。
こういうプロトコルは特に**Puppet**と相性が良く、`approve` ベースの入金をしているプロトコルの多くが**Puppet**のメリットを受けられる、というのが元の主張です。

#### Puppet自体をアップグレードしなくても全体を更新できる

**Puppet**の本体ロジックは基本的に固定で、アップグレード不要です。
挙動を変えたければdeployer側が次のどちらかを変えます。

* `delegatecall` 先のアドレス
* `delegatecall` 用に渡す `calldata`

つまり「**Puppetはただの器**」で、実際に動かすロジックはdeployerが指示して差し替えられます。

さらに、1つのコントラクト（deployer）が大量の**Puppet**を配っている場合でも、deployerをアップグレードすれば、配下の**Puppet**全体の振る舞いをまとめて変えられます。
ここで元の文章が言っているのは、「**Beacon（ビーコン）**」のような仕組みを**Puppet**側に持たせなくてもよい、という点です。

* **Beacon（ビーコン）**
    たくさんのプロキシが共通の実装アドレスを参照し、参照先を差し替えることで一括アップグレードするパターンです。

また「**便利なトリック**」として、**Puppet**が `delegatecall` する先を「**deployer自身のロジックを保持するアドレス**」にしておくと、**Puppet**のロジックはdeployerの中にカプセル化できます。
要するに、**Puppet**は常にdeployerの中身で動く形に寄せられます。

#### デプロイヤー以外にAPIを公開できない制約がある

**Puppet**はdeployer以外の呼び出し元に対してAPIを提供できません。
第三者が**Puppet**にこれをやってと直接頼むことはできません。

もし第三者にも何か実行させたいなら、第三者が呼べる関数をdeployer側に用意して、その関数の中で**Puppet**を呼び出して実行させる必要があります。
**Puppet**を直接叩かせるのではなく、必ずdeployerを経由する形になります。

この制約の結果、コントラクト側が「**あるAPIが公開されている前提**」で動く仕組みとは相性が悪いです。
元の例だと **ERC721**の `safeTransfer` のように「**受け取り先が特定の関数を実装していること**」を期待する仕組みは**Puppet**ではそのまま成立しません。

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

[\[ERC721\] ERC721を1からわかりやすく解説](/articles/0570a8d05bc7c9b9593f)

* **safeTransfer（ERC-721）**
    NFTをコントラクトに安全に送るため、受け取り側が特定の関数（受領確認）を実装しているかチェックする転送です。

:::message
コントラクト内にNFTを送付する機能がない場合に、そのコントラクト内にNFTが一生ロックされてしまうため、事前にNFTを送付する機能をチェックしてから送付する仕組みです。
:::

#### 生成コード（creation code）のバイト列として定義する理由

この標準は**Puppet**を「**コントラクトのソース**」ではなく、`creation code`（デプロイ時に使うコード）のバイト列として定義します。

* **creation code（作成コード）**
    コントラクトをデプロイするときに実行され、最終的なruntime bytecode（実行時コード）をチェーン上に残すためのコードです。
* **blob of bytes**
    バイト列のかたまり、という意味です。

こう定義しておくと、特定言語・特定コンパイラに依存しにくく、さまざまなフレームワークや実装言語で同一の**Puppet**を作りやすくなります。
ツールやライブラリ類は標準の範囲外ですが、実運用のためのヘルパーは作りやすいはず、という主張です。

また、実装が同じバイト列を使う限り、どの実装でも同一の**Puppet**が作られます。CREATE2 を使う場合はアドレスも決定的なので、互換性が高くなります。

#### `CREATE3` の代替や`CREATE3` ファクトリーの置き換えにもなり得る

**Puppet**は固定ロジックを持たないのに「**予測可能なアドレスにデプロイできる**」という性質があるため、場合によっては `CREATE3` の代替として使えます。

* **CREATE3**
    「**デプロイされる最終コントラクトのアドレスを、デプロイするコード（実装）に依存させず `salt` のみに依存させたい**」といった目的で使われることが多いパターン・仕組みの呼び名です（EVM命令としての `CREATE3` があるわけではなく、一般にファクトリー実装などで実現されます）。

さらに、`CREATE2` で予測可能な**Puppet**をデプロイし、その**Puppet**が通常の `CREATE` を使って任意コードをデプロイすることで、`CREATE3` ファクトリーを完全に置き換えられる場合があります。

#### デプロイコストが小さく決定論的アドレスに置きやすい

**Puppet**はデプロイコストが安いことも強調されています。

* デプロイ後のバイトコード（runtime bytecode）は **66 bytes**
* デプロイ用の `creation code` は **62 bytes**
* デプロイコストは **45K gas**
* clone proxy（いわゆる最小プロキシ）より **4K gas 高い程度**

ここでの **clone proxy（クローンプロキシ）**は、最小限のコードで実装コントラクトへ処理を転送する軽量プロキシのことです（一般に**EIP1167**の最小プロキシが知られています）。

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

https://qiita.com/biga816/items/aa5950e50bb195029a86

また Puppet は clone proxy と同様に、Solidity のメモリ上の scratch space（作業用領域）だけでデプロイできる、と言っています。ここは「デプロイコードが非常に短く、組み立てやすい」ことを指しています。

最後にもう1点重要なのが、「バイトコードがコンパイル生成物ではないので、コンパイラのバージョンに依存せず、信頼できる CREATE2 の決定的アドレスに配置できる」という点です。つまり、コンパイラ差分で微妙に bytecode が変わってアドレスがズレる、といった問題を避けやすい、という意図です。

## 仕様

#### デリゲート実行の入力形式（`calldata` の構造）

**Puppet**は、呼び出し時の `calldata` を使って
「**どのコントラクトのコードを `delegatecall` するか**」を判断します。

そのため、`calldata` は以下の構造の必要があります。

| 位置        | 内容                                |
| --------- | --------------------------------- |
| 先頭 `32` バイト | `delegatecall` 先のコントラクトアドレス（ABI 形式） |
| `32` バイト以降  | `delegatecall` 先で実行したい関数呼び出しデータ     |

ここで言うABI 形式のアドレスとは、実際の `address`（20 バイト）の左側を `0` で埋めて `32` バイトを指します。

```
calldata =
| 0..31 bytes                     | 32..end bytes          |
| delegatecall 先アドレス（ABI形式） | 実行したい関数の calldata |
```

**Puppet**は `calldata` の先頭 `32` バイトだけを見て `delegatecall` 先を決定し、残りのデータをそのまま `delegatecall` の入力として使います。

#### delegatecall を実行しない条件（ガード条件）

**Puppet**は常に `delegatecall` を実行するわけではありません。
以下のいずれかに該当する場合、`delegatecall` は実行されません。

1. 呼び出し元（`CALLER`）がdeployerではない
2. `calldata` の長さが `32` バイト未満
3. `calldata` の先頭 `32` バイトがABI形式のアドレスではない

#### `delegatecall` 判定フロー（mermaid 図）

```mermaid
flowchart TD
    A[コントラクトが呼ばれる] --> B{CALLER == deployer ?}
    B -- No --> X[何も実行せず終了]
    B -- Yes --> C{calldata長 >= 32 ?}
    C -- No --> X
    C -- Yes --> D{先頭32BがABI形式address ?}
    D -- No --> X
    D -- Yes --> E[delegatecall を実行]
    E --> F{成功 ?}
    F -- Yes --> G[RETURN（戻りデータを返す）]
    F -- No --> H[REVERT（戻りデータを返す）]
```

#### ETH送金時に `delegatecall` が実行されない理由

ETHなどのネイティブトークンを送金する場合、以下となります。

* `calldata` は空（長さ 0）
* 条件2（calldata 長 < 32）に必ず該当

そのため**Puppet**は `delegatecall` を実行せず、ETHを受け取って処理を終了します。

これは「**ETH送金**」と「**`delegatecall` 実行**」を明確に分離するための設計です。

#### Puppetのデプロイ方法（creation code）

**Puppet**は以下の `creation code` でデプロイされます。

```text
0x604260126D60203D3D3683113D3560A01C17733D3360147F331817604057823603803D943D373D3D355AF43D82803E903D91604057FD5BF36034525252F3
```

この `creation code` の目的は1つだけです。

> **runtime code を組み立てて、そのまま `RETURN` する**

#### `creation code` がやっていること

`creation code` は `runtime code` を以下の構造で生成します。

```mermaid
graph LR
    A[code 1] --> B[deployer address]
    B --> C[code 2]
```

* `code 1` と `code 2` は固定バイト列
* deployer address は `CALLER` から取得
* 3 つを連結したものが `runtime code` になる

この構造により、以下の性質を持ちます。

* deployerのアドレスが `runtime code` に直接埋め込まれる
* ストレージを使わずにdeployer判定が可能

#### デプロイ後コード（`runtime code`）の処理内容

`runtime code` が実行時に行う処理を、実際の順序どおりに整理すると以下です。

1. `calldata` と `CALLER` を使って `delegatecall` 可否を判定
2. `delegatecall` 不可なら何も実行せず終了
3. `delegatecall` 可なら
    * `delegatecall` 先アドレスを `calldata[0..32]` から取得
    * 残りの `calldata` を `payload` としてコピー
    * `DELEGATECALL` を実行
4. `delegatecall` の戻りデータをそのまま返す

#### `payload` の扱い

```mermaid
flowchart LR
    A[calldata全体] --> B[先頭32Bを除外]
    B --> C[payload]
    C --> D[delegatecall の calldata として使用]
```

ここで重要なのは以下の点です。

* **Puppet**は `payload` を一切解釈しない
* `delegatecall` 先のコントラクトが payload をどう扱うかは完全に自由

## 補足

#### 目標：低コストでモジュールとして使えること

**ERC7613**の設計で最も重視しているのは、以下の2点です。

* デプロイと実行のコストが低いこと
* 他のコントラクト設計の部品として使いやすいこと

**Puppet**は単体で複雑なことをするコントラクトではありません。
「**アドレスと残高とストレージを持つ実行コンテナ**」として、できるだけ単純で挙動を追いやすく、再利用しやすい存在であることが目的です。

そのため、以下の点が設計上かなり強く意識されています。

* ストレージをほぼ使わない
* 分岐が少ない
* `delegatecall` の仕組みが明確

#### Solidity実装案が採用されなかった理由

**Puppet**と同じ挙動は、Solidityでも実装できます。
例えば、通常の Solidityコントラクトに inline Yul を書いて `delegatecall` を行う方法です。

しかし、この方法には問題があります。

まずバイトコードが大きくなります。
Solidityが生成するコードには、関数ディスパッチや安全チェックなどが含まれるため、最小構成にしてもサイズは避けられません。
結果として、以下の欠点があります。

* デプロイコストが高くなる
* 実行コストも増える

次に、コンパイラ依存の問題があります。
Solidityのバイトコードは、以下によって微妙に変わります。

* コンパイラのバージョン
* 最適化設定

これは `CREATE2` で予測可能なアドレスにデプロイしたい場合に致命的です。
同じソースコードでも、環境が違うとアドレスが変わる可能性があり、設計上の前提が崩れます。

このため、Solidity実装は簡単だが目的に合わないと判断されています。

#### クローンプロキシ（EIP1167）を使う案とその問題点

次の代替案として考えられるのが、**クローンプロキシ（最小プロキシ）**を使う方法です。

構成としては以下のようになります。

```mermaid
flowchart LR
    A[ユーザー呼び出し] --> B[クローンプロキシ]
    B -->|delegatecall| C[Puppet実装コントラクト]
    C -->|delegatecall| D[実際のロジック]
```

この方法には以下のメリットがあります。

* 各**Puppet**のデプロイコストは小さい
* `CREATE2` を使えばアドレスも予測可能

しかし、以下のようなデメリットがあります。

まず `delegatecall` が1回増えることです。
実行時の流れは以下のように2段階 `delegatecall` になります。

1. クローン → **Puppet**実装
2. **Puppet**実装 → 実行ロジック

これはそのままガスコスト増加につながります。

また、構成が複雑になります。

* **Puppet**実装コントラクトが必要
* 先にそれをデプロイする初期化ステップが必要
* 管理すべきコントラクトが増える

さらに重要なのが `CREATE2` アドレス予測への影響です。

クローンプロキシの `creation code` には、**Puppet**実装コントラクトのアドレスが含まれます。
つまり、実装コントラクトのアドレスが変わると、クローンのアドレスも変わる構造になります。

これにより、以下の制約が生まれます。

* 完全に独立した `CREATE2` アドレス予測ができない
* 初期化順序に依存する

#### Beacon プロキシ案と却下理由

もう1つの代替案がBeaconプロキシパターンです。

Beaconプロキシは、実装アドレスをBeaconコントラクトに保持して各プロキシがBeaconに問い合わせて `delegatecall` 先を決めるという仕組みです。

しかし、この方式は**Puppet**の目的とは合いません。

理由は以下です。

まず、Solidityで安全にBeaconを参照する処理自体が重いです。
アドレス取得やチェックのためのコードが増え、バイトコードサイズも実行コストも増えます。

次に、**Puppet**のような極小コントラクトでコストを抑えたい場合、
Beacon プロキシ単体では足りず、結局クローンプロキシと組み合わせる必要が出てきます。

その結果、コントラクト構成がさらに複雑になり、デプロイ・実行コストがさらに上がるという状態になります。

また、Beaconはステートを更新しないと `delegatecall` 先を変えられません。
これは、以下の点で設計思想が根本的に異なります。

* `calldata` で柔軟に `delegatecall` 先を指定できる**Puppet**
* ステート更新が必要なBeacon

#### Puppet方式が選ばれた理由の整理

各方式を目的別に整理すると、以下のようになります。

| 方式  | デプロイコスト | 実行コスト | 構成の単純さ | CREATE2 との相性 | delegatecall 先の柔軟性 |
| ----------- | ------- | ----- | ------ | ------------ | ------------------ |
| Solidity 実装 | 高い  | 高い    | 普通     | 悪い           | 高い                 |
| クローンプロキシ    | 中       | やや高い  | 複雑     | 制限あり         | 低い                 |
| Beacon プロキシ | 高い      | 高い    | 非常に複雑  | 悪い           | 低い                 |
| Puppet      | 低い      | 低い    | 非常に単純  | 良い           | 非常に高い              |

## 参考実装

```js:Puppet.sol
library Puppet {
    bytes internal constant CREATION_CODE =
        hex"604260126D60203D3D3683113D3560A01C17733D3360147F33181760405782"
        hex"3603803D943D373D3D355AF43D82803E903D91604057FD5BF36034525252F3";
    bytes32 internal constant CREATION_CODE_HASH = keccak256(CREATION_CODE);

    /// @notice Deploy a new puppet.
    /// @return instance The address of the puppet.
    function deploy() internal returns (address instance) {
        bytes memory creationCode = CREATION_CODE;
        assembly {
            instance := create(0, add(creationCode, 32), mload(creationCode))
        }
        require(instance != address(0), "Failed to deploy the puppet");
    }

    /// @notice Deploy a new puppet under a deterministic address.
    /// @param salt The salt to use for the deterministic deployment.
    /// @return instance The address of the puppet.
    function deployDeterministic(bytes32 salt) internal returns (address instance) {
        bytes memory creationCode = CREATION_CODE;
        assembly {
            instance := create2(0, add(creationCode, 32), mload(creationCode), salt)
        }
        require(instance != address(0), "Failed to deploy the puppet");
    }

    /// @notice Calculate the deterministic address for a puppet deployment made by this contract.
    /// @param salt The salt to use for the deterministic deployment.
    /// @return predicted The address of the puppet.
    function predictDeterministicAddress(bytes32 salt) internal view returns (address predicted) {
        return predictDeterministicAddress(salt, address(this));
    }

    /// @notice Calculate the deterministic address for a puppet deployment.
    /// @param salt The salt to use for the deterministic deployment.
    /// @param deployer The address of the deployer of the puppet.
    /// @return predicted The address of the puppet.
    function predictDeterministicAddress(bytes32 salt, address deployer)
        internal
        pure
        returns (address predicted)
    {
        bytes32 hash = keccak256(abi.encodePacked(hex"ff", deployer, salt, CREATION_CODE_HASH));
        return address(uint160(uint256(hash)));
    }

    function delegationCalldata(address delegateTo, bytes memory data)
        internal
        pure
        returns (bytes memory payload)
    {
        return abi.encodePacked(bytes32(uint256(uint160(delegateTo))), data);
    }
}
```

## セキュリティ

#### クローンプロキシに似せたバイトコード設計

**ERC7613**のバイトコードは、可能な限りクローンプロキシ（最小プロキシ）に似た構造になるよう設計されています。

これは機能面の理由ではなく、監査（audit）をしやすくするための配慮です。

クローンプロキシはすでに広く使われており、以下の背景があります。

* バイトコードの構造がよく知られている
* `delegatecall` を使う前提の設計に監査者が慣れている

**Puppet**がまったく未知の構造をしていると、監査時に「**意図しない挙動が隠れていないか**」を1から精査する必要が出てきます。

そこで**Puppet** では、以下を既存のクローンプロキシに近い形に寄せることで、「**見たことのある構造**」、「**想定どおりの `delegatecall` 専用コントラクト**」として理解しやすくしています。

* 処理の流れ
* `delegatecall` 周りの構造
* エラー時の挙動

結果として、以下の実務的なセキュリティ向上につながっています。

* コードレビューの負担が下がる
* 想定外の挙動を疑われにくい

#### delegation先アドレスをABIエンコードさせる理由

もう1つ重要なのが、`delegatecall` 先アドレスをABI形式で `calldata` に含めるという設計です。

これは、第三者による意図しない `delegatecall` 誘導を防ぐための仕組みです。

#### 想定される攻撃シナリオ

もし**Puppet**が、`calldata` の先頭を厳密にチェックせず、単に最初の `20` バイトをアドレスとして使うといった仕様だった場合、第三者が用意した `calldata` をdeployerが意図せず**Puppet**に渡してしまい**Puppet**が攻撃者指定のアドレスに `delegatecall` してしまいます。

つまり、「**deployer自身がPuppetを呼んだ**」という事実だけを利用して、`delegatecall` 先をすり替える攻撃が成立する余地が出てきます。

#### ABI形式チェックによる防御

**ERC7613**では、この問題を避けるために以下の条件をすべて満たさない限り `delegatecall` を実行しません。

* `calldata が `32` バイト以上ある
* 先頭 `32` バイトがABI形式のアドレス
    * 上位 `12` バイトがすべて `0`
    * 下位 `20` バイトがアドレス

このチェックにより、適当に作った `calldata`や通常の関数呼び出しが、そのまま `delegatecall` 先指定として解釈されることはありません。

#### 関数セレクタ `0x00000000` の特殊性

`delegatecall` が成立する唯一の例外的なケースとして、deployerが関数セレクタ `0x00000000` を持つ関数を**Puppet** に対して呼び出した場合関数セレクタは、関数シグネチャ（`func(type1,type2,...)`）のKeccak-256ハッシュの先頭 `4` バイトです。

`0x00000000` というセレクタは、現実的な関数名・引数から生成されることがほぼなく、Solidityで通常定義される関数ではまず使われないという性質を持ちます。

そのため、deployerが通常のSolidity関数呼び出しをしている限り第三者が `calldata` を細工していても**Puppet**が誤って `delegatecall` を実行する状況は実質的に発生しません。

```mermaid
flowchart TD
    A[第三者が calldata を用意] --> B[deployer が Puppet を呼ぶ]
    B --> C{ABI形式 address チェック}
    C -- 不正 --> D[delegatecall しない]
    C -- 正常 --> E[deployerの明示的な操作]
    E --> F[意図した delegatecall のみ実行]
```

このように、`delegatecall` が成立するのはdeployerが明確に意図した場合だけに限定されています。

## 引用

Igor Żuk (@CodeSandwich), "ERC-7613: Puppet Proxy Contract [DRAFT]," Ethereum Improvement Proposals, no. 7613, February 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7613.

## 最後に

今回は「デプロイヤーから呼ばれた場合にのみ、呼び出し時の `calldata` に含めたアドレスへ `delegatecall` することで、固定の実装を持たずに実行ロジックを切り替えられる**Puppet**型プロキシの仕組みを提案している**ERC7613**」についてまとめてきました！
いかがだったでしょうか？

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