概要:
由于智能合约不可修改的特性,如果已经发布的智能合约出现bug,或者需要业务扩展,数据迁移等业务需求(尽管可以预先预留升级功能),往往显得缚手缚脚。
OpenZeppelin Upgrades 的出现就解决了这种问题。当合约出现问题时,通过升级你的智能合约,就像传统项目发布新版本一样,方便的给你的智能合约进行迭代升级(让你可以更安心的写bug~)。
开始
升级库
npm install --save-dev @openzeppelin/hardhat-upgrades
npm install --save-dev @nomiclabs/hardhat-ethers ethers
在 hardhat.config.js 中引入
require('@openzeppelin/hardhat-upgrades');
demo
js 脚本:
const { ethers, upgrades } = require("hardhat");
const {writeFile} = require("./tools")
// npx hardhat run scripts/sample-script.js --network localhost
async function main() {
// 发布合约
const Greeter = await ethers.getContractFactory("Greeter");
const greeter = await upgrades.deployProxy(Greeter, ["Hello, Hardhat!"], { initializer: 'initialize' });
console.log('___0', greeter.address)
// 更新合约
const Greeter1 = await ethers.getContractFactory("Greeter1");
const upgraded = await upgrades.upgradeProxy(greeter.address, Greeter1);
console.log('___1', upgraded.address)
// 可以看到, greeter 同事具备了 greeter1 合约的能力,同时保留了 自身的属性
const GreeterContract1 = await ethers.getContractAt("Greeter1", greeter.address);
console.log('___3', await GreeterContract1.greet());
console.log('___3', await GreeterContract1.greet1());
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
solidity文件
// Greeter.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.7.0;
import "hardhat/console.sol";
contract Greeter {
string greeting;
function initialize(string memory _greeting) public virtual {
console.log("Deploying a Greeter with greeting:", _greeting);
greeting = _greeting;
}
function greet() public view returns (string memory) {
return greeting;
}
function setGreeting(string memory _greeting) public {
console.log("Changing greeting from '%s' to '%s'", greeting, _greeting);
greeting = _greeting;
}
}
// Greeter1.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.7.0;
import "hardhat/console.sol";
contract Greeter1 {
string greeting;
function initialize(string memory _greeting) public virtual {
console.log("Deploying a Greeter1 with greeting:", _greeting);
greeting = _greeting;
}
function greet() public view returns (string memory) {
return greeting;
}
function greet1() public view returns (string memory) {
return "123";
}
function setGreeting(string memory _greeting) public {
console.log("Changing greeting from '%s' to '%s'", greeting, _greeting);
greeting = _greeting;
}
}
tips
- 合约代码必须实现初始化函数,用参数 initializer 制定,而且不能使用 constructor,详见文档
- 官方文档