1use crate::{Cheatcode, Cheatcodes, Error, Result, Vm::*, string};
4use alloy_dyn_abi::DynSolType;
5use alloy_sol_types::SolValue;
6use foundry_evm_core::evm::FoundryEvmNetwork;
7use std::{env, sync::OnceLock};
8
9pub static FORGE_CONTEXT: OnceLock<ForgeContext> = OnceLock::new();
11
12impl Cheatcode for setEnvCall {
13 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
14 let Self { name: key, value } = self;
15 if key.is_empty() {
16 Err(fmt_err!("environment variable key can't be empty"))
17 } else if key.contains('=') {
18 Err(fmt_err!("environment variable key can't contain equal sign `=`"))
19 } else if key.contains('\0') {
20 Err(fmt_err!("environment variable key can't contain NUL character `\\0`"))
21 } else if value.contains('\0') {
22 Err(fmt_err!("environment variable value can't contain NUL character `\\0`"))
23 } else {
24 unsafe {
25 env::set_var(key, value);
26 }
27 Ok(Default::default())
28 }
29 }
30}
31
32impl Cheatcode for resolveEnvCall {
33 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
34 let Self { input } = self;
35 let resolved = foundry_config::resolve::interpolate(input)
36 .map_err(|e| fmt_err!("failed to resolve env var: {e}"))?;
37 Ok(resolved.abi_encode())
38 }
39}
40
41impl Cheatcode for envExistsCall {
42 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
43 let Self { name } = self;
44 Ok(env::var(name).is_ok().abi_encode())
45 }
46}
47
48impl Cheatcode for envBool_0Call {
49 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
50 let Self { name } = self;
51 env(name, &DynSolType::Bool)
52 }
53}
54
55impl Cheatcode for envUint_0Call {
56 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
57 let Self { name } = self;
58 env(name, &DynSolType::Uint(256))
59 }
60}
61
62impl Cheatcode for envInt_0Call {
63 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
64 let Self { name } = self;
65 env(name, &DynSolType::Int(256))
66 }
67}
68
69impl Cheatcode for envAddress_0Call {
70 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
71 let Self { name } = self;
72 env(name, &DynSolType::Address)
73 }
74}
75
76impl Cheatcode for envBytes32_0Call {
77 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
78 let Self { name } = self;
79 env(name, &DynSolType::FixedBytes(32))
80 }
81}
82
83impl Cheatcode for envString_0Call {
84 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
85 let Self { name } = self;
86 env(name, &DynSolType::String)
87 }
88}
89
90impl Cheatcode for envBytes_0Call {
91 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
92 let Self { name } = self;
93 env(name, &DynSolType::Bytes)
94 }
95}
96
97impl Cheatcode for envBool_1Call {
98 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
99 let Self { name, delim } = self;
100 env_array(name, delim, &DynSolType::Bool)
101 }
102}
103
104impl Cheatcode for envUint_1Call {
105 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
106 let Self { name, delim } = self;
107 env_array(name, delim, &DynSolType::Uint(256))
108 }
109}
110
111impl Cheatcode for envInt_1Call {
112 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
113 let Self { name, delim } = self;
114 env_array(name, delim, &DynSolType::Int(256))
115 }
116}
117
118impl Cheatcode for envAddress_1Call {
119 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
120 let Self { name, delim } = self;
121 env_array(name, delim, &DynSolType::Address)
122 }
123}
124
125impl Cheatcode for envBytes32_1Call {
126 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
127 let Self { name, delim } = self;
128 env_array(name, delim, &DynSolType::FixedBytes(32))
129 }
130}
131
132impl Cheatcode for envString_1Call {
133 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
134 let Self { name, delim } = self;
135 env_array(name, delim, &DynSolType::String)
136 }
137}
138
139impl Cheatcode for envBytes_1Call {
140 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
141 let Self { name, delim } = self;
142 env_array(name, delim, &DynSolType::Bytes)
143 }
144}
145
146impl Cheatcode for envOr_0Call {
148 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
149 let Self { name, defaultValue } = self;
150 env_default(name, defaultValue, &DynSolType::Bool)
151 }
152}
153
154impl Cheatcode for envOr_1Call {
156 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
157 let Self { name, defaultValue } = self;
158 env_default(name, defaultValue, &DynSolType::Uint(256))
159 }
160}
161
162impl Cheatcode for envOr_2Call {
164 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
165 let Self { name, defaultValue } = self;
166 env_default(name, defaultValue, &DynSolType::Int(256))
167 }
168}
169
170impl Cheatcode for envOr_3Call {
172 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
173 let Self { name, defaultValue } = self;
174 env_default(name, defaultValue, &DynSolType::Address)
175 }
176}
177
178impl Cheatcode for envOr_4Call {
180 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
181 let Self { name, defaultValue } = self;
182 env_default(name, defaultValue, &DynSolType::FixedBytes(32))
183 }
184}
185
186impl Cheatcode for envOr_5Call {
188 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
189 let Self { name, defaultValue } = self;
190 env_default(name, defaultValue, &DynSolType::String)
191 }
192}
193
194impl Cheatcode for envOr_6Call {
196 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
197 let Self { name, defaultValue } = self;
198 env_default(name, defaultValue, &DynSolType::Bytes)
199 }
200}
201
202impl Cheatcode for envOr_7Call {
204 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
205 let Self { name, delim, defaultValue } = self;
206 env_array_default(name, delim, defaultValue, &DynSolType::Bool)
207 }
208}
209
210impl Cheatcode for envOr_8Call {
212 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
213 let Self { name, delim, defaultValue } = self;
214 env_array_default(name, delim, defaultValue, &DynSolType::Uint(256))
215 }
216}
217
218impl Cheatcode for envOr_9Call {
220 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
221 let Self { name, delim, defaultValue } = self;
222 env_array_default(name, delim, defaultValue, &DynSolType::Int(256))
223 }
224}
225
226impl Cheatcode for envOr_10Call {
228 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
229 let Self { name, delim, defaultValue } = self;
230 env_array_default(name, delim, defaultValue, &DynSolType::Address)
231 }
232}
233
234impl Cheatcode for envOr_11Call {
236 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
237 let Self { name, delim, defaultValue } = self;
238 env_array_default(name, delim, defaultValue, &DynSolType::FixedBytes(32))
239 }
240}
241
242impl Cheatcode for envOr_12Call {
244 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
245 let Self { name, delim, defaultValue } = self;
246 env_array_default(name, delim, defaultValue, &DynSolType::String)
247 }
248}
249
250impl Cheatcode for envOr_13Call {
252 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
253 let Self { name, delim, defaultValue } = self;
254 let default = defaultValue.clone();
255 env_array_default(name, delim, &default, &DynSolType::Bytes)
256 }
257}
258
259impl Cheatcode for isContextCall {
260 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
261 let Self { context } = self;
262 Ok((FORGE_CONTEXT.get() == Some(context)).abi_encode())
263 }
264}
265
266pub fn set_execution_context(context: ForgeContext) {
269 let _ = FORGE_CONTEXT.set(context);
270}
271
272fn env(key: &str, ty: &DynSolType) -> Result {
273 get_env(key).and_then(|val| string::parse(&val, ty).map_err(map_env_err(key, &val)))
274}
275
276fn env_default<T: SolValue>(key: &str, default: &T, ty: &DynSolType) -> Result {
277 Ok(env(key, ty).unwrap_or_else(|_| default.abi_encode()))
278}
279
280fn env_array(key: &str, delim: &str, ty: &DynSolType) -> Result {
281 get_env(key).and_then(|val| {
282 string::parse_array(val.split(delim).map(str::trim), ty).map_err(map_env_err(key, &val))
283 })
284}
285
286fn env_array_default<T: SolValue>(key: &str, delim: &str, default: &T, ty: &DynSolType) -> Result {
287 Ok(env_array(key, delim, ty).unwrap_or_else(|_| default.abi_encode()))
288}
289
290fn get_env(key: &str) -> Result<String> {
291 match env::var(key) {
292 Ok(val) => Ok(val),
293 Err(env::VarError::NotPresent) => Err(fmt_err!("environment variable {key:?} not found")),
294 Err(env::VarError::NotUnicode(s)) => {
295 Err(fmt_err!("environment variable {key:?} was not valid unicode: {s:?}"))
296 }
297 }
298}
299
300fn map_env_err<'a>(key: &'a str, value: &'a str) -> impl FnOnce(Error) -> Error + 'a {
303 move |e| {
304 let mut e = e.to_string();
309 e = e.replacen(&format!("\"{value}\""), &format!("${key}"), 1);
310 e = e.replacen(&format!("\n{value}\n"), &format!("\n${key}\n"), 1);
311 Error::from(e)
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318
319 #[test]
320 fn parse_env_uint() {
321 let key = "parse_env_uint";
322 let value = "t";
323 unsafe {
324 env::set_var(key, value);
325 }
326
327 let err = env(key, &DynSolType::Uint(256)).unwrap_err().to_string();
328 assert_eq!(err.matches("$parse_env_uint").count(), 2, "{err:?}");
329 unsafe {
330 env::remove_var(key);
331 }
332 }
333}