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