Skip to main content

合约升级方案

使用openzeppelin@openzeppelin/hardhat-upgrades

hardhat 中集成

  • 安装依赖
yarn add -D @openzeppelin/hardhat-upgrades @nomiclabs/hardhat-ethers ethers
  • hardhat.config配置文件中导入依赖

如果是 JS

// hardhat.config.js
require('@openzeppelin/hardhat-upgrades');

如果是 TS

// hardhat.config.ts
import '@openzeppelin/hardhat-upgrades';
  • 示例合约

注意: 可升级合约的部署不会调用constructor方法。所以实现一个initialize方法来做合约初始化

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

contract TodoList {
string[] private list;
address public admin;

event AddTodo(address indexed author, string item);

function initialize(address _admin) external {
admin = _admin;
}

function addTodo(string memory message) external {
list.push(message);
emit AddTodo(msg.sender, message);
}

function getTodoList() external view returns(string[] memory totoList) {
totoList = list;
}

// 相比V1 增加了获取列表长度的方法
// function getTodoListLength() external view returns(uint256) {
// return list.length;
// }
}
  • 第一次部署合约
async function main() {
// 第一次部署合约
const signers = await ethers.getSigners();
const admin = signers[0];
const TodoList = await ethers.getContractFactory("TodoList");
// 这里通过数组传参给initialize方法进行初始化
const instance = await upgrades.deployProxy(TodoList, [admin.address]);
await instance.deployed();
console.log(`proxy deployed: ${instance.address}`);
}

  • 合约升级后,部署升级合约
async function main() {
// 部署升级版本的合约
const TodoListV2 = await ethers.getContractFactory("TodoList");
// 第一个参数是上一次部署的proxy 地址
const upgraded = await upgrades.upgradeProxy(instance.address, TodoListV2);
await upgraded.deployed();
console.log(`upgraded success`);
}
  • 测试

注意,这里本地测试的时候要加上--network localhost,否则每次都会生成一个新的网络节点

npx hardhat run scripts/deploy.ts --network localhost

其他 truffle 等集成方案可以参考Upgrades Plugins

参考资料