@@ -1374,6 +1374,218 @@ def analyze_etherfi_penalties(tx_df, penalty_multiplier):
13741374 return results
13751375
13761376
1377+ # ============================================================================
1378+ # PARAMETER COMPARISON ANALYSIS
1379+ # ============================================================================
1380+
1381+ def compare_parameters (current_params , commit_scalar , blob_scalar , penalty_multiplier , tx_df , batch_df ):
1382+ """
1383+ Compare derived parameters against current on-chain parameters.
1384+
1385+ Computes per-tx L1 fees under both old and new parameter sets using:
1386+ effective_size = compressed_tx_size + compressed_tx_size² / penalty_factor
1387+ L1_fee = (commit_scalar * l1_base_fee + blob_scalar * l1_blob_base_fee) * effective_size
1388+
1389+ Args:
1390+ current_params: Dict with current on-chain parameters from read_current_gas_parameters()
1391+ commit_scalar: Newly derived commit scalar
1392+ blob_scalar: Newly derived blob scalar
1393+ penalty_multiplier: Newly derived penalty multiplier
1394+ tx_df: Transaction DataFrame
1395+ batch_df: Batch DataFrame with L1 costs
1396+ """
1397+ print ("\n " + "=" * 60 )
1398+ print ("PARAMETER COMPARISON ANALYSIS" )
1399+ print ("=" * 60 )
1400+
1401+ # Extract current (old) parameters
1402+ old_commit_scalar = current_params ['commit_scalar' ]
1403+ old_blob_scalar = current_params ['blob_scalar' ]
1404+ old_penalty_factor = current_params ['penalty_factor' ]
1405+
1406+ new_commit_scalar = commit_scalar
1407+ new_blob_scalar = blob_scalar
1408+ new_penalty_factor = penalty_multiplier
1409+
1410+ # --- Analysis 1: Fee Comparison (Old vs New) ---
1411+ print ("\n " + "-" * 60 )
1412+ print ("Analysis 1: Fee Comparison (Old vs New)" )
1413+ print ("-" * 60 )
1414+
1415+ print (f"\n Parameter Comparison:" )
1416+ print (f" { 'Parameter' :<25} { 'Current' :>15} { 'New' :>15} { 'Change' :>15} " )
1417+ print (f" { '-' * 25 } { '-' * 15 } { '-' * 15 } { '-' * 15 } " )
1418+ print (f" { 'commit_scalar' :<25} { old_commit_scalar :>15.4f} { new_commit_scalar :>15.4f} { new_commit_scalar - old_commit_scalar :>+15.4f} " )
1419+ print (f" { 'blob_scalar' :<25} { old_blob_scalar :>15.4f} { new_blob_scalar :>15.4f} { new_blob_scalar - old_blob_scalar :>+15.4f} " )
1420+ print (f" { 'penalty_factor' :<25} { old_penalty_factor :>15.0f} { new_penalty_factor :>15.0f} { new_penalty_factor - old_penalty_factor :>+15.0f} " )
1421+
1422+ # Calculate effective_size and fees under both parameter sets
1423+ df = tx_df .copy ()
1424+
1425+ df ['old_effective_size' ] = df ['compressed_tx_size' ] + df ['compressed_tx_size' ]** 2 / old_penalty_factor
1426+ df ['new_effective_size' ] = df ['compressed_tx_size' ] + df ['compressed_tx_size' ]** 2 / new_penalty_factor
1427+
1428+ df ['old_fee' ] = (old_commit_scalar * df ['l1_base_fee' ] + old_blob_scalar * df ['l1_blob_base_fee' ]) * df ['old_effective_size' ]
1429+ df ['new_fee' ] = (new_commit_scalar * df ['l1_base_fee' ] + new_blob_scalar * df ['l1_blob_base_fee' ]) * df ['new_effective_size' ]
1430+
1431+ df ['fee_change' ] = df ['new_fee' ] - df ['old_fee' ]
1432+ df ['fee_change_pct' ] = df ['fee_change' ] / df ['old_fee' ] * 100
1433+
1434+ print (f"\n Per-Transaction Fee Change Statistics:" )
1435+ print (f" { 'Metric' :<20} { 'Absolute (wei)' :>20} { 'Percentage' :>15} " )
1436+ print (f" { '-' * 20 } { '-' * 20 } { '-' * 15 } " )
1437+ print (f" { 'Mean' :<20} { df ['fee_change' ].mean ():>+20,.0f} { df ['fee_change_pct' ].mean ():>+14.2f} %" )
1438+ print (f" { 'Median' :<20} { df ['fee_change' ].median ():>+20,.0f} { df ['fee_change_pct' ].median ():>+14.2f} %" )
1439+ print (f" { 'P95' :<20} { df ['fee_change' ].quantile (0.95 ):>+20,.0f} { df ['fee_change_pct' ].quantile (0.95 ):>+14.2f} %" )
1440+ print (f" { 'P99' :<20} { df ['fee_change' ].quantile (0.99 ):>+20,.0f} { df ['fee_change_pct' ].quantile (0.99 ):>+14.2f} %" )
1441+
1442+ paying_more = (df ['fee_change' ] > 0 ).sum ()
1443+ paying_less = (df ['fee_change' ] < 0 ).sum ()
1444+ paying_same = (df ['fee_change' ] == 0 ).sum ()
1445+ total_txs = len (df )
1446+
1447+ print (f"\n Fee Direction:" )
1448+ print (f" Paying more: { paying_more :>8,} ({ paying_more / total_txs * 100 :>6.2f} %)" )
1449+ print (f" Paying less: { paying_less :>8,} ({ paying_less / total_txs * 100 :>6.2f} %)" )
1450+ print (f" No change: { paying_same :>8,} ({ paying_same / total_txs * 100 :>6.2f} %)" )
1451+
1452+ total_old_fee = df ['old_fee' ].sum ()
1453+ total_new_fee = df ['new_fee' ].sum ()
1454+ total_change = total_new_fee - total_old_fee
1455+
1456+ print (f"\n Aggregate Total Fee:" )
1457+ print (f" Old total: { total_old_fee :>25,.0f} wei ({ total_old_fee / 1e18 :.6f} ETH)" )
1458+ print (f" New total: { total_new_fee :>25,.0f} wei ({ total_new_fee / 1e18 :.6f} ETH)" )
1459+ print (f" Change: { total_change :>+25,.0f} wei ({ total_change / total_old_fee * 100 :>+.2f} %)" )
1460+
1461+ # --- Analysis 2: Fee Change by Transaction Size Group ---
1462+ print ("\n " + "-" * 60 )
1463+ print ("Analysis 2: Fee Change by Transaction Size Group" )
1464+ print ("-" * 60 )
1465+
1466+ p50_size = df ['compressed_tx_size' ].quantile (0.50 )
1467+ p95_size = df ['compressed_tx_size' ].quantile (0.95 )
1468+
1469+ def size_group (size ):
1470+ if size < p50_size :
1471+ return 'Small (< P50)'
1472+ elif size <= p95_size :
1473+ return 'Medium (P50-P95)'
1474+ else :
1475+ return 'Large (> P95)'
1476+
1477+ df ['size_group' ] = df ['compressed_tx_size' ].apply (size_group )
1478+
1479+ # Calculate penalty terms for both parameter sets
1480+ df ['old_penalty_term' ] = df ['compressed_tx_size' ]** 2 / old_penalty_factor
1481+ df ['new_penalty_term' ] = df ['compressed_tx_size' ]** 2 / new_penalty_factor
1482+
1483+ group_order = ['Small (< P50)' , 'Medium (P50-P95)' , 'Large (> P95)' ]
1484+ print (f"\n Size thresholds: P50 = { p50_size :.0f} bytes, P95 = { p95_size :.0f} bytes\n " )
1485+
1486+ for group_name in group_order :
1487+ g = df [df ['size_group' ] == group_name ]
1488+ if len (g ) == 0 :
1489+ continue
1490+
1491+ print (f" { group_name } :" )
1492+ print (f" Count: { len (g ):,} " )
1493+ print (f" Size range: { g ['compressed_tx_size' ].min ():.0f} - { g ['compressed_tx_size' ].max ():.0f} bytes" )
1494+ print (f" Old fee: mean={ g ['old_fee' ].mean ():,.0f} median={ g ['old_fee' ].median ():,.0f} wei" )
1495+ print (f" New fee: mean={ g ['new_fee' ].mean ():,.0f} median={ g ['new_fee' ].median ():,.0f} wei" )
1496+ print (f" Fee change: mean={ g ['fee_change' ].mean ():+,.0f} median={ g ['fee_change' ].median ():+,.0f} wei" )
1497+ print (f" Fee change %%: mean={ g ['fee_change_pct' ].mean ():+.2f} %% median={ g ['fee_change_pct' ].median ():+.2f} %%" )
1498+ print (f" Old penalty/eff: mean={ ((g ['old_penalty_term' ] / g ['old_effective_size' ]) * 100 ).mean ():.2f} %%" )
1499+ print (f" New penalty/eff: mean={ ((g ['new_penalty_term' ] / g ['new_effective_size' ]) * 100 ).mean ():.2f} %%" )
1500+ print ()
1501+
1502+ # --- Analysis 3: Cost Recovery by Batch ---
1503+ print ("-" * 60 )
1504+ print ("Analysis 3: Cost Recovery by Batch" )
1505+ print ("-" * 60 )
1506+
1507+ batch_old_fees = df .groupby ('batch_index' )['old_fee' ].sum ()
1508+ batch_new_fees = df .groupby ('batch_index' )['new_fee' ].sum ()
1509+
1510+ batch_actual_cost = batch_df ['commit_cost' ] + batch_df ['finalize_cost' ] + batch_df ['blob_cost' ]
1511+
1512+ # Align indices
1513+ common_idx = batch_old_fees .index .intersection (batch_actual_cost .index )
1514+ batch_old_fees = batch_old_fees .loc [common_idx ]
1515+ batch_new_fees = batch_new_fees .loc [common_idx ]
1516+ batch_actual_cost = batch_actual_cost .loc [common_idx ]
1517+
1518+ old_recovery_rate = batch_old_fees / batch_actual_cost
1519+ new_recovery_rate = batch_new_fees / batch_actual_cost
1520+
1521+ print (f"\n Recovery Rate Statistics:" )
1522+ print (f" { 'Metric' :<15} { 'Old Params' :>15} { 'New Params' :>15} " )
1523+ print (f" { '-' * 15 } { '-' * 15 } { '-' * 15 } " )
1524+ print (f" { 'Mean' :<15} { old_recovery_rate .mean ():>14.4f} x { new_recovery_rate .mean ():>14.4f} x" )
1525+ print (f" { 'Median' :<15} { old_recovery_rate .median ():>14.4f} x { new_recovery_rate .median ():>14.4f} x" )
1526+ print (f" { 'Min' :<15} { old_recovery_rate .min ():>14.4f} x { new_recovery_rate .min ():>14.4f} x" )
1527+ print (f" { 'Max' :<15} { old_recovery_rate .max ():>14.4f} x { new_recovery_rate .max ():>14.4f} x" )
1528+
1529+ old_over = (old_recovery_rate > 1 ).sum ()
1530+ old_under = (old_recovery_rate < 1 ).sum ()
1531+ new_over = (new_recovery_rate > 1 ).sum ()
1532+ new_under = (new_recovery_rate < 1 ).sum ()
1533+
1534+ print (f"\n Over/Under Recovery:" )
1535+ print (f" Old params: { old_over } over, { old_under } under (of { len (common_idx )} batches)" )
1536+ print (f" New params: { new_over } over, { new_under } under (of { len (common_idx )} batches)" )
1537+
1538+ # Per-batch table (show all if <= 30 batches)
1539+ if len (common_idx ) <= 30 :
1540+ print (f"\n Per-Batch Detail:" )
1541+ print (f" { 'Batch' :>8} { 'Actual Cost' :>18} { 'Old Fees' :>18} { 'Old Rate' :>10} { 'New Fees' :>18} { 'New Rate' :>10} " )
1542+ print (f" { '-' * 8 } { '-' * 18 } { '-' * 18 } { '-' * 10 } { '-' * 18 } { '-' * 10 } " )
1543+ for idx in sorted (common_idx ):
1544+ print (f" { idx :>8} { batch_actual_cost .loc [idx ]:>18,.0f} { batch_old_fees .loc [idx ]:>18,.0f} { old_recovery_rate .loc [idx ]:>9.4f} x { batch_new_fees .loc [idx ]:>18,.0f} { new_recovery_rate .loc [idx ]:>9.4f} x" )
1545+
1546+ # Aggregate totals
1547+ total_actual = batch_actual_cost .sum ()
1548+ total_old = batch_old_fees .sum ()
1549+ total_new = batch_new_fees .sum ()
1550+
1551+ print (f"\n Aggregate Totals:" )
1552+ print (f" Actual L1 cost: { total_actual :>25,.0f} wei ({ total_actual / 1e18 :.6f} ETH)" )
1553+ print (f" Old fee total: { total_old :>25,.0f} wei ({ total_old / 1e18 :.6f} ETH) ({ total_old / total_actual :.4f} x)" )
1554+ print (f" New fee total: { total_new :>25,.0f} wei ({ total_new / 1e18 :.6f} ETH) ({ total_new / total_actual :.4f} x)" )
1555+
1556+ # --- Analysis 4: Penalty Proportion ---
1557+ print ("\n " + "-" * 60 )
1558+ print ("Analysis 4: Penalty Proportion" )
1559+ print ("-" * 60 )
1560+
1561+ df ['old_penalty_pct' ] = df ['old_penalty_term' ] / df ['old_effective_size' ] * 100
1562+ df ['new_penalty_pct' ] = df ['new_penalty_term' ] / df ['new_effective_size' ] * 100
1563+
1564+ print (f"\n Overall Penalty Proportion (penalty_term / effective_size × 100):" )
1565+ print (f" { 'Metric' :<15} { 'Old Params' :>15} { 'New Params' :>15} " )
1566+ print (f" { '-' * 15 } { '-' * 15 } { '-' * 15 } " )
1567+ print (f" { 'Mean' :<15} { df ['old_penalty_pct' ].mean ():>14.2f} % { df ['new_penalty_pct' ].mean ():>14.2f} %" )
1568+ print (f" { 'Median' :<15} { df ['old_penalty_pct' ].median ():>14.2f} % { df ['new_penalty_pct' ].median ():>14.2f} %" )
1569+ print (f" { 'P95' :<15} { df ['old_penalty_pct' ].quantile (0.95 ):>14.2f} % { df ['new_penalty_pct' ].quantile (0.95 ):>14.2f} %" )
1570+ print (f" { 'P99' :<15} { df ['old_penalty_pct' ].quantile (0.99 ):>14.2f} % { df ['new_penalty_pct' ].quantile (0.99 ):>14.2f} %" )
1571+
1572+ print (f"\n Per Size Group:" )
1573+ for group_name in group_order :
1574+ g = df [df ['size_group' ] == group_name ]
1575+ if len (g ) == 0 :
1576+ continue
1577+
1578+ print (f"\n { group_name } (n={ len (g ):,} ):" )
1579+ print (f" { 'Metric' :<15} { 'Old Params' :>15} { 'New Params' :>15} " )
1580+ print (f" { '-' * 15 } { '-' * 15 } { '-' * 15 } " )
1581+ print (f" { 'Mean' :<15} { g ['old_penalty_pct' ].mean ():>14.2f} % { g ['new_penalty_pct' ].mean ():>14.2f} %" )
1582+ print (f" { 'Median' :<15} { g ['old_penalty_pct' ].median ():>14.2f} % { g ['new_penalty_pct' ].median ():>14.2f} %" )
1583+ print (f" { 'P95' :<15} { g ['old_penalty_pct' ].quantile (0.95 ):>14.2f} % { g ['new_penalty_pct' ].quantile (0.95 ):>14.2f} %" )
1584+ print (f" { 'P99' :<15} { g ['old_penalty_pct' ].quantile (0.99 ):>14.2f} % { g ['new_penalty_pct' ].quantile (0.99 ):>14.2f} %" )
1585+
1586+ print ("\n " + "=" * 60 )
1587+
1588+
13771589# ============================================================================
13781590# MAIN
13791591# ============================================================================
@@ -1455,6 +1667,9 @@ def main():
14551667 # Step 6: Analyze EtherFi penalties
14561668 etherfi_results = analyze_etherfi_penalties (tx_df , penalty_multiplier )
14571669
1670+ # Step 7: Compare with current on-chain parameters
1671+ compare_parameters (current_params , commit_scalar , blob_scalar , penalty_multiplier , tx_df , batch_df )
1672+
14581673 # Final summary
14591674 print ("\n " + "=" * 60 )
14601675 print ("FINAL RESULTS" )
0 commit comments