簡體   English   中英

透明代理測試 - 錯誤:調用異常中缺少還原數據; 交易在沒有原因字符串的情況下被恢復;

[英]Transparent proxy tests - Error: missing revert data in call exception; Transaction reverted without a reason string;

我正在嘗試使用 Openzeppelin (OZ) 提供的 ERC20 可升級合約創建一個新的代幣合約。 我創建了代幣合約,然后進行了一些基本的單元測試。 但是,在其中一項測試中,我希望在從代理管理員調用實現方法時看到“TransparentUpgradeableProxy: admin cannot fallback to proxy target” 在我的一個項目中它工作正常,但在另一個從頭開始的項目中 - 它沒有。 我收到的錯誤是“錯誤:調用異常中缺少還原數據;事務在沒有原因字符串的情況下還原...”

這是失敗的代碼:

// the contract ---
contract TokenName is ERC20PresetMinterPauserUpgradeable {
    /**
     * @dev Used to prevent implementation manipulation
     */
    constructor() initializer {}

    /**
     * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE`, `PAUSER_ROLE` to the owner
     * specified in the owner param.
     * @param owner is the owner of the contract after initialization
     * See {ERC20-constructor}.
     */
    function initialize(string memory name, string memory symbol, address owner) public initializer {
        require(owner != address(0x0), "New owner cannot be 0");
        __ERC20PresetMinterPauser_init(name, symbol);
        __ERC20_init(name, symbol);
        _setupRole(DEFAULT_ADMIN_ROLE, owner);
        _setupRole(MINTER_ROLE, owner);
        _setupRole(PAUSER_ROLE, owner);
        revokeRole(PAUSER_ROLE, _msgSender());
        revokeRole(MINTER_ROLE, _msgSender());
        revokeRole(DEFAULT_ADMIN_ROLE, _msgSender());
     }


    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override(ERC20PresetMinterPauserUpgradeable) {
        ERC20PresetMinterPauserUpgradeable._beforeTokenTransfer(from, to, amount);
    }
}

// token unit tests ---
describe.only("Upgradeable token tests", function () {
  let accounts;
  let deployer;
  let owner;

  let tokenInstance;

  let tokenName = "Token Name";
  let tokenSymbol = "symbol";
  const tokenAmount = '10000000000000000000';

  before(async function() {
    accounts = await ethers.getSigners();
    deployer = accounts[0];
    owner = accounts[1];
    user = accounts[2];
  })

  it("should throw error when calling the implementation contract with the proxy admin", async function() {
    const tokenContract = await ethers.getContractFactory(tokenSymbol);
    tokenInstance = await upgrades.deployProxy(tokenContract, [tokenName, tokenSymbol, owner.address], { initializer: 'initialize(string,string,address)', unsafeAllow: ['constructor'] });
    await tokenInstance.deployed();

    console.log("default admin addr: ", await upgrades.erc1967.getAdminAddress(tokenInstance.address));
    console.log("token instance addr: ", tokenInstance.address);
    await upgrades.admin.changeProxyAdmin(tokenInstance.address, owner.address);

    console.log("changed admin addr: ", await upgrades.erc1967.getAdminAddress(tokenInstance.address));
    expect(await upgrades.erc1967.getAdminAddress(tokenInstance.address)).to.equal(owner.address);

    //console.log("tokenInstance", tokenInstance);
    console.log("owner addr: ", owner.address);
    console.log("deployer addr: ", deployer.address);

    console.log("admin changed ---");
    
    await expect(tokenInstance.connect(owner).name()).to.be.revertedWith('TransparentUpgradeableProxy: admin cannot fallback to proxy target');
  });
})

其他項目的代碼就不用多加了,因為一模一樣,不過為了拿來對比一下。

// token contract ---
contract MarsCoin is ERC20PresetMinterPauserUpgradeable {
    uint counter;

    function increment() public {
        counter += 1;
    }

    function getCounter() public view returns (uint) {
        return counter;
    }

    /**
     * @dev Used to prevent implementation manipulation
     */
    constructor() initializer {}

    /**
     * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE`, `PAUSER_ROLE` to the owner
     * specified in the owner param.
     * @param owner is the owner of the contract after initialization
     * See {ERC20-constructor}.
     */
    function initialize(string memory name, string memory symbol, address owner) public initializer {
        require(owner != address(0x0), "New owner cannot be 0");
        counter = 0;
        __ERC20PresetMinterPauser_init(name, symbol);
        __ERC20_init(name, symbol);
        _setupRole(DEFAULT_ADMIN_ROLE, owner);
        _setupRole(MINTER_ROLE, owner);
        _setupRole(PAUSER_ROLE, owner);
        revokeRole(PAUSER_ROLE, _msgSender());
        revokeRole(MINTER_ROLE, _msgSender());
        revokeRole(DEFAULT_ADMIN_ROLE, _msgSender());
     }


    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual override(ERC20PresetMinterPauserUpgradeable) {
        ERC20PresetMinterPauserUpgradeable._beforeTokenTransfer(from, to, amount);
    }
}

// token unit tests ---
const { expect } = require("chai");
const { ethers, upgrades } = require("hardhat");

describe.only("Mars Coin tests", function () {
  let accounts;
  let deployer;
  let owner;

  let tokenInstance;

  let tokenName = "Mars Coin";
  let tokenSymbol = "MARS";
  const tokenAmount = '10000000000000000000';

  before(async function() {
    accounts = await ethers.getSigners();
    deployer = accounts[0];
    owner = accounts[1];
    user = accounts[2];
  })

  it("Should deploy MARS token with correct owner set", async function () {
    const MarsCoin = await ethers.getContractFactory("MarsCoin");
    tokenInstance = await upgrades.deployProxy(MarsCoin, [tokenName, tokenSymbol, owner.address], { initializer: 'initialize(string,string,address)', unsafeAllow: ['constructor'] });
    await tokenInstance.deployed();

    const adminRole = await tokenInstance.DEFAULT_ADMIN_ROLE();
    const minterRole = await tokenInstance.MINTER_ROLE();
    const pauserRole = await tokenInstance.PAUSER_ROLE();

    expect(await tokenInstance.name()).to.equal(tokenName);
    expect(await tokenInstance.symbol()).to.equal(tokenSymbol);

    expect(await tokenInstance.hasRole(adminRole, deployer.address)).to.equal(false);
    expect(await tokenInstance.hasRole(minterRole, deployer.address)).to.equal(false);
    expect(await tokenInstance.hasRole(pauserRole, deployer.address)).to.equal(false);

    expect(await tokenInstance.hasRole(adminRole, owner.address)).to.equal(true);
    expect(await tokenInstance.hasRole(minterRole, owner.address)).to.equal(true);
    expect(await tokenInstance.hasRole(pauserRole, owner.address)).to.equal(true);
  });

  it("Should mint tokens to user account", async function() {
    const tokenInstanceWithOwner = tokenInstance.connect(owner);
    await tokenInstanceWithOwner.mint(user.address, tokenAmount);
    const accountBalance = (await tokenInstance.balanceOf(user.address)).toString();
    expect(accountBalance).to.equal(tokenAmount)
  })

  it("Should try to call contract implementation contract with deployer", async function () {
    const tokenInstanceWithDeployer = tokenInstance.connect(deployer);
    expect(await tokenInstanceWithDeployer.name()).to.equal(tokenName)
  })

  it("Should change the MARS token proxy admin correctly", async function() {
    await upgrades.admin.changeProxyAdmin(tokenInstance.address, owner.address);
    expect(await upgrades.erc1967.getAdminAddress(tokenInstance.address)).to.equal(owner.address);
  })
  
  it.only("Should throw on trying to call contract implementation from new proxy admin owner", async function () {
    const MarsCoin = await ethers.getContractFactory("MarsCoin");
    tokenInstance = await upgrades.deployProxy(MarsCoin, [tokenName, tokenSymbol, owner.address], { initializer: 'initialize(string,string,address)', unsafeAllow: ['constructor'] });
    await tokenInstance.deployed();
    
    await upgrades.admin.changeProxyAdmin(tokenInstance.address, owner.address);
    expect(await upgrades.erc1967.getAdminAddress(tokenInstance.address)).to.equal(owner.address);

    await expect(tokenInstance.connect(owner).name()).to.be.revertedWith('TransparentUpgradeableProxy: admin cannot fallback to proxy target');
  })
});

請記住我正在運行的.only測試,因此可以跳過 rest,但我只是粘貼它以獲得准確的代碼。

好的,我通過從頭開始創建項目成功地解決了這個問題。

npm init -> 然后按照基本說明進行操作
npm install hardhat
npx hardhat init -> 創建一個高級示例項目並按照說明進行操作
npm install - 缺少所有必要的包(一些現有的包是用舊版本重新安裝的,因為問題似乎來自較新版本的庫)

非常有趣的東西.. 以前我只是嘗試刪除所有文件夾,如.cache、node_module、內置文件夾、package-lock.json,然后點擊npm install ,但沒有成功。 我不明白到底是什么問題。

但是,這些是我正在使用的包:

   "devDependencies": {
    "@nomiclabs/hardhat-ethers": "^2.0.2",
    "@nomiclabs/hardhat-etherscan": "^3.0.3",
    "@nomiclabs/hardhat-waffle": "^2.0.1",
    "chai": "^4.3.4",
    "dotenv": "^10.0.0",
    "eslint": "^7.32.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-config-standard": "^16.0.3",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-prettier": "^3.4.1",
    "eslint-plugin-promise": "^5.2.0",
    "ethereum-waffle": "^3.4.0",
    "ethers": "^5.4.5",
    "hardhat": "^2.6.1",
    "hardhat-gas-reporter": "^1.0.8",
    "prettier": "^2.6.2",
    "prettier-plugin-solidity": "^1.0.0-beta.13",
    "solhint": "^3.3.7",
    "solidity-coverage": "^0.7.20"
  },
  "dependencies": {
    "@openzeppelin/contracts": "^4.3.0",
    "@openzeppelin/contracts-upgradeable": "^4.3.2",
    "@openzeppelin/hardhat-upgrades": "^1.10.0"
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM