快捷搜索:  汽车  科技

owhat升级方法(如何使用hardhat进行合约uups模式升级)

owhat升级方法(如何使用hardhat进行合约uups模式升级)初始化完成后的目录结构为执行npx hardhat选择Create a basic sample project3.安装依赖npm install --save-dev @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers4.安装openZeppelin的uups可升级合约包 npm install --save-dev @openzeppelin/contracts-upgradeable5.安装测试工具mocha npm install --save-dev mocha

背景:在开发或维护solidity语言的智能合约时,经常会因为业务逻辑变动而变动合约内的逻辑,这就要考虑在不影响以前智能合约中已上链的数据的同时,修改或扩展新的业务逻辑,所以合约第一次开发时就需要考虑其本身支持可升级功能

目的:本篇文章是为了让读者快速上手使用hardhat并搭配openZeppelin的uups升级模式对合约进行可升级适配以及指导后续如何进行合约升级

适用对象:适用于BSN开放联盟链武汉链(基于ETH),也可适用于其他支持solidity语言的链框架

如何使用hardhat进行合约uups模式升级

  • 安装hardhat
  • 初始化项目
  • 编写合约
  • 编写测试文件
  • 编辑配置文件
  • 执行项目
  • 参考
安装hardhat

1.创建空的文件夹demo-uups并进入文件夹里面,执行npm init

2.执行安装命令npm install --save-dev hardhat

3.安装依赖npm install --save-dev @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers

4.安装openZeppelin的uups可升级合约包 npm install --save-dev @openzeppelin/contracts-upgradeable

5.安装测试工具mocha npm install --save-dev mocha

初始化项目

执行npx hardhat选择Create a basic sample project

owhat升级方法(如何使用hardhat进行合约uups模式升级)(1)

初始化完成后的目录结构为

owhat升级方法(如何使用hardhat进行合约uups模式升级)(2)

编写合约

在contracts目录下面新建两个名称分别为MyLogicV1和MyLogicV2的.sol文件并进行代码编写。实现openZeppelin的uups升级模式必须要引入openZeppelin相关库文件,且必须在constructor()方法上加@custom:oz-upgrades-unsafe-allow constructor字样注释

// contract/MyLogicV1.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; contract MyLogicV1 is Initializable UUPSUpgradeable OwnableUpgradeable { function initialize() initializer public { __Ownable_init(); __UUPSUpgradeable_init(); } /// @custom:oz-upgrades-unsafe-allow constructor constructor() initializer {} function _authorizeUpgrade(address) internal override onlyOwner {} mapping(string => uint256) private logic; event logicSetted(string indexed _key uint256 _value); function SetLogic(string memory _key uint256 _value) external { logic[_key] = _value; emit logicSetted(_key _value); } function GetLogic(string memory _key) public view returns (uint256){ return logic[_key]; } }

// contract/MyLogicV2.sol // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; contract MyLogicV2 is Initializable UUPSUpgradeable OwnableUpgradeable { function initialize() initializer public { __Ownable_init(); __UUPSUpgradeable_init(); } /// @custom:oz-upgrades-unsafe-allow constructor constructor() initializer {} function _authorizeUpgrade(address) internal override onlyOwner {} mapping(string => uint256) private logic; event logicSetted(string indexed _key uint256 _value); function SetLogic(string memory _key uint256 _value) external { logic[_key] = _value; emit logicSetted(_key _value); } function GetLogic(string memory _key) public view returns (uint256){ return logic[_key] 100; } }

MyLogicV1实现了一个对于logic的map的写入方法和读取方法,MyLogicV2只是改写了MyLogicV1的GetLogic方法中的处理逻辑,使得每次返回的值加了100

编写测试文件

在test目录下创建生成名称为update-test的.js文件并进行代码编写

// test/update-test.ts const { expect } = require('chai'); const { ethers upgrades } = require('hardhat'); let myLogicV1; let myLogicV2; describe('uups mode upgrade' function () { it('deploys' async function () { const MyLogicV1 = await ethers.getContractFactory('MyLogicV1'); myLogicV1 = (await upgrades.deployProxy(MyLogicV1 {kind: 'uups'})); console.log(myLogicV1.address); }) it('myLogicV1 set' async function () { await myLogicV1.SetLogic("aa" 1); expect((await myLogicV1.GetLogic("aa")).toString()).to.equal('1'); }) it('upgrades' async function () { const MyLogicV2 = await ethers.getContractFactory('MyLogicV2'); myLogicV2 = (await upgrades.upgradeProxy(myLogicV1 MyLogicV2)); console.log(myLogicV2.address); }) it('myLogicV2 get' async function () { expect((await myLogicV2.GetLogic("aa")).toString()).to.equal('101'); }) })

测试文件步骤详解

  • deploys: 调用upgrades中的deployProxy方法以uups的方式部署MyLogicV1合约
  • myLogicV1 set:调用MyLogicV1合约中的SetLogic方法将值传入,并调用GetLogic方法确认返回值为1
  • upgrades:调用upgrades中的upgradeProxy方法升级

  • myLogicV2 get:调用MyLogicV2合约中的GetLogic方法确认返回值为101
编辑配置文件

编辑hardhat.config.js文件

require("@nomiclabs/hardhat-waffle"); require('@openzeppelin/hardhat-upgrades'); // This is a sample Hardhat task. To learn how to create your own go to // https://hardhat.org/guides/create-task.html task("accounts" "Prints the list of accounts" async (taskArgs hre) => { const accounts = await hre.ethers.getSigners(); for (const account of accounts) { console.log(account.address); } }); // You need to export an object to set up your config // Go to https://hardhat.org/config/ to learn more /** * @type import('hardhat/config').HardhatUserConfig */ module.exports = { solidity: { version: "0.8.4" settings: { optimizer: { enabled: true runs: 200 } } } mocha: { timeout: 60000 } }; 执行项目

1.执行编译合约

npx hardhat compile

2.启动本地测试节点

npx hardhat node

3.新开一个窗口运行测试文件

npx hardhat test test/update-test.js --network localhost

owhat升级方法(如何使用hardhat进行合约uups模式升级)(3)

测试通过,合约地址都为代理合约地址,测试说明成功升级改写了GetLogic中的处理逻辑,使得每次返回的值都在原来的基础上多加了100

参考

Hardhat官方文档:Overview | Hardhat | Ethereum development environment for professionals by Nomic Foundation[1]

OpenZeppelin官方文档:Using with Upgrades - OpenZeppelin Docs[2]

References

[1] Overview | Hardhat | Ethereum development environment for professionals by Nomic Foundation: https://hardhat.org/getting-started/
[2] Using with Upgrades - OpenZeppelin Docs: https://docs.openzeppelin.com/contracts/4.x/upgradeable

猜您喜欢: