foundry_evm_core/
utils.rs1use crate::{EvmEnv, FoundryBlock};
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;
10use revm::primitives::{
11 eip4844::{BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN, BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE},
12 hardfork::SpecId,
13};
14pub use revm::state::EvmState as StateChangeset;
15
16#[cold]
18#[inline(always)]
19pub const fn cold_path() {
20 }
22
23pub fn block_env_from_header<BLOCK: FoundryBlock + Default>(header: &impl BlockHeader) -> BLOCK {
25 let mut block = BLOCK::default();
26 block.set_number(U256::from(header.number()));
27 block.set_beneficiary(header.beneficiary());
28 block.set_timestamp(U256::from(header.timestamp()));
29 block.set_difficulty(header.difficulty());
30 block.set_prevrandao(header.mix_hash());
31 block.set_basefee(header.base_fee_per_gas().unwrap_or_default());
32 block.set_gas_limit(header.gas_limit());
33 block
34}
35
36pub fn apply_chain_and_block_specific_env_changes<
44 N: Network,
45 SPEC: Into<SpecId> + Copy,
46 BLOCK: FoundryBlock,
47>(
48 evm_env: &mut EvmEnv<SPEC, BLOCK>,
49 block: &N::BlockResponse,
50 configs: NetworkConfigs,
51) {
52 use NamedChain::{BinanceSmartChain, BinanceSmartChainTestnet, Mainnet};
53
54 if let Ok(chain) = NamedChain::try_from(evm_env.cfg_env.chain_id) {
55 let block_number = block.header().number();
56
57 match chain {
58 Mainnet => {
59 if block_number >= 15_537_351u64 {
61 evm_env
62 .block_env
63 .set_difficulty(evm_env.block_env.prevrandao().unwrap_or_default().into());
64 }
65
66 return;
67 }
68 BinanceSmartChain | BinanceSmartChainTestnet => {
69 evm_env.block_env.set_prevrandao(Some(evm_env.block_env.difficulty().into()));
76 return;
77 }
78 c if c.is_arbitrum() => {
79 if let Some(l1_block_number) = block
82 .other_fields()
83 .and_then(|other| other.get("l1BlockNumber").cloned())
84 .and_then(|l1_block_number| {
85 serde_json::from_value::<U256>(l1_block_number).ok()
86 })
87 {
88 evm_env.block_env.set_number(l1_block_number);
89 }
90 }
91 _ => {}
92 }
93 }
94
95 if configs.bypass_prevrandao(evm_env.cfg_env.chain_id)
96 && evm_env.block_env.prevrandao().is_none()
97 {
98 evm_env.block_env.set_prevrandao(Some(B256::random()));
100 }
101
102 if block.header().difficulty().is_zero() {
104 evm_env.block_env.set_difficulty(evm_env.block_env.prevrandao().unwrap_or_default().into());
105 }
106}
107
108pub fn get_blob_params(chain_id: ChainId, timestamp: u64) -> BlobParams {
113 let hardfork = EthereumHardfork::from_chain_and_timestamp(Chain::from_id(chain_id), timestamp)
114 .unwrap_or_default();
115
116 match hardfork {
117 EthereumHardfork::Prague => BlobParams::prague(),
118 EthereumHardfork::Osaka => BlobParams::osaka(),
119 EthereumHardfork::Bpo1 => BlobParams::bpo1(),
120 EthereumHardfork::Bpo2 => BlobParams::bpo2(),
121
122 EthereumHardfork::Bpo3 => BlobParams::bpo2(),
124 EthereumHardfork::Bpo4 => BlobParams::bpo2(),
125 EthereumHardfork::Bpo5 => BlobParams::bpo2(),
126 EthereumHardfork::Amsterdam => BlobParams::bpo2(),
127
128 _ => BlobParams::cancun(),
130 }
131}
132
133pub fn get_blob_base_fee_update_fraction(chain_id: ChainId, timestamp: u64) -> u64 {
136 get_blob_params(chain_id, timestamp).update_fraction as u64
137}
138
139pub fn get_blob_base_fee_update_fraction_by_spec_id(spec: SpecId) -> u64 {
141 if spec >= SpecId::PRAGUE {
142 BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
143 } else {
144 BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
145 }
146}
147
148pub fn get_function<'a>(
150 contract_name: &str,
151 selector: Selector,
152 abi: &'a JsonAbi,
153) -> eyre::Result<&'a Function> {
154 abi.functions()
155 .find(|func| func.selector() == selector)
156 .ok_or_else(|| eyre::eyre!("{contract_name} does not have the selector {selector}"))
157}