本文讨论了Safe智能合约架构中,是否应该使用Diamond Proxy模式。
Safe 智能账户 & Diamond Proxies (钻石代理)
概要:
Safe 是一个模块化的智能账户协议,它使用 账户抽象 通过共享的插件接口来构建各种钱包和其他解决方案
一些社区成员,包括 最近的 ERC-6900 中的成员,提倡对像 Safe 这样的模块化智能账户使用 Diamond Proxies
在过去的几周里,Safe Core 团队评估了将其智能合约架构更改为 Diamond Proxy 模式,以用于即将推出的 v2 智能合约
由于安全问题,Diamond Proxy 设置被放弃,我们通常建议不要将其用于智能账户
Safe 合约的目标之一是模块化和可扩展性。 我们认为这对于充分利用智能账户(账户抽象)的力量至关重要。自 2018 年 Safe 的第一个版本 以来,这一直是首要任务,并且会不断重新评估。Safe 合约的另一个关键方面是安全性。我们的目标是在不牺牲安全性的前提下提供高水平的模块化。
模块化智能账户面临的最大安全挑战之一是管理与复杂智能合约设置相关的风险。 一种方法是明确区分关注点 [ 1, 2]。 在当前的 Safe 合约中,这种分离是通过不同的、独特的插件类型来实现的:
模块(Modules)- 白名单地址,可以以 Safe 智能账户的名义执行交易。
守卫(Guard)- 可以设置为对要执行的交易执行额外检查的合约
回退处理程序(Fallback Handler)- 可以设置为处理任意传入(读取)调用的合约
Safe 模块通过创建额外的访问逻辑来执行交易,从而扩展了核心 Safe 合约的逻辑。 例如,Allowance Module 允许向单独的账户授予消费限制,然后这些账户不需要来自所有用户的确认。图 1 显示 Safe 模块是独立的智能合约,确保了关注点的明确分离。“接触点” 只有允许 Safe 模块执行交易的方法(即 execTransactionFromModule
)。这强制执行了对模块合约的严格安全假设,这是必要的,因为模块可以通过 Safe 执行任何任意交易。
图 1:Safe 模块与 Safe 智能账户的交互
Safe Guard 是一个可以为 Safe 设置的合约,用于执行额外的安全检查(也称为“Hook”)。 图 2 概述了注册 Guard 时的总体流程。在执行 Safe 交易之前,会使用所有交易参数调用 Guard。如果 Guard 没有 revert,Safe 智能账户将执行 Safe 交易并在之后再次调用 Guard。例如,这可以用于仅允许与特定合约交互或检查 Safe 在执行交易后的状态。
图 2:Safe Guard 在 Safe 智能账户上的流程
Fallback Handler 处理传入的调用,并允许为需要不同类型回调的新颖标准/资产实现逻辑。 图 3 概述了 Safe 如何使用它来启用对合约签名 (EIP-1271) 以及不同 token 标准(即 ERC-721、ERC-1155 和 ERC-777)的支持。
图 3:Safe 智能账户的回退处理程序功能
这三种插件类型使 Safe 合约非常灵活,同时明确区分不同的关注点以限制复杂性。 插件完全独立于核心 Safe 合约,并维护自己的存储。交互仅通过明确定义的接口进行,从而允许强大的安全指南和自动化测试。
随着以太坊格局的发展和智能合约新模式的开发,有必要不断评估如何改进 Safe 合约。几个主题将影响 Safe 合约的 v2 的开发。
我们关注的一种模式是 Multi-Facet Proxy 模式(又名 Diamonds),这也是 最近的标准化模块化智能账户提案草案 所青睐的。
Safe Proxy 模式设置了一个逻辑合约(又名 Singleton 或 Mastercopy),它定义了代理将如何对传入的调用和交易做出反应。这也是 OpenZepplin 在其 可升级代理 中使用的一种非常常见的模式。Diamond Proxies 通过允许根据传入的调用设置多个逻辑合约(称为 Facets)来扩展此模式。 有趣的部分是这些传入的调用被智能合约处理时会发生什么。图 4 显示了 Diamond 合约的总体布局。对于每个传入的调用,Diamond 基础逻辑 (CodeD) 都会检查是否注册了 Facet。如果是这种情况,Facet 的代码(CodeA 或 CodeB)会在 Diamond 的上下文中使用 delegate call 执行。
图 4:Diamond 合约布局
Diamond 及其 Facets 共享相同的存储区域。这使得它们可以共享特定的存储值(DataABD 或 DataAB),同时每个仍然有自己的值(DataD、DataA 和 DataB)。为了避免存储布局冲突的问题,建议通过使用 “非结构化存储” 方法为每个 Facet 设置一个唯一的“存储区域”。
如果任何 Facet 覆盖了另一个 Facet 的存储区域或 Diamond 不正确地使用了共享存储,则可能会导致完全出乎意料的行为。因此,明确定义使用的存储区域非常重要,因为存储冲突可能会破坏账户、使交互变得不可能或以其他方式危及其安全性和完整性。
Diamond 模式非常灵活和模块化,如果你有一个依赖于单个合约的大型项目,这将特别有用。然后,项目团队可以维护具有不同 Facets 的 Diamond 设置,并审计任何提议的更改,以确保新的 Facets 不会破坏该设置。但是,这可能非常复杂并且需要相当多的关注。由于 Facets 相互影响,只有在已知包括所有 Facets 的特定设置时,才能进行完整的审计和做出强大的安全假设。Trail of Bits 提供了 一个很好的总结,说明在使用 Diamond 模式时应该注意什么。
虽然 Diamond 模式可能提供一些好处,但我们认为它会损害关注点的分离,并增加为 Safe 智能账户维护高安全标准的复杂性。 虽然专业的团队可能能够评估和审计这种复杂性,但对于个人用户来说,这可能非常具有挑战性。此外,每个用户的设置可能略有不同,并导致对不同 Facets 产生特有的影响。这增加了复杂性,即使是专业的审计师也会发现确保所有可能设置的安全性具有挑战性。
另一方面,与当前模块方法相比,使用 Diamond 模式的好处是有限的。最大的优势是 gas 使用量略低,并且可以通过 Diamond 公开所有 Facets。 由于我们的目标是最大限度地提高合约的安全性,因此我们认为 Diamond 模式不是实现此目标的正确方法。尽管如此,我们将继续评估不同的模式,以在最高的安全级别提供最佳的用户体验。
经过仔细考虑,我们决定不对 Safe 合约的下一个版本使用 Diamond 模式。 我们的主要优先事项是在为用户保持灵活性的同时提供高水平的安全性。为实现此目标,我们将 Safe 智能账户设计为将核心合约的存储和逻辑代码与任何插件(例如模块、守卫或回退处理程序)明确分离。
Diamond Proxies 可能非常有用,特别是对于较大的项目,其中每笔交易都由多人检查,从而提供极高的灵活性。但是,Diamond Proxies 引入了多个合约直接相互影响的复杂性。理解这种复杂性并验证没有交易破坏任何东西变得具有挑战性。我们认为,这使得 Diamond Proxies 不适合每天触发交易的账户。
如果你想参与Safe v2 合约的讨论,请随时在此 论坛主题 中分享你的想法。
- 原文链接: safe.mirror.xyz/P83_rVQu...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!