EIP-1167最小代理为何省Gas? 图 1
EIP-1167最小代理为何省Gas? · 图 1

批量创建相同逻辑的金库、账户或市场时,逐份部署完整字节码会重复付出代码存储成本。EIP-1167定义一段极短代理代码:每个实例只把调用转给同一个实现合约,逻辑复用,状态仍保存在各自地址。省Gas来自少部署代码,不是少执行所有逻辑。

元素放在哪里变化方式
业务逻辑代码implementation部署后由实现地址决定
用户状态clone地址的storage每个克隆独立变化
实现地址克隆字节码常量标准EIP-1167不提供更新入口
初始化参数clone的初始化调用必须防止重复或抢先初始化

克隆代理的三个不变量

  1. EIP-1167代理把所有调用通过DELEGATECALL转发到写死的实现地址,并把返回值或revert原样返回。
  2. 代码在实现合约,实例状态和msg.sender上下文属于克隆地址,因此每个克隆都需要独立初始化。
  3. 标准最小代理本身没有实现地址更新入口;确定性克隆可用salt预计算地址,但同一部署者和salt不能重复部署。

DELEGATECALL保留谁的上下文

用户调用clone,最小代理把calldata交给implementation执行。实现代码看到的address(this)是clone,读写的是clone storage,msg.sender仍是原调用者。于是实现合约构造函数写入的状态不会自动出现在克隆里,逻辑必须提供安全的initializer。

初始化是最常见失误

工厂若先部署、后用另一笔交易初始化,第三方可能抢先调用初始化并取得owner。更稳妥的流程是在同一交易创建后立刻初始化,并让初始化函数只能执行一次。实现合约自身也应锁定初始化,避免有人把实现地址配置成可被利用的独立实例。

批量部署前的工厂检查

  1. 从clone字节码提取并核对implementation
  2. 确认每个实例初始化已原子完成
  3. 检查storage layout与实现预期一致
  4. 区分cloneDeterministic的salt和部署者
  5. 不要误把标准克隆当可升级代理

标准克隆通常不是升级代理

实现地址被嵌入极短运行时代码,clone没有admin和implementation slot。要变更逻辑通常部署新实现和新clone,或让实现内部再读取其他路由;后者已经不是单纯EIP-1167。审核时应识别真实字节码,而不是看到“proxy”标签就套用透明代理规则。

代码复用也会放大共同漏洞

同一个implementation并不意味着所有克隆共享余额;状态位于各自地址。反过来,实现合约有漏洞时,大量克隆会同时受影响。代码复用放大了审计价值,也放大了共同缺陷,工厂必须能明确列出版本和迁移策略。

确定性克隆地址依赖CREATE2,可先看CREATE2地址公式;代理状态核对可结合账户与存储证明,交互前再执行合约连接检查