foundry_evm_core/
utils.rs1use crate::EnvMut;
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_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 | Gnosis | Chiado => {
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_params(chain_id: ChainId, timestamp: u64) -> BlobParams {
92 let hardfork = EthereumHardfork::from_chain_and_timestamp(Chain::from_id(chain_id), timestamp)
93 .unwrap_or_default();
94
95 match hardfork {
96 EthereumHardfork::Prague => BlobParams::prague(),
97 EthereumHardfork::Osaka => BlobParams::osaka(),
98 EthereumHardfork::Bpo1 => BlobParams::bpo1(),
99 EthereumHardfork::Bpo2 => BlobParams::bpo2(),
100
101 EthereumHardfork::Bpo3 => BlobParams::bpo2(),
103 EthereumHardfork::Bpo4 => BlobParams::bpo2(),
104 EthereumHardfork::Bpo5 => BlobParams::bpo2(),
105 EthereumHardfork::Amsterdam => BlobParams::bpo2(),
106
107 _ => BlobParams::cancun(),
109 }
110}
111
112pub fn get_blob_base_fee_update_fraction(chain_id: ChainId, timestamp: u64) -> u64 {
115 get_blob_params(chain_id, timestamp).update_fraction as u64
116}
117
118pub fn get_blob_base_fee_update_fraction_by_spec_id(spec: SpecId) -> u64 {
120 if spec >= SpecId::PRAGUE {
121 BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE
122 } else {
123 BLOB_BASE_FEE_UPDATE_FRACTION_CANCUN
124 }
125}
126
127pub fn get_function<'a>(
129 contract_name: &str,
130 selector: Selector,
131 abi: &'a JsonAbi,
132) -> eyre::Result<&'a Function> {
133 abi.functions()
134 .find(|func| func.selector() == selector)
135 .ok_or_else(|| eyre::eyre!("{contract_name} does not have the selector {selector}"))
136}
137
138pub fn configure_tx_env(env: &mut EnvMut<'_>, tx: &Transaction<AnyTxEnvelope>) {
141 let from = tx.from();
142 if let AnyTxEnvelope::Ethereum(tx) = &tx.inner.inner() {
143 configure_tx_req_env(env, &tx.clone().into(), Some(from)).expect("cannot fail");
144 }
145}
146
147pub fn configure_tx_req_env(
151 env: &mut EnvMut<'_>,
152 tx: &TransactionRequest,
153 impersonated_from: Option<Address>,
154) -> eyre::Result<()> {
155 let tx_type = tx.transaction_type.unwrap_or_else(|| tx.minimal_tx_type() as u8);
157 env.tx.tx_type = tx_type;
158
159 let TransactionRequest {
160 nonce,
161 from,
162 to,
163 value,
164 gas_price,
165 gas,
166 max_fee_per_gas,
167 max_priority_fee_per_gas,
168 max_fee_per_blob_gas,
169 ref input,
170 chain_id,
171 ref blob_versioned_hashes,
172 ref access_list,
173 ref authorization_list,
174 transaction_type: _,
175 sidecar: _,
176 } = *tx;
177
178 env.tx.kind = to.unwrap_or(TxKind::Create);
180 env.tx.caller =
183 impersonated_from.unwrap_or(from.ok_or_else(|| eyre::eyre!("missing `from` field"))?);
184 env.tx.gas_limit = gas.ok_or_else(|| eyre::eyre!("missing `gas` field"))?;
185 env.tx.nonce = nonce.unwrap_or_default();
186 env.tx.value = value.unwrap_or_default();
187 env.tx.data = input.input().cloned().unwrap_or_default();
188 env.tx.chain_id = chain_id;
189
190 env.tx.access_list = access_list.clone().unwrap_or_default();
192
193 env.tx.gas_price = gas_price.or(max_fee_per_gas).unwrap_or_default();
195 env.tx.gas_priority_fee = max_priority_fee_per_gas;
196
197 env.tx.blob_hashes = blob_versioned_hashes.clone().unwrap_or_default();
199 env.tx.max_fee_per_blob_gas = max_fee_per_blob_gas.unwrap_or_default();
200
201 env.tx.set_signed_authorization(authorization_list.clone().unwrap_or_default());
203
204 Ok(())
205}