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(&executor, &trace)?;
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 None,
372 )
373 .await?;
374
375 return Ok(());
376 }
377
378 let response = Cast::new(&provider)
379 .call(&tx, func.as_ref(), block, state_overrides, block_overrides)
380 .await?;
381
382 if response == "0x"
383 && let Some(contract_address) = tx.to.and_then(|tx_kind| tx_kind.into_to())
384 {
385 let code = provider.get_code_at(contract_address).await?;
386 if code.is_empty() {
387 sh_warn!("Contract code is empty")?;
388 }
389 }
390 sh_println!("{}", response)?;
391
392 Ok(())
393 }
394
395 pub fn get_state_overrides(&self) -> eyre::Result<Option<StateOverride>> {
397 if [
399 self.balance_overrides.as_ref(),
400 self.nonce_overrides.as_ref(),
401 self.code_overrides.as_ref(),
402 self.state_overrides.as_ref(),
403 self.state_diff_overrides.as_ref(),
404 ]
405 .iter()
406 .all(Option::is_none)
407 {
408 return Ok(None);
409 }
410
411 let mut state_overrides_builder = StateOverridesBuilder::default();
412
413 for override_str in self.balance_overrides.iter().flatten() {
415 let (addr, balance) = address_value_override(override_str)?;
416 state_overrides_builder =
417 state_overrides_builder.with_balance(addr.parse()?, balance.parse()?);
418 }
419
420 for override_str in self.nonce_overrides.iter().flatten() {
422 let (addr, nonce) = address_value_override(override_str)?;
423 state_overrides_builder =
424 state_overrides_builder.with_nonce(addr.parse()?, nonce.parse()?);
425 }
426
427 for override_str in self.code_overrides.iter().flatten() {
429 let (addr, code_str) = address_value_override(override_str)?;
430 state_overrides_builder =
431 state_overrides_builder.with_code(addr.parse()?, Bytes::from_str(code_str)?);
432 }
433
434 type StateOverrides = HashMap<Address, HashMap<B256, B256>>;
435 let parse_state_overrides =
436 |overrides: &Option<Vec<String>>| -> Result<StateOverrides, eyre::Report> {
437 let mut state_overrides: StateOverrides = StateOverrides::default();
438
439 overrides.iter().flatten().try_for_each(|s| -> Result<(), eyre::Report> {
440 let (addr, slot, value) = address_slot_value_override(s)?;
441 state_overrides.entry(addr).or_default().insert(slot.into(), value.into());
442 Ok(())
443 })?;
444
445 Ok(state_overrides)
446 };
447
448 for (addr, entries) in parse_state_overrides(&self.state_overrides)? {
450 state_overrides_builder = state_overrides_builder.with_state(addr, entries.into_iter());
451 }
452
453 for (addr, entries) in parse_state_overrides(&self.state_diff_overrides)? {
455 state_overrides_builder =
456 state_overrides_builder.with_state_diff(addr, entries.into_iter())
457 }
458
459 Ok(Some(state_overrides_builder.build()))
460 }
461
462 pub fn get_block_overrides(&self) -> eyre::Result<Option<BlockOverrides>> {
464 let mut overrides = BlockOverrides::default();
465 if let Some(number) = self.block_number {
466 overrides = overrides.with_number(U256::from(number));
467 }
468 if let Some(time) = self.block_time {
469 overrides = overrides.with_time(time);
470 }
471 if overrides.is_empty() { Ok(None) } else { Ok(Some(overrides)) }
472 }
473}
474
475impl figment::Provider for CallArgs {
476 fn metadata(&self) -> Metadata {
477 Metadata::named("CallArgs")
478 }
479
480 fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {
481 let mut map = Map::new();
482
483 if let Some(evm_version) = self.evm_version {
484 map.insert("evm_version".into(), figment::value::Value::serialize(evm_version)?);
485 }
486
487 Ok(Map::from([(Config::selected_profile(), map)]))
488 }
489}
490
491fn address_value_override(address_override: &str) -> Result<(&str, &str)> {
493 address_override.split_once(':').ok_or_else(|| {
494 eyre::eyre!("Invalid override {address_override}. Expected <address>:<value>")
495 })
496}
497
498fn address_slot_value_override(address_override: &str) -> Result<(Address, U256, U256)> {
500 let captures = OVERRIDE_PATTERN.captures(address_override).ok_or_else(|| {
501 eyre::eyre!("Invalid override {address_override}. Expected <address>:<slot>:<value>")
502 })?;
503
504 Ok((
505 captures[1].parse()?, captures[2].parse()?, captures[3].parse()?, ))
509}
510
511#[cfg(test)]
512mod tests {
513 use super::*;
514 use alloy_primitives::{U64, address, b256, fixed_bytes, hex};
515
516 #[test]
517 fn test_get_state_overrides() {
518 let call_args = CallArgs::parse_from([
519 "foundry-cli",
520 "--override-balance",
521 "0x0000000000000000000000000000000000000001:2",
522 "--override-nonce",
523 "0x0000000000000000000000000000000000000001:3",
524 "--override-code",
525 "0x0000000000000000000000000000000000000001:0x04",
526 "--override-state",
527 "0x0000000000000000000000000000000000000001:5:6",
528 "--override-state-diff",
529 "0x0000000000000000000000000000000000000001:7:8",
530 ]);
531 let overrides = call_args.get_state_overrides().unwrap().unwrap();
532 let address = address!("0x0000000000000000000000000000000000000001");
533 if let Some(account_override) = overrides.get(&address) {
534 if let Some(balance) = account_override.balance {
535 assert_eq!(balance, U256::from(2));
536 }
537 if let Some(nonce) = account_override.nonce {
538 assert_eq!(nonce, 3);
539 }
540 if let Some(code) = &account_override.code {
541 assert_eq!(*code, Bytes::from([0x04]));
542 }
543 if let Some(state) = &account_override.state
544 && let Some(value) = state.get(&b256!(
545 "0x0000000000000000000000000000000000000000000000000000000000000005"
546 ))
547 {
548 assert_eq!(
549 *value,
550 b256!("0x0000000000000000000000000000000000000000000000000000000000000006")
551 );
552 }
553 if let Some(state_diff) = &account_override.state_diff
554 && let Some(value) = state_diff.get(&b256!(
555 "0x0000000000000000000000000000000000000000000000000000000000000007"
556 ))
557 {
558 assert_eq!(
559 *value,
560 b256!("0x0000000000000000000000000000000000000000000000000000000000000008")
561 );
562 }
563 }
564 }
565
566 #[test]
567 fn test_get_state_overrides_empty() {
568 let call_args = CallArgs::parse_from([""]);
569 let overrides = call_args.get_state_overrides().unwrap();
570 assert_eq!(overrides, None);
571 }
572
573 #[test]
574 fn test_get_block_overrides() {
575 let mut call_args = CallArgs::parse_from([""]);
576 call_args.block_number = Some(1);
577 call_args.block_time = Some(2);
578 let overrides = call_args.get_block_overrides().unwrap().unwrap();
579 assert_eq!(overrides.number, Some(U256::from(1)));
580 assert_eq!(overrides.time, Some(2));
581 }
582
583 #[test]
584 fn test_get_block_overrides_empty() {
585 let call_args = CallArgs::parse_from([""]);
586 let overrides = call_args.get_block_overrides().unwrap();
587 assert_eq!(overrides, None);
588 }
589
590 #[test]
591 fn test_address_value_override_success() {
592 let text = "0x0000000000000000000000000000000000000001:2";
593 let (address, value) = address_value_override(text).unwrap();
594 assert_eq!(address, "0x0000000000000000000000000000000000000001");
595 assert_eq!(value, "2");
596 }
597
598 #[test]
599 fn test_address_value_override_error() {
600 let text = "invalid_value";
601 let error = address_value_override(text).unwrap_err();
602 assert_eq!(error.to_string(), "Invalid override invalid_value. Expected <address>:<value>");
603 }
604
605 #[test]
606 fn test_address_slot_value_override_success() {
607 let text = "0x0000000000000000000000000000000000000001:2:3";
608 let (address, slot, value) = address_slot_value_override(text).unwrap();
609 assert_eq!(*address, fixed_bytes!("0x0000000000000000000000000000000000000001"));
610 assert_eq!(slot, U256::from(2));
611 assert_eq!(value, U256::from(3));
612 }
613
614 #[test]
615 fn test_address_slot_value_override_error() {
616 let text = "invalid_value";
617 let error = address_slot_value_override(text).unwrap_err();
618 assert_eq!(
619 error.to_string(),
620 "Invalid override invalid_value. Expected <address>:<slot>:<value>"
621 );
622 }
623
624 #[test]
625 fn can_parse_call_data() {
626 let data = hex::encode("hello");
627 let args = CallArgs::parse_from(["foundry-cli", "--data", data.as_str()]);
628 assert_eq!(args.data, Some(data));
629
630 let data = hex::encode_prefixed("hello");
631 let args = CallArgs::parse_from(["foundry-cli", "--data", data.as_str()]);
632 assert_eq!(args.data, Some(data));
633 }
634
635 #[test]
636 fn can_parse_state_overrides() {
637 let args = CallArgs::parse_from([
638 "foundry-cli",
639 "--override-balance",
640 "0x123:0x1234",
641 "--override-nonce",
642 "0x123:1",
643 "--override-code",
644 "0x123:0x1234",
645 "--override-state",
646 "0x123:0x1:0x1234",
647 ]);
648
649 assert_eq!(args.balance_overrides, Some(vec!["0x123:0x1234".to_string()]));
650 assert_eq!(args.nonce_overrides, Some(vec!["0x123:1".to_string()]));
651 assert_eq!(args.code_overrides, Some(vec!["0x123:0x1234".to_string()]));
652 assert_eq!(args.state_overrides, Some(vec!["0x123:0x1:0x1234".to_string()]));
653 }
654
655 #[test]
656 fn can_parse_multiple_state_overrides() {
657 let args = CallArgs::parse_from([
658 "foundry-cli",
659 "--override-balance",
660 "0x123:0x1234",
661 "--override-balance",
662 "0x456:0x5678",
663 "--override-nonce",
664 "0x123:1",
665 "--override-nonce",
666 "0x456:2",
667 "--override-code",
668 "0x123:0x1234",
669 "--override-code",
670 "0x456:0x5678",
671 "--override-state",
672 "0x123:0x1:0x1234",
673 "--override-state",
674 "0x456:0x2:0x5678",
675 ]);
676
677 assert_eq!(
678 args.balance_overrides,
679 Some(vec!["0x123:0x1234".to_string(), "0x456:0x5678".to_string()])
680 );
681 assert_eq!(args.nonce_overrides, Some(vec!["0x123:1".to_string(), "0x456:2".to_string()]));
682 assert_eq!(
683 args.code_overrides,
684 Some(vec!["0x123:0x1234".to_string(), "0x456:0x5678".to_string()])
685 );
686 assert_eq!(
687 args.state_overrides,
688 Some(vec!["0x123:0x1:0x1234".to_string(), "0x456:0x2:0x5678".to_string()])
689 );
690 }
691
692 #[test]
693 fn test_negative_args_with_flags() {
694 let args = CallArgs::parse_from([
696 "foundry-cli",
697 "--trace",
698 "0xDeaDBeeFcAfEbAbEfAcEfEeDcBaDbEeFcAfEbAbE",
699 "process(int256)",
700 "-999999",
701 "--debug",
702 ]);
703
704 assert!(args.trace);
705 assert!(args.debug);
706 assert_eq!(args.args, vec!["-999999"]);
707 }
708
709 #[test]
710 fn test_transaction_opts_with_trace() {
711 let args = CallArgs::parse_from([
713 "foundry-cli",
714 "--trace",
715 "--gas-limit",
716 "1000000",
717 "--gas-price",
718 "20000000000",
719 "--priority-gas-price",
720 "2000000000",
721 "--nonce",
722 "42",
723 "--value",
724 "1000000000000000000", "--blob-gas-price",
726 "10000000000",
727 "0xDeaDBeeFcAfEbAbEfAcEfEeDcBaDbEeFcAfEbAbE",
728 "balanceOf(address)",
729 "0x123456789abcdef123456789abcdef123456789a",
730 ]);
731
732 assert!(args.trace);
733 assert_eq!(args.tx.gas_limit, Some(U256::from(1000000u32)));
734 assert_eq!(args.tx.gas_price, Some(U256::from(20000000000u64)));
735 assert_eq!(args.tx.priority_gas_price, Some(U256::from(2000000000u64)));
736 assert_eq!(args.tx.nonce, Some(U64::from(42)));
737 assert_eq!(args.tx.value, Some(U256::from(1000000000000000000u64)));
738 assert_eq!(args.tx.blob_gas_price, Some(U256::from(10000000000u64)));
739 }
740}