99"""
1010
1111from dataclasses import replace
12- from typing import List , Sized
12+ from typing import List , Sequence , Sized
1313
1414from execution_testing .base_types import AccessList
1515from execution_testing .base_types .conversions import BytesConvertible
1616
1717from .....recipient_type import RecipientType
1818from ....base_fork import (
19+ AuthorizationGasInfo ,
1920 BaseFork ,
21+ RefundTypes ,
2022 TopFrameGasCalculator ,
2123 TransactionDataFloorCostCalculator ,
2224 TransactionIntrinsicCostCalculator ,
@@ -112,17 +114,39 @@ def fn(
112114 sends_value : bool = False ,
113115 recipient_type : RecipientType = RecipientType .CONTRACT ,
114116 ) -> int :
117+ # Only the state-independent base cost per authorization is
118+ # charged in the intrinsic; the state-dependent
119+ # account-creation and delegation-write costs are charged at
120+ # the top frame. Exclude the base-fork authorization cost
121+ # and re-add the base cost here.
122+ authorization_count = 0
123+ if authorization_list_or_count is not None :
124+ authorization_count = (
125+ len (authorization_list_or_count )
126+ if isinstance (authorization_list_or_count , Sized )
127+ else authorization_list_or_count
128+ )
129+
115130 intrinsic_cost : int = super_fn (
116131 calldata = calldata ,
117132 contract_creation = contract_creation ,
118133 access_list = access_list ,
119- authorization_list_or_count = authorization_list_or_count ,
134+ authorization_list_or_count = None ,
120135 return_cost_deducted_prior_execution = True ,
121136 )
137+ intrinsic_cost += (
138+ authorization_count * gas_costs .REGULAR_PER_AUTH_BASE_COST
139+ )
122140
123141 is_self_transfer = recipient_type == RecipientType .SELF
124142
125143 if contract_creation :
144+ # EIP-2780: the created account's NEW_ACCOUNT state gas
145+ # is charged at the top frame, not deducted in the
146+ # intrinsic. The base-fork intrinsic bundles it in, so
147+ # remove it here, mirroring value transfer to an empty
148+ # account whose NEW_ACCOUNT is likewise top-frame.
149+ intrinsic_cost -= gas_costs .NEW_ACCOUNT
126150 if sends_value :
127151 intrinsic_cost += gas_costs .TRANSFER_LOG_COST
128152 elif not is_self_transfer :
@@ -151,6 +175,28 @@ def fn(
151175
152176 return fn
153177
178+ @classmethod
179+ def transaction_intrinsic_state_gas (
180+ cls ,
181+ * ,
182+ contract_creation : bool = False ,
183+ authorization_count : int = 0 ,
184+ ) -> int :
185+ """
186+ Return the intrinsic state gas for a transaction.
187+
188+ Under EIP-2780 neither authorizations nor contract creation
189+ contribute intrinsic state gas: the authority account-creation
190+ and delegation-write costs and the created account's
191+ ``NEW_ACCOUNT`` are all state-dependent and charged at the top
192+ frame instead.
193+ """
194+ del contract_creation , authorization_count
195+ return super (EIP2780 , cls ).transaction_intrinsic_state_gas (
196+ contract_creation = False ,
197+ authorization_count = 0 ,
198+ )
199+
154200 @classmethod
155201 def transaction_top_frame_gas_calculator (
156202 cls ,
@@ -160,10 +206,14 @@ def transaction_top_frame_gas_calculator(
160206 transaction frame, after intrinsic gas is deducted but before
161207 the EVM dispatches.
162208
163- Charges ``COLD_ACCOUNT_ACCESS`` when the recipient is an
164- existing delegated account. The empty-recipient
165- ``NEW_ACCOUNT`` charge is state gas, returned separately by
166- ``transaction_top_frame_state_gas``.
209+ Charges the delegation-target access when the recipient is an
210+ existing delegated account: ``WARM_ACCESS`` when the target is
211+ already warm, otherwise ``COLD_ACCOUNT_ACCESS``. Each
212+ authorization whose application is the transaction's first
213+ write to its authority's leaf (``first_write``) adds
214+ ``ACCOUNT_WRITE``. The state-gas portions (empty-recipient and
215+ per-authorization ``NEW_ACCOUNT``, plus ``AUTH_BASE``) are
216+ returned separately by ``transaction_top_frame_state_gas``.
167217 """
168218 gas_costs = cls .gas_costs ()
169219
@@ -172,14 +222,24 @@ def fn(
172222 contract_creation : bool = False ,
173223 sends_value : bool = False ,
174224 recipient_type : RecipientType = RecipientType .CONTRACT ,
225+ delegation_warm : bool = False ,
226+ authorizations : Sequence [AuthorizationGasInfo ] = (),
175227 ) -> int :
176228 del sends_value
177229 if contract_creation :
178230 return 0
179231
232+ regular = 0
180233 if recipient_type == RecipientType .DELEGATION_7702 :
181- return gas_costs .COLD_ACCOUNT_ACCESS
182- return 0
234+ regular += (
235+ gas_costs .WARM_ACCESS
236+ if delegation_warm
237+ else gas_costs .COLD_ACCOUNT_ACCESS
238+ )
239+ for auth in authorizations :
240+ if auth .first_write :
241+ regular += gas_costs .ACCOUNT_WRITE
242+ return regular
183243
184244 return fn
185245
@@ -190,15 +250,43 @@ def transaction_top_frame_state_gas(
190250 contract_creation : bool = False ,
191251 sends_value : bool = False ,
192252 recipient_type : RecipientType = RecipientType .CONTRACT ,
253+ authorizations : Sequence [AuthorizationGasInfo ] = (),
193254 ) -> int :
194255 """
195256 Return the state gas charged at the top-level transaction
196- frame. Charges ``NEW_ACCOUNT`` when value is transferred to an
197- empty recipient; zero otherwise.
257+ frame. A contract creation charges the created account's
258+ ``NEW_ACCOUNT`` here (state-dependent, no longer intrinsic),
259+ assuming a fresh target. Otherwise, charges ``NEW_ACCOUNT`` when
260+ value is transferred to an empty recipient, and each
261+ authorization adds ``NEW_ACCOUNT`` when its authority's account
262+ leaf must be created and ``AUTH_BASE`` when it writes a net-new
263+ delegation indicator.
198264 """
199265 gas_costs = cls .gas_costs ()
200266 if contract_creation :
201- return 0
202- if sends_value and recipient_type == RecipientType .EMPTY_ACCOUNT :
203267 return gas_costs .NEW_ACCOUNT
204- return 0
268+ state = 0
269+ if sends_value and recipient_type == RecipientType .EMPTY_ACCOUNT :
270+ state += gas_costs .NEW_ACCOUNT
271+ for auth in authorizations :
272+ if auth .creates_account :
273+ state += gas_costs .NEW_ACCOUNT
274+ if auth .writes_delegation :
275+ state += gas_costs .AUTH_BASE
276+ return state
277+
278+ @classmethod
279+ def refund_types (cls ) -> List [RefundTypes ]:
280+ """
281+ Drop the existing-authority authorization refund.
282+
283+ EIP-2780 charges each authorization's state-dependent cost at the
284+ top frame, keyed on the authority's pre-transaction state, with no
285+ refund. The Prague-era ``AUTHORIZATION_EXISTING_AUTHORITY`` refund
286+ therefore no longer applies.
287+ """
288+ return [
289+ refund
290+ for refund in super (EIP2780 , cls ).refund_types ()
291+ if refund != RefundTypes .AUTHORIZATION_EXISTING_AUTHORITY
292+ ]
0 commit comments