本文介绍了如何在Hardhat项目中使用@openzeppelin/hardhat-upgrades
插件来部署和升级代理合约以及信标代理合约。文章提供了安装插件、在脚本和测试中使用的示例代码,以及升级代理合约和信标合约的步骤,并提及了完整的API文档。
此包向你的 Hardhat 脚本添加函数,以便你可以为你的合约部署和升级代理。依赖于 ethers.js
。
查看分步教程,展示了从创建、测试和部署,一直到使用 Gnosis Safe 进行升级的全过程。 |
$ npm install --save-dev @openzeppelin/hardhat-upgrades
$ npm install --save-dev @nomicfoundation/hardhat-ethers ethers # peer dependencies
并在你的 hardhat.config.js
中注册该插件:
require('@openzeppelin/hardhat-upgrades');
你可以在 Hardhat 脚本 中使用此插件,通过 deployProxy
函数部署你的合约的可升级实例:
// scripts/create-box.js
const { ethers, upgrades } = require("hardhat");
async function main() {
const Box = await ethers.getContractFactory("Box");
const box = await upgrades.deployProxy(Box, [42]);
await box.waitForDeployment();
console.log("Box deployed to:", await box.getAddress());
}
main();
这将自动检查 Box
合约是否是升级安全的,为 Box
合约部署一个实现合约(除非之前部署过一个),创建一个代理(如果需要,还会创建一个代理管理员),并通过调用 initialize(42)
来初始化它。
然后,在另一个脚本中,你可以使用 upgradeProxy
函数将已部署的实例升级到新版本。新版本可以是不同的合约(例如 BoxV2
),或者你可以只修改现有的 Box
合约并重新编译它 - 插件会注意到它已更改。
// scripts/upgrade-box.js
const { ethers, upgrades } = require("hardhat");
async function main() {
const BoxV2 = await ethers.getContractFactory("BoxV2");
const box = await upgrades.upgradeProxy(BOX_ADDRESS, BoxV2);
console.log("Box upgraded");
}
main();
注意:虽然此插件会跟踪你在每个网络上部署的所有实现合约,以便重用它们并验证存储兼容性,但它_不_跟踪你已部署的代理。这意味着你需要手动跟踪每个部署地址,以便在需要时将其提供给升级函数。
该插件将负责比较 BoxV2
与前一个版本,以确保它们与升级兼容,部署新的 BoxV2
实现合约(除非之前部署过一个),并将现有代理升级到新的实现。
你还可以使用此插件通过 deployBeacon
函数为你的合约部署一个可升级的信标,然后通过使用 deployBeaconProxy
函数部署一个或多个指向它的信标代理。
// scripts/create-box.js
const { ethers, upgrades } = require("hardhat");
async function main() {
const Box = await ethers.getContractFactory("Box");
const beacon = await upgrades.deployBeacon(Box);
await beacon.waitForDeployment();
console.log("Beacon deployed to:", await beacon.getAddress());
const box = await upgrades.deployBeaconProxy(beacon, Box, [42]);
await box.waitForDeployment();
console.log("Box deployed to:", await box.getAddress());
}
main();
然后,在另一个脚本中,你可以使用 upgradeBeacon
函数将信标升级到新版本。 当信标升级后,所有指向它的信标代理将使用新的合约实现。
// scripts/upgrade-box.js
const { ethers, upgrades } = require("hardhat");
async function main() {
const BoxV2 = await ethers.getContractFactory("BoxV2");
await upgrades.upgradeBeacon(BEACON_ADDRESS, BoxV2);
console.log("Beacon upgraded");
const box = BoxV2.attach(BOX_ADDRESS);
}
main();
你还可以从你的 Hardhat 测试中使用该插件的函数,以防你想为升级你的合约添加测试(你应该这样做!)。API 与脚本中相同。
const { expect } = require("chai");
describe("Box", function() {
it('works', async () => {
const Box = await ethers.getContractFactory("Box");
const BoxV2 = await ethers.getContractFactory("BoxV2");
const instance = await upgrades.deployProxy(Box, [42]);
const upgraded = await upgrades.upgradeProxy(await instance.getAddress(), BoxV2);
const value = await upgraded.value();
expect(value.toString()).to.equal('42');
});
});
const { expect } = require("chai");
describe("Box", function() {
it('works', async () => {
const Box = await ethers.getContractFactory("Box");
const BoxV2 = await ethers.getContractFactory("BoxV2");
const beacon = await upgrades.deployBeacon(Box);
const instance = await upgrades.deployBeaconProxy(beacon, Box, [42]);
await upgrades.upgradeBeacon(beacon, BoxV2);
const upgraded = BoxV2.attach(await instance.getAddress());
const value = await upgraded.value();
expect(value.toString()).to.equal('42');
});
});
有关完整的 API 文档,请参见 Hardhat Upgrades API。
- 原文链接: docs.openzeppelin.com/up...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!