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
17pub fn apply_chain_and_block_specific_env_changes<N: Network>(
24 env: EnvMut<'_>,
25 block: &N::BlockResponse,
26) {
27 use NamedChain::*;
28
29 if let Ok(chain) = NamedChain::try_from(env.cfg.chain_id) {
30 let block_number = block.header().number();
31
32 match chain {
33 Mainnet => {
34 if block_number >= 15_537_351u64 {
36 env.block.difficulty = env.block.prevrandao.unwrap_or_default().into();
37 }
38
39 return;
40 }
41 BinanceSmartChain | BinanceSmartChainTestnet => {
42 env.block.prevrandao = Some(env.block.difficulty.into());
49 return;
50 }
51 Moonbeam | Moonbase | Moonriver | MoonbeamDev | Rsk | RskTestnet => {
52 if env.block.prevrandao.is_none() {
53 env.block.prevrandao = Some(B256::random());
55 }
56 }
57 c if c.is_arbitrum() => {
58 if let Some(l1_block_number) = block
61 .other_fields()
62 .and_then(|other| other.get("l1BlockNumber").cloned())
63 .and_then(|l1_block_number| {
64 serde_json::from_value::<U256>(l1_block_number).ok()
65 })
66 {
67 env.block.number = l1_block_number.to();
68 }
69 }
70 _ => {}
71 }
72 }
73
74 if block.header().difficulty().is_zero() {
76 env.block.difficulty = env.block.prevrandao.unwrap_or_default().into();
77 }
78}
79
80pub fn get_blob_base_fee_update_fraction(chain_id: ChainId, timestamp: u64) -> u64 {
83 let hardfork = EthereumHardfork::from_chain_and_timestamp(Chain::from_id(chain_id), timestamp)
84 .unwrap_or_default();
85
86 if hardfork >= EthereumHardfork::Prague {
87 BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
88 } else {
89 BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
90 }
91}
92
93pub fn get_blob_base_fee_update_fraction_by_spec_id(spec: SpecId) -> u64 {
95 if spec >= SpecId::PRAGUE {
96 BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
97 } else {
98 BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
99 }
100}
101
102pub fn get_function<'a>(
104 contract_name: &str,
105 selector: Selector,
106 abi: &'a JsonAbi,
107) -> eyre::Result<&'a Function> {
108 abi.functions()
109 .find(|func| func.selector() == selector)
110 .ok_or_else(|| eyre::eyre!("{contract_name} does not have the selector {selector}"))
111}
112
113pub fn configure_tx_env(env: &mut EnvMut<'_>, tx: &Transaction<AnyTxEnvelope>) {
116 let from = tx.from();
117 if let AnyTxEnvelope::Ethereum(tx) = &tx.inner.inner() {
118 configure_tx_req_env(env, &tx.clone().into(), Some(from)).expect("cannot fail");
119 }
120}
121
122pub fn configure_tx_req_env(
126 env: &mut EnvMut<'_>,
127 tx: &TransactionRequest,
128 impersonated_from: Option<Address>,
129) -> eyre::Result<()> {
130 let tx_type = tx.transaction_type.unwrap_or_else(|| tx.minimal_tx_type() as u8);
132 env.tx.tx_type = tx_type;
133
134 let TransactionRequest {
135 nonce,
136 from,
137 to,
138 value,
139 gas_price,
140 gas,
141 max_fee_per_gas,
142 max_priority_fee_per_gas,
143 max_fee_per_blob_gas,
144 ref input,
145 chain_id,
146 ref blob_versioned_hashes,
147 ref access_list,
148 ref authorization_list,
149 transaction_type: _,
150 sidecar: _,
151 } = *tx;
152
153 env.tx.kind = to.unwrap_or(TxKind::Create);
155 env.tx.caller =
158 impersonated_from.unwrap_or(from.ok_or_else(|| eyre::eyre!("missing `from` field"))?);
159 env.tx.gas_limit = gas.ok_or_else(|| eyre::eyre!("missing `gas` field"))?;
160 env.tx.nonce = nonce.unwrap_or_default();
161 env.tx.value = value.unwrap_or_default();
162 env.tx.data = input.input().cloned().unwrap_or_default();
163 env.tx.chain_id = chain_id;
164
165 env.tx.access_list = access_list.clone().unwrap_or_default();
167
168 env.tx.gas_price = gas_price.or(max_fee_per_gas).unwrap_or_default();
170 env.tx.gas_priority_fee = max_priority_fee_per_gas;
171
172 env.tx.blob_hashes = blob_versioned_hashes.clone().unwrap_or_default();
174 env.tx.max_fee_per_blob_gas = max_fee_per_blob_gas.unwrap_or_default();
175
176 env.tx.set_signed_authorization(authorization_list.clone().unwrap_or_default());
178
179 Ok(())
180}