DEV Community

loading...
Cover image for Getting Gas Prices In Solidity

Getting Gas Prices In Solidity

patrickalphac profile image Patrick Collins ・3 min read

Introduction

When making transactions in the ethereum chain, you always have to set a gas price to do so. Generally, your wallet will have some sort of estimator to decide the gas price. This is great, but what happens if you NEED to get your transaction processed quickly? You'll need a way to estimate the fast gas price so your transaction can get through.

What is gas?

Gas in solidity is a special unit of computational work and storage it costs to execute on-chain interactions and state changes. So if you do some addition, that will cost less gas than if you do addition, multiplication, and division.

1 unit of gas costs ethereum. This is why you pay a fee whenever you make a transaction on-chain, you are asking the system to perform some computational work. However, the ETH that you need to pay to do that 1 unit of gas, changes depending on the congestion of the network.

When a lot of people want their transactions processed, miners will prioritize the transactions that are offering more gas. This is known as the gas price.

The fee you pay is going to be the amount of gas times the cost of gas.

Sending transactions

When sending transactions, you need to estimate this price of gas so you'll have roughly a good idea when your transaction will get through. Maybe you have a massive transaction and you want it to settle quickly. When looking at your code, you can choose how much gas to send.

Sample code

Let's look at some code that shows sending a transaction. We will be using ethers.js to send our transaction.

const main = async () => {
    let contract = new ethers.Contract(address, abi, wallet)
    let contractWithSigner = contract.connect(wallet)
    let tx = await contractWithSigner.executeThisFunctionQuick()
    console.log(tx.hash)
    await tx.wait()
}
Enter fullscreen mode Exit fullscreen mode

In this function, we are calling executeThisFunctionQuick, but we are not giving the transaction any input about how much gas it should use, and therefore, it has no idea how quickly it should send this information. This is really bad, since we need this to go through.

Having your contract depend on a centralized data provider, can, can cause issues since now your application depends on them being up and honest. So the best solution for this is to the fast gas Chainlink price feed. You'll pull in the fast gas information, and then run your contract with it. You can find out more about Chainlink price feeds in the Chainlink documentation.

First, let's grab some default information to get going.

const aggregatorV3InterfaceABI = [{ "inputs": [], "name": "decimals", "outputs": [{ "internalType": "uint8", "name": "", "type": "uint8" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "description", "outputs": [{ "internalType": "string", "name": "", "type": "string" }], "stateMutability": "view", "type": "function" }, { "inputs": [{ "internalType": "uint80", "name": "_roundId", "type": "uint80" }], "name": "getRoundData", "outputs": [{ "internalType": "uint80", "name": "roundId", "type": "uint80" }, { "internalType": "int256", "name": "answer", "type": "int256" }, { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "latestRoundData", "outputs": [{ "internalType": "uint80", "name": "roundId", "type": "uint80" }, { "internalType": "int256", "name": "answer", "type": "int256" }, { "internalType": "uint256", "name": "startedAt", "type": "uint256" }, { "internalType": "uint256", "name": "updatedAt", "type": "uint256" }, { "internalType": "uint80", "name": "answeredInRound", "type": "uint80" }], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "version", "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], "stateMutability": "view", "type": "function" }]
const priceFeedAddr = "0x562C092bEb3a6DF77aDf0BB604F52c018E4f2814" // swap this for the fast gas address
let priceFeed = new ethers.Contract(priceFeedAddr, aggregatorV3InterfaceABI, wallet)
let gasPrice = 30000000000
Enter fullscreen mode Exit fullscreen mode

We need the ABI and address of the fast gas aggregator contract so we can interact with the contract, then we can pop back into our main function.

Before we go calling our executeThisFunctionQuick we want to get the fast gas price into our contract.

roundData = await priceFeed.latestRoundData()
    // gasPrice = roundData['1'] // this is what you'll use
    console.log("Gas Price is now " + gasPrice)
    let overrides = {
        // The price (in wei) per unit of gas
        gasPrice: gasPrice, // Set the price based on the fast gas here
    }
Enter fullscreen mode Exit fullscreen mode

This will tell us what a safe fast gas is to set. Then, all we have to do is add the overrides object to our call. This will override the default of the gasPrice value.

let tx = await contractWithSigner.executeThisFunctionQuick(overrides)
Enter fullscreen mode Exit fullscreen mode

And that's it! Now we can be sure that our transactions in our code will be sent out in a fast secure manner.

To see a full example, check out my gist on making a simple contract call with gas cost estimation as well.

Discussion

pic
Editor guide