use alloy_primitives::U256;
use crate::utils::flz_compress_len;
use core::ops::Mul;
const ZERO_BYTE_COST: u64 = 4;
const NON_ZERO_BYTE_COST: u64 = 16;
pub fn data_gas_bedrock(input: &[u8]) -> U256 {
data_gas_regolith(input) + U256::from(NON_ZERO_BYTE_COST).mul(U256::from(68))
}
pub fn data_gas_regolith(input: &[u8]) -> U256 {
let rollup_data_gas_cost = U256::from(input.iter().fold(0, |acc, byte| {
acc + if *byte == 0x00 { ZERO_BYTE_COST } else { NON_ZERO_BYTE_COST }
}));
rollup_data_gas_cost
}
pub fn data_gas_fjord(input: &[u8]) -> U256 {
let estimated_size = tx_estimated_size_fjord(input);
estimated_size
.saturating_mul(U256::from(NON_ZERO_BYTE_COST))
.wrapping_div(U256::from(1_000_000))
}
fn tx_estimated_size_fjord(input: &[u8]) -> U256 {
let fastlz_size = U256::from(flz_compress_len(input));
fastlz_size
.saturating_mul(U256::from(836_500))
.saturating_sub(U256::from(42_585_600))
.max(U256::from(100_000_000))
}
pub fn calculate_tx_l1_cost_bedrock(
input: &[u8],
l1_fee_overhead: U256,
base_fee: U256,
l1_fee_scalar: U256,
) -> U256 {
if input.is_empty() || input.first() == Some(&0x7F) {
return U256::ZERO;
}
let rollup_data_gas_cost = data_gas_bedrock(input);
rollup_data_gas_cost
.saturating_add(l1_fee_overhead)
.saturating_mul(base_fee)
.saturating_mul(l1_fee_scalar)
.wrapping_div(U256::from(1_000_000))
}
pub fn calculate_tx_l1_cost_regolith(
input: &[u8],
l1_fee_overhead: U256,
base_fee: U256,
l1_fee_scalar: U256,
) -> U256 {
if input.is_empty() || input.first() == Some(&0x7F) {
return U256::ZERO;
}
let rollup_data_gas_cost = data_gas_regolith(input);
rollup_data_gas_cost
.saturating_add(l1_fee_overhead)
.saturating_mul(base_fee)
.saturating_mul(l1_fee_scalar)
.wrapping_div(U256::from(1_000_000))
}
pub fn calculate_tx_l1_cost_ecotone(
input: &[u8],
base_fee: U256,
base_fee_scalar: U256,
blob_base_fee: U256,
blob_base_fee_scalar: U256,
) -> U256 {
if input.is_empty() || input.first() == Some(&0x7F) {
return U256::ZERO;
}
let rollup_data_gas_cost = data_gas_regolith(input);
let l1_fee_scaled = calculate_l1_fee_scaled_ecotone(
base_fee,
base_fee_scalar,
blob_base_fee,
blob_base_fee_scalar,
);
l1_fee_scaled
.saturating_mul(rollup_data_gas_cost)
.wrapping_div(U256::from(1_000_000 * NON_ZERO_BYTE_COST))
}
pub fn calculate_tx_l1_cost_fjord(
input: &[u8],
base_fee: U256,
base_fee_scalar: U256,
blob_base_fee: U256,
blob_base_fee_scalar: U256,
) -> U256 {
if input.is_empty() || input.first() == Some(&0x7F) {
return U256::ZERO;
}
let l1_fee_scaled = calculate_l1_fee_scaled_ecotone(
base_fee,
base_fee_scalar,
blob_base_fee,
blob_base_fee_scalar,
);
let estimated_size = tx_estimated_size_fjord(input);
estimated_size.saturating_mul(l1_fee_scaled).wrapping_div(U256::from(1_000_000_000_000u64))
}
fn calculate_l1_fee_scaled_ecotone(
base_fee: U256,
base_fee_scalar: U256,
blob_base_fee: U256,
blob_base_fee_scalar: U256,
) -> U256 {
let calldata_cost_per_byte: U256 =
base_fee.saturating_mul(U256::from(NON_ZERO_BYTE_COST)).saturating_mul(base_fee_scalar);
let blob_cost_per_byte = blob_base_fee.saturating_mul(blob_base_fee_scalar);
U256::from(calldata_cost_per_byte).saturating_add(blob_cost_per_byte)
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_primitives::{bytes, hex};
#[test]
fn test_data_gas_bedrock() {
let input_1 = bytes!("FACADE");
let input_2 = bytes!("FA00CA00DE");
let bedrock_data_gas = data_gas_bedrock(&input_1);
assert_eq!(bedrock_data_gas, U256::from(1136));
let bedrock_data_gas = data_gas_bedrock(&input_2);
assert_eq!(bedrock_data_gas, U256::from(1144));
}
#[test]
fn test_data_gas_regolith() {
let input_1 = bytes!("FACADE");
let input_2 = bytes!("FA00CA00DE");
let bedrock_data_gas = data_gas_regolith(&input_1);
assert_eq!(bedrock_data_gas, U256::from(48));
let bedrock_data_gas = data_gas_regolith(&input_2);
assert_eq!(bedrock_data_gas, U256::from(56));
}
#[test]
fn test_data_gas_fjord() {
let input_1 = bytes!("FACADE");
let input_2 = bytes!("FA00CA00DE");
let fjord_data_gas = data_gas_fjord(&input_1);
assert_eq!(fjord_data_gas, U256::from(1600));
let fjord_data_gas = data_gas_fjord(&input_2);
assert_eq!(fjord_data_gas, U256::from(1600));
}
#[test]
fn test_calculate_tx_l1_cost_bedrock() {
let base_fee = U256::from(1_000);
let l1_fee_overhead = U256::from(1_000);
let l1_fee_scalar = U256::from(1_000);
let input = bytes!("FACADE");
let gas_cost =
calculate_tx_l1_cost_bedrock(&input, l1_fee_overhead, base_fee, l1_fee_scalar);
assert_eq!(gas_cost, U256::from(2136));
let input = bytes!("");
let gas_cost =
calculate_tx_l1_cost_bedrock(&input, l1_fee_overhead, base_fee, l1_fee_scalar);
assert_eq!(gas_cost, U256::ZERO);
let input = bytes!("7FFACADE");
let gas_cost =
calculate_tx_l1_cost_bedrock(&input, l1_fee_overhead, base_fee, l1_fee_scalar);
assert_eq!(gas_cost, U256::ZERO);
}
#[test]
fn test_calculate_tx_l1_cost_regolith() {
let base_fee = U256::from(1_000);
let l1_fee_overhead = U256::from(1_000);
let l1_fee_scalar = U256::from(1_000);
let input = bytes!("FACADE");
let gas_cost =
calculate_tx_l1_cost_regolith(&input, l1_fee_overhead, base_fee, l1_fee_scalar);
assert_eq!(gas_cost, U256::from(1048));
let input = bytes!("");
let gas_cost =
calculate_tx_l1_cost_regolith(&input, l1_fee_overhead, base_fee, l1_fee_scalar);
assert_eq!(gas_cost, U256::ZERO);
let input = bytes!("7FFACADE");
let gas_cost =
calculate_tx_l1_cost_regolith(&input, l1_fee_overhead, base_fee, l1_fee_scalar);
assert_eq!(gas_cost, U256::ZERO);
}
#[test]
fn test_calculate_tx_l1_cost_ecotone() {
let base_fee = U256::from(1_000);
let blob_base_fee = U256::from(1_000);
let blob_base_fee_scalar = U256::from(1_000);
let base_fee_scalar = U256::from(1_000);
let input = bytes!("FACADE");
let gas_cost = calculate_tx_l1_cost_ecotone(
&input,
base_fee,
base_fee_scalar,
blob_base_fee,
blob_base_fee_scalar,
);
assert_eq!(gas_cost, U256::from(51));
let input = bytes!("");
let gas_cost = calculate_tx_l1_cost_ecotone(
&input,
base_fee,
base_fee_scalar,
blob_base_fee,
blob_base_fee_scalar,
);
assert_eq!(gas_cost, U256::ZERO);
let input = bytes!("7FFACADE");
let gas_cost = calculate_tx_l1_cost_ecotone(
&input,
base_fee,
base_fee_scalar,
blob_base_fee,
blob_base_fee_scalar,
);
assert_eq!(gas_cost, U256::ZERO);
}
#[test]
fn test_calculate_tx_l1_cost_fjord() {
let base_fee = U256::from(1_000);
let blob_base_fee = U256::from(1_000);
let blob_base_fee_scalar = U256::from(1_000);
let base_fee_scalar = U256::from(1_000);
let input = bytes!("FACADE");
let gas_cost = calculate_tx_l1_cost_fjord(
&input,
base_fee,
base_fee_scalar,
blob_base_fee,
blob_base_fee_scalar,
);
assert_eq!(gas_cost, U256::from(1700));
let input = bytes!("02f901550a758302df1483be21b88304743f94f80e51afb613d764fa61751affd3313c190a86bb870151bd62fd12adb8e41ef24f3f000000000000000000000000000000000000000000000000000000000000006e000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000003c1e5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000148c89ed219d02f1a5be012c689b4f5b731827bebe000000000000000000000000c001a033fd89cb37c31b2cba46b6466e040c61fc9b2a3675a7f5f493ebd5ad77c497f8a07cdf65680e238392693019b4092f610222e71b7cec06449cb922b93b6a12744e");
let gas_cost = calculate_tx_l1_cost_fjord(
&input,
base_fee,
base_fee_scalar,
blob_base_fee,
blob_base_fee_scalar,
);
assert_eq!(gas_cost, U256::from(2148));
let input = bytes!("");
let gas_cost = calculate_tx_l1_cost_fjord(
&input,
base_fee,
base_fee_scalar,
blob_base_fee,
blob_base_fee_scalar,
);
assert_eq!(gas_cost, U256::ZERO);
let input = bytes!("7FFACADE");
let gas_cost = calculate_tx_l1_cost_fjord(
&input,
base_fee,
base_fee_scalar,
blob_base_fee,
blob_base_fee_scalar,
);
assert_eq!(gas_cost, U256::ZERO);
}
#[test]
fn calculate_tx_l1_cost_fjord_actual_block() {
let base_fee = U256::from(1055991687);
let blob_base_fee = U256::from(1);
let blob_base_fee_scalar = U256::from(1014213);
let base_fee_scalar = U256::from(5227);
const TX: &[u8] = &hex!("02f904940a8303fba78401d6d2798401db2b6d830493e0943e6f4f7866654c18f536170780344aa8772950b680b904246a761202000000000000000000000000087000a300de7200382b55d40045000000e5d60e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000022482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000021c4928109acb0659a88ae5329b5374a3024694c0000000000000000000000000000000000000000000000049b9ca9a6943400000000000000000000000000000000000000000000000000000000000000000000000000000000000021c4928109acb0659a88ae5329b5374a3024694c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000024b6b55f250000000000000000000000000000000000000000000000049b9ca9a694340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415ec214a3950bea839a7e6fbb0ba1540ac2076acd50820e2d5ef83d0902cdffb24a47aff7de5190290769c4f0a9c6fabf63012986a0d590b1b571547a8c7050ea1b00000000000000000000000000000000000000000000000000000000000000c080a06db770e6e25a617fe9652f0958bd9bd6e49281a53036906386ed39ec48eadf63a07f47cf51a4a40b4494cf26efc686709a9b03939e20ee27e59682f5faa536667e");
let expected_data_gas = U256::from(4471);
let expected_l1_fee = U256::from_be_bytes(hex!(
"00000000000000000000000000000000000000000000000000000005bf1ab43d"
));
let data_gas = data_gas_fjord(TX);
assert_eq!(data_gas, expected_data_gas);
let l1_fee = calculate_tx_l1_cost_fjord(
TX,
base_fee,
base_fee_scalar,
blob_base_fee,
blob_base_fee_scalar,
);
assert_eq!(l1_fee, expected_l1_fee)
}
}