作者:Seungmin Jeon 來源:medium 翻譯:善歐巴,金色財經
首爾國立大學區塊鏈學院的 Decipher Open Source Warriors 團隊撰寫了一篇關于 ERC-6900 的文章。本文基于代碼進行分析,從提案的背景到實現的方法和意義。
ERC-4337是一個標準,允許在不改變以太坊客戶端的情況下順利使用合約錢包(賬戶),通過一個名為“用戶操作”的對象進行額外的驗證,取代傳統交易。遵循 ERC-4337 標準的合約賬戶可以包含各種功能,例如支付 Gas 費用的 Paymaster、批量交易、BLS 簽名聚合、社交恢復和會話密鑰。
與傳統的 EOA(外部擁有帳戶)相比,這可以實現更高水平的用戶體驗。例如,使用ERC-4337的paymaster,用戶可以使用ERC-20代幣而不是ETH來支付gas費,或者讓協議支付。此外,如果用戶可以通過會話密鑰臨時將其帳戶委托給協議,則不必為每筆交易單擊按鈕,他們只需單擊一下即可與協議進行交互。
然而,ERC-4337的提出是為了在不改變協議的情況下實現賬戶抽象,因此并沒有定義智能合約賬戶應該采取什么形式。于是,各種形式的合約賬戶被提出,導致以下兩個問題:
1.不同賬戶形式導致的兼容性問題
目前,各個公司(例如ZeroDev、Biconomy)都提供SDK形式的合約賬戶,但每個公司提供的賬戶形式都不同,導致兼容性問題。這使得支持合約錢包的應用程序的用戶很難在應用程序之外使用這些錢包,也使得應用程序很難容納各種合約賬戶的用戶。換句話說,雖然通過 ERC-4337 改進了 UX,但它具有將用戶鎖定在應用內的副作用。
2.賬戶的擴展性問題
通過 ERC-4337 提供的大多數功能都在賬戶內運行,但由于賬戶采用智能合約的形式,因此更改和可擴展性都受到限制。雖然可以對賬戶應用Proxy結構來進行升級,但這個過程也很不方便。例如,如果用戶想要向其現有合約帳戶添加新功能,則必須將整個代碼轉移到具有該功能的新合約中。此升級過程可能會導致新合同的額外審計成本等問題。此外,由于為所有用戶提供統一形式的帳戶,因此存在用戶無法選擇其帳戶內的功能的缺點。
為了解決這些問題,2023 年 4 月提出了名為 ERC-6900 的新標準。
ERC-6900 是一個名為“模塊化智能合約賬戶和插件”的 EIP,為與 ERC-4337 兼容的賬戶提供了標準。它基于模塊化結構,允許在帳戶中自由安裝和刪除各種功能,類似于在 Android 上安裝或卸載應用程序。包含要包含在帳戶中的功能的模塊合約稱為插件。
ERC-6900通過其模塊化結構,使用戶能夠輕松地向其帳戶添加或刪除各種插件(功能)。特別是,由于當前的合約帳戶通常僅限于特定應用程序,因此使用 ERC-6900 可以允許單個合約帳戶輕松地在多個應用程序中使用。
雖然這是一個非常有趣的想法,但在實際代碼中實現它時必須考慮以下因素,重點關注安全性和用戶體驗:
插件的安裝和刪除
首先考慮的應該是如何實現插件的安裝和刪除。ERC-6900 的開發者從 Diamond Proxy 中汲取了靈感。Diamond Proxy 是典型可升級代理的擴展結構,將合約劃分為多個組件(或方面),并只允許其中的某些組件進行升級。與簡單的可升級代理結構不同,簡單的可升級代理結構需要更改整個邏輯合約才能進行升級,鉆石代理允許僅選擇和升級所需的組件。
在 Diamond Proxy 中,合約的各種功能被劃分為稱為 Facet 的組件,Proxy 使用 來調用它們delegatecall
。delegatecall
是一個“借用”外部合約函數并在自己的合約上下文中使用它們的函數,允許通過外部函數對其自己的合約存儲進行強大的操作。
此外,Diamond Proxy 維護基于函數選擇器的映射,以指定每個方面的訪問路徑。這允許代理合約自由訪問每個方面內的功能。
Diamond Proxy 的結構 來源:ERC-2535 官方文檔
此外,為了安全起見,Diamond Proxy 將所有數據存儲在代理合約中,并將可訪問的數據分配給每個方面。如果對facet使用的數據沒有權限限制,在某些情況下可能會出現問題。例如,zkSync 在以太坊上部署了類似 Diamond 代理的合約,為治理、L1 ? L2 橋接和匯總數據發布創建了方面。如果治理方面可以訪問用于橋接的參數,則可能會因不當操作或攻擊而危及整個系統。
總結起來,Diamond Proxy 具有三個主要特點:
協議功能分為多個方面合約,通過 訪問delegatecall
。
代理合約可以通過函數的選擇器調用切面函數。
每個方面可訪問的數據都受到限制。
Diamond Proxy 具有這些特性,針對構建多功能合約系統進行了優化。這與 ERC-6900 創建“具有各種功能的智能合約賬戶”的目標非常吻合。因此,ERC-6900借用了Diamond Proxy的結構來實現安裝和刪除插件的功能。然而,ERC-6900 和 Diamond Proxy 之間存在顯著差異,稍后將討論。
2. 用戶與賬戶交互
假設建立了一個可以自由安裝和刪除插件的環境,那么要考慮的第二個方面是用戶如何與帳戶交互。合約賬戶與用戶的交互主要分為兩種:一是通過ERC-4337的入口點合約進行用戶操作進行交互,二是用戶直接調用合約賬戶內的函數。ERC-6900 將這兩種類型的交互分別區分為“用戶操作驗證”和“運行時驗證”,并為每種交互提供單獨的驗證和執行流程。
3. 許可
要考慮的第三個方面是許可。如果任何人都可以創建和安裝插件,則必須考慮這些插件被濫用的可能性。例如,想象一個會話密鑰插件,它可以在一段時間內提供帳戶所有權。如果會話密鑰所有者與惡意合約交互,則帳戶的資金可能會完全丟失。因此,嚴格設置和驗證插件可以訪問的外部合約功能以及插件之間交互的權限至關重要。
4. 保證模塊化
最后要考慮的是如何保證模塊化。在可以自由安裝和從帳戶中刪除各種插件的環境中,存在一些可能導致意外結果的邊緣情況。例如,插件 A 和 B 可能具有具有相同選擇器的功能。與 Diamond Proxy 一樣,ERC-6900 使用選擇器映射來調用插件內的函數,但如果這些選擇器重疊,則存儲在先前安裝的插件的選擇器中的信息可能會被刪除,并替換為后來安裝的插件中的信息。
這可能會導致帳戶出現意外錯誤,因此需要加以預防。
為了解決這個問題,ERC-6900 引入了一項稱為“依賴性”的功能。當想要從中借用函數或插件中的特定函數具有相同的選擇器和功能時,此機制通過將已部署的插件設置為依賴項來防止沖突。
因此,ERC-6900的特點可以概括為四點:
它遵循 Diamond Proxy 的結構(但有顯著差異,稍后將討論)。
用戶交互分為用戶操作和運行時,每種交互都有不同的驗證和執行過程。
它嚴格限制通過插件進行的操作權限。
為了防止沖突并確保插件安裝和刪除過程中的模塊化,可以設置依賴關系。
在接下來的章節中,我們將仔細研究這四個方面。
Diamond Proxy
ERC-6900采用Diamond Proxy的結構,形成插件和合約賬戶的模塊化結構。該帳戶充當代理合約,每個插件充當一個方面。因此,當帳戶發生用戶操作或直接調用時,它會通過后備函數(當在合約中找不到被調用函數的選擇器時執行的函數,通常在代理模式中使用)在插件內進行處理。在這個過程中,與前面提到的Diamond Proxy有一個至關重要的區別。
Diamond Proxy 用于delegatecall
調用構面內的函數。由于facet是只包含執行邏輯并且不需要存儲(有時甚至部署為沒有存儲的庫)的合約,因此delegatecall
被使用。然而,在 ERC-6900 中,插件內的函數被調用 using call
,并且插件有自己的存儲。原因如下:
如果delegatecall
帳戶允許插件,則插件的功能可以訪問帳戶的存儲數據。這是非常危險的,因為惡意插件可能會刪除或操縱帳戶的存儲信息。這在最初的 Diamond Proxy 中并不是一個主要問題,因為并非任何人都可以添加構面。然而,由于 ERC-6900 的目標是一個任何人都可以自由構建插件的環境,因此delegatecall
可能會帶來重大風險。
因此,在 ERC-6900 中,call
使用 代替delegatecall
,允許數據也存儲在插件的存儲中。
MSCA 內部的調用流程
在 ERC-6900 中,合約賬戶被稱為模塊化智能合約賬戶 (MSCA)。ERC-6900 定義的 MSCA 內部的調用流程可以概括如下:
我們來看看用戶操作部分。在ERC-4337中,用戶操作的驗證和執行是分離的,因此流程分為驗證和執行,如上圖左側所示。另一方面,對于MSCA內的直接調用,流程通過運行時驗證功能進行驗證,如右圖所示。每個流程都會經歷幾個階段,包括驗證函數、掛鉤和執行函數。
這里使用的函數大致可以分為三種類型。首先,在帳戶或插件內執行某些操作的函數稱為執行函數。隨后,對于每個執行函數,都有一個驗證函數對其調用進行驗證。此外,可以在每個函數調用之前和之后應用掛鉤。讓我們更詳細地研究每一個。
驗證功能
該函數對賬戶調用者進行權限驗證。如前所述,如果任何人都可以調用賬戶內的函數,則該賬戶可能容易受到通過 Gas 消耗耗盡資金的攻擊。因此,消耗gas或訪問存儲的函數必須通過驗證函數進行控制。
有兩種類型的驗證函數:用于從入口點傳入的調用的用戶操作驗證函數,以及當 EOA 直接調用帳戶內的函數時執行的運行時驗證函數。
這些驗證功能并不存在于賬戶本身;它們都可以在插件中找到。因此,對帳戶的所有調用都會通過插件中的驗證函數。根據用例,可以有各種類型的驗證函數,例如:
驗證簽名并僅允許所有者的地址通過的功能。
驗證簽名并僅允許指定地址通過的功能。
允許任何地址通過的函數。
2. 執行函數
這些是實際資金轉移和與外部合約交互發生的功能。主要有兩種類型:
1) 標準執行函數
指與ERC-4337參考實現的接口execute
和executeBatch
功能兼容。IAccount
這些函數可以根據賬戶的gas費執行所有類型的交互,因此需要嚴格的驗證函數(例如,只允許所有者調用)。
2)執行函數
這些是每個插件中存在的功能以及可以從帳戶執行的常用功能。例如,考慮recoverOwner
在社交恢復插件中調用的函數。由于只有分配用于恢復的監護人才能調用此函數,因此它必須具有適當的驗證函數。在ERC-6900中,這應用于執行函數,如下所示:
通過將此信息存儲在帳戶的存儲中,當recoverOwner
調用該函數時,可以通過onlyGuardiansValidationFunction
.
執行函數的選擇器存儲在帳戶存儲中,在插件安裝時映射到插件地址。
3. 掛鉤
還有一個稱為鉤子的函數,它在其他函數之前和之后運行。與Uniswap V4的Hook類似,它定義了特定任務之前和之后需要執行的操作。例如,可能有一個DailyGasSpendingLimit
限制每日燃氣消耗的 Hook。該鉤子可以在執行函數之前和之后使用該函數檢查gas消耗情況gasleft()
,如果一天內消耗了一定量的gas,則阻止該函數的執行。
驗證函數之前還可以有一個預驗證鉤子,主要用于需要多次驗證的情況。例如,如果會話密鑰插件中的會話密鑰是多重簽名錢包,則它需要同時通過多重簽名和會話密鑰驗證。在這種情況下,多重簽名的驗證可以作為預驗證掛鉤來執行,而會話密鑰的驗證可以作為驗證函數來執行。
更詳細的調用流程可以用下圖表示:
每個過程總結如下:
封裝并調用要執行的插件的執行函數calldata
。如果帳戶中沒有與此函數匹配的選擇器,fallback
則執行該函數(這適用于除標準執行函數(如 、 或稍后提到的 、 )之外的execute
所有executeBatch
情況executeFromPlugin
)executionFromPluginExternal
。
解析出哪個插件地址包含 中的執行函數后calldata
,就會執行關聯的預驗證鉤子和驗證函數。如果調用通過 ERC-4337 入口點,則驗證邏輯已經執行,因此會被跳過。
執行與 Execution 函數相關的預執行鉤子。此掛鉤執行的結果返回有關要運行哪個執行后掛鉤的信息。
執行函數被執行。
根據步驟3返回的結果,執行執行后掛鉤。
這里重要的一點是,msg.sender
對插件的調用始終是帳戶。因此,在插件中存儲或查詢帳戶相關信息時,msg.sender
使用如下:
這意味著該插件的功能是建立在從賬戶調用的前提下的。但是,這可能會導致以下問題:
如果從另一個帳戶或插件調用特定插件的函數,msg.sender
則將其設置為調用者,引用與從帳戶調用時不同的存儲,從而導致不同的結果。如果某個特定插件需要調用另一個插件中的函數,如何解決這個問題?
executeFromPlugin
為了解決這個問題,ERC-6900 定義了和 等函數executeFromPluginExternal
。這些功能不僅解決了上述問題,還可以防止賬戶受到各種攻擊場景。
executeFromPlugin
和executeFromPluginExternal
是定義和限制可以通過插件執行的任務的函數,每個函數都具有以下功能:
executeFromPlugin
當一個插件想要調用另一個插件中的函數時使用。它設置msg.sender
為帳戶,允許在另一個插件中執行執行函數,而不會引用錯誤的存儲或丟失調用的上下文。此外,為了防止惡意插件的攻擊,如果該函數不是安裝時預先指定的插件的函數,則該函數會恢復調用。
另一方面,executeFromPluginExternal
更加注重安全問題。當插件想要調用外部實體中的函數時使用它。一個典型的用例是會話密鑰插件。如果具有會話密鑰的地址可以調用任何外部函數,則會帶來重大的安全風險。因此,有必要預先指定會話密鑰可以訪問的外部合約和函數,并在嘗試訪問未列出的函數時恢復調用。根據 ERC-6900 標準實現這一點如下所示:
首先,在插件內指定可以訪問的外部合約和函數。這在插件部署期間被硬編碼到合約中,使其以后不可變。
然后,在同一個插件中定義以下執行函數:
executeFromPluginExternal
當會話密鑰通過調用帳戶內的函數發送令牌時,使用此函數。在executeFromPluginExternal
帳戶內執行以下步驟:
從存儲中檢索預定義的允許呼叫信息。
將此信息與輸入的呼叫信息進行比較,如果不允許呼叫,則恢復。
執行調用。如果有執行鉤子,它也會被執行。
因此,executeFromPlugin
并executeFromPluginExternal
限制插件可以執行的功能。msg.sender
這不僅可以防止從插件內直接調用另一個插件時調用 () 的上下文發生更改,而且還可以限制對外部合約的訪問。
然而,不可能完全禁止插件通過executeFromPluginExternal
. 它無法阻止插件內的執行函數對地址進行硬編碼并從外部調用。因此,只有已完成審核的插件才應安裝在帳戶上,以防止黑客攻擊等問題。
依賴性
最后,一個插件可以對其他插件有依賴性(dependency)。這主要在從其他插件借用函數(驗證函數、執行函數)時使用。一個典型的例子是SingleOwnerPlugin
參考實現中的。它包含一個只允許所有者調用的函數,如下所示:
由于這是一個非常通用的驗證函數,其他插件可能會借用并使用它。在這種情況下,如果在安裝插件時將其作為依賴項輸入,則可以在插件中使用驗證功能,而無需單獨實現該功能。
當特定執行函數的驗證函數重疊時,此功能極大地有助于減少代碼的大小并提高可讀性。具有只有所有者才能訪問的功能的插件可以將上述 SingleOwnerPlugin 設置為依賴項,并對其功能使用其驗證功能。
因此,可以從其他插件接收所有 Hook、驗證函數和執行函數,如上所示。換句話說,可以基于依賴關系來實現插件的模塊化架構。
這方面的一個例子可以在上面提到的類似代理的結構中看到。基本驗證函數和必要的數據位于“父插件”中,多個“子插件”僅包含邏輯并依賴于父插件中的驗證函數。這允許安全地添加、刪除或替換邏輯,同時保留父插件合約中的數據和上下文。
Decipher Open Source Warriors 團隊利用插件的模塊化架構和上述功能,實現了符合 ERC-6900 標準的會話密鑰插件,executeFromPluginExternal
并向官方 ERC-6900 實現 GitHub 請求拉取請求。目前,我們正在根據 PR 后收到的反饋對其進行修改,并計劃為基于社區的插件提供一個單獨的位置。
會話密鑰插件由一個名為 的父插件BaseSessionKeyPlugin
和一個名為 的子插件組成TokenSessionKeyPlugin
。與現有的會話密鑰實現相比,該插件具有以下兩個優點:
通過使用依賴關系,它可以管理單個父插件中的所有會話密鑰信息。
通過使用executeFromPluginExternal
,它嚴格限制子插件可以訪問的外部合約,從而即使在會話密鑰被惡意或被黑客攻擊的情況下也可以防止帳戶內的資金外流。
顯現
最后,為了確保安全安裝而不與其他安裝的插件發生沖突,插件有一個名為manifest
. 它包括有關插件的執行函數、驗證函數、掛鉤以及依賴項、允許的調用等的信息。在安裝過程中,會驗證此信息,并將插件內函數的所有選擇器存儲在帳戶的存儲中。
ERC-6900仍有許多問題需要解決,原因如下:
1.合約規模
參考實現中智能賬戶UpgradeableModularAccount.sol的合約大小約為33KB。以太坊將可在主網上部署的合約的最大大小限制為 24KB,這是 2016 年Spurious Dragon硬分叉中設置的限制。因此,該合約尚無法部署在主網或測試網上。
原因之一是因為 ERC-6900 使用call
而不是delegatecall
. 通過在外部庫或合約中實現一些函數并通過調用它們delegatecall
,可以在縮小合約大小的同時修改帳戶存儲。然而,由于ERC-6900出于安全原因限制了使用delegatecall
,訪問存儲的功能必須在合約內實現,從而增加了合約的大小。
因此,需要努力減少合約的規模,例如重構冗余部分。
2. Gas Consumption
從調用流程圖中可以看出,ERC-6900 包括賬戶和插件之間的多次調用,這增加了 Gas 成本。根據實現情況,每次外部合約調用大約消耗 2,000 GAS。雖然如果只涉及一個插件(熱/冷地址),這一成本可能會略有降低,但如果涉及多個插件,成本就會變得昂貴,增加用戶的負擔。然而,通過gas優化來降低用戶成本至關重要,例如在賬戶和插件合約的功能中使用組裝塊。實現 ERC-6900 的 Alchemy 團隊正在考慮根據各種選項修改架構,例如應用 Dencun 更新附帶的 EIP-1153 的臨時存儲或將多個驗證步驟捆綁到多重調用中。
同時,當前的參考實現部分犧牲了可讀性的優化。Alchemy 團隊計劃在明年初將其更新為可部署在主網上,屆時,第 1 點和第 2 點提到的問題預計將大部分得到解決。
3. 插件實現的復雜性
從開發人員的角度來看,實現插件需要考慮許多因素。雖然有很多復雜性,但一些例子包括:
決定是直接定義與每個執行函數關聯的驗證函數,還是通過其他插件的依賴設置接收它們。
當需要對調用者進行多次驗證時,確定如何劃分和設置預驗證鉤子和驗證函數。
確保與現有插件的兼容性。例如,如果要在插件中實現的功能已經存在于現有插件中,則需要通過調用它executeFromPlugin
或將其設置為依賴項。
這些復雜性可以從不同的角度來解決。首先,架構本身可以添加某種形式的接口或方法來抽象復雜性。需要為插件開發人員提供文檔,并且可以開發一個組織現有插件的功能和方法的儀表板,以方便管理依賴項和executeFromPlugin
.
Alchemy 團隊正在致力于更新以降低所指出的復雜性,以響應通過 Telegram 和每兩周一次的社區電話收到的社區反饋。
ERC-6900 允許從帳戶安裝和刪除插件,類似于安裝和卸載 Android 應用程序。這使得用戶能夠根據自己的需求和偏好個性化他們的錢包并添加或刪除功能,從而創建定制的用戶環境。它將解決ERC-4337兼容錢包之間的兼容性問題,允許在不同錢包平臺之間自由移動。
此外,ERC-6900提出了一個可以被合約賬戶廣泛接受的通用標準,同時融入了各種元素以促進實施并增強賬戶安全性。
修改后的 Diamond 代理結構,用于安全安裝和刪除插件。
函數(驗證函數、執行函數、掛鉤)和調用流程結構可有效、安全地管理帳戶和插件之間的交互。
權限設置保證插件的靈活性和安全性。
依賴關系可防止插件之間功能重疊引起的沖突并幫助代碼優化。
通過該標準,預計以太坊和EVM兼容鏈的錢包生態系統將得到發展,用戶體驗將得到顯著改善。
ERC-6900 官方文檔
ERC-6900 參考實現 GitHub
ERC-6900 社區通話