foundry_cheatcodes/
string.rs
1use crate::{Cheatcode, Cheatcodes, Result, Vm::*};
4use alloy_dyn_abi::{DynSolType, DynSolValue};
5use alloy_primitives::{hex, U256};
6use alloy_sol_types::SolValue;
7
8impl Cheatcode for toString_0Call {
10 fn apply(&self, _state: &mut Cheatcodes) -> Result {
11 let Self { value } = self;
12 Ok(value.to_string().abi_encode())
13 }
14}
15
16impl Cheatcode for toString_1Call {
18 fn apply(&self, _state: &mut Cheatcodes) -> Result {
19 let Self { value } = self;
20 Ok(value.to_string().abi_encode())
21 }
22}
23
24impl Cheatcode for toString_2Call {
26 fn apply(&self, _state: &mut Cheatcodes) -> Result {
27 let Self { value } = self;
28 Ok(value.to_string().abi_encode())
29 }
30}
31
32impl Cheatcode for toString_3Call {
34 fn apply(&self, _state: &mut Cheatcodes) -> Result {
35 let Self { value } = self;
36 Ok(value.to_string().abi_encode())
37 }
38}
39
40impl Cheatcode for toString_4Call {
42 fn apply(&self, _state: &mut Cheatcodes) -> Result {
43 let Self { value } = self;
44 Ok(value.to_string().abi_encode())
45 }
46}
47
48impl Cheatcode for toString_5Call {
50 fn apply(&self, _state: &mut Cheatcodes) -> Result {
51 let Self { value } = self;
52 Ok(value.to_string().abi_encode())
53 }
54}
55
56impl Cheatcode for parseBytesCall {
57 fn apply(&self, _state: &mut Cheatcodes) -> Result {
58 let Self { stringifiedValue } = self;
59 parse(stringifiedValue, &DynSolType::Bytes)
60 }
61}
62
63impl Cheatcode for parseAddressCall {
64 fn apply(&self, _state: &mut Cheatcodes) -> Result {
65 let Self { stringifiedValue } = self;
66 parse(stringifiedValue, &DynSolType::Address)
67 }
68}
69
70impl Cheatcode for parseUintCall {
71 fn apply(&self, _state: &mut Cheatcodes) -> Result {
72 let Self { stringifiedValue } = self;
73 parse(stringifiedValue, &DynSolType::Uint(256))
74 }
75}
76
77impl Cheatcode for parseIntCall {
78 fn apply(&self, _state: &mut Cheatcodes) -> Result {
79 let Self { stringifiedValue } = self;
80 parse(stringifiedValue, &DynSolType::Int(256))
81 }
82}
83
84impl Cheatcode for parseBytes32Call {
85 fn apply(&self, _state: &mut Cheatcodes) -> Result {
86 let Self { stringifiedValue } = self;
87 parse(stringifiedValue, &DynSolType::FixedBytes(32))
88 }
89}
90
91impl Cheatcode for parseBoolCall {
92 fn apply(&self, _state: &mut Cheatcodes) -> Result {
93 let Self { stringifiedValue } = self;
94 parse(stringifiedValue, &DynSolType::Bool)
95 }
96}
97
98impl Cheatcode for toLowercaseCall {
99 fn apply(&self, _state: &mut Cheatcodes) -> Result {
100 let Self { input } = self;
101 Ok(input.to_lowercase().abi_encode())
102 }
103}
104
105impl Cheatcode for toUppercaseCall {
106 fn apply(&self, _state: &mut Cheatcodes) -> Result {
107 let Self { input } = self;
108 Ok(input.to_uppercase().abi_encode())
109 }
110}
111
112impl Cheatcode for trimCall {
113 fn apply(&self, _state: &mut Cheatcodes) -> Result {
114 let Self { input } = self;
115 Ok(input.trim().abi_encode())
116 }
117}
118
119impl Cheatcode for replaceCall {
120 fn apply(&self, _state: &mut Cheatcodes) -> Result {
121 let Self { input, from, to } = self;
122 Ok(input.replace(from, to).abi_encode())
123 }
124}
125
126impl Cheatcode for splitCall {
127 fn apply(&self, _state: &mut Cheatcodes) -> Result {
128 let Self { input, delimiter } = self;
129 let parts: Vec<&str> = input.split(delimiter).collect();
130 Ok(parts.abi_encode())
131 }
132}
133
134impl Cheatcode for indexOfCall {
135 fn apply(&self, _state: &mut Cheatcodes) -> Result {
136 let Self { input, key } = self;
137 Ok(input.find(key).map(U256::from).unwrap_or(U256::MAX).abi_encode())
138 }
139}
140
141impl Cheatcode for containsCall {
142 fn apply(&self, _state: &mut Cheatcodes) -> Result {
143 let Self { subject, search } = self;
144 Ok(subject.contains(search).abi_encode())
145 }
146}
147
148pub(super) fn parse(s: &str, ty: &DynSolType) -> Result {
149 parse_value(s, ty).map(|v| v.abi_encode())
150}
151
152pub(super) fn parse_array<I, S>(values: I, ty: &DynSolType) -> Result
153where
154 I: IntoIterator<Item = S>,
155 S: AsRef<str>,
156{
157 let mut values = values.into_iter();
158 match values.next() {
159 Some(first) if !first.as_ref().is_empty() => std::iter::once(first)
160 .chain(values)
161 .map(|s| parse_value(s.as_ref(), ty))
162 .collect::<Result<Vec<_>, _>>()
163 .map(|vec| DynSolValue::Array(vec).abi_encode()),
164 _ => Ok("".abi_encode()),
166 }
167}
168
169#[instrument(target = "cheatcodes", level = "debug", skip(ty), fields(%ty), ret)]
170pub(super) fn parse_value(s: &str, ty: &DynSolType) -> Result<DynSolValue> {
171 match ty.coerce_str(s) {
172 Ok(value) => Ok(value),
173 Err(e) => match parse_value_fallback(s, ty) {
174 Some(Ok(value)) => Ok(value),
175 Some(Err(e2)) => Err(fmt_err!("failed parsing {s:?} as type `{ty}`: {e2}")),
176 None => Err(fmt_err!("failed parsing {s:?} as type `{ty}`: {e}")),
177 },
178 }
179}
180
181fn parse_value_fallback(s: &str, ty: &DynSolType) -> Option<Result<DynSolValue, &'static str>> {
183 match ty {
184 DynSolType::Bool => {
185 let b = match s {
186 "1" => true,
187 "0" => false,
188 s if s.eq_ignore_ascii_case("true") => true,
189 s if s.eq_ignore_ascii_case("false") => false,
190 _ => return None,
191 };
192 return Some(Ok(DynSolValue::Bool(b)));
193 }
194 DynSolType::Int(_) |
195 DynSolType::Uint(_) |
196 DynSolType::FixedBytes(_) |
197 DynSolType::Bytes => {
198 if !s.starts_with("0x") && hex::check_raw(s) {
199 return Some(Err("missing hex prefix (\"0x\") for hex string"));
200 }
201 }
202 _ => {}
203 }
204 None
205}