1use crate::{
2 Cast,
3 traces::TraceKind,
4 tx::{CastTxBuilder, SenderKind},
5};
6use alloy_ens::NameOrAddress;
7use alloy_primitives::{Address, Bytes, TxKind, U256};
8use alloy_provider::Provider;
9use alloy_rpc_types::{
10 BlockId, BlockNumberOrTag, BlockOverrides,
11 state::{StateOverride, StateOverridesBuilder},
12};
13use clap::Parser;
14use eyre::Result;
15use foundry_cli::{
16 opts::{EthereumOpts, TransactionOpts},
17 utils::{self, TraceResult, handle_traces, parse_ether_value},
18};
19use foundry_common::shell;
20use foundry_compilers::artifacts::EvmVersion;
21use foundry_config::{
22 Config,
23 figment::{
24 self, Figment, Metadata, Profile,
25 value::{Dict, Map},
26 },
27};
28use foundry_evm::{
29 executors::TracingExecutor,
30 opts::EvmOpts,
31 traces::{InternalTraceMode, TraceMode},
32};
33use regex::Regex;
34use revm::context::TransactionType;
35use std::{str::FromStr, sync::LazyLock};
36
37use super::run::fetch_contracts_bytecode_from_trace;
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 args: Vec<String>,
76
77 #[arg(
79 long,
80 conflicts_with_all = &["sig", "args"]
81 )]
82 data: Option<String>,
83
84 #[arg(long, default_value_t = false)]
86 trace: bool,
87
88 #[arg(long, default_value_t = false, requires = "trace")]
91 disable_labels: bool,
92
93 #[arg(long, requires = "trace")]
96 debug: bool,
97
98 #[arg(long, requires = "trace")]
99 decode_internal: bool,
100
101 #[arg(long, requires = "trace")]
104 labels: Vec<String>,
105
106 #[arg(long, requires = "trace")]
109 evm_version: Option<EvmVersion>,
110
111 #[arg(long, short)]
115 block: Option<BlockId>,
116
117 #[arg(long, alias = "alphanet")]
119 pub odyssey: bool,
120
121 #[command(subcommand)]
122 command: Option<CallSubcommands>,
123
124 #[command(flatten)]
125 tx: TransactionOpts,
126
127 #[command(flatten)]
128 eth: EthereumOpts,
129
130 #[arg(long, visible_alias = "la")]
132 pub with_local_artifacts: bool,
133
134 #[arg(long = "override-balance", value_name = "ADDRESS:BALANCE")]
137 pub balance_overrides: Option<Vec<String>>,
138
139 #[arg(long = "override-nonce", value_name = "ADDRESS:NONCE")]
142 pub nonce_overrides: Option<Vec<String>>,
143
144 #[arg(long = "override-code", value_name = "ADDRESS:CODE")]
147 pub code_overrides: Option<Vec<String>>,
148
149 #[arg(long = "override-state", value_name = "ADDRESS:SLOT:VALUE")]
152 pub state_overrides: Option<Vec<String>>,
153
154 #[arg(long = "override-state-diff", value_name = "ADDRESS:SLOT:VALUE")]
157 pub state_diff_overrides: Option<Vec<String>>,
158
159 #[arg(long = "block.time", value_name = "TIME")]
161 pub block_time: Option<u64>,
162
163 #[arg(long = "block.number", value_name = "NUMBER")]
165 pub block_number: Option<u64>,
166}
167
168#[derive(Debug, Parser)]
169pub enum CallSubcommands {
170 #[command(name = "--create")]
172 Create {
173 code: String,
175
176 sig: Option<String>,
178
179 args: Vec<String>,
181
182 #[arg(long, value_parser = parse_ether_value)]
188 value: Option<U256>,
189 },
190}
191
192impl CallArgs {
193 pub async fn run(self) -> Result<()> {
194 let figment = Into::<Figment>::into(&self.eth).merge(&self);
195 let evm_opts = figment.extract::<EvmOpts>()?;
196 let mut config = Config::from_provider(figment)?.sanitized();
197 let state_overrides = self.get_state_overrides()?;
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 )?;
294
295 let value = tx.value.unwrap_or_default();
296 let input = tx.inner.input.into_input().unwrap_or_default();
297 let tx_kind = tx.inner.to.expect("set by builder");
298 let env_tx = &mut executor.env_mut().tx;
299
300 if let Some(tx_type) = tx.inner.transaction_type {
301 env_tx.tx_type = tx_type;
302 }
303
304 if let Some(access_list) = tx.inner.access_list {
305 env_tx.access_list = access_list;
306
307 if env_tx.tx_type == TransactionType::Legacy as u8 {
308 env_tx.tx_type = TransactionType::Eip2930 as u8;
309 }
310 }
311
312 let trace = match tx_kind {
313 TxKind::Create => {
314 let deploy_result = executor.deploy(from, input, value, None);
315 TraceResult::try_from(deploy_result)?
316 }
317 TxKind::Call(to) => TraceResult::from_raw(
318 executor.transact_raw(from, to, input, value)?,
319 TraceKind::Execution,
320 ),
321 };
322
323 let contracts_bytecode = fetch_contracts_bytecode_from_trace(&provider, &trace).await?;
324 handle_traces(
325 trace,
326 &config,
327 chain,
328 &contracts_bytecode,
329 labels,
330 with_local_artifacts,
331 debug,
332 decode_internal,
333 disable_labels,
334 )
335 .await?;
336
337 return Ok(());
338 }
339
340 let response = Cast::new(&provider)
341 .call(&tx, func.as_ref(), block, state_overrides, block_overrides)
342 .await?;
343
344 if response == "0x"
345 && let Some(contract_address) = tx.to.and_then(|tx_kind| tx_kind.into_to())
346 {
347 let code = provider.get_code_at(contract_address).await?;
348 if code.is_empty() {
349 sh_warn!("Contract code is empty")?;
350 }
351 }
352 sh_println!("{}", response)?;
353
354 Ok(())
355 }
356
357 pub fn get_state_overrides(&self) -> eyre::Result<Option<StateOverride>> {
359 if [
361 self.balance_overrides.as_ref(),
362 self.nonce_overrides.as_ref(),
363 self.code_overrides.as_ref(),
364 self.state_overrides.as_ref(),
365 self.state_diff_overrides.as_ref(),
366 ]
367 .iter()
368 .all(Option::is_none)
369 {
370 return Ok(None);
371 }
372
373 let mut state_overrides_builder = StateOverridesBuilder::default();
374
375 for override_str in self.balance_overrides.iter().flatten() {
377 let (addr, balance) = address_value_override(override_str)?;
378 state_overrides_builder =
379 state_overrides_builder.with_balance(addr.parse()?, balance.parse()?);
380 }
381
382 for override_str in self.nonce_overrides.iter().flatten() {
384 let (addr, nonce) = address_value_override(override_str)?;
385 state_overrides_builder =
386 state_overrides_builder.with_nonce(addr.parse()?, nonce.parse()?);
387 }
388
389 for override_str in self.code_overrides.iter().flatten() {
391 let (addr, code_str) = address_value_override(override_str)?;
392 state_overrides_builder =
393 state_overrides_builder.with_code(addr.parse()?, Bytes::from_str(code_str)?);
394 }
395
396 for override_str in self.state_overrides.iter().flatten() {
398 let (addr, slot, value) = address_slot_value_override(override_str)?;
399 state_overrides_builder =
400 state_overrides_builder.with_state(addr, [(slot.into(), value.into())]);
401 }
402
403 for override_str in self.state_diff_overrides.iter().flatten() {
405 let (addr, slot, value) = address_slot_value_override(override_str)?;
406 state_overrides_builder =
407 state_overrides_builder.with_state_diff(addr, [(slot.into(), value.into())]);
408 }
409
410 Ok(Some(state_overrides_builder.build()))
411 }
412
413 pub fn get_block_overrides(&self) -> eyre::Result<Option<BlockOverrides>> {
415 let mut overrides = BlockOverrides::default();
416 if let Some(number) = self.block_number {
417 overrides = overrides.with_number(U256::from(number));
418 }
419 if let Some(time) = self.block_time {
420 overrides = overrides.with_time(time);
421 }
422 if overrides.is_empty() { Ok(None) } else { Ok(Some(overrides)) }
423 }
424}
425
426impl figment::Provider for CallArgs {
427 fn metadata(&self) -> Metadata {
428 Metadata::named("CallArgs")
429 }
430
431 fn data(&self) -> Result<Map<Profile, Dict>, figment::Error> {
432 let mut map = Map::new();
433
434 if self.odyssey {
435 map.insert("odyssey".into(), self.odyssey.into());
436 }
437
438 if let Some(evm_version) = self.evm_version {
439 map.insert("evm_version".into(), figment::value::Value::serialize(evm_version)?);
440 }
441
442 Ok(Map::from([(Config::selected_profile(), map)]))
443 }
444}
445
446fn address_value_override(address_override: &str) -> Result<(&str, &str)> {
448 address_override.split_once(':').ok_or_else(|| {
449 eyre::eyre!("Invalid override {address_override}. Expected <address>:<value>")
450 })
451}
452
453fn address_slot_value_override(address_override: &str) -> Result<(Address, U256, U256)> {
455 let captures = OVERRIDE_PATTERN.captures(address_override).ok_or_else(|| {
456 eyre::eyre!("Invalid override {address_override}. Expected <address>:<slot>:<value>")
457 })?;
458
459 Ok((
460 captures[1].parse()?, captures[2].parse()?, captures[3].parse()?, ))
464}
465
466#[cfg(test)]
467mod tests {
468 use super::*;
469 use alloy_primitives::{address, b256, fixed_bytes, hex};
470
471 #[test]
472 fn test_get_state_overrides() {
473 let call_args = CallArgs::parse_from([
474 "foundry-cli",
475 "--override-balance",
476 "0x0000000000000000000000000000000000000001:2",
477 "--override-nonce",
478 "0x0000000000000000000000000000000000000001:3",
479 "--override-code",
480 "0x0000000000000000000000000000000000000001:0x04",
481 "--override-state",
482 "0x0000000000000000000000000000000000000001:5:6",
483 "--override-state-diff",
484 "0x0000000000000000000000000000000000000001:7:8",
485 ]);
486 let overrides = call_args.get_state_overrides().unwrap().unwrap();
487 let address = address!("0x0000000000000000000000000000000000000001");
488 if let Some(account_override) = overrides.get(&address) {
489 if let Some(balance) = account_override.balance {
490 assert_eq!(balance, U256::from(2));
491 }
492 if let Some(nonce) = account_override.nonce {
493 assert_eq!(nonce, 3);
494 }
495 if let Some(code) = &account_override.code {
496 assert_eq!(*code, Bytes::from([0x04]));
497 }
498 if let Some(state) = &account_override.state
499 && let Some(value) = state.get(&b256!(
500 "0x0000000000000000000000000000000000000000000000000000000000000005"
501 ))
502 {
503 assert_eq!(
504 *value,
505 b256!("0x0000000000000000000000000000000000000000000000000000000000000006")
506 );
507 }
508 if let Some(state_diff) = &account_override.state_diff
509 && let Some(value) = state_diff.get(&b256!(
510 "0x0000000000000000000000000000000000000000000000000000000000000007"
511 ))
512 {
513 assert_eq!(
514 *value,
515 b256!("0x0000000000000000000000000000000000000000000000000000000000000008")
516 );
517 }
518 }
519 }
520
521 #[test]
522 fn test_get_state_overrides_empty() {
523 let call_args = CallArgs::parse_from([""]);
524 let overrides = call_args.get_state_overrides().unwrap();
525 assert_eq!(overrides, None);
526 }
527
528 #[test]
529 fn test_get_block_overrides() {
530 let mut call_args = CallArgs::parse_from([""]);
531 call_args.block_number = Some(1);
532 call_args.block_time = Some(2);
533 let overrides = call_args.get_block_overrides().unwrap().unwrap();
534 assert_eq!(overrides.number, Some(U256::from(1)));
535 assert_eq!(overrides.time, Some(2));
536 }
537
538 #[test]
539 fn test_get_block_overrides_empty() {
540 let call_args = CallArgs::parse_from([""]);
541 let overrides = call_args.get_block_overrides().unwrap();
542 assert_eq!(overrides, None);
543 }
544
545 #[test]
546 fn test_address_value_override_success() {
547 let text = "0x0000000000000000000000000000000000000001:2";
548 let (address, value) = address_value_override(text).unwrap();
549 assert_eq!(address, "0x0000000000000000000000000000000000000001");
550 assert_eq!(value, "2");
551 }
552
553 #[test]
554 fn test_address_value_override_error() {
555 let text = "invalid_value";
556 let error = address_value_override(text).unwrap_err();
557 assert_eq!(error.to_string(), "Invalid override invalid_value. Expected <address>:<value>");
558 }
559
560 #[test]
561 fn test_address_slot_value_override_success() {
562 let text = "0x0000000000000000000000000000000000000001:2:3";
563 let (address, slot, value) = address_slot_value_override(text).unwrap();
564 assert_eq!(*address, fixed_bytes!("0x0000000000000000000000000000000000000001"));
565 assert_eq!(slot, U256::from(2));
566 assert_eq!(value, U256::from(3));
567 }
568
569 #[test]
570 fn test_address_slot_value_override_error() {
571 let text = "invalid_value";
572 let error = address_slot_value_override(text).unwrap_err();
573 assert_eq!(
574 error.to_string(),
575 "Invalid override invalid_value. Expected <address>:<slot>:<value>"
576 );
577 }
578
579 #[test]
580 fn can_parse_call_data() {
581 let data = hex::encode("hello");
582 let args = CallArgs::parse_from(["foundry-cli", "--data", data.as_str()]);
583 assert_eq!(args.data, Some(data));
584
585 let data = hex::encode_prefixed("hello");
586 let args = CallArgs::parse_from(["foundry-cli", "--data", data.as_str()]);
587 assert_eq!(args.data, Some(data));
588 }
589
590 #[test]
591 fn can_parse_state_overrides() {
592 let args = CallArgs::parse_from([
593 "foundry-cli",
594 "--override-balance",
595 "0x123:0x1234",
596 "--override-nonce",
597 "0x123:1",
598 "--override-code",
599 "0x123:0x1234",
600 "--override-state",
601 "0x123:0x1:0x1234",
602 ]);
603
604 assert_eq!(args.balance_overrides, Some(vec!["0x123:0x1234".to_string()]));
605 assert_eq!(args.nonce_overrides, Some(vec!["0x123:1".to_string()]));
606 assert_eq!(args.code_overrides, Some(vec!["0x123:0x1234".to_string()]));
607 assert_eq!(args.state_overrides, Some(vec!["0x123:0x1:0x1234".to_string()]));
608 }
609
610 #[test]
611 fn can_parse_multiple_state_overrides() {
612 let args = CallArgs::parse_from([
613 "foundry-cli",
614 "--override-balance",
615 "0x123:0x1234",
616 "--override-balance",
617 "0x456:0x5678",
618 "--override-nonce",
619 "0x123:1",
620 "--override-nonce",
621 "0x456:2",
622 "--override-code",
623 "0x123:0x1234",
624 "--override-code",
625 "0x456:0x5678",
626 "--override-state",
627 "0x123:0x1:0x1234",
628 "--override-state",
629 "0x456:0x2:0x5678",
630 ]);
631
632 assert_eq!(
633 args.balance_overrides,
634 Some(vec!["0x123:0x1234".to_string(), "0x456:0x5678".to_string()])
635 );
636 assert_eq!(args.nonce_overrides, Some(vec!["0x123:1".to_string(), "0x456:2".to_string()]));
637 assert_eq!(
638 args.code_overrides,
639 Some(vec!["0x123:0x1234".to_string(), "0x456:0x5678".to_string()])
640 );
641 assert_eq!(
642 args.state_overrides,
643 Some(vec!["0x123:0x1:0x1234".to_string(), "0x456:0x2:0x5678".to_string()])
644 );
645 }
646}