foundry_cheatcodes/
test.rs1use crate::{Cheatcode, Cheatcodes, CheatsCtxt, Result, Vm::*};
4use alloy_chains::Chain as AlloyChain;
5use alloy_primitives::{Address, Bytes, U256};
6use alloy_sol_types::SolValue;
7use foundry_common::version::SEMVER_VERSION;
8use foundry_evm_core::{constants::MAGIC_SKIP, evm::FoundryEvmNetwork};
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<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> 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<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> 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<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
32 let Self {} = self;
33 Ok(SEMVER_VERSION.abi_encode())
34 }
35}
36
37impl Cheatcode for rpcUrlCall {
38 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> 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<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> 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<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> 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<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> 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<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
70 let Self { skipTest } = *self;
71 skip(ccx, skipTest, "")
72 }
73}
74
75impl Cheatcode for skip_1Call {
76 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
77 let Self { skipTest, reason } = self;
78 skip(ccx, *skipTest, reason)
79 }
80}
81
82impl Cheatcode for getChain_0Call {
83 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
84 let Self { chainAlias } = self;
85 get_chain(state, chainAlias)
86 }
87}
88
89impl Cheatcode for getChain_1Call {
90 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
91 let Self { chainId } = self;
92 let chain_id_str = chainId.to_string();
94 get_chain(state, &chain_id_str)
95 }
96}
97
98fn skip<FEN: FoundryEvmNetwork>(
101 ccx: &mut CheatsCtxt<'_, '_, FEN>,
102 skip_test: bool,
103 reason: &str,
104) -> Result {
105 if !skip_test {
106 return Ok(Default::default());
107 }
108 ensure!(ccx.depth() <= 1, "`skip` can only be used at test level");
111 let payload = Bytes::from([MAGIC_SKIP, reason.as_bytes()].concat());
112 ccx.state.skip_payloads.push(payload.clone());
113 Err(payload.into())
114}
115
116fn breakpoint<FEN: FoundryEvmNetwork>(
118 state: &mut Cheatcodes<FEN>,
119 caller: &Address,
120 s: &str,
121 add: bool,
122) -> Result {
123 let mut chars = s.chars();
124 let (Some(point), None) = (chars.next(), chars.next()) else {
125 bail!("breakpoints must be exactly one character");
126 };
127 ensure!(point.is_alphabetic(), "only alphabetic characters are accepted as breakpoints");
128
129 if add {
130 state.breakpoints.insert(point, (*caller, state.pc));
131 } else {
132 state.breakpoints.remove(&point);
133 }
134
135 Ok(Default::default())
136}
137
138fn get_chain<FEN: FoundryEvmNetwork>(state: &mut Cheatcodes<FEN>, chain_alias: &str) -> Result {
140 let alloy_chain = AlloyChain::from_str(chain_alias)
142 .map_err(|_| fmt_err!("invalid chain alias: {chain_alias}"))?;
143 let chain_name = alloy_chain.to_string();
144 let chain_id = alloy_chain.id();
145
146 if chain_name == chain_id.to_string() {
150 return Err(fmt_err!("invalid chain alias: {chain_alias}"));
151 }
152
153 let (rpc_url, chain_alias) = if let Some(rpc_url) =
155 state.config.rpc_endpoint(&chain_name).ok().and_then(|e| e.url().ok())
156 {
157 (rpc_url, chain_name.clone())
158 } else {
159 (String::new(), chain_alias.to_string())
160 };
161
162 let chain_struct = Chain {
163 name: chain_name,
164 chainId: U256::from(chain_id),
165 chainAlias: chain_alias,
166 rpcUrl: rpc_url,
167 };
168
169 Ok(chain_struct.abi_encode())
170}