# Enzyme 架構 Enzyme協議是一種基於以太坊的用於去中心化的鏈上資產管理協議。 它是個人或團體在可定制且安全的環境中管理其財富和他人財富的協議。 Enzyme 使任何人都可以建立、管理和投資定制的鏈上投資工具。 # 架構 ## 永久架構 ### 設計理念 Enzyme v2 的最大目標之一是擁有可升級的資金。找到合適的模式是一項具有挑戰性的任務,因為 - 我們有不同類型的合約,由基金組成並由基金共享,例如基金庫、插件(費用、政策和 DeFi 適配器)、可以在版本之間持續存在的基礎設施等, - 對於基金經理和投資者來說,有機會選擇加入或退出每次更新對我們的理念很重要(即,我們無法改變 PerformanceFee 對已經在使用它的每隻基金的運作方式) ### 方法 我們確定的模式是用戶啟動的從舊版本到當前版本的部分遷移(僅限基本狀態)。 基金的基本狀態是: - 其持有量(即代幣餘額) - 其對基金投資者份額的會計處理 - 所有權和狀態變化交互的訪問控制 這種遷移模式是通過兩個持久合約完成的:一個“Dispatcher”和每個基金的“VaultProxy”實例。 #### VaultProxy(代理金庫) 上面描述的“基本狀態”存在於每個基金的 `VaultProxy` 合約實例中,這些合約是遵循 EIP-1822 代理模式的可升級合約。 `VaultProxy` 指定了一個 `VaultLib` 作為其目標邏輯,這些邏輯合約在每個版本中部署,並在遷移期間換出。 `VaultLibBaseCore` 合約為每個 VaultProxy 定義了絕對必要的狀態和邏輯。這包括 - 一個名為“SharesTokenBase”的標準 ERC20 實現 - 由`Dispatcher`調用的`IProxiableVault`所需的功能 - 核心訪問控制角色:`owner`、`accessor`、`creator` 和`migrator` `owner` 是基金的所有者。 `migrator` 是一個可選角色,允許非所有者遷移基金 `creator` 是 `Dispatcher` 合約,只有這個角色被允許更新 `accessor` 和 `vaultLib` 值。 `accessor` 是可以對 `VaultProxy` 進行狀態更改調用的主要帳戶。在實踐中,這是與金庫資產交互、更新股票餘額等的發布級別合約。 這個極其抽象的接口——其中一個“VaultProxy”不需要任何關於版本的知識,除了調用者可以寫狀態——允許發布級架構幾乎無限的可能性。 `VaultLibBaseCore` 合約可以通過實現一個新的 `VaultLibBaseN` 擴展以前的基礎來擴展新的存儲和事件。例如,第一個版本實現了“抽象合約 VaultLibBase1 是 VaultLibBaseCore”。添加到狀態或事件的下一個版本將使用“抽象合約 VaultLibBase2 是 VaultLibBase1”繼續這種模式,依此類推。 該版本本身將提供一個 `VaultLib`,它擴展了最新的 `VaultLibBaseN` 實現,並具有該版本所需的邏輯。 #### Dispatcher(調度員) 一個總體的、不可升級的“調度員”合同負責 - 部署`VaultProxy`的新實例 - 將“VaultProxy”從舊版本遷移到當前版本 - 維護全局狀態,例如當前版本、全局所有者(即酶委員會)和基金份額代幣的默認`symbol`值 `Dispatcher` 存儲 `currentFundDeployer`(對負責部署和遷移資金的最新版本合約的通用引用),並且只有具有該值的 `msg.sender` 被允許調用函數來部署或遷移 ` VaultProxy`。 這個發布級別的`FundDeployer` 可以選擇實現`IMigrationHookHandler` 提供的遷移掛鉤,這使發布有機會運行任意邏輯,因為`Dispatcher` 在遷移過程的每一步都調用這些掛鉤。 與上面對 `VaultLibBaseCore` 描述的情況一樣,這個 `FundDeployer` 的抽象概念 - 其中 `Dispatcher` 只關心其訪問和可選回調的身份 - 完全不受發布級別的限制協議。 因此,從這些持久性合約的角度來看,發布級別的合約大多是任意的,為未來的迭代和更改提供了最大的靈活性。 # 發布架構 ## 核心 ### FundDeployer(資金部署者) `FundDeployer` 是用戶創建新基金和指示基金從舊版本遷移到當前版本的網關(gateway)。 如上一頁所述,這是`Dispatcher` 認為是`currentFundDeployer` 的契約,因此允許它部署和遷移`VaultProxy` 實例。 `FundDeployer` 為每個基金部署配置合約(`ComptrollerProxy`),然後附加到 `VaultProxy` 實例(更多內容在下一節)。 `FundDeployer` 還用作幾種類型值的發布範圍參考點。 第一個是`releaseStatus`。當設置為 `Paused` 時,除了贖回份額外,禁止任何寫入 `VaultProxy` 存儲的功能。這是在其中一個協議合約中發現嚴重錯誤的情況下的安全機制。 `FundDeployer` 的第二個存儲值是在發布範圍內引用的,它是允許的“金庫調用(vault calls)”的註冊表,它由 `ComptrollerLib` 引用。這允許從 `VaultProxy` 作為 `msg.sender` 進行任意調用,這將用於調用,例如將 `SynthetixAdapter` 直接從 `VaultProxy` 委派為 Synths 的批准交易者。 該版本有 1 個共享的“FundDeployer”。 ### 審計員代理(ComptrollerProxy) 每個基金都部署了一個“ComptrollerProxy”,它是此版本中與基金交互的規範合約。它存儲核心版本級別的配置,並通過上一頁中描述的後者的accessor角色附加到“VaultProxy”。 因此,所有與基金持有和股份相關的“VaultProxy”的狀態改變調用都必須通過“ComptrollerProxy”,使其成為訪問控制的一個至關重要的瓶頸。 `ComptrollerProxy` 的存儲和邏輯由 `ComptrollerLib` 及其相關庫定義。儘管它繼承了與“VaultProxy”相同的可升級“Proxy”,但在此版本中無法調用升級。 ### VaultLib 如上一頁所述,“VaultLib”合約包含附加到此版本的“VaultProxy”實例的存儲佈局、事件簽名和邏輯。 該版本有 1 個共享的“VaultLib”。 ## 擴展 擴展通過添加額外種類的功能來擴展核心合約的邏輯。 它們是半信任的,因為它們被有選擇地授予對“VaultProxy”實例的狀態更改調用的訪問權限。 為了進行這樣的狀態改變調用,必須滿足兩個條件: 1. 擴展功能必須已被`ComptrollerProxy`通過帶有`allowsPermissionedVaultAction`修飾符的函數調用,該修飾符打開調用`ComptrollerProxy`到`VaultProxy`的狀態變化。 2. 狀態改變調用必須通過`ComptrollerProxy`回傳,並委託給`PermissionedVaultActionLib`來確定是否允許調用Extension執行這樣的動作。 這種範式確保擴展只能對“VaultProxy”執行狀態更改操作,前提是它被“VaultProxy”的相應“ComptrollerProxy”調用,並且如果擴展被允許進行此類更改。 雖然這對於當前版本來說似乎有點矯枉過正,其中擴展都是受信任和審計的,但它減少了審計表面積(例如,`PolicyManager` 沒有允許的操作)並為後續版本打開大門,以允許任意擴展。 在此版本中,共有三個擴展。所有基金每個擴展共享一份合同。 ### 集成管理器 `IntegrationManager` 允許通過 DeFi 協議(例如 Uniswap、Kyber、Compound、Chai)的“適配器”將基金資產交換為其他資產。 它以幾乎不受信任的方式處理這些適配器插件(它確實依賴適配器根據用戶輸入報告預期花費和接收的資產),根據預期值驗證花費和接收的資產價值,並為政策實施提供機會在資產交換之前和之後運行的鉤子(hooks)。 ### 策略管理器 `PolicyManager` 允許通過“策略”進行狀態驗證,這些策略實現了在購買股份和在 `IntegrationManager` 中進行交換時調用的鉤子 策略中不涉及信任,因為“PolicyManager”無法訪問更改狀態的保險庫操作。 ### 費用管理器 “費用管理器”允許“費用”根據其內部邏輯來決定基金份額的鑄造、銷毀或轉讓。 與 `PolicyManager` 一樣,`FeeManager` 在核心邏輯的不同點調用鉤子,即在購買份額、贖回份額時,以及在特定函數上調用“持續”鉤子(例如,對於每增長一次的 `ManagementFee`堵塞)。 ## 插件 上面的每個擴展都使用插件。 `IntegrationManager` 使用“適配器”,`PolicyManager` 使用“策略”,而 `FeeManager` 使用“費用”。 允許的插件都在其各自的擴展中的註冊表中定義。 與擴展一樣,後續版本的計劃是為第三方開發開放這些插件。 ### 基礎設施 除了“核心”和“擴展”發布級合約,還有完全解耦的“基礎設施”合約,理論上可以在發布之間循環使用。目前,該類別僅包含與資產價格和價值相關的合約,但它也可以包含諸如即將發布的將實施協議費用的合約。 #### 值解釋器(ValueInterpreter) ValueInterpreter 是各種價格饋送的單一聚合點,用於根據輸出資產計算一個或多個輸入資產金額的價值。 此版本中有兩類資產: - 基礎資產(primitives) —— 有直接利率的資產,用於將一種基礎資產轉換為任何其他基礎資產(例如,WETH、MLN 等) - 衍生資產(derivatives) —— 用機率構成的資產(例如 Chai、Compound cTokens、Uniswap 池代幣等) ValueInterpreter 決定資產是原始資產還是衍生資產,並執行邏輯以使用相應的價格饋送來確定輸出資產的價值。 此版本中的每個類別只有一個受支持的價格饋送,因此兩者都被硬編碼為不可變變量。 #### 基礎資產價格資料 ChainlinkPriceFeed (IPrimitivePriceFeed) ChainlinkPriceFeed 提供基礎資產之間的所有轉換。該提要向其 Chainlink 聚合器註冊資產,從而定義發布的原始資產領域。 #### 聚合衍生資產價格資料(AggregatedDerivativePriceFeed) AggregatedDerivativePriceFeed 作為一個中央註冊表,將衍生品映射到相應的價格源,並從中獲取匯率。 有幾個單獨的價格饋送提供衍生品對其標的資產的實際匯率。每個都繼承了 IDerivativePriceFeed 來為 AggregatedDerivativePriceFeed 提供一個標準接口來註冊衍生映射和抓取率。例如,CompoundPriceFeed、ChaiPriceFeed #### 接口 外部合約的所有接口都包含在 release/interfaces/ 目錄中。 內部合約的接口(例如 IFundDeployer )保存在它們所引用的合約旁邊。這些是窄接口,僅包含其他非插件、發布級合約(即上面“核心”和“擴展”部分中的那些)所需的功能。這個想法是對合約之間交互的內部發布表面積有一個方便的視覺參考。