Account Abstraction 抽象帳戶:EIP-3074 與 EIP-4337 簡介

ChiHaoLu
Taipei Ethereum Meetup
19 min readOct 18, 2022

以太坊的社群其實討論了好一陣子究竟要如何設計新一代的帳戶,不同的思路也對應了不同的提案,本文主要介紹 AA 在以下這兩種方向的相關內容:

  1. 讓現行的 EOA 有智能合約的功能(EIP-3074)
  2. 讓現行的智能合約有 EOA 的功能(EIP-4337)

Table of Contents

  • EIP-3074
  • EIP-4337
  • Closing

Background

本文主要繼承自前篇:Account Abstraction 抽象帳戶:EIP-2938 簡介,因此會希望讀者已經閱讀完前篇,以及具備相關的背景知識。

▎EIP-3074

EIP-3074: AUTH and AUTHCALL opcodes 打算在 EVM 中加入兩個新的 OpCodes,分別是 AUTHAUTHCALL,讓 EOA 能透過這兩個 opcode 授權合約代替 EOA 的身份去呼叫其他合約。

此提案仍在 review 階段,請大家謹慎服用。

EIP-3074 的主要目的並非設計一個嶄新的 protocol 來擴展 EOA 的 functionality,因為隨著 protocol 與相關的介面標準越來越複雜,能被攻擊的地方也會越來越多。

它傾向讓 User(EOA)可以以合約(Invoker Contract)代理自己執行各種動作,同時讓開發者能以一個更具彈性的框架來設計交易物件和驗證機制(簽章演算法),使任何的 EOA 可以像一個合約帳戶(Contract Account)一樣運作,卻不用自己佈署任何合約。

Overview

Image Source: Ethereum wallets today and tomorrow — EIP-3074 vs. ERC-4337

概括來說一個 EOA 能將一則已簽的訊息(交易)送至自己信任的合約(稱作 Invoker)上,合約可以利用 AUTHAUTHCALL 代替這個 EOA 送出這筆交易。

由於 EOA / User 提交給 Invoker 的形式是合約自訂的,搭配新的 OpCodes 之後能讓各種需求變得很好實現,例如批次交易、包裝交易、手續費繳交方式、多簽、簽章驗證方式等。EOA 也能透過他喜歡的方式(ERC-20、法幣等)給予 Invoker 手續費。

特別注意:

  • EIP-3074 可以視為是 EOA 的擴充而非必要。
  • Invoker 是不可升級的,因為可升級合約的新邏輯可能會讓 Invoker 無法適當地驗證 commit,導致造成非常嚴重的問題,例如讓不該通過的交易簽章通過,或該通過的無法通過。

此外,commit 可以利用平行的 call 和在其之中的 nonce,達到 multi-call 的「包裝交易」效果。例如我們在面對 ERC-20 的交易時,就可以把 approve-transfer 包在一個動作裡面。

關於這個部分每一個 call frame 裡面的角色及運作,可以見下文。

EIP-3074 相關的缺點與改進建議的部分可以看:A case for a simpler alternative to EIP 3074EIP-3074 Threat Models 和 Reference 處的內容。

authorized

  • authorized 是一個型態為 address 的變數(合約除了 tx.originmsg.sender 之外現在還能讀取 authorized),表示當今合約是被哪個帳戶授權的。被授權的合約能夠使用 AUTHCALL 代表此帳戶(authorizedaddress)執行各種行為。
  • authorized 和其他以太坊中的變數不同,它沒有預設值,每次合約開始一個執行前就會將其初始化為 unset,代表當前沒有 EOA 授權此合約執行。
  • authorizedAUTHAUTHCALL 這兩個新 OpCodes 會去查看的變數,存在當前合約執行時的 EVM 中,用於確認是否已經正確設置授權帳戶(看 authorized 是否不是 unset),如果已經被設置且所有簽章合法則 authorized 的值會被 AUTHAUTHCALL 取用(下一節會說明)。
  • 合約每一次只能有一個 authorized,也就是說合約不能同時代替兩個 EOA 執行動作。
  • 每次執行(Call)時(separate execution frames),每次的 authorized 是獨立的,不能監聽到別人的 authorized。即便是利用DELEGATECALL,或同樣 address 授權加上同樣一筆交易,當前 authorized 都不能離開作用域影響別人。

不能跨出 execution frame(call frame)的原因是同一筆交易裡面可能有多個 call frame,而每一個 call frame 都有一個經過 AUTH 授權的 authorized,這個授權只停留在自己的 call frames 裡面,也就是 authorized 不能影響他人及被影響的原因。

AUTH 和 AUTHCALL

AUTH0xf6):會基於 ECDSA 簽章演算法去設定 authorized 的值

  • AUTH 會從 Stack 中取出三個元素:authorityoffsetlength,首項代表 signer address,後兩者代表 memory 的 range,會接收 EOA 的 (v, r, s) 以及 commit
  • 由於是接收 dynamic memory range,因此 AUTH 未來是有機會升級來支援與 Contract Account 互動或使用其他驗證方法的。
  • 此處 EOA 送來的簽章仍然是使用 secp256k1 這個演算法,簽章結果為:(v, r, s)
  • 如果簽章合法且簽章 recover 後 authority == signerauthority == tx.origin(允許簡單的 Batch 交易,例如 ERC-20 中的 approve-transfer),則將 authorized 設為 authority
  • 如果 authorized 被成功設定成 authority 也就是 signer,那 AUTH 會回傳 1,否則回傳 0
  • commit 是 EOA 提交的交易資訊,Invoker Contract 會驗證這裡面的內容,包含 nonce(replay protection)、togascalldata

AUTHCALL0xf7):會代理 authorized 這個帳戶發送 call

  • AUTHCALL 會從 Stack 中取出八個元素,包含:gasaddrvalue 等,用於發送 call(建置一筆交易物件)。
  • CALL(0xF1) 的行為很像,差別主要在於一些參數的邏輯判斷,例如: authorized 如果是 unset 的狀態,則這次執行動作就不合法。

在 EIP-3074 中還有 dynamic_gas 的設計,這個部份因為比較瑣碎我就先略過,如果有興趣或是想知道其他參數的 Spec. 可以詳閱此處

▎EIP-4337

EIP-4337: Account Abstraction via Entry Point Contract specification 則希望可以把原本交易在底層運作的邏輯拉到合約中:

  1. 當 User 簽核完一筆交易(這裡我們將 EOA 簽送一筆交易的行為改稱為 UserOperation)後
  2. 將其送到 UserOperation mempool 之中(類似當今的 Tx Mempool)
  3. 而 Bundler 會從中挑選交易,綑綁成一筆 Bundle Transaction
  4. 呼叫 Entry Point Smart Contract 的 handleOps
  5. 完成相關執行與驗證之後,把交易推到鏈上。

在這裡我們有許多名詞是第一次碰到,下文我會慢慢解釋!

此提案仍在 draft 階段,請大家謹慎服用。

Source: ERC 4337: account abstraction without Ethereum protocol changes

首先,這個提案最大的特點就如同上圖來源, Vitalik 文章的標題敘述一樣,不用去更改 Ethereum 底層的 Protocol 就能完成 AA 的實作。

嚴謹來說是不用去修改或增加共識層的 Protocol。

EIP-4337 可以達到以下目標,某些點可能與我們之前介紹過的 EIP-2938 和 EIP-3074 稍微不同:

  1. 以 Contract Account 作為真正的主要帳戶: 不再需要任何 EOA 作為呼叫的源頭(當今的 Contract Account 和 EIP-3074 都無法達到)
  2. 去中心化: 不需要對 bundler 這個角色的信任假設
  3. 不需要修改共識層的 Protocol: 所以不會有新的 OpCodes 也不會有新的 Transaction Type。
  4. 擁有過往我們提到的其他特性,例如:Atomic multi-operations、Privacy-Solution、不同支付手續費的方式(ERC-20)

Contract Specification

我們可以把 EIP-4337 的 AA 實作當成是一個 Contract 的 Spec.,它的目的是要把底層的交易與帳戶運作拉到合約層面執行。這邊我會邊解釋名詞,邊順過整個交易在 AA 被執行的過程。

1. UserOperation & 2. UserOperation mempool

在合約裡面,用戶送上來的交易物件是一個在合約中名為 UserOperationstruct。這個 struct 的 members 和我們認識的交易很像,包含 sendernoncecallDatacallGassignature 等,細節可見原提案

為了避免 Replay Attack(跨鏈或跨不同的 EntryPoint),Signature 的製作必須要包含 chainidEntryPoint address 等元素。

3. Bundler & 4. Bundle Transaction

Bundler 有可能是礦工,或是能作為 User 和 Miner 之間的中介人。會去聆聽 UserOperation mempool 中新加入的 UserOperation,並且將從這些交易中挑選一部分綑綁成 Bundle Transactions。

這邊我們可以假設 UserOperation 一定會被打包處理,因為可能會有類似 Flash Bot 的 Bundler 去快速過濾出有利潤(手續費)可圖的交易。

首先 Bundler 會在 Local 使用 RPC Call 呼叫 Entry Point Smart Contract 中的 simulateValidation(),以此先確保這些 UserOperation 的簽章沒問題和 Gas Fee 被正常支付。關於模擬交易結果的部分可見此處

最後 Bundle Transactions 會呼叫 Entry Point Smart Contract 中的函式 handleOps

5. handleOps & 6. Entry Point Smart Contract

Entry Point Smart Contract(EntryPoint)是一個早就被佈署的合約,將在未來被相關的 AA Transaction 呼叫使用,例如某一個 Dapp 有它想要的 AA 交易模式,它就需要佈署一個它的 EntryPoint

EntryPoint 會處理 UserOperations 的內容和替 Bundle Trandactions 佈署一個 Wallets Contract(使用標準 EIP-2470: Singleton Factory 以及 CREATE2initCode 來自於 UserOperation.initCodesalt 來自於 UserOperation.nonce)。

Wallet Contract 會用來處理 nonce 與 signature 的驗證並且執行交易。

Entry Point Smart Contract

在進到 EntryPointhandleOps 的解釋之前,我們先回憶一下之前在 EIP-2938 提到的,節點需要負責驗證一筆 AA 交易是否合法的兩個階段:PAYGAS 以前的驗證階段(verification phase),與 PAYGAS 以後的執行階段(execution phase)。

  • 前者限制交易只能閱讀合約的 storage(e.g. public keys, anti-replay nonces, Merkle roots) 以及不能更改任何狀態,如果交易在這個階段失敗,礦工會拒絕這筆交易。
  • 後者因為已經支付了 fee,如果交易在這個階段失敗,礦工仍然可以選擇要不要加入這筆交易。
Source: Implementing account abstraction as part of eth1.x

handleOps 中有很類似的舉動,面對每一個 UserOperation,handleOps 會用兩個 For Loop 來實作上述兩個 phases,一個是 verification loop,另一個是 execution loop

Verification Loop

  1. 如果這個 UserOperation 還沒有一個對應的 wallet contract,就用 UserOperation 中的其中一個 field:initCode,來佈署一個合約。
  2. 如果 initCode 是空的,或者佈署之後的 Wallet Contract Address 和 UserOperation.sender 不同,這個 call 就視為失敗。
  3. UserOperation 作為參數並且附上手續費,以呼叫 wallet contract 中的 validateUserOp
  4. validateUserOp 首先會用 require(msg.sender == ENTRY_POINT) 確認 EntryPoint 是自己認可的。接著驗證交易是否合法,包含我們上述提到的那些 AA 特性的驗證(multi-sig、social recovery、不同的 Sig. Algorithms 等)以及 nonce 是否正確。
  5. 若是都合法則 Wallet 支付手續費(對應到我們當初說的 PAYGAS)。以上過程中有任何失敗都會 revert。

補充說明:

  • 用戶在送上 UserOperation 這個物件時,必須先用 EIP-1014 自行計算 UserOperation.sender,也就是 CREATE2 創建的 Wallet Contract 的地址。
  • validateUserOp() 和我們之前提到 Bundler 會預先呼叫 EntryPointsimulateValidation() 要做相同的檢查。
  • 需要特別注意 Verification Loop 中,如果再用 call 呼叫其他合約時(depth > 2)有禁止執行的 OpCodes,這個部份對應到之前 EIP-2938 的「限制交易在 PAYGAS 之前只能閱讀合約自己的 storage 以及不能更改任何狀態」。

Execution Loop

handleOps 中的第二個步驟(迴圈)會以 UserOperation 作為 calldata,去呼叫 Verification Loop 佈署的 Wallet Contract。並且執行交易本身該執行的內容。(可想而知 Wallet Contract 要有辦法去 parse 這個 calldata。)

執行完以後,會將剩餘的 gas fee 給予 Wallet Contract。

Paymasters

在 EIP-4337 還有特別重要的一個 Features 叫做 Paymasters

大家還記得在之前的文章中有介紹過的其他支付手續費的方式,以及 Tornado Cash 的 AA Example 嗎。Paymasters 可以做到第三方代替別人支付一筆交易的手續費的行為,此時就可以去接收其他種的 Fee(e.g. 信用卡、ERC-20 等)。

要如何判斷這筆交易的手續費是 Wallet Contract 還是 Paymasters 支付,得看 validateUserOp 中的參數 requiredPrefund 是否為 0。如果我們已經確定要用 Paymaster 支付的話,可以對應著看上方示意圖。

EntryPoint 中要特別去實做一些屬於 Paymaster 的函式,例如:

  1. addStakeunlockStakewithdrawStake:這些函式可以讓 paymasters 管理他們在 EntryPoint 中的資金,Paymaster 必須要抵押資金以此代表同意(保證)成為第三方支付者。
  2. balanceOfdepositTowithdrawTo :這些函式能夠讓 Paymaster 去管理用戶資產在 EntryPoint 這個 Contract 中的狀態。例如 depositTo 可以讓 Paymaster 存款到用戶身上(EntryPoint 中一個儲存用戶狀態的資料結構),之後就可以這裡扣除該用戶交易(UserOperation)需要用到的手續費。

在以上的示意圖中,對應的步驟如下:

  1. Bundler 會呼叫 EntryPointhandleOps
  2. EntryPointUserOperation 作為參數呼叫 wallet contract 中的 validateUserOp,驗證所有交易該驗證的事情,和上文介紹兩迴圈時不同的是:這邊不會支付手續費。 先不付的原因就是為了等第三方的角色(Paymaster)支付手續費。
  3. handleOps除了 validateUserOp 以外,還需要確認 Paymaster 的狀況,例如擁有足夠的 ETH 可以支付這筆交易的手續費。
  4. EntryPoint 呼叫 Paymaster Contract 中的 validatePaymasterUserOp,確認 paymaster 願意支付這筆交易的手續費。願意則支付,如果不願意這筆交易就會 failed。
  5. 呼叫 Wallet Contract 並執行交易本身該執行的內容。
  6. 做完第五步之後,必須緊接著呼叫 Paymaster Contract 的 postOp。需要注意這裡除了跳出去找 paymaster 之外,這一到六步都是不可分割的!
Image Source: Ethereum wallets today and tomorrow — EIP-3074 vs. ERC-4337

上面這張圖也蠻漂亮的,大家可以參考一下:

補充說明:

  • 第一到第四步為 Verification Loop,第五與第六步為 Execution Loop。
  • 為了防止 Paymasters 可能 DoS 系統的風險,我們需要一個 Paymaster 的聲望機制(reputation system) ,詳細可見:reputation, throttling and banning section
  • 可以有多個 Paymasters 來分擔一筆交易的手續費。

Security

整個系統的安全假設有一個前提是 Node(miner / bundler)必須在包裝這筆 UserOperation 時就先利用上文提到的模擬行為確保交易會成功、手續費會被支付(細節可見 此處)。如果這件事情沒有做到,那我們可以假設有惡意人士會提交很多個 operations,並且被包裝抵達 EntryPoint 但在最後一刻(執行了很久之後),才被 revert。但如果有在每次提交到EntryPoint 前確實模擬,那系統就可以預設是 DoS Safe 的。

雖然無論是使用 Wallet Contract 還是 Paymaster 支付手續費,都可以利用模擬行為避免交易在最後一步才被 revert,但 Paymaster 是被第三方製造出來的,因此我們可以想像有一種惡意情況是模擬行為中 paymaster.validatePaymasterUserOp 會成功,但之後的 postOp 等真正要執行時會失敗。

Closing

和前一篇介紹 AA 的文章相同,由於是簡介所以非常多設計細節還有實作的設計想法我都沒有提到,如果想要了解的話可以細細品嘗該 EIP 本身還有下方 Reference 提到的資料。

由於以上介紹的兩個提案都還不是定案,在研究時也會找到許多舊版提案的內容,因此如果大家發現認知與資料不一的情況,可以先去確認 EIP 內文,那裏肯定是最準確的!

本文要感謝 NIC Lin 老師的 Review(這篇超級長的😣)!

Reference: EIP-3074

Reference:EIP-4337

Link Tree

--

--

ChiHaoLu
Taipei Ethereum Meetup

Multitasking Master & Mr.MurMur | Blockchain Dev. @ imToken Labs | chihaolu.me | Advisory Services - https://forms.gle/mVGKQwPQEUP37fLYA