1use super::run::fetch_contracts_bytecode_from_trace;
2use crate::{
3 Cast,
4 traces::TraceKind,
5 tx::{CastTxBuilder, SenderKind},
6};
7use alloy_ens::NameOrAddress;
8use alloy_primitives::{Address, B256, Bytes, TxKind, U256, map::HashMap};
9use alloy_provider::Provider;
10use alloy_rpc_types::{
11 BlockId, BlockNumberOrTag, BlockOverrides,
12 state::{StateOverride, StateOverridesBuilder},
13};
14use clap::Parser;
15use eyre::Result;
16use foundry_cli::{
17 opts::{EthereumOpts, TransactionOpts},
18 utils::{self, TraceResult, handle_traces, parse_ether_value},
19};
20use foundry_common::shell;
21use foundry_compilers::artifacts::EvmVersion;
22use foundry_config::{
23 Config,
24 figment::{
25 self, Metadata, Profile,
26 value::{Dict, Map},
27 },
28};
29use foundry_evm::{
30 executors::TracingExecutor,
31 opts::EvmOpts,
32 traces::{InternalTraceMode, TraceMode},
33};
34use itertools::Either;
35use regex::Regex;
36use revm::context::TransactionType;
37use std::{str::FromStr, sync::LazyLock};
38
39static OVERRIDE_PATTERN: LazyLock<Regex> =
42 LazyLock::new(|| Regex::new(r"^([^:]+):([^:]+):([^:]+)$").unwrap());
43
44#[derive(Debug, Parser)]
66pub struct CallArgs {
67 #[arg(value_parser = NameOrAddress::from_str)]
69 to: Option<NameOrAddress>,
70
71 sig: Option<String>,
73
74 #[arg(allow_negative_numbers = true)]
76 args: Vec<String>,
77
78 #[arg(
80 long,
81 conflicts_with_all = &["sig", "args"]
82 )]
83 data: Option<String>,
84
85 #[arg(long, default_value_t = false)]
87 trace: bool,
88
89 #[arg(long, default_value_t = false, requires = "trace")]
92 disable_labels: bool,
93
94 #[arg(long, requires = "trace")]
97 debug: bool,
98
99 #[arg(long, requires = "trace")]
100 decode_internal: bool,
101
102 #[arg(long, requires = "trace")]
105 labels: Vec<String>,
106
107 #[arg(long, requires = "trace")]
110 evm_version: Option<EvmVersion>,
111
112 #[arg(long, short)]
116 block: Option<BlockId>,
117
118 #[command(subcommand)]
119 command: Option<CallSubcommands>,
120
121 #[command(flatten)]
122 tx: TransactionOpts,
123
124 #[command(flatten)]
125 eth: EthereumOpts,
126
127 #[arg(long, visible_alias = "la")]
129 pub with_local_artifacts: bool,
130
131 #[arg(long = "override-balance", value_name = "ADDRESS:BALANCE", value_delimiter = ',')]
134 pub balance_overrides: Option<Vec<String>>,
135
136 #[arg(long = "override-nonce", value_name = "ADDRESS:NONCE", value_delimiter = ',')]
139 pub nonce_overrides: Option<Vec<String>>,
140
141 #[arg(long = "override-code", value_name = "ADDRESS:CODE", value_delimiter = ',')]
144 pub code_overrides: Option<Vec<String>>,
145
146 #[arg(long = "override-state", value_name = "ADDRESS:SLOT:VALUE", value_delimiter = ',')]
149 pub state_overrides: Option<Vec<String>>,
150
151 #[arg(long = "override-state-diff", value_name = "ADDRESS:SLOT:VALUE", value_delimiter = ',')]
154 pub state_diff_overrides: Option<Vec<String>>,
155
156 #[arg(long = "block.time", value_name = "TIME")]
158 pub block_time: Option<u64>,
159
160 #[arg(long = "block.number", value_name = "NUMBER")]
162 pub block_number: Option<u64>,
163}
164
165#[derive(Debug, Parser)]
166pub enum CallSubcommands {
167 #[command(name = "--create")]
169 Create {
170 code: String,
172
173 sig: Option<String>,
175
176 #[arg(allow_negative_numbers = true)]
178 args: Vec<String>,
179
180 #[arg(long, value_parser = parse_ether_value)]
186 value: Option<U256>,
187 },
188}
189
190impl CallArgs {
191 pub async fn run(self) -> Result<()> {
192 let figment = self.eth.rpc.clone().into_figment(self.with_local_artifacts).merge(&self);
193 let evm_opts = figment.extract::<EvmOpts>()?;
194 let mut config = Config::from_provider(figment)?.sanitized();
195 let state_overrides = self.get_state_overrides()?;
196 let block_overrides = self.get_block_overrides()?;
197
198 let Self {
199 to,
200 mut sig,
201 mut args,
202 mut tx,
203 eth,
204 command,
205 block,
206 trace,
207 evm_version,
208 debug,
209 decode_internal,
210 labels,
211 data,
212 with_local_artifacts,
213 disable_labels,
214 ..
215 } = self;
216
217 if let Some(data) = data {
218 sig = Some(data);
219 }
220
221 let provider = utils::get_provider(&config)?;
222 let sender = SenderKind::from_wallet_opts(eth.wallet).await?;
223 let from = sender.address();
224
225 let code = if let Some(CallSubcommands::Create {
226 code,
227 sig: create_sig,
228 args: create_args,
229 value,
230 }) = command
231 {
232 sig = create_sig;
233 args = create_args;
234 if let Some(value) = value {
235 tx.value = Some(value);
236 }
237 Some(code)
238 } else {
239 None
240 };
241
242 let (tx, func) = CastTxBuilder::new(&provider, tx, &config)
243 .await?
244 .with_to(to)
245 .await?
246 .with_code_sig_and_args(code, sig, args)
247 .await?
248 .build_raw(sender)
249 .await?;
250
251 if trace {
252 if let Some(BlockId::Number(BlockNumberOrTag::Number(block_number))) = self.block {
253 config.fork_block_number = Some(block_number);
255 }
256
257 let create2_deployer = evm_opts.create2_deployer;
258 let (mut env, fork, chain, networks) =
259 TracingExecutor::get_fork_material(&config, evm_opts).await?;
260
261 env.evm_env.cfg_env.disable_block_gas_limit = true;
263 env.evm_env.cfg_env.tx_gas_limit_cap = Some(u64::MAX);
264 env.evm_env.block_env.gas_limit = u64::MAX;
265
266 if let Some(block_overrides) = block_overrides {
268 if let Some(number) = block_overrides.number {
269 env.evm_env.block_env.number = number.to();
270 }
271 if let Some(time) = block_overrides.time {
272 env.evm_env.block_env.timestamp = U256::from(time);
273 }
274 }
275
276 let trace_mode = TraceMode::Call
277 .with_debug(debug)
278 .with_decode_internal(if decode_internal {
279 InternalTraceMode::Full
280 } else {
281 InternalTraceMode::None
282 })
283 .with_state_changes(shell::verbosity() > 4);
284 let mut executor = TracingExecutor::new(
285 env,
286 fork,
287 evm_version,
288 trace_mode,
289 networks,
290 create2_deployer,
291 state_overrides,
292 )?;
293
294 let value = tx.value.unwrap_or_default();
295 let input = tx.inner.input.into_input().unwrap_or_default();
296 let tx_kind = tx.inner.to.expect("set by builder");
297 let env_tx = &mut executor.env_mut().tx;
298
299 if let Some(tx_type) = tx.inner.transaction_type {
300 env_tx.tx_type = tx_type;
301 }
302
303 if let Some(access_list) = tx.inner.access_list {
304 env_tx.access_list = access_list;
305
306 if env_tx.tx_type == TransactionType::Legacy as u8 {
307 env_tx.tx_type = TransactionType::Eip2930 as u8;
308 }
309 }
310
311 if let Some(auth) = tx.inner.authorization_list {
312 env_tx.authorization_list = auth.into_iter().map(Either::Left).collect();
313
314 env_tx.tx_type = TransactionType::Eip7702 as u8;
315 }
316
317 let trace = match tx_kind {
318 TxKind::Create => {
319 let deploy_result = executor.deploy(from, input, value, None);
320 TraceResult::try_from(deploy_result)?
321 }
322 TxKind::Call(to) => TraceResult::from_raw(
323 executor.transact_raw(from, to, input, value)?,
324 TraceKind::Execution,
325 ),
326 };
327
328 let contracts_bytecode = fetch_contracts_bytecode_from_trace(&provider, &trace).await?;
329 handle_traces(
330 trace,
331 &config,
332 chain,
333 &contracts_bytecode,
334 labels,
335 with_local_artifacts,
336 debug,
337 decode_internal,
338 disable_labels,
339 )
340 .await?;
341
342 return Ok(());
343 }
344
345 let response = Cast::new(&provider)
346 .call(&tx, func.as_ref(), block, state_overrides, block_overrides)
347 .await?;
348
349 if response == "0x"
350 && let Some(contract_address) = tx.to.and_then(|tx_kind| tx_kind.into_to())
351 {
352 let code = provider.get_code_at(contract_address).await?;
353 if code.is_empty() {
354 sh_warn!("Contract code is empty")?;
355 }
356 }
357 sh_println!("{}", response)?;
358
359 Ok(())
360 }
361
362 pub fn get_state_overrides(&self) -> eyre::Result<Option<StateOverride>> {
364 if [
366 self.balance_overrides.as_ref(),
367 self.nonce_overrides.as_ref(),
368 self.code_overrides.as_ref(),
369 self.state_overrides.as_ref(),
370 self.state_diff_overrides.as_ref(),
371 ]
372 .iter()
373 .all(Option::is_none)
374 {
375 return Ok(None);
376 }
377
378 let mut state_overrides_builder = StateOverridesBuilder::default();
379
380 for override_str in self.balance_overrides.iter().flatten() {
382 let (addr, balance) = address_value_override(override_str)?;
383 state_overrides_builder =
384 state_overrides_builder.with_balance(addr.parse()?, balance.parse()?);
385 }
386
387 for override_str in self.nonce_overrides.iter().flatten() {
389 let (addr, nonce) = address_value_override(override_str)?;
390 state_overrides_builder =
391 state_overrides_builder.with_nonce(addr.parse()?, nonce.parse()?);
392 }
393
394 for override_str in self.code_overrides.iter().flatten() {
396 let (addr, code_str) = address_value_override(override_str)?;
397 state_overrides_builder =
398 state_overrides_builder.with_code(addr.parse()?, Bytes::from_str(code_str)?);
399 }
400
401 type StateOverrides = HashMap<Address, HashMap<B256, B256>>;
402 let parse_state_overrides =
403 |overrides: &Option<Vec<String>>| -> Result<StateOverrides, eyre::Report> {
404 let mut state_overrides: StateOverrides = StateOverrides::default();
405
406 overrides.iter().flatten().try_for_each(|s| -> Result<(), eyre::Report> {
407 let (addr, slot, value) = address_slot_value_override(s)?;
408 state_overrides.entry(addr).or_default().insert(slot.into(), value.into());
409 Ok(())
410 })?;
411
412 Ok(state_overrides)
413 };
414
415 for (addr, entries) in parse_state_overrides(&self.state_overrides)? {
417 state_overrides_builder = state_overrides_builder.with_state(addr, entries.into_iter());
418 }
419
420 for (addr, entries) in parse_state_overrides(&self.state_diff_overrides)? {
422 state_overrides_builder =
423 state_overrides_builder.with_state_diff(addr, entries.into_iter())
424 }
425
426 Ok(Some(state_overrides_builder.build()))
427 }
428
429 pub fn get_block_overrides(&self) -> eyre::Result<Option<BlockOverrides>> {
431 let mut overrides = BlockOverrides::default();
432 if let Some(number) = self.block_number {
433 overrides = overrides.with_number(U256::from(number));
434 }
435 if let Some(time) = self.block_time {
436 overrides = overrides.with_time(time);
437 }
438 if overrides.is_empty() { Ok(None) } else { Ok(Some(overrides)) }
439 }
440}
441
442impl figment::Provider for CallArgs {
443 fn metadata(&self) -> Metadata {
444 Metadata::named("CallArgs")
445 }
446
447 fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {
448 let mut map = Map::new();
449
450 if let Some(evm_version) = self.evm_version {
451 map.insert("evm_version".into(), figment::value::Value::serialize(evm_version)?);
452 }
453
454 Ok(Map::from([(Config::selected_profile(), map)]))
455 }
456}
457
458fn address_value_override(address_override: &str) -> Result<(&str, &str)> {
460 address_override.split_once(':').ok_or_else(|| {
461 eyre::eyre!("Invalid override {address_override}. Expected <address>:<value>")
462 })
463}
464
465fn address_slot_value_override(address_override: &str) -> Result<(Address, U256, U256)> {
467 let captures = OVERRIDE_PATTERN.captures(address_override).ok_or_else(|| {
468 eyre::eyre!("Invalid override {address_override}. Expected <address>:<slot>:<value>")
469 })?;
470
471 Ok((
472 captures[1].parse()?, captures[2].parse()?, captures[3].parse()?, ))
476}
477
478#[cfg(test)]
479mod tests {
480 use super::*;
481 use alloy_primitives::{address, b256, fixed_bytes, hex};
482
483 #[test]
484 fn test_get_state_overrides() {
485 let call_args = CallArgs::parse_from([
486 "foundry-cli",
487 "--override-balance",
488 "0x0000000000000000000000000000000000000001:2",
489 "--override-nonce",
490 "0x0000000000000000000000000000000000000001:3",
491 "--override-code",
492 "0x0000000000000000000000000000000000000001:0x04",
493 "--override-state",
494 "0x0000000000000000000000000000000000000001:5:6",
495 "--override-state-diff",
496 "0x0000000000000000000000000000000000000001:7:8",
497 ]);
498 let overrides = call_args.get_state_overrides().unwrap().unwrap();
499 let address = address!("0x0000000000000000000000000000000000000001");
500 if let Some(account_override) = overrides.get(&address) {
501 if let Some(balance) = account_override.balance {
502 assert_eq!(balance, U256::from(2));
503 }
504 if let Some(nonce) = account_override.nonce {
505 assert_eq!(nonce, 3);
506 }
507 if let Some(code) = &account_override.code {
508 assert_eq!(*code, Bytes::from([0x04]));
509 }
510 if let Some(state) = &account_override.state
511 && let Some(value) = state.get(&b256!(
512 "0x0000000000000000000000000000000000000000000000000000000000000005"
513 ))
514 {
515 assert_eq!(
516 *value,
517 b256!("0x0000000000000000000000000000000000000000000000000000000000000006")
518 );
519 }
520 if let Some(state_diff) = &account_override.state_diff
521 && let Some(value) = state_diff.get(&b256!(
522 "0x0000000000000000000000000000000000000000000000000000000000000007"
523 ))
524 {
525 assert_eq!(
526 *value,
527 b256!("0x0000000000000000000000000000000000000000000000000000000000000008")
528 );
529 }
530 }
531 }
532
533 #[test]
534 fn test_get_state_overrides_empty() {
535 let call_args = CallArgs::parse_from([""]);
536 let overrides = call_args.get_state_overrides().unwrap();
537 assert_eq!(overrides, None);
538 }
539
540 #[test]
541 fn test_get_block_overrides() {
542 let mut call_args = CallArgs::parse_from([""]);
543 call_args.block_number = Some(1);
544 call_args.block_time = Some(2);
545 let overrides = call_args.get_block_overrides().unwrap().unwrap();
546 assert_eq!(overrides.number, Some(U256::from(1)));
547 assert_eq!(overrides.time, Some(2));
548 }
549
550 #[test]
551 fn test_get_block_overrides_empty() {
552 let call_args = CallArgs::parse_from([""]);
553 let overrides = call_args.get_block_overrides().unwrap();
554 assert_eq!(overrides, None);
555 }
556
557 #[test]
558 fn test_address_value_override_success() {
559 let text = "0x0000000000000000000000000000000000000001:2";
560 let (address, value) = address_value_override(text).unwrap();
561 assert_eq!(address, "0x0000000000000000000000000000000000000001");
562 assert_eq!(value, "2");
563 }
564
565 #[test]
566 fn test_address_value_override_error() {
567 let text = "invalid_value";
568 let error = address_value_override(text).unwrap_err();
569 assert_eq!(error.to_string(), "Invalid override invalid_value. Expected <address>:<value>");
570 }
571
572 #[test]
573 fn test_address_slot_value_override_success() {
574 let text = "0x0000000000000000000000000000000000000001:2:3";
575 let (address, slot, value) = address_slot_value_override(text).unwrap();
576 assert_eq!(*address, fixed_bytes!("0x0000000000000000000000000000000000000001"));
577 assert_eq!(slot, U256::from(2));
578 assert_eq!(value, U256::from(3));
579 }
580
581 #[test]
582 fn test_address_slot_value_override_error() {
583 let text = "invalid_value";
584 let error = address_slot_value_override(text).unwrap_err();
585 assert_eq!(
586 error.to_string(),
587 "Invalid override invalid_value. Expected <address>:<slot>:<value>"
588 );
589 }
590
591 #[test]
592 fn can_parse_call_data() {
593 let data = hex::encode("hello");
594 let args = CallArgs::parse_from(["foundry-cli", "--data", data.as_str()]);
595 assert_eq!(args.data, Some(data));
596
597 let data = hex::encode_prefixed("hello");
598 let args = CallArgs::parse_from(["foundry-cli", "--data", data.as_str()]);
599 assert_eq!(args.data, Some(data));
600 }
601
602 #[test]
603 fn can_parse_state_overrides() {
604 let args = CallArgs::parse_from([
605 "foundry-cli",
606 "--override-balance",
607 "0x123:0x1234",
608 "--override-nonce",
609 "0x123:1",
610 "--override-code",
611 "0x123:0x1234",
612 "--override-state",
613 "0x123:0x1:0x1234",
614 ]);
615
616 assert_eq!(args.balance_overrides, Some(vec!["0x123:0x1234".to_string()]));
617 assert_eq!(args.nonce_overrides, Some(vec!["0x123:1".to_string()]));
618 assert_eq!(args.code_overrides, Some(vec!["0x123:0x1234".to_string()]));
619 assert_eq!(args.state_overrides, Some(vec!["0x123:0x1:0x1234".to_string()]));
620 }
621
622 #[test]
623 fn can_parse_multiple_state_overrides() {
624 let args = CallArgs::parse_from([
625 "foundry-cli",
626 "--override-balance",
627 "0x123:0x1234",
628 "--override-balance",
629 "0x456:0x5678",
630 "--override-nonce",
631 "0x123:1",
632 "--override-nonce",
633 "0x456:2",
634 "--override-code",
635 "0x123:0x1234",
636 "--override-code",
637 "0x456:0x5678",
638 "--override-state",
639 "0x123:0x1:0x1234",
640 "--override-state",
641 "0x456:0x2:0x5678",
642 ]);
643
644 assert_eq!(
645 args.balance_overrides,
646 Some(vec!["0x123:0x1234".to_string(), "0x456:0x5678".to_string()])
647 );
648 assert_eq!(args.nonce_overrides, Some(vec!["0x123:1".to_string(), "0x456:2".to_string()]));
649 assert_eq!(
650 args.code_overrides,
651 Some(vec!["0x123:0x1234".to_string(), "0x456:0x5678".to_string()])
652 );
653 assert_eq!(
654 args.state_overrides,
655 Some(vec!["0x123:0x1:0x1234".to_string(), "0x456:0x2:0x5678".to_string()])
656 );
657 }
658
659 #[test]
660 fn test_negative_args_with_flags() {
661 let args = CallArgs::parse_from([
663 "foundry-cli",
664 "--trace",
665 "0xDeaDBeeFcAfEbAbEfAcEfEeDcBaDbEeFcAfEbAbE",
666 "process(int256)",
667 "-999999",
668 "--debug",
669 ]);
670
671 assert!(args.trace);
672 assert!(args.debug);
673 assert_eq!(args.args, vec!["-999999"]);
674 }
675}