Estimating EIP-1559 Transaction Gas on Polygon with ethers.js

Amogh Jahagirdar
2 min readJan 8, 2023

--

Polygon Mainnet was upgraded to EIP-1559 on Jan 18th 2022.

Pre-EIP1559 we could estimate the gasPrice from getFeeData() that is available on the provider object. Eg:

  const feeData = await provider.getFeeData();
const tx = await yourContract.yourMethod(yourArguments, {gasPrice: feeData.gasPrice});
await tx.wait();
console.log(tx.hash);

However, the introduction of EIP-1559 deprecates gasPriceand the gas for a transaction is dictated by 3 new parameters.

baseFee, maxPriorityFeePerGas and maxFeePerGas

Of these, we need to send only maxPriorityFeePerGas and maxFeePerGas with our transaction. This is because maxFeePerGas is the the sum of maxPriorityFeePerGas and baseFee. maxPriorityFeePerGas is seperately included as is the amount that is directly forwarded to the miner as a “tip” in return for a higher priority while executing all the txs included that block.

So evidently, in order to send an EIP-1559 compatible transaction, we have to change how we estimate gas before sending a transaction using ethers.js.

If you use the values for maxPriorityFeePerGas and maxFeePerGas from provider.getFeeData()and while sending a transaction on Polygon, you’ll recieve an error that says

“error”:{“code”:-32000,”message”:”transaction underpriced”}}

This error persists even if you 5x or 10x both the params. That means we have to deal with it differently.

So instead of sourcing our maxPriorityFeePerGas and maxFeePerGas from provider.getFeeData() , let us source our values from Polygon’s gas station end point:

https://gasstation-mainnet.matic.network/v2

An example response looks like this:

{
"safeLow": {
"maxPriorityFee": 30.102290831615385,
"maxFee": 50.15799883361538
},
"standard": {
"maxPriorityFee": 30.52003085923077,
"maxFee": 50.57573886123077
},
"fast": {
"maxPriorityFee": 31.700968178846153,
"maxFee": 51.756676180846156
},
"estimatedBaseFee": 20.055708002,
"blockTime": 2,
"blockNumber": 37822302
}

Using these values in our code looks a little like this:

const resp = await fetch('https://gasstation-mainnet.matic.network/v2')
const data = await resp.json()

const maxFeePerGas = ethers.utils.parseUnits(${Math.ceil(data.fast.maxFee)}`,'gwei',)const maxFeePerGas = ethers.utils.parseUnits(${Math.ceil(data.fast.maxFee)}`,'gwei',)
const maxPriorityFeePerGas = ethers.utils.parseUnits(${Math.ceil(data.fast.maxPriorityFeePerGas)}`,'gwei',)const maxFeePerGas = ethers.utils.parseUnits(${Math.ceil(data.fast.maxFee)}`,'gwei',)const tx = await yourContract.yourMethod(yourArguments, { maxFeePerGas, maxPriorityFeePerGas })
await tx.wait();
console.log(tx.hash);

And the transaction goes through!

Hope this helped! If you have any question regarding this you find me on Twitter @0xamogh! Have a nice day! 😄

--

--