How to deploy a UUPS proxy contract using ethers.js? - smartcontracts

I have erc721 uups proxy contract with initializer as :
function initialize(address owner) public initializer {
__ERC721_init("demo", "demo");
__ERC721URIStorage_init();
__Pausable_init();
__AccessControl_init();
__ERC721Burnable_init();
__UUPSUpgradeable_init();
_grantRole(DEFAULT_ADMIN_ROLE, owner);
_grantRole(PAUSER_ROLE, owner);
_grantRole(MINTER_ROLE, owner);
_grantRole(UPGRADER_ROLE, owner);
}
Now I am writing a test case for this contract using hardhat toolbox typescript version in a hardhat project.
In my testcase I first have to deploy this contract. My code for that is
const Demo = await ethers.getContractFactory("demo");
const demo = await upgrades.deployProxy(Demo, [owner.address], {
kind: "uups",
initializer: "initialize",
});
await demo.deployed();
The error I get in running this code is at that deployment code as :
Error: types/values length mismatch (count={"types":1,"values":0}, value={"types":[{"name":"owner","type":"address","indexed":null,"components":null,"arrayLength":null,"arrayChildren":null,"baseType":"address","_isParamType":true}],"values":[]}, code=INVALID_ARGUMENT, version=abi/5.7.0)

OpenZepplin Upgrades module uses autogenerated .openzepplin folder to store network related data. In my case, I had an empty folder of .openzepplin so I deleted that folder and upon running my tests again a new .openzepplin folder with new configurations was autogenerated.
Hence the upgrade.deployProxy function which was causing issues In my case was resolved.

Related

Get deployed contract by address

According to this doc. We can use ethers.getContract to get deployed contract.
I have deployed my contract at 0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2 and my creator address is 0x6e0F5B57FEdc8911722c92dcD5D7D0cf69ceA385 now to get contract i am doing
deployedContract = await ethers.getContract(
"0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2",
"0x6e0F5B57FEdc8911722c92dcD5D7D0cf69ceA385"
)
But its throwing error
Error: No Contract deployed with name 0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2
But you can see contract is deployed https://goerli.etherscan.io/address/0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2
Can someone help me here?
It's just simple.
You can use getContractAt function.
getContractAt: <T extends ethers.Contract>(
nameOrAbi: string | any[],
address: string,
signer?: ethers.Signer | string
) => Promise<T>;
So in your case, it could be:
const raffle = await ethers.getcontractAt(
"Raffle",
"0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2",
"0x6e0F5B57FEdc8911722c92dcD5D7D0cf69ceA385"
);
In addition, you got the error since you used the contract address for the contract name.
getContract: <T extends ethers.Contract>(
name: string,
signer?: ethers.Signer | string
) => Promise<T>;
The 0x33F4... contract is deployed on the Goerli testnet, and it's available only on this network. Your post doesn't state to which network is your ethers provider connected to, but based on the context I'm assuming it's a different network - for example the local emulated hardhat network (which is the default option if you don't specify any provider) or the Ethereum mainnet.
The getContract() function is present only in historic versions of the ethers package. Based on the documentation that you linked, it seems that you're using version 0.0.1 (and it seems that it's not a misconfiguration of the docs page, as the 0.0.1 version in fact exists). Current version (January 2023) of the package is 5.4 - you can find its docs at https://docs.ethers.io/v5/.
Second argument in the originally linked documentation is contractInterface. Which is not the deployer address (passed in your example) but an ABI (Application Binary Interface) - a JSON-formatted specification of public and external methods of the contract and its events. Example of such ABI JSON can be found in the original docs a below the Example headline.
Each contract usually has its own unique ABI that is generated from its source code during contract compilation, but you can also use generic ABI for standardized functions. For example all ERC-20 token contracts have the same functions required by the ERC-20 standard (and these functions are included in the generic ERC-20 ABI), plus they might implement some other functions on top of that (these custom functions are not in the generic ABI).
Here's an example of interacting with the contract with the current version (0.5.4) of ethers, connected to a Goerli network provider:
const { ethers } = require("ethers");
// A 3rd party provider that is connected to the Goerli network
const provider = new ethers.providers.JsonRpcProvider("https://goerli.infura.io/v3/<your_api_key>");
const CONTRACT_ADDRESS = "0x33F4623337b8F9EDc9529a79F0d68B2BeC98d5E2";
// ABI JSON of this specific contract, not included in the answer for readability
const CONTRACT_ABI = [/* ... */];
async function run() {
const myContract = new ethers.Contract(CONTRACT_ADDRESS, CONTRACT_ABI, provider);
// `getEntryFee()` function defined in the ABI JSON as well as in the actual contract
const entryFee = await myContract.getEntryFee();
console.log(entryFee.toString());
}
run();
Note: Above is a standalone NodeJS script that is not using the Hardhat framework. You can also add the network in your Hardhat config file, and then run a script from their scripts folder that automatically includes ethers and connects to the selected provider.
require("#nomicfoundation/hardhat-toolbox");
module.exports = {
solidity: "0.8.17",
networks: {
goerli: {
url: "https://goerli.infura.io/v3/<your_api_key>",
accounts: [<private_key>, <private_key>], // for sending transactions
}
}
};
npx hardhat run --network goerli scripts/myScript.js
Add this to hardhat.config.js
networks: {
goerli: {
url: `https://goerli.infura.io/v3/${process.env.INFURA_API_KEY}`,
accounts: [process.env.PRI_KEY],
},
},
create .env and add your env variables
// I am loading env variables
env $(cat .env) npx hardhat run --network goerli scripts/yourScriptFile.js

deploy solidity smart contract

I am learning Solidity.
I wrote solidity code using openzeppelin and compile it using solcjs.
It returns multiple bytecode for main.sol and imported other sol file.
should I deploy only bytecode for main.sol?
(main.sol bytecode contains other sol files bytecode?)
I am not a native english speaker, so please forgive me my weird english.
pragma solidity ^0.8.0;
import "./contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "./contracts/utils/Counters.sol";
import "./contracts/access/Ownable.sol";
contract Name is ERC721URIStorage,Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor() ERC721("Name", "name") {}
function mint(address nftowner)
public
onlyOwner
returns(uint256)
{
uint256 newItemId = _tokenIds.current();
_mint(nftowner, newItemId);
_setTokenURI(newItemId, "https://example.com");
_tokenIds.increment();
return newItemId;
}
}
On remix select the main contract with your logic to deploy. It will deploy all the dependencies as well.
Id suggest installing the etherscan plugin and making an account on their website to get an etherscan API_KEY to verify your contracts easily.
If you're not using framework like Hardhat or truffle then use remix injected web3 it's the easiest way to deploy
To deploy a smart contract, I recommend you use either Hardhat (if your familiar with JavaScript) or Foundry/Forge (which is in Solidity)
If you want to use Hardhat, you can create a deploy script like explained here in a JS file inside the scripts folder of your project:
const hardhat = require("hardhat");
async function main() {
const Contract = await hardhat.ethers.getContractFactory("YourContract");
const contract = await Contract.deploy();
await contract.deployed();
console.log(`Contract address: ${contract.address}`);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Then, you can run the script with this command:
npx hardhat run --network <your-network> scripts/deploy.js
And you can verify your contract on Etherscan with this command
npx hardhat verify --network <your-network> <contract-address>
Both commands require some configuration in the Hardhat config file. Check the article above or the documentation for more info!
Or check out this article if you prefer to use Foundry

Hardhat compile, deploy and verify in a single script

I am using hardhat to compile, deploy and verify an Ethereum Smart Contract. Currently, I am mannually peforming these commands:
npx hardhat compile
npx hardhat run scripts/deploy.js
Wait until the deployment script returns the contract address. Then manually copy the returned address to the verify command:
npx hardhat verify 0x<contract-address>
Copy the compiled contract json (abi) file to my project's directory in the filesystem.
Is there any way that I can run all these commands automatically? I am thinking to automate it using shell/bash/powershell scripting but I am not sure if this is the best way to achieve this.
Many thanks!
Just saw this so just posting my answer for future reference.
Running npx hardhat run scripts/deploy.js automatically compiles uncompiled code. So you don't need to run it every time.
For the Automation you mentioned (deploy + verify in one script) you can just add the below lines of code in your deploy.js script to automatically verify it after it deploys:
//wait for 5 block transactions to ensure deployment before verifying
await myContract.deployTransaction.wait(5);
//verify
await hre.run("verify:verify", {
address: myContract.address,
contract: "contracts/MyContract.sol:MyContract", //Filename.sol:ClassName
constructorArguments: [arg1, arg2, arg3],
});
Now you can just call your usual deploy command npx hardhat run scripts/deploy.js and the terminal will log the deployment + the verification like:
MyContract deployed to "0xTheDeployedContractAddress" constructor arguments: arg1, arg2, arg3
Nothing to compile
Successfully submitted source code for contract
contracts/MyContract.sol:Contrac at 0xTheDeployedContractAddress
for verification on the block explorer. Waiting for verification result...
Successfully verified contract HoloVCore on Etherscan.
https://goerli.etherscan.io/address/0xTheDeployedContractAddress#code
Here's a sample of my overall deploy.js script
const hre = require("hardhat");
async function main() {
const arg1 = "Contract Name";
const arg2 = "TKN";
const arg3 = 100000;
const MyContract = await hre.ethers.getContractFactory("MyContract");
const myContract = await MyContract.deploy(arg1, arg2, arg3);
await myContract.deployed();
console.log(`VLX Token deployed to ${myContract.address}`);
//wait for 5 block transactions to ensure deployment before verifying
await myContract.deployTransaction.wait(5);
//verify (source: https://hardhat.org/hardhat-runner/plugins/nomiclabs-hardhat-etherscan#using-programmatically)
await hre.run("verify:verify", {
address: myContract.address,
contract: "contracts/MyContract.sol:MyContract", //Filename.sol:ClassName
constructorArguments: [arg1, arg2, arg3],
});
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Remember to adjust the wait(n) parameter to adjust the wait time depending on the traffic on the network you're deploying to.
For more info about programatically verifying, check this link from Hardhat-Etherscan docs
You can also create a folder called utils and import it into your deploy folder in a much more organized manner.
const { run } = require("hardhat")
const verify = async (contractAddress, args) => {
console.log("Verifying contract...")
try {
await run("verify:verify", {
address: contractAddress,
constructorArguments: args,
})
} catch (e) {
if (e.message.toLowerCase().includes("already verified")) {
console.log("Already verified!")
} else {
console.log(e)
}
}
}
module.exports = {
verify,
}

How to deploy a pre-compiled contract to hardhat node

I have a proxy contract and would like to replace the underlying implementation contract.
I already have the abi & bytecode of a smart contract(retrieved from artifacts folder), so here is what I did:
const NFTv2 = await ethers.getContractFactory(upgradedContract.abi, upgradedContract.bytecode);
contract = await upgrades.upgradeProxy(proxyContract.address, NFTv2);
It works fine, but I don't want the contract to exist in my contracts folder, so I've deleted it and run npx hardhat compile again.
Now when I try to run this deploy script again, hardhat keep throwing this error:
Error: The requested contract was not found. Make sure the source code is available for compilation
at getContractNameAndRunValidation (node_modules/#openzeppelin/upgrades-core/src/validate/query.ts:46:11)
at Object.getStorageLayout (node_modules/#openzeppelin/upgrades-core/src/validate/query.ts:54:41)
at Object.deployImpl (node_modules/#openzeppelin/hardhat-upgrades/src/utils/deploy-impl.ts:30:18)
at Proxy.upgradeProxy (node_modules/#openzeppelin/hardhat-upgrades/src/upgrade-proxy.ts:36:22)
After some try & error, it seems to be related to the cache folder, once the related metadata inside the cache folder disappeared, then this error will pop out, otherwise no.
Can someone guide me on this problem and how can I deploy contract with only abi & bytecode without leaving the contract inside the contracts folder?
Thank you! :)
Here's the code of my upgraded contract:
// SPDX-License-Identifier: Apache2.0
pragma solidity ^0.8.4;
import "#openzeppelin/contracts-upgradeable/token/ERC1155/presets/ERC1155PresetMinterPauserUpgradeable.sol";
contract Test is ERC1155PresetMinterPauserUpgradeable {
string private _uri;
event upgradeEvent(string);
function uri(uint256) public view virtual override returns (string memory) {
return string(abi.encodePacked(_uri, "/new"));
}
function seturi(string memory uri) public {
emit upgradeEvent("this is an upgraded contract");
_uri = uri;
}
}
I stumbled upon this question because I struggled with the same issue, but here is what I did in the end. Basic idea is to ignore the API extensions provided by Hardhat and use Ethers.js directly.
const allSigners = await hre.ethers.getSigners();
const deployingSigner = allSigners[0];
const factory = new ContractFactory(artifact.abi, artifact.bytecode, deployingSigner);
const contract = await factory.deploy(); // no args
await contract.deployed();
console.log("Contract deployed to: ", contract.address);

Cannot able to call the contract inside the truffle console

I am new to the truffle framework. I have initialised my contract Dapp with the constructor function as given below
pragma solidity ^0.5.0;
contract Dapp {
uint public totalSupply;
constructor() public {
totalSupply = 1000000;
}
}
and my migrations file in regards with the contract is
const Dapp = artifacts.require("Dapp");
module.exports = function(deployer) {
deployer.deploy(Dapp);
};
I have compiled and migrated using the command truffle compile and truffle migrate, which results in successful compilation.
But when accessing the contract in truffle console like
let instance = await Dapp.deployed()
It results in ReferenceError: Dapp is not defined, I cannot able to figure out what went wrong. Is there any possible solution to this. And yeah I have followed the latest Truffle documentation. And also, I have followed the solution been presented in this platform.
Documentation link for migration and interacting with truffle console.