foundry_cheatcodes/
test.rs
1use crate::{Cheatcode, Cheatcodes, CheatsCtxt, Result, Vm::*};
4use alloy_chains::Chain as AlloyChain;
5use alloy_primitives::{Address, U256};
6use alloy_sol_types::SolValue;
7use foundry_common::version::SEMVER_VERSION;
8use foundry_evm_core::constants::MAGIC_SKIP;
9use std::str::FromStr;
10
11pub(crate) mod assert;
12pub(crate) mod assume;
13pub(crate) mod expect;
14pub(crate) mod revert_handlers;
15
16impl Cheatcode for breakpoint_0Call {
17 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
18 let Self { char } = self;
19 breakpoint(ccx.state, &ccx.caller, char, true)
20 }
21}
22
23impl Cheatcode for breakpoint_1Call {
24 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
25 let Self { char, value } = self;
26 breakpoint(ccx.state, &ccx.caller, char, *value)
27 }
28}
29
30impl Cheatcode for getFoundryVersionCall {
31 fn apply(&self, _state: &mut Cheatcodes) -> Result {
32 let Self {} = self;
33 Ok(SEMVER_VERSION.abi_encode())
34 }
35}
36
37impl Cheatcode for rpcUrlCall {
38 fn apply(&self, state: &mut Cheatcodes) -> Result {
39 let Self { rpcAlias } = self;
40 let url = state.config.rpc_endpoint(rpcAlias)?.url()?.abi_encode();
41 Ok(url)
42 }
43}
44
45impl Cheatcode for rpcUrlsCall {
46 fn apply(&self, state: &mut Cheatcodes) -> Result {
47 let Self {} = self;
48 state.config.rpc_urls().map(|urls| urls.abi_encode())
49 }
50}
51
52impl Cheatcode for rpcUrlStructsCall {
53 fn apply(&self, state: &mut Cheatcodes) -> Result {
54 let Self {} = self;
55 state.config.rpc_urls().map(|urls| urls.abi_encode())
56 }
57}
58
59impl Cheatcode for sleepCall {
60 fn apply(&self, _state: &mut Cheatcodes) -> Result {
61 let Self { duration } = self;
62 let sleep_duration = std::time::Duration::from_millis(duration.saturating_to());
63 std::thread::sleep(sleep_duration);
64 Ok(Default::default())
65 }
66}
67
68impl Cheatcode for skip_0Call {
69 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
70 let Self { skipTest } = *self;
71 skip_1Call { skipTest, reason: String::new() }.apply_stateful(ccx)
72 }
73}
74
75impl Cheatcode for skip_1Call {
76 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
77 let Self { skipTest, reason } = self;
78 if *skipTest {
79 ensure!(ccx.ecx.journaled_state.depth() <= 1, "`skip` can only be used at test level");
82 Err([MAGIC_SKIP, reason.as_bytes()].concat().into())
83 } else {
84 Ok(Default::default())
85 }
86 }
87}
88
89impl Cheatcode for getChain_0Call {
90 fn apply(&self, state: &mut Cheatcodes) -> Result {
91 let Self { chainAlias } = self;
92 get_chain(state, chainAlias)
93 }
94}
95
96impl Cheatcode for getChain_1Call {
97 fn apply(&self, state: &mut Cheatcodes) -> Result {
98 let Self { chainId } = self;
99 let chain_id_str = chainId.to_string();
101 get_chain(state, &chain_id_str)
102 }
103}
104
105fn breakpoint(state: &mut Cheatcodes, caller: &Address, s: &str, add: bool) -> Result {
107 let mut chars = s.chars();
108 let (Some(point), None) = (chars.next(), chars.next()) else {
109 bail!("breakpoints must be exactly one character");
110 };
111 ensure!(point.is_alphabetic(), "only alphabetic characters are accepted as breakpoints");
112
113 if add {
114 state.breakpoints.insert(point, (*caller, state.pc));
115 } else {
116 state.breakpoints.remove(&point);
117 }
118
119 Ok(Default::default())
120}
121
122fn get_chain(state: &mut Cheatcodes, chain_alias: &str) -> Result {
124 let alloy_chain = AlloyChain::from_str(chain_alias)
126 .map_err(|_| fmt_err!("invalid chain alias: {chain_alias}"))?;
127
128 if alloy_chain.to_string() == alloy_chain.id().to_string() {
132 return Err(fmt_err!("invalid chain alias: {chain_alias}"));
133 }
134
135 let rpc_url = state.config.rpc_endpoint(chain_alias).ok().and_then(|e| e.url().ok());
137
138 let rpc_url = rpc_url.unwrap_or_default();
140
141 let chain_struct = Chain {
142 name: alloy_chain.to_string(),
143 chainId: U256::from(alloy_chain.id()),
144 chainAlias: chain_alias.to_string(),
145 rpcUrl: rpc_url,
146 };
147
148 Ok(chain_struct.abi_encode())
149}