Gas and transaction fees
This section describes fees that are paid on L2 starting in Starknet 0.13.0. For information about messaging fees that are paid on L1, see L1 → L2 message fees.
Overall transaction fee
This section shows the formula for determining a transaction’s fee. The following sections describe how this formula was derived.
The following formula describes the overall fee, \(F\), for a transaction:
where:

\(v\) is a vector that represents resource usage, where each of its entries, \(v_k\), corresponds to different resource types: Cairo steps and number of applications of each builtin.
For more information see Calculation of computation costs.

\(n\) is the number of unique contracts updated, which also includes changes to classes of existing contracts and contract deployments, even if the storage of the newly deployed contract is untouched. In other words, \(n\ge\ell\). Notice that \(n\ge 1\) always holds, because the fee token contract is always updated, which does not incur any fee.

\(m\) is the number of values updated, not counting multiple updates for the same key. Notice that \(m\ge 1\) always holds, because the sequencer’s balance is always updated, which does not incur any fee.

\(t\) is the number of L2→L1 messages sent, where the corresponding payload sizes are denoted by \(q_1,...,q_t\).

\(\ell\) is the number of contracts whose class was changed, which happens on contract deployment and when applying the
replace_class
syscall. 
\(w\) is the
CairoResourceFeeWeights
vector. 
\(\text{da_calldata_cost}\) is 551 gas per 32byte word. This cost is derived as follows:

512 gas per 32byte word for calldata.

~100 gas for onchain hashing that happens for every sent word.

a 10% discount, because the sequencer does not incur additional costs for repeated updates to the same storage slot within a single block.


\(\text{message_calldata_cost}\) is 512 gas per 32byte word. For more details, see Onchain data: L2→L1 messages.

\(240\) is the gas discount for updating the sender’s balance, for the derivation of this number see Onchain data: Storage updates.

\(\text{contract_update_discount}\) is 312 gas, for the derivation of this discount see Onchain data: Storage updates.

\(\text{storage_write_cost}\) is 20,000 gas, the cost of allocating a new storage cell on Ethereum.
When is the fee charged?
The fee is charged atomically with the transaction execution on L2. The Starknet OS injects a transfer of the feerelated ERC20, with an amount equal to the fee paid, the sender equal to the transaction submitter, and the sequencer as a receiver.
Fee limitations
Users can specify the maximum fee that they are willing to pay for a transaction.
v3 transactions use max_amount
and max_price_per_unit
to set the maximum amount of a resource that can be used on L1,
and the maximum price per unit of that resource that the user is willing to pay. These fields replace the max_fee
field.
At the time of writing, the only resource involved is the marginal verification cost of the transaction, measured in units of L1 gas. An additional resource, 
For transaction versions before v3 transactions, the max_fee
field specifies the maximum fee.
The only limitation on the sequencer, which is enforced by the Starknet OS, is that the actual fee charged is bounded by max_fee
, but for now, StarkWare’s sequencer only charges the fee required to cover the proof cost, which is potentially less than the maximum fee.
Currently, the sequencer only takes into account L1 costs involving proof submission. The following two components affect the L1 footprint of a transaction:

Computational complexity: A transaction’s portion of the proof verification cost is proportional to its complexity.

Onchain data: L1 calldata cost originating from data availability and L2→L1 messages.
Fee units
Each transaction is associated with an estimate of the amount of gas used. Combining this estimate with the price of gas yields the estimated fee.
For transactions prior to v3, the fee is denominated in WEI. For transactions v3 and later, the fee is denominated in STRK.
Fee calculation
Computation without builtins
Let’s analyze the correct metric for measuring transaction complexity. For simplicity, we will ignore Cairo’s builtins, and address them later.
A Cairo program execution yields an execution trace. When proving a Starknet block, we aggregate all the transactions appearing in that block to the execution trace.
Starknet’s prover generates proofs for execution traces, up to some maximal length \(L\), derived from the specs of the proving machine and the desired proof latency.
Tracking the execution trace length associated with each transaction is simple. Each assertion over field elements, such as verifying addition/multiplication over the field, requires the same, constant number of trace cells, which is where our "nobuiltins" assumption kicks in: Pedersen occupies more trace cells than addition. Therefore, in a world without builtins, the fee of the transaction \(tx\) is correlated with \(\text{TraceCells}[tx]/L\).
Computation with builtins
In the Cairo execution trace each builtin has its own slot, which is important to consider when determining the fee.
For example, consider that the prover can process a trace with the following limits:
up to 500,000,000 Cairo Steps  up to 20,000,000 Pedersen hashes  up to 4,000,000 signature verifications  up to 10,000,000 range checks 

The proof is closed and sent to L1 when any of these slots is filled.
Suppose that a transaction uses 10,000 Cairo steps and 500 Pedersen hashes. At most 40,000 such transactions can fit into the hypothetical trace (20,000,000/500). Therefore, its gas price correlates with 1/40,000 of the cost of submitting proof.
Notice that this estimate ignores the number of Cairo steps, as it is not the limiting factor, since 500,000,000/10,000 > 20,000,000/500.
With this example in mind, it is possible to formulate the exact fee associated with L2 computation.
The allocation of resources among builtin operations must be predetermined; it is not possible to decide, postexecution, to include only 20,000,001 Pedersen hashes without additional components. This safeguards fairness and prevents manipulation, ensuring integrity in proof generation and fee determination. 
Calculation of computation costs
For each transaction, the sequencer calculates a vector, CairoResourceUsage
, that contains the following:

The number of Cairo steps.

The number of applications of each Cairo builtin. For example, five range checks and two Pedersen hashes.
The sequencer crosses this information with the CairoResourceFeeWeights
vector. For each resource type, either a Cairo step or a specific builtin application, CairoResourceFeeWeights
has an entry that specifies the relative gas cost of that component in the proof.
Going back to the above example, if the cost of submitting a proof with 20,000,000 Pedersen hashes is roughly 5m gas, then the weight of the Pedersen builtin is 0.25 gas per application (5,000,000/20,000,000). The sequencer has a predefined weights vector, in accordance with the proof parameters.
The sequencer charges only according to the limiting factor. Therefore the fee is correlated with:
where \(k\) enumerates the Cairo resource components, that is the number of Cairo steps and builtins used.
The weights are listed in the table Amount of gas used per Cairo step or per each time a Cairo builtin is applied.
Step or builtin  Gas cost 

Cairo step 
0.005 gas/step 
Pedersen 
0.16 gas/application 
Poseidon 
0.16 gas/application 
Range check 
0.08 gas/application 
ECDSA 
10.24 gas/application 
Keccak 
10.24 gas/application 
Bitwise 
0.32 gas/application 
EC_OP 
5.12 gas/application 
Onchain data components
The onchain data associated with a transaction is composed of three parts

Storage updates

L2→L1 messages

Deployed contracts
Onchain data: Storage updates
Whenever a transaction updates some value in the storage of some contract, the following data is sent to L1:

two 32byte words per contract

two 32byte words for every updated storage value
For information on the exact data and its construction, see Data availability.
Only the most recent value reaches L1. So the transaction’s fee only depends on the number of unique storage updates. If the same storage cell is updated multiple times within the transaction, the fee remains that of a single update. 
The following formula describes the storage update fee for a transaction:
where:

\(n\) is the number of unique contracts updated, which also includes changes to classes of existing contracts and contract deployments, even if the storage of the newly deployed contract is untouched. In other words, \(n\ge\ell\). Notice that \(n\ge 1\) always holds, because the fee token contract is always updated at the end of each transaction, in order to update the sequencer’s and the sender’s balances. The fee token contract update is not taken into account when computing the fee.

\(m\) is the number of values updated, not counting multiple updates for the same key. Notice that \(m\ge 1\) always holds, because the sequencer’s balance is updated at the end of each transaction. The sequencer’s balance update is not taken into account when computing the fee.

\(\text{contract_update_discount}\) is 312 gas, which is discounted for every updated contract. This discount is a result of the fact that out of the \(2n\) words caused by updating contracts, \(n\) words are short, including at most 6 nonzero bytes:

three bytes for the nonce

two bytes for the number of storage updates

one byte for the class information flag
Taking into account that zero bytes only cost 4 gas, the cost difference between a full 32byte word, which does not contain zeros, and a word with only six nonzero bytes is \(32\cdot16(6\cdot16+26\cdot4)=312\).


\(240\) is the gas discount for updating the sender’s balance, and is derived by assuming the balance requires at most 12 nonzero bytes, which is enough for 1.2B ETH or STRK, resulting in the following discount: \(512(20\cdot4+12\cdot16)=240\).
Improvements to the above pessimistic estimation might be gradually implemented in future versions of Starknet. For example, if different transactions within the same block update the same storage cell, there is no need to charge for both transactions, because only the last value reaches L1. In the future, Starknet might include a refund mechanism for such cases. 
Onchain data: L2→L1 messages
When a transaction that raises the send_message_to_l1
syscall is included in a state update, the following data reaches L1:

L2 sender address

L1 destination address

Payload size

Payload (list of field elements)
Consequently, the gas cost associated with a single L2→L1 message is:
Where \(\text{da_calldata_cost}\) is 551 gas, and \(\text{message_calldata_cost}\) is 512 gas. Messages appear twice in the fee formula, and pay both in \(\text{da_calldata_cost}\) and \(\text{message_calldata_cost}\), because they are sent to Ethereum twice: once to the STARK verifier contract, where the additional hashing cost is incurred, and once when it is sent to the Starknet Core Contract as part of the state update transaction.
Onchain data: Deployed contracts
When a transaction that raises the deploy
syscall is included in a state update, the following data reaches L1:

contract address

number of storage updates and the new nonce

class hash
The first two elements are counted in the number of unique modified contracts, denoted by \(n\) throughout this page. So the only additional word comes from publishing the class hash, which adds 551 gas. For more information, see \(\text{da_calldata_cost}\) in the final formula.