Skip to content

Commit 821038a

Browse files
authored
refactored fee mechanism (#1409)
1 parent e211633 commit 821038a

File tree

2 files changed

+69
-66
lines changed

2 files changed

+69
-66
lines changed

components/Starknet/modules/architecture-and-concepts/pages/network-architecture/fee-mechanism.adoc

Lines changed: 69 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,66 @@
11
[id="gas-and-transaction-fees"]
2-
= Gas and transaction fees
2+
= Fee mechanism
33
:--auto-ids:
44

55
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 xref:network-architecture/messaging-mechanism.adoc#l1-l2-message-fees[L1 → L2 message fees].
66

7+
[#what_do_we_pay_for]
8+
== What do we price?
9+
10+
At the time of writing, the following components are contributing to the transaction fee:
11+
12+
* xref:#computation_without_builtins[Computational complexity]: The marginal cost of verifying the transaction on L1, measured in L1 gas.
13+
* xref:#onchain_data_components[Onchain data]: The cost of posting the state diffs induced by the transaction to L1 (for more details, see xref:network-architecture/data-availability.adoc[data availability]). This is measured in L1 gas or L1 data gas, depending on whether or not the L2 block in which the transaction was included uses calldata or blobs.
14+
* L2→L1 messages: Messages sent to L1 are eventually sent to the Starknet core contract as L1 calldata by the sequencer; therefore L2 transaction that send L2->L1 messages incur an additional L1 gas cost.
15+
* L2 calldata, events and code: From Starknet 0.13.1 onwards, there is a per-byte (or per felt) price for L2 payloads. For more details, see xref:#l2_calldata[].
16+
17+
== When is the fee charged?
18+
19+
The fee is charged atomically with the transaction execution on L2. The Starknet OS injects a transfer of the fee-related ERC-20, with an amount equal to the fee paid, the sender equal to the transaction submitter, and the sequencer as a receiver.
20+
21+
== Fee units
22+
23+
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.
24+
25+
For transactions prior to v3, the fee is denominated in WEI. For transactions v3 and later, the fee is denominated in STRK.
26+
27+
[#fee_limitations]
28+
== Transaction Fee limits
29+
30+
[#v3_fee_limitations]
31+
=== v3 transactions
32+
33+
With v3 transactions, users specify the max amount and max price for each resource. At the time of writing, the only available resource is L1 gas. In the future, we will introduce L2 gas which will be used to price L2 work (as opposed to only charging for the proof verification in L1 gas, which is what happens today).
34+
35+
[#deprecated_fee_limitations]
36+
=== Deprecated transactions (version < 3)
37+
38+
With older transaction versions, users specify the maximum fee that they are willing to pay for a transaction.
39+
40+
The only limitation on the sequencer, which is enforced by the Starknet OS, is that the actual fee charged is bounded by `max_fee`. While not enforced in the proof, the Starknet sequencer usually charges less than `max_fee`, as it charges in accordance with the above fee formula.
41+
42+
[id="v3-fee-estimation"]
43+
== Estimating fees
44+
45+
The fee of transactions can be estimated with using `starknet_estimateFee` API call, which is part of Starknet's API v0.7.0 and above. For more information, see the link:https://github.com/starkware-libs/starknet-specs/blob/v0.7.1/api/starknet_api_openrpc.json#L612[Starknet JSON RPC specification]. For more information on how to construct the appropriate `resource_bounds` based on the response of `starknet_estimateFee`, see link:https://community.starknet.io/t/starknet-v0-13-1-pre-release-notes/113664#sdkswallets-how-to-use-the-new-fee-estimates-7[How to use the new fee estimates?] on the Starknet community forum.
46+
47+
[#fee_calculation]
48+
== Fee calculation
49+
750
[#overall_fee]
8-
== Overall transaction fee
51+
=== Overall
52+
53+
This section shows the formula for determining a transaction's fee. The following sections describe how this formula was derived.
54+
55+
[#blobs-vs-calldata]
56+
==== Blobs vs. calldata
957

1058
Starting with Starknet v0.13.1, Starknet distinguishes between blocks whose state diffs are sent to L1 as calldata and blocks whose state diffs are sent to L1 as blobs. The `l1_da_mode` property in the Starknet block header contains this information. The cost of computation remains the same on both options, but the cost related to data availability differs.
1159

1260
[#overall_fee_blob]
13-
=== Overall transaction fee with blobs
61+
==== Overall fee with blobs
1462

15-
This section shows the formula for determining a transaction's fee. The following sections describe how this formula was derived.
16-
17-
The following formula describes the overall fee, stem:[F], for a transaction:
63+
The following formula describes the overall fee, stem:[F], for a transaction in blocks whose state diffs are sent to L1 as blobs:
1864

1965
[stem]
2066
++++
@@ -52,11 +98,9 @@ For more information, see xref:#l_2-l_1_messages[].
5298
* stem:[$\text{felt_size_in_bytes}$] is 32, which is the number of bytes required to encode a single STARK field element.
5399

54100
[#overall_fee_calldata]
55-
=== Overall transaction fee with calldata
56-
57-
This section shows the formula for determining a transaction's fee. The following sections describe how this formula was derived.
101+
==== Overall fee with calldata
58102

59-
The following formula describes the overall fee, stem:[F], for a transaction:
103+
The following formula describes the overall fee, stem:[F], for a transaction in blocks whose state diffs are sent to L1 as calldata:
60104

61105
[stem]
62106
++++
@@ -84,55 +128,20 @@ where:
84128
* stem:[$240$] is the gas discount for updating the sender's balance, for the derivation of this number see xref:#storage_updates[].
85129
* stem:[$\text{contract_update_discount}$] is 312 gas, for the derivation of this discount see xref:#storage_updates[].
86130

87-
== When is the fee charged?
88-
89-
The fee is charged atomically with the transaction execution on L2. The Starknet OS injects a transfer of the fee-related ERC-20, with an amount equal to the fee paid, the sender equal to the transaction submitter, and the sequencer as a receiver.
90-
91-
[#fee_limitations]
92-
== Transaction Fee limits
93-
94-
[#v3_fee_limitations]
95-
=== v3 transactions
96-
97-
With v3 transactions, users specify the max amount and max price for each resource. At the time of writing, the only available resource is L1 gas. In the future, we will introduce L2 gas which will be used to price L2 work (as opposed to only charging for the proof verification in L1 gas, which is what happens today).
98-
99-
[#deprecated_fee_limitations]
100-
=== Deprecated transactions (version < 3)
101-
102-
With older transaction versions, users specify the maximum fee that they are willing to pay for a transaction.
103-
104-
The only limitation on the sequencer, which is enforced by the Starknet OS, is that the actual fee charged is bounded by `max_fee`. While not enforced in the proof, the Starknet sequencer usually charges less than `max_fee`, as it charges in accordance with the above fee formula.
105-
106-
[#what_do_we_pay_for]
107-
== What do we price
108-
109-
At the time of writing, the following components are contributing to the transaction fee:
110-
111-
* xref:#computation_without_builtins[Computational complexity]: The marginal cost of verifying the transaction on L1, measured in L1 gas.
112-
* xref:#onchain_data_components[Onchain data]: The cost of posting the state diffs induced by the transaction to L1 (for more details, see xref:network-architecture/data-availability.adoc[data availability]). This is measured in L1 gas or L1 data gas, depending on whether or not the L2 block in which the transaction was included uses calldata or blobs.
113-
* L2→L1 messages: Messages sent to L1 are eventually sent to the Starknet core contract as L1 calldata by the sequencer; therefore L2 transaction that send L2->L1 messages incur an additional L1 gas cost.
114-
* L2 calldata, events and code: From Starknet 0.13.1 onwards, there is a per-byte (or per felt) price for L2 payloads. For more details, see xref:#l2_calldata[].
115-
116-
== Fee units
117-
118-
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.
119-
120-
For transactions prior to v3, the fee is denominated in WEI. For transactions v3 and later, the fee is denominated in STRK.
121-
122-
[#fee_calculation]
123-
== Fee calculation
124-
125131
[#calculation_of_gas_costs]
126-
=== Calculation of gas prices
132+
=== Gas
127133

128134
Every 60 seconds, Starknet samples the base price of gas and data gas on L1.
129135

130136
The price of gas on Starknet is set to the average of the last 60 gas price samples, plus 1 gwei.
131137

132138
The price of data gas on Starknet is set to the average of the last 60 data gas price samples. The data gas price on Ethereum is derived from the value of `excess_blob_gas`. For more information, see link:https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md[EIP-4844].
133139

140+
[#computation]
141+
=== Computation
142+
134143
[#computation_without_builtins]
135-
=== Computation without builtins
144+
==== Without builtins
136145

137146
Let's analyze the correct metric for measuring transaction complexity. For simplicity, we will ignore Cairo's builtins, and address them later.
138147

@@ -144,7 +153,7 @@ Tracking the execution trace length associated with each transaction is simple.
144153
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 "no-builtins" assumption kicks in: Pedersen occupies more trace cells than addition. Therefore, in a world without builtins, the fee of the transaction stem:[$tx$] is correlated with stem:[$\text{TraceCells}[tx\]/L$].
145154

146155
[#computation_with_builtins]
147-
=== Computation with builtins
156+
==== With builtins
148157

149158
In the Cairo execution trace each builtin has its own slot, which is important to consider when determining the fee.
150159

@@ -172,7 +181,7 @@ This safeguards fairness and prevents manipulation, ensuring integrity in proof
172181
====
173182

174183
[#calculation_of_computation_costs]
175-
=== Calculation of computation costs
184+
==== Overall
176185

177186
For each transaction, the sequencer calculates a vector, `CairoResourceUsage`, that contains the following:
178187

@@ -192,13 +201,12 @@ The sequencer charges only according to the limiting factor. Therefore the fee i
192201

193202
where stem:[$k$] enumerates the Cairo resource components, that is the number of Cairo steps and builtins used.
194203

195-
The weights are listed in the table xref:#gas_cost_per_cairo_step_or_builtin_step[].
204+
The weights are listed in the following table:
196205

197206
[#gas_cost_per_cairo_step_or_builtin_step]
198-
.Amount of gas used per Cairo step or per each time a Cairo builtin is applied
199-
[width=80%,cols="1,2",options="header",stripes=even]
207+
[%autowidth.stretch,options="header"]
200208
|===
201-
| Step or builtin | Gas cost
209+
| Resource | Gas cost
202210

203211
| Cairo step | 0.0025 gas/step
204212
| Pedersen | 0.08 gas/application
@@ -212,7 +220,7 @@ The weights are listed in the table xref:#gas_cost_per_cairo_step_or_builtin_ste
212220

213221

214222
[id="onchain_data_components"]
215-
=== Onchain data components
223+
=== Onchain data
216224

217225
The onchain data associated with a transaction is composed of three parts
218226

@@ -222,7 +230,7 @@ The onchain data associated with a transaction is composed of three parts
222230
* Declared classes (only relevant for `DECLARE` transactions, and adds two additional words)
223231

224232
[#storage_updates]
225-
=== Onchain data: Storage updates
233+
==== Storage updates
226234

227235
Whenever a transaction updates some value in the storage of some contract, the following data is sent to L1:
228236

@@ -271,7 +279,7 @@ For example, if different transactions within the same block update the same sto
271279
====
272280

273281
[#l_2-l_1_messages]
274-
=== Onchain data: L2->L1 messages
282+
==== L2->L1 messages
275283

276284
When a transaction that raises the `send_message_to_l1` syscall is included in a state update, the following data reaches L1:
277285

@@ -301,7 +309,7 @@ Where:
301309
* stem:[$\text{l1_storage_write_cost}$] is 20,000 gas per message which is paid in order to store the message hash on the Starknet core contract. This recording of the message is what later enables the intended L1 contract to consume the message.
302310

303311
[#deployed_contracts]
304-
=== Onchain data: Deployed contracts
312+
==== Deployed contracts
305313

306314
When a transaction that raises the `deploy` syscall is included in a state update, the following data reaches L1:
307315

@@ -312,7 +320,7 @@ When a transaction that raises the `deploy` syscall is included in a state updat
312320
The first two elements are counted in the number of unique modified contracts, denoted by stem:[$n$] throughout this page. So the only additional word comes from publishing the class hash, which adds 551 gas. For more information, see stem:[$\text{da_calldata_cost}$] in the xref:#overall_fee[final formula].
313321

314322
[#l2_calldata]
315-
=== L2 payloads: calldata, events, and code
323+
=== L2 payloads
316324

317325
As of Starknet v0.13.1 onwards, L2 data is taken into account during pricing. This includes:
318326

components/Starknet/modules/architecture-and-concepts/pages/network-architecture/transactions.adoc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -465,11 +465,6 @@ The generator used in the ECDSA algorithm is stem:[G=\left(g_x, g_y\right)] wher
465465

466466
stem:[g_x=874739451078007766457464989774322083649278607533249481151382481072868806602] stem:[g_y=152666792071518830868575557812948353041420400780739481342941381225525861407]
467467

468-
[id="v3-fee-estimation"]
469-
== v3 transaction fee estimation
470-
471-
Estimate the fees of transactions with the `starknet_estimateFee` API call, which is part of Starknet's API v0.7.0 and above. For more information, see the link:https://github.com/starkware-libs/starknet-specs/blob/v0.7.1/api/starknet_api_openrpc.json#L612[Starknet JSON RPC specification]. For more information on how to construct the appropriate `resource_bounds` based on the response of `starknet_estimateFee`, see link:https://community.starknet.io/t/starknet-v0-13-1-pre-release-notes/113664#sdkswallets-how-to-use-the-new-fee-estimates-7[How to use the new fee estimates?] on the Starknet community forum.
472-
473468
[id="chain-id"]
474469
== Chain ID
475470

0 commit comments

Comments
 (0)