Hardhat-deploy: OpenZeppelin UUPS 代理支持

创建于 2021-06-28  ·  13评论  ·  资料来源: wighawag/hardhat-deploy

我看到支持OpenZeppelinTransparentProxy 。 是否有计划在不久的将来添加UUPS 代理支持?

enhancement

最有用的评论

计划本地支持,但现在仍然可以将它们与安全帽部署一起使用。 代理 jist 需要在其构造函数中有一个虚拟/未使用的所有者 arg 以保持兼容。

所有13条评论

计划本地支持,但现在仍然可以将它们与安全帽部署一起使用。 代理 jist 需要在其构造函数中有一个虚拟/未使用的所有者 arg 以保持兼容。

代理 jist 需要在其构造函数中有一个虚拟/未使用的所有者 arg 以保持兼容。

这不会使使用 UUPS 不再有益吗? 使用 UUPS 的原因是为了节省事务调用的 gas,因为代理不需要检查是否是管理员发出调用。

也许我错过了它,您能否用一些伪代码详细说明如何将安全帽部署与 uups 代理一起使用(使用未使用的参数)?

谢谢

它不会影响gas,它只是一个虚拟参数,因此安全帽部署可以在不更改代码的情况下部署它。 构造函数不需要对该参数做任何事情。
看看我是否可以进行更改以使其在不进行任何更改的情况下尽快工作。 这应该是一个小的更改,您可以在其中为代理指定构造函数 arg,或者可能只是指定它是一个 UUPS 代理

感谢@wigawag ,终于解决了这个问题。

对于那些有兴趣的人,我创建了这个合同:

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

// Kept for backwards compatibility with older versions of Hardhat and Truffle plugins.
contract UUPSProxy is ERC1967Proxy {
  constructor(
    address _logic,
    address, // This is completely unused by the uups proxy, required to remain compatible with hardhat deploy: https://github.com/wighawag/hardhat-deploy/issues/146
    bytes memory _data
  ) payable ERC1967Proxy(_logic, _data) {}
}

然后我的部署看起来像这样( proxyContract: "UUPSProxy"是重要的部分):

  await deploy(CONTRACT, {
    from: deployer,
    proxy: {
      proxyContract: "UUPSProxy",
      // ... your other config, initializers etc
    },
    log: true,
  });

@JasoonS请您澄清一下UUPSProxy合同代码的用途吗? 它只是一个虚拟合同,以便安全帽部署知道实际代理构造函数的接口吗? 或者它实际上是否与部署的代理合同有关?

admin的作用究竟是什么,无论是否存在deployer (=upgrade admin) 或省略该字段,我都会收到错误消息。

proxy: {
      proxyContract: "UUPSProxy",
      execute: {
        methodName: "initialize",
        args: [admin],
      },
    },

@marceljay请(总是)粘贴你得到的错误:-)

@aspiers ,我还没有深入研究安全帽部署,所以请纠正我@wighawag。 但据我所知,它知道如何部署透明代理。 透明代理与管理这些代理的管理员一起部署。 在 UUPS 合同中,您没有管理升级的外部合同(代理管理员),而是在实现本身中 - 因此不会传递到代理构造函数中。

因此,为了使用 hardhat-deploy 进行这项工作,我们使用与透明代理相同的构造函数部署它,但我们只是忽略 admin 字段并获得相同的效果。

似乎对我有用@marceljay

免责声明我的代码片段没有经过审核 :sweat_smile: - 我对配置不当的代理不承担任何责任 :laughing:

@marceljay啊,是的,我能猜到你的问题。 我编辑了我的原始回复。

下面的代码是在实现上要做的事情。 所以我在实现(不是代理)上有一个名为 initialize 的函数,它接受 1 个参数(管理员)。

execute: {
  methodName: "initialize",
  args: [admin],
},

@marceljay啊,是的,我能猜到你的问题。 我编辑了我的原始回复。

下面的代码是在实现上要做的事情。 所以我在实现(不是代理)上有一个名为 initialize 的函数,它接受 1 个参数(管理员)。

execute: {
  methodName: "initialize",
  args: [admin],
},

是的,现在它完全有道理,看到你编辑了答案:)

您知道ERC1967Proxy合同是否与 OZ 升级插件使用的合同相同吗?

@JasoonS非常感谢的解释,但我还是不完全明白这一点。 您在上面发布了一份合同,起始时间为:

contract UUPSProxy is ERC1967Proxy {

这是否真的通过您上面发布的示例await deploy代码进行了部署,还是只是一个虚拟合同,以便安全帽部署知道实际代理的构造函数的接口,或者其他什么? 你写了:

我们使用与透明代理相同的构造函数部署它

但如果它真的在部署,那么我看不出它是如何工作的,因为该合同继承自ERC1967Proxy而不是UUPSUpgradeable ,那么实际的 UUPS 功能从何而来?

您上面发布的示例等待部署代码是否真的部署了它

是的,它实际上部署了它。

因为该合约继承自 ERC1967Proxy 而不是 UUPSUpgradeable

它应该使用 ERC1967Proxy(来自 openzeppelin 的 UUPS 和透明代理都使用 erc1967,https://docs.openzeppelin.com/contracts/4.x/api/proxy#transparent-vs-uups)。 UUPSUpgradeable合同由实现合同使用(它不是代理的一部分)。

那么实际的 UUPS 功能从何而来?

通过设计,实现合约持有 UUPS 功能,(这很好,因为它更高效,因为逻辑不在代理本身中,但不好,因为可能会错误地升级到不兼容的合约并破坏可升级性)。

另外,我绝对不是代理方面的专家,这只是我自己的研究。

@JasoonS2021 年 9 月 1 日晚上 9:18发表评论:

因为该合约继承自 ERC1967Proxy 而不是 UUPSUpgradeable

它应该使用 ERC1967Proxy(来自 openzeppelin 的 UUPS 和透明代理都使用 erc1967, docs.openzeppelin.com/ contracts/4.x/ vs-uups )。

对。 而ERC-1967除了指定执行地址、信标地址和管理地址的存储位置外,并没有做太多事情。 顺便说一句,我注意到一个有趣的事实:为了符合 ERC-1967,OZ UUPS 实现实际上违反了 EIP1822,它为实现地址指定了一个稍微不同的存储位置。

UUPSUpgradeable合同由实现合同使用(它不是代理的一部分)。

哦,当然! 谢谢你帮我看看我在这里愚蠢地错过了什么。

那么实际的 UUPS 功能从何而来?

通过设计,实现合约持有 UUPS 功能,(这很好,因为它更高效,因为逻辑不在代理本身中,但不好,因为可能会错误地升级到不兼容的合约并破坏可升级性)。

是的,所以实现必须从UUPSUpgradeable继承。

再次非常感谢您的大力帮助!

此页面是否有帮助?
0 / 5 - 0 等级