# EIP-7702 を理解して実装する

> トークンのスワップ、流動性の追加、報酬のステーキングをまとめて行う、複雑なオールインワンのアトミックトランザクションを実行しようとしているとしましょう。ところが、普通の Ethereum ウォレットである EOA では、バッチトランザクションができません。

著者 Shodipo Ayomide、2025年9月27日 公開。Web 版：https://blog.shodipoayomide.com/ja/understanding-and-implementing-eip-7702

![EIP-7702 を理解して実装する](https://blog.shodipoayomide.com/banners/understanding-and-implementing-eip-7702.png)

トークンのスワップ、流動性の追加、報酬のステーキングをまとめて行う、複雑なオールインワンのアトミックトランザクションを実行しようとしているとしましょう。ところが、普通の Ethereum ウォレットである EOA では、バッチトランザクションができません。そうなると、3 つの別々のトランザクションに署名して、ガス代を 3 回払う必要があります。これはありえませんよね。しかも、ステップの合間に MEV ボットにサンドイッチされないよう祈るしかありません。

これは最近の `EVM` エコシステムで白熱している議論の 1 つです。普通のウォレットに、すべてを一度に壊すことなく、いったいどうやってスーパーパワーを与えればいいのでしょうか？

この課題から 2 つの `EIPs` が生まれました。`EIP-3074` と、その後に続いた `EIP-7702` です。どちらもシンプルな `EOA` と `smart contract accounts` のあいだのギャップを埋めようとするものですが、権限の委任に対するアプローチが異なります。一方は永続的な権限を与えるもので、事態がひどく悪化してウォレットが空にされる可能性があります。もう一方は、永続的な委任と一時的な委任の両方を提供でき、一時的な委任ならトランザクションがオンチェーンで実行された瞬間に消えてなくなることもあります。

この違いがなぜ重要なのか、そして Vitalik の提案が、潜在的なセキュリティ上の悪夢から Ethereum をどう救ったのかもしれないのかを話していきましょう。

## EIP-2718 - 型付きトランザクションエンベロープ

委任の話に入る前に、これらすべてを可能にしている重要なインフラがあります。それが `EIP-2718` です。トランザクションのための、Ethereum の輸送用コンテナシステムのようなものだと考えてください。

```typescript
// before eip-2718 all transactions looked the same
const legacyTx = rlp([nonce, gasPrice, gasLimit, to, value, data, v, r, s]);

// after eip-2718 transactions can now be typed
const typedTx = TransactionType || TransactionPayload;
```

`EIP-2718` は `Typed Transaction Envelopes` を導入しました。`TransactionType || TransactionPayload` が有効なトランザクションになります。`TransactionType` はトランザクションの形式を識別し、`Payload` はトランザクションの中身を持ちます。このラッパーの仕組みのおかげで、既存の機能を壊すことなく、まったく新しいトランザクションの振る舞いを導入できるようになりました。

エンベロープ型のトランザクションタイプを導入することで、既存のトランザクションとの後方互換性さえ確保すればよくなり、それ以降は `TransactionTypes` のあいだで番号が衝突しないようにするという、はるかに単純な問題を解くだけで済みます。だからこそ、`EIP-7702` が一時的な委任の仕組みを導入する必要があったときも、例えば `0x04` のような新しいトランザクションタイプを定義するだけでよく、`EVM` そのものには何の変更も必要ありませんでした。

## EIP-3074 - 永続的な委任のアプローチ

[EIP-3074](https://eips.ethereum.org/EIPS/eip-3074) は、委任に対して大胆なアプローチを取りました。`AUTH` と `AUTHCALL` という 2 つの新しい `EVM` `opcodes` を使って、`EOAs` がスマートコントラクトに権限を永続的に委任できるようにしたのです。

### AUTH と AUTHCALL の仕組み

仕組みはシンプルです

```solidity
// user signs an auth message
bytes32 commit = keccak256(abi.encode(invokerAddress, batchActions));
bytes memory signature = signMessage(userPrivateKey, commit);

// invoker contract calls AUTH opcode
AUTH(commit, signature.v, signature.r, signature.s);
// This sets the 'authorized' context variable to user's address

// now invoker can make calls as the user
AUTHCALL(gasLimit, targetContract, 0, 0, calldata, calldataLength, 0, 0);
```

`AUTH` は `commit` と、署名の `yParity`、`r`、`s` という 4 つのパラメータを受け取ります。署名が有効で、署名者のアドレスが authority と一致すれば、コンテキスト変数 authorized にその authority がセットされます。そのうえで `AUTHCALL` によって、承認された invoker コントラクトがトランザクションを送信できるようになり、そのとき `CALLER` には invoker ではなく承認されたアドレスがセットされます。

では、バッチトランザクションを処理できる invoker コントラクトを想像してみてください

```solidity
contract BatchInvoker {
    struct BatchCall {
        address target;
        bytes data;
        uint256 value;
    }
    
    function executeBatch(
        BatchCall[] calldata calls,
        bytes32 commit,
        uint8 v, bytes32 r, bytes32 s
    ) external {
        // authorize the user
        AUTH(commit, v, r, s);
        
        // Execute all calls as the user
        for (uint i = 0; i < calls.length; i++) {
            AUTHCALL(
                gasleft(),
                calls[i].target,
                calls[i].value,
                0, // valueExt (must be 0 for now)
                // ... calldata parameters
            );
        }
    }
}
```

ワクワクする話ではありますが、この 2 つの `opcodes` は `EVM` コミュニティにいくつものセキュリティ上の懸念をもたらしました。コンテキスト変数 `authorized` は、コントラクトの 1 つの実行フレーム全体を通して保持されますが、`DELEGATECALL` を含むどの呼び出しにも引き継がれません。これは基本的に、承認がトランザクションのスコープ全体で有効だということです。

本当の問題は、トランザクション内での一時的な性質ではありません。広く使われる invoker コントラクトがあるときに何が起きるか、です。いずれ誰もがスマートアカウントを使うようになるのなら、`AUTH` と `AUTHCALL` の `opcodes` は大きな技術的負担になり、`EVM` そのものを複雑にしかねません。

上のような人気の invoker コントラクトにバグがあったらどうなるでしょうか？ そのコントラクトを一度でも承認したことのあるすべてのユーザーが、突然リスクにさらされるかもしれません。悪意のあるアップデートが 1 つ、見落とされたエッジケースが 1 つ、整数オーバーフローが 1 つあれば、それで終わりです。大規模な資金流出が始まります。

`EVM` エコシステムは、これが奇妙な力学を生むことに気づきました。`EIP-3074` のセキュリティモデルは、invoker コントラクトに大きく依存しています。複数のユーザーが同じ invoker のロジックに頼る可能性があるため、1 つの invoker の脆弱性やエクスプロイトによって、多くのユーザーの資産や権限が一度に危険にさらされかねません。これが、`EIP-3074` が取り下げられた理由です。

## EIP-7702 - 柔軟な委任のソリューション

さて、2024 年 5 月に Vitalik が提案した [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) は、2025 年 5 月に `pectra upgrade` によって `mainnet` に導入されました。これは新しく洗練されたアプローチを導入するもので、`EOAs` が 1 つのトランザクションの間だけ一時的にスマートコントラクトのように機能できるようにします。これは大きな出来事です！

新しい `opcodes` の代わりに、`EIP-7702` は `EIP-2718's` のトランザクションエンベロープの仕組みを活用して、新しいトランザクションタイプを導入します

```typescript
interface EIP7702Transaction {
    chainId: number;
    nonce: number;
    maxPriorityFeePerGas: bigint;
    maxFeePerGas: bigint;
    gasLimit: bigint;
    to: string;
    value: bigint;
    data: Uint8Array;
    accessList: AccessList;
    authorizationList: Authorization[];
}

interface Authorization {
    chainId: number;
    address: string;  // the address of the contract code to delegate to
    nonce: number;
    yParity: 0 | 1;
    r: Uint8Array;
    s: Uint8Array;
}
```

各 authorization オブジェクトについて、委任インジケーター `(0xef0100 || address)` が、承認したアカウントのコードに書き込まれます。コードを実行するすべての操作は、その委任が指すコードを読み込んで実行しなければなりません。

### 委任の永続性は実際にどう機能するのか
ここで多くの人が混乱します。`EIP-7702` は最初のドラフトから進化してきました。当初、この提案は `EOAs` をトランザクション 1 つの間だけ一時的にスマートにするように設計されていました。しかし最終版では、委任がどれくらい続くかを自分でコントロールできるようになっています。

```javascript
function processEIP7702Transaction(tx) {
    // verify all auth signatures
    for (const auth of tx.authorizationList) {
        const signer = recoverSigner(auth);
        if (signer !== getAddressFromAuth(auth)) {
            throw new Error("Invalid authorization");
        }
    }
    
    // set delegation pointers (these persist after transaction)
    for (const auth of tx.authorizationList) {
        const eoaAddress = getAddressFromAuth(auth);
        
        // set delegation pointer - 0xef0100 || contract_address
        const delegationPointer = concat(['0xef0100', auth.address]);
        setCode(eoaAddress, delegationPointer);
        
        // nowm this delegation PERSISTS unless explicitly cleared
    }
    
    // execute the transaction normally
    executeTransaction(tx);
    
    // no auto cleanup, delegation stays active
}
```

**注意：** `7702` トランザクションの実行が失敗しても、処理済みの委任インジケーターはロールバックされません。後続の `7702` トランザクションで委任先アドレスを `0x0` に設定して明示的にクリアしない限り、そのまま残ります。

つまり、委任のパターンは 3 つあります：

- 永続的な委任：委任を設定し、複数のトランザクションにわたってそれを使い続けます
- 一時的な委任：特定のユースケースのために委任を設定します。例えば 1 日だけ `Batching Contract` に委任するような場合ですが、委任そのものは、ユーザーがクリアするまで残り続けます。

### 一時的な選択肢と永続的な選択肢の両方

`EIP-7702` の良いところは、選択肢を与えてくれることです。1 回限りの複雑なトランザクションのために一時的に委任したいですか？ それもできます。`EOA` を永続的にアップグレードして、スマートコントラクトウォレットのように動かしたいですか？ それもできます。

一時的な委任の例はこちらです

```typescript
// one off delegation
const tempDelegationTx = {
    type: 0x04,
    authorizationList: [{
        address: batchExecutorContract,
        // ... auth details
    }],
    to: userAddress,
    data: encodeBatchCall([
        // execute your complex operation
        swapTokens(),
        addLiquidity(), 
        stakeRewards(),
    ])
};
```
そして、永続的な委任の例はこちらです

```typescript
// upgrade EOA to smart wallet
const persistentDelegationTx = {
    type: 0x04,
    authorizationList: [{
        address: smartWalletImplementation,
        // ... auth details  
    }],
    to: userAddress,
    data: encodeCall("initializeSmartFeatures", [])
    // this delegation persists for future txns
};

// later txns can now use smart wallet features
const futureTransaction = {
    to: userAddress, // your EOA will now execute smart wallet code
    data: encodeCall("batchExecute", [multipleOperations])
    // no new auth needed
};
```

### なぜ 7702 の方が安全なのか

`EIP-3074` と `EIP-7702` の重要な違いは、単に一時的か永続的かということではありません。リスクの分散とコントロールの問題なのです。`EIP-3074` は共有された単一障害点を作り出し、人気のあるコントラクト 1 つの問題が何千人ものユーザーに影響しかねません。`EIP-7702` は各トランザクションを分離するので、バグが影響するのはその特定のトランザクションだけです。`EIP-7702` は既存の `ERC-4337` と完全に互換性があり、新しい `opcodes` も必要ありません。つまり、ウォレットは既存のシステムを何も壊すことなく、段階的にこれを採用できるということです。

重要なのは、委任を管理するのは `dApps` ではなく `wallets` だという点です。そのため、委任の管理はウォレットにだけ許可するというのが一般的な合意になっています。これはつまり：

- dApps があなたの委任を直接コントロールすることはできません
- ウォレットプロバイダーは、精査・監査済みの委任ロジックを実装します
- リスクは、少数の人気の invoker コントラクトに集中するのではなく、多くの実装に分散されます

## 開発者が知っておくべきこと

`EIP-7702` をサポートするアプリケーションを作っているなら、技術的に注意すべき点がいくつかあります

1. **トランザクションの構築方法の変更**
トランザクションを組み立てるロジックで、authorization のリストを扱う必要があります

```typescript
// old: simple EOA transaction
const tx = {
    to: contractAddress,
    data: encodedCall,
    // ... standard fields
};

// new way with eip-7702 delegation
const tx = {
    type: 0x04,
    to: userAddress, // calling user's own address
    data: encodeBatchCall([
        contract.interface.encodeFunctionData("swap", [tokenA, tokenB, amount]),
        contract.interface.encodeFunctionData("addLiquidity", [lpTokens]),
        contract.interface.encodeFunctionData("stake", [lpAmount])
    ]),
    authorizationList: [{
        address: batchExecutorImplementation,
        // ... authorization signature
    }],
    // ... standard fields
};
```

2. **ガス見積もりの複雑さ**
EOA がスマートコントラクトによるコントロールを取り消すと決めた場合、委任を `0x0` に戻すために、もう 1 つ `7702` トランザクションを送る必要があります。つまり、ガスの見積もりでは次の点を考慮しなければなりません

- authorization の署名検証
- コードポインターの設定
- 実際の実行
- クリーンアップのオーバーヘッド

3. **スマートコントラクト署名のサポート**
`EIP-7702` によって、`EOAs` で `EIP-1271` の署名検証が使えるようになります。つまり、**アップグレードされた** `EOA` は、後方互換性を保ちながら、`passkeys` のような別の方法でメッセージに署名できるのです。

```solidity
// your EOA can now implement smart signature verification
function isValidSignature(bytes32 hash, bytes signature) external view returns (bytes4) {
    // can verify passkey signatures, multisig, etc.
    if (verifyPasskeySignature(hash, signature)) {
        return 0x1626ba7e; // EIP-1271 magic value
    }
    return 0xffffffff;
}
```

## 必須リンク

- [EIP-2718：型付きトランザクションエンベロープ](https://eips.ethereum.org/EIPS/eip-2718) - 基礎となるトランザクションエンベロープの仕組み
- [EIP-3074：AUTH と AUTHCALL のオペコード](https://eips.ethereum.org/EIPS/eip-3074) - 永続的な委任の提案
- [EIP-7702：1 つのトランザクションのために EOA のアカウントコードを設定する](https://eips.ethereum.org/EIPS/eip-7702) - 一時的な委任の提案
- [Ethereum Magicians での議論](https://ethereum-magicians.org/t/eip-set-eoa-account-code-for-one-transaction/19923) - EIP-7702 に関するコミュニティの議論
- [Vitalik のアカウント抽象化ロードマップ](https://ethereum-magicians.org/t/eip-set-eoa-account-code-for-one-transaction/19923)
