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::{LIBRARY_DEPLOYER, 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 fn deploy_local_libraries(
60 &mut self,
61 libraries: &[foundry_linking::LinkedLibrary],
62 debug_bytecodes: &mut AddressHashMap<Bytes>,
63 ) -> Result<()> {
64 if libraries.is_empty() {
65 return Ok(());
66 }
67 let balance = self.executor.get_balance(LIBRARY_DEPLOYER)?;
68 let nonce = self.executor.get_nonce(LIBRARY_DEPLOYER)?;
69 self.executor.set_balance(LIBRARY_DEPLOYER, U256::MAX)?;
70 self.executor.set_nonce(LIBRARY_DEPLOYER, 0)?;
71 for library in libraries {
72 let DeployResult { address, raw } = self
73 .executor
74 .deploy(LIBRARY_DEPLOYER, library.bytecode.clone(), U256::ZERO, None)
75 .map_err(|err| eyre::eyre!("couldn't deploy local library: {err}"))?;
76 eyre::ensure!(
77 library.address == address,
78 "local library deployed at an unexpected address"
79 );
80 self.extend_debug_bytecodes(debug_bytecodes, raw.debug_bytecodes);
81 }
82 self.executor.set_balance(LIBRARY_DEPLOYER, balance)?;
83 self.executor.set_nonce(LIBRARY_DEPLOYER, nonce)?;
84 Ok(())
85 }
86
87 pub fn setup(
89 &mut self,
90 libraries: &ScriptPredeployLibraries,
91 code: Bytes,
92 setup: bool,
93 script_config: &ScriptConfig<FEN>,
94 is_broadcast: bool,
95 ) -> Result<(Address, ScriptResult<FEN::Network>)> {
96 trace!(target: "script", "executing setUP()");
97
98 if !is_broadcast {
99 if self.evm_opts.sender == Config::DEFAULT_SENDER {
100 self.executor.set_balance(self.evm_opts.sender, U256::MAX)?;
102 }
103
104 if script_config.evm_opts.fork_url.is_none()
105 && !script_config.evm_opts.networks.is_tempo()
106 {
107 self.executor.deploy_create2_deployer()?;
108 }
109 }
110
111 let sender_nonce = script_config.sender_nonce;
112 self.executor.set_nonce(self.evm_opts.sender, sender_nonce)?;
113
114 self.executor.set_balance(CALLER, U256::MAX)?;
116
117 let mut library_transactions = VecDeque::new();
118 let mut traces = Traces::default();
119 let mut debug_bytecodes: AddressHashMap<Bytes> = Default::default();
120
121 match libraries {
123 ScriptPredeployLibraries::Default { onchain, local } => {
124 self.deploy_local_libraries(local, &mut debug_bytecodes)?;
125 for library in onchain {
126 let code = &library.bytecode;
127 let RawCallResult {
128 traces: deploy_traces,
129 debug_bytecodes: deploy_debug_bytecodes,
130 ..
131 } = self
132 .executor
133 .deploy(self.evm_opts.sender, code.clone(), U256::ZERO, None)
134 .map_err(|err| eyre::eyre!("couldn't deploy library: {err}"))?
135 .raw;
136
137 self.extend_debug_bytecodes(&mut debug_bytecodes, deploy_debug_bytecodes);
138
139 if let Some(deploy_traces) = deploy_traces {
140 traces.push((TraceKind::Deployment, deploy_traces));
141 }
142
143 let mut tx_req = TransactionRequestFor::<FEN>::default()
144 .with_from(self.evm_opts.sender)
145 .with_input(code.clone())
146 .with_nonce(sender_nonce + library_transactions.len() as u64);
147
148 script_config.tempo.apply::<FEN::Network>(&mut tx_req, None);
149
150 library_transactions.push_back(BroadcastableTransaction {
151 rpc: self.evm_opts.fork_url.clone(),
152 transaction: TransactionMaybeSigned::new(tx_req),
153 })
154 }
155 }
156 ScriptPredeployLibraries::Create2 { onchain, salt, local } => {
157 self.deploy_local_libraries(local, &mut debug_bytecodes)?;
158 let create2_deployer = self.executor.create2_deployer();
159 for library in onchain {
160 let address =
161 create2_deployer.create2_from_code(salt, library.bytecode.as_ref());
162 if !self.executor.is_empty_code(address)? {
164 continue;
165 }
166 let calldata = [salt.as_ref(), library.bytecode.as_ref()].concat();
167 let RawCallResult {
168 traces: deploy_traces,
169 debug_bytecodes: deploy_debug_bytecodes,
170 ..
171 } = self
172 .executor
173 .transact_raw(
174 self.evm_opts.sender,
175 create2_deployer,
176 calldata.clone().into(),
177 U256::from(0),
178 )
179 .map_err(|err| eyre::eyre!("couldn't deploy library: {err}"))?;
180
181 self.extend_debug_bytecodes(&mut debug_bytecodes, deploy_debug_bytecodes);
182
183 if let Some(deploy_traces) = deploy_traces {
184 traces.push((TraceKind::Deployment, deploy_traces));
185 }
186
187 let mut tx_req = TransactionRequestFor::<FEN>::default()
188 .with_from(self.evm_opts.sender)
189 .with_input(calldata)
190 .with_nonce(sender_nonce + library_transactions.len() as u64)
191 .with_to(create2_deployer);
192
193 script_config.tempo.apply::<FEN::Network>(&mut tx_req, None);
194
195 library_transactions.push_back(BroadcastableTransaction {
196 rpc: self.evm_opts.fork_url.clone(),
197 transaction: TransactionMaybeSigned::new(tx_req),
198 });
199 }
200
201 self.executor.set_nonce(
204 self.evm_opts.sender,
205 sender_nonce + library_transactions.len() as u64,
206 )?;
207 }
208 };
209
210 let address = CALLER.create(self.executor.get_nonce(CALLER)?);
211
212 self.executor.set_balance(address, self.evm_opts.initial_balance)?;
215
216 let prev_sender_nonce = self.executor.get_nonce(self.evm_opts.sender)?;
223 if self.evm_opts.sender == CALLER {
224 self.executor.set_nonce(self.evm_opts.sender, u64::MAX / 2)?;
225 }
226
227 let DeployResult {
229 address,
230 raw:
231 RawCallResult {
232 mut logs,
233 traces: constructor_traces,
234 debug_bytecodes: constructor_debug_bytecodes,
235 ..
236 },
237 } = self
238 .executor
239 .deploy(CALLER, code, U256::ZERO, None)
240 .map_err(|err| eyre::eyre!("Failed to deploy script:\n{}", err))?;
241
242 if self.evm_opts.sender == CALLER {
243 self.executor.set_nonce(self.evm_opts.sender, prev_sender_nonce)?;
244 }
245
246 if script_config.config.script_execution_protection {
248 self.executor.set_script_execution(address);
249 }
250
251 traces.extend(constructor_traces.map(|traces| (TraceKind::Deployment, traces)));
252 self.extend_debug_bytecodes(&mut debug_bytecodes, constructor_debug_bytecodes);
253
254 let (success, gas_used, labeled_addresses, transactions) = if setup {
256 match self.executor.setup(Some(self.evm_opts.sender), address, None) {
257 Ok(RawCallResult {
258 reverted,
259 traces: setup_traces,
260 labels,
261 logs: setup_logs,
262 gas_used,
263 debug_bytecodes: setup_debug_bytecodes,
264 transactions: setup_transactions,
265 ..
266 }) => {
267 traces.extend(setup_traces.map(|traces| (TraceKind::Setup, traces)));
268 logs.extend_from_slice(&setup_logs);
269 self.extend_debug_bytecodes(&mut debug_bytecodes, setup_debug_bytecodes);
270
271 if let Some(txs) = setup_transactions {
272 library_transactions.extend(txs);
273 }
274
275 (!reverted, gas_used, labels, Some(library_transactions))
276 }
277 Err(EvmError::Execution(err)) => {
278 let RawCallResult {
279 reverted,
280 traces: setup_traces,
281 labels,
282 logs: setup_logs,
283 gas_used,
284 debug_bytecodes: setup_debug_bytecodes,
285 transactions,
286 ..
287 } = err.raw;
288 traces.extend(setup_traces.map(|traces| (TraceKind::Setup, traces)));
289 logs.extend_from_slice(&setup_logs);
290 self.extend_debug_bytecodes(&mut debug_bytecodes, setup_debug_bytecodes);
291
292 if let Some(txs) = transactions {
293 library_transactions.extend(txs);
294 }
295
296 (!reverted, gas_used, labels, Some(library_transactions))
297 }
298 Err(e) => return Err(e.into()),
299 }
300 } else {
301 self.executor.backend_mut().set_test_contract(address);
302 (true, 0, Default::default(), Some(library_transactions))
303 };
304
305 Ok((
306 address,
307 ScriptResult {
308 returned: Bytes::new(),
309 success,
310 gas_used,
311 labeled_addresses,
312 debug_bytecodes: self.maybe_debug_bytecodes(debug_bytecodes),
313 transactions,
314 logs,
315 traces,
316 address: None,
317 ..Default::default()
318 },
319 ))
320 }
321
322 pub fn script(
324 &mut self,
325 address: Address,
326 calldata: Bytes,
327 ) -> Result<ScriptResult<FEN::Network>> {
328 self.call(self.evm_opts.sender, address, calldata, U256::ZERO, None, false)
329 }
330
331 pub fn simulate(
333 &mut self,
334 from: Address,
335 to: Option<Address>,
336 calldata: Option<Bytes>,
337 value: Option<U256>,
338 authorization_list: Option<Vec<SignedAuthorization>>,
339 ) -> Result<ScriptResult<FEN::Network>> {
340 if let Some(to) = to {
341 self.call(
342 from,
343 to,
344 calldata.unwrap_or_default(),
345 value.unwrap_or(U256::ZERO),
346 authorization_list,
347 true,
348 )
349 } else {
350 let res = self.executor.deploy(
351 from,
352 calldata.expect("No data for create transaction"),
353 value.unwrap_or(U256::ZERO),
354 None,
355 );
356 let (
357 address,
358 RawCallResult { gas_used, logs, traces, debug_bytecodes, exit_reason, .. },
359 ) = match res {
360 Ok(DeployResult { address, raw }) => (address, raw),
361 Err(EvmError::Execution(err)) => {
362 let ExecutionErr { raw, reason } = *err;
363 sh_err!("Failed with `{reason}`:\n")?;
364 (Address::ZERO, raw)
365 }
366 Err(e) => {
367 eyre::bail!("Failed deploying contract: {e:?}");
368 }
369 };
370
371 Ok(ScriptResult {
372 returned: Bytes::new(),
373 success: address != Address::ZERO,
374 gas_used,
375 logs,
376 debug_bytecodes: self.maybe_debug_bytecodes(debug_bytecodes),
377 traces: traces
379 .map(|traces| vec![(TraceKind::Execution, traces)])
380 .unwrap_or_default(),
381 exit_reason,
382 address: Some(address),
383 ..Default::default()
384 })
385 }
386 }
387
388 fn call(
395 &mut self,
396 from: Address,
397 to: Address,
398 calldata: Bytes,
399 value: U256,
400 authorization_list: Option<Vec<SignedAuthorization>>,
401 commit: bool,
402 ) -> Result<ScriptResult<FEN::Network>> {
403 let mut res = if let Some(authorization_list) = &authorization_list {
404 self.executor.call_raw_with_authorization(
405 from,
406 to,
407 calldata.clone(),
408 value,
409 authorization_list.clone(),
410 )?
411 } else {
412 self.executor.call_raw(from, to, calldata.clone(), value)?
413 };
414 let mut gas_used = res.gas_used;
415
416 if commit {
422 gas_used = self.search_optimal_gas_usage(&res, from, to, &calldata, value)?;
423 res = if let Some(authorization_list) = authorization_list {
424 self.executor.transact_raw_with_authorization(
425 from,
426 to,
427 calldata,
428 value,
429 authorization_list,
430 )?
431 } else {
432 self.executor.transact_raw(from, to, calldata, value)?
433 }
434 }
435
436 let RawCallResult {
437 result,
438 reverted,
439 logs,
440 traces,
441 labels,
442 transactions,
443 debug_bytecodes,
444 exit_reason,
445 cheatcodes,
446 ..
447 } = res;
448 let breakpoints = cheatcodes.map(|cheats| cheats.breakpoints).unwrap_or_default();
449
450 Ok(ScriptResult {
451 returned: result,
452 success: !reverted,
453 gas_used,
454 logs,
455 debug_bytecodes: self.maybe_debug_bytecodes(debug_bytecodes),
456 traces: traces
457 .map(|traces| {
458 vec![(TraceKind::Execution, traces)]
461 })
462 .unwrap_or_default(),
463 labeled_addresses: labels,
464 transactions,
465 exit_reason,
466 address: None,
467 breakpoints,
468 })
469 }
470
471 fn search_optimal_gas_usage(
478 &mut self,
479 res: &RawCallResult<FEN>,
480 from: Address,
481 to: Address,
482 calldata: &Bytes,
483 value: U256,
484 ) -> Result<u64> {
485 let mut gas_used = res.gas_used;
486 if matches!(res.exit_reason, Some(return_ok!())) {
487 let init_gas_limit = self.executor.tx_env().gas_limit();
489
490 let mut highest_gas_limit = gas_used * 3;
491 let mut lowest_gas_limit = gas_used;
492 let mut last_highest_gas_limit = highest_gas_limit;
493 while (highest_gas_limit - lowest_gas_limit) > 1 {
494 let mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
495 self.executor.tx_env_mut().set_gas_limit(mid_gas_limit);
496 let res = self.executor.call_raw(from, to, calldata.0.clone().into(), value)?;
497 match res.exit_reason {
498 Some(
499 InstructionResult::Revert
500 | InstructionResult::OutOfGas
501 | InstructionResult::OutOfFunds,
502 ) => {
503 lowest_gas_limit = mid_gas_limit;
504 }
505 _ => {
506 highest_gas_limit = mid_gas_limit;
507 const ACCURACY: u64 = 10;
510 if (last_highest_gas_limit - highest_gas_limit) * ACCURACY
511 / last_highest_gas_limit
512 < 1
513 {
514 gas_used = highest_gas_limit;
516 break;
517 }
518 last_highest_gas_limit = highest_gas_limit;
519 }
520 }
521 }
522 self.executor.tx_env_mut().set_gas_limit(init_gas_limit);
524 }
525 Ok(gas_used)
526 }
527}