How to estimate gas in Arbitrum
This document is currently in public preview and may change significantly as feedback is captured from readers like you. Click the Request an update button at the top of this document or join the Arbitrum Discord to share your feedback.
This how-to is intended for users and developers who want to understand how gas is calculated in Arbitrum, and how it can be estimated before submitting transactions. More information about the theory behind these calculations can be found in this Medium article and the Gas and Fees page.
We'll first break down the formula mentioned in the Medium article, moving then to where to get the information of each variable, and finally seeing an example of how to apply the formula in your code as well as other practical ways of estimating gas costs.
However, if you want to jump straight to the code, we have created this script in our tutorials repository that goes through all the calculations explained in this how-to.
Breaking down the formula
As explained in the Medium article, the transaction fees to pay at any given moment are the result of the following product:
Transaction fees (TXFEES) = L2 Gas Price (P) * Gas Limit (G)
This Gas Limit includes the gas of the L2 computation and an additional buffer to cover the L1 gas to be paid by the Sequencer when posting the batch including this transaction on L1.
Gas Limit (G) = Gas used on L2 (L2G) + Extra Buffer for L1 cost (B)
This buffer takes into account the cost of posting the transaction, batched and compressed, on L1. The L1 estimated posting cost is calculated by multiplying these two values:
- L1S, which estimates the amount of data the transaction will take up in the batch by compressing the transaction with Brotli.
- L1P, which is the L2's estimated view of the current L1's price of data (per byte), which the L2 dynamically adjusts over time.
More information is available in this page.
L1 Estimated Cost (L1C) = L1 price per byte of data (L1P) * Size of data to be posted in bytes (L1S)
To calculate the buffer, that estimated cost is divided by the L2 Gas Price.
Extra Buffer (B) = L1 Estimated Cost (L1C) / L2 Gas Price (P)
Finally, using all of the above elements, the formula can be written as follows:
TXFEES = P * (L2G + ((L1P * L1S) / P))
Where do we get all this information from?
We'll use two resources available in Arbitrum: the ArbGasInfo precompile and the NodeInterface.
- P (L2 Gas Price) ⇒ Price to pay for each gas unit. It starts at 0.1 gwei on Arbitrum One (0.01 gwei on Arbitrum Nova) and can increase depending on the demand for network resources.
- Call
ArbGasInfo.getPricesInWei()
and get the sixth element.
- Call
- L2G (Gas used on L2) ⇒ Gas used to compute the transaction on L2. This does not include the “posting on L1” part of the calculations. The value of L2G will depend on the transaction itself, but having the data of the transaction, we can calculate it as follows:
- Call
NodeInterface.GasEstimateComponents()
with the transaction data and subtract the second element (gasEstimateForL1
, which estimates the L1 part of the fees) from the first (gasEstimate
, which includes both the L1 and the L2 parts).
- Call
- L1P (L1 estimated price per byte of data) ⇒ Estimated cost of posting 1 byte of data on L1:
- Call
ArbGasInfo.getPricesInWei()
and get the second element.
- Call
- L1S (Size of data to be posted on L1, in bytes) ⇒ This will depend on the data of the transaction. Keep in mind that Arbitrum adds a fixed amount to this number to make up for the static part of the transaction, which is also posted on L1 (140 bytes).
- For Arbitrum Nova (AnyTrust), the size of the data is also a fixed value, as only the Data Availability Certificate is posted on L1, as explained here.
An example of how to apply this formula in your code
Finally, we show an example of how to get the values we just described and how to estimate the gas usage of a transaction in Javascript. We'll use our SDK to connect to ArbGasInfo
and NodeInterface
.
We first instantiate a factory object for ArbGasInfo and NodeInterface, using two methods from the SDK. l2Provider
is a regular JSON RPC provider for the L2 network we are using, and both ARB_GAS_INFO
and NODE_INTERFACE_ADDRESS
are the addresses of the precompiles in said network.
const { ArbGasInfo__factory } = require("@arbitrum/sdk/dist/lib/abi/factories/ArbGasInfo__factory");
const { NodeInterface__factory } = require("@arbitrum/sdk/dist/lib/abi/factories/NodeInterface__factory");
const { ARB_GAS_INFO, NODE_INTERFACE_ADDRESS } = require("@arbitrum/sdk/dist/lib/dataEntities/constants");
...
// Instantiation the ArbGasInfo and NodeInterface objects
const arbGasInfo = ArbGasInfo__factory.connect(
ARB_GAS_INFO,
l2Provider
);
const nodeInterface = NodeInterface__factory.connect(
NODE_INTERFACE_ADDRESS,
l2Provider
);
For this example, we'll use the method ArbGasInfo.getPricesInWei()
and NodeInterface.gasEstimateComponents()
to get the information we need. For the gasEstimateComponents()
call, we'll pass a destinationAddress
(this can be any address) and the data we want to send, to get results as accurate as possible.
// Getting the gas prices from ArbGasInfo.getPricesInWei()
const gasComponents = await arbGasInfo.callStatic.getPricesInWei();
// And the estimations from NodeInterface.GasEstimateComponents()
const gasEstimateComponents = await nodeInterface.callStatic.gasEstimateComponents(
destinationAddress,
false,
txData
);
With this, we can now get the values of the 4 variables we'll use in our formula:
// Setting the variables of the formula
const P = gasComponents[5];
const L2G = gasEstimateComponents[0].sub(gasEstimateComponents[1]);
const L1P = gasComponents[1];
const L1S = 140 + txDataLengthInBytes;
And finally, we estimate the transaction fees applying the formula described in the beginning.
// L1C (L1 Cost) = L1P * L1S
const L1C = L1P.mul(L1S);
// B (Extra Buffer) = L1C / P
const B = L1C.div(P);
// G (Gas Limit) = L2G + B
const G = L2G.add(B);
// TXFEES (Transaction fees) = P * G
const TXFEES = P.mul(G);
Refer to our tutorials repository for a working example of this code.
Other practical ways of estimating gas costs in your code
Instead of going through the formula, we can also use the following methods to easily estimate gas costs:
- We can call an Arbitrum node’s
eth_estimateGas
to get the gas limit of the transaction. We would then need to multiply that amount by the L2 gas price, which we can get by callingeth_gasPrice
. - When working with L1 to L2 messages (also known as Retryable tickets), we can use the function L1ToL2MessageGasEstimator.estimateAll() of the SDK or NodeInterface.estimateRetryableTicket() to get all the gas information needed to send the transaction.
Final note
Note that gas estimations from the above techniques are approximate and the actual gas fees may differ. We encourage developers to set this expectation explicitly wherever this information is shared with end-users.