@kyriework/upgrade-control-contracts
v1.1.3
Published
Upgrade Control Contracts
Maintainers
Readme
(已经迁移至 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)
创建可升级的逻辑合约
// 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();
}
}部署和注册合约
// 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)
部署和注册合约
// 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可以调用权限管理
// 注册人和管理员可以是不同的地址
address registrant = msg.sender; // 注册合约的用户
address admin = 0x1234...; // 管理合约的管理员
// 创建代理时指定管理员
openManager.createProxy(tag, logic, admin, initData);
// 计算命名空间标签
bytes32 namespacedTag = openManager.getNamespacedTag(registrant, tag);
// 只有管理员可以升级
openManager.upgrade(namespacedTag, newLogic); // 必须由admin调用升级合约
// 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);回滚合约
// 中心化模式回滚
manager.rollback(tag, 1); // 回滚到版本1
// 去中心化模式回滚
openManager.rollback(namespacedTag, 1); // 回滚到版本1开发和测试
安装依赖
pnpm install编译合约
npx hardhat compile运行测试
npx hardhat test部署合约
npx hardhat ignition deploy ./ignition/modules/UpgradeManager.js获取测试报告
REPORT_GAS=true npx hardhat test技术栈
- Solidity ^0.8.20: 智能合约开发语言
- OpenZeppelin: 安全的智能合约库
- Hardhat: 以太坊开发环境
- 代理模式: 可升级合约架构模式
- 库模式: 代码复用和模块化
- 命名空间隔离: 防止多用户环境下的冲突
注意事项
- 存储布局兼容性: 升级时需要保持存储布局的兼容性
- 权限管理: 合理设置管理员权限,避免权限滥用
- 版本管理: 建议在升级前进行充分测试
- Gas优化: 代理调用会产生额外的Gas开销
- 基类继承: 逻辑合约应该继承
UpgradeLogicBase以获得完整的升级功能 - 初始化器: 使用
initializer修饰符确保初始化函数只被调用一次 - 命名空间管理: 在
UpgradeManagerOpen中,确保使用正确的namespacedTag进行管理操作 - 角色分离: 注册人和管理员可以是不同的地址,合理规划权限分配
选择指南
使用 UpgradeManager 的场景
- 需要集中管理和控制合约注册
- 企业级应用,需要严格的权限控制
- 合约数量较少,管理相对简单
- 有明确的系统管理员角色
使用 UpgradeManagerOpen 的场景
- 开放平台,允许任何人注册可升级合约
- 去中心化应用,减少中心化控制
- 多用户环境,需要隔离不同用户的合约
- 需要灵活的权限管理(注册人 ≠ 管理员)
许可证
MIT
