Remix中UUPS代理合约部署、开源验证等问题的解决

本文记录一下UUPS代理合约无法在XLayer链上开源验证的问题。

昨天遇到了一个UUPS 代理合约无法在 X Layer 链上开源验证的问题,搜索了大量文章,看了油管视频,还是没有解决,最后我直接扒开@openzeppelin源码进行实验才解决了问题。本文记录一下这个问题的解决。

关于 UUPS 代理的原理和详细内容 本文不讲,但一些文章对我的帮助很大,在此列出来:

全面理解智能合约升级 Solidity 可升级代理模式: 透明代理与 UUPS 代理 智能合约设计模式:代理

编写一个测试用的实现合约

使用@openzeppelin/contracts-upgradeable编写一个实现合约(注意,不需要自己实现代理合约,openzeppelin 已经实现好了

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

contract Counter is Initializable, UUPSUpgradeable, OwnableUpgradeable {

    uint256 public count;

    // initialize: required
    function initialize() public initializer {

        __Ownable_init();
        __UUPSUpgradeable_init();
    }

    // _authorizeUpgrade: required
    function _authorizeUpgrade(address) internal override onlyOwner {}

    function store(uint256 _count) external {
        count = _count;
    }
}

只是为了测试 uups 代理的编写、部署和验证,因此,这个合约特别简单,一个公共状态变量count,和一个store方法。

使用 Remix 部署实现合约,并自动部署代理合约

如下图所示,我们选择 X Layer 网络(ChainId: 195),并在Deploy按钮下方勾选Deploy with Proxy

image.png

点击Deploy按钮,会弹出一个对话框,提示你将要发送两笔交易,一笔是我们自己写的 Counter 实现合约,另一笔是代理合约(PS: 困扰我的问题就是这个代理合约在开源验证的时候,由于代理合约是Remix自动帮我们部署的,没有源码,始终无法验证,这个问题下文我会给出解决方法

image.png

点击Proceed开始调出钱包签名发送交易,不出意外的话,当第一笔交易成功后,会再弹出一个对话框(如下图),提示我们确认部署一个ERC1967Proxy合约,这个合约就是 Remix 自动帮我们部署的代理合约,并且和上一笔交易部署的Counter实现合约进行关联。

image.png

点击OK继续调出钱包签名发送交易,成功后,我们在 Remix 里就会看见这两个合约。

需要提醒的是,我们与合约的所有交互都应该调用代理合约,即ERC1967Proxy合约,所有的状态信息都存储在这个合约里,可以查看这个合约的 Owner 已经初始化好了。当你去查看实现合约(即 Counter 合约)的 Owner 时会发现是零地址,这是对的,因为实现合约只负责业务逻辑,不做存储。

开源验证实现合约(Counter 合约)、代理合约(ERC1967Proxy 合约)

在进行合约验证时,应先验证实现合约,再验证代理合约。

  1. 实现合约的验证

打开 X Layer 测试网的区块浏览器,找到我们刚才部署的合约,其中有个合约选项框,打开之后能看到有跳转验证页面的按钮,点击[去验证合约->]就可以进入验证页面了。

image.png

<br /> 这里的 编译器类型选择Solidity(SingleFile),编译器版本选择你编译合约的版本。之后点击下一步进入下一个页面。

image.png

<br />

这个页面有很多选项,大部分不用管,把Counter合约的源码粘贴进来,其他的如 优化选项、开源许可类型等 根据自己的实际情况写就行了。

image.png

注意,这里的Counter合约源码需要先进行展开,以hardhat项目为例,执行npx hardhat flatten contracts/Counter.sol > contracts/Counter_flat.sol,执行后,这个Counter_flat.sol就是展开的代码。

当源码和所有选项都写好,就可以点击提交按钮了。如果你的所有步骤都操作正确,这时候合约就验证成功了。

  1. 代理合约的验证

上文说了,代理合约是Remix帮我们自动部署的,不是我们自己写的代码。所以问题是源码在哪里?

实际上,这个代理合约的源码就是 @openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol。根据前面的验证流程,我们需要把这个合约的源码展开,因此,我们将这个合约复制到我们自己的hardhat项目中,把ERC1967Proxy.sol中引用的相对路径(”./“, "../")都改成绝对路径(@openzeppelin/contracts......), 之后,和上面实现合约验证一样,我们执行 npx hardhat flatten ......就可以展开代码了。

还需要注意:验证代理合约时的编译器版本选择v0.8.7+commit.e28d00a7,虽然我们自己部署合约用的是v0.8.18,但是代理合约是Remix自动编译部署的,可能Remix编译代理合约的时候用的是v0.8.7

其他的验证流程和上面的实现合约验证流程一样,这里就不再赘述了。

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
认知那些事
认知那些事
0x2b62...95a0
人立于天地之间,必然有我们的出路。