1use crate::{
4 Cheatcode, Cheatcodes, Result,
5 Vm::*,
6 json::{
7 check_json_key_exists, parse_json, parse_json_coerce, parse_json_keys, resolve_type,
8 upsert_json_value,
9 },
10};
11use alloy_dyn_abi::DynSolType;
12use alloy_sol_types::SolValue;
13use foundry_common::{fmt::StructDefinitions, fs};
14use foundry_config::fs_permissions::FsAccessKind;
15use foundry_evm_core::evm::FoundryEvmNetwork;
16use serde_json::Value as JsonValue;
17use toml::Value as TomlValue;
18
19impl Cheatcode for keyExistsTomlCall {
20 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
21 let Self { toml, key } = self;
22 check_json_key_exists(&toml_to_json_string(toml)?, key)
23 }
24}
25
26impl Cheatcode for parseToml_0Call {
27 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
28 let Self { toml } = self;
29 parse_toml(
30 toml,
31 "$",
32 state.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok()),
33 )
34 }
35}
36
37impl Cheatcode for parseToml_1Call {
38 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
39 let Self { toml, key } = self;
40 parse_toml(
41 toml,
42 key,
43 state.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok()),
44 )
45 }
46}
47
48impl Cheatcode for parseTomlUintCall {
49 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
50 let Self { toml, key } = self;
51 parse_toml_coerce(toml, key, &DynSolType::Uint(256))
52 }
53}
54
55impl Cheatcode for parseTomlUintArrayCall {
56 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
57 let Self { toml, key } = self;
58 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Uint(256))))
59 }
60}
61
62impl Cheatcode for parseTomlIntCall {
63 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
64 let Self { toml, key } = self;
65 parse_toml_coerce(toml, key, &DynSolType::Int(256))
66 }
67}
68
69impl Cheatcode for parseTomlIntArrayCall {
70 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
71 let Self { toml, key } = self;
72 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Int(256))))
73 }
74}
75
76impl Cheatcode for parseTomlBoolCall {
77 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
78 let Self { toml, key } = self;
79 parse_toml_coerce(toml, key, &DynSolType::Bool)
80 }
81}
82
83impl Cheatcode for parseTomlBoolArrayCall {
84 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
85 let Self { toml, key } = self;
86 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Bool)))
87 }
88}
89
90impl Cheatcode for parseTomlAddressCall {
91 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
92 let Self { toml, key } = self;
93 parse_toml_coerce(toml, key, &DynSolType::Address)
94 }
95}
96
97impl Cheatcode for parseTomlAddressArrayCall {
98 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
99 let Self { toml, key } = self;
100 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Address)))
101 }
102}
103
104impl Cheatcode for parseTomlStringCall {
105 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
106 let Self { toml, key } = self;
107 parse_toml_coerce(toml, key, &DynSolType::String)
108 }
109}
110
111impl Cheatcode for parseTomlStringArrayCall {
112 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
113 let Self { toml, key } = self;
114 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::String)))
115 }
116}
117
118impl Cheatcode for parseTomlBytesCall {
119 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
120 let Self { toml, key } = self;
121 parse_toml_coerce(toml, key, &DynSolType::Bytes)
122 }
123}
124
125impl Cheatcode for parseTomlBytesArrayCall {
126 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
127 let Self { toml, key } = self;
128 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::Bytes)))
129 }
130}
131
132impl Cheatcode for parseTomlBytes32Call {
133 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
134 let Self { toml, key } = self;
135 parse_toml_coerce(toml, key, &DynSolType::FixedBytes(32))
136 }
137}
138
139impl Cheatcode for parseTomlBytes32ArrayCall {
140 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
141 let Self { toml, key } = self;
142 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(DynSolType::FixedBytes(32))))
143 }
144}
145
146impl Cheatcode for parseTomlType_0Call {
147 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
148 let Self { toml, typeDescription } = self;
149 parse_toml_coerce(
150 toml,
151 "$",
152 &resolve_type(
153 typeDescription,
154 state.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok()),
155 )?,
156 )
157 .map(|v| v.abi_encode())
158 }
159}
160
161impl Cheatcode for parseTomlType_1Call {
162 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
163 let Self { toml, key, typeDescription } = self;
164 parse_toml_coerce(
165 toml,
166 key,
167 &resolve_type(
168 typeDescription,
169 state.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok()),
170 )?,
171 )
172 .map(|v| v.abi_encode())
173 }
174}
175
176impl Cheatcode for parseTomlTypeArrayCall {
177 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
178 let Self { toml, key, typeDescription } = self;
179 let ty = resolve_type(
180 typeDescription,
181 state.analysis.as_ref().and_then(|analysis| analysis.struct_defs().ok()),
182 )?;
183 parse_toml_coerce(toml, key, &DynSolType::Array(Box::new(ty))).map(|v| v.abi_encode())
184 }
185}
186
187impl Cheatcode for parseTomlKeysCall {
188 fn apply<FEN: FoundryEvmNetwork>(&self, _state: &mut Cheatcodes<FEN>) -> Result {
189 let Self { toml, key } = self;
190 parse_toml_keys(toml, key)
191 }
192}
193
194impl Cheatcode for writeToml_0Call {
195 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
196 let Self { json, path } = self;
197 let value =
198 serde_json::from_str(json).unwrap_or_else(|_| JsonValue::String(json.to_owned()));
199
200 let toml_string = format_json_to_toml(value)?;
201 super::fs::write_file(state, path.as_ref(), toml_string.as_bytes())
202 }
203}
204
205impl Cheatcode for writeToml_1Call {
206 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
207 let Self { json: value, path, valueKey } = self;
208
209 let data_path = state.config.ensure_path_allowed(path, FsAccessKind::Read)?;
212 let mut json_data: JsonValue = if data_path.exists() {
213 let toml_data = fs::locked_read_to_string(&data_path)?;
214 toml::from_str(&toml_data).map_err(|e| fmt_err!("failed parsing TOML: {e}"))?
215 } else {
216 JsonValue::Object(Default::default())
217 };
218 upsert_json_value(&mut json_data, value, valueKey)?;
219
220 let toml_string = format_json_to_toml(json_data)?;
222 super::fs::write_file(state, path.as_ref(), toml_string.as_bytes())
223 }
224}
225
226fn parse_toml_str(toml: &str) -> Result<TomlValue> {
228 toml::from_str(toml).map_err(|e| fmt_err!("failed parsing TOML: {e}"))
229}
230
231fn parse_toml(toml: &str, key: &str, struct_defs: Option<&StructDefinitions>) -> Result {
233 parse_json(&toml_to_json_string(toml)?, key, struct_defs)
234}
235
236fn parse_toml_coerce(toml: &str, key: &str, ty: &DynSolType) -> Result {
238 parse_json_coerce(&toml_to_json_string(toml)?, key, ty)
239}
240
241fn parse_toml_keys(toml: &str, key: &str) -> Result {
243 parse_json_keys(&toml_to_json_string(toml)?, key)
244}
245
246fn toml_to_json_string(toml: &str) -> Result<String> {
248 let toml = parse_toml_str(toml)?;
249 let json = toml_to_json_value(toml);
250 serde_json::to_string(&json).map_err(|e| fmt_err!("failed to serialize JSON: {e}"))
251}
252
253fn format_json_to_toml(json: JsonValue) -> Result<String> {
255 let toml = json_to_toml_value(json);
256 toml::to_string_pretty(&toml).map_err(|e| fmt_err!("failed to serialize TOML: {e}"))
257}
258
259pub(super) fn toml_to_json_value(toml: TomlValue) -> JsonValue {
261 match toml {
262 TomlValue::String(s) => match s.as_str() {
263 "null" => JsonValue::Null,
264 _ => JsonValue::String(s),
265 },
266 TomlValue::Integer(i) => JsonValue::Number(i.into()),
267 TomlValue::Float(f) => match serde_json::Number::from_f64(f) {
268 Some(n) => JsonValue::Number(n),
269 None => JsonValue::String(f.to_string()),
270 },
271 TomlValue::Boolean(b) => JsonValue::Bool(b),
272 TomlValue::Array(a) => JsonValue::Array(a.into_iter().map(toml_to_json_value).collect()),
273 TomlValue::Table(t) => {
274 JsonValue::Object(t.into_iter().map(|(k, v)| (k, toml_to_json_value(v))).collect())
275 }
276 TomlValue::Datetime(d) => JsonValue::String(d.to_string()),
277 }
278}
279
280fn json_to_toml_value(json: JsonValue) -> TomlValue {
282 match json {
283 JsonValue::String(s) => TomlValue::String(s),
284 JsonValue::Number(n) => match n.as_i64() {
285 Some(i) => TomlValue::Integer(i),
286 None => match n.as_f64() {
287 Some(f) => TomlValue::Float(f),
288 None => TomlValue::String(n.to_string()),
289 },
290 },
291 JsonValue::Bool(b) => TomlValue::Boolean(b),
292 JsonValue::Array(a) => TomlValue::Array(a.into_iter().map(json_to_toml_value).collect()),
293 JsonValue::Object(o) => {
294 TomlValue::Table(o.into_iter().map(|(k, v)| (k, json_to_toml_value(v))).collect())
295 }
296 JsonValue::Null => TomlValue::String("null".to_string()),
297 }
298}