EIP-1167:ERC-1167最小代理合约
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中提取并编辑以包含堆栈可视化)
| 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:
| 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个字节的代理合约大小(每次部署都能节省),对运行时的燃气成本没有任何影响。