Need help. I got the following error:
Error: VM Exception while processing transaction: reverted with reason string 'multi call failed'
at RoleMultiCall.multiCall (contracts/optional/RoleMultiCall.sol:21)
at async HardhatNode._mineBlockWithPendingTxs (/Users/azlan/projects/hardhats/dao-mix/node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:1772:23)
at async HardhatNode.mineBlock (/Users/azlan/projects/hardhats/dao-mix/node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:466:16)
at async EthModule._sendTransactionAndReturnHash (/Users/azlan/projects/hardhats/dao-mix/node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:1496:18)
at async HardhatNetworkProvider.request (/Users/azlan/projects/hardhats/dao-mix/node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:118:18)
at async EthersProviderWrapper.send (/Users/azlan/projects/hardhats/dao-mix/node_modules/#nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)
when execute the following codes in a Hardhat task:
const targets = [timeLockContract.address, timeLockContract.address];
const encodedFunctions = [
await timeLockContract.getDataGrantProposerRole(governorContract.address),
await timeLockContract.getDataGrantExecutorRole(governorContract.address),
];
const multiCallResult = await roleMultiCall.multiCall(
targets,
encodedFunctions,
);
multi call contract :
contract RoleMultiCall {
function multiCall(
address[] calldata targets,
bytes[] calldata encodedFunctions
) external returns (bytes[] memory) {
...
for (uint256 i; i < targets.length; i++) {
(bool success, bytes memory result) = address(targets[i]).call(
encodedFunctions[i]
);
require(success, 'multi call failed');
results[i] = result;
}
return results;
}
}
contract that uses abi.encodeWithSelector:
contract GovernanceTimeLock is TimelockController {
...
function getDataGrantProposerRole(address account)
external
view
returns (bytes memory)
{
return
abi.encodeWithSelector(
this.grantRole.selector,
this.PROPOSER_ROLE,
account
);
}
function getDataGrantExecutorRole(address account) external view
returns (bytes memory)
{
//similar to function above
}
Its all here https://github.com/azizazlan/dao-mix/tree/feature/multi-call-roles
Ok. the RoleMultiCall contract must be granted the TIMELOCK_ADMIN_ROLE role.
So in the Hardhat task:
...
await timeLockContract.grant(
await timeLockContract.TIMELOCK_ADMIN_ROLE(),
roleMultiCall.address);
const multiCallResult = await roleMultiCall.multiCall(
targets,
encodedFunctions,
);
Related
I'm trying to verify and submit my contract source code to etherscan using a headset, but I'm getting the following error and I don't understand how to solve it. I've read through the code and can't figure out what I'm doing wrong. Please can anyone advise?
The error that I am getting when I run:
NomicLabsHardhatPluginError: The constructor for contracts/FundMe.sol:FundMe has 1 parameters
but 0 arguments were provided instead.
heres all the code FundMe.sol code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "./PriceConverter.sol";
error NotOwner();
contract FundMe {
using PriceConverter for uint256;
mapping(address => uint256) public addressToAmountFunded;
address[] public funders;
address public /* immutable */ i_owner;
uint256 public constant MINIMUM_USD = 50 * 10 ** 18;
AggregatorV3Interface public priceFeed;
constructor(address priceFeedAddress) {
i_owner = msg.sender;
priceFeed = AggregatorV3Interface(priceFeedAddress);
}
function fund() public payable {
require(msg.value.getConversionRate(priceFeed) >= MINIMUM_USD, "You need to spend more ETH!");
addressToAmountFunded[msg.sender] += msg.value;
funders.push(msg.sender);
}
modifier onlyOwner {
if (msg.sender != i_owner) revert NotOwner();
_;
}
function withdraw() payable onlyOwner public {
for (uint256 funderIndex=0; funderIndex < funders.length; funderIndex++){
address funder = funders[funderIndex];
addressToAmountFunded[funder] = 0;
}
funders = new address[](0);
(bool callSuccess, ) = payable(msg.sender).call{value: address(this).balance}("");
require(callSuccess, "Call failed");
}
fallback() external payable {
fund();
}
receive() external payable {
fund();
}
}
and also the 01-deploy-fund-me.js to see the code of verify
const { getNamedAccounts, deployments, network } = require("hardhat")
const { networkConfig, developmentChains } = require("../helper-hardhat-config")
const { verify } = require("../utils/verify")
module.exports = async ({ getNamedAccounts, deployments }) => {
const { deploy, log } = deployments
const { deployer } = await getNamedAccounts()
const chainId = network.config.chainId
let ethUsdPriceFeedAddress
if (chainId == 31337) {
const ethUsdAggregator = await deployments.get("MockV3Aggregator")
ethUsdPriceFeedAddress = ethUsdAggregator.address
} else {
ethUsdPriceFeedAddress = networkConfig[chainId]["ethUsdPriceFeed"]
}
log("----------------------------------------------------")
log("Deploying FundMe and waiting for confirmations...")
const fundMe = await deploy("FundMe", {
from: deployer,
args: [ethUsdPriceFeedAddress],
log: true,
// we need to wait if on a live network so we can verify properly
waitConfirmations: network.config.blockConfirmations || 1,
})
//log("----------------------------------------------------")
log(`FundMe deployed at ${fundMe.address}`)
if (
!developmentChains.includes(network.name) &&
process.env.ETHERSCAN_API_KEY
) {
await verify(fundMe.address, [ethUsdPriceFeedAddress])
}
log("----------------------------------------------------")
}
module.exports.tags = ["all", "fundme"]
Please help me!
I am new to crypto and just exploring Solidity language. I try to make a simple Solidify token contract with some basic functionality. It should transfer the token and update the balance. However when I run the test that supposed to try add to balance functionality, I get this error:
npx hardhat test
No need to generate any newer typings.
MyERC20Contract
when I transfer 10 tokens
1) sould transfer tokens correctly
0 passing (728ms)
1 failing
1) MyERC20Contract
when I transfer 10 tokens
sould transfer tokens correctly:
Error: VM Exception while processing transaction: reverted with reason string 'ERC20: transfer amount exceeds balance'
at ERC20._transfer (contracts/ERC20.sol:49)
at ERC20.transfer (contracts/ERC20.sol:25)
at async HardhatNode._mineBlockWithPendingTxs (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:1773:23)
at async HardhatNode.mineBlock (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:466:16)
at async EthModule._sendTransactionAndReturnHash (node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:1504:18)
at async HardhatNetworkProvider.request (node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:118:18)
at async EthersProviderWrapper.send (node_modules/#nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)
Do I make some mistake I'm not aware of?
My test file:
import { SignerWithAddress } from "#nomiclabs/hardhat-ethers/signers";
import { expect } from "chai";
import { ethers } from "hardhat";
import { ERC20 } from "../typechain";
describe("MyERC20Contract", function() {
let MyERC20Contract: ERC20;
let someAddress: SignerWithAddress;
let someOtherAddress: SignerWithAddress;
beforeEach(async function() {
const ERC20ContractFactory = await ethers.getContractFactory("ERC20");
MyERC20Contract = await ERC20ContractFactory.deploy("Hello","SYM");
await MyERC20Contract.deployed();
someAddress = (await ethers.getSigners())[1];
someOtherAddress = (await ethers.getSigners())[2];
});
describe("When I have 10 tokens", function() {
beforeEach(async function() {
await MyERC20Contract.transfer(someAddress.address, 10);
});
});
describe("when I transfer 10 tokens", function() {
it("sould transfer tokens correctly", async function() {
await MyERC20Contract
.connect(someAddress)
.transfer(someOtherAddress.address, 10);
expect(
await MyERC20Contract.balanceOf(someOtherAddress.address)
).to.equal(10);
});
});
});
Mys .sol contract:
//SPDX-License-Identifier: Unlicense: MIT
pragma solidity ^0.8.0;
contract ERC20 {
uint256 public totalSupply;
string public name;
string public symbol;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) public allowance;
constructor(string memory name_, string memory symbol_) {
name = name_;
symbol = symbol_;
_mint(msg.sender, 100e18);
}
function decimals() external pure returns (uint8) {
return 18;
}
function transfer(address recipient, uint256 amount) external returns (bool) {
return _transfer(msg.sender, recipient, amount);
}
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool) {
uint256 currentAllowance = allowance[sender][msg.sender];
require(currentAllowance >= amount, "ERC20: Transfer amount exceeds allowance" ) ;
allowance[sender][msg.sender] = currentAllowance - amount;
return _transfer(sender, recipient, amount);
}
function approve(address spender, uint256 amount) external returns (bool) {
allowance[msg.sender][spender] = amount;
return true;
}
function _transfer(address sender, address recipient, uint256 amount) private returns (bool) {
require(recipient != address(0), "ERC20: transfer to zero address");
uint256 senderBalance = balanceOf[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
balanceOf[sender] = senderBalance - amount;
balanceOf[recipient] += amount;
return true;
}
function _mint(address to, uint256 amount) internal {
require(recipient != address(0), "ERC20: transfer to zero address");
totalSupply += amount;
balanceOf[to] +=amount;
}
}
MyERC20Contract = await ERC20ContractFactory.deploy("Hello","SYM");
Since your snippet doesn't specify from which address is the deploying tranaction, the contract is deployed from the first address (index 0).
The 0th address receives the tokens from the constructor, other addresses don't have any tokens.
constructor(string memory name_, string memory symbol_) {
name = name_;
symbol = symbol_;
_mint(msg.sender, 100e18);
}
But then your snippet tries to send tokens from the 2nd address (index 1).
someAddress = (await ethers.getSigners())[1];
it("sould transfer tokens correctly", async function() {
await MyERC20Contract
.connect(someAddress)
.transfer(someOtherAddress.address, 10);
Because the someAddress does not own any tokens, the transaction fails.
Solution: Either fund the someAddress in your Solidity code as well, or send the tokens from the deployer address (currently the only address that has non-zero token balance).
Edit:
There is a beforeEach() in your When I have 10 tokens block, but that's applied only to this specific block - not to the when I transfer 10 tokens block that performs the failed transfer.
So another solution is to move this specific beforeEach() to the when I transfer block but, based on the context, it doesn't seem like a very clean approach. A good practice is to have as few as possible test cases not affecting each other.
I use hardhat to test a solidity contract but I get a different result with functions:
getUserBalance (contract function)
balanceOf
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/utils/Counters.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/utils/math/SafeMath.sol";
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "hardhat/console.sol";
contract TestContract is ERC721Enumerable, Ownable {
using SafeMath for uint;
...
function getContractBalance() public view onlyOwner returns (uint) {
return address(this).balance;
}
function getUserBalance(address _owner) external view returns (uint) {
return address(_owner).balance;
}
}
test.js
...
beforeEach(async function () {
Token = await ethers.getContractFactory("TestContract");
[owner, addr1, addr2, ...addrs] = await ethers.getSigners();
hardhatToken = await Token.deploy("test");
});
it("First test", async function () {
let total = await hardhatToken.totalSupply() // BigNumber { value: "0" }
let userBalance2 = await hardhatToken.getUserBalance(owner.address) // BigNumber { value: "9999979080649422213031" }
let userBalance = await hardhatToken.balanceOf(owner.address) // BigNumber { value: "0" }
let cBalance = await hardhatToken.getContractBalance() // BigNumber { value: "0" }
})
I think it's because a different unity (ether -> wei) but I don't know why. Can you explain me ?
Thank you
This function returns the amount of eth of the _owner.
function getUserBalance(address _owner) external view returns (uint) {
return address(_owner).balance;
}
This function returns the amount of the eth that the contract own.
function getContractBalance() public view onlyOwner returns (uint) {
return address(this).balance;
}
This function returns the amount of TOKEN that the owner has:
balanceOf(owner.address)
I'm working to deploy an ERC777 token using hardhat, ethers in typescript. My deployment script is as follows
import { MarketSvc, ProductSvc } from '../libs/deployment-service/src';
import hre from 'hardhat';
async function main() {
const marketAddress = await MarketSvc.deployContract(contractType);
const productAddress = await ProductSvc.deployContract(contractType, marketAddress);
}
my execution function looks like this
async deployContract(
contractType: ContractType,
...args: any[]
): Promise<string> {
const contractFactory = await hre.ethers.getContractFactory(contractType);
const contract =
args === undefined
? await contractFactory.deploy()
: await contractFactory.deploy(...args);
await contract.deployed();
console.log(contractType + ' Contract deployed to:', contract.address);
return contract.address;
}
The first deployment succeeds. The second deployment fails with and error of
MarketContract Contract deployed to: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
ProviderError: Error: Transaction reverted: function call to a non-contract account
at HttpProvider.request (C:\src\trae\gbc\exchange\exchange_ui\node_modules\hardhat\src\internal\core\providers\http.ts:49:19)
at GanacheGasMultiplierProvider.request (C:\src\trae\gbc\exchange\exchange_ui\node_modules\hardhat\src\internal\core\providers\gas-providers.ts:312:34)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
In the ERC777 contract it is failing in the method below (#openzeppelin\contracts\token\ERC777\ERC777.sol:75)
/**
* #dev `defaultOperators` may be an empty array.
*/
constructor(
string memory name_,
string memory symbol_,
address[] memory defaultOperators_
) {
_name = name_;
_symbol = symbol_;
_defaultOperatorsArray = defaultOperators_;
for (uint256 i = 0; i < defaultOperators_.length; i++) {
_defaultOperators[defaultOperators_[i]] = true;
}
console.log("added operators");
// register interfaces - It is failing here
_ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this));
console.log("registered ERC777");
_ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC20Token"), address(this));
}
the constructor to my contract is this
constructor(address defaultOperator)
ERC777("SOMEtoken", "TKN", _defaultOps(defaultOperator)) {
console.log(defaultOperator);
_mint(_msgSender(), 1000000, "Initial Mint", "defaultOps");
}
my solidity log is
Error: Transaction reverted: function call to a non-contract account
at GParticle.constructor (#openzeppelin/contracts/token/ERC777/ERC777.sol:75)
at EthModule._estimateGasAction (C:\src\trae\gbc\exchange\exchange_ui\node_modules\hardhat\src\internal\hardhat-network\provider\modules\eth.ts:425:7)
at HardhatNetworkProvider._sendWithLogging (C:\src\trae\gbc\exchange\exchange_ui\node_modules\hardhat\src\internal\hardhat-network\provider\provider.ts:138:22)
at HardhatNetworkProvider.request (C:\src\trae\gbc\exchange\exchange_ui\node_modules\hardhat\src\internal\hardhat-network\provider\provider.ts:115:18)
at JsonRpcHandler._handleRequest (C:\src\trae\gbc\exchange\exchange_ui\node_modules\hardhat\src\internal\hardhat-network\jsonrpc\handler.ts:188:20)
at JsonRpcHandler._handleSingleRequest (C:\src\trae\gbc\exchange\exchange_ui\node_modules\hardhat\src\internal\hardhat-network\jsonrpc\handler.ts:167:17)
at Server.JsonRpcHandler.handleHttp (C:\src\trae\gbc\exchange\exchange_ui\node_modules\hardhat\src\internal\hardhat-network\jsonrpc\handler.ts:52:21)
the operator address I'm giving it, is defiantly deployed and is a contract. but so I'm a bit baffled about what could possibly be happening in the 777 contract specifically. I have a ERC20 and 1155 that deploy perfectly...
If anyone has any insight, all information is appreciated.
The root of the issue is that if you're working on a localnet, like hardhat... you will have to deploy your own ERC1820_REGISTRY, because it does not exist.
openzepplin has some utilites you can use to enable this pretty simply..
const { singletons } = require('#openzeppelin/test-helpers');
require('#openzeppelin/test-helpers/configure')
async function main() {
const signers = await hre.ethers.getSigners();
const address = signers[0].address;
const erc1820 = await singletons.ERC1820Registry(address);
... deploy your ERC777
}
I implemented a full deployment of ERC1820 & ERC777,
my code checks if it's not deployed, deploys it, and then deploys the ERC777 and registers the recipient,
It's implemented with hardhat and I put the guide in the readme.md
This is my repo :
https://github.com/EhsanParsania/ERC777
I am trying to verify my contract with arguments and I am getting this error:
Error in plugin #nomiclabs/hardhat-etherscan: The contract verification failed.
Reason: Fail - Unable to verify
I am also importing Open Zeppelin contracts ERC721Enumerable and Ownable.
Here's my NFTCollectible.sol
pragma solidity 0.8.10;
import "#openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "hardhat/console.sol";
contract NFTCollectible is ERC721Enumerable, Ownable {
using Strings for uint256;
string public baseURI;
string public baseExtension = ".json";
uint256 public cost = 0.08 ether;
uint256 public maxSupply = 5000;
uint256 public maxMintAmount = 25;
mapping(address => uint256) public addressMintedBalance;
constructor(
string memory _name,
string memory _symbol,
string memory _initBaseURI,
string memory _initNotRevealedUri
) ERC721(_name, _symbol) {
setBaseURI(_initBaseURI);
setNotRevealedURI(_initNotRevealedUri);
}
function _baseURI() internal view virtual override returns (string memory) {
return baseURI;
}
function mint(uint256 _mintAmount) public payable {
require(!paused, "the contract is paused");
uint256 supply = totalSupply();
require(_mintAmount > 0, "need to mint at least 1 NFT");
}
function walletOfOwner(address _owner)
public
view
returns (uint256[] memory)
{
uint256 ownerTokenCount = balanceOf(_owner);
uint256[] memory tokenIds = new uint256[](ownerTokenCount);
for (uint256 i; i < ownerTokenCount; i++) {
tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
}
return tokenIds;
}
function tokenURI(uint256 tokenId)
public
view
virtual
override
returns (string memory)
{
require(
_exists(tokenId),
"ERC721Metadata: URI query for nonexistent token"
);
string memory currentBaseURI = _baseURI();
return
bytes(currentBaseURI).length > 0
? string(
abi.encodePacked(
currentBaseURI,
tokenId.toString(),
baseExtension
)
)
: "";
}
function setCost(uint256 _newCost) public onlyOwner {
cost = _newCost;
}
function setBaseURI(string memory _newBaseURI) public onlyOwner {
baseURI = _newBaseURI;
}
function setBaseExtension(string memory _newBaseExtension)
public
onlyOwner
{
baseExtension = _newBaseExtension;
}
function withdraw() public payable onlyOwner {
(bool me, ) = payable(owner())
.call{value: address(this).balance}("");
require(me);
}
}
Here's my deploy.js
const main = async () => {
const nftContractFactory = await hre.ethers.getContractFactory('NFTCollectible');
const nftContract = await nftContractFactory.deploy(
"NFTCollectible",
"NFTC",
"ipfs://CID",
"https://www.example.com"
);
await nftContract.deployed();
console.log("Contract deployed to:", nftContract.address);
};
const runMain = async () => {
try {
await main();
process.exit(0);
} catch (error) {
console.log(error);
process.exit(1);
}
};
runMain();
Here's my hardhat.config
require('#nomiclabs/hardhat-waffle');
require('#nomiclabs/hardhat-etherscan');
require('dotenv').config();
module.exports = {
solidity: '0.8.10',
networks: {
rinkeby: {
url: process.env.STAGING_ALCHEMY_KEY,
accounts: [process.env.PRIVATE_KEY],
},
mainnet: {
chainId: 1,
url: process.env.PROD_ALCHEMY_KEY,
accounts: [process.env.PRIVATE_KEY],
gasPrice: 3000000
},
},
etherscan: {
apiKey: process.env.ETHERSCAN_KEY
}
};
I realize Hardhat does not support 0.8.10+ compiler version, but no other versions work either. Same error.
You need to pass in the constructor into the command line.
hh verify --network mainnet DEPLOYED_CONTRACT_ADDRESS "Constructor argument 1"
Here's the documentation.
https://hardhat.org/plugins/nomiclabs-hardhat-etherscan.html
You have this error because you are not using the same arguments that you used during the deployment, be sure to use the same arguments at deployment as at verification
What worked for me is changing:
etherscan: {
apiKey: process.env.ETHERSCAN_KEY
}
to:
etherscan: {
apiKey: {
rinkeby:"ETHERSCAN API KEY HERE",
}
}
SOLVED
This isn't really an answer, but my solve was to use both Remix and Hardhat, the latter via VSCode. Basically, deploy via Remix and verify through Hardhat.
Because I'm using libraries, I need to verify every file, obviously. The degen way of pasting every Open Zeppelin file...I don't recommend it. I tried and still got it wrong.
Suspicion: I was not creating a transaction in my deploy script, which is weird because my params seem correct. In any event...
My issue is resolved by simply adding my own proxy config in the "hardhat.config.js" file:
// set proxy
const { ProxyAgent, setGlobalDispatcher } = require("undici");
const proxyAgent = new ProxyAgent('http://127.0.0.1:7890'); // change to yours
setGlobalDispatcher(proxyAgent);
I got success finally:
I just used the docs here and using the npx hardhat --network xxxx verify xxxx worked for me. One more thing is be patient maybe you need to execute this after a few block since the Smart contract deployment.