Estimating Gas and Tx Fees
Scroll Alpha Testnet is now deprecated.
Please visit our new documentation for the Scroll Sepolia Testnet at https://docs.scroll.io/
Since Scroll is an L2 rollup, part of the transaction lifecycle is committing some data to L1 for security. To pay for this, all transaction incurs an additional fee called the L1 fee.
In this guide, we will go over how to estimate the L1 fee on Scroll and calculate final transaction fee estimations through a hands-on code example you can find here.
The formula
In short, the transaction fee on Scroll, at any given moment, can be calculated as
An important distinction we need to make is that l1Fee
is separated from the l2Fee
.
For a more comprehensive explanation and details on the formula, check the documentation on how Transaction Fees work on Scroll.
Interfacing with values
To fetch these values and calculate the final fee, we’ll interact with Scroll’s public RPC and pre-deployed Smart Contract L1GasOracle.sol, which is deployed at 0x5300000000000000000000000000000000000002
For our example codebase, we make a Hardhat project and fetch values using the Ethers.js library.
l2GasUsed
- We get this using the estimateGas method, which queries our RPC with the TX data to get an estimate of the gas to be used.
l2GasPrice
- For this, we’ll use the getFeeData method, which will get the current market conditions on the L2
The Gas Oracle smart contract exposes multiple key fields we need to figure out the cost of the transaction. overhead()
, scalar()
, l1BaseFee()
and getL1GasUsed(bytes memory data)
But it also exposes the getL1Fee(bytes memory data)
function, which abstracts all these complexities and allows us to get the fee in just one function call.
Hands-on example
Project structure
First of all, let’s quickly go over the key folders inside our project structure.
It’s a standard Hardhat project, but most of our work is inside the contracts and scripts folders.
This tutorial will review the critical parts of the code, using the example code as an easy way to get an overview of what’s done in the project. Some code, like error handling, will be excluded for simplicity.
The smart contract
First, we need a Smart Contract to interact with to showcase the gas estimation. For that, we’ll create a ExampleContract.sol
.
Remember the setExampleVariable
method signature since we’ll use it later as an example
Once deployed, we fill the EXAMPLE_CONTRACT_ADDRESS
value in our .env
file. For the example project, it’s already deployed at 0xc37ee92c73753B46eB865Ee156d89741ad0a8777
and pre-filled, so nothing has to be done here.
Estimating the fees
The central part of the example lives in the /scripts/gasEstimation.ts
file.
We’ll do just four things:
Create a dummy transaction using the ExampleContract
Estimate the L2 fee of that transaction
Estimate the L1 fee of that transaction
Emit an actual transaction to Scroll and compare the values
Creating the dummy transaction
The goal of this step is to create an (RLP) Serialized Unsigned Transaction to be used later on as the parameter for calling the oracle gas estimation method.
Let’s populate our transaction with the needed values to estimate its cost by calling
buildPopulatedExampleContractTransaction
. This will fill thedata
,to
,gasPrice
,type
andgasLimit
fields:
Now, let’s trim it down to the basic fields using
buildUnsignedTransaction
. We won’t be signing it.
Make sure that the nonce is a valid one!
With the output of the previous function, we serialize it using
getSerializedTransaction
Estimating the L2 fee
This step is pretty standard and the same as on Ethereum. We’ll use the estimateL2Fee
function which takes the populated transaction as an input and returns an estimate of the total gas it will use by multiplying the current gas price and gas needed to be used.
Estimating the L1 fee of that transaction
This step is very straightforward. Using the output of the getSerializedTransaction
function, we query the oracle and get the estimated fee in return.
Emitting the transaction and comparing estimated vs actual values
Emitting the transaction
We’ll create a call to our contract using the same values used for the dummy transaction.
Calculating the L2 fee
Using the transaction receipt we can see the amount of gas used by the transaction
Getting the amount used to pay for the L1 fee
To do this, we’ll compare the balance of the account before the transaction execution, the account balance after the execution and then subtract the L2 fee.
Comparing the values
Fee markets are constantly moving and unpredictable. Since the values estimated may differ from the actual execution, let’s check how much they differ.
We can run all the code that we previously wrote by typing yarn gas:estimate
command in our project that will run the gasEstimation.ts
script and give us the output below:
We can see above that the estimated values (in wei) differ by around 1%, but keep in mind that during spikes in gas prices, this difference may increase. Be sure to account for this in your front end for users!
For more details about what happens when gas fluctuates on L1 and about the limits set there, check out the lifecycle of a transaction on the Gas Fees.
Last updated
Was this helpful?