foundry_evm_core/
utils.rs1use crate::EvmEnv;
2use alloy_chains::Chain;
3use alloy_consensus::{BlockHeader, private::alloy_eips::eip7840::BlobParams};
4use alloy_hardforks::EthereumHardfork;
5use alloy_json_abi::{Function, JsonAbi};
6use alloy_primitives::{B256, ChainId, Selector, U256};
7use alloy_provider::{Network, network::BlockResponse};
8use foundry_config::NamedChain;
9use foundry_evm_networks::NetworkConfigs;
10pub use revm::state::EvmState as StateChangeset;
11use revm::{
12 context::BlockEnv,
13 primitives::{
14 eip4844::{BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN, BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE},
15 hardfork::SpecId,
16 },
17};
18
19#[cold]
21#[inline(always)]
22pub fn cold_path() {
23 }
25
26pub fn block_env_from_header(header: &impl BlockHeader) -> BlockEnv {
28 BlockEnv {
29 number: U256::from(header.number()),
30 beneficiary: header.beneficiary(),
31 timestamp: U256::from(header.timestamp()),
32 difficulty: header.difficulty(),
33 prevrandao: header.mix_hash(),
34 basefee: header.base_fee_per_gas().unwrap_or_default(),
35 gas_limit: header.gas_limit(),
36 ..Default::default()
37 }
38}
39
40pub fn apply_chain_and_block_specific_env_changes<N: Network>(
47 evm_env: &mut EvmEnv,
48 block: &N::BlockResponse,
49 configs: NetworkConfigs,
50) {
51 use NamedChain::*;
52
53 if let Ok(chain) = NamedChain::try_from(evm_env.cfg_env.chain_id) {
54 let block_number = block.header().number();
55
56 match chain {
57 Mainnet => {
58 if block_number >= 15_537_351u64 {
60 evm_env.block_env.difficulty =
61 evm_env.block_env.prevrandao.unwrap_or_default().into();
62 }
63
64 return;
65 }
66 BinanceSmartChain | BinanceSmartChainTestnet => {
67 evm_env.block_env.prevrandao = Some(evm_env.block_env.difficulty.into());
74 return;
75 }
76 c if c.is_arbitrum() => {
77 if let Some(l1_block_number) = block
80 .other_fields()
81 .and_then(|other| other.get("l1BlockNumber").cloned())
82 .and_then(|l1_block_number| {
83 serde_json::from_value::<U256>(l1_block_number).ok()
84 })
85 {
86 evm_env.block_env.number = l1_block_number.to();
87 }
88 }
89 _ => {}
90 }
91 }
92
93 if configs.bypass_prevrandao(evm_env.cfg_env.chain_id) && evm_env.block_env.prevrandao.is_none()
94 {
95 evm_env.block_env.prevrandao = Some(B256::random());
97 }
98
99 if block.header().difficulty().is_zero() {
101 evm_env.block_env.difficulty = evm_env.block_env.prevrandao.unwrap_or_default().into();
102 }
103}
104
105pub fn get_blob_params(chain_id: ChainId, timestamp: u64) -> BlobParams {
110 let hardfork = EthereumHardfork::from_chain_and_timestamp(Chain::from_id(chain_id), timestamp)
111 .unwrap_or_default();
112
113 match hardfork {
114 EthereumHardfork::Prague => BlobParams::prague(),
115 EthereumHardfork::Osaka => BlobParams::osaka(),
116 EthereumHardfork::Bpo1 => BlobParams::bpo1(),
117 EthereumHardfork::Bpo2 => BlobParams::bpo2(),
118
119 EthereumHardfork::Bpo3 => BlobParams::bpo2(),
121 EthereumHardfork::Bpo4 => BlobParams::bpo2(),
122 EthereumHardfork::Bpo5 => BlobParams::bpo2(),
123 EthereumHardfork::Amsterdam => BlobParams::bpo2(),
124
125 _ => BlobParams::cancun(),
127 }
128}
129
130pub fn get_blob_base_fee_update_fraction(chain_id: ChainId, timestamp: u64) -> u64 {
133 get_blob_params(chain_id, timestamp).update_fraction as u64
134}
135
136pub fn get_blob_base_fee_update_fraction_by_spec_id(spec: SpecId) -> u64 {
138 if spec >= SpecId::PRAGUE {
139 BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
140 } else {
141 BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
142 }
143}
144
145pub fn get_function<'a>(
147 contract_name: &str,
148 selector: Selector,
149 abi: &'a JsonAbi,
150) -> eyre::Result<&'a Function> {
151 abi.functions()
152 .find(|func| func.selector() == selector)
153 .ok_or_else(|| eyre::eyre!("{contract_name} does not have the selector {selector}"))
154}