ethbind_json/
lib.rs

1//! Ethereum constract abi json format encode/decode support
2//!
3//! Visit [`official document`](https://docs.soliditylang.org/en/v0.8.17/abi-spec.html#json) for details
4
5use std::{fmt::Display, str::FromStr};
6
7use regex::Regex;
8use serde::{Deserialize, Serialize};
9
10use thiserror::Error;
11
12#[derive(Debug, Error)]
13pub enum AbiError {
14    #[error("Invalid fixed type declare {0}, {1}")]
15    FixedMN(String, String),
16
17    #[error("Invalid integer type declare {0}, {1}")]
18    IntegerM(String, String),
19
20    #[error("Invalid fixed length binary type declare {0}, {1}")]
21    BytesM(String, String),
22
23    #[error("Invalid tuple type declare {0}, {1}")]
24    Tuple(String, String),
25
26    #[error("Invalid fixed-length Array type declare {0}, {1}")]
27    ArrayM(String, String),
28
29    #[error("Invalid Array type declare {0}, {1}")]
30    Array(String, String),
31
32    #[error("Invalid Type declare {0}")]
33    UnknownType(String),
34}
35
36/// Hardhat generate artifact
37#[derive(Debug, Serialize, Deserialize)]
38#[serde(rename_all = "camelCase")]
39pub struct HardhatArtifact {
40    pub contract_name: String,
41    pub source_name: String,
42    pub abi: Vec<AbiField>,
43    pub bytecode: String,
44    pub deployed_bytecode: String,
45}
46
47/// Contract interface type enum
48#[derive(Debug, Serialize, Deserialize)]
49#[serde(rename_all = "camelCase", tag = "type")]
50pub enum AbiField {
51    Function(Function),
52    Constructor(Constructor),
53    Receive(Receive),
54    Fallback(Fallback),
55    Event(Event),
56    Error(Error),
57}
58
59/// A structure type to represent `function` abi
60#[derive(Debug, Serialize, Deserialize)]
61#[serde(rename_all = "camelCase")]
62pub struct Function {
63    /// the function name
64    pub name: String,
65    /// An array of function's input params
66    #[serde(default = "default_parameters")]
67    pub inputs: Vec<Parameter>,
68    /// An array of function's output params
69    #[serde(default = "default_parameters")]
70    pub outputs: Vec<Parameter>,
71    /// a string with one of the following values: pure (specified to not read blockchain state),
72    /// view (specified to not modify the blockchain state),
73    /// nonpayable (function does not accept Ether - the default) and payable (function accepts Ether)
74    pub state_mutability: StateMutability,
75}
76
77impl Function {
78    /// Only include inputs,e.g: withdraw(address)
79    pub fn signature(&self) -> String {
80        let tuple = Self::to_signature(&self.inputs);
81
82        format!("{}{}", self.name, tuple)
83    }
84
85    fn to_signature(params: &[Parameter]) -> String {
86        let mut pairs = vec![];
87
88        for param in params.iter() {
89            if let Some(components) = &param.components {
90                let element = Self::to_signature(components);
91                match &param.r#type {
92                    Type::Array(_) => {
93                        pairs.push(format!("{}[]", element));
94                    }
95                    Type::ArrayM(array_m) => {
96                        pairs.push(format!("{}[{}]", element, array_m.m));
97                    }
98                    _ => {
99                        pairs.push(format!("{}", element));
100                    }
101                }
102            } else {
103                pairs.push(format!("{}", param.r#type));
104            }
105        }
106
107        format!("({})", pairs.join(","))
108    }
109}
110
111fn default_parameters() -> Vec<Parameter> {
112    vec![]
113}
114
115/// A structure type to represent `constructor` abi
116#[derive(Debug, Serialize, Deserialize)]
117#[serde(rename_all = "camelCase")]
118pub struct Constructor {
119    /// An array of function's input params
120    pub inputs: Vec<Parameter>,
121    /// a string with one of the following values: pure (specified to not read blockchain state),
122    /// view (specified to not modify the blockchain state),
123    /// nonpayable (function does not accept Ether - the default) and payable (function accepts Ether)
124    pub state_mutability: StateMutability,
125}
126
127impl Constructor {
128    /// Only include inputs,e.g: withdraw(address)
129    pub fn signature(&self) -> String {
130        let tuple = Self::to_signature(&self.inputs);
131
132        format!("Constructor{}", tuple)
133    }
134
135    fn to_signature(params: &[Parameter]) -> String {
136        let mut pairs = vec![];
137
138        for param in params.iter() {
139            if let Some(components) = &param.components {
140                let element = Self::to_signature(components);
141                match &param.r#type {
142                    Type::Array(_) => {
143                        pairs.push(format!("{}[]", element));
144                    }
145                    Type::ArrayM(array_m) => {
146                        pairs.push(format!("{}[{}]", element, array_m.m));
147                    }
148                    _ => {
149                        pairs.push(format!("{}", element));
150                    }
151                }
152            } else {
153                pairs.push(format!("{}", param.r#type));
154            }
155        }
156
157        format!("({})", pairs.join(","))
158    }
159}
160
161/// A structure type to represent `receive function` abi
162#[derive(Debug, Serialize, Deserialize)]
163#[serde(rename_all = "camelCase")]
164pub struct Receive {
165    /// a string with one of the following values: pure (specified to not read blockchain state),
166    /// view (specified to not modify the blockchain state),
167    /// nonpayable (function does not accept Ether - the default) and payable (function accepts Ether)
168    pub state_mutability: StateMutability,
169}
170
171/// A structure type to represent `fallback function` abi
172#[derive(Debug, Serialize, Deserialize)]
173#[serde(rename_all = "camelCase")]
174pub struct Fallback {
175    /// a string with one of the following values: pure (specified to not read blockchain state),
176    /// view (specified to not modify the blockchain state),
177    /// nonpayable (function does not accept Ether - the default) and payable (function accepts Ether)
178    pub state_mutability: StateMutability,
179}
180
181#[derive(Debug, Serialize, Deserialize)]
182#[serde(rename_all = "camelCase")]
183pub enum StateMutability {
184    Pure,
185    View,
186    Nonpayable,
187    Payable,
188}
189
190/// A structure type to represent `event` abi
191#[derive(Debug, Serialize, Deserialize)]
192#[serde(rename_all = "camelCase")]
193pub struct Event {
194    /// the function name
195    pub name: String,
196    /// An array of function's input params
197    pub inputs: Vec<Parameter>,
198    /// `true` if the event was declared as anonymous
199    pub anonymous: bool,
200}
201
202/// A structure type to represent `event` abi
203#[derive(Debug, Serialize, Deserialize)]
204#[serde(rename_all = "camelCase")]
205pub struct Error {
206    /// the function name
207    pub name: String,
208    /// An array of function's input params
209    pub inputs: Vec<Parameter>,
210}
211/// Handle Function/Event/Error 's input or output parameter type
212#[derive(Debug, Clone, Serialize, Deserialize)]
213#[serde(rename_all = "camelCase")]
214pub struct Parameter {
215    /// The name of the parameter
216    pub name: String,
217    /// The canonical type of the parameter
218    pub r#type: Type,
219    /// used for tuple types, only if the type field start with prefix `tuple`. e.g, `tupe[]`,`tuple`
220    pub components: Option<Vec<Parameter>>,
221    /// This field is only meaningful for `Event` or `Error`
222    #[serde(default = "default_indexed")]
223    pub indexed: bool,
224    /// Hardhat extension field
225    pub internal_type: Option<String>,
226}
227
228fn default_indexed() -> bool {
229    false
230}
231
232/// Contract abi simple types enum
233#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
234#[serde(rename_all = "camelCase")]
235pub enum SimpleType {
236    Address,
237    Uint,
238    Int,
239    Bool,
240    Fixed,
241    Ufixed,
242    /// an address (20 bytes) followed by a function selector (4 bytes). Encoded identical to bytes24.
243    Function,
244    Bytes,
245    String,
246    Tuple,
247}
248
249impl ToString for SimpleType {
250    fn to_string(&self) -> String {
251        // to canonical type name
252        match self {
253            Self::Ufixed => "fixed128x18".into(),
254            Self::Fixed => "ufixed128x18".into(),
255            Self::Int => "int256".into(),
256            Self::Uint => "uint256".into(),
257            _ => {
258                let data = serde_json::to_string(self).unwrap();
259
260                data[1..data.len() - 1].to_string()
261            }
262        }
263    }
264}
265
266impl SimpleType {
267    pub fn is_tuple(&self) -> bool {
268        match self {
269            Self::Tuple => true,
270            _ => false,
271        }
272    }
273}
274
275#[derive(Debug, Clone, PartialEq)]
276/// fixed-point decimal number of M bits, 8 <= M <= 256, M % 8 == 0, and 0 < N <= 80, which denotes the value v as v / (10 ** N).
277pub struct FixedMN {
278    pub m: usize,
279    pub n: usize,
280    pub signed: bool,
281}
282
283impl Display for FixedMN {
284    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285        let value = serde_json::to_string(self).expect("Serialize type to json");
286        write!(f, "{}", &value[1..value.len() - 1])
287    }
288}
289
290impl Serialize for FixedMN {
291    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
292    where
293        S: serde::Serializer,
294    {
295        if self.signed {
296            serializer.serialize_str(&format!("fixed{}x{}", self.m, self.n))
297        } else {
298            serializer.serialize_str(&format!("ufixed{}x{}", self.m, self.n))
299        }
300    }
301}
302
303fn fixed_regex() -> Regex {
304    Regex::new(r"^(u){0,1}fixed(\d{1,3})x(\d{1,3})$").unwrap()
305}
306
307impl<'de> Deserialize<'de> for FixedMN {
308    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
309    where
310        D: serde::Deserializer<'de>,
311    {
312        let data = String::deserialize(deserializer)?;
313
314        if let Some(captures) = fixed_regex().captures(&data) {
315            let signed = captures.get(1).map(|_| false).unwrap_or(true);
316
317            let m: usize = (&captures[2]).parse().map_err(serde::de::Error::custom)?;
318            let n: usize = (&captures[3]).parse().map_err(serde::de::Error::custom)?;
319
320            if m < 8 || m > 256 || m % 8 != 0 {
321                return Err(AbiError::FixedMN(
322                    data,
323                    "M bits must meet the condition 0 < M <= 256, M % 8 == 0".to_string(),
324                ))
325                .map_err(serde::de::Error::custom);
326            }
327
328            if n > 80 {
329                return Err(AbiError::FixedMN(
330                    data,
331                    "decimal numbers N must meet the condition 0 < N <= 80".to_string(),
332                ))
333                .map_err(serde::de::Error::custom);
334            }
335
336            Ok(Self { signed, m, n })
337        } else {
338            return Err(AbiError::FixedMN(
339                data,
340                "{u}fixed<M>x<N>: fixed-point decimal number of M bits, 8 <= M <= 256, M % 8 == 0, and 0 < N <= 80"
341                    .to_string(),
342            ))
343            .map_err(serde::de::Error::custom);
344        }
345    }
346}
347
348/// integer type of M bits, 0 < M <= 256, M % 8 == 0. e.g. uint32, uint8
349#[derive(Debug, Clone, PartialEq)]
350pub struct IntegerM {
351    pub signed: bool,
352    pub m: usize,
353}
354
355impl Display for IntegerM {
356    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
357        let value = serde_json::to_string(self).expect("Serialize type to json");
358        write!(f, "{}", &value[1..value.len() - 1])
359    }
360}
361
362impl Serialize for IntegerM {
363    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
364    where
365        S: serde::Serializer,
366    {
367        if self.signed {
368            serializer.serialize_str(&format!("int{}", self.m,))
369        } else {
370            serializer.serialize_str(&format!("uint{}", self.m,))
371        }
372    }
373}
374
375fn integer_regex() -> Regex {
376    Regex::new(r"^(u){0,1}int(\d{1,3})$").unwrap()
377}
378
379impl<'de> Deserialize<'de> for IntegerM {
380    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
381    where
382        D: serde::Deserializer<'de>,
383    {
384        let data = String::deserialize(deserializer)?;
385
386        if let Some(captures) = integer_regex().captures(&data) {
387            let signed = captures.get(1).map(|_| false).unwrap_or(true);
388
389            let m: usize = (&captures[2]).parse().map_err(serde::de::Error::custom)?;
390
391            if m < 8 || m > 256 || m % 8 != 0 {
392                return Err(AbiError::IntegerM(
393                    data,
394                    "M bits must meet the condition 0 < M <= 256, M % 8 == 0".to_string(),
395                ))
396                .map_err(serde::de::Error::custom);
397            }
398
399            Ok(Self { signed, m })
400        } else {
401            return Err(AbiError::FixedMN(
402                data,
403                "{u}int<M>: unsigned integer type of M bits, 0 < M <= 256, M % 8 == 0".to_string(),
404            ))
405            .map_err(serde::de::Error::custom);
406        }
407    }
408}
409
410#[derive(Debug, Clone, PartialEq)]
411/// binary type of M bytes, 0 < M <= 32
412pub struct BytesM {
413    pub m: usize,
414}
415
416impl Display for BytesM {
417    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
418        let value = serde_json::to_string(self).expect("Serialize type to json");
419        write!(f, "{}", &value[1..value.len() - 1])
420    }
421}
422
423impl Serialize for BytesM {
424    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
425    where
426        S: serde::Serializer,
427    {
428        serializer.serialize_str(&format!("bytes{}", self.m,))
429    }
430}
431
432impl<'de> Deserialize<'de> for BytesM {
433    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
434    where
435        D: serde::Deserializer<'de>,
436    {
437        let data = String::deserialize(deserializer)?;
438
439        if data.starts_with("bytes") {
440            let m: usize = (&data[5..]).parse().map_err(serde::de::Error::custom)?;
441
442            if m > 32 {
443                return Err(AbiError::BytesM(data, "0 < M <= 32".to_string()))
444                    .map_err(serde::de::Error::custom);
445            }
446
447            Ok(Self { m })
448        } else {
449            return Err(AbiError::BytesM(
450                data,
451                "bytes<M>: binary type of M bytes, 0 < M <= 32".to_string(),
452            ))
453            .map_err(serde::de::Error::custom);
454        }
455    }
456}
457
458#[derive(Debug, Clone, PartialEq)]
459pub enum Type {
460    Simple(SimpleType),
461
462    BytesM(BytesM),
463
464    IntegerM(IntegerM),
465
466    FixedMN(FixedMN),
467
468    ArrayM(Box<ArrayM>),
469    Array(Box<Array>),
470}
471
472impl From<Type> for String {
473    fn from(value: Type) -> Self {
474        let str = serde_json::to_string(&value).unwrap();
475
476        str[1..str.len() - 1].to_owned()
477    }
478}
479
480impl FromStr for Type {
481    type Err = serde_json::Error;
482    fn from_str(s: &str) -> Result<Self, Self::Err> {
483        serde_json::from_str(&format!("\"{}\"", s))
484    }
485}
486
487impl Display for Type {
488    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
489        let value = serde_json::to_string(self).expect("Serialize type to json");
490        write!(f, "{}", &value[1..value.len() - 1])
491    }
492}
493
494impl Serialize for Type {
495    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
496    where
497        S: serde::Serializer,
498    {
499        match self {
500            Self::Simple(simple) => simple.serialize(serializer),
501            Self::BytesM(byte_m) => byte_m.serialize(serializer),
502            Self::IntegerM(integer_m) => integer_m.serialize(serializer),
503            Self::FixedMN(fixed_m) => fixed_m.serialize(serializer),
504            Self::ArrayM(array_m) => array_m.serialize(serializer),
505            Self::Array(array) => array.serialize(serializer),
506        }
507    }
508}
509
510impl<'de> Deserialize<'de> for Type {
511    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
512    where
513        D: serde::Deserializer<'de>,
514    {
515        let data = String::deserialize(deserializer)?;
516
517        let data = format!("\"{}\"", data);
518
519        if let Ok(array_m) = serde_json::from_str::<ArrayM>(&data) {
520            return Ok(Self::ArrayM(Box::new(array_m)));
521        }
522
523        if let Ok(array) = serde_json::from_str::<Array>(&data) {
524            return Ok(Self::Array(Box::new(array)));
525        }
526
527        if let Ok(fixed_m_n) = serde_json::from_str::<FixedMN>(&data) {
528            return Ok(Self::FixedMN(fixed_m_n));
529        }
530
531        if let Ok(integer_m) = serde_json::from_str::<IntegerM>(&data) {
532            return Ok(Self::IntegerM(integer_m));
533        }
534
535        if let Ok(bytes_m) = serde_json::from_str::<BytesM>(&data) {
536            return Ok(Self::BytesM(bytes_m));
537        }
538
539        if let Ok(simple_type) = serde_json::from_str::<SimpleType>(&data) {
540            return Ok(Self::Simple(simple_type));
541        }
542
543        return Err(AbiError::UnknownType(data)).map_err(serde::de::Error::custom);
544    }
545}
546
547#[derive(Debug, Clone, PartialEq)]
548/// a fixed-length array of M elements, M >= 0, of the given type.
549pub struct ArrayM {
550    pub element: Type,
551    /// fixed-length array of `m` elements, M >= 0,
552    pub m: usize,
553}
554
555impl Display for ArrayM {
556    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
557        let value = serde_json::to_string(self).expect("Serialize type to json");
558        write!(f, "{}", &value[1..value.len() - 1])
559    }
560}
561
562impl Serialize for ArrayM {
563    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
564    where
565        S: serde::Serializer,
566    {
567        let element = serde_json::to_string(&self.element).map_err(serde::ser::Error::custom)?;
568
569        serializer.serialize_str(&format!("{}[{}]", &element[1..element.len() - 1], self.m))
570    }
571}
572
573fn array_m_regex() -> Regex {
574    Regex::new(r"\[(\d{1,3})\]$").unwrap()
575}
576
577impl<'de> Deserialize<'de> for ArrayM {
578    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
579    where
580        D: serde::Deserializer<'de>,
581    {
582        let array_m = String::deserialize(deserializer)?;
583
584        let end_with_regex = array_m_regex();
585
586        if let Some(caps) = end_with_regex.captures(&array_m) {
587            let m: usize = (&caps[1]).parse().map_err(serde::de::Error::custom)?;
588
589            let data = format!("\"{}\"", &array_m[..array_m.len() - caps.len() - 2]);
590
591            let element: Type = serde_json::from_str(&data).map_err(serde::de::Error::custom)?;
592
593            return Ok(Self { element, m });
594        } else {
595            return Err(AbiError::ArrayM(
596                array_m,
597                "<type>[M]: a fixed-length array of M elements, M >= 0, of the given type"
598                    .to_string(),
599            ))
600            .map_err(serde::de::Error::custom);
601        }
602    }
603}
604
605#[derive(Debug, Clone, PartialEq)]
606/// a variable-length array of elements of the given type
607pub struct Array {
608    pub element: Type,
609}
610
611impl Display for Array {
612    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
613        let value = serde_json::to_string(self).expect("Serialize type to json");
614        write!(f, "{}", &value[1..value.len() - 1])
615    }
616}
617
618impl Serialize for Array {
619    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
620    where
621        S: serde::Serializer,
622    {
623        let element = serde_json::to_string(&self.element).map_err(serde::ser::Error::custom)?;
624
625        serializer.serialize_str(&format!("{}[]", &element[1..element.len() - 1]))
626    }
627}
628
629impl<'de> Deserialize<'de> for Array {
630    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
631    where
632        D: serde::Deserializer<'de>,
633    {
634        let array_m = String::deserialize(deserializer)?;
635
636        if array_m.ends_with("[]") {
637            let data = format!("\"{}\"", &array_m[..array_m.len() - 2]);
638            let element: Type = serde_json::from_str(&data).map_err(serde::de::Error::custom)?;
639
640            return Ok(Self { element });
641        } else {
642            return Err(AbiError::Array(
643                array_m,
644                "<type>[]: a variable-length array of elements of the given type.".to_string(),
645            ))
646            .map_err(serde::de::Error::custom);
647        }
648    }
649}
650
651#[cfg(test)]
652mod tests {
653
654    use super::*;
655
656    #[test]
657    fn test_fixed_regex() {
658        _ = pretty_env_logger::try_init();
659        let re = fixed_regex();
660
661        assert!(re.is_match("ufixed100x18"));
662
663        assert!(re.is_match("fixed100x18"));
664
665        assert!(!re.is_match("fixed1000x18"));
666
667        assert!(!re.is_match("ufixed1000x18"));
668        assert!(!re.is_match("uufixed1000x18"));
669
670        assert!(!re.is_match("fixed-100x18"));
671
672        if let Some(captures) = fixed_regex().captures("fixed128x18") {
673            assert_eq!(captures.get(1), None);
674            assert_eq!(captures.get(2).map(|c| c.as_str()), Some("128"));
675            assert_eq!(captures.get(3).map(|c| c.as_str()), Some("18"));
676        }
677    }
678
679    #[test]
680    fn test_fixed_json() {
681        let fixed: FixedMN = serde_json::from_str(r#""fixed128x18""#).expect("Parse fixed");
682
683        assert_eq!(fixed.signed, true);
684        assert_eq!(fixed.m, 128);
685        assert_eq!(fixed.n, 18);
686
687        let fixed: FixedMN = serde_json::from_str(r#""ufixed128x18""#).expect("Parse fixed");
688
689        assert_eq!(fixed.signed, false);
690        assert_eq!(fixed.m, 128);
691        assert_eq!(fixed.n, 18);
692
693        serde_json::from_str::<FixedMN>(r#""ufixed100x18""#).expect_err("M % 8 == 0");
694
695        serde_json::from_str::<FixedMN>(r#""ufixed128x180""#).expect_err("N <= 80");
696    }
697
698    #[test]
699    fn test_int_json() {
700        let fixed: IntegerM = serde_json::from_str(r#""int128""#).expect("Parse integer");
701
702        assert_eq!(fixed.signed, true);
703        assert_eq!(fixed.m, 128);
704
705        let fixed: IntegerM = serde_json::from_str(r#""uint128""#).expect("Parse integer");
706
707        assert_eq!(fixed.signed, false);
708        assert_eq!(fixed.m, 128);
709
710        serde_json::from_str::<IntegerM>(r#""uint100""#).expect_err("M % 8 == 0");
711    }
712
713    #[test]
714    fn test_end_with() {
715        let end_with_regex = array_m_regex();
716
717        let caps = end_with_regex.captures("Hello[1][123]").unwrap();
718
719        assert_eq!(&caps[1], "123");
720    }
721
722    #[test]
723    fn test_type_serde() {
724        _ = pretty_env_logger::try_init();
725        fn check(expect: &str) {
726            let t: Type = expect.parse().expect("Parse type string");
727
728            let data: String = t.into();
729
730            assert_eq!(data, expect);
731        }
732
733        let test_vector = vec![
734            "uint256",
735            "int256",
736            "address",
737            "int8",
738            "uint",
739            "int",
740            "bool",
741            "fixed128x16",
742            "ufixed128x16",
743            "fixed",
744            "ufixed",
745            "bytes",
746            "bytes24",
747            "tuple",
748            "function",
749            "string",
750            "tuple[]",
751            "tuple[][32]",
752            "bool[20]",
753            "uint256[20]",
754        ];
755
756        for v in test_vector {
757            check(v);
758        }
759    }
760
761    #[test]
762    fn test_hardhat_artifact() {
763        let _: HardhatArtifact =
764            serde_json::from_str(include_str!("abi.json")).expect("Parse hardhat artifact");
765    }
766
767    #[test]
768    fn test_field() {
769        let data = r#"
770             {
771      "inputs": [
772        {
773          "internalType": "address",
774          "name": "WETH_",
775          "type": "address"
776        }
777      ],
778      "stateMutability": "nonpayable",
779      "type": "constructor"
780    }
781        "#;
782
783        _ = serde_json::from_str::<AbiField>(data).expect("Parse abi field");
784    }
785}