foundry_evm_core/
utils.rs1use crate::EnvMut;
2use alloy_chains::Chain;
3use alloy_consensus::BlockHeader;
4use alloy_hardforks::EthereumHardfork;
5use alloy_json_abi::{Function, JsonAbi};
6use alloy_network::{AnyTxEnvelope, TransactionResponse};
7use alloy_primitives::{Address, B256, ChainId, Selector, TxKind, U256};
8use alloy_provider::{Network, network::BlockResponse};
9use alloy_rpc_types::{Transaction, TransactionRequest};
10use foundry_config::NamedChain;
11use revm::primitives::{
12 eip4844::{BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN, BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE},
13 hardfork::SpecId,
14};
15pub use revm::state::EvmState as StateChangeset;
16
17#[cold]
19#[inline(always)]
20pub fn cold_path() {
21 }
23
24pub fn apply_chain_and_block_specific_env_changes<N: Network>(
31 env: EnvMut<'_>,
32 block: &N::BlockResponse,
33) {
34 use NamedChain::*;
35
36 if let Ok(chain) = NamedChain::try_from(env.cfg.chain_id) {
37 let block_number = block.header().number();
38
39 match chain {
40 Mainnet => {
41 if block_number >= 15_537_351u64 {
43 env.block.difficulty = env.block.prevrandao.unwrap_or_default().into();
44 }
45
46 return;
47 }
48 BinanceSmartChain | BinanceSmartChainTestnet => {
49 env.block.prevrandao = Some(env.block.difficulty.into());
56 return;
57 }
58 Moonbeam | Moonbase | Moonriver | MoonbeamDev | Rsk | RskTestnet => {
59 if env.block.prevrandao.is_none() {
60 env.block.prevrandao = Some(B256::random());
62 }
63 }
64 c if c.is_arbitrum() => {
65 if let Some(l1_block_number) = block
68 .other_fields()
69 .and_then(|other| other.get("l1BlockNumber").cloned())
70 .and_then(|l1_block_number| {
71 serde_json::from_value::<U256>(l1_block_number).ok()
72 })
73 {
74 env.block.number = l1_block_number.to();
75 }
76 }
77 _ => {}
78 }
79 }
80
81 if block.header().difficulty().is_zero() {
83 env.block.difficulty = env.block.prevrandao.unwrap_or_default().into();
84 }
85}
86
87pub fn get_blob_base_fee_update_fraction(chain_id: ChainId, timestamp: u64) -> u64 {
90 let hardfork = EthereumHardfork::from_chain_and_timestamp(Chain::from_id(chain_id), timestamp)
91 .unwrap_or_default();
92
93 if hardfork >= EthereumHardfork::Prague {
94 BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
95 } else {
96 BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
97 }
98}
99
100pub fn get_blob_base_fee_update_fraction_by_spec_id(spec: SpecId) -> u64 {
102 if spec >= SpecId::PRAGUE {
103 BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
104 } else {
105 BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
106 }
107}
108
109pub fn get_function<'a>(
111 contract_name: &str,
112 selector: Selector,
113 abi: &'a JsonAbi,
114) -> eyre::Result<&'a Function> {
115 abi.functions()
116 .find(|func| func.selector() == selector)
117 .ok_or_else(|| eyre::eyre!("{contract_name} does not have the selector {selector}"))
118}
119
120pub fn configure_tx_env(env: &mut EnvMut<'_>, tx: &Transaction<AnyTxEnvelope>) {
123 let from = tx.from();
124 if let AnyTxEnvelope::Ethereum(tx) = &tx.inner.inner() {
125 configure_tx_req_env(env, &tx.clone().into(), Some(from)).expect("cannot fail");
126 }
127}
128
129pub fn configure_tx_req_env(
133 env: &mut EnvMut<'_>,
134 tx: &TransactionRequest,
135 impersonated_from: Option<Address>,
136) -> eyre::Result<()> {
137 let tx_type = tx.transaction_type.unwrap_or_else(|| tx.minimal_tx_type() as u8);
139 env.tx.tx_type = tx_type;
140
141 let TransactionRequest {
142 nonce,
143 from,
144 to,
145 value,
146 gas_price,
147 gas,
148 max_fee_per_gas,
149 max_priority_fee_per_gas,
150 max_fee_per_blob_gas,
151 ref input,
152 chain_id,
153 ref blob_versioned_hashes,
154 ref access_list,
155 ref authorization_list,
156 transaction_type: _,
157 sidecar: _,
158 } = *tx;
159
160 env.tx.kind = to.unwrap_or(TxKind::Create);
162 env.tx.caller =
165 impersonated_from.unwrap_or(from.ok_or_else(|| eyre::eyre!("missing `from` field"))?);
166 env.tx.gas_limit = gas.ok_or_else(|| eyre::eyre!("missing `gas` field"))?;
167 env.tx.nonce = nonce.unwrap_or_default();
168 env.tx.value = value.unwrap_or_default();
169 env.tx.data = input.input().cloned().unwrap_or_default();
170 env.tx.chain_id = chain_id;
171
172 env.tx.access_list = access_list.clone().unwrap_or_default();
174
175 env.tx.gas_price = gas_price.or(max_fee_per_gas).unwrap_or_default();
177 env.tx.gas_priority_fee = max_priority_fee_per_gas;
178
179 env.tx.blob_hashes = blob_versioned_hashes.clone().unwrap_or_default();
181 env.tx.max_fee_per_blob_gas = max_fee_per_blob_gas.unwrap_or_default();
182
183 env.tx.set_signed_authorization(authorization_list.clone().unwrap_or_default());
185
186 Ok(())
187}