Pectra後のEIP-7702:Ethereum アプリ開発者のための実践的プレイブック
2025年5月7日、EthereumのPectraアップグレード(Prague + Electra)がメインネットにリリースされました。開発者にとって最も目に見える変更の一つがEIP-7702で、これは外部所有アカウント(EOA)が資金を移行したりアドレスを変更したりすることなく、スマートコントラクトロジックを「マウント」できるようにします。ウォレット、dapp、リレイヤーを構築している場合、これはスマートアカウントUXへのより簡単な道筋を提供します。
以下は実装重視の簡潔なガイドです:実際に出荷されたもの、7702がどのように動作するか、純粋なERC-4337よりもいつ選択するべきか、そして今日適用できるコピー&ペースト可能なスカフォールド。
実際に出荷されたもの
- EIP-7702はPectraの最終範囲に含まれています。 Pectraハードフォークのメタ-EIPは、含まれる変更の中に7702を正式にリストしています。
- アクティベーション詳細: Pectraは2025年5月7日のエポック364032でメインネット上でアクティベートされ、すべての主要テストネットでの成功したアクティベーションに続きました。
- ツールチェーン注記: Solidity v0.8.30は、Pectra互換性のためにデフォルトEVMターゲットをpragueに更新しました。コンパイラとCIパイプラインをアップグレードする必要があります、特に特定のバージョンを固定している場合。
EIP-7702—どのように動作するか(詳細)
EIP-7702は新しいトランザクションタイプと、EOAがその実行ロジックをスマートコントラクトに委任するメカニズムを導入します。
- 新しいトランザクションタイプ(0x04): タイプ4トランザクションには
authorization_listという新しいフィールドが含まれます。このリストには一つ以上の認証タプル—(chain_id, address, nonce, y_parity, r, s)—が含まれ、それぞれEOAの秘密鍵で署名されています。このトランザクションが処理されると、プロトコルはEOAのコードフィールドに委任インジケーターを書き込みます:0xef0100 || address。それ以降、EOAへのすべての呼び出しは指定されたaddress(実装)にプロキシされますが、EOAのストレージとバランスコンテキスト内で実行されます。この委任は明示的に変更されるまで有効です。 - チェーンスコープ: 認証は
chain_idを提供することでチェーン固有にできるか、chain_idが0に設定されている場合はすべてのチェーンに適用できます。これにより、ユーザーが各チェーンに対して新しい認証に署名することなく、同じ実装コントラクトを複数のネットワークにデプロイできます。 - 取り消し: EOAを元の非プログラマブル動作に戻すには、実装
addressがゼロアドレスに設定された別の7702トランザクションを送信するだけです。これにより委任インジケーターがクリアされます。 - セルフスポンサード vs. リレー: EOA自身がタイプ4トランザクションを送信することも、サードパーティのリレイヤーがEOAの代わりに送信することもできます。後者はガスレスユーザーエクスペリエンスを作成するために一般的です。nonceハンドリングは方法によって若干異なるため、この区別を正しく管理するライブラリを使用することが重要です。
セキュリティモデルの変化: 元のEOA秘密鍵がまだ存在するため、新しい7702トランザクションを送信して委任を変更することで、常にスマートコントラクトルール(ソーシャルリカバリーや支出制限など)を上書きできます。これは根本的な変化です。
tx.originを使用してEOAからの呼び出しであることを確認するコントラクトは再監査が必要です、7702がこれらの前提を破る可能性があるためです。フローを適切に監査してください。
7702かERC-4337か?(そして組み合わせるべき時)
EIP-7702とERC-4337の両方がアカウント抽象化を可能にしますが、異なるニーズに対応します。
- EIP-7702を選ぶべき時…
- ユーザーに資金を移行させたりアドレスを変更させることなく、既存のEOAに即座のスマートアカウントUXを提供したい場合。
- 新機能で段階的にアップグレードできるチェーン間での一貫したアドレスが必要な場合。
- アカウント抽象化への移行を段階的に進めたい場合、シンプルな機能から始めて時間をかけて複雑さを追加する。
- 純粋なERC-4337を選ぶべき時…
- 製品が完全なプログラマビリティと複雑なポリシーエンジン(マルチシグ、高度な回復など)を最初から必要とする場合。
- 既存のEOAを持たない新しいユーザー向けに構築している場合、新しいスマートアカウントアドレスと関連する設定が受け入れられる。
- 両方を組み合わせる: 最も強力なパターンは両方を使用することです。EOAは7702トランザクションを使用してERC-4337ウォレット実装をそのロジックとして指定できます。これによりEOAは4337アカウントのように動作し、既存の4337インフラストラクチャによってバンドル、ペイマスターによるスポンサー、処理が可能になります—すべてユーザーが新しいアドレスを必要とすることなく。これはEIPの著者によって明示的に推奨 される前方互換パスです。
適用可能な最小限の7702スカフォールド
実装コントラクトとそれを有効化するクライアントサイドコードの実用的な例を以下に示します。
1. 小さく監査可能な実装コントラクト
このコントラクトコードは指定されるとEOAのコンテキスト内で実行されます。小さく監査可能に保ち、アップグレードメカニズムの追加を検討してください。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @notice EIP-7702で指定された時にEOAコンテキストから呼び出しを実行します。
contract DelegatedAccount {
// 他のコントラクトとの衝突を避けるためのユニークなストレージスロット。
bytes32 private constant INIT_SLOT =
0x3fb93b3d3dcd1d1f4b4a1a8db6f4c5d55a1b7f9ac01dfe8e53b1b0f35f0c1a01;
event Initialized(address indexed account);
event Executed(address indexed to, uint256 value, bytes data, bytes result);
modifier onlyEOA() {
// オプション:特定の関数を呼び出せるユーザーを制限するチェックを追加。
_;
}
function initialize() external payable onlyEOA {
// EOAのストレージにシンプルなワンタイム初期化フラグを設定。
bytes32 slot = INIT_SLOT;
assembly {
if iszero(iszero(sload(slot))) { revert(0, 0) } // すでに初期化済みの場合はrevert
sstore(slot, 1)
}
emit Initialized(address(this));
}
function execute(address to, uint256 value, bytes calldata data)
external
payable
onlyEOA
returns (bytes memory result)
{
(bool ok, bytes memory ret) = to.call{value: value}(data);
require(ok, "CALL_FAILED");
emit Executed(to, value, data, ret);
return ret;
}
function executeBatch(address[] calldata to, uint256[] calldata value, bytes[] calldata data)
external
payable
onlyEOA
{
uint256 n = to.length;
require(n == value.length && n == data.length, "LENGTH_MISMATCH");
for (uint256 i = 0; i < n; i++) {
(bool ok, ) = to[i].call{value: value[i]}(data[i]);
require(ok, "CALL_FAILED");
}
}
}