比最小代理更小的代理合约

33357 发布于 2024-03-02 阅读 2646

比最小代理更小的代理合约

比最小代理更小的代理合约

备注

时间:2023 年 9 月 17 日

作者:33357

正文

看过我写的EIP7511 最小代理合约解析,就能发现如果舍弃一些功能,可以写出比最小代理更小的代理合约。

全功能最小代理

合约字节码:
365f5f375f5f365f73bebebebebebebebebebebebebebebebebebebebe5af43d5f5f3e5f3d91602a57fd5bf3
运行gas: 192

部署字节码:
602c8060095f395ff3365f5f375f5f365f73bebebebebebebebebebebebebebebebebebebebe5af43d5f5f3e5f3d91602a57fd5bf3
部署gas: 8828

场景

可以用于所有代理交易。

没有返回值

字节码

合约字节码:
365f5f375f5f365f73bebebebebebebebebebebebebebebebebebebebe5af4
运行gas: 162

部署字节码:
601f8060095f395ff3365f5f375f5f365f73bebebebebebebebebebebebebebebebebebebebe5af4
部署gas: 6222

分析

  • 复制 CALLDATA 到内存
执行位置 字节码 操作名 堆栈 内存 说明 |
00 36 CALLDATASIZE cds 将 calldatasize 计为 cds,并压入堆栈
01 5f PUSH0 0 cds 将 0 压入堆栈
02 5f PUSH0 0 0 cds 将 0 压入堆栈
03 37 CALLDATACOPY calldata 将 0 - cds 的 calldata 复制到从 0 开始的内存空间
  • DELEGATECALL
执行位置 字节码 操作名 堆栈 内存 说明 |
04 5f PUSH0 0 calldata 将 0 压入堆栈
05 5f PUSH0 0 0 calldata 将 0 压入堆栈
06 36 CALLDATASIZE cds 0 0 calldata 将 calldatasize 计为 cds,并压入堆栈
07 5f PUSH0 0 cds 0 0 calldata 将 0 压入堆栈
08 73bebe. PUSH20 0xbebe. 0xbebe. 0 cds 0 0 calldata 将 20 个字节的数据压入堆栈
1d 5a GAS gas 0xbebe. 0 cds 0 0 calldata 将 gas 压入堆栈
1e f4 DELEGATECALL suc calldata 将 0 - cds 的内存数据作为参数执行 0xbebe. 地址的代码,将执行是否成功计为 suc,并压入堆栈

场景

用于不需要返回值的代理交易。

没有参数和返回值

字节码

合约字节码:
5f5f5f5f73bebebebebebebebebebebebebebebebebebebebe5af4
运行gas: 153

部署字节码:
601b8060095f395ff35f5f5f5f73bebebebebebebebebebebebebebebebebebebebe5af4
部署gas: 5422

分析

  • DELEGATECALL
执行位置 字节码 操作名 堆栈 内存 说明 |
01 5f PUSH0 0 将 0 压入堆栈
02 5f PUSH0 0 0 将 0 压入堆栈
03 5f PUSH0 0 0 0 将 0 压入堆栈
04 5f PUSH0 0 0 0 0 将 0 压入堆栈
05 73bebe. PUSH20 0xbebe. 0xbebe. 0 0 0 0 将 20 个字节的数据压入堆栈
19 5a GAS gas 0xbebe. 0 0 0 0 将 gas 压入堆栈
1a f4 DELEGATECALL suc 将 0 - 0 的内存数据作为参数执行 0xbebe. 地址的代码,将执行是否成功计为 suc,并压入堆栈

场景

用于不需要参数和返回值的代理交易。

没有参数、返回值和指定代理地址

字节码

合约字节码:
5f5f5f5f335af4
运行gas: 154

部署字节码:
60078060095f395ff35f5f5f5f335af4
部署gas: 1622

分析

  • DELEGATECALL
执行位置 字节码 操作名 堆栈 内存 说明 |
01 5f PUSH0 0 将 0 压入堆栈
02 5f PUSH0 0 0 将 0 压入堆栈
03 5f PUSH0 0 0 0 将 0 压入堆栈
04 5f PUSH0 0 0 0 0 将 0 压入堆栈
05 33 CALLER caller 0 0 0 0 将调用地址压入堆栈
06 5a GAS gas caller 0 0 0 0 将 gas 压入堆栈
07 f4 DELEGATECALL suc 将 0 - 0 的内存数据作为参数执行 caller 地址的代码,将执行是否成功计为 suc,并压入堆栈

场景

用于不需要参数、返回值和指定代理地址的代理交易。

总结

针对不同功能修改最小代理合约可以实现更低的 GAS 消耗。

原文发布在 <https://github.com/33357/smartcontract-apps> 这是一个面向中文社区,分析市面上智能合约应用的架构与实现的仓库。欢迎关注开源知识项目!

相关文章

1 条评论

谢谢大佬,请假一下 谢谢大佬,请教一下: 下面是openzeppelin的最小代理合约的创建代码 ,这个代码只有请求转发到逻辑合约,并返回执行结果的功能。现在我想给逻辑最小代理合约增加一个owner功能,就是把在最小代理合约的0槽位上保存一个地址,比如caller() 假设逻辑合约对应的零槽位也保留一个地址来对齐最小行业的owner),那么需要在下面的字节码上如何修改? 我的想法是在下面字节码的基础上增加一个构造函数的逻辑,在构造函数中调用store(0, caller()) , 但是我不知道证明用字节码来实现,请大佬们帮忙看看怎么搞? 需要说明的是,希望用字节码来实现,保持合约的size足够小,用户汇编实现就不用考虑了,大小会大不少。谢谢!

function clone(address implementation, uint256 value) internal returns (address instance) {
    if (address(this).balance &lt; value) {
        revert Errors.InsufficientBalance(address(this).balance, value);
    }
    assembly ("memory-safe") {
        // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
        // of the `implementation` address with the bytecode before the address.
        mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
        // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
        mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
        instance := create(value, 0x09, 0x37)
    }
    if (instance == address(0)) {
        revert Errors.FailedDeployment();
    }
}
2025-02-27 16:55