1

I am using ethers as part of hardhat and I'm preparing to deploy to mainnet. I am using the gas-estimator plugin, and I see how much gas is used during each test/testnet deployment. However, so far, I haven't once had to specify gas for a transaction or deployment.

This is scary, as I know from the past deploying to mainnet is a bit different.

In the past I kinda just put in an arbitrarily high gasLimit, which seems wrong, like this:

const token = await ethers.getContractFactory("CreepKidsNFT");

const contract = await token.deploy({
  gasLimit:6660666
});

I haven't been able to find any clear answer or documentation on what exactly is going on under the hood. It seems like this would be something there is clear documentation/sample code somewhere... Maybe this can be that place?

If I run this code, will ethers handle getting the gas price and submitting a "market rate" amount of gas?

 const MyContract = await ethers.getContractFactory("MyContract");
 const myContract = await MyContract.deploy();

Or do I need to do something like, run tests, get gas used from gas-estimator, figure out that amount in wei, and supply gasPrice, maxFeePerGas, maxPriorityFeePerGas as options?

I see what looks like a single call way of handling a similar process done on the answer provided by Diego Ferri here in which he makes a "feeData" provider call

// The gas price (in wei)...
const feeData = await provider.getFeeData();

And then he just passes that in as the contract options

const MyContract = await ethers.getContractFactory('MyContract', signer);
const mycontract = await MyContract.deploy(feeData);

Is this the way?

And if it is the way how do we do this in hardhat, specifically the provider.getFeeData() part?

It's my understanding that ethers is the provider for hardhat, but I don't see any function call like getFeeData in the helpers api

2 Answers 2

0

Note that the gas price can fluctuate rapidly, so it is always best to check the gas price before deploying your contract. You can do this using a gas price estimator such as EthGasStation or Etherscan.

To specify a gas price and gas limit when deploying a contract, you can use the gasPrice and gasLimit options when calling the deploy() method. For example:

const MyContract = await ethers.getContractFactory('MyContract', signer);
const mycontract = await MyContract.deploy({
  gasPrice: 1000000000000000000, // 100 Gwei
  gasLimit: 6660666,
});

The feeData object that you mentioned in your question is a new feature that was introduced in EIP-1559. It provides a more flexible way to specify the gas fees for a transaction.

To use the feeData object to deploy a contract, you can pass it as the options object to the deploy() method. For example:

const feeData = await provider.getFeeData();

const MyContract = await ethers.getContractFactory('MyContract', signer);
const mycontract = await MyContract.deploy(feeData);

The provider.getFeeData() method returns a FeeData object that contains the following information:

maxFeePerGas: The maximum fee per gas that the user is willing to pay. maxPriorityFeePerGas: The maximum priority fee per gas that the user is willing to pay.

gasPrice: The base fee per gas that will be paid to the miner. The maxFeePerGas and maxPriorityFeePerGas values are specified in Gwei. The gasPrice value is specified in Wei.

If you are using Hardhat, you can use the getFeeData() method from the ethers package. For example:

const { getFeeData } = require('ethers');

const feeData = await getFeeData();

Once you have the feeData object, you can pass it to the deploy() method when deploying your contract.

Which method you choose to use depends on your specific needs. If you are comfortable with EIP-1559, then I recommend using the feeData object. It provides a more flexible way to specify the gas fees for your transaction. However, if you are not comfortable with EIP-1559, then you can continue to use the gasPrice and gasLimit options.

Here is the two methods:

Method 1: Using the feeData object

// Get the fee data from the provider.
const feeData = await provider.getFeeData();

// Deploy the contract using the fee data.
const MyContract = await ethers.getContractFactory('MyContract', signer);
const mycontract = await MyContract.deploy(feeData);

Method 2: Using the gasPrice and gasLimit options

// Specify the gas price and gas limit.
const gasPrice = 1000000000000000000; // 100 Gwei
const gasLimit = 6660666;

// Deploy the contract using the gas price and gas limit options.
const MyContract = await ethers.getContractFactory('MyContract', signer);
const mycontract = await MyContract.deploy({
  gasPrice,
  gasLimit,
});
5
  • Thank you, this is the exact hand-holding informational breakdown I was hoping for <3 Commented Sep 19, 2023 at 8:38
  • @LucasMoskun Cool. Please upvote so it helps to me as I had to create new profile. My old was ranking at top in Stake Exchange. What are you working for? Lets get connected on telegram : mohtajj95 Commented Sep 20, 2023 at 11:48
  • sorry, i totally would but my ranking isn't high enough to upvote :-/ Commented Sep 21, 2023 at 15:39
  • Hey, sorry, I had to un-accept this answer. After implementing your fee data solution, I am getting this error: ProviderError: both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified. Note, my initial ask is specific to hardhat, and hardhat ethers, so maybe that's the problem? Commented Sep 21, 2023 at 15:50
  • You have to put gasprice : "30000000" and Max fees and priority fees depending on maximum gas you can afford to pay. This is not an eroor but the parameter you need to pass. Commented Sep 22, 2023 at 10:38
0

After digging through the source code, and doing some research, I've discovered that gas calculation is being fully handled under the hood.

Since ethersjs 5.6.0 eip-1559 gas calculation is automatically handled. (here's a nice breakdown of eip-1559.

To see how this is handled, you can check out the populateTransaction function in theabstract-signers.ts script. Here's the core snippet from that function:

   //estimates gas
           if (pop.gasLimit == null) {
              pop.gasLimit = await this.estimateGas(pop);
            }

  //... then later on

  // We need to get fee data to determine things
            const feeData = await provider.getFeeData();

            if (pop.type == null) {
                // We need to auto-detect the intended type of this transaction...

                if (feeData.maxFeePerGas != null && feeData.maxPriorityFeePerGas != null) {
                    // The network supports EIP-1559!

                    // Upgrade transaction from null to eip-1559
                    pop.type = 2;

                    if (pop.gasPrice != null) {
                        // Using legacy gasPrice property on an eip-1559 network,
                        // so use gasPrice as both fee properties
                        const gasPrice = pop.gasPrice;
                        delete pop.gasPrice;
                        pop.maxFeePerGas = gasPrice;
                        pop.maxPriorityFeePerGas = gasPrice;

                    } else {
                        // Populate missing fee data

                        if (pop.maxFeePerGas == null) {
                            pop.maxFeePerGas = feeData.maxFeePerGas;
                        }

                        if (pop.maxPriorityFeePerGas == null) {
                            pop.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;
                        }
                    }

So, this means, from hardhat ethers, when calling deploy, or functions on a contract, there is no need to calculate, or provide, additional gas value parameters.

here's an example:

    const MyContract = await ethers.getContractFactory("MyContract");
    const myContract = await MyContract.deploy();

And if you want to override the default values, you can do something like this:

    const MyContract = await ethers.getContractFactory("MyContract");
    const feeData = await ethers.provider.getFeeData();
    const overrides = {
      maxFeePerGas: feeData.maxFeePerGas,
    };
    const myContract = await MyContract.deploy(overrides);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.