alloy_json_abi/
param.rs

1use crate::{
2    internal_type::BorrowedInternalType,
3    utils::{mk_eparam, mk_param, validate_identifier},
4    InternalType,
5};
6use alloc::{borrow::Cow, string::String, vec::Vec};
7use core::{fmt, str::FromStr};
8use parser::{Error, ParameterSpecifier, TypeSpecifier};
9use serde::{de::Unexpected, Deserialize, Deserializer, Serialize, Serializer};
10
11/// JSON specification of a parameter.
12///
13/// Parameters are the inputs and outputs of [Function]s, and the fields of
14/// [Error]s.
15///
16/// [Function]: crate::Function
17/// [Error]: crate::Error
18#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
19pub struct Param {
20    /// The canonical Solidity type of the parameter, using the word "tuple" to
21    /// represent complex types. E.g. `uint256` or `bytes[2]` or `tuple` or
22    /// `tuple[2]`.
23    ///
24    /// Generally, this is a valid [`TypeSpecifier`], but in very rare
25    /// circumstances, such as when a function in a library contains an enum
26    /// in its parameters or return types, this will be `Contract.EnumName`
27    /// instead of the actual type (`uint8`).
28    /// Visible for macros, functions inside the crate, and doc tests. It is not recommended to
29    /// instantiate directly. Use Param::new instead.
30    #[doc(hidden)]
31    pub ty: String,
32    /// The name of the parameter. This field always contains either the empty
33    /// string, or a valid Solidity identifier.
34    /// Visible for macros, functions inside the crate, and doc tests. It is not recommended to
35    /// instantiate directly. Use Param::new instead.
36    #[doc(hidden)]
37    pub name: String,
38    /// If the parameter is a compound type (a struct or tuple), a list of the
39    /// parameter's components, in order. Empty otherwise
40    pub components: Vec<Param>,
41    /// The internal type of the parameter. This type represents the type that
42    /// the author of the Solidity contract specified. E.g. for a contract, this
43    /// will be `contract MyContract` while the `type` field will be `address`.
44    pub internal_type: Option<InternalType>,
45}
46
47impl fmt::Display for Param {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        if let Some(it) = &self.internal_type { it.fmt(f) } else { f.write_str(&self.ty) }?;
50        f.write_str(" ")?;
51        f.write_str(&self.name)
52    }
53}
54
55impl<'de> Deserialize<'de> for Param {
56    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
57        ParamInner::deserialize(deserializer).and_then(|inner| {
58            if inner.indexed.is_none() {
59                inner.validate_fields()?;
60                Ok(Self {
61                    name: inner.name,
62                    ty: inner.ty,
63                    internal_type: inner.internal_type,
64                    components: inner.components,
65                })
66            } else {
67                Err(serde::de::Error::custom("indexed is not supported in params"))
68            }
69        })
70    }
71}
72
73impl Serialize for Param {
74    #[inline]
75    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
76        self.as_inner().serialize(serializer)
77    }
78}
79
80impl FromStr for Param {
81    type Err = parser::Error;
82
83    #[inline]
84    fn from_str(s: &str) -> Result<Self, Self::Err> {
85        Self::parse(s)
86    }
87}
88
89impl Param {
90    /// Parse a parameter from a Solidity parameter string.
91    ///
92    /// # Examples
93    ///
94    /// ```
95    /// # use alloy_json_abi::Param;
96    /// assert_eq!(
97    ///     Param::parse("uint256[] foo"),
98    ///     Ok(Param {
99    ///         name: "foo".into(),
100    ///         ty: "uint256[]".into(),
101    ///         components: vec![],
102    ///         internal_type: None,
103    ///     })
104    /// );
105    /// ```
106    pub fn parse(input: &str) -> parser::Result<Self> {
107        ParameterSpecifier::parse(input).map(|p| mk_param(p.name, p.ty))
108    }
109
110    /// Validate and create new instance of Param.
111    pub fn new(
112        name: &str,
113        ty: &str,
114        components: Vec<Self>,
115        internal_type: Option<InternalType>,
116    ) -> parser::Result<Self> {
117        Self::validate_fields(name, ty, !components.is_empty())?;
118        Ok(Self { ty: ty.into(), name: name.into(), components, internal_type })
119    }
120
121    /// The name of the parameter. This function always returns either an empty
122    /// slice, or a valid Solidity identifier.
123    #[inline]
124    pub fn name(&self) -> &str {
125        &self.name
126    }
127
128    /// The internal type of the parameter.
129    #[inline]
130    pub const fn internal_type(&self) -> Option<&InternalType> {
131        self.internal_type.as_ref()
132    }
133
134    /// True if the parameter is a UDT (user-defined type).
135    ///
136    /// A UDT will have
137    /// - an internal type that does not match its canonical type
138    /// - no space in its internal type (as it does not have a keyword body)
139    ///
140    /// Any `Other` specifier will definitely be a UDT if it contains a
141    /// contract.
142    #[inline]
143    pub fn is_udt(&self) -> bool {
144        match self.internal_type().and_then(|it| it.as_other()) {
145            Some((contract, ty)) => contract.is_some() || (self.is_simple_type() && ty != self.ty),
146            _ => false,
147        }
148    }
149
150    /// True if the parameter is a struct.
151    #[inline]
152    pub const fn is_struct(&self) -> bool {
153        match self.internal_type() {
154            Some(ty) => ty.is_struct(),
155            None => false,
156        }
157    }
158
159    /// True if the parameter is an enum.
160    #[inline]
161    pub const fn is_enum(&self) -> bool {
162        match self.internal_type() {
163            Some(ty) => ty.is_enum(),
164            None => false,
165        }
166    }
167
168    /// True if the parameter is a contract.
169    #[inline]
170    pub const fn is_contract(&self) -> bool {
171        match self.internal_type() {
172            Some(ty) => ty.is_contract(),
173            None => false,
174        }
175    }
176
177    /// The UDT specifier is a [`TypeSpecifier`] containing the UDT name and any
178    /// array sizes. It is computed from the `internal_type`. If this param is
179    /// not a UDT, this function will return `None`.
180    #[inline]
181    pub fn udt_specifier(&self) -> Option<TypeSpecifier<'_>> {
182        // UDTs are more annoying to check for, so we reuse logic here.
183        if !self.is_udt() {
184            return None;
185        }
186        self.internal_type().and_then(|ty| ty.other_specifier())
187    }
188
189    /// The struct specifier is a [`TypeSpecifier`] containing the struct name
190    /// and any array sizes. It is computed from the `internal_type` If this
191    /// param is not a struct, this function will return `None`.
192    #[inline]
193    pub fn struct_specifier(&self) -> Option<TypeSpecifier<'_>> {
194        self.internal_type().and_then(|ty| ty.struct_specifier())
195    }
196
197    /// The enum specifier is a [`TypeSpecifier`] containing the enum name and
198    /// any array sizes. It is computed from the `internal_type`. If this param
199    /// is not a enum, this function will return `None`.
200    #[inline]
201    pub fn enum_specifier(&self) -> Option<TypeSpecifier<'_>> {
202        self.internal_type().and_then(|ty| ty.enum_specifier())
203    }
204
205    /// The struct specifier is a [`TypeSpecifier`] containing the contract name
206    /// and any array sizes. It is computed from the `internal_type` If this
207    /// param is not a struct, this function will return `None`.
208    #[inline]
209    pub fn contract_specifier(&self) -> Option<TypeSpecifier<'_>> {
210        self.internal_type().and_then(|ty| ty.contract_specifier())
211    }
212
213    /// True if the type is simple
214    #[inline]
215    pub fn is_simple_type(&self) -> bool {
216        self.components.is_empty()
217    }
218
219    /// True if the type is complex (tuple or struct)
220    #[inline]
221    pub fn is_complex_type(&self) -> bool {
222        !self.components.is_empty()
223    }
224
225    /// Formats the canonical type of this parameter into the given string.
226    ///
227    /// This is used to encode the preimage of a function or error selector.
228    #[inline]
229    pub fn selector_type_raw(&self, s: &mut String) {
230        if self.components.is_empty() {
231            s.push_str(&self.ty);
232        } else {
233            crate::utils::params_abi_tuple(&self.components, s);
234            // checked during deserialization, but might be invalid from a user
235            if let Some(suffix) = self.ty.strip_prefix("tuple") {
236                s.push_str(suffix);
237            }
238        }
239    }
240
241    /// Formats the canonical type of this parameter into the given string including then names of
242    /// the params.
243    #[inline]
244    pub fn full_selector_type_raw(&self, s: &mut String) {
245        if self.components.is_empty() {
246            s.push_str(&self.ty);
247        } else {
248            s.push_str("tuple");
249            crate::utils::params_tuple(&self.components, s);
250            // checked during deserialization, but might be invalid from a user
251            if let Some(suffix) = self.ty.strip_prefix("tuple") {
252                s.push_str(suffix);
253            }
254        }
255    }
256
257    /// Returns the canonical type of this parameter.
258    ///
259    /// This is used to encode the preimage of a function or error selector.
260    #[inline]
261    pub fn selector_type(&self) -> Cow<'_, str> {
262        if self.components.is_empty() {
263            Cow::Borrowed(&self.ty)
264        } else {
265            let mut s = String::with_capacity(self.components.len() * 32);
266            self.selector_type_raw(&mut s);
267            Cow::Owned(s)
268        }
269    }
270
271    #[inline]
272    fn borrowed_internal_type(&self) -> Option<BorrowedInternalType<'_>> {
273        self.internal_type().as_ref().map(|it| it.as_borrowed())
274    }
275
276    #[inline]
277    fn as_inner(&self) -> BorrowedParamInner<'_> {
278        BorrowedParamInner {
279            name: &self.name,
280            ty: &self.ty,
281            indexed: None,
282            internal_type: self.borrowed_internal_type(),
283            components: Cow::Borrowed(&self.components),
284        }
285    }
286
287    #[inline]
288    fn validate_fields(name: &str, ty: &str, has_components: bool) -> parser::Result<()> {
289        if !name.is_empty() && !parser::is_valid_identifier(name) {
290            return Err(Error::invalid_identifier_string(name));
291        }
292
293        // any components means type is "tuple" + maybe brackets, so we can skip
294        // parsing with TypeSpecifier
295        if !has_components {
296            parser::TypeSpecifier::parse(ty)?;
297        } else {
298            // https://docs.soliditylang.org/en/latest/abi-spec.html#handling-tuple-types
299            // checking for "tuple" prefix should be enough
300            if !ty.starts_with("tuple") {
301                return Err(Error::invalid_type_string(ty));
302            }
303        }
304        Ok(())
305    }
306}
307
308/// A Solidity Event parameter.
309///
310/// Event parameters are distinct from function parameters in that they have an
311/// `indexed` field.
312#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
313pub struct EventParam {
314    /// The canonical Solidity type of the parameter, using the word "tuple" to
315    /// represent complex types. E.g. `uint256` or `bytes[2]` or `tuple` or
316    /// `tuple[2]`.
317    ///
318    /// Generally, this is a valid [`TypeSpecifier`], but in very rare
319    /// circumstances, such as when a function in a library contains an enum
320    /// in its parameters or return types, this will be `Contract.EnumName`
321    /// instead of the actual type (`uint8`).
322    /// Visible for macros, functions inside the crate, and doc tests. It is not recommended to
323    /// instantiate directly. Use Param::new instead.
324    #[doc(hidden)]
325    pub ty: String,
326    /// The name of the parameter. This field always contains either the empty
327    /// string, or a valid Solidity identifier.
328    /// Visible for macros, functions inside the crate, and doc tests. It is not recommended to
329    /// instantiate directly. Use Param::new instead.
330    #[doc(hidden)]
331    pub name: String,
332    /// Whether the parameter is indexed. Indexed parameters have their
333    /// value, or the hash of their value, stored in the log topics.
334    pub indexed: bool,
335    /// If the parameter is a compound type (a struct or tuple), a list of the
336    /// parameter's components, in order. Empty otherwise. Because the
337    /// components are not top-level event params, they will not have an
338    /// `indexed` field.
339    pub components: Vec<Param>,
340    /// The internal type of the parameter. This type represents the type that
341    /// the author of the Solidity contract specified. E.g. for a contract, this
342    /// will be `contract MyContract` while the `type` field will be `address`.
343    pub internal_type: Option<InternalType>,
344}
345
346impl fmt::Display for EventParam {
347    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
348        if let Some(it) = &self.internal_type { it.fmt(f) } else { f.write_str(&self.ty) }?;
349        f.write_str(" ")?;
350        f.write_str(&self.name)
351    }
352}
353
354impl<'de> Deserialize<'de> for EventParam {
355    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
356        ParamInner::deserialize(deserializer).and_then(|inner| {
357            inner.validate_fields()?;
358            Ok(Self {
359                name: inner.name,
360                ty: inner.ty,
361                indexed: inner.indexed.unwrap_or(false),
362                internal_type: inner.internal_type,
363                components: inner.components,
364            })
365        })
366    }
367}
368
369impl Serialize for EventParam {
370    #[inline]
371    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
372        self.as_inner().serialize(serializer)
373    }
374}
375
376impl FromStr for EventParam {
377    type Err = parser::Error;
378
379    #[inline]
380    fn from_str(s: &str) -> Result<Self, Self::Err> {
381        Self::parse(s)
382    }
383}
384
385impl EventParam {
386    /// Parse an event parameter from a Solidity parameter string.
387    ///
388    /// # Examples
389    ///
390    /// ```
391    /// # use std::panic::catch_unwind;
392    /// use alloy_json_abi::EventParam;
393    /// assert_eq!(
394    ///     EventParam::parse("uint256[] indexed foo"),
395    ///     Ok(EventParam {
396    ///         name: "foo".into(),
397    ///         ty: "uint256[]".into(),
398    ///         indexed: true,
399    ///         components: vec![],
400    ///         internal_type: None,
401    ///     })
402    /// );
403    /// ```
404    #[inline]
405    pub fn parse(input: &str) -> parser::Result<Self> {
406        ParameterSpecifier::parse(input).map(mk_eparam)
407    }
408
409    /// Validate and create new instance of EventParam
410    pub fn new(
411        name: &str,
412        ty: &str,
413        indexed: bool,
414        components: Vec<Param>,
415        internal_type: Option<InternalType>,
416    ) -> parser::Result<Self> {
417        Param::validate_fields(name, ty, !components.is_empty())?;
418        Ok(Self { name: name.into(), ty: ty.into(), indexed, components, internal_type })
419    }
420
421    /// The internal type of the parameter.
422    #[inline]
423    pub const fn internal_type(&self) -> Option<&InternalType> {
424        self.internal_type.as_ref()
425    }
426
427    /// True if the parameter is a UDT (user-defined type).
428    ///
429    /// A UDT will have
430    /// - an internal type that does not match its canonical type
431    /// - no space in its internal type (as it does not have a keyword body)
432    ///
433    /// Any `Other` specifier will definitely be a UDT if it contains a
434    /// contract.
435    #[inline]
436    pub fn is_udt(&self) -> bool {
437        match self.internal_type().and_then(|it| it.as_other()) {
438            Some((contract, ty)) => contract.is_some() || (self.is_simple_type() && ty != self.ty),
439            _ => false,
440        }
441    }
442
443    /// True if the parameter is a struct.
444    #[inline]
445    pub const fn is_struct(&self) -> bool {
446        match self.internal_type() {
447            Some(ty) => ty.is_struct(),
448            None => false,
449        }
450    }
451
452    /// True if the parameter is an enum.
453    #[inline]
454    pub const fn is_enum(&self) -> bool {
455        match self.internal_type() {
456            Some(ty) => ty.is_enum(),
457            None => false,
458        }
459    }
460
461    /// True if the parameter is a contract.
462    #[inline]
463    pub const fn is_contract(&self) -> bool {
464        match self.internal_type() {
465            Some(ty) => ty.is_contract(),
466            None => false,
467        }
468    }
469
470    /// The UDT specifier is a [`TypeSpecifier`] containing the UDT name and any
471    /// array sizes. It is computed from the `internal_type`. If this param is
472    /// not a UDT, this function will return `None`.
473    #[inline]
474    pub fn udt_specifier(&self) -> Option<TypeSpecifier<'_>> {
475        // UDTs are more annoying to check for, so we reuse logic here.
476        if !self.is_udt() {
477            return None;
478        }
479        self.internal_type().and_then(|ty| ty.other_specifier())
480    }
481
482    /// The struct specifier is a [`TypeSpecifier`] containing the struct name
483    /// and any array sizes. It is computed from the `internal_type` If this
484    /// param is not a struct, this function will return `None`.
485    #[inline]
486    pub fn struct_specifier(&self) -> Option<TypeSpecifier<'_>> {
487        self.internal_type().and_then(|ty| ty.struct_specifier())
488    }
489
490    /// The enum specifier is a [`TypeSpecifier`] containing the enum name and
491    /// any array sizes. It is computed from the `internal_type`. If this param
492    /// is not a enum, this function will return `None`.
493    #[inline]
494    pub fn enum_specifier(&self) -> Option<TypeSpecifier<'_>> {
495        self.internal_type().and_then(|ty| ty.enum_specifier())
496    }
497
498    /// The struct specifier is a [`TypeSpecifier`] containing the contract name
499    /// and any array sizes. It is computed from the `internal_type` If this
500    /// param is not a struct, this function will return `None`.
501    #[inline]
502    pub fn contract_specifier(&self) -> Option<TypeSpecifier<'_>> {
503        self.internal_type().and_then(|ty| ty.contract_specifier())
504    }
505
506    /// True if the type is simple
507    #[inline]
508    pub fn is_simple_type(&self) -> bool {
509        self.components.is_empty()
510    }
511
512    /// True if the type is complex (tuple or struct)
513    #[inline]
514    pub fn is_complex_type(&self) -> bool {
515        !self.components.is_empty()
516    }
517
518    /// Formats the canonical type of this parameter into the given string.
519    ///
520    /// This is used to encode the preimage of the event selector.
521    #[inline]
522    pub fn selector_type_raw(&self, s: &mut String) {
523        if self.components.is_empty() {
524            s.push_str(&self.ty);
525        } else {
526            crate::utils::params_abi_tuple(&self.components, s);
527            // checked during deserialization, but might be invalid from a user
528            if let Some(suffix) = self.ty.strip_prefix("tuple") {
529                s.push_str(suffix);
530            }
531        }
532    }
533
534    /// Formats the canonical type of this parameter into the given string including then names of
535    /// the params.
536    #[inline]
537    pub fn full_selector_type_raw(&self, s: &mut String) {
538        if self.components.is_empty() {
539            s.push_str(&self.ty);
540        } else {
541            s.push_str("tuple");
542            crate::utils::params_tuple(&self.components, s);
543            // checked during deserialization, but might be invalid from a user
544            if let Some(suffix) = self.ty.strip_prefix("tuple") {
545                s.push_str(suffix);
546            }
547        }
548    }
549
550    /// Returns the canonical type of this parameter.
551    ///
552    /// This is used to encode the preimage of the event selector.
553    #[inline]
554    pub fn selector_type(&self) -> Cow<'_, str> {
555        if self.components.is_empty() {
556            Cow::Borrowed(&self.ty)
557        } else {
558            let mut s = String::with_capacity(self.components.len() * 32);
559            self.selector_type_raw(&mut s);
560            Cow::Owned(s)
561        }
562    }
563
564    #[inline]
565    fn borrowed_internal_type(&self) -> Option<BorrowedInternalType<'_>> {
566        self.internal_type().as_ref().map(|it| it.as_borrowed())
567    }
568
569    #[inline]
570    fn as_inner(&self) -> BorrowedParamInner<'_> {
571        BorrowedParamInner {
572            name: &self.name,
573            ty: &self.ty,
574            indexed: Some(self.indexed),
575            internal_type: self.borrowed_internal_type(),
576            components: Cow::Borrowed(&self.components),
577        }
578    }
579}
580
581#[derive(Deserialize)]
582struct ParamInner {
583    #[serde(default)]
584    name: String,
585    #[serde(rename = "type")]
586    ty: String,
587    #[serde(default, skip_serializing_if = "Option::is_none")]
588    indexed: Option<bool>,
589    #[serde(rename = "internalType", default, skip_serializing_if = "Option::is_none")]
590    internal_type: Option<InternalType>,
591    #[serde(default, skip_serializing_if = "Vec::is_empty")]
592    components: Vec<Param>,
593}
594
595impl Serialize for ParamInner {
596    #[inline]
597    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
598        self.as_borrowed().serialize(serializer)
599    }
600}
601
602impl ParamInner {
603    #[inline]
604    fn validate_fields<E: serde::de::Error>(&self) -> Result<(), E> {
605        self.as_borrowed().validate_fields()
606    }
607
608    #[inline]
609    fn as_borrowed(&self) -> BorrowedParamInner<'_> {
610        BorrowedParamInner {
611            name: &self.name,
612            ty: &self.ty,
613            indexed: self.indexed,
614            internal_type: self.internal_type.as_ref().map(InternalType::as_borrowed),
615            components: Cow::Borrowed(&self.components),
616        }
617    }
618}
619
620#[derive(Serialize, Deserialize)]
621struct BorrowedParamInner<'a> {
622    #[serde(default)]
623    name: &'a str,
624    #[serde(rename = "type")]
625    ty: &'a str,
626    #[serde(default, skip_serializing_if = "Option::is_none")]
627    indexed: Option<bool>,
628    #[serde(rename = "internalType", default, skip_serializing_if = "Option::is_none")]
629    internal_type: Option<BorrowedInternalType<'a>>,
630    #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
631    components: Cow<'a, [Param]>,
632}
633
634impl BorrowedParamInner<'_> {
635    fn validate_fields<E: serde::de::Error>(&self) -> Result<(), E> {
636        validate_identifier(self.name)?;
637
638        // any components means type is "tuple" + maybe brackets, so we can skip
639        // parsing with TypeSpecifier
640        if self.components.is_empty() {
641            if parser::TypeSpecifier::parse(self.ty).is_err() {
642                return Err(E::invalid_value(
643                    Unexpected::Str(self.ty),
644                    &"a valid Solidity type specifier",
645                ));
646            }
647        } else {
648            // https://docs.soliditylang.org/en/latest/abi-spec.html#handling-tuple-types
649            // checking for "tuple" prefix should be enough
650            if !self.ty.starts_with("tuple") {
651                return Err(E::invalid_value(
652                    Unexpected::Str(self.ty),
653                    &"a string prefixed with `tuple`, optionally followed by a sequence of `[]` or `[k]` with integers `k`",
654                ));
655            }
656        }
657
658        Ok(())
659    }
660}
661
662#[cfg(test)]
663mod tests {
664    use super::*;
665
666    #[test]
667    fn param_from_json() {
668        let param = r#"{
669            "internalType": "string",
670            "name": "reason",
671            "type": "string"
672        }"#;
673        let expected = Param {
674            name: "reason".into(),
675            ty: "string".into(),
676            internal_type: Some(InternalType::Other { contract: None, ty: "string".into() }),
677            components: vec![],
678        };
679
680        assert_eq!(serde_json::from_str::<Param>(param).unwrap(), expected);
681
682        let param_value = serde_json::from_str::<serde_json::Value>(param).unwrap();
683        assert_eq!(serde_json::from_value::<Param>(param_value).unwrap(), expected);
684
685        #[cfg(feature = "std")]
686        {
687            let reader = std::io::Cursor::new(param);
688            assert_eq!(serde_json::from_reader::<_, Param>(reader).unwrap(), expected);
689        }
690    }
691
692    #[test]
693    fn param_from_new() {
694        let param = Param::new("something", "string", vec![], None);
695        assert_eq!(
696            param,
697            Ok(Param {
698                name: "something".into(),
699                ty: "string".into(),
700                components: vec![],
701                internal_type: None,
702            })
703        );
704
705        let err_not_a_type = Param::new("something", "not a type", vec![], None);
706        assert!(err_not_a_type.is_err());
707
708        let err_not_tuple = Param::new("something", "string", vec![param.unwrap()], None);
709        assert!(err_not_tuple.is_err())
710    }
711}