[英]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.