1use crate::{DynSolCall, DynSolType, Result};
6use alloc::vec::Vec;
7use alloy_json_abi::{EventParam, Function, Param};
8use parser::{ParameterSpecifier, Parameters, RootType, TupleSpecifier, TypeSpecifier, TypeStem};
9
10#[cfg(feature = "eip712")]
11use alloy_json_abi::InternalType;
12
13pub trait Specifier<T> {
42 fn resolve(&self) -> Result<T>;
44}
45
46impl Specifier<DynSolType> for str {
47 #[inline]
48 fn resolve(&self) -> Result<DynSolType> {
49 DynSolType::parse(self)
50 }
51}
52
53impl Specifier<DynSolType> for RootType<'_> {
54 fn resolve(&self) -> Result<DynSolType> {
55 match self.span() {
56 "address" => Ok(DynSolType::Address),
57 "function" => Ok(DynSolType::Function),
58 "bool" => Ok(DynSolType::Bool),
59 "string" => Ok(DynSolType::String),
60 "bytes" => Ok(DynSolType::Bytes),
61 "uint" => Ok(DynSolType::Uint(256)),
62 "int" => Ok(DynSolType::Int(256)),
63 name => {
64 if let Some(sz) = name.strip_prefix("bytes") {
65 if let Ok(sz) = sz.parse() {
66 if sz != 0 && sz <= 32 {
67 return Ok(DynSolType::FixedBytes(sz));
68 }
69 }
70 return Err(parser::Error::invalid_size(name).into());
71 }
72
73 let (s, is_uint) =
75 if let Some(s) = name.strip_prefix('u') { (s, true) } else { (name, false) };
76
77 if let Some(sz) = s.strip_prefix("int") {
78 if let Ok(sz) = sz.parse() {
79 if sz != 0 && sz <= 256 && sz % 8 == 0 {
80 return if is_uint {
81 Ok(DynSolType::Uint(sz))
82 } else {
83 Ok(DynSolType::Int(sz))
84 };
85 }
86 }
87 Err(parser::Error::invalid_size(name).into())
88 } else {
89 Err(parser::Error::invalid_type_string(name).into())
90 }
91 }
92 }
93 }
94}
95
96impl Specifier<DynSolType> for TupleSpecifier<'_> {
97 #[inline]
98 fn resolve(&self) -> Result<DynSolType> {
99 tuple(&self.types).map(DynSolType::Tuple)
100 }
101}
102
103impl Specifier<DynSolType> for TypeStem<'_> {
104 #[inline]
105 fn resolve(&self) -> Result<DynSolType> {
106 match self {
107 Self::Root(root) => root.resolve(),
108 Self::Tuple(tuple) => tuple.resolve(),
109 }
110 }
111}
112
113impl Specifier<DynSolType> for TypeSpecifier<'_> {
114 fn resolve(&self) -> Result<DynSolType> {
115 self.stem.resolve().map(|ty| ty.array_wrap_from_iter(self.sizes.iter().copied()))
116 }
117}
118
119impl Specifier<DynSolType> for ParameterSpecifier<'_> {
120 #[inline]
121 fn resolve(&self) -> Result<DynSolType> {
122 self.ty.resolve()
123 }
124}
125
126impl Specifier<DynSolType> for Parameters<'_> {
127 #[inline]
128 fn resolve(&self) -> Result<DynSolType> {
129 tuple(&self.params).map(DynSolType::Tuple)
130 }
131}
132
133impl Specifier<DynSolType> for Param {
134 #[inline]
135 fn resolve(&self) -> Result<DynSolType> {
136 resolve_param(
137 &self.ty,
138 &self.components,
139 #[cfg(feature = "eip712")]
140 self.internal_type(),
141 )
142 }
143}
144
145impl Specifier<DynSolType> for EventParam {
146 #[inline]
147 fn resolve(&self) -> Result<DynSolType> {
148 resolve_param(
149 &self.ty,
150 &self.components,
151 #[cfg(feature = "eip712")]
152 self.internal_type(),
153 )
154 }
155}
156
157impl Specifier<DynSolCall> for Function {
158 #[inline]
159 fn resolve(&self) -> Result<DynSolCall> {
160 let selector = self.selector();
161 let parameters =
162 self.inputs.iter().map(Specifier::<DynSolType>::resolve).collect::<Result<Vec<_>>>()?;
163 let returns = self
164 .outputs
165 .iter()
166 .map(Specifier::<DynSolType>::resolve)
167 .collect::<Result<Vec<_>>>()?
168 .into();
169 let method = self.name.clone();
170
171 Ok(DynSolCall::new(selector, parameters, Some(method), returns))
172 }
173}
174
175fn resolve_param(
176 ty: &str,
177 components: &[Param],
178 #[cfg(feature = "eip712")] it: Option<&InternalType>,
179) -> Result<DynSolType> {
180 let ty = TypeSpecifier::parse(ty)?;
181
182 if components.is_empty() {
184 return ty.resolve();
185 }
186
187 let tuple = tuple(components)?;
189
190 #[cfg(feature = "eip712")]
191 let resolved = if let Some((_, name)) = it.and_then(|i| i.as_struct()) {
192 DynSolType::CustomStruct {
193 name: name.split('[').next().unwrap().into(),
195 prop_names: components.iter().map(|c| c.name.clone()).collect(),
196 tuple,
197 }
198 } else {
199 DynSolType::Tuple(tuple)
200 };
201
202 #[cfg(not(feature = "eip712"))]
203 let resolved = DynSolType::Tuple(tuple);
204
205 Ok(resolved.array_wrap_from_iter(ty.sizes))
206}
207
208fn tuple<T: Specifier<DynSolType>>(slice: &[T]) -> Result<Vec<DynSolType>> {
209 let mut types = Vec::with_capacity(slice.len());
210 for ty in slice {
211 types.push(ty.resolve()?);
212 }
213 Ok(types)
214}
215
216macro_rules! deref_impls {
217 ($($(#[$attr:meta])* [$($gen:tt)*] $t:ty),+ $(,)?) => {$(
218 $(#[$attr])*
219 impl<$($gen)*> Specifier<DynSolType> for $t {
220 #[inline]
221 fn resolve(&self) -> Result<DynSolType> {
222 (**self).resolve()
223 }
224 }
225 )+};
226}
227
228deref_impls! {
229 [] alloc::string::String,
230 [T: ?Sized + Specifier<DynSolType>] &T,
231 [T: ?Sized + Specifier<DynSolType>] &mut T,
232 [T: ?Sized + Specifier<DynSolType>] alloc::boxed::Box<T>,
233 [T: ?Sized + alloc::borrow::ToOwned + Specifier<DynSolType>] alloc::borrow::Cow<'_, T>,
234 [T: ?Sized + Specifier<DynSolType>] alloc::rc::Rc<T>,
235 [T: ?Sized + Specifier<DynSolType>] alloc::sync::Arc<T>,
236}
237
238#[cfg(test)]
239mod tests {
240 use super::*;
241 use alloc::boxed::Box;
242
243 fn parse(s: &str) -> Result<DynSolType> {
244 s.parse()
245 }
246
247 #[test]
248 fn extra_close_parens() {
249 parse("(bool,uint256))").unwrap_err();
250 parse("bool,uint256))").unwrap_err();
251 parse("bool,uint256)").unwrap_err();
252 }
253
254 #[test]
255 fn extra_open_parents() {
256 parse("((bool,uint256)").unwrap_err();
257 parse("((bool,uint256").unwrap_err();
258 parse("(bool,uint256").unwrap_err();
259 }
260
261 #[test]
262 fn it_parses_tuples() {
263 assert_eq!(parse("(bool,)"), Ok(DynSolType::Tuple(vec![DynSolType::Bool])));
264 assert_eq!(
265 parse("(uint256,uint256)"),
266 Ok(DynSolType::Tuple(vec![DynSolType::Uint(256), DynSolType::Uint(256)]))
267 );
268 assert_eq!(
269 parse("(uint256,uint256)[2]"),
270 Ok(DynSolType::FixedArray(
271 Box::new(DynSolType::Tuple(vec![DynSolType::Uint(256), DynSolType::Uint(256)])),
272 2
273 ))
274 );
275 }
276
277 #[test]
278 fn nested_tuples() {
279 assert_eq!(
280 parse("(bool,(uint256,uint256))"),
281 Ok(DynSolType::Tuple(vec![
282 DynSolType::Bool,
283 DynSolType::Tuple(vec![DynSolType::Uint(256), DynSolType::Uint(256)])
284 ]))
285 );
286 assert_eq!(
287 parse("(((bool),),)"),
288 Ok(DynSolType::Tuple(vec![DynSolType::Tuple(vec![DynSolType::Tuple(vec![
289 DynSolType::Bool
290 ])])]))
291 );
292 }
293
294 #[test]
295 fn empty_tuples() {
296 assert_eq!(parse("()"), Ok(DynSolType::Tuple(vec![])));
297 assert_eq!(
298 parse("((),())"),
299 Ok(DynSolType::Tuple(vec![DynSolType::Tuple(vec![]), DynSolType::Tuple(vec![])]))
300 );
301 assert_eq!(
302 parse("((()))"),
303 Ok(DynSolType::Tuple(vec![DynSolType::Tuple(vec![DynSolType::Tuple(vec![])])]))
304 );
305 }
306
307 #[test]
308 fn it_parses_simple_types() {
309 assert_eq!(parse("uint256"), Ok(DynSolType::Uint(256)));
310 assert_eq!(parse("uint8"), Ok(DynSolType::Uint(8)));
311 assert_eq!(parse("uint"), Ok(DynSolType::Uint(256)));
312 assert_eq!(parse("address"), Ok(DynSolType::Address));
313 assert_eq!(parse("bool"), Ok(DynSolType::Bool));
314 assert_eq!(parse("string"), Ok(DynSolType::String));
315 assert_eq!(parse("bytes"), Ok(DynSolType::Bytes));
316 assert_eq!(parse("bytes32"), Ok(DynSolType::FixedBytes(32)));
317 }
318
319 #[test]
320 fn it_parses_complex_solidity_types() {
321 assert_eq!(parse("uint256[]"), Ok(DynSolType::Array(Box::new(DynSolType::Uint(256)))));
322 assert_eq!(
323 parse("uint256[2]"),
324 Ok(DynSolType::FixedArray(Box::new(DynSolType::Uint(256)), 2))
325 );
326 assert_eq!(
327 parse("uint256[2][3]"),
328 Ok(DynSolType::FixedArray(
329 Box::new(DynSolType::FixedArray(Box::new(DynSolType::Uint(256)), 2)),
330 3
331 ))
332 );
333 assert_eq!(
334 parse("uint256[][][]"),
335 Ok(DynSolType::Array(Box::new(DynSolType::Array(Box::new(DynSolType::Array(
336 Box::new(DynSolType::Uint(256))
337 ))))))
338 );
339
340 assert_eq!(
341 parse("tuple(address,bytes,(bool,(string,uint256)[][3]))[2]"),
342 Ok(DynSolType::FixedArray(
343 Box::new(DynSolType::Tuple(vec![
344 DynSolType::Address,
345 DynSolType::Bytes,
346 DynSolType::Tuple(vec![
347 DynSolType::Bool,
348 DynSolType::FixedArray(
349 Box::new(DynSolType::Array(Box::new(DynSolType::Tuple(vec![
350 DynSolType::String,
351 DynSolType::Uint(256)
352 ])))),
353 3
354 ),
355 ]),
356 ])),
357 2
358 ))
359 );
360 }
361
362 #[test]
363 fn library_enum_workaround() {
364 assert_eq!(parse("MyLibrary.MyEnum"), Ok(DynSolType::Uint(8)));
365 assert_eq!(
366 parse("MyLibrary.MyEnum[]"),
367 Ok(DynSolType::Array(Box::new(DynSolType::Uint(8))))
368 );
369 }
370}