从 OpenZeppelin CLI 迁移

本指南适用于从已弃用的旧 CLI 迁移。

本指南将引导您将项目从 OpenZeppelin CLI 迁移到用于 Truffle 或 Hardhat 的 OpenZeppelin Upgrades 插件。

Instructions are available for both Truffle and Hardhat. Choose your preference using this toggle!

如果您想在示例 OpenZeppelin CLI 项目上尝试这些说明,您可以克隆 OpenZeppelin/openzeppelin-upgrades-migration-example 并在继续之前按照自述文件中的设置说明进行操作。

差异

CLI 和插件之间的主要区别在于,前者用于跟踪您的可升级(和不可升级)部署。 这在某些情况下很方便,因为您不必过多担心代理、实现或地址,您可以只关注诸如升级或将交易发送到您的合约等操作,只需通过它们的名称即可。

但是让 CLI 跟踪您的部署,代价是限制了您与其他工具和工作流程集成的自由。 并且由于插件被设计为独立于 CLI 工作,因此我们解除了该限制,因此现在您可以灵活地以您认为最佳的方式跟踪您的代理。

撇开这一点不谈,其他一切都保持不变,因为 CLI 和插件都在底层使用了相同的已知 ProxyProxyAdmin 合约,从而构成了管理它们的两种不同的接口。 这意味着迁移您的项目不会触及链上的任何内容,一切都是安全和本地的。

安装

安装 Hardhat,并在初始化时,选择 Create an empty hardhat.config.js 选项。

$ npm install --save-dev hardhat
$ npx hardhat

然后安装 Upgrades 插件:

$ npm install --save-dev @openzeppelin/hardhat-upgrades
$ npm install --save-dev @nomiclabs/hardhat-ethers ethers # peer dependencies

完成后,通过添加以下行在 Hardhat 配置文件中注册该插件:

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

module.exports = {
  // ...
};

安装 Truffle,然后初始化您的项目。

当 Truffle 询问时,选择不覆盖合约或测试目录。 通过不覆盖,您将不会获得 初始迁移。 确保创建 Migrations.sol 和初始迁移。
$ npm install --save-dev truffle
$ npx truffle init

然后安装 Upgrades 插件:

$ npm install --save-dev @openzeppelin/truffle-upgrades

迁移 CLI 项目

这是一个单向过程。 确保您保留 .openzeppelin/ 文件夹的备份或版本控制副本。

现在,让我们通过运行以下命令来迁移我们的项目:

$ npx migrate-oz-cli-project
✔ Successfully migrated .openzeppelin/rinkeby.json
✔ Migration data exported to openzeppelin-cli-export.json
✔ Deleting .openzeppelin/project.json

These were your project's compiler options:
// 这些是您项目的编译器选项:
{
  "compilerSettings": {
    "optimizer": {
      "enabled": false,
      "runs": "200"
    }
  },
  "typechain": {
    "enabled": false
  },
  "manager": "openzeppelin",
  "solcVersion": "0.6.12",
  "artifactsDir": "build/contracts",
  "contractsDir": "contracts"
}

此脚本随插件一起安装,它的作用是删除 CLI 项目文件并将您的旧网络文件(所有这些文件都位于 .openzeppelin 目录下)转换为其 Upgrades 插件等效文件。 同样,链上的任何内容都不会更改,只有本地文件。 另请注意,一旦您运行此命令,除非您通过备份或版本控制还原更改,否则您将无法再使用 CLI 来管理此项目的合约。

迁移脚本还将 openzeppelin-cli-export.json 文件导出到您的工作目录中,其中包含 CLI 用于为您管理的所有数据,现在您可以自由地以您认为最佳的方式使用它。 这包括您的编译器设置,为了方便起见,这些设置也会在迁移结束时打印出来。 让我们将它们添加到我们的新项目配置中:

将编译器设置复制到 Hardhat 配置文件中的 solidity 字段

// hardhat.config.js

// ...

module.exports = {
  // ...
  solidity: {
    version: "0.6.12",
    settings: {
      optimizer: {
        enabled": false,
        runs": 200
      }
    }
  }
}

将编译器设置复制到我们 Truffle 配置文件的 compilers 字段

// truffle-config.js

module.exports = {
  // ...
  compilers: {
    solc: {
      version: "0.6.12",
      settings: {
        optimizer: {
          enabled": false,
          runs": 200
        }
      }
    }
  }
}
solidity 编译器配置格式在 truffle-config.jshardhat.config.js 文件中是不同的

就是这样,您已成功迁移您的 CLI 项目。 现在让我们尝试使用您的新设置来升级您的迁移合约之一。

升级到新版本

假设我们在 CLI 项目中有一个 Box 合约,已部署到 Rinkeby 网络。 然后,如果我们打开我们的导出文件,我们将看到类似这样的内容:

// openzeppelin-cli-export.json
{
  "networks": {
    "rinkeby": {
      "proxies": {
        "openzeppelin-upgrades-migration-example/Box": [
          {
            "address": "0x500D1d6A4c7D8Ae28240b47c8FCde034D827fD5e",
            "version": "1.0.0",
            "implementation": "0x038B86d9d8FAFdd0a02ebd1A476432877b0107C8",
            "admin": "0x1A1FEe7EeD918BD762173e4dc5EfDB8a78C924A8",
            "kind": "Upgradeable"
          }
        ]
      }
    }
  },
  "compiler": {
    // we'll ignore compiler settings for this
    // 我们将忽略此编译器的设置
  }
}

我们在这里看到的是地址方面可升级合约的 JSON 表示形式:

  • address: 代理地址(代理合约包含您的可升级合约状态)

  • implementation: 实现地址(您的可升级合约逻辑)

  • admin: 代理管理员的地址,除非您另行设置,否则它可能属于 ProxyAdmin 合约

如果我们决定使用插件和此导出文件将我们的 Box 合约升级到 BoxV2 合约,它将如下所示:

这些脚本只是如何使用导出数据的示例。 我们不对是否按原样保留该文件或如何处理其数据提出任何建议。 这现在取决于用户。

对于 Hardhat,我们将编写一个脚本(您可以在 此处阅读有关 Hardhat 脚本的更多信息,并在 此处阅读有关使用 hardhat-upgrades 插件的更多信息):

// scripts/upgradeBoxToV2.js

const { ethers, upgrades } = require("hardhat");
const OZ_SDK_EXPORT = require("../openzeppelin-cli-export.json");

async function main() {
  const [ Box ] = OZ_SDK_EXPORT.networks.rinkeby.proxies["openzeppelin-upgrades-migration-example/Box"];
  const BoxV2 = await ethers.getContractFactory("BoxV2");
  await upgrades.upgradeProxy(Box.address, BoxV2);
}

main();
$ npx hardhat run scripts/upgradeBoxToV2.js --network rinkeby

对于 Truffle,我们将编写一个迁移(您可以在 此处阅读有关 Truffle 迁移的更多信息,并在 此处阅读有关使用 truffle-upgrades 插件的更多信息):

// migrations/2_upgrade_box_contract.js

const { upgradeProxy } = require('@openzeppelin/truffle-upgrades');
const OZ_SDK_EXPORT = require("../openzeppelin-cli-export.json");

const BoxV2 = artifacts.require('BoxV2');

module.exports = async function (deployer) {
  const [ Box ] = OZ_SDK_EXPORT.networks.rinkeby.proxies["openzeppelin-upgrades-migration-example/Box"];
  const instance = await upgradeProxy(Box.address, BoxV2, { deployer });
  console.log("Upgraded", instance.address);
};
$ npx truffle migrate --network rinkeby

就是这样! 您已将您的 OpenZeppelin CLI 项目迁移到 Truffle 或 Hardhat,并使用插件执行了升级。