1use super::{ScriptConfig, ScriptResult};
2use crate::build::ScriptPredeployLibraries;
3use alloy_eips::eip7702::SignedAuthorization;
4use alloy_evm::revm::context::Transaction;
5use alloy_network::TransactionBuilder;
6use alloy_primitives::{Address, Bytes, U256, map::AddressHashMap};
7use eyre::Result;
8use foundry_cheatcodes::BroadcastableTransaction;
9use foundry_common::TransactionMaybeSigned;
10use foundry_config::Config;
11use foundry_evm::{
12 constants::CALLER,
13 core::{
14 FoundryTransaction,
15 evm::{FoundryEvmNetwork, TransactionRequestFor},
16 },
17 executors::{DeployResult, EvmError, ExecutionErr, Executor, RawCallResult},
18 opts::EvmOpts,
19 revm::interpreter::{InstructionResult, return_ok},
20 traces::{TraceKind, Traces},
21};
22use std::collections::VecDeque;
23
24#[derive(Debug)]
26pub struct ScriptRunner<FEN: FoundryEvmNetwork> {
27 pub executor: Executor<FEN>,
28 pub evm_opts: EvmOpts,
29 collect_debug_bytecodes: bool,
30}
31
32impl<FEN: FoundryEvmNetwork> ScriptRunner<FEN> {
33 pub const fn new(executor: Executor<FEN>, evm_opts: EvmOpts) -> Self {
34 Self { executor, evm_opts, collect_debug_bytecodes: false }
35 }
36
37 pub const fn with_debug_bytecodes(mut self, collect_debug_bytecodes: bool) -> Self {
38 self.collect_debug_bytecodes = collect_debug_bytecodes;
39 self
40 }
41
42 fn maybe_debug_bytecodes(
43 &self,
44 debug_bytecodes: AddressHashMap<Bytes>,
45 ) -> AddressHashMap<Bytes> {
46 if self.collect_debug_bytecodes { debug_bytecodes } else { Default::default() }
47 }
48
49 fn extend_debug_bytecodes(
50 &self,
51 target: &mut AddressHashMap<Bytes>,
52 debug_bytecodes: AddressHashMap<Bytes>,
53 ) {
54 if self.collect_debug_bytecodes {
55 target.extend(debug_bytecodes);
56 }
57 }
58
59 pub fn setup(
61 &mut self,
62 libraries: &ScriptPredeployLibraries,
63 code: Bytes,
64 setup: bool,
65 script_config: &ScriptConfig<FEN>,
66 is_broadcast: bool,
67 ) -> Result<(Address, ScriptResult<FEN::Network>)> {
68 trace!(target: "script", "executing setUP()");
69
70 if !is_broadcast {
71 if self.evm_opts.sender == Config::DEFAULT_SENDER {
72 self.executor.set_balance(self.evm_opts.sender, U256::MAX)?;
74 }
75
76 if script_config.evm_opts.fork_url.is_none()
77 && !script_config.evm_opts.networks.is_tempo()
78 {
79 self.executor.deploy_create2_deployer()?;
80 }
81 }
82
83 let sender_nonce = script_config.sender_nonce;
84 self.executor.set_nonce(self.evm_opts.sender, sender_nonce)?;
85
86 self.executor.set_balance(CALLER, U256::MAX)?;
88
89 let mut library_transactions = VecDeque::new();
90 let mut traces = Traces::default();
91 let mut debug_bytecodes: AddressHashMap<Bytes> = Default::default();
92
93 match libraries {
95 ScriptPredeployLibraries::Default(libraries) => {
96 for code in libraries {
97 let RawCallResult {
98 traces: deploy_traces,
99 debug_bytecodes: deploy_debug_bytecodes,
100 ..
101 } = self
102 .executor
103 .deploy(self.evm_opts.sender, code.clone(), U256::ZERO, None)
104 .expect("couldn't deploy library")
105 .raw;
106
107 self.extend_debug_bytecodes(&mut debug_bytecodes, deploy_debug_bytecodes);
108
109 if let Some(deploy_traces) = deploy_traces {
110 traces.push((TraceKind::Deployment, deploy_traces));
111 }
112
113 let mut tx_req = TransactionRequestFor::<FEN>::default()
114 .with_from(self.evm_opts.sender)
115 .with_input(code.clone())
116 .with_nonce(sender_nonce + library_transactions.len() as u64);
117
118 script_config.tempo.apply::<FEN::Network>(&mut tx_req, None);
119
120 library_transactions.push_back(BroadcastableTransaction {
121 rpc: self.evm_opts.fork_url.clone(),
122 transaction: TransactionMaybeSigned::new(tx_req),
123 })
124 }
125 }
126 ScriptPredeployLibraries::Create2(libraries, salt) => {
127 let create2_deployer = self.executor.create2_deployer();
128 for library in libraries {
129 let address = create2_deployer.create2_from_code(salt, library.as_ref());
130 if !self.executor.is_empty_code(address)? {
132 continue;
133 }
134 let calldata = [salt.as_ref(), library.as_ref()].concat();
135 let RawCallResult {
136 traces: deploy_traces,
137 debug_bytecodes: deploy_debug_bytecodes,
138 ..
139 } = self
140 .executor
141 .transact_raw(
142 self.evm_opts.sender,
143 create2_deployer,
144 calldata.clone().into(),
145 U256::from(0),
146 )
147 .expect("couldn't deploy library");
148
149 self.extend_debug_bytecodes(&mut debug_bytecodes, deploy_debug_bytecodes);
150
151 if let Some(deploy_traces) = deploy_traces {
152 traces.push((TraceKind::Deployment, deploy_traces));
153 }
154
155 let mut tx_req = TransactionRequestFor::<FEN>::default()
156 .with_from(self.evm_opts.sender)
157 .with_input(calldata)
158 .with_nonce(sender_nonce + library_transactions.len() as u64)
159 .with_to(create2_deployer);
160
161 script_config.tempo.apply::<FEN::Network>(&mut tx_req, None);
162
163 library_transactions.push_back(BroadcastableTransaction {
164 rpc: self.evm_opts.fork_url.clone(),
165 transaction: TransactionMaybeSigned::new(tx_req),
166 });
167 }
168
169 self.executor.set_nonce(
172 self.evm_opts.sender,
173 sender_nonce + library_transactions.len() as u64,
174 )?;
175 }
176 };
177
178 let address = CALLER.create(self.executor.get_nonce(CALLER)?);
179
180 self.executor.set_balance(address, self.evm_opts.initial_balance)?;
183
184 let prev_sender_nonce = self.executor.get_nonce(self.evm_opts.sender)?;
191 if self.evm_opts.sender == CALLER {
192 self.executor.set_nonce(self.evm_opts.sender, u64::MAX / 2)?;
193 }
194
195 let DeployResult {
197 address,
198 raw:
199 RawCallResult {
200 mut logs,
201 traces: constructor_traces,
202 debug_bytecodes: constructor_debug_bytecodes,
203 ..
204 },
205 } = self
206 .executor
207 .deploy(CALLER, code, U256::ZERO, None)
208 .map_err(|err| eyre::eyre!("Failed to deploy script:\n{}", err))?;
209
210 if self.evm_opts.sender == CALLER {
211 self.executor.set_nonce(self.evm_opts.sender, prev_sender_nonce)?;
212 }
213
214 if script_config.config.script_execution_protection {
216 self.executor.set_script_execution(address);
217 }
218
219 traces.extend(constructor_traces.map(|traces| (TraceKind::Deployment, traces)));
220 self.extend_debug_bytecodes(&mut debug_bytecodes, constructor_debug_bytecodes);
221
222 let (success, gas_used, labeled_addresses, transactions) = if setup {
224 match self.executor.setup(Some(self.evm_opts.sender), address, None) {
225 Ok(RawCallResult {
226 reverted,
227 traces: setup_traces,
228 labels,
229 logs: setup_logs,
230 gas_used,
231 debug_bytecodes: setup_debug_bytecodes,
232 transactions: setup_transactions,
233 ..
234 }) => {
235 traces.extend(setup_traces.map(|traces| (TraceKind::Setup, traces)));
236 logs.extend_from_slice(&setup_logs);
237 self.extend_debug_bytecodes(&mut debug_bytecodes, setup_debug_bytecodes);
238
239 if let Some(txs) = setup_transactions {
240 library_transactions.extend(txs);
241 }
242
243 (!reverted, gas_used, labels, Some(library_transactions))
244 }
245 Err(EvmError::Execution(err)) => {
246 let RawCallResult {
247 reverted,
248 traces: setup_traces,
249 labels,
250 logs: setup_logs,
251 gas_used,
252 debug_bytecodes: setup_debug_bytecodes,
253 transactions,
254 ..
255 } = err.raw;
256 traces.extend(setup_traces.map(|traces| (TraceKind::Setup, traces)));
257 logs.extend_from_slice(&setup_logs);
258 self.extend_debug_bytecodes(&mut debug_bytecodes, setup_debug_bytecodes);
259
260 if let Some(txs) = transactions {
261 library_transactions.extend(txs);
262 }
263
264 (!reverted, gas_used, labels, Some(library_transactions))
265 }
266 Err(e) => return Err(e.into()),
267 }
268 } else {
269 self.executor.backend_mut().set_test_contract(address);
270 (true, 0, Default::default(), Some(library_transactions))
271 };
272
273 Ok((
274 address,
275 ScriptResult {
276 returned: Bytes::new(),
277 success,
278 gas_used,
279 labeled_addresses,
280 debug_bytecodes: self.maybe_debug_bytecodes(debug_bytecodes),
281 transactions,
282 logs,
283 traces,
284 address: None,
285 ..Default::default()
286 },
287 ))
288 }
289
290 pub fn script(
292 &mut self,
293 address: Address,
294 calldata: Bytes,
295 ) -> Result<ScriptResult<FEN::Network>> {
296 self.call(self.evm_opts.sender, address, calldata, U256::ZERO, None, false)
297 }
298
299 pub fn simulate(
301 &mut self,
302 from: Address,
303 to: Option<Address>,
304 calldata: Option<Bytes>,
305 value: Option<U256>,
306 authorization_list: Option<Vec<SignedAuthorization>>,
307 ) -> Result<ScriptResult<FEN::Network>> {
308 if let Some(to) = to {
309 self.call(
310 from,
311 to,
312 calldata.unwrap_or_default(),
313 value.unwrap_or(U256::ZERO),
314 authorization_list,
315 true,
316 )
317 } else {
318 let res = self.executor.deploy(
319 from,
320 calldata.expect("No data for create transaction"),
321 value.unwrap_or(U256::ZERO),
322 None,
323 );
324 let (
325 address,
326 RawCallResult { gas_used, logs, traces, debug_bytecodes, exit_reason, .. },
327 ) = match res {
328 Ok(DeployResult { address, raw }) => (address, raw),
329 Err(EvmError::Execution(err)) => {
330 let ExecutionErr { raw, reason } = *err;
331 sh_err!("Failed with `{reason}`:\n")?;
332 (Address::ZERO, raw)
333 }
334 Err(e) => {
335 eyre::bail!("Failed deploying contract: {e:?}");
336 }
337 };
338
339 Ok(ScriptResult {
340 returned: Bytes::new(),
341 success: address != Address::ZERO,
342 gas_used,
343 logs,
344 debug_bytecodes: self.maybe_debug_bytecodes(debug_bytecodes),
345 traces: traces
347 .map(|traces| vec![(TraceKind::Execution, traces)])
348 .unwrap_or_default(),
349 exit_reason,
350 address: Some(address),
351 ..Default::default()
352 })
353 }
354 }
355
356 fn call(
363 &mut self,
364 from: Address,
365 to: Address,
366 calldata: Bytes,
367 value: U256,
368 authorization_list: Option<Vec<SignedAuthorization>>,
369 commit: bool,
370 ) -> Result<ScriptResult<FEN::Network>> {
371 let mut res = if let Some(authorization_list) = &authorization_list {
372 self.executor.call_raw_with_authorization(
373 from,
374 to,
375 calldata.clone(),
376 value,
377 authorization_list.clone(),
378 )?
379 } else {
380 self.executor.call_raw(from, to, calldata.clone(), value)?
381 };
382 let mut gas_used = res.gas_used;
383
384 if commit {
390 gas_used = self.search_optimal_gas_usage(&res, from, to, &calldata, value)?;
391 res = if let Some(authorization_list) = authorization_list {
392 self.executor.transact_raw_with_authorization(
393 from,
394 to,
395 calldata,
396 value,
397 authorization_list,
398 )?
399 } else {
400 self.executor.transact_raw(from, to, calldata, value)?
401 }
402 }
403
404 let RawCallResult {
405 result,
406 reverted,
407 logs,
408 traces,
409 labels,
410 transactions,
411 debug_bytecodes,
412 exit_reason,
413 cheatcodes,
414 ..
415 } = res;
416 let breakpoints = cheatcodes.map(|cheats| cheats.breakpoints).unwrap_or_default();
417
418 Ok(ScriptResult {
419 returned: result,
420 success: !reverted,
421 gas_used,
422 logs,
423 debug_bytecodes: self.maybe_debug_bytecodes(debug_bytecodes),
424 traces: traces
425 .map(|traces| {
426 vec![(TraceKind::Execution, traces)]
429 })
430 .unwrap_or_default(),
431 labeled_addresses: labels,
432 transactions,
433 exit_reason,
434 address: None,
435 breakpoints,
436 })
437 }
438
439 fn search_optimal_gas_usage(
446 &mut self,
447 res: &RawCallResult<FEN>,
448 from: Address,
449 to: Address,
450 calldata: &Bytes,
451 value: U256,
452 ) -> Result<u64> {
453 let mut gas_used = res.gas_used;
454 if matches!(res.exit_reason, Some(return_ok!())) {
455 let init_gas_limit = self.executor.tx_env().gas_limit();
457
458 let mut highest_gas_limit = gas_used * 3;
459 let mut lowest_gas_limit = gas_used;
460 let mut last_highest_gas_limit = highest_gas_limit;
461 while (highest_gas_limit - lowest_gas_limit) > 1 {
462 let mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
463 self.executor.tx_env_mut().set_gas_limit(mid_gas_limit);
464 let res = self.executor.call_raw(from, to, calldata.0.clone().into(), value)?;
465 match res.exit_reason {
466 Some(
467 InstructionResult::Revert
468 | InstructionResult::OutOfGas
469 | InstructionResult::OutOfFunds,
470 ) => {
471 lowest_gas_limit = mid_gas_limit;
472 }
473 _ => {
474 highest_gas_limit = mid_gas_limit;
475 const ACCURACY: u64 = 10;
478 if (last_highest_gas_limit - highest_gas_limit) * ACCURACY
479 / last_highest_gas_limit
480 < 1
481 {
482 gas_used = highest_gas_limit;
484 break;
485 }
486 last_highest_gas_limit = highest_gas_limit;
487 }
488 }
489 }
490 self.executor.tx_env_mut().set_gas_limit(init_gas_limit);
492 }
493 Ok(gas_used)
494 }
495}