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 regex::Regex;
35use revm::context::TransactionType;
36use std::{str::FromStr, sync::LazyLock};
37
38static OVERRIDE_PATTERN: LazyLock<Regex> =
41 LazyLock::new(|| Regex::new(r"^([^:]+):([^:]+):([^:]+)$").unwrap());
42
43#[derive(Debug, Parser)]
65pub struct CallArgs {
66 #[arg(value_parser = NameOrAddress::from_str)]
68 to: Option<NameOrAddress>,
69
70 sig: Option<String>,
72
73 args: Vec<String>,
75
76 #[arg(
78 long,
79 conflicts_with_all = &["sig", "args"]
80 )]
81 data: Option<String>,
82
83 #[arg(long, default_value_t = false)]
85 trace: bool,
86
87 #[arg(long, default_value_t = false, requires = "trace")]
90 disable_labels: bool,
91
92 #[arg(long, requires = "trace")]
95 debug: bool,
96
97 #[arg(long, requires = "trace")]
98 decode_internal: bool,
99
100 #[arg(long, requires = "trace")]
103 labels: Vec<String>,
104
105 #[arg(long, requires = "trace")]
108 evm_version: Option<EvmVersion>,
109
110 #[arg(long, short)]
114 block: Option<BlockId>,
115
116 #[arg(long, alias = "alphanet")]
118 pub odyssey: bool,
119
120 #[command(subcommand)]
121 command: Option<CallSubcommands>,
122
123 #[command(flatten)]
124 tx: TransactionOpts,
125
126 #[command(flatten)]
127 eth: EthereumOpts,
128
129 #[arg(long, visible_alias = "la")]
131 pub with_local_artifacts: bool,
132
133 #[arg(long = "override-balance", value_name = "ADDRESS:BALANCE", value_delimiter = ',')]
136 pub balance_overrides: Option<Vec<String>>,
137
138 #[arg(long = "override-nonce", value_name = "ADDRESS:NONCE", value_delimiter = ',')]
141 pub nonce_overrides: Option<Vec<String>>,
142
143 #[arg(long = "override-code", value_name = "ADDRESS:CODE", value_delimiter = ',')]
146 pub code_overrides: Option<Vec<String>>,
147
148 #[arg(long = "override-state", value_name = "ADDRESS:SLOT:VALUE", value_delimiter = ',')]
151 pub state_overrides: Option<Vec<String>>,
152
153 #[arg(long = "override-state-diff", value_name = "ADDRESS:SLOT:VALUE", value_delimiter = ',')]
156 pub state_diff_overrides: Option<Vec<String>>,
157
158 #[arg(long = "block.time", value_name = "TIME")]
160 pub block_time: Option<u64>,
161
162 #[arg(long = "block.number", value_name = "NUMBER")]
164 pub block_number: Option<u64>,
165}
166
167#[derive(Debug, Parser)]
168pub enum CallSubcommands {
169 #[command(name = "--create")]
171 Create {
172 code: String,
174
175 sig: Option<String>,
177
178 args: Vec<String>,
180
181 #[arg(long, value_parser = parse_ether_value)]
187 value: Option<U256>,
188 },
189}
190
191impl CallArgs {
192 pub async fn run(self) -> Result<()> {
193 let figment = self.eth.rpc.clone().into_figment(self.with_local_artifacts).merge(&self);
194 let evm_opts = figment.extract::<EvmOpts>()?;
195 let mut config = Config::from_provider(figment)?.sanitized();
196 let state_overrides = self.get_state_overrides()?;
197 let strategy = utils::get_executor_strategy(&config);
198 let block_overrides = self.get_block_overrides()?;
199
200 let Self {
201 to,
202 mut sig,
203 mut args,
204 mut tx,
205 eth,
206 command,
207 block,
208 trace,
209 evm_version,
210 debug,
211 decode_internal,
212 labels,
213 data,
214 with_local_artifacts,
215 disable_labels,
216 ..
217 } = self;
218
219 if let Some(data) = data {
220 sig = Some(data);
221 }
222
223 let provider = utils::get_provider(&config)?;
224 let sender = SenderKind::from_wallet_opts(eth.wallet).await?;
225 let from = sender.address();
226
227 let code = if let Some(CallSubcommands::Create {
228 code,
229 sig: create_sig,
230 args: create_args,
231 value,
232 }) = command
233 {
234 sig = create_sig;
235 args = create_args;
236 if let Some(value) = value {
237 tx.value = Some(value);
238 }
239 Some(code)
240 } else {
241 None
242 };
243
244 let (tx, func) = CastTxBuilder::new(&provider, tx, &config)
245 .await?
246 .with_to(to)
247 .await?
248 .with_code_sig_and_args(code, sig, args)
249 .await?
250 .build_raw(sender)
251 .await?;
252
253 if trace {
254 if let Some(BlockId::Number(BlockNumberOrTag::Number(block_number))) = self.block {
255 config.fork_block_number = Some(block_number);
257 }
258
259 let create2_deployer = evm_opts.create2_deployer;
260 let (mut env, fork, chain, odyssey) =
261 TracingExecutor::get_fork_material(&config, evm_opts).await?;
262
263 env.evm_env.cfg_env.disable_block_gas_limit = true;
265 env.evm_env.block_env.gas_limit = u64::MAX;
266
267 if let Some(block_overrides) = block_overrides {
269 if let Some(number) = block_overrides.number {
270 env.evm_env.block_env.number = number.to();
271 }
272 if let Some(time) = block_overrides.time {
273 env.evm_env.block_env.timestamp = U256::from(time);
274 }
275 }
276
277 let trace_mode = TraceMode::Call
278 .with_debug(debug)
279 .with_decode_internal(if decode_internal {
280 InternalTraceMode::Full
281 } else {
282 InternalTraceMode::None
283 })
284 .with_state_changes(shell::verbosity() > 4);
285 let mut executor = TracingExecutor::new(
286 env,
287 fork,
288 evm_version,
289 trace_mode,
290 odyssey,
291 create2_deployer,
292 state_overrides,
293 strategy,
294 )?;
295
296 let value = tx.value.unwrap_or_default();
297 let input = tx.inner.input.into_input().unwrap_or_default();
298 let tx_kind = tx.inner.to.expect("set by builder");
299 let env_tx = &mut executor.env_mut().tx;
300
301 if let Some(tx_type) = tx.inner.transaction_type {
302 env_tx.tx_type = tx_type;
303 }
304
305 if let Some(access_list) = tx.inner.access_list {
306 env_tx.access_list = access_list;
307
308 if env_tx.tx_type == TransactionType::Legacy as u8 {
309 env_tx.tx_type = TransactionType::Eip2930 as u8;
310 }
311 }
312
313 let trace = match tx_kind {
314 TxKind::Create => {
315 let deploy_result = executor.deploy(from, input, value, None);
316 TraceResult::try_from(deploy_result)?
317 }
318 TxKind::Call(to) => TraceResult::from_raw(
319 executor.transact_raw(from, to, input, value)?,
320 TraceKind::Execution,
321 ),
322 };
323
324 let contracts_bytecode = fetch_contracts_bytecode_from_trace(&provider, &trace).await?;
325 handle_traces(
326 trace,
327 &config,
328 chain,
329 &contracts_bytecode,
330 labels,
331 with_local_artifacts,
332 debug,
333 decode_internal,
334 disable_labels,
335 )
336 .await?;
337
338 return Ok(());
339 }
340
341 let response = Cast::new(&provider)
342 .call(&tx, func.as_ref(), block, state_overrides, block_overrides)
343 .await?;
344
345 if response == "0x"
346 && let Some(contract_address) = tx.to.and_then(|tx_kind| tx_kind.into_to())
347 {
348 let code = provider.get_code_at(contract_address).await?;
349 if code.is_empty() {
350 sh_warn!("Contract code is empty")?;
351 }
352 }
353 sh_println!("{}", response)?;
354
355 Ok(())
356 }
357
358 pub fn get_state_overrides(&self) -> eyre::Result<Option<StateOverride>> {
360 if [
362 self.balance_overrides.as_ref(),
363 self.nonce_overrides.as_ref(),
364 self.code_overrides.as_ref(),
365 self.state_overrides.as_ref(),
366 self.state_diff_overrides.as_ref(),
367 ]
368 .iter()
369 .all(Option::is_none)
370 {
371 return Ok(None);
372 }
373
374 let mut state_overrides_builder = StateOverridesBuilder::default();
375
376 for override_str in self.balance_overrides.iter().flatten() {
378 let (addr, balance) = address_value_override(override_str)?;
379 state_overrides_builder =
380 state_overrides_builder.with_balance(addr.parse()?, balance.parse()?);
381 }
382
383 for override_str in self.nonce_overrides.iter().flatten() {
385 let (addr, nonce) = address_value_override(override_str)?;
386 state_overrides_builder =
387 state_overrides_builder.with_nonce(addr.parse()?, nonce.parse()?);
388 }
389
390 for override_str in self.code_overrides.iter().flatten() {
392 let (addr, code_str) = address_value_override(override_str)?;
393 state_overrides_builder =
394 state_overrides_builder.with_code(addr.parse()?, Bytes::from_str(code_str)?);
395 }
396
397 type StateOverrides = HashMap<Address, HashMap<B256, B256>>;
398 let parse_state_overrides =
399 |overrides: &Option<Vec<String>>| -> Result<StateOverrides, eyre::Report> {
400 let mut state_overrides: StateOverrides = StateOverrides::default();
401
402 overrides.iter().flatten().try_for_each(|s| -> Result<(), eyre::Report> {
403 let (addr, slot, value) = address_slot_value_override(s)?;
404 state_overrides.entry(addr).or_default().insert(slot.into(), value.into());
405 Ok(())
406 })?;
407
408 Ok(state_overrides)
409 };
410
411 for (addr, entries) in parse_state_overrides(&self.state_overrides)? {
413 state_overrides_builder = state_overrides_builder.with_state(addr, entries.into_iter());
414 }
415
416 for (addr, entries) in parse_state_overrides(&self.state_diff_overrides)? {
418 state_overrides_builder =
419 state_overrides_builder.with_state_diff(addr, entries.into_iter())
420 }
421
422 Ok(Some(state_overrides_builder.build()))
423 }
424
425 pub fn get_block_overrides(&self) -> eyre::Result<Option<BlockOverrides>> {
427 let mut overrides = BlockOverrides::default();
428 if let Some(number) = self.block_number {
429 overrides = overrides.with_number(U256::from(number));
430 }
431 if let Some(time) = self.block_time {
432 overrides = overrides.with_time(time);
433 }
434 if overrides.is_empty() { Ok(None) } else { Ok(Some(overrides)) }
435 }
436}
437
438impl figment::Provider for CallArgs {
439 fn metadata(&self) -> Metadata {
440 Metadata::named("CallArgs")
441 }
442
443 fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {
444 let mut map = Map::new();
445
446 if self.odyssey {
447 map.insert("odyssey".into(), self.odyssey.into());
448 }
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}