UNPKG

@kyriework/upgrade-control-contracts

Version:

Upgrade Control Contracts

374 lines (266 loc) 10.4 kB
(已经迁移至 kyriework-contracts 仓库) # 合约升级管理系统 这是一个基于代理模式的智能合约升级管理系统,提供了安全可靠的合约升级机制,类似信标代理的集中管理多个可升级合约。 ## 核心功能 ### 🔧 升级管理器 (UpgradeManager) - 管理可升级合约的注册与注销 - 支持合约实现的升级和回滚 - 版本历史记录和管理 - 权限控制和管理员转移 - **需要Owner权限**进行合约注册 ### 🌍 开放升级管理器 (UpgradeManagerOpen) - **无需许可**,任何人都可以注册和管理自己的可升级合约 - 使用**命名空间隔离**防止不同用户之间的tag冲突 - 支持注册人和管理员角色分离 - 提供完整的升级、回滚和管理功能 - 继承 `IUpgradeManagerOpen` 接口 ### 🔄 升级代理 (UpgradeProxy) - 基于OpenZeppelin的代理模式 - 动态获取最新的逻辑合约地址 - 透明的函数调用代理 ### 📚 升级工具库 (UpgradeLib) - 提供升级相关的实用工具函数 - 统一管理存储槽位和常量 - 简化升级逻辑的实现 ### 🏗️ 升级逻辑基类 (UpgradeLogicBase) - 为可升级逻辑合约提供基础功能 - 集成初始化器和升级管理功能 - 抽象基类,便于继承使用 ## 系统架构 ### 中心化管理模式 (UpgradeManager) ``` 用户调用 → UpgradeProxy → 委托调用 → 逻辑合约 (继承 UpgradeLogicBase) ↓ ↓ UpgradeManager ← ← ← ← ← ← ← ← ← UpgradeLib (工具库) (需要Owner权限) ``` ### 去中心化管理模式 (UpgradeManagerOpen) ``` 用户调用 → UpgradeProxy → 委托调用 → 逻辑合约 (继承 UpgradeLogicBase) ↓ ↓ UpgradeManagerOpen ← ← ← ← ← ← ← ← ← UpgradeLib (工具库) (无需许可访问) ↓ 命名空间隔离 (registrant + tag) ``` ## 合约组件 ### 1. IUpgradeManager.sol 定义了升级管理器的接口,包含: - `ContractInfo` 结构体:存储合约信息(逻辑地址、代理地址、管理员、版本、激活状态) - 事件定义:注册、升级、注销、管理员转移 - 核心函数接口:创建代理、注册、升级、回滚等 ### 2. UpgradeManager.sol 升级管理器的核心实现: - 继承 `Ownable2Step` 提供所有权管理 - 实现 `IUpgradeManager` 接口 - 支持通过 CREATE2 部署代理合约 - 版本管理和历史记录 - 权限控制(只有Owner可以注册,只有管理员可以升级) ### 3. IUpgradeManagerOpen.sol 开放升级管理器的接口定义: - 基于 `IUpgradeManager` 扩展,使用 `namespacedTag` 参数 - 支持无需许可的合约注册和管理 - 提供 `getNamespacedTag` 函数用于命名空间计算 - 明确区分注册函数和管理函数的参数类型 ### 4. UpgradeManagerOpen.sol 无需许可的升级管理器实现: - 实现 `IUpgradeManagerOpen` 接口 - **任何人都可以注册**和管理自己的可升级合约 - 使用 `keccak256(abi.encodePacked(registrant, tag))` 进行命名空间隔离 - 支持注册人和管理员角色分离 - 提供完整的升级、回滚和管理功能 ### 5. UpgradeProxy.sol 代理合约实现: - 继承 OpenZeppelin 的 `Proxy` 合约 - 使用 `UpgradeLib` 管理存储槽位 - 动态获取当前逻辑合约地址 - 透明代理所有函数调用 ### 6. UpgradeLib.sol 升级工具库: - 定义升级相关的存储槽位常量 - 提供获取升级管理器地址的函数 - 提供获取升级标签的函数 - 提供获取注册信息和管理员地址的函数 ### 7. UpgradeLogicBase.sol 升级逻辑基类: - 继承 OpenZeppelin 的 `Initializable` 合约 - 使用 `UpgradeLib` 获取升级相关信息 - 提供内部函数访问升级管理器、标签、注册信息和管理员 - 抽象合约,需要被具体逻辑合约继承 ## 核心特性 ### 版本管理 - 自动版本递增 - 历史版本记录 - 支持回滚到指定版本 ### 权限控制 - **中心化模式**:Owner控制合约注册,管理员控制升级 - **去中心化模式**:任何人可以注册,管理员控制升级 - 支持管理员转移 - 只有管理员可以执行升级操作 ### 安全机制 - 地址零值检查 - 重复注册防护 - 逻辑合约地址验证 - **命名空间隔离**(UpgradeManagerOpen) ### 模块化设计 - 工具库统一管理升级逻辑 - 基类提供标准升级功能 - 组件化架构,便于扩展和维护 - 双模式支持:中心化 vs 去中心化 ## 使用示例 ### 中心化模式 (UpgradeManager) #### 创建可升级的逻辑合约 ```solidity // OpenZeppelin import { Initializable } from '@openzeppelin/contracts/proxy/utils/Initializable.sol'; // UpgradeLogicBase import { UpgradeLogicBase } from '@kyriework/upgrade-control-contracts/contracts/UpgradeLogicBase.sol'; // 继承 UpgradeLogicBase 基类 contract MyContract is UpgradeLogicBase, Initializable { uint256 public value; constructor() { _disableInitializers(); } function initialize(uint256 _value) public initializer { value = _value; } function setValue(uint256 _value) public { // 可以使用基类提供的升级相关函数 address admin = _upgradeAdminAddress(); require(msg.sender == admin, 'Only admin can set value'); value = _value; } function getUpgradeInfo() external view returns (address manager, bytes32 tag) { manager = _upgradeManagerAddress(); tag = _upgradeTagBytes32(); } } ``` #### 部署和注册合约 ```solidity // 1. 部署UpgradeManager UpgradeManager manager = new UpgradeManager(owner); // 2. 创建代理并注册合约 bytes32 tag = keccak256("MyContract"); address logic = address(new MyContract()); bytes memory initData = abi.encodeWithSignature("initialize(uint256)", 100); (address proxy, bytes memory result) = manager.createProxy(tag, logic, admin, initData); // 3. 通过代理调用合约 MyContract(proxy).setValue(200); ``` ### 去中心化模式 (UpgradeManagerOpen) #### 部署和注册合约 ```solidity // 1. 部署UpgradeManagerOpen UpgradeManagerOpen openManager = new UpgradeManagerOpen(); // 2. 任何人都可以创建代理并注册合约 bytes32 tag = keccak256("MyContract"); address logic = address(new MyContract()); bytes memory initData = abi.encodeWithSignature("initialize(uint256)", 100); (address proxy, bytes memory result) = openManager.createProxy(tag, logic, admin, initData); // 3. 获取命名空间标签 bytes32 namespacedTag = openManager.getNamespacedTag(msg.sender, tag); // 4. 管理员可以升级合约 address newLogic = address(new MyContractV2()); openManager.upgrade(namespacedTag, newLogic); // 只有admin可以调用 ``` #### 权限管理 ```solidity // 注册人和管理员可以是不同的地址 address registrant = msg.sender; // 注册合约的用户 address admin = 0x1234...; // 管理合约的管理员 // 创建代理时指定管理员 openManager.createProxy(tag, logic, admin, initData); // 计算命名空间标签 bytes32 namespacedTag = openManager.getNamespacedTag(registrant, tag); // 只有管理员可以升级 openManager.upgrade(namespacedTag, newLogic); // 必须由admin调用 ``` ### 升级合约 ```solidity // OpenZeppelin import { Initializable } from '@openzeppelin/contracts/proxy/utils/Initializable.sol'; // UpgradeLogicBase import { UpgradeLogicBase } from '@kyriework/upgrade-control-contracts/contracts/UpgradeLogicBase.sol'; // 部署新的逻辑合约(继承 UpgradeLogicBase) contract MyContractV2 is UpgradeLogicBase, Initializable { uint256 public value; uint256 public newFeature; // 新增功能 constructor() { _disableInitializers(); } function initialize(uint256 _value) public initializer { value = _value; } function setNewFeature(uint256 _newFeature) public { address admin = _upgradeAdminAddress(); require(msg.sender == admin, "Only admin"); newFeature = _newFeature; } } // 中心化模式升级 address newLogic = address(new MyContractV2()); manager.upgrade(tag, newLogic); // 去中心化模式升级 bytes32 namespacedTag = openManager.getNamespacedTag(registrant, tag); openManager.upgrade(namespacedTag, newLogic); ``` ### 回滚合约 ```solidity // 中心化模式回滚 manager.rollback(tag, 1); // 回滚到版本1 // 去中心化模式回滚 openManager.rollback(namespacedTag, 1); // 回滚到版本1 ``` ## 开发和测试 ### 安装依赖 ```shell pnpm install ``` ### 编译合约 ```shell npx hardhat compile ``` ### 运行测试 ```shell npx hardhat test ``` ### 部署合约 ```shell npx hardhat ignition deploy ./ignition/modules/UpgradeManager.js ``` ### 获取测试报告 ```shell REPORT_GAS=true npx hardhat test ``` ## 技术栈 - **Solidity ^0.8.20**: 智能合约开发语言 - **OpenZeppelin**: 安全的智能合约库 - **Hardhat**: 以太坊开发环境 - **代理模式**: 可升级合约架构模式 - **库模式**: 代码复用和模块化 - **命名空间隔离**: 防止多用户环境下的冲突 ## 注意事项 1. **存储布局兼容性**: 升级时需要保持存储布局的兼容性 2. **权限管理**: 合理设置管理员权限,避免权限滥用 3. **版本管理**: 建议在升级前进行充分测试 4. **Gas优化**: 代理调用会产生额外的Gas开销 5. **基类继承**: 逻辑合约应该继承 `UpgradeLogicBase` 以获得完整的升级功能 6. **初始化器**: 使用 `initializer` 修饰符确保初始化函数只被调用一次 7. **命名空间管理**: 在 `UpgradeManagerOpen` 中,确保使用正确的 `namespacedTag` 进行管理操作 8. **角色分离**: 注册人和管理员可以是不同的地址,合理规划权限分配 ## 选择指南 ### 使用 UpgradeManager 的场景 - 需要集中管理和控制合约注册 - 企业级应用,需要严格的权限控制 - 合约数量较少,管理相对简单 - 有明确的系统管理员角色 ### 使用 UpgradeManagerOpen 的场景 - 开放平台,允许任何人注册可升级合约 - 去中心化应用,减少中心化控制 - 多用户环境,需要隔离不同用户的合约 - 需要灵活的权限管理(注册人 ≠ 管理员) ## 许可证 MIT