@@ -110,14 +110,26 @@ where
110110 ctx. tx ( ) . compression_ratio ( ) ,
111111 ctx. tx ( ) . compressed_size ( ) ,
112112 ) ;
113+
114+ // Optionally check balance covers 2x L1 cost (1 unit charged + 1 unit buffer)
115+ let l1_cost_with_optional_buffer = if ctx. cfg ( ) . is_l1_data_fee_buffer_required ( ) {
116+ tx_l1_cost. saturating_add ( tx_l1_cost)
117+ } else {
118+ tx_l1_cost
119+ } ;
120+
113121 let caller_account = ctx. journal_mut ( ) . load_account ( caller) ?;
114- if tx_l1_cost. gt ( & caller_account. info . balance ) {
122+
123+ // Ensure caller has enough balance to cover L1 cost + optional buffer
124+ if l1_cost_with_optional_buffer. gt ( & caller_account. info . balance ) {
115125 return Err ( InvalidTransaction :: LackOfFundForMaxFee {
116- fee : tx_l1_cost . into ( ) ,
126+ fee : l1_cost_with_optional_buffer . into ( ) ,
117127 balance : caller_account. info . balance . into ( ) ,
118128 }
119129 . into ( ) ) ;
120130 }
131+
132+ // Deduct only actual L1 cost (buffer is NOT deducted)
121133 caller_account. data . info . balance =
122134 caller_account. data . info . balance . saturating_sub ( tx_l1_cost) ;
123135 }
@@ -440,4 +452,38 @@ mod tests {
440452
441453 Ok ( ( ) )
442454 }
455+
456+ #[ test]
457+ fn test_validate_l1_cost_buffer_required ( ) -> Result < ( ) , Box < dyn core:: error:: Error > > {
458+ // With buffer enabled via CfgEnv: 1x L1_cost should fail
459+ let ctx = context ( )
460+ . with_funds ( MIN_TRANSACTION_COST + L1_DATA_COST )
461+ . modify_cfg_chained ( |cfg| cfg. require_l1_data_fee_buffer = true ) ;
462+ let mut evm = ctx. build_scroll ( ) ;
463+ let handler = ScrollHandler :: < _ , EVMError < _ > , EthFrame < _ > > :: new ( ) ;
464+ assert ! ( matches!(
465+ handler. pre_execution( & mut evm) ,
466+ Err ( EVMError :: Transaction ( InvalidTransaction :: LackOfFundForMaxFee { .. } ) )
467+ ) ) ;
468+
469+ // With buffer enabled: 2x L1_cost should pass
470+ let ctx = context ( )
471+ . with_funds ( MIN_TRANSACTION_COST + L1_DATA_COST + L1_DATA_COST )
472+ . modify_cfg_chained ( |cfg| cfg. require_l1_data_fee_buffer = true ) ;
473+ let mut evm = ctx. build_scroll ( ) ;
474+ assert ! ( handler. pre_execution( & mut evm) . is_ok( ) ) ;
475+
476+ Ok ( ( ) )
477+ }
478+
479+ #[ test]
480+ fn test_validate_l1_cost_no_buffer_by_default ( ) -> Result < ( ) , Box < dyn core:: error:: Error > > {
481+ // Without buffer: 1x L1_cost should pass
482+ let ctx = context ( ) . with_funds ( MIN_TRANSACTION_COST + L1_DATA_COST ) ;
483+ let mut evm = ctx. build_scroll ( ) ;
484+ let handler = ScrollHandler :: < _ , EVMError < _ > , EthFrame < _ > > :: new ( ) ;
485+ assert ! ( handler. pre_execution( & mut evm) . is_ok( ) ) ;
486+
487+ Ok ( ( ) )
488+ }
443489}
0 commit comments