Remix 中 UUPS 代理合约部署、开源验证等问题的解决
2024-05-1018:00
登链社区
2024-05-10 18:00
登链社区
2024-05-10 18:00
收藏文章
订阅专栏

 


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

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

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

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

使用@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

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

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

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

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

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

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

  1. 实现合约的验证

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


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

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

注意,这里的 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

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




登链社区是区块链开发者的家园,在这里不仅可以阅读文章、学习课程、参与问答与讨论,还可以发布活动、进行人才招募。我们帮助开发者更好的进入 web3 。


学习系统的技术内容 / 发布活动、招聘

https://learnblockchain.cn/


开发者的链上技能认证平台

https://decert.me/


给开发者的开源、免费工具箱

https://chaintool.tech/

关注社区 Twitter

@UpchainDAO


加入社区 Discord

https://discord.gg/pZxy3CU8mh


加入微信群

参考资料
[1]

全面理解智能合约升级: https://learnblockchain.cn/article/1933

[2]

Solidity 可升级代理模式: 透明代理与 UUPS 代理: https://learnblockchain.cn/article/4257

[3]

智能合约设计模式:代理: https://learnblockchain.cn/article/7249

[4]

X Layer 测试网的区块浏览器: https://www.okx.com/zh-hans/web3/explorer/xlayer-test


【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。

专栏文章
查看更多
数据请求中

推荐专栏

数据请求中

一起「遇见」未来

DOWNLOAD FORESIGHT NEWS APP

Download QR Code