@kyriework/upgrade-control-contracts
Version:
Upgrade Control Contracts
374 lines (266 loc) • 10.4 kB
Markdown
(已经迁移至 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