OpenZeppelin Defender 集成 - OpenZeppelin 文档

本文档介绍了如何将 OpenZeppelin Foundry Upgrades 与 OpenZeppelin Defender 集成,以便通过 Defender 进行合约部署和升级。主要包括安装配置、环境设置、网络选择以及可升级和不可升级合约的部署示例,强调了使用 Defender 部署时的注意事项,如API密钥配置、网络选择、以及如何在Defender界面监控部署状态。

OpenZeppelin Defender 集成

OpenZeppelin Foundry Upgrades 可以用于通过 OpenZeppelin Defender 执行部署,它允许诸如 gas 价格评估、重新提交以及自动字节码和源代码验证等功能。

无论你是否使用 broadcast cheatcode,Defender 部署总是广播到实时网络。<br> 推荐的模式是将 Defender 脚本与依赖于网络分叉和模拟的脚本分开,以避免混合模拟和实时网络数据。

安装

请参阅 与 Foundry 一起使用 - 安装

准备工作

  1. 安装 Node.js

  2. 配置你的 foundry.toml 以启用 ffi,ast,构建信息和存储布局:

[profile.default]
ffi = true
ast = true
build_info = true
extra_output = ["storageLayout"]
元数据也必须包含在编译器输出中,默认情况下是包含的。
  1. 在你的项目根目录下的 .env 文件中设置以下环境变量,使用来自 OpenZeppelin Defender 的 Team API 密钥和 secret:
DEFENDER_KEY=&lt;你的 API 密钥>
DEFENDER_SECRET=&lt;你的 API secret>
上述 API 密钥必须至少具有管理部署的权限(如果需要通过 Relayer 创建审批流程,则还需要管理 Relayers 的权限)。你可以在 https://defender.openzeppelin.com/#/settings/api-keys 配置你的 API 密钥。

网络选择

与 OpenZeppelin Defender 一起使用的网络由 Foundry 连接到的网络决定。 如果你想确保 Defender 使用特定的网络,请在你的 .env 文件中设置 DEFENDER_NETWORK 环境变量,例如:

DEFENDER_NETWORK=my-mainnet-fork

如果设置了此项,则它必须是 Defender 中公共、私有或分叉网络的名称。 如果 Foundry 连接到不同的网络,同时设置了此项,则不会发生部署,而是会引发错误。

如果你在 Defender 中有多个具有相同 chainId 的分叉网络,则需要这样做,在这种情况下,将使用名称与 DEFENDER_NETWORK 环境变量匹配的网络。

用法

可升级合约

如果要部署可升级合约,请按照 与 Foundry 一起使用 - 安装 中所述使用 Upgrades 库,但在调用函数时设置选项 defender.useDefenderDeploy = true,以使所有部署都通过 OpenZeppelin Defender 进行。

示例 1 - 部署代理: 要部署 UUPS 代理,请创建一个名为 Defender.s.sol 的脚本,如下所示:

pragma solidity ^0.8.20;

import {Script} from "forge-std/Script.sol";
import {console} from "forge-std/console.sol";

import {Defender, ApprovalProcessResponse} from "openzeppelin-foundry-upgrades/Defender.sol";
import {Upgrades, Options} from "openzeppelin-foundry-upgrades/Upgrades.sol";

import {MyContract} from "../src/MyContract.sol";

contract DefenderScript is Script {
    function setUp() public {}

    function run() public {
        ApprovalProcessResponse memory upgradeApprovalProcess = Defender.getUpgradeApprovalProcess();

        if (upgradeApprovalProcess.via == address(0)) {
            revert(string.concat("Upgrade approval process with id ", upgradeApprovalProcess.approvalProcessId, " has no assigned address"));
        }

        Options memory opts;
        opts.defender.useDefenderDeploy = true;

        address proxy = Upgrades.deployUUPSProxy(
            "MyContract.sol",
            abi.encodeCall(MyContract.initialize, ("Hello World", upgradeApprovalProcess.via)),
            opts
        );

        console.log("Deployed proxy to address", proxy);
    }
}

然后运行以下命令:

forge script &lt;你创建的脚本的路径> --force --rpc-url &lt;你想使用的网络的 RPC URL>

上面的示例假设实现合约将初始所有者地址作为其 initialize 函数的参数。 该脚本检索与 Defender 中配置的升级审批流程相关的地址(例如多重签名地址),并将该地址用作初始所有者,以便它可以拥有代理的升级权限。

此示例调用 Upgrades.deployUUPSProxy 函数,并使用 defender.useDefenderDeploy 选项,以使用 Defender 将实现合约和 UUPS 代理部署到连接的网络。 该函数等待部署完成,每个合约可能需要几分钟,然后返回已部署的代理地址。 在该函数等待时,你可以在 OpenZeppelin Defender 的 部署模块 中监视你的部署状态。

如果使用 EOA 或 Safe 进行部署,则必须在脚本运行时在 Defender 中提交挂起的部署。 该脚本会等待每个部署完成,然后继续。

示例 2 - 提议升级到代理: 要通过 Defender 提议升级,请创建一个如下脚本:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Script} from "forge-std/Script.sol";
import {console} from "forge-std/console.sol";

import {MyContractV2} from "../src/MyContractV2.sol";

import {ProposeUpgradeResponse, Defender, Options} from "openzeppelin-foundry-upgrades/Defender.sol";

contract DefenderScript is Script {
    function setUp() public {}

    function run() public {
        Options memory opts;
        ProposeUpgradeResponse memory response = Defender.proposeUpgrade(
            &lt;MY_PROXY_ADDRESS>,
            "MyContractV2.sol",
            opts
        );
        console.log("Proposal id", response.proposalId);
        console.log("Url", response.url);
    }
}

然后像示例 1 中一样运行脚本,然后转到生成的 URL 以查看和批准升级提案。

不可升级合约

如果要部署不可升级的合约,请从 Defender.sol 导入 Defender 库,并使用其函数通过 OpenZeppelin Defender 部署合约。

示例:

要部署不可升级合约,请创建一个名为 Defender.s.sol 的脚本,如下所示:

pragma solidity ^0.8.20;

import {Script} from "forge-std/Script.sol";
import {console} from "forge-std/console.sol";

import {MyContract} from "../src/MyContract.sol";

import {Defender} from "openzeppelin-foundry-upgrades/Defender.sol";

contract DefenderScript is Script {
    function setUp() public {}

    function run() public {
        address deployed = Defender.deployContract("MyContract.sol", abi.encode("constructor 的参数"));
        console.log("Deployed contract to address", deployed);
    }
}

然后运行以下命令:

forge script &lt;你创建的脚本的路径> --force --rpc-url &lt;你想使用的网络的 RPC URL>

上面的示例调用 Defender.deployContract 函数,以使用 Defender 将指定的合约部署到连接的网络。 该函数等待部署完成,这可能需要几分钟,然后返回已部署的合约地址。 在该函数等待时,你可以在 OpenZeppelin Defender 的 部署模块 中监视你的部署状态。

如果使用 EOA 或 Safe 进行部署,则必须在脚本运行时在 Defender 中提交挂起的部署。 该脚本会等待部署完成,然后继续。

← 与 Foundry 一起使用

编写可升级合约 →

  • 原文链接: docs.openzeppelin.com/up...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
OpenZeppelin
OpenZeppelin
江湖只有他的大名,没有他的介绍。