EIP-4337|Standards Track: ERC|狀態 Final|建立 2021-09-29|Requires: EIP-712, EIP-7702
作者:Vitalik Buterin、Yoav Weiss、Dror Tirosh、Shahaf Nacson、Alex Forshtat、Kristof Gazso、Tjaden Hess|授權 CC0
規格原文:https://eips.ethereum.org/EIPS/eip-4337
🎯 什麼情境該想到我
當你「要讓帳戶自己帶驗證邏輯」——多簽、社交回復、自訂簽章演算法、代付 gas、用代幣付手續費——的時候。
一句話定位:帳戶抽象,但完全不改共識層。
⚙️ 怎麼用(步驟 / 公式)
整條路徑:不是交易,是 UserOperation
使用者 → UserOperation → 專屬 mempool → Bundler 打包
→ entryPoint.handleOps(ops[], beneficiary) → 上鏈
刻意不叫 transaction,避免混淆。它像交易一樣有 to/calldata/nonce/signature/gas 欄位,但 signature 的用法不由協議定義,而是由帳戶合約自己決定——這就是「抽象」的所在。
六個角色
| 角色 | 職責 |
|---|---|
| Sender | 發出 UserOperation 的智能合約帳戶(SCA) |
| EntryPoint | 單例合約,執行整批 UserOperation。bundler 應白名單化支援的 EntryPoint |
| Bundler | 收集 UserOperation、組成 handleOps() 交易送上鏈。本身是 block builder,或透過 mev-boost 之類的 PBS 基礎設施 |
| Paymaster | 代付手續費的輔助合約 |
| Factory | 需要時部署新的 sender 合約 |
| Aggregator | 讓多個 UserOperation 共用一次驗證(完整設計不在本規格範圍) |
帳戶要實作的介面
interface IAccount {
function validateUserOp(
PackedUserOperation calldata userOp,
bytes32 userOpHash,
uint256 missingAccountFunds
) external returns (uint256 validationData);
}userOpHash 是對 userOp(不含 signature)、EntryPoint、chainId 的雜湊。帳戶:
- MUST 驗證呼叫者是可信的 EntryPoint。
- MUST 驗證簽章對
userOpHash有效。 - ⭐ 簽章不符時 SHOULD 回傳
SIG_VALIDATION_FAILED(1)而不是 revert;其他錯誤 MUST revert。 - ⭐ 而且 SHOULD 不要提早 return,要跑完正常流程——這兩條都是為了讓 gas 估算能運作。
- MUST 付給 EntryPoint 至少
missingAccountFunds(可能是 0)。付多了可用withdrawTo取回。
回傳值是 packed 的三段:aggregator/authorizer(0=簽章有效,1=失敗,其他=aggregator 地址)+ validUntil + validAfter(各 6 bytes 時間戳,0 表示無限)。
要改用區塊高度表達有效區間,兩個值的最高位都要設 1;時間戳與區塊高度不能混用。
半抽象 nonce:192-bit key + 64-bit sequence
把單一 uint256 nonce 拆兩段,getNonce(sender, key) 查詢。
每個 key 各自維持一條遞增序列 → 同一個帳戶可以有多條互不阻塞的操作流,而不是被單一遞增 nonce 卡住排序。
防重放
signature MUST 依賴 chainid 與 EntryPoint 地址——否則會被跨鏈重放,或被不同版本的 EntryPoint 重放。
Paymaster 流程
paymasterAndData 非空時,EntryPoint 走不同流程:
- 驗證迴圈中額外檢查 paymaster 在 EntryPoint 的 ETH 存款是否足夠。
- 呼叫
validatePaymasterUserOp確認它願意付。此時validateUserOp的missingAccountFunds傳 0(帳戶存款不會被動用)。 - 若
validatePaymasterUserOp回傳非空的context,主執行呼叫之後 MUST 呼叫postOp。
⭐ 模擬(Simulation)—— 整個安全模型的核心
規格講得很清楚為什麼需要它:
- 一般交易的檢查(ecrecover、nonce、餘額、gasLimit、chainId)不依賴 EVM 狀態,別人的交易改不掉。
- UserOperation 的驗證依賴 EVM 狀態,會被同批或其他交易改掉。
所以 bundler 必須做離線的 view/trace call,跑 EntryPoint 的驗證段並強制 opcode 與 storage 存取規則。目的是讓驗證邏輯 sandboxed、與同 bundle 的其他 operation 隔離。
模擬 revert,bundler MUST 丟棄該 UserOperation。
打包時 bundler MUST:
- 排除會存取同 bundle 中其他 UserOperation 之 sender 地址的 op。
- 排除會存取同 bundle 中由 factory 新建地址的 op。
- 逐一累計每個 paymaster 的餘額,確保足以支付所有使用它的 op。
上鏈前 SHOULD 用最大 gas 跑 debug_traceCall 再驗一次規則。
信譽與質押
惡意 paymaster 可以對系統發動 DoS。緩解方式:bundler 應對其服務的合約建立信譽系統,paymaster 要嘛限制自己的 storage 用量、要嘛質押。完整的信譽系統規格不在本提案範圍。
規則太嚴而卡到合法用途時,逃生口是 alternative mempool(放寬規則的另一組 P2P 網路),但其推廣程序同樣不在本規格範圍。
🧪 我實際套用的紀錄
- 2026-08-27:(待填)
⚠️ 注意 / 什麼時候不適用
1. EntryPoint 是被刻意集中的信任點
規格自己在 Security Considerations 承認:EntryPoint 需要審計與形式驗證,因為它是所有 ERC-4337 的中央信任點。
論證是這樣的取捨——把風險集中在一個合約,換取每個帳戶要驗證的東西變得很小(只要驗 validateUserOp 的「查簽章、付費用」邏輯,以及其他函式有 msg.sender == ENTRY_POINT 把關)。整個生態的稽核總量因此下降。
形式驗證要涵蓋的兩個主要宣稱:
- 不可任意劫持:EntryPoint 只會用
userOp.calldata呼叫 sender,且只在該 sender 的validateUserOp通過之後。 - 不可抽乾手續費:驗證通過就必須真的做出那個呼叫。
2. 「不改共識層」的代價(我的補註)
規格開宗明義的目標是不動共識層——因為共識層開發正專注於擴展性,短期不會有機會塞新交易型別。代價是把複雜度整包推到鏈下基礎設施:你需要 bundler 網路、需要信任 EntryPoint 這一個合約、驗證邏輯被 opcode 與 storage 規則綁死、還要一套規格自己都說「不在範圍內」的信譽系統。
這不是「更好的帳戶」,是「用鏈下複雜度換不用等硬分叉」。
3. 最容易寫錯的一條:簽章失敗要回 1、不要 revert
validateUserOp 在簽章不符時 SHOULD 回傳 1 而不是 revert,而且不要提早 return。理由是 gas 估算需要跑完整條路徑。直覺會寫成 require(sig ok)——那會讓估算失效。
4. 有效區間不能混用時間戳與區塊高度
validUntil/validAfter 要嘛都是時間戳、要嘛都是區塊高度(最高位設 1),不能一邊一個。
5. 規格明確排除在外的部分
Aggregator 的完整設計、canonical mempool 的完整規則、信譽系統的完整規格、alternative mempool 的推廣程序——都不在這份文件裡。真要實作得再找對應的規範或既有實作。
6. 它與 EIP-7702 的關係
本規格 Requires: EIP-7702,factory 欄位可放 0x7702 旗標代表 EIP-7702 帳戶。規格在動機處明說:4337 的目標是完全不需要使用者另外持有 EOA,而現況的智能合約帳戶與 EIP-7702 都還需要。
🔗 相關工具
- 工具-以太坊帳戶與交易 —— 先懂 EOA/合約帳戶與一般交易的 nonce 機制,才看得懂 4337 在替換什麼
- 工具-Gas與EVM ——
verificationGasLimit/callGasLimit/preVerificationGas的拆分要有 gas 模型基礎 - 工具-智能合約安全反模式 —— 帳戶合約與 paymaster 都管真實價值,權限與重入的坑照那張掃
- ERC-20 代幣標準 —— 「用代幣付手續費」是 paymaster 的招牌用途之一