22
33import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services' ;
44import { ethers , Transaction } from 'ethers' ;
5+ import { Logger } from 'pino' ;
56
67import { prepend0x } from '../formatters' ;
78import { MirrorNodeClient } from './clients' ;
@@ -205,7 +206,7 @@ export class Precheck {
205206 */
206207 gasLimit ( tx : Transaction ) : void {
207208 const gasLimit = Number ( tx . gasLimit ) ;
208- const intrinsicGasCost = Precheck . transactionIntrinsicGasCost ( tx . data ) ;
209+ const intrinsicGasCost = Precheck . transactionIntrinsicGasCost ( tx ) ;
209210
210211 if ( gasLimit > constants . MAX_TRANSACTION_FEE_THRESHOLD ) {
211212 throw predefined . GAS_LIMIT_TOO_HIGH ( gasLimit , constants . MAX_TRANSACTION_FEE_THRESHOLD ) ;
@@ -215,30 +216,67 @@ export class Precheck {
215216 }
216217
217218 /**
218- * Calculates the intrinsic gas cost based on the number of bytes in the data field.
219- * Using a loop that goes through every two characters in the string it counts the zero and non-zero bytes.
220- * Every two characters that are packed together and are both zero counts towards zero bytes.
221- * @param data - The data with the bytes to be calculated
222- * @returns The intrinsic gas cost.
223- * @private
219+ * Calculates the intrinsic gas cost based on EIP-7623 floor pricing rules.
220+ *
221+ * The intrinsic gas is calculated as:
222+ * max(standardIntrinsicGas, floorPrice)
223+ *
224+ * Where:
225+ * - standardIntrinsicGas = TX_BASE_COST + calldata cost + contract creation cost + auth list cost
226+ * - floorPrice = TX_BASE_COST + TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata
227+ * - tokens_in_calldata = zero_bytes + non_zero_bytes * 4
228+ *
229+ * @see https://eips.ethereum.org/EIPS/eip-7623
230+ * @see https://eips.ethereum.org/EIPS/eip-7702
231+ * @see https://eips.ethereum.org/EIPS/eip-3860
232+ *
233+ * @param tx - The transaction object
234+ * @returns The intrinsic gas cost (maximum of standard cost and floor price).
224235 */
225- public static transactionIntrinsicGasCost ( data : string ) : number {
226- const trimmedData = data . replace ( '0x' , '' ) ;
227-
228- let zeros = 0 ;
229- let nonZeros = 0 ;
230- for ( let index = 0 ; index < trimmedData . length ; index += 2 ) {
231- const bytes = trimmedData [ index ] + trimmedData [ index + 1 ] ;
232- if ( bytes === '00' ) {
233- zeros ++ ;
236+ public static transactionIntrinsicGasCost ( tx : Transaction ) : number {
237+ const calldata = tx . data . replace ( '0x' , '' ) ;
238+
239+ // Count zero and non-zero bytes in calldata
240+ let zeroBytes = 0 ;
241+ let nonZeroBytes = 0 ;
242+ for ( let index = 0 ; index < calldata . length ; index += 2 ) {
243+ const byte = calldata [ index ] + calldata [ index + 1 ] ;
244+ if ( byte === '00' ) {
245+ zeroBytes ++ ;
234246 } else {
235- nonZeros ++ ;
247+ nonZeroBytes ++ ;
236248 }
237249 }
238250
239- return (
240- constants . TX_BASE_COST + constants . TX_DATA_ZERO_COST * zeros + constants . ISTANBUL_TX_DATA_NON_ZERO_COST * nonZeros
241- ) ;
251+ // EIP-7623: tokens_in_calldata = zero_bytes + non_zero_bytes * 4
252+ const tokensInCalldata = zeroBytes + nonZeroBytes * 4 ;
253+
254+ // Standard intrinsic gas cost (calldata pricing: 4 gas per zero byte, 16 gas per non-zero byte)
255+ let standardIntrinsicGas =
256+ constants . TX_BASE_COST +
257+ constants . TX_DATA_ZERO_COST * zeroBytes +
258+ constants . ISTANBUL_TX_DATA_NON_ZERO_COST * nonZeroBytes ;
259+
260+ // EIP-3860: Add contract creation cost if tx.to is null (contract deployment)
261+ const isContractCreation = tx . to === null || tx . to === undefined ;
262+ if ( isContractCreation ) {
263+ const calldataLengthInBytes = calldata . length / 2 ;
264+ const words = Math . ceil ( calldataLengthInBytes / 32 ) ;
265+ standardIntrinsicGas += constants . TX_CREATE_EXTRA + constants . INITCODE_WORD_COST * words ;
266+ }
267+
268+ // EIP-7702: Add authorization list cost for type 4 transactions
269+ // Note: ethers.js Transaction type may not have authorizationList property yet
270+ const authorizationList = ( tx as any ) . authorizationList ;
271+ if ( tx . type === 4 && authorizationList && Array . isArray ( authorizationList ) ) {
272+ standardIntrinsicGas += constants . PER_EMPTY_ACCOUNT_COST * authorizationList . length ;
273+ }
274+
275+ // EIP-7623: Floor price for calldata-heavy transactions
276+ const floorPrice = constants . TX_BASE_COST + constants . TOTAL_COST_FLOOR_PER_TOKEN * tokensInCalldata ;
277+
278+ // Return the maximum of standard intrinsic gas and floor price
279+ return Math . max ( standardIntrinsicGas , floorPrice ) ;
242280 }
243281
244282 /**
0 commit comments