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