How to calculate a smart contract deployment price on RSK? - solidity

Say I have an ERC20 smart contract which I'm developing and testing in Hardhat:
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
contract Erc20Token is ERC20, Ownable {
constructor(uint initialSupply) ERC20("ERC20 Token", "ETK") {
ERC20._mint(msg.sender, initialSupply);
}
}
I intend to deploy it to the RSK network with the following Hardhat deploy.js script:
async function deploy() {
try {
const initialSupply = 1e6;
const ERC20TokenFactory = await ethers.getContractFactory('Erc20Token');
const erc20Token = await ERC20TokenFactory.deploy(initialSupply);
await erc20Token.deployed();
console.log(
`ERC20 Token was deployed on ${hre.network.name} with an address: ${erc20Token.address} `,
);
process.exit(0);
} catch (error) {
console.error(error);
process.exit(1);
}
}
deploy();
To run this script and deploy my smart contract on RSK mainnet I need to run the following command in terminal:
npx hardhat run scripts/deploy.js --network rskmainnet
However, before deploying the smart contract on a real blockchain, I would really like to know how much this deployment will cost (in EUR)! How to calculate the price of my smart contract deployment transaction on the RSK mainnet, priced in fiat?
For reference, this is the hardhat.config.js file I'm using:
require('#nomiclabs/hardhat-waffle');
const { mnemonic } = require('./.secret.json');
module.exports = {
solidity: '0.8.4',
defaultNetwork: 'rsktestnet',
networks: {
rsktestnet: {
chainId: 31,
url: 'https://public-node.testnet.rsk.co/',
accounts: {
mnemonic,
path: "m/44'/60'/0'/0",
},
},
rskmainnet: {
chainId: 30,
url: 'https://public-node.rsk.co',
accounts: {
mnemonic,
path: "m/44'/60'/0'/0",
},
},
},
};

First you need to estimate the amount of gas which your deploy transaction is going to use. To accomplish this, use ethers.js signer.estimateGas() method.
const deployTx = ERC20TokenFactory.getDeployTransaction(initialSupply);
const estimatedGas = await ERC20TokenFactory.signer.estimateGas(deployTx);
Then you need to know the current gas price in your network:
const gasPrice = await ERC20TokenFactory.signer.getGasPrice();
To get the deployment RBTC price,
multiply gas amount by the gas price:
const deploymentPriceWei = gasPrice.mul(estimatedGas);
const deploymentPriceRBTC =
ethers.utils.formatEther(deploymentPriceWei);
Next you can use the Coingecko API to get current RBTC/EUR rate:
const rbtcEurRate = (
await axios.get('https://api.coingecko.com/api/v3/coins/rootstock')
).data.market_data.current_price.eur;
(Note that CoinGecko uses rootstock to denote the native currency of the RSK network, RBTC.)
And finally, to get the deployment price in EUR, multiply the deployment RBTC price by RBTC/EUR exchange rate:
const deploymentPriceEUR = (deploymentPriceRBTC * rbtcEurRate).toFixed(2);
We can make all of the above repeatable by creating a
hardhat script that combines the above.
To do this create scripts/estimateDeploymentPrice.js,
with the following:
const axios = require('axios').default;
async function estimateDeploymentPrice() {
try {
const initialSupply = 1e6;
const contractFactory = await ethers.getContractFactory('Erc20Token');
const deployTx = contractFactory.getDeployTransaction(initialSupply);
const estimatedGas = await contractFactory.signer.estimateGas(deployTx);
const gasPrice = await contractFactory.signer.getGasPrice();
const deploymentPriceWei = gasPrice.mul(estimatedGas);
const deploymentPriceRBTC = ethers.utils.formatEther(deploymentPriceWei);
const rbtcEurRate = (
await axios.get('https://api.coingecko.com/api/v3/coins/rootstock')
).data.market_data.current_price.eur;
const deploymentPriceEUR = (deploymentPriceRBTC * rbtcEurRate).toFixed(2);
console.log(
`ERC20 token deployment price on ${hre.network.name} is ${deploymentPriceEUR} EUR`,
);
process.exit(0);
} catch (error) {
console.error(error);
process.exit(1);
}
}
estimateDeploymentPrice();
Run the script with a command:
npx hardhat run scripts/estimateDeploymentPrice.js --network rskmainnet
(Note that the script needs to be run through hardhat
in order for hre to be injected.)
The script outputs:
ERC20 token deployment price on rskmainnet is 3.34 EUR

Related

Filecoin EVM : What is the possible solution to the error with code 1 when trying to look up actor state nonce on the Hyperspace network?

import '#ethersproject/shims';
import 'text-encoding';
import { ethers } from 'ethers';
import { Buffer } from 'buffer';
const fa = require("#glif/filecoin-address");
import { DAPP_CONTRACT } from "#env"
const networkInfo = {
defaultNetwork: "hyperspace",
networks: {
hyperspace: {
chainId: 3141,
url: "https://api.hyperspace.node.glif.io/rpc/v1",
},
},
}
const MintTokens = async (key, amount) => {
try {
let cleanKey = key.replace(/["]/g, "");
let provider = new ethers.providers.JsonRpcProvider(FevmProviderUrl, networkInfo.networks.hyperspace);
const wallet = new ethers.Wallet(cleanKey, provider);
const signer = wallet.connect(provider);
const f4ContractAddress = fa.newDelegatedEthAddress(DAPP_CONTRACT).toString();
const f4WalletAddress = fa.newDelegatedEthAddress(wallet.address).toString();
const f4ActorAddress = fa.newActorAddress(wallet.address).toString();
console.log("Ethereum Contract address in .env (this address should work for most tools):", DAPP_CONTRACT);
console.log("f4address Contract (also known as t4 address on testnets):", f4ContractAddress);
console.log("f4address Actor (also known as t4 address on testnets):", f4ActorAddress);
console.log("f4address Wallet (also known as t4 address on testnets):", f4WalletAddress);
console.log("Provider:", provider);
console.log("Eth Wallet:", wallet);
console.log("Minting FitMint");
const FitMints = new ethers.Contract(DAPP_CONTRACT, ContractABI.abi, signer)
console.log("Contract:", FitMints)
// //Call the mint method
let result = await FitMints.mint(wallet.address, amount, { gasLimit: 30000 })
if(result) {
console.log("Minting Token:", result)
return result
} else {
return {"result": result.toString()}
}
} catch (error) {
console.log(error)
return error
}
}
export default {
MintTokens,
};
Output of mint token:
[Error: processing response error (bod
c":"2.0","id":50,"error":{"code":1,
"failed to look up actor state nonce: resol
failed (t410fzzzo2dimmzy63d4vgxvfak6wvxdhcr
resolve address t410fzzzo2dimmzy63d4vgxvfak6
j3vy: actor not found: validation failure"}
{"code":1}, requestBody="{"method":"eth_s
ction","params":["0x02f8b1820c4580845968c6aa9ae8453d4e311f6749ae0c80b84440c10f1900008f9535ea502bd6adc671469c0000000000000000000000000001c001a00a9df20582d715909d4d7dd7606f2622e3f64c0faa03bdbc7b6b23cb5f26aaccbd12060c3djsonrpc":"2.0"}", requestMethod="POST", u.io/rpc/v1", code=SERVER_ERROR, version=web/
AI Said
Check the imports to make sure all necessary packages are imported correctly.
Verify the contract address in the .env file is correct.
Verify the network information is correctly set for the Hyperspace network.
Check the code for the getTokens and MintTokens functions to ensure all parameters are correctly passed.
Make sure the wallet address is correct and matches the f4 address.
Check the gas limit settings for the MintTokens function.
Ensure the request body and method are correctly set in the code.
Verify the URL for the Json RPC Provider is correct.
But Im just lost, thanks

AAVE v3 - POLYGON - TEST <UnrecognizedContract>.<unknown> When running a script to deposit tokens to AAVE using a fork of the polygon mainnet

I'm testing v3 AAVE contracts on a fork of the polygon mainnet using harhat locally, but when I call de supply() function I get this error:
Error: Transaction reverted without a reason string
at <UnrecognizedContract>.<unknown> (0x794a61358d6845594f94dc1db02a252b5b4814ad)
at <UnrecognizedContract>.<unknown> (0x794a61358d6845594f94dc1db02a252b5b4814ad)
at <UnrecognizedContract>.<unknown> (0x794a61358d6845594f94dc1db02a252b5b4814ad)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at HardhatNode._mineBlockWithPendingTxs (/home/daniel/daniel/dev/chainlink/flowmi/node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:1802:23)
at HardhatNode.mineBlock (/home/daniel/daniel/dev/chainlink/flowmi/node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:491:16)
at EthModule._sendTransactionAndReturnHash (/home/daniel/daniel/dev/chainlink/flowmi/node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:1522:18)
at HardhatNetworkProvider.request (/home/daniel/daniel/dev/chainlink/flowmi/node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:118:18)
at EthersProviderWrapper.send (/home/daniel/daniel/dev/chainlink/flowmi/node_modules/#nomiclabs/hardhat-ethers/src/internal/ethers-provider-wrapper.ts:13:20)
The script I'm trying to run:
const { getNamedAccounts, ethers } = require("hardhat");
async function main() {
const { deployer } = await getNamedAccounts();
// Mainnet pool adready given by the deployment
// Deposit
// Aprove to get Matic
const AMOUNT = ethers.utils.parseEther("0.11");
//const maticTokenAddress = "0x0000000000000000000000000000000000001010"; //mainnet
const Pool = await getPool(deployer);
const maticTokenAddress = "0xD65d229951E94a7138F47Bd9e0Faff42A7aCe0c6"; // testnet matic address
await approveErc20(maticTokenAddress, Pool.address, AMOUNT, deployer);
console.log("Depositing...");
console.log("Address provided: ", Pool.address);
await Pool.supply(maticTokenAddress, AMOUNT, deployer, 0);
console.log("Deposited!");
}
async function getPool(account) {
const PoolAddressesProvider = await ethers.getContractAt(
"IPoolAddressesProvider",
"0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb", // mainnet pool addresses provider
//"0x5343b5bA672Ae99d627A1C87866b8E53F47Db2E6", // testnet pool addresses provider
account
);
const PoolAddress = await PoolAddressesProvider.getPool();
const Pool = await ethers.getContractAt("IPool", PoolAddress, account);
return Pool;
}
async function approveErc20(
erc20Address,
spenderAddress,
amountToSpend,
account
) {
const erc20Token = await ethers.getContractAt(
"IERC20",
erc20Address,
account
);
const tx = await erc20Token.approve(spenderAddress, amountToSpend);
await tx.wait(1);
console.log("Approved!");
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
When I ask for which address was provided the answer is:
Address provided: 0x794a61358D6845594F94dc1DB02A252b5b4814aD
Which happens to be a polygon mainnet pool address according to documentation. Notice is the same address the error gives.
I'll be most thankful if someone points out my mistake
I've tried different combinations of "mainnet" and "testnet" addresses, for the maticToken, and the pool addresses provider
The problem was the matic address, It seems I misundertood documentation, thought the fact that matic is an ERC20 compliant implied it should not need to be wrapped to deposit.
But the script only works with the address of wrapped matic on mainnet.
Maybe is a problem of the mainnet fork, don't know but I moved on.

Error deploying smart contract using hardhat -- Cannot read property 'sendTransaction' of null

Getting the below error while trying to deploy a smart contract from hardhat. Error details
TypeError: Cannot read property 'sendTransaction' of null
at ContractFactory.<anonymous> (C:\Collection\node_modules\#ethersproject\contracts\src.ts\index.ts:1249:38)
at step (C:\Collection\node_modules\#ethersproject\contracts\lib\index.js:48:23)
at Object.next (C:\Collection\node_modules\#ethersproject\contracts\lib\index.js:29:53)
at fulfilled (C:\Collection\node_modules\#ethersproject\contracts\lib\index.js:20:58)
Here are the config files
hardhat.config.js
require('#nomiclabs/hardhat-waffle');
require("#nomiclabs/hardhat-ethers");
require("dotenv").config();
// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
});
// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more
/**
* #type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
solidity: "0.8.2",
networks: {
mumbai: {
url: process.env.MUMBAI_URL,
account: process.env.PRIVATE_KEY
}
}
};
deploy.js
const {ethers} = require("hardhat");
async function main() {
const SuperMario = await ethers.getContractFactory("SuperMario");
const superInstance = await SuperMario.deploy("SuperMarioCollection", "SMC");
await superInstance.deployed();
console.log("contract was deployed to:", superInstance.address());
await superInstance.mint("https://ipfs.io/ipfs/XXXXXXX");
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
I am trying to deploy it using the following command
npx hardhat run scripts/deploy.js --network mumbai
thanks
Change account to accounts in the network config
found the fix. There was an error in the hardhat.config file
instead of account:, it should have been
accounts:[process.env.PRIVATE_KEY]

Solidity issue passing parameters to a function

I have a Smart Contract with the function:
contract Example {
event claimed(address owner);
function claimStar() public {
owner = msg.sender;
emit claimed(msg.sender);
}
}
I'm using Truffle V5.0 and the Webpack box as a boiler plate code.
In my truffle-config.js file I have the in the networks configuration:
development:{
host:"127.0.0.1",
port: 9545,
network_id:"*"
}
Everything compile fine using:
- truffle develop
- compile
- migrate --reset
It says Truffle Develop started at http://127.0.0.1:9545
In my index.js file I have the following code:
import Web3 from "web3";
import starNotaryArtifact from "../../build/contracts/StarNotary.json";
const App = {
web3: null,
account: null,
meta: null,
start: async function() {
const { web3 } = this;
try {
// get contract instance
const networkId = await web3.eth.net.getId();
const deployedNetwork = starNotaryArtifact.networks[networkId];
this.meta = new web3.eth.Contract(
starNotaryArtifact.abi,
deployedNetwork.address,
);
// get accounts
const accounts = await web3.eth.getAccounts();
this.account = accounts[0];
} catch (error) {
console.error("Could not connect to contract or chain.");
}
},
setStatus: function(message) {
const status = document.getElementById("status");
status.innerHTML = message;
},
claimStarFunc: async function(){
const { claimStar } = this.meta.methods;
await claimStar();
App.setStatus("New Star Owner is " + this.account + ".");
}
};
window.App = App;
window.addEventListener("load", async function() {
if (window.ethereum) {
// use MetaMask's provider
App.web3 = new Web3(window.ethereum);
await window.ethereum.enable(); // get permission to access accounts
} else {
console.warn("No web3 detected. Falling back to http://127.0.0.1:9545. You should remove this fallback when you deploy live",);
// fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
App.web3 = new Web3(new Web3.providers.HttpProvider("http://127.0.0.1:9545"),);
}
App.start();
});
In my browser I have Metamask installed and I added a Private Network with the same URL and also imported two accounts.
When I start the application and opened in the browser it opens Metamask to request permission because I'm using window.ethereum.enable();.
But when I click on the button to claim it doesn't do anything.
The normal behavior is to Metamask open a prompt to ask for confirmation but it never happen.
I created also a new property in the contract for test and it works fine showing me the value assigned in the contract constructor.
My question is, Am I missing something?
I also tried to change the functionawait claimStar(); to await claimStar({from: this.account}); but in this case I got an error saying that claimStar doesn't expect parameters.
I would appreciate any help. Thanks
I solved the issue, the problem was in the function claimStarFunc
It should be in this way:
claimStarFunc: async function(){
const { claimStar } = this.meta.methods;
await claimStar().send({from:this.account});
App.setStatus("New Star Owner is " + this.account + ".");
}
Because I'm sending a transaction.
Thanks

Truffle and Ganache-cli test case fails

So I have this setup : truffle and ganache-cli
I'm sending some ether to my contract, here is the related part of my contract:
mapping(address => uint256) public balanceOf;
function () payable public {
uint amount = msg.value;
balanceOf[msg.sender] += amount;
}
In truffle this is how I send the ether.
it("Test if can be payed", function(){
return web3.eth.sendTransaction({
from:fromAddr,
to:MyContract.address,
value:amountToSend
}).then(function(res){
expect(res).to.not.be.an("error"); // test passed
});
});
it("Test if contract received ether", function(){
return web3.eth.getBalance(MyContract.address,
function(err, res){
expect(parseInt(res)).to.be.at.least(1000000000000000000); // test passed
});
});
it("Catch if balanceOf "+fromAddr, function(){
return sale.balanceOf.call(fromAddr).then(function(res){
expect(parseInt(res)).to.be.at.least(1); // fails the test
});
});
Am I doing it right? What could be the reason for failed test?
truffle test output :
AssertionError: expected 0 to be at least 1
+ expected - actual
-0
+1
I can provide more info if needed.
UPDATE :
for clarification on sale which is global variable.
it("Test if MyContract is deployed", function(){
return MyContract.deployed().then(function(instance){
sale = instance;
});
});
I think this is what you are looking for:
File path:
test/vault.js
const Vault = artifacts.require("Vault");
contract("Vault test", async accounts => {
// Rely on one instance for all tests.
let vault;
let fromAccount = accounts[0];
let oneEtherInWei = web3.utils.toWei('1', 'ether');
// Runs before all tests.
// https://mochajs.org/#hooks
before(async () => {
vault = await Vault.deployed();
});
// The `receipt` will return boolean.
// https://web3js.readthedocs.io/en/1.0/web3-eth.html#gettransactionreceipt
it("Test if 1 ether can be paid", async () => {
let receipt = await web3.eth.sendTransaction({
from: fromAccount,
to: vault.address,
value: oneEtherInWei
});
expect(receipt.status).to.equal(true);
});
it("Test if contract received 1 ether", async () => {
let balance = await web3.eth.getBalance(vault.address);
expect(balance).to.equal(oneEtherInWei);
});
// In Web3JS v1.0, `fromWei` will return string.
// In order to use `at.least`, string needs to be parsed to integer.
it("Test if balanceOf fromAccount is at least 1 ether in the contract", async () => {
let balanceOf = await vault.balanceOf.call(fromAccount);
let balanceOfInt = parseInt(web3.utils.fromWei(balanceOf, 'ether'));
expect(balanceOfInt).to.be.at.least(1);
});
});
You can see the full project here. Do note that I'm using Truffle v5 and Ganache v2. See the README file inside that GitLab repository.
Back to your question, there were 2 mistakes:
The sale is not defined. I have a feeling that you were actually referring to MyContract.
In order to use the least method in ChaiJS, you need to make sure you are passing integers. The balanceOf call is returning BigNumber or BN object and you can't use it with .least method.
FYI, Truffle v5 is now using BN by default (previously BigNumber). More about it here.
Let me know if this helps.