快捷导航

深入浅出解读合约最小代理 EIP-1167

[复制链接]
查看: 77|回复: 0
发表于 2024-12-19 13:48:25 | 显示全部楼层 |阅读模式
真的挺后悔自己高中没好好学习,自己曾是湖北八校之一的学生,毕业之后看着自己的同学不是985就是211,也许当时可能觉得没啥差距,但是真就一本管学习,二本管纪律,三本管卫生,985大学的教学模式和方法以及教育资源,真的不是二本,三本可以比的,希望大家都可以好好学习,我个大学生看个这个,快感动死了。
深入浅出解读合约最小代理EIP-1167

EIP-1167是一种标准化的代理合约实现,旨在通过最小的字节码和委托调用的方式实现合约逻辑的复用。这种模式不仅节省部署和存储成本,还提供了开发者灵活的合约管理能力。

一、核心概念

EIP-1167定义了一种代理合约标准,代理合约的作用是将用户的调用委托到另一个逻辑合约(目标合约)。它通过 delegatecall 操作将调用转发给目标合约,从而实现代码复用,同时代理自身不存储逻辑,只存储状态。

代理合约的主要特点

轻量高效:代理合约的字节码极短,部署成本低。

逻辑复用:多个代理可以复用一个逻辑合约,节省存储。

工厂合约模型:支持创建交易中的克隆初始化(通过工厂合约模型)。

易于升级:通过调整代理指向的目标地址,可以实现逻辑的动态升级。

二、EIP-1167的标准字节码

代理合约的字节码模板如下:

0x363d3d373d3d3d363d735af43d82803e903d91602b57fd5bf3

1. 字节码结构详解

2. 生成代理字节码的Solidity代码

function createProxyBytecode(address logic) public pure returns (bytes memory) {

return abi.encodePacked(

hex"363d3d373d3d3d363d73",

logic,

hex"5af43d82803e903d91602b57fd5bf3"

);

}

三、EIP-1167的工作原理

●代理合约的部署

○ 使用上述标准字节码和目标逻辑合约地址,通过 create 部署代理合约

○ 部署后的代理只包含标准字节码,并指向逻辑合约的地址

●函数调用的转发

○ 用户调用代理合约时,代理合约通过 delegatecall 将调用转发到逻辑合约

○ delegatecall 的特点是使用调用者的上下文(代理合约的存储和余额),执行逻辑合约的代码

●逻辑合约的复用

○ 一个逻辑合约可以被多个代理合约复用,从而节约存储成本和开发成本

●可升级性

○ 如果代理合约使用了灵活的目标地址存储方式(如 EIP-1967 中的存储槽规范),可以动态改变逻辑合约地址,从而实现逻辑升级

四、EIP-1167使用场景

●多实例工厂模式:工厂合约可以快速部署多个代理合约实例,这些实例共享同一个逻辑合约

●可升级合约:可以通过设置存储中的逻辑合约地址,实现合约逻辑的动态升级

●模块化合约:通过代理合约实现模块化设计,各模块分离逻辑代码和状态存储,提高合约的可维护性

五、EIP-1167的优缺点

●优点:

○ 部署成本低:代理合约的字节码极短,部署时消耗的 Gas 显着减少

○逻辑代码复用: 多个代理合约共享一个逻辑合约,节省存储空间

○灵活性强:支持通过 delegatecall 动态转发调用,轻松实现复杂的功能

○ 升级便捷: 如果代理设计支持动态目标地址,可以实现逻辑的动态更新

●缺点

○ 调试复杂:由于状态存储在代理合约,而逻辑在目标合约中,调试时需要查看两者。

○ 无内置的升级机制:EIP-1167 本身并未提供升级机制,需要开发者自行设计目标地址的存储方案。

○ Gas 成本稍高:每次函数调用都需要额外的 delegatecall,略微增加了执行成本

六、EIP-1167实现案例

以下是一个完整的实现案例,包括逻辑合约、代理工厂合约以及交互流程。

● 逻辑合约

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract LogicContract {

uint256 public value;

function setValue(uint256 _value) external {

value = _value;

}

function getValue() external view returns (uint256) {

return value;

}

}

●代理工厂合约

○  0x14: SHA3 操作码(也称为 KECCAK256)

○  0x28: 将字节值 0x28(十进制 40)推入栈。PUSH1 是一字节操作码,用于将紧接的单字节值推入栈中

○ 0x37: CALLDATACOPY,将调用数据(calldata)从输入中复制到内存。通常用于在合约中处理调用参数。

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

contract MinimalProxyFactory {

event ProxyCreated(address proxy);

function createProxy(address logic) external returns (address) {

bytes20 targetBytes = bytes20(logic);

address proxy;

assembly {

let ptr := mload(0x40) // Free memory pointer

mstore(ptr, 0x3d602d80600a3d3981f3) // Prefix

mstore(add(ptr, 0x14), targetBytes) // Logic address

mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3) // Suffix

proxy := create(0, ptr, 0x37) // Deploy proxy

}

require(proxy != address(0), "Proxy deployment failed");

emit ProxyCreated(proxy);

return proxy;

}

}

● 交互示例

○ 逻辑合约和工厂合约: 部署 LogicContract 和 MinimalProxyFactory

○  使用工厂部署代理合约: 调用 createProxy 方法,传入逻辑合约地址

address proxy = factory.createProxy(logicAddress);

○ 与代理合约交互: 调用代理合约调用逻辑合约的方法

const proxyContract = new ethers.Contract(proxyAddress, LogicContract.abi, signer);

// 设置值

await proxyContract.setValue(42);

// 获取值

const value = await proxyContract.getValue();

console.log("Value:", value); // 42

EIP-1167 的重要性

优化资源使用:EIP-1167 提供了一种高效、标准化的代理合约实现,特别适用于需要部署大量实例的场景。

推动智能合约生态发展:EIP-1167 降低了开发者实现代理合约的门槛,是许多工厂模式和可升级合约实现的基础。

EIP-1167 是以太坊合约开发中不可或缺的工具,极大地提高了资源利用效率和开发灵活性。

七、OZ的最小代理实现源码解析

OZ 实现了EIP-1167 标准的一个库,提供了使用 create 和 create2 操作码部署最小代理合约(即 Clone)的功能,同时支持通过 create2 操作码预测代理合约地址。

1. 功能概述

clone:使用 create 操作码部署一个代理合约。

cloneDeterministic:使用 create2 操作码,结合 salt 部署代理合约,部署地址是可预测的。

predictDeterministicAddress:预测由 create2 部署的代理合约地址。

2. 合约函数解析

2.1 clone 函数

function clone(address implementation) internal returns (address instance) {

/// @solidity memory-safe-assembly

assembly {

// 将 implementation 地址压缩存储在 0x00 和 0x20 内存位置,并拼接代理合约字节码。

mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))

mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))

// 使用 `create` 操作码部署代理合约。

instance := create(0, 0x09, 0x37)

}

// 如果部署失败,抛出错误。

if (instance == address(0)) {

revert ERC1167FailedCreateClone();

}

}

作用

○ 使用 create 部署一个最小代理合约。

○ 代理合约将所有调用转发到指定的 implementation 地址。

部署的字节码

○ 使用 create 操作码动态部署代理合约。

○ 代理合约字节码包括:

◆前置字节码:0x3d602d80600a3d3981f3,用来设置代理合约环境。

◆ 指向 implementation 的逻辑转发代码。

2.2 cloneDeterministic 函数

function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {

/// @solidity memory-safe-assembly

assembly {

// 将 implementation 地址拼接代理合约字节码,存储到内存中。

mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))

mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))

// 使用 create2 操作码部署合约。

instance := create2(0, 0x09, 0x37, salt)

}

// 如果部署失败,抛出错误。

if (instance == address(0)) {

revert ERC1167FailedCreateClone();

}

}

作用

○ 使用 create2 部署代理合约,结合 salt 确定地址。

○ 通过 salt,部署地址可以在部署前预测。

部署的字节码:create2 操作码的优点是可以通过 salt 确保每次部署的地址是确定的,适用于需求特定地址的场景。

2.3 predictDeterministicAddress 函数

function predictDeterministicAddress(

address implementation,

bytes32 salt,

address deployer

) internal pure returns (address predicted) {

/// @solidity memory-safe-assembly

assembly {

let ptr := mload(0x40)

// 部署者地址

mstore(add(ptr, 0x38), deployer)

// 后置字节码

mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)

// 实现地址(implementation)

mstore(add(ptr, 0x14), implementation)

// 前置字节码

mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)

// salt

mstore(add(ptr, 0x58), salt)

// 计算合约地址

mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))

predicted := keccak256(add(ptr, 0x43), 0x55)

}

}

作用

○ 用于预测通过 create2 部署的代理合约地址。

○ 两种实现:

指定部署者的预测版本。

使用当前合约地址的预测版本。

预测公式

○ keccak256(0xff ++ deployer ++ salt ++ keccak256(bytecode))

deployer:部署合约的地址。

salt:提供的随机数。

bytecode:代理合约的字节码。

八、总结

EIP-1167 提供了一种标准化的代理合约实现,广泛应用于工厂模式和模块化合约。通过代理技术,可以显着节约部署成本,提高合约逻辑复用性,同时提升开发灵活性。

它是以太坊生态中不可或缺的工具,促进了智能合约的高效实现和模块化设计。

本文地址:https://www.tuopo.com/chanye/4027.html

本文来源:The Web3Dao

声明:本网站所有相关资料如有侵权请联系站长删除,资料仅供用户学习及研究之用,不构成任何投资建议!

相关阅读:币安交易平台
作为一个24岁还在读大三的老阿姨,给大家一个忠告,一定一定要努力学习,考上好大学。你只有真正经历过了,才知道没有学历,你甚至连一个机会都得不到。我现在专升本上了大学,在我专科实习的时候,我有一个同学特别优秀,基础很扎实,带他的老师也很喜欢他,但就因为他是专科毕业,最终没能留在那里。而且考研,有很多学校是明确专硕不收专升本学生的(就我的专业来说),只能考学硕。没有一个本科学历真的很难,尤其是在我们都是普通人的情况下。即使你现在很迷茫,但你也必须努力学习,考上好大学,这样后来你希望改变,也比由专科挣扎轻松得多。大家现在都还很年轻,珍惜你们现在无尽的可能性,我已经因为自己的选择,失去了很多机会。以我为鉴,与君共勉。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

精彩推荐

让学习更简单

  • 反馈建议:麻烦到学习网管理处反馈
  • 我的电话:这个不能给
  • 工作时间:周一到周五

关于我们

云服务支持

精彩文章,快速检索

关注我们

Copyright 学习网  Powered by©  技术支持:飛     ( 闽ICP备2021007264号-3 )