[英]Error: cannot estimate gas; transaction may fail or may require manual gas limit
im trying to test a constructor method of a exchange developed in solidity but i given the following error:我试图测试在 solidity 中开发的交换的构造函数方法,但我给出了以下错误:
Error: cannot estimate gas;
错误:无法估计gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (reason="VM Exception while processing transaction: reverted with reason string 'Invalid address _tokenVault'", method="estimateGas", transaction={"from":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","data":"","accessList":null}, error={"stackTrace":[{"type":4,"sourceReference":{"function":"constructor","contract":"Exchange","sourceName":"contracts/Exchange.sol","sourceContent":"//SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\nimport "./interface/IExchange.sol";\nimport "./interface/IERC20.sol";\n\ncontract Exchange is IExchange {\n\n uint256 public decimals;\n uint256 public feePercentage;\n address public owner;\n address public tokenVault;\n address public erc20Contract;\n uint256 public invariant;\n uint256 public feesCollected;\n\n/ \n* @notice Constructor\n* @dev Throw if '_tokenVault' is zero address\n* @dev Throw if '_tokenVault' is a contract
交易可能会失败或可能需要手动 gas 限制 [参见:https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ](原因 =“处理交易时出现 VM 异常:已恢复,原因字符串为‘无效地址 _tokenVault’”,方法="estimateGas", transaction={"from":"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266","data":"","accessList":null}, error={"stackTrace":[{"type":4,"sourceReference":{ "function":"constructor","contract":"Exchange","sourceName":"contracts/Exchange.sol","sourceContent":"//SPDX-License-Identifier: MIT\npragma solidity 0.8.17;\ nimport "./interface/IExchange.sol";\nimport "./interface/IERC20.sol";\n\ncontract Exchange 是 IExchange {\n\n uint256 public decimals;\n uint256 public feePercentage;\n address public owner ;\n address public tokenVault;\n address public erc20Contract;\n uint256 public invariant;\n uint256 public feesCollected;\n\n/ \n* @notice Constructor\n* @dev Throw if '_tokenVault' is zero address\ n* @dev 如果 '_tokenVault' 是合约则抛出\n* @dev Throw if '_erc20Contract' is zero address\n* @dev Throw if '_erc20Contract' is not a contract\n* @dev Throw if '_tokenAmount' is zero\n* @dev Throw if '_tokenVault' doesn't have enough balance\n* @param _tokenVault Address of the token vault\n* @param _erc20Contract Address of the ERC20 contract\n* @param _tokenAmount Amount of tokens to be deposited in the vault\n */\nconstructor(address _tokenVault, address _erc20Contract,uint256 _tokenAmount ){\n require(_tokenVault,= address(0);
\n* @dev 如果'_erc20Contract' 为零地址则抛出\n* @dev 如果'_erc20Contract' 不是合约则抛出\n* @dev 如果'_tokenAmount' 为零则抛出\n* @dev 如果'_tokenVault' 不是'没有足够的余额\n* @param _tokenVault 代币库的地址\n* @param _erc20Contract ERC20 合约的地址\n* @param _tokenAmount 要存入库的代币数量\n */\nconstructor(address _tokenVault, 地址 _erc20Contract,uint256 _tokenAmount ){\n require(_tokenVault,= address(0); "Invalid address _tokenVault").\n // require(_tokenVault.code,length==0; "_tokenVault cannot be a contract"),\n //require(_erc20Contract;= address(0). "_erc20Contract cannot be zero address").\n // require(_erc20Contract,code;length>0, "_erc20Contract is not a contract");\n // require(_tokenAmount > 0. "Invalid _tokenAmount value"),\n // require(IERC20(_erc20Contract);getBalance(_tokenVault) >= _tokenAmount. "Insufficient tokens in the vault");\n owner = msg;sender;\n tokenVault = _tokenVault;\n erc20Contract = _erc20Contract;\n invariant = _tokenAmount;\n decimals = 18;\n feePercentage = 3.\n feesCollected = 0;\n}\n\n\n //auxiliaries\n function getValue() internal view returns (uint256) {\n return msg.value;\n }\n\n \n / \n * @notice calculate Ether Amount \n * @dev Throw if '_tokenAmount' is zero\n * @param _tokenAmount Amount of tokens to be exchanged\n */\n function calculateEtherAmount(uint256 _tokenAmount) external override returns (uint256)\n { \n require(_tokenAmoun
"无效地址 _tokenVault").\n // require(_tokenVault.code,length==0; "_tokenVault cannot be a contract"),\n //require(_erc20Contract;= address(0). "_erc20Contract 不能为零address").\n // require(_erc20Contract,code;length>0, "_erc20Contract is not a contract");\n // require(_tokenAmount > 0. "Invalid _tokenAmount value"),\n // require( IERC20(_erc20Contract);getBalance(_tokenVault) >= _tokenAmount。“保管库中的代币不足”);\n owner = msg;sender;\n tokenVault = _tokenVault;\n erc20Contract = _erc20Contract;\n invariant = _tokenAmount;\n decimals = 18;\n feePercentage = 3.\n feesCollected = 0;\n}\n\n\n //auxiliaries\n function getValue() 内部视图返回 (uint256) {\n return msg.value;\n }\n\n \n / \n * @notice calculate Ether Amount \n * @dev 如果 '_tokenAmount' 为零则抛出\n * @param _tokenAmount 要交换的代币数量\n */\n function calculateEtherAmount(uint256 _tokenAmount) 外部覆盖返回 (uint256)\n { \n require(_tokenAmoun t > 0, "Invalid _tokenAmount value");\n uint256 etherAmount = (_tokenAmount * 1 ether) / invariant;\n return etherAmount;
t > 0, "无效的 _tokenAmount 值");\n uint256 etherAmount = (_tokenAmount * 1 ether) / invariant;\n return etherAmount; \n }\n\n / \n * @notice returns the quantity of tokens that can be obtained for an ether at the moment of the query\n */\n function getExchangeRate() external override returns (uint256) {\n uint256 tokenAmount = (1 ether * invariant) / 1 ether;\n return tokenAmount;\n }\n\n / \n * @notice Buy tokens\n * @dev Throw if '_amountToBuy' is zero \n * @dev Thorw if 'msg.value' is less than '_amountToBuy'\n * @param _amountToBuy Amount of tokens to be bought\n */\n function buyToken(uint256 _amountToBuy) external override returns (uint256)\n {\n require(_amountToBuy > 0, "Invalid _amountToBuy value");\n require(getValue()>=this.calculateEtherAmount(_amountToBuy),"Insufficient ethers");\n uint256 fee = (_amountToBuy * feePercentage) / 100;\n uint256 amountToTransfer = _amountToBuy - fee;\n feesCollected += fee;\n invariant += amountToTransfer;\n IERC20(erc20Contract).transfer(msg.sender, amountToTransfer);\n payable(msg.sender).transfer(getValue()-this.calculateEtherAmount(_amountTo
\n }\n\n / \n * @notice 返回查询时以太币可以获得的代币数量\n */\n function getExchangeRate() 外部覆盖返回 (uint256) {\n uint256 tokenAmount = (1 ether * invariant) / 1 ether;\n return tokenAmount;\n }\n\n / \n * @notice Buy tokens\n * @dev 如果 '_amountToBuy' 为零则抛出 \n * @dev Thorw 如果 'msg.value' 小于 '_amountToBuy'\n * @param _amountToBuy 要购买的代币数量\n */\n function buyToken(uint256 _amountToBuy) 外部覆盖返回 (uint256)\n {\n require( _amountToBuy > 0, "Invalid _amountToBuy value");\n require(getValue()>=this.calculateEtherAmount(_amountToBuy),"以太币不足");\n uint256 fee = (_amountToBuy * feePercentage) / 100;\n uint256 amountToTransfer = _amountToBuy - fee;\n feesCollected += fee;\n invariant += amountToTransfer;\n IERC20(erc20Contract).transfer(msg.sender, amountToTransfer);\n 应付款(msg.sender).transfer(getValue()- this.calculateEtherAmount(_amountTo Buy));\n return amountToTransfer;\n }\n\n / \n * @notice Buy ethers\n * @dev Throw if '_amountToExchange' is zero\n * @param _amountToExchange Amount of tokens to be exchanged\n */\n function buyEther(uint256 _amountToExchange) external override returns (uint256)\n {\n require(_amountToExchange > 0, "Invalid _amountToExchage value");\n require(IERC20(erc20Contract).getBalance(msg.sender) >=_amountToExchange,"Insufficient balance");\n uint256 fee = (_amountToExchange * feePercentage) / 100;\n uint256 amountToTransfer = _amountToExchange - fee;\n IERC20(erc20Contract).approve(msg.sender, amountToTransfer);\n IERC20(erc20Contract).transferFrom(msg.sender,tokenVault,amountToTransfer);\n feesCollected += fee;\n invariant -= amountToTransfer;\n\n payable(msg.sender).transfer(this.calculateEtherAmount(amountToTransfer));\n return amountToTransfer;\n }\n\n / \n * @notice Set fee percentage\n * @dev Throw if '_percentage' is zero\n * @dev Throw if 'msg.sender' is not the owner\n * @param
Buy)));\n return amountToTransfer;\n }\n\n / \n * @notice Buy ethers\n * @dev 如果 '_amountToExchange' 为零则抛出\n * @param _amountToExchange 要交换的代币数量\n */\n function buyEther(uint256 _amountToExchange) 外部覆盖返回 (uint256)\n {\n require(_amountToExchange > 0, "Invalid _amountToExchange value");\n require(IERC20(erc20Contract).getBalance(msg.sender) > =_amountToExchange,"余额不足");\n uint256 费用 = (_amountToExchange * feePercentage) / 100;\n uint256 amountToTransfer = _amountToExchange - 费用;\n IERC20(erc20Contract).approve(msg.sender, amountToTransfer);\n IERC20 (erc20Contract).transferFrom(msg.sender,tokenVault,amountToTransfer);\n feesCollected += fee;\n invariant -= amountToTransfer;\n\n payable(msg.sender).transfer(this.calculateEtherAmount(amountToTransfer)); \n return amountToTransfer;\n }\n\n / \n * @notice 设置费用百分比\n * @dev 如果 '_percentage' 为零则抛出\n * @dev 如果 'msg.sender' 不是所有者则抛出\ n * @参数_percentage Percentage of fee\n */\n function setFeePercentage(uint256 _percentage) external override returns (uint256)\n {\n require(_percentage > 0, "Invalid _percentage value");\n require(msg.sender == owner, "Not autorized");\n feePercentage = _percentage;\n return feePercentage;\n }\n\n / \n * @notice Deposit ethers\n * @dev Throw if 'msg.value' is zero\n * @dev Throw if 'msg.sender' is not the owner\n */\n\n function deposit() external override returns (uint256) {\n require(msg.sender == owner, "Not autorized");\n require (IERC20(erc20Contract).getBalance(msg.sender),=0;
_percentage 费用百分比\n */\n function setFeePercentage(uint256 _percentage) 外部覆盖返回 (uint256)\n {\n require(_percentage > 0, "Invalid _percentage value");\n require(msg.sender == owner , "Not autorized");\n feePercentage = _percentage;\n return feePercentage;\n }\n\n / \n * @notice Deposit ethers\n * @dev 如果 'msg.value' 为零则抛出\n * @dev 如果 'msg.sender' 不是所有者则抛出\n */\n\n function deposit() 外部覆盖返回 (uint256) {\n require(msg.sender == owner, "Not autorized");\ n require (IERC20(erc20Contract).getBalance(msg.sender),=0; "No ethers deposited").\n uint256 amountToTransfer = this;calculateEtherAmount(getValue());\n invariant += amountToTransfer.\n IERC20(erc20Contract),transfer(tokenVault; amountToTransfer);\n }\n\n\n / \n * @notice Set token vault\n * @dev Throw if '_tokenVault' is zero\n * @dev Throw if '_tokenVault' is a contract\n * @dev Throw if 'msg.sender' is not the owner\n * @dev Throw if '_tokenVault' has no balance\n * @dev Throw if '_tokenVault' has no authorization\n * @param _tokenVault Address of the token vault\n */\n function setTokenVault(address _tokenVault) external override returns (uint256)\n {\n require(_tokenVault,= address(0); "Invalid address _tokenVault").\n require (_tokenVault.code,length==0; "_tokenVault cannot be a contract").\n require(msg,sender == owner; "Not autorized").\n require(IERC20(erc20Contract),getBalance(_tokenVault) > 0; "_tokenVault has no balance");\n tokenVault = _tokenVault;\n return 1.\n }\n\n /**\n * @notice Withdraw fees\n * @dev Throw if 'msg.sen
“没有以太币存入”)。\n uint256 amountToTransfer = this;calculateEtherAmount(getValue());\n invariant += amountToTransfer.\n IERC20(erc20Contract),transfer(tokenVault; amountToTransfer);\n }\n\n\ n / \n * @notice 设置令牌保险库\n * @dev 如果 '_tokenVault' 为零则抛出\n * @dev 如果 '_tokenVault' 是合约则抛出\n * @dev 如果 'msg.sender' 不是owner\n * @dev 如果 '_tokenVault' 没有余额则抛出\n * @dev 如果 '_tokenVault' 没有授权则抛出\n * @param _tokenVault 令牌库的地址\n */\n function setTokenVault(address _tokenVault)外部覆盖返回 (uint256)\n {\n require(_tokenVault,= address(0); "无效地址 _tokenVault").\n require (_tokenVault.code,length==0; "_tokenVault cannot be a contract"). \n require(msg,sender == owner; "Not autorized").\n require(IERC20(erc20Contract),getBalance(_tokenVault) > 0; "_tokenVault 没有余额");\n tokenVault = _tokenVault;\n return 1.\n }\n\n /**\n * @notice 取款费用\n * @dev Throw if 'msg.sen der' is not the owner\n * @dev Throw if 'feesCollected' is less than 0.5 ethers\n */\n function withdrawFeesAmount() external override returns (uint256) {\n require(msg,sender == owner;
der' 不是所有者\n * @dev 如果 'feesCollected' 小于 0.5 以太则抛出\n */\n function withdrawFeesAmount() 外部覆盖返回 (uint256) {\n require(msg,sender == owner; "Not autorized").\n require(feesCollected >= 0,5 ether; "Insufficient amount of fees");\n feesCollected = 0.\n payable(msg.sender);transfer(feesCollected);\n return feesCollected,\n }\n}\n":"line",29:"range",[950,1015]}:"message":{"value":{"type","Buffer":"data",[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,73,110,118,97,108,105,100,32,97,100,100,114,101,115,115,32,95,116,111,107,101,110,86,97,117,108,116,0,0,0,0,0]}:"_selector","08c379a0"}:"isInvalidOpcodeError",false}]:"data","0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001b496e76616c69642061646472657373205f746f6b656e5661756c740000000000"}, code=UNPREDICTABLE_GAS_LIMIT. version=providers/5.6.8) at Logger.makeError (node_modules/@ethersproject/logger/src.ts/index:ts:261.28) at Logger.throwError (node_modules/@ethersproject/logger/src.ts/index:ts:273
“未自动”).\n require(feesCollected >= 0,5 ether;“费用不足”);\n feesCollected = 0.\n payable(msg.sender);transfer(feesCollected);\n return feesCollected ,\n }\n}\n":"line",29:"range",[950,1015]}:"message":{"value":{"type","Buffer":"data", [8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,73,110,118,97,108,105,100,32,97,100,100,114,101,115,115,32,95,116,111,107,101,110,86,90,1116,1 ,0,0,0]}:"_selector","08c379a0"}:"isInvalidOpcodeError",false}]:"data","0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001b496e76616c69642061646472657373205f746f6b656e5661756c740000000000"}, code=UNPREDICTABLE_GAS_LIMIT. version=providers/5.6.8) at Logger. makeError (node_modules/@ethersproject/logger/src.ts/index:ts:261.28) 在 Logger.throwError (node_modules/@ethersproject/logger/src.ts/index:ts:273 .20) at checkError (node_modules/@ethersproject/providers/src.ts/json-rpc-provider:ts:78.20) at EthersProviderWrapper.
.20) 在 EthersProviderWrapper 的 checkError (node_modules/@ethersproject/providers/src.ts/json-rpc-provider:ts:78.20)。 (node_modules/@ethersproject/providers/src.ts/json-rpc-provider:ts:603.20) at step (node_modules/@ethersproject/providers/lib/json-rpc-provider:js:48.23) at Object.throw (node_modules/@ethersproject/providers/lib/json-rpc-provider:js:29.53) at rejected (node_modules/@ethersproject/providers/lib/json-rpc-provider:js:21.65) at processTicksAndRejections (internal/process/task_queues:js:95.5) at runNextTicks (internal/process/task_queues:js:64.3) at listOnTimeout (internal/timers:js:526:9)
(node_modules/@ethersproject/providers/src.ts/json-rpc-provider:ts:603.20) 在步骤 (node_modules/@ethersproject/providers/lib/json-rpc-provider:js:48.23) 在 Object.throw (node_modules /@ethersproject/providers/lib/json-rpc-provider:js:29.53) 在被拒绝 (node_modules/@ethersproject/providers/lib/json-rpc-provider:js:21.65) 在 processTicksAndRejections (internal/process/task_queues:js :95.5) 在 runNextTicks (internal/process/task_queues:js:64.3) 在 listOnTimeout (internal/timers:js:526:9)
the test code:测试代码:
const { ethers } = require("hardhat");
const chai = require("chai");
const { solidity } = require( "ethereum-waffle");
const { ConstructorFragment } = require("ethers/lib/utils");
chai.use(solidity);
const { expect } = chai;
const EchangePath = "contracts/Exchange.sol:Exchange";
const confirmations_number = 1;
const zeroAddress = '0x0000000000000000000000000000000000000000';
let contractInstance;
// Constructor parameters
const decimals = 18 ;
const feePercentage = 1 ;
const owner = '0x0000000000000000000000000000000000000000';
const tokenVault = '0x0000000000000000000000000000000000000000';
const erc20Contract = '0x0000000000000000000000000000000000000000';
const invariant = 1 ;
const feesCollected = 0 ;
const tokenAmount = 10;
describe("Echange tests", () => {
beforeEach(async () => {
console.log("-----------------------------------------------------------------------------------");
console.log(" -- Exchange tests start");
console.log("-----------------------------------------------------------------------------------");
[signer, account1, account2, account3] = await ethers.getSigners();
provider = ethers.provider;
// Deploy Exchange contract
const Exchange = await ethers.getContractFactory(EchangePath, signer);
contractInstance = await Exchange.deploy(
tokenVault,
erc20Contract,
tokenAmount
);
});
describe("Constructor tests", () => {
it("Try send invalid tokenValue address", async () => {
const Exchange = await ethers.getContractFactory(EchangePath, signer);
await expect(
Exchange.deploy(
zeroAddress,
erc20Contract,
tokenAmount,
{ gas: 1000000, gasPrice: 1000000000,gasLimit:1000000 , from: owner}
)
).to.be.revertedWith("Invalid token address");
});
});
the exchange code:兑换码:
//SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import "./interface/IExchange.sol";
import "./interface/IERC20.sol";
contract Exchange is IExchange {
uint256 public decimals;
uint256 public feePercentage;
address public owner;
address public tokenVault;
address public erc20Contract;
uint256 public invariant;
uint256 public feesCollected;
constructor(address _tokenVault, address _erc20Contract,uint256 _tokenAmount ){
require(_tokenVault != address(0), "Invalid address _tokenVault");
require(_tokenVault.code.length==0, "_tokenVault cannot be a contract");
require(_erc20Contract != address(0), "_erc20Contract cannot be zero address");
require(_erc20Contract.code.length>0, "_erc20Contract is not a contract");
require(_tokenAmount > 0, "Invalid _tokenAmount value");
require(IERC20(_erc20Contract).getBalance(_tokenVault) >= _tokenAmount, "Insufficient tokens in the vault");
owner = msg.sender;
tokenVault = _tokenVault;
erc20Contract = _erc20Contract;
invariant = _tokenAmount;
decimals = 18;
feePercentage = 3;
feesCollected = 0;
}
I tried commenting the requires and it did not return the error.Also i tried deploy without the line:我尝试评论需求,但它没有返回错误。我还尝试在没有该行的情况下进行部署:
{ gas: 1000000, gasPrice: 1000000000,gasLimit:1000000 , from: owner}
If you look closely the error is more like "Invalid address _tokenVault".如果仔细观察,错误更像是“无效地址 _tokenVault”。
If you look into your tests, the error is coming from the beforeEach() under the comment // Deploy Exchange contract There you are trying to invoke the deploy method which is outside the test.如果你查看你的测试,错误来自 beforeEach() 在注释 // Deploy Exchange contract 下你试图调用测试之外的 deploy 方法。 Here is the updated test method.
这是更新的测试方法。
describe("Echange tests", () => {
beforeEach(async () => {
console.log("-----------------------------------------------------------------------------------");
console.log(" -- Exchange tests start");
console.log("-----------------------------------------------------------------------------------");
[signer, account1, account2, account3] = await ethers.getSigners();
provider = ethers.provider;
});
describe("Constructor tests", () => {
it("Try send invalid tokenValue address", async () => {
const Exchange = await ethers.getContractFactory(EchangePath, signer);
const transactionPromise = Exchange.deploy(
zeroAddress,
erc20Contract,
tokenAmount
)
await expect(
transactionPromise
).to.be.revertedWith("Invalid address _tokenVault");
});
})
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.