Receive and claim gas fees
Overview
Existing L2s like Optimism and Arbitrum keep sequencer fees for themselves. Blast redirects sequencer fees to the dapps that induced them, allowing smart contract developers to have an additional source of revenue.
Contracts have two options for their Gas Mode:
- Void (DEFAULT): base + priority fees go to the sequencer operator
- Claimable: base + priority fees spent on this contract can be claimed by the contract, net of L1 fees
Smart contracts must interact with the Blast contract located at 0x4300000000000000000000000000000000000002
to change their Gas Mode.
Setting Gas Mode to Claimable
The entity that is allowed to claim the gas fees spent on a contract is known as its “governor”. By default, the governor of a smart contract is the contract itself. The following example sets the Gas Mode to claimable and exposes a function to allow anybody to claim this contract’s gas fees.
Alternatively, you can specify an external governor. Once the governor is changed away from the contract itself, only the governor can set the gas mode, claim gas fees, and reconfigure the governor. In the following example, the governor could be an EOA belonging to the contract creator or another smart contract.
The governor now has the ability to claim the gas fees for this contract by sending a claimAllGas
transaction to the Blast contract.
Claiming Gas Fees
If you claim the gas fees for a contract immediately after the fees are earned, then 50% of the fees will be sent to the claim recipient and 50% will be sent to the sequencer operator. This is known as the “claim rate”, and it starts at 50% and increases to 100% over time. For mainnet, the parameters will be set to a 50% initial claim rate, 30 day maturity period, and 100% final claim rate.
You can think of each transaction’s gas fees as having their own claim rate that evolves independently. As an example, suppose you have 1 ETH in fees from January 1st and 1 ETH in fees from January 15th. When you claim 1 month later on February 1st, you’ll be able to claim 100% of your January 1st fees and 75% of your January 15th fees. Only half a month has passed since your January 15th fees, so the claim rate has increased halfway to its max potential, from 50% to 75%. Your average claim rate for the full 2 ETH of fees will be the weighted average of these two claim rates: 87.5%.
Thinking about the effective claim rate can get very confusing when you have many transactions over time, so for convenience, there are a handful of utility methods to make the claiming process easy.
claimAllGas
To claim all of your contract’s gas fees, regardless of your resulting claim rate, you can call claimAllGas
. Your resulting claim rate may be anywhere from 50% to 100% depending on how long it has been since the fees were earned.
claimMaxGas
If you’d like to maximize the amount of gas fees claimed and you’re okay waiting for the fees to mature, then you can use claimMaxGas
to guarantee a 100% claim rate. By guaranteeing the claim rate, you may not be able to claim all of your gas fees though. Any remaining fees after calling this function will remain in the Blast Gas contract for you to claim later.
claimGasAtMinClaimRate
This helper allows you to claim the maximum amount of gas fees while guaranteeing a specific claim rate. If you’re comfortable with an 80% claim rate, that translates to 8000 bips, so you would call claimGasAtMinClaimRate(contractAddress, recipient, 8000)
. Calling this function with a 100% min claim rate is the same as calling claimMaxGas
.
How Gas Fees Are Allocated
The gas fees spent on Blast transactions can be broken up into three components: L1 data availability fees, L2 base fees, and L2 priority fees. The L1 data availability fee ensures that other nodes can trustlessly recover the state of the Blast L2, and it gets burned on the Ethereum L1. The L2 base and priority fees (“sequencer fees”) however either go to the sequencer operator or to the smart contracts that caused the gas to be spent.
Blast allocates sequencer fees to contracts based on the amount of gas that contract consumed in the transaction. This means that contracts that make nested calls to other smart contracts will get a proportional amount of the total gas fees spent on the transation, not the total amount.
In cases where delegatecall
is used, gas fees are allocated to the contract that initiated the delegatecall
and not the target contract where the implementation logic lives.
Example: Nested Calls
To further demonstrate how gas fees are allocated across nested calls, consider the following example:
- Contract A (30,000 gas)
- Contract B (50,000 gas)
- Contract C (20,000 gas)
- Contract A (30,000 gas)
- Contract D (40,000 gas)
Suppose that only contracts A and D have set their Gas Mode to claimable. In this sample transaction, contract A would be allocated 30,000 + 30,000 = 60,000 gas worth of fees, and contract D would be allocated 40,000 gas worth of fees. The gas spent on contracts B and C, 50,000 + 20,000 = 70,000, would be allocated to the sequencer operator.
Example: Proxy / Delegatecall
Now, suppose that contract D is a proxy contract that forwards calls via delegatecall
to an implementation contract, contract E.
- Contract A (30,000 gas)
- Contract B (50,000 gas)
- Contract C (20,000 gas)
- Contract A (30,000 gas)
- (Proxy) Contract D (1,000 gas)
delegatecall
Contract E (39,000 gas)
In this modified example, contract D will still be allocated 1,000 + 39,000 = 40,000 gas worth of fees because the execution of contract E’s code happens within the context of contract D.
Calculating Claimable ETH
To determine the maximum amount of ETH that contract A would be able to claim from the examples above, you need to multiply the gas amount by the gas price. If the gas price for this transaction was 15 gwei (10 gwei base + 5 gwei priority), then the ETH amount contract A would be able to claim a maxiumum of 60,000 gas * 15 gwei/gas = 0.0009 ETH.
How Gas Fees and Claim Rates Are Tracked
This section contains low level details on how the Blast Gas contract works. You don’t need to read or understand this section to configure your contracts or claim your gas, but if you’re interested in a optimizing your integration, or just a bit curious, read on.
The Blast Gas contract keeps track of the integral of your contract’s unclaimed fees over time. If you had 1 ETH of unclaimed fees for 1 day, the resulting integral would be 1 ether-day. If you instead had 2 ETH of unclaimed fees for 1 week, then the integral would be 14 ether-days.
To make this integration process clear, let’s build on top of this second scenario. If you suddenly accumulated 1 additional ETH of fees, your contract’s unclaimed fee balance would be 3 ETH, but the integral would still be 14 ether-days. If you waited 1 more day, then the integral would be 17 ether-days. The Blast Gas contract uses this integral to determine the effective maturity of your unclaimed fee balance.
Blast Gas Claim Parameters
There are five parameters that determine how your contract’s accumulated ether-days relates to your claim rate:
zeroClaimRate
: your claim rate immediately after earning gas feesbaseGasSeconds
: the number of seconds your gas fees need to mature to receive thebaseClaimRate
ceilGasSeconds
: the number of seconds your gas fees need to mature to receive theceilClaimRate
Represented visually, this looks like:
The intended mainnet parameters look like this:
Custom Gas Fee Claims
The following function is the lowest level claim helper. It allows you to specify exactly how much ETH you’d like to claim and how many ether-seconds you’d like to use to contribute to your claim rate.
Claiming 1 ETH at the ceilClaimRate
requires ceilGasSeconds
ether-seconds. Providing fewer ceilGasSeconds
than this would result in an effective claim rate less than the ceilClaimRate
, based on the zeroClaimRate
and baseClaimRate
parameters.
IBlast Interface
In the interface below, when you see a function like configureX
with corresponding configureXOnBehalf
version, the difference is that configureX
configures the caller and configureXOnBehalf
configures the contract corresponding to the contractAddress
parameter.