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
Related
I'm running the following javascript file and using web3js to call a smart contract (0xF3885ca057a42B10b6cb432B816FE11426a2E369) on Goerli:
const Web3 = require("web3");
// Loading the contract ABI
// (the results of a previous compilation step)
const fs = require("fs");
const { abi } = JSON.parse(fs.readFileSync("EtherSplitter.json"));
async function main() {
// Configuring the connection to an Ethereum node
const network = process.env.ETHEREUM_NETWORK;
const web3 = new Web3(
new Web3.providers.HttpProvider(
`https://${network}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`
)
);
// Creating a signing account from a private key
const signer = web3.eth.accounts.privateKeyToAccount(
process.env.SIGNER_PRIVATE_KEY
);
web3.eth.accounts.wallet.add(signer);
// Creating a Contract instance
const contract = new web3.eth.Contract(
abi,
// Replace this with the address of your deployed contract
process.env.ETHERSPLITTER_CONTRACT
);
// Issuing a transaction that calls the splitEther method
const tx = contract.methods.splitEther(["0xdF8b511C3682b093736318A67Fcc2FEC6772D1a6","0x1E2eBeBB3348B1FeFC29239c20Df1c78668180Cc"]);
const receipt = await tx
.send({
from: signer.address,
value: 1e15, // IS THIS CORRECT? IF NOT, HOW DO I SPECIFY VALUE FOR SEND
gas: await tx.estimateGas(),
})
.once("transactionHash", (txhash) => {
console.log(`Mining transaction ...`);
console.log(`https://${network}.etherscan.io/tx/${txhash}`);
});
// The transaction is now on chain!
console.log(`Mined in block ${receipt.blockNumber}`);
}
require("dotenv").config();
main();
The smart contract is:
contract EtherSplitter {
function splitEther(address payable[] memory recipients) public payable {
uint fee = 10;
recipients[0].transfer(msg.value * fee / 100);
recipients[1].transfer(msg.value * (100 - fee) / 100);
}
receive() external payable {
}
}
Execution is reverting with the following error:
users/myusername/demo-eth-tx/node_modules/web3-core-helpers/lib/errors.js:28
var err = new Error('Returned error: ' + message);
I think I'm using send incorrectly, and incorrectly specifying the send value. How do I fix that?
Based on your code, seems like you mixed up some ether.js into your web3.js code coz in web3.js there when executing contract because in web3.js, function parameters doesn't need to be in an array like in ether.js
Try this
const tx = contract.methods.splitEther("0xdF8b511C3682b093736318A67Fcc2FEC6772D1a6","0x1E2eBeBB3348B1FeFC29239c20Df1c78668180Cc");
I created 2 smart contracts.
contract A is ERC20 token and B is a contract that accepts ERC20 A as payment method. When deploying, contract A got deployed but when I passed its proxy address to the initialize function in contract B for deployment it shows this error:
TypeError: Cannot create property 'kind' on string '0x814bd9012bD1e51b86890343b9731501875502e8'
what could be the problem?
hardhat deploy script
const token = await ethers.getContractFactory("Token");
console.log("Deploying token...");
const tokeninit= await upgrades.deployProxy(token , {
initializer: "initialize",
});
await tokeninit.deployed();
const tokenaddr = tokeninit.address;
console.log("token deployed at :", tokenaddr );
const SmartB= await ethers.getContractFactory("SmartB");
const SmartBInit= await upgrades.deployProxy(SmartB,tokenaddr, {
initializer: "initialize",
});
Smart contract B shorten code:
contract SamrtB is Initializable, UUPSUpgradeable, OwnableUpgradeable {
using CountersUpgradeable for CountersUpgradeable.Counter;
CountersUpgradeable.Counter private _tokenIdCounter;
IERC20Upgradeable public tokenAccepted;
constructor() initializer {}
function initialize(address _token) initializer public {
__Ownable_init();
__UUPSUpgradeable_init();
tokenAccepted =IERC20Upgradeable(_token);
}
I was passing the parameters in the next smart contract the wrong way, it should be
const SmartBInit= await upgrades.deployProxy(SmartB,[tokenaddr],{}
Instead of
const SmartBInit= await upgrades.deployProxy(SmartB,tokenaddr, {}
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.
I am practicing writing smart contracts in Solidity and running the code below results in
no such file or directory error.
Error: ENOENT: no such file or directory, open 'C:\kickstart\ethereum\build:Campaign.json'
This is a Kickstarter type contract with multiple participants and a manager(owner of the contract). Users are able to donate funds. The manager is the only one who is able to withdraw money, but other user`s permission is needed for that type of action.
**Campaign.sol**
pragma solidity ^0.4.20;
contract CampaignFactory {
address[] public deployedCampaigns;
function createCampaign(uint minimum) public {
address newCampaign = new Campaign(minimum, msg.sender);
deployedCampaigns.push(newCampaign);
}
function getDeployedCampaigns() public view returns(address []) {
return deployedCampaigns;
}
}
contract Campaign {
struct Request {
string description;
uint value;
address recipient;
bool complete;
uint approvalCount;
mapping(address => bool) approvals;
}
Request[] public requests;
address public manager;
uint public minimumContribution;
//address[] public approvers; mapping has a constant time lookup
mapping(address => bool) public approvers;
uint public approversCount;
modifier restricted() {
require(msg.sender == manager);
_;
}
constructor (uint minimum, address creator) public {
manager = creator;
minimumContribution = minimum;
}
function contribute() public payable {
require(msg.value > minimumContribution);
approvers[msg.sender] = true;
approversCount++;
}
function createRequest(string description, uint value, address recipient) public restricted {
Request memory newRequest = Request({
description: description,
value:value,
recipient: recipient,
complete: false,
approvalCount:0
});
requests.push(newRequest);
}
function approveRequest(uint index) public {
Request storage request = requests[index];
require (approvers [msg.sender]);
require(!request.approvals[msg.sender]);
request.approvals[msg.sender] = true;
request.approvalCount++;
}
function finalizeRequest(uint index) public restricted {
Request storage request = requests[index];
require(!request.complete);
request.complete = true;
}
}
**compile.js**
const path = require("path");
const solc = require("solc");
//file system on local compuiter
const fs = require("fs-extra");
const buildPath = path.resolve(__dirname, "build");
// file removal in fs-extra version
fs.removeSync(buildPath);
//path to the file
const campaignPath = path.resolve(__dirname, "contracts", "Campaign.sol");
//get a content of file
const source = fs.readFileSync(campaignPath, "utf8");
// output from the compiler
const output = solc.compile(source, 1).contracts;
for (let contract in output) {
fs.outputJsonSync(
path.resolve(buildPath, contract + ".json"),
output[contract]
);
}
Answering your question: Campain.json is located in the build folder and contains the output for all instances of Campaign contract.
I was able to fix the error by doing the following steps:
Completely deleting node_modules folder in the project
Running npm cache clean --force command
Running npm install
Please find the link to the project below:
https://github.com/StephenGrider/EthereumCasts
I ran across the same issue. The problem is that Windows is not happy with having special characters in the filename, in this case the colon ":" character.
As such remove the colon when you're outputting the result as follows:
for (let contract in output) {
fs.outputJSONSync(
path.resolve(buildPath, contract.replace(':', '') + ".json"),
output[contract]
);
}
If you want to make sure that your compile.js file is correctly configured add "console.log(solc.compile(source, 1));" before the for loop and check the output.
About this issue, you can replace:
path.resolve(buildPath, contract + '.json'),
with
path.resolve(buildPath, contract.replace(':', '') + '.json'),
Hope this helps !
If you have changed the filename, you need to migrate it.
npx truffle migrate --reset --compile-all
I had the same issue and that worked for me.
The code example is https://github.com/facuspagnuolo/ethereum-spiking/tree/master/5-token-sale-contract
The related files are:
1. contracts\MyToken.sol
contract MyToken is BasicToken, Ownable {
uint256 public constant INITIAL_SUPPLY = 10000;
function MyToken() {
totalSupply = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
Transfer(0x0, msg.sender, INITIAL_SUPPLY);
}
}
2. contracts\TokenSale.sol
contract TokenSale is Ownable {
MyToken public token;
uint256 public priceInWei;
bool public tokenSaleClosed;
event TokenPurchase(address buyer, address seller, uint256 price, uint256 amount);
function TokenSale(MyToken _token, uint256 _price) public {
if (_price < 0) return;
token = _token;
priceInWei = _price;
tokenSaleClosed = false;
}
}
3. migrations\2_deploy_contracts.js
const MyToken = artifacts.require("./MyToken.sol");
const TokenSale = artifacts.require("./TokenSale.sol");
module.exports = function(deployer) {
deployer.deploy(MyToken);
deployer.deploy(TokenSale);
};
when I deploy it by truffle and testrpc ($ truffle migrate), it fails as the following:
Using network 'development'.
Running migration: 2_deploy_contracts.js
Deploying MyToken...
... 0x289577d078c8fbc61585127ac123dbef43aa711529bf079c4fd400206c65e0de
MyToken: 0x33ddda65330e75e45d3d2e4e270457915883c2fc
Deploying TokenSale...
Error encountered, bailing. Network state unknown. Review successful transactions manually.
Error: TokenSale contract constructor expected 2 arguments, received 0
at C:\Users\zklin\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\truffle-contract\contract.js:390:1
at new Promise ()
at C:\Users\zklin\AppData\Roaming\npm\node_modules\truffle\build\webpack:\~\truffle-contract\contract.js:374:1
at
at process._tickCallback (internal/process/next_tick.js:188:7)
http://truffleframework.com/docs/getting_started/migrations#deployer
// Deploy A, then deploy B, passing in A's newly deployed address
deployer.deploy(A).then(function() {
return deployer.deploy(B, A.address);
});
Might work migrating only the second one so TokenSale and automatically it will be deployed MyToken.