Gas & Fee Management in Scroll SDK
Scroll SDK provides a comprehensive gas and fee management system to ensure the efficient operation of the network. This section provides an overview of the gas and fee management tools and best practices for using them.
Transaction Fees on an SDK Chain
Transaction fees for users on Scroll are split between an L2 Fee and an L1 Fee. For more information on how transaction fees work, see Transaction Fees on Scroll.
Paid network fees are collected in the L2FeeVault
contract. Any user can trigger the movement of funds to L1, where they can be claimed by the OWNER
role.
Configuring L2 Execution Fees
L2 transaction fees are set as a minimum “floor” for the execution component of the fee, beyond which normal mechanisms for EIP1559 adjustment apply.
This is set with --miner.gasprice
on the sequencer. You can modify this value and --gpo.ignoreprice
in the chart by overriding the L2GETH_MIN_GAS_PRICE
environment variable here.
Additionally, you could modify the --gpo.percentile
and --gpo.blocks
arguements, but will need to manually modify the l2-sequencer
chart.
Lastly, RPC nodes (or any node that accepts transactions) should set --gpo.congestionthreshold
, which we default to 500. This configuration allows nodes to provide more accurate fee estimate. The value is the number of pending transactions to consider the network congested and suggest a minimum tip cap if there are fewer pending transactions in the txpool.1
For additional information, see the geth documentation.
Configuring L1 Fees
The L1GasOracle
pre-deployed contract holds the values used to calculate the L1 fee for transactions.
The following fields are set by the Gas Oracle service, specifically by transactions submitted by the L2GasOracleSender
:
l1BaseFee
: the base fee for the L1 transactionl1BlobBaseFee
: the base fee for the L1 blob data
The following fields are set by the Owner using setter functions in the L1GasOracle
contract:
commitScalar
blobScalar
overhead
scalar
To see these on Scroll’s mainnet deployment, view the L1GasOracle contract.
For more information on how gas fees on Scroll are calculated, see the Calculating the L1 Data Fee with Gas Oracle.
Calculating and Setting Gas Oracle Fields
L1GasPriceOracle
has two variables commitScalar
and blobScalar
which are used to calculate L1 fee for a L1 transaction.
To calculate the scalars, you can use the following formula:
To set the scalars on L1GasPriceOracle
, you can run this command with cast
:
Claiming Fees from the Vault
As L2 Fees accumulate in the L2FeeVault, any user can call the withdrawl
method to “claim” these fees. This will bridge the funds to the L1_FEE_VAULT_ADDR
address (configured in config.toml
) on the L1 chain.
After the funds are bridged, the bridged funds will still need to be claimed on L1 with a proof that can be easily obtained using the bridge-history-api
. To see this process on Scroll, see Finalizing Transactions on L1
Alternative Gas Token
Beyond using Ethereum as the native gas token, Scroll SDK also supports alternative gas tokens. This customization allows users to use their preferred gas token for transactions.
Because transaction fees are calculated by not just charging a gas fee, but also an L1 fee, conversion is needed between the L1’s native token and the SDK’s gas token, additional configuration and logic is needed in the gas oracle.
Gas Oracle Fields for Alternative Gas Tokens
Instead of introducing another variable to the L1GasPriceOracle
contract which requires manual updates from the owner, operators should modify the Gas Oracle to include the ETH/ERC20 conversion rate.
Configuring Gas Oracle for Alternative Gas Tokens
Basic configuration for the Gas Oracle can be made in the config.toml
file before generating the service’s config values.
config.toml [gas-token] values
GAS_ORACLE_INCORPORATE_TOKEN_EXCHANGE_RATE_ENANBLED
- if
true
, includes the L2/L1 exchange rate into gas price. Should only set to true when alternative gas token enabled. - Default:
false
- if
EXCHANGE_RATE_UPDATE_MODE
- The mode used to set L2/L1 gas token exchange rate. Options supported are
Fixed
andBinanceApi
. - Default:
Fixed
- The mode used to set L2/L1 gas token exchange rate. Options supported are
FIXED_EXCHANGE_RATE
- When using “Fixed” exchange rate mode, the number of native token on L1 required to exchange for 1 native token on L2
- Devnet Default:
0.01
TOKEN_SYMBOL_PAIR
- When using “BinanceApi” exchange rate mode, the pair should be L2 gas token symbol + L1 native token symbol. For instance, if using UNI token as the gas token on L2, the pair should be “UNIETH”. Token pair should be supported by Binance and included in their ticker list API
- NOTE: This API is not accessible in some regions, including the US. Confirm access eligibility before using.
gas-oracle
config values
For more complicated configurations, you’ll want to make manual adjustments to the your Gas Oracle config values, specifically the alternative_gas_token_config
sections.
L1 gas oracle config
min_gas_price
- The minimal gas price set to contract
L1GasPriceOracle
(for both baseFee and blobBaseFee)
- The minimal gas price set to contract
gas_price_diff
- The minimum percentage of gas price difference to update gas oracle (for both baseFee and blobBaseFee)
l1_blob_base_fee_weight
- The weight for L1 blob base fee (deprecated after curie upgrade)
check_committed_batches_window_minutes
- The time frame to check if we committed batches to decide to update gas oracle or not in minutes. If we are not committing batches due to high fees then we shouldn’t update fees to prevent users from paying high l1_data_fee, so we should set fees to some default value
- Should be set it to the same or slightly larger value as
batch_timeout_sec
, remembering to convert second to minutes
l1_base_fee_default
- The default base cost value set when a batch is not committed for longer than
check_committed_batches_window_minutes
.
- The default base cost value set when a batch is not committed for longer than
l1_blob_base_fee_default
- The default blob base cost value set when a batch is not committed for longer than
check_committed_batches_window_minutes
.
- The default blob base cost value set when a batch is not committed for longer than
alternative_gas_token_config
:enabled
- If enabled, incorporates L2/L1 gas token exchange rate into gas price. (Should only set to true when alternative gas token enabled)
mode
- The mode to retrieve L2/L1 gas token exchange rate. (
Fixed
||BinanceApi
)
- The mode to retrieve L2/L1 gas token exchange rate. (
fixed_exchange_rate
- When using “Fixed” exchange rate mode, the number of native tokens on L1 required to exchange for 1 native token on L2
token_symbol_pair
- When using “BinanceApi” exchange rate mode, the pair should be L2 gas token symbol + L1 native token symbol. For instance, if using UNI token as the gas token on L2, the pair should be “UNIETH”. Token pair should be supported by Binance and included in their ticker list API
- NOTE: This API is not accessible in some regions, including the US. Confirm access eligibility before using.
L2 gas oracle config
min_gas_price
- The minimal gas price set to contract L1GasPriceOracle.
gas_price_diff
- The minimum percentage of gas price difference to update gas oracle.
alternative_gas_token_config
- Refer to
alternative_gas_token_config
on L1 gas oracle config above.
- Refer to
Security Considerations for Alternative Gas Tokens
When implementing alternative gas tokens, operators should be aware of several important security considerations to prevent potential loss of funds and user errors.
The contract and gas oracle changes for Scroll SDK are not used on Scroll mainnet, but have been audited by Trail of Bits.
L2 to L1 Message Queue Restrictions
The L2 Message Queue system has strict requirements for handling native token transfers:
- Messages with non-zero value must be sent to the
L1GasTokenGateway
address - Messages sent to any other address with non-zero value will fail to relay on L1, resulting in burned tokens
- Ideally, custom gateway implementations should validate destination addresses on L2 before allowing transfers
Token Decimal Scaling Issues
When bridging ERC-20 tokens to be used as native L2 tokens:
- Tokens are automatically scaled to 18 decimals on L2
- Example: If using USDT (6 decimals) as gas token:
- 1 USDT on L1 = 1012 native tokens on L2
- This maintains UI display values but can affect base unit calculations
Contract Interface Naming
Operators should be aware of potentially confusing contract interfaces:
L1GasTokenGateway.depositETH()
- Actually deposits ERC-20 gas tokens, not ETH- L2-side functions reference “ETH” even when using alternative tokens
L1WrappedTokenGateway
handles wrapped ETH, not wrapped gas tokens
Footnotes
-
See these
l2geth
code comments for more info. ↩