ERC-1167:最小代理合约 原文章:https://eips.ethereum.org/EIPS/eip-1167
简要说明: 为了以简单且廉价的方式在不可变的情况下克隆合约功能,该标准规定了一种最小字节码实现,将所有调用委托给了一个已知的固定地址。
摘要 通过在已知的最小字节码重定向实现上进行标准化,该标准允许用户和第三方工具(例如:etherscan)简单地发现一个合约将始终以已知方式重定向,并依赖于目标合约中代码的行为作为重定向合约的行文。具体而言,工具可以查询重定向地址处的字节码,以确定将运行的代码位置,并且可以依赖于关于该代码的表示(经过验证的源代码、第三方审计等)。此实现将所有调用和 100% 的 gas 转发到实际合约,然后将返回值传递回调用者。在实施出现还原时,还会传递回还原与有效负载数据(用于带有消息的还原)
动机 该标准支持这样一种情况,即希望在最小化副作用(例如内存槽覆盖)和低 Gas 成本部署重复合约的情况下克隆精确合约功能
规范: 标准克隆合约的确切字节码如下:363d3d373d3d3d363d73bebebebebebebebebebebebebebebebebebebebe5af43d82803e903d91602b57fd5bf3
,其中索引10 - 29(包括 10 和 29)的字节被替换为实际合约的 20 个字节地址。
可以在optionlity/clone-factory github 仓库中找到此项参考的实现
原理 这一努力的目标是:
廉价部署(低 Gas 用于部署 clons)
支持在创建交易中初始化 clones (通过工厂合约模型)
简单的克隆字节码,以鼓励直接进行字节码查询(参考 clone-factory 项目中的 CloneProbe.sol)
可靠、锁定行为 - 这不是设计用于处理升级性问题,也不应该如此,因为我们正在寻求更强大的表示
小操作开销 - 每次调用都会增加一个调用成本
处理回滚消息返回错误
向后兼容性 没有向后兼容性问题。可能有一些系统正在使用早期版本的代理合约字节码。它们将不符合此标准。
测试案例 测试案例包括:
无参数调用
带参数调用
具有固定长度返回值的调用
具有可变长度返回值的调用
具有回滚的调用(确认已转移回滚有效载荷)
这些案例的测试包含在参考实现项目中。
实施 部署字节码不包括在此规范中。代理合约参考实现中定义了一种方法。
开始代理 标准部署的代理合约代码的反汇编(从r2中提取并编辑以包含堆栈可视化)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 0x00000000 36 calldatasize cds | 0x00000001 3d returndatasize 0 cds | 0x00000002 3d returndatasize 0 0 cds | 0x00000003 37 calldatacopy | 0x00000004 3d returndatasize 0 | 0x00000005 3d returndatasize 0 0 | 0x00000006 3d returndatasize 0 0 0 | 0x00000007 36 calldatasize cds 0 0 0 | 0x00000008 3d returndatasize 0 cds 0 0 0 | 0x00000009 73bebebebebe. push20 0xbebebebe 0xbebe 0 cds 0 0 0 | 0x0000001e 5a gas gas 0xbebe 0 cds 0 0 0 | 0x0000001f f4 delegatecall suc 0 | 0x00000020 3d returndatasize rds suc 0 | 0x00000021 82 dup3 0 rds suc 0 | 0x00000022 80 dup1 0 0 rds suc 0 | 0x00000023 3e returndatacopy suc 0 | 0x00000024 90 swap1 0 suc | 0x00000025 3d returndatasize rds 0 suc | 0x00000026 91 swap2 suc 0 rds | 0x00000027 602b push1 0x2b 0x2b suc 0 rds | ,=< 0x00000029 57 jumpi 0 rds | | 0x0000002a fd revert | `-> 0x0000002b 5b jumpdest 0 rds \ 0x0000002c f3 return
注意: 为了尽可能减少燃气成本,上述字节码依赖于 EIP-211 规范,在调用框架内的任何调用之前,returndatasize
返回零。returndatasize
比 dup*
使用更少的燃气。
虚拟地址优化 通过在以前导零字节开头的虚荣合约部署地址上安装主合约,可以进一步优化代理部署。通过生成一个包含 Z 个前导 0 字节的主合约虚荣地址,在其地址中用 pushN(其中 N 是 20 - Z)替换 push20 操作码,您可以缩短代理字节码,并在之后跟随 N 个非零地址字节。在这种情况下,还会将回退跳转地址减少 Z。以下是一个示例,其中 Z = 4:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 0x00000000 36 calldatasize cds | 0x00000001 3d returndatasize 0 cds | 0x00000002 3d returndatasize 0 0 cds | 0x00000003 37 calldatacopy | 0x00000004 3d returndatasize 0 | 0x00000005 3d returndatasize 0 0 | 0x00000006 3d returndatasize 0 0 0 | 0x00000007 36 calldatasize cds 0 0 0 | 0x00000008 3d returndatasize 0 cds 0 0 0 | 0x00000009 6fbebebebebe. push16 0xbebebebe 0xbebe 0 cds 0 0 0 | 0x0000001a 5a gas gas 0xbebe 0 cds 0 0 0 | 0x0000001b f4 delegatecall suc 0 | 0x0000001c 3d returndatasize rds suc 0 | 0x0000001d 82 dup3 0 rds suc 0 | 0x0000001e 80 dup1 0 0 rds suc 0 | 0x0000001f 3e returndatacopy suc 0 | 0x00000020 90 swap1 0 suc | 0x00000021 3d returndatasize rds 0 suc | 0x00000022 91 swap2 suc 0 rds | 0x00000023 6027 push1 0x27 0x27 suc 0 rds | ,=< 0x00000025 57 jumpi 0 rds | | 0x00000026 fd revert | `-> 0x00000027 5b jumpdest 0 rds \ 0x00000028 f3 return
这将节省4个字节的代理合约大小(每次部署都能节省),对运行时的燃气成本没有任何影响。