【问题标题】:How to interact with UUPS upgradeable contract using web3?如何使用 web3 与 UUPS 可升级合约交互?
【发布时间】:2021-12-19 04:12:53
【问题描述】:

我已经在 Ropsten 测试网上部署了一个 ERC20 代币,有两个版本。

V1 是一个简单的未经代理的 ERC20 代币,如下所示:

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC20, Ownable {
    constructor() ERC20("MyToken", "MTK") {}

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }
}

我可以使用 web3 与这个合约交互:

const Web3 = require('web3');
const MyToken = require('./build/contracts/MyToken.json');
const HDWalletProvider = require('@truffle/hdwallet-provider');

const provider = new HDWalletProvider(process.env.ACCOUNT_SECRET, process.env.INFURA_URL);
const web3 = new Web3(provider);
const contract = new web3.eth.Contract(MyToken.abi, process.env.CONTRACT_ADDRESS);

例如,这是一个检索合约所有者的调用:

await contract.methods.owner().call();

另一方面,V2 是一个 UUPS 可升级合约,如下所示:

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

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

contract MyToken is Initializable, ERC20Upgradeable, OwnableUpgradeable, UUPSUpgradeable {
    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() initializer {}

    function initialize() initializer public {
        __ERC20_init("MyToken", "MTK");
        __Ownable_init();
        __UUPSUpgradeable_init();
    }

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }

    function _authorizeUpgrade(address newImplementation)
        internal
        onlyOwner
        override
    {}
}

为了使用相同的 web3 nodejs 代码与 V2 交互,我尝试将 build/abi 以及 process.env.CONTRACT_ADDRESS 从 V1 的地址更新到 V2 的地址。但是,每当我使用相同的代码检索所有者时,它总是返回零地址。

我认为呼叫应该被代理或其他什么,但我不知道如何并且我找不到关于此的资源(文档/教程)。不胜感激。

编辑:

更多信息

  • 合约 V1 和 V2 是从 wizard.openzeppelin.com 生成的。没有任何修改。

  • V2 通过了获取所有者、符号和名称松露测试。

【问题讨论】:

    标签: solidity smartcontracts web3 erc20


    【解决方案1】:

    我不太确定关于 constructor() 中的 initializer {} 修饰符的最佳做法是什么。我的猜测是 OpenZeppelin 建议将它与构造函数一起使用,以防您还在构造函数中设置其他变量而不使用其他 init 函数。

    但是,您的实现的效果是它只是将 initialized 变量设置为 true 而不执行顶级 initialize() 函数 - 实际上没有设置 owner 变量(以及其他,例如namesymbol)。

    我能够通过删除 initializer 修饰符来执行快速修复(因为它已经使用 initialize() 函数,并从构造函数中调用 initialize()。请检查是否没有任何副作用它。

    // removed the modifier
    // added the call to `initialize()`
    constructor() {
        initialize();
    }
    
    // stays the same
    function initialize() initializer public {
    

    【讨论】:

    • 感谢您的回答!但是,(我的错)我可能应该补充一点,V1 和 V2 是从wizard.openzeppelin.com 生成的。绝对没有任何修改。关于constructor() initializer {},这里是reference,为什么它被添加为安全标准。所以我有点犹豫要修改那部分代码。此外,我应该提到 V2 通过了获取所有者、符号、名称等松露测试。
    • @L.Lei 我明白了。我能够重现您的问题(通过从向导生成“错误”源代码)。从this discussion 看来,可升级的 OZ 合约通常在 Remix 中不起作用。当我有时间时,我会尝试更深入地研究这个。
    • 是的,我使用 OZ upgrades plugins(链接中提到的 nodejs 包)和 Truffle 来部署和测试我的 V2,而不是 remix,因为它是 UUPS 代理的(我还想指出在您链接的帖子中,该操作使用透明代理)。到目前为止,根据文档,他们工作得很好。我真的不知道如何使用 web3 与像 V2 这样的 UUPS 可升级合同进行交互。另外,非常感谢您的帮助,谢谢!
    猜你喜欢
    • 2020-08-25
    • 1970-01-01
    • 1970-01-01
    • 2022-07-19
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 2021-09-27
    • 1970-01-01
    相关资源
    最近更新 更多