StarkNet Alpha launched on Mainnet a few weeks ago, without a transaction fee mechanism, i.e., with L1 gas costs effectively subsidized by StarkWare. We present a method to estimate and collect transaction fees in the current StarkNet Alpha version.
As the network evolves, we expect the way fees are evaluated and collected to evolve as well. We present here a first approximation of calculation and method for collecting fees, with the purpose of refining it as StarkNet evolves. Knowing these parameters will help builders to better plan when designing their StarkNet dApp.
Transaction Cost in StarkNet
Generally, a transaction’s cost depends on several factors:
- Data - the amount of data sent to L1:
1.1 State diff information
1.2 Number of L2 → L1 messages
1.3 The L1 → L2 messages that were consumed
These are sent as call data to L1 in different StarkNet L1 transactions. - Cost of computation - this is the count of trace steps, including the OS steps, i.e., system calls.
It includes:- L1 proof verification
- L2 computation cost (SHARP)
- Storage cost: how many read/write operations were performed during the transaction execution.
- L2 network transmission cost for the transaction: its call data and events emitted.
Current Mechanism
At a high level, the current solution lets users/applications use the sequencer to get an estimate for the fee required to accept the transaction:
A user asks a new service (”estimate gas service”) to estimate the fee required to run the given transaction at the current state. The service estimates and returns the result based on the formula below. This service is exposed by the sequencer. Internally, it will try to estimate the resources consumed by processing the transaction based on the current StarkNet state.
As explained below, the estimation will be a first and somewhat rough approximation of the transaction cost. The fee itself will be specified in ETH - the payment currency - with the gas price provided as a parameter of the estimated service.
At this point, the user can choose whether to accept the estimated fee or mark it up/down. The user then signs the fee she’s willing to pay, as part of the transaction and sends it to the sequencer to be executed and added to a future block.
The Cost Formula
Our first approximation for the fee considers some of the external costs that the service provider (sequencer+prover) pays, like L1 gas for data and computation (items 1 and 2.1 above). The fee calculated may include a markup to compensate for L1 gas cost fluctuations.
At this point, we neglect L2 costs for proof creation, storage operations, and network (items 2.2, 3, 4 above).
The formula, therefore, for calculating the cost, at this phase, will be:
where:
- gas\_price is the gas price, ETH per gas unit, configured in the service.
This may be later exposed for querying through an API. - gas\_per\_byte is the gas cost of storing a single byte as call data, currently 16 gas per byte.
- \sharp(msgs) is the number of messages sent by the transaction from L2 to L1.
- bytes\_per\_msg is the number of bytes of the message. This could of course be different per message, so we may use an average message size for all messages.
The 5000 extra gas is for updating an internal counter. - \sharp(state\_diff\_items) is the number of state diffs done by this transaction.
The 2 \cdot 31 factor comes from writing two field elements per storage write, each field element consisting of 31 bytes. - gas\_per\_step is a constant pricing for a single step validation (on L1).
steps_{txn} is the number of steps for this function’s execution.
The main factor driving the cost is the L1 data component. This includes the state diff and the messages. In other words, the computation cost will be negligible compared to the cost of data posted on L1 (gas\_per\_step << gas\_per\_byte).
The Road Ahead
We see several possible ways this mechanism might change in the future.
First, we expect to make several optimizations that will reduce the cost. Specifically, when several transactions share the same proof, they share some overhead and therefore might cost less to produce and verify. In such a case, some reduction may be applied to the fees estimated for the original transactions.
Introducing volition for data availability (i.e. off-chain data availability) should provide another opportunity for cost savings, and we expect we will be able to factor it into the cost estimation. Storage modifications done for L2-based data may bear different costs.
When the network becomes decentralized, we expect other mechanisms and market designs to apply, the details of which are currently being researched. An example would be to make fee auction possible - users will specify the fee as some linear combination of the different cost components, and allow the sequencer to pick the transaction with the most beneficial fee.
Finally, introducing fee abstraction will allow network participants to specify fees in tokens other than ETH.