1use super::ScriptResult;
2use crate::build::ScriptPredeployLibraries;
3use alloy_eips::eip7702::SignedAuthorization;
4use alloy_primitives::{Address, Bytes, TxKind, U256};
5use alloy_rpc_types::TransactionRequest;
6use eyre::Result;
7use foundry_cheatcodes::BroadcastableTransaction;
8use foundry_config::Config;
9use foundry_evm::{
10 constants::CALLER,
11 executors::{DeployResult, EvmError, ExecutionErr, Executor, RawCallResult},
12 opts::EvmOpts,
13 revm::interpreter::{return_ok, InstructionResult},
14 traces::{TraceKind, Traces},
15};
16use std::collections::VecDeque;
17
18#[derive(Debug)]
20pub struct ScriptRunner {
21 pub executor: Executor,
22 pub evm_opts: EvmOpts,
23}
24
25impl ScriptRunner {
26 pub fn new(executor: Executor, evm_opts: EvmOpts) -> Self {
27 Self { executor, evm_opts }
28 }
29
30 pub fn setup(
32 &mut self,
33 libraries: &ScriptPredeployLibraries,
34 code: Bytes,
35 setup: bool,
36 sender_nonce: u64,
37 is_broadcast: bool,
38 need_create2_deployer: bool,
39 ) -> Result<(Address, ScriptResult)> {
40 trace!(target: "script", "executing setUP()");
41
42 if !is_broadcast {
43 if self.evm_opts.sender == Config::DEFAULT_SENDER {
44 self.executor.set_balance(self.evm_opts.sender, U256::MAX)?;
46 }
47
48 if need_create2_deployer {
49 self.executor.deploy_create2_deployer()?;
50 }
51 }
52
53 self.executor.set_nonce(self.evm_opts.sender, sender_nonce)?;
54
55 self.executor.set_balance(CALLER, U256::MAX)?;
57
58 let mut library_transactions = VecDeque::new();
59 let mut traces = Traces::default();
60
61 match libraries {
63 ScriptPredeployLibraries::Default(libraries) => libraries.iter().for_each(|code| {
64 let result = self
65 .executor
66 .deploy(self.evm_opts.sender, code.clone(), U256::ZERO, None)
67 .expect("couldn't deploy library")
68 .raw;
69
70 if let Some(deploy_traces) = result.traces {
71 traces.push((TraceKind::Deployment, deploy_traces));
72 }
73
74 library_transactions.push_back(BroadcastableTransaction {
75 rpc: self.evm_opts.fork_url.clone(),
76 transaction: TransactionRequest {
77 from: Some(self.evm_opts.sender),
78 input: code.clone().into(),
79 nonce: Some(sender_nonce + library_transactions.len() as u64),
80 ..Default::default()
81 }
82 .into(),
83 })
84 }),
85 ScriptPredeployLibraries::Create2(libraries, salt) => {
86 let create2_deployer = self.executor.create2_deployer();
87 for library in libraries {
88 let address = create2_deployer.create2_from_code(salt, library.as_ref());
89 if !self.executor.is_empty_code(address)? {
91 continue;
92 }
93 let calldata = [salt.as_ref(), library.as_ref()].concat();
94 let result = self
95 .executor
96 .transact_raw(
97 self.evm_opts.sender,
98 create2_deployer,
99 calldata.clone().into(),
100 U256::from(0),
101 )
102 .expect("couldn't deploy library");
103
104 if let Some(deploy_traces) = result.traces {
105 traces.push((TraceKind::Deployment, deploy_traces));
106 }
107
108 library_transactions.push_back(BroadcastableTransaction {
109 rpc: self.evm_opts.fork_url.clone(),
110 transaction: TransactionRequest {
111 from: Some(self.evm_opts.sender),
112 input: calldata.into(),
113 nonce: Some(sender_nonce + library_transactions.len() as u64),
114 to: Some(TxKind::Call(create2_deployer)),
115 ..Default::default()
116 }
117 .into(),
118 });
119 }
120
121 self.executor.set_nonce(
124 self.evm_opts.sender,
125 sender_nonce + library_transactions.len() as u64,
126 )?;
127 }
128 };
129
130 let address = CALLER.create(self.executor.get_nonce(CALLER)?);
131
132 self.executor.set_balance(address, self.evm_opts.initial_balance)?;
135
136 let prev_sender_nonce = self.executor.get_nonce(self.evm_opts.sender)?;
143 if self.evm_opts.sender == CALLER {
144 self.executor.set_nonce(self.evm_opts.sender, u64::MAX / 2)?;
145 }
146
147 let DeployResult {
149 address,
150 raw: RawCallResult { mut logs, traces: constructor_traces, .. },
151 } = self
152 .executor
153 .deploy(CALLER, code, U256::ZERO, None)
154 .map_err(|err| eyre::eyre!("Failed to deploy script:\n{}", err))?;
155
156 if self.evm_opts.sender == CALLER {
157 self.executor.set_nonce(self.evm_opts.sender, prev_sender_nonce)?;
158 }
159
160 traces.extend(constructor_traces.map(|traces| (TraceKind::Deployment, traces)));
161
162 let (success, gas_used, labeled_addresses, transactions) = if !setup {
164 self.executor.backend_mut().set_test_contract(address);
165 (true, 0, Default::default(), Some(library_transactions))
166 } else {
167 match self.executor.setup(Some(self.evm_opts.sender), address, None) {
168 Ok(RawCallResult {
169 reverted,
170 traces: setup_traces,
171 labels,
172 logs: setup_logs,
173 gas_used,
174 transactions: setup_transactions,
175 ..
176 }) => {
177 traces.extend(setup_traces.map(|traces| (TraceKind::Setup, traces)));
178 logs.extend_from_slice(&setup_logs);
179
180 if let Some(txs) = setup_transactions {
181 library_transactions.extend(txs);
182 }
183
184 (!reverted, gas_used, labels, Some(library_transactions))
185 }
186 Err(EvmError::Execution(err)) => {
187 let RawCallResult {
188 reverted,
189 traces: setup_traces,
190 labels,
191 logs: setup_logs,
192 gas_used,
193 transactions,
194 ..
195 } = err.raw;
196 traces.extend(setup_traces.map(|traces| (TraceKind::Setup, traces)));
197 logs.extend_from_slice(&setup_logs);
198
199 if let Some(txs) = transactions {
200 library_transactions.extend(txs);
201 }
202
203 (!reverted, gas_used, labels, Some(library_transactions))
204 }
205 Err(e) => return Err(e.into()),
206 }
207 };
208
209 Ok((
210 address,
211 ScriptResult {
212 returned: Bytes::new(),
213 success,
214 gas_used,
215 labeled_addresses,
216 transactions,
217 logs,
218 traces,
219 address: None,
220 ..Default::default()
221 },
222 ))
223 }
224
225 pub fn script(&mut self, address: Address, calldata: Bytes) -> Result<ScriptResult> {
227 self.call(self.evm_opts.sender, address, calldata, U256::ZERO, None, false)
228 }
229
230 pub fn simulate(
232 &mut self,
233 from: Address,
234 to: Option<Address>,
235 calldata: Option<Bytes>,
236 value: Option<U256>,
237 authorization_list: Option<Vec<SignedAuthorization>>,
238 ) -> Result<ScriptResult> {
239 if let Some(to) = to {
240 self.call(
241 from,
242 to,
243 calldata.unwrap_or_default(),
244 value.unwrap_or(U256::ZERO),
245 authorization_list,
246 true,
247 )
248 } else if to.is_none() {
249 let res = self.executor.deploy(
250 from,
251 calldata.expect("No data for create transaction"),
252 value.unwrap_or(U256::ZERO),
253 None,
254 );
255 let (address, RawCallResult { gas_used, logs, traces, .. }) = match res {
256 Ok(DeployResult { address, raw }) => (address, raw),
257 Err(EvmError::Execution(err)) => {
258 let ExecutionErr { raw, reason } = *err;
259 sh_err!("Failed with `{reason}`:\n")?;
260 (Address::ZERO, raw)
261 }
262 Err(e) => eyre::bail!("Failed deploying contract: {e:?}"),
263 };
264
265 Ok(ScriptResult {
266 returned: Bytes::new(),
267 success: address != Address::ZERO,
268 gas_used,
269 logs,
270 traces: traces
272 .map(|traces| vec![(TraceKind::Execution, traces)])
273 .unwrap_or_default(),
274 address: Some(address),
275 ..Default::default()
276 })
277 } else {
278 eyre::bail!("ENS not supported.");
279 }
280 }
281
282 fn call(
289 &mut self,
290 from: Address,
291 to: Address,
292 calldata: Bytes,
293 value: U256,
294 authorization_list: Option<Vec<SignedAuthorization>>,
295 commit: bool,
296 ) -> Result<ScriptResult> {
297 let mut res = if let Some(authorization_list) = authorization_list {
298 self.executor.call_raw_with_authorization(
299 from,
300 to,
301 calldata.clone(),
302 value,
303 authorization_list,
304 )?
305 } else {
306 self.executor.call_raw(from, to, calldata.clone(), value)?
307 };
308 let mut gas_used = res.gas_used;
309
310 if commit {
316 gas_used = self.search_optimal_gas_usage(&res, from, to, &calldata, value)?;
317 res = self.executor.transact_raw(from, to, calldata, value)?;
318 }
319
320 let RawCallResult { result, reverted, logs, traces, labels, transactions, .. } = res;
321 let breakpoints = res.cheatcodes.map(|cheats| cheats.breakpoints).unwrap_or_default();
322
323 Ok(ScriptResult {
324 returned: result,
325 success: !reverted,
326 gas_used,
327 logs,
328 traces: traces
329 .map(|traces| {
330 vec![(TraceKind::Execution, traces)]
333 })
334 .unwrap_or_default(),
335 labeled_addresses: labels,
336 transactions,
337 address: None,
338 breakpoints,
339 })
340 }
341
342 fn search_optimal_gas_usage(
349 &mut self,
350 res: &RawCallResult,
351 from: Address,
352 to: Address,
353 calldata: &Bytes,
354 value: U256,
355 ) -> Result<u64> {
356 let mut gas_used = res.gas_used;
357 if matches!(res.exit_reason, return_ok!()) {
358 let init_gas_limit = self.executor.env().tx.gas_limit;
360
361 let mut highest_gas_limit = gas_used * 3;
362 let mut lowest_gas_limit = gas_used;
363 let mut last_highest_gas_limit = highest_gas_limit;
364 while (highest_gas_limit - lowest_gas_limit) > 1 {
365 let mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
366 self.executor.env_mut().tx.gas_limit = mid_gas_limit;
367 let res = self.executor.call_raw(from, to, calldata.0.clone().into(), value)?;
368 match res.exit_reason {
369 InstructionResult::Revert |
370 InstructionResult::OutOfGas |
371 InstructionResult::OutOfFunds => {
372 lowest_gas_limit = mid_gas_limit;
373 }
374 _ => {
375 highest_gas_limit = mid_gas_limit;
376 const ACCURACY: u64 = 10;
379 if (last_highest_gas_limit - highest_gas_limit) * ACCURACY /
380 last_highest_gas_limit <
381 1
382 {
383 gas_used = highest_gas_limit;
385 break;
386 }
387 last_highest_gas_limit = highest_gas_limit;
388 }
389 }
390 }
391 self.executor.env_mut().tx.gas_limit = init_gas_limit;
393 }
394 Ok(gas_used)
395 }
396}