fuels_rs/
json_abi.rs

1use crate::{abi_decoder::ABIDecoder, abi_encoder::ABIEncoder, errors::Error};
2use fuels_core::{ParamType, Token};
3use hex::FromHex;
4use itertools::Itertools;
5use std::convert::TryInto;
6use std::str;
7use std::str::FromStr;
8
9use sway_types::{JsonABI, Property};
10
11use serde_json;
12
13pub struct ABIParser {
14    fn_selector: Option<Vec<u8>>,
15}
16
17impl ABIParser {
18    pub fn new() -> Self {
19        ABIParser { fn_selector: None }
20    }
21
22    /// Higher-level layer of the ABI encoding module.
23    /// Encode is essentially a wrapper of [`crate::abi_encoder`],
24    /// but it is responsible for parsing strings into proper [`Token`]
25    /// that can be encoded by the [`crate::abi_encoder`].
26    /// Note that `encode` only encodes the parameters for an ABI call,
27    /// It won't include the function selector in it. To get the function
28    /// selector, use `encode_with_function_selector`.
29    ///
30    /// # Examples
31    /// ```
32    /// use fuels_rs::json_abi::ABIParser;
33    /// let json_abi = r#"
34    ///     [
35    ///         {
36    ///             "type":"contract",
37    ///             "inputs":[
38    ///                 {
39    ///                     "name":"arg",
40    ///                     "type":"u32"
41    ///                 }
42    ///             ],
43    ///             "name":"takes_u32_returns_bool",
44    ///             "outputs":[
45    ///                 {
46    ///                     "name":"",
47    ///                     "type":"bool"
48    ///                 }
49    ///             ]
50    ///         }
51    ///     ]
52    ///     "#;
53    ///
54    ///     let values: Vec<String> = vec!["10".to_string()];
55    ///
56    ///     let mut abi = ABIParser::new();
57    ///
58    ///     let function_name = "takes_u32_returns_bool";
59    ///     let encoded = abi.encode(json_abi, function_name, &values).unwrap();
60    ///     let expected_encode = "000000000000000a";
61    ///     assert_eq!(encoded, expected_encode);
62    /// ```
63    pub fn encode(&mut self, abi: &str, fn_name: &str, values: &[String]) -> Result<String, Error> {
64        let parsed_abi: JsonABI = serde_json::from_str(abi)?;
65
66        let entry = parsed_abi.iter().find(|e| e.name == fn_name);
67
68        if entry.is_none() {
69            return Err(Error::InvalidName(format!(
70                "couldn't find function name: {}",
71                fn_name
72            )));
73        }
74
75        let entry = entry.unwrap();
76
77        let mut encoder = ABIEncoder::new_with_fn_selector(
78            self.build_fn_selector(fn_name, &entry.inputs)?.as_bytes(),
79        );
80
81        // Update the fn_selector field with the encoded selector.
82        self.fn_selector = Some(encoder.function_selector.to_vec());
83
84        let params: Vec<_> = entry
85            .inputs
86            .iter()
87            .map(|param| parse_param(param).unwrap())
88            .zip(values.iter().map(|v| v as &str))
89            .collect();
90
91        let tokens = self.parse_tokens(&params)?;
92
93        Ok(hex::encode(encoder.encode(&tokens)?))
94    }
95
96    /// Similar to `encode`, but includes the function selector in the
97    /// final encoded string.
98    ///
99    /// # Examples
100    /// ```
101    /// use fuels_rs::json_abi::ABIParser;
102    /// let json_abi = r#"
103    ///     [
104    ///         {
105    ///             "type":"contract",
106    ///             "inputs":[
107    ///                 {
108    ///                     "name":"arg",
109    ///                     "type":"u32"
110    ///                 }
111    ///             ],
112    ///             "name":"takes_u32_returns_bool",
113    ///             "outputs":[
114    ///                 {
115    ///                     "name":"",
116    ///                     "type":"bool"
117    ///                 }
118    ///             ]
119    ///         }
120    ///     ]
121    ///     "#;
122    ///
123    ///     let values: Vec<String> = vec!["10".to_string()];
124    ///
125    ///     let mut abi = ABIParser::new();
126
127    ///     let function_name = "takes_u32_returns_bool";
128    ///
129    ///     let encoded = abi
130    ///         .encode_with_function_selector(json_abi, function_name, &values)
131    ///         .unwrap();
132    ///
133    ///     let expected_encode = "000000006355e6ee000000000000000a";
134    ///     assert_eq!(encoded, expected_encode);
135    /// ```
136    pub fn encode_with_function_selector(
137        &mut self,
138        abi: &str,
139        fn_name: &str,
140        values: &[String],
141    ) -> Result<String, Error> {
142        let encoded_params = self.encode(abi, fn_name, values)?;
143        let fn_selector = self
144            .fn_selector
145            .to_owned()
146            .expect("Function selector not encoded");
147
148        let encoded_fn_selector = hex::encode(fn_selector);
149
150        Ok(format!("{}{}", encoded_fn_selector, encoded_params))
151    }
152
153    /// Helper function to return the encoded function selector.
154    /// It must already be encoded.
155    pub fn get_encoded_function_selector(&self) -> String {
156        let fn_selector = self
157            .fn_selector
158            .to_owned()
159            .expect("Function selector not encoded");
160
161        hex::encode(fn_selector)
162    }
163
164    /// Similar to `encode`, but it encodes only an array of strings containing
165    /// [<type_1>, <param_1>, <type_2>, <param_2>, <type_n>, <param_n>]
166    /// Without having to reference to a JSON specification of the ABI.
167    pub fn encode_params(&self, params: &[String]) -> Result<String, Error> {
168        let pairs: Vec<_> = params.chunks(2).collect_vec();
169
170        let mut param_type_pairs: Vec<(ParamType, &str)> = vec![];
171
172        let mut encoder = ABIEncoder::new();
173
174        for pair in pairs {
175            let prop = Property {
176                name: "".to_string(),
177                type_field: pair[0].clone(),
178                components: None,
179            };
180            let p = parse_param(&prop)?;
181
182            let t: (ParamType, &str) = (p, &pair[1]);
183            param_type_pairs.push(t);
184        }
185
186        let tokens = self.parse_tokens(&param_type_pairs)?;
187
188        let encoded = encoder.encode(&tokens)?;
189
190        Ok(hex::encode(encoded))
191    }
192
193    /// Helper function to turn a list of tuples(ParamType, &str) into
194    /// a vector of Tokens ready to be encoded.
195    /// Essentially a wrapper on `tokenize`.
196    pub fn parse_tokens<'a>(&self, params: &'a [(ParamType, &str)]) -> Result<Vec<Token>, Error> {
197        params
198            .iter()
199            .map(|&(ref param, value)| self.tokenize(param, value.to_string()))
200            .collect::<Result<_, _>>()
201            .map_err(From::from)
202    }
203
204    /// Takes a ParamType and a value string and joins them as a single
205    /// Token that holds the value within it. This Token is used
206    /// in the encoding process.
207    pub fn tokenize<'a>(&self, param: &ParamType, value: String) -> Result<Token, Error> {
208        let trimmed_value = value.trim();
209        match &*param {
210            ParamType::U8 => Ok(Token::U8(trimmed_value.parse::<u8>()?)),
211            ParamType::U16 => Ok(Token::U16(trimmed_value.parse::<u16>()?)),
212            ParamType::U32 => Ok(Token::U32(trimmed_value.parse::<u32>()?)),
213            ParamType::U64 => Ok(Token::U64(trimmed_value.parse::<u64>()?)),
214            ParamType::Bool => Ok(Token::Bool(trimmed_value.parse::<bool>()?)),
215            ParamType::Byte => Ok(Token::Byte(trimmed_value.parse::<u8>()?)),
216            ParamType::B256 => {
217                let v = Vec::from_hex(trimmed_value)?;
218                let s: [u8; 32] = v.as_slice().try_into().unwrap();
219                Ok(Token::B256(s))
220            }
221            ParamType::Array(t, _) => Ok(self.tokenize_array(trimmed_value, &*t)?),
222            ParamType::String(_) => Ok(Token::String(trimmed_value.to_string())),
223            ParamType::Struct(struct_params) => {
224                Ok(self.tokenize_struct(trimmed_value, struct_params)?)
225            }
226            ParamType::Enum(s) => {
227                let discriminant = self.get_enum_discriminant_from_string(&value);
228                let value = self.get_enum_value_from_string(&value);
229
230                let token = self.tokenize(&s[discriminant], value)?;
231
232                Ok(Token::Enum(Box::new((discriminant as u8, token))))
233            }
234        }
235    }
236
237    /// Creates a struct `Token` from an array of parameter types and a string of values.
238    /// I.e. it takes a string containing values "value_1, value_2, value_3" and an array
239    /// of `ParamType` containing the type of each value, in order:
240    /// [ParamType::<Type of value_1>, ParamType::<Type of value_2>, ParamType::<Type of value_3>]
241    /// And attempts to return a `Token::Struct()` containing the inner types.
242    /// It works for nested/recursive structs.
243    pub fn tokenize_struct(&self, value: &str, params: &[ParamType]) -> Result<Token, Error> {
244        if !value.starts_with('(') || !value.ends_with(')') {
245            return Err(Error::InvalidData);
246        }
247
248        if value.chars().count() == 2 {
249            return Ok(Token::Struct(vec![]));
250        }
251
252        let mut result = vec![];
253        let mut nested = 0isize;
254        let mut ignore = false;
255        let mut last_item = 1;
256        let mut params_iter = params.iter();
257
258        for (pos, ch) in value.chars().enumerate() {
259            match ch {
260                '(' if !ignore => {
261                    nested += 1;
262                }
263                ')' if !ignore => {
264                    nested -= 1;
265
266                    match nested.cmp(&0) {
267                        std::cmp::Ordering::Less => {
268                            return Err(Error::InvalidData);
269                        }
270                        std::cmp::Ordering::Equal => {
271                            let sub = &value[last_item..pos];
272
273                            let token = self.tokenize(
274                                params_iter.next().ok_or(Error::InvalidData)?,
275                                sub.to_string(),
276                            )?;
277                            result.push(token);
278                            last_item = pos + 1;
279                        }
280                        _ => {}
281                    }
282                }
283                '"' => {
284                    ignore = !ignore;
285                }
286                ',' if nested == 1 && !ignore => {
287                    let sub = &value[last_item..pos];
288                    // If we've encountered an array within a struct property
289                    // keep iterating until we see the end of it "]".
290                    if sub.contains('[') && !sub.contains(']') {
291                        continue;
292                    }
293
294                    let token = self.tokenize(
295                        params_iter.next().ok_or(Error::InvalidData)?,
296                        sub.to_string(),
297                    )?;
298                    result.push(token);
299                    last_item = pos + 1;
300                }
301                _ => (),
302            }
303        }
304
305        if ignore {
306            return Err(Error::InvalidData);
307        }
308
309        Ok(Token::Struct(result))
310    }
311
312    /// Creates an enum `Token` from an array of parameter types and a string of values.
313    /// I.e. it takes a string containing values "value_1, value_2, value_3" and an array
314    /// of `ParamType` containing the type of each value, in order:
315    /// [ParamType::<Type of value_1>, ParamType::<Type of value_2>, ParamType::<Type of value_3>]
316    /// And attempts to return a `Token::Enum()` containing the inner types.
317    /// It works for nested/recursive enums.
318    pub fn tokenize_array<'a>(&self, value: &'a str, param: &ParamType) -> Result<Token, Error> {
319        if !value.starts_with('[') || !value.ends_with(']') {
320            return Err(Error::InvalidData);
321        }
322
323        if value.chars().count() == 2 {
324            return Ok(Token::Array(vec![]));
325        }
326
327        let mut result = vec![];
328        let mut nested = 0isize;
329        let mut ignore = false;
330        let mut last_item = 1;
331        for (i, ch) in value.chars().enumerate() {
332            match ch {
333                '[' if !ignore => {
334                    nested += 1;
335                }
336                ']' if !ignore => {
337                    nested -= 1;
338
339                    match nested.cmp(&0) {
340                        std::cmp::Ordering::Less => {
341                            return Err(Error::InvalidData);
342                        }
343                        std::cmp::Ordering::Equal => {
344                            // Last element of this nest level; proceed to tokenize.
345                            let sub = &value[last_item..i];
346                            match self.is_array(sub) {
347                                true => {
348                                    let arr_param = ParamType::Array(
349                                        Box::new(param.to_owned()),
350                                        self.get_array_length_from_string(sub),
351                                    );
352
353                                    result.push(self.tokenize(&arr_param, sub.to_string())?);
354                                }
355                                false => {
356                                    result.push(self.tokenize(param, sub.to_string())?);
357                                }
358                            }
359
360                            last_item = i + 1;
361                        }
362                        _ => {}
363                    }
364                }
365                '"' => {
366                    ignore = !ignore;
367                }
368                ',' if nested == 1 && !ignore => {
369                    let sub = &value[last_item..i];
370                    match self.is_array(sub) {
371                        true => {
372                            let arr_param = ParamType::Array(
373                                Box::new(param.to_owned()),
374                                self.get_array_length_from_string(sub),
375                            );
376
377                            result.push(self.tokenize(&arr_param, sub.to_string())?);
378                        }
379                        false => {
380                            result.push(self.tokenize(param, sub.to_string())?);
381                        }
382                    }
383                    last_item = i + 1;
384                }
385                _ => (),
386            }
387        }
388
389        if ignore {
390            return Err(Error::InvalidData);
391        }
392
393        Ok(Token::Array(result))
394    }
395
396    /// Higher-level layer of the ABI decoding module.
397    /// Decodes a value of a given ABI and a target function's output.
398    /// Note that the `value` has to be a byte array, meaning that
399    /// the caller must properly cast the "upper" type into a `&[u8]`,
400    pub fn decode<'a>(
401        &self,
402        abi: &str,
403        fn_name: &str,
404        value: &'a [u8],
405    ) -> Result<Vec<Token>, Error> {
406        let parsed_abi: JsonABI = serde_json::from_str(abi)?;
407
408        let entry = parsed_abi.iter().find(|e| e.name == fn_name);
409
410        if entry.is_none() {
411            return Err(Error::InvalidName(format!(
412                "couldn't find function name: {}",
413                fn_name
414            )));
415        }
416
417        let params_result: Result<Vec<_>, _> = entry
418            .unwrap()
419            .outputs
420            .iter()
421            .map(|param| parse_param(param))
422            .collect();
423
424        match params_result {
425            Ok(params) => {
426                let mut decoder = ABIDecoder::new();
427
428                Ok(decoder.decode(&params, value)?)
429            }
430            Err(e) => Err(e),
431        }
432    }
433
434    /// Similar to decode, but it decodes only an array types and the encoded data
435    /// without having to reference to a JSON specification of the ABI.
436    pub fn decode_params(&self, params: &[ParamType], data: &[u8]) -> Result<Vec<Token>, Error> {
437        let mut decoder = ABIDecoder::new();
438        Ok(decoder.decode(params, data)?)
439    }
440
441    fn is_array(&self, ele: &str) -> bool {
442        ele.starts_with('[') && ele.ends_with(']')
443    }
444
445    fn get_enum_discriminant_from_string(&self, ele: &str) -> usize {
446        let mut chars = ele.chars();
447        chars.next(); // Remove "("
448        chars.next_back(); // Remove ")"
449        let v: Vec<_> = chars.as_str().split(',').collect();
450        v[0].parse().unwrap()
451    }
452
453    fn get_enum_value_from_string(&self, ele: &str) -> String {
454        let mut chars = ele.chars();
455        chars.next(); // Remove "("
456        chars.next_back(); // Remove ")"
457        let v: Vec<_> = chars.as_str().split(',').collect();
458        v[1].to_string()
459    }
460
461    fn get_array_length_from_string(&self, ele: &str) -> usize {
462        let mut chars = ele.chars();
463        chars.next();
464        chars.next_back();
465        chars.as_str().split(',').count()
466    }
467
468    /// Builds a string representation of a function selector,
469    /// i.e: <fn_name>(<type_1>, <type_2>, ..., <type_n>)
470    pub fn build_fn_selector(&self, fn_name: &str, params: &[Property]) -> Result<String, Error> {
471        let fn_selector = fn_name.to_owned();
472
473        let mut result: String = format!("{}(", fn_selector);
474
475        for (idx, param) in params.iter().enumerate() {
476            result.push_str(&self.build_fn_selector_params(param));
477            if idx + 1 < params.len() {
478                result.push(',');
479            }
480        }
481
482        result.push(')');
483
484        Ok(result)
485    }
486
487    fn build_fn_selector_params(&self, param: &Property) -> String {
488        let mut result: String = String::new();
489
490        if param.type_field.contains("struct ") || param.type_field.contains("enum ") {
491            // Custom type, need to break down inner fields
492            // Will return `"s(field_1,field_2,...,field_n)"`.
493            result.push_str("s(");
494
495            for (idx, component) in param.components.as_ref().unwrap().iter().enumerate() {
496                let res = self.build_fn_selector_params(component);
497                result.push_str(&res);
498
499                if idx + 1 < param.components.as_ref().unwrap().len() {
500                    result.push(',');
501                }
502            }
503            result.push(')');
504        } else {
505            result.push_str(&param.type_field);
506        }
507        result
508    }
509}
510
511/// Turns a JSON property into ParamType
512pub fn parse_param(param: &Property) -> Result<ParamType, Error> {
513    match ParamType::from_str(&param.type_field) {
514        // Simple case (primitive types, no arrays, including string)
515        Ok(param_type) => Ok(param_type),
516        Err(_) => {
517            match param.type_field.contains("struct") || param.type_field.contains("enum") {
518                true => Ok(parse_custom_type_param(param)?),
519                false => {
520                    match param.type_field.contains('[') && param.type_field.contains(']') {
521                        // Try to parse array (T[M]) or string (str[M])
522                        true => Ok(parse_array_param(param)?),
523                        // Try to parse enum or struct
524                        false => Ok(parse_custom_type_param(param)?),
525                    }
526                }
527            }
528        }
529    }
530}
531
532pub fn parse_array_param(param: &Property) -> Result<ParamType, Error> {
533    // Split "T[n]" string into "T" and "[n]"
534    let split: Vec<&str> = param.type_field.split('[').collect();
535    if split.len() != 2 {
536        return Err(Error::MissingData(format!(
537            "invalid parameter type: {}",
538            param.type_field
539        )));
540    }
541
542    let param_type = ParamType::from_str(split[0]).unwrap();
543
544    // Grab size in between brackets, i.e the `n` in "[n]"
545    let size: usize = split[1][..split[1].len() - 1].parse().unwrap();
546
547    if let ParamType::String(_) = param_type {
548        Ok(ParamType::String(size))
549    } else {
550        Ok(ParamType::Array(Box::new(param_type), size))
551    }
552}
553
554pub fn parse_custom_type_param(param: &Property) -> Result<ParamType, Error> {
555    let mut params: Vec<ParamType> = vec![];
556
557    match param.components.as_ref() {
558        Some(components) => {
559            for component in components {
560                params.push(parse_param(component)?)
561            }
562        }
563        None => {
564            return Err(Error::MissingData(
565                "cannot parse custom type with no components".into(),
566            ))
567        }
568    }
569
570    if param.type_field.contains("struct") {
571        return Ok(ParamType::Struct(params));
572    }
573    if param.type_field.contains("enum") {
574        return Ok(ParamType::Enum(params));
575    }
576    Err(Error::InvalidType(param.type_field.clone()))
577}
578
579#[cfg(test)]
580mod tests {
581    use super::*;
582
583    #[test]
584    fn simple_encode_and_decode_no_selector() {
585        let json_abi = r#"
586        [
587            {
588                "type":"contract",
589                "inputs":[
590                    {
591                        "name":"arg",
592                        "type":"u32"
593                    }
594                ],
595                "name":"takes_u32_returns_bool",
596                "outputs":[
597                    {
598                        "name":"",
599                        "type":"bool"
600                    }
601                ]
602            }
603        ]
604        "#;
605
606        let values: Vec<String> = vec!["10".to_string()];
607
608        let mut abi = ABIParser::new();
609
610        let function_name = "takes_u32_returns_bool";
611
612        let encoded = abi.encode(json_abi, function_name, &values).unwrap();
613        println!("encoded: {:?}\n", encoded);
614
615        let expected_encode = "000000000000000a";
616        assert_eq!(encoded, expected_encode);
617
618        let return_value = [
619            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // false
620        ];
621
622        let decoded_return = abi.decode(json_abi, function_name, &return_value).unwrap();
623
624        let expected_return = vec![Token::Bool(false)];
625
626        assert_eq!(decoded_return, expected_return);
627    }
628
629    #[test]
630    fn simple_encode_and_decode() {
631        let json_abi = r#"
632        [
633            {
634                "type":"contract",
635                "inputs":[
636                    {
637                        "name":"arg",
638                        "type":"u32"
639                    }
640                ],
641                "name":"takes_u32_returns_bool",
642                "outputs":[
643                    {
644                        "name":"",
645                        "type":"bool"
646                    }
647                ]
648            }
649        ]
650        "#;
651
652        let values: Vec<String> = vec!["10".to_string()];
653
654        let mut abi = ABIParser::new();
655
656        let function_name = "takes_u32_returns_bool";
657
658        let encoded = abi
659            .encode_with_function_selector(json_abi, function_name, &values)
660            .unwrap();
661        println!("encoded: {:?}\n", encoded);
662
663        let expected_encode = "000000006355e6ee000000000000000a";
664        assert_eq!(encoded, expected_encode);
665
666        let return_value = [
667            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // false
668        ];
669
670        let decoded_return = abi.decode(json_abi, function_name, &return_value).unwrap();
671
672        let expected_return = vec![Token::Bool(false)];
673
674        assert_eq!(decoded_return, expected_return);
675    }
676
677    #[test]
678    fn b256_and_single_byte_encode_and_decode() {
679        let json_abi = r#"
680        [
681            {
682                "type":"contract",
683                "inputs":[
684                    {
685                        "name":"foo",
686                        "type":"b256"
687                    },
688                    {
689                        "name":"bar",
690                        "type":"byte"
691                    }
692                ],
693                "name":"my_func",
694                "outputs":[
695                    {
696                        "name":"",
697                        "type":"b256"
698                    }
699                ]
700            }
701        ]
702        "#;
703
704        let values: Vec<String> = vec![
705            "d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b".to_string(),
706            "1".to_string(),
707        ];
708
709        let mut abi = ABIParser::new();
710
711        let function_name = "my_func";
712
713        let encoded = abi
714            .encode_with_function_selector(json_abi, function_name, &values)
715            .unwrap();
716        println!("encoded: {:?}\n", encoded);
717
718        let expected_encode = "00000000e64019abd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b0000000000000001";
719        assert_eq!(encoded, expected_encode);
720
721        let return_value =
722            hex::decode("a441b15fe9a3cf56661190a0b93b9dec7d04127288cc87250967cf3b52894d11")
723                .unwrap();
724
725        let decoded_return = abi.decode(json_abi, function_name, &return_value).unwrap();
726
727        let s: [u8; 32] = return_value.as_slice().try_into().unwrap();
728
729        let expected_return = vec![Token::B256(s)];
730
731        assert_eq!(decoded_return, expected_return);
732    }
733
734    #[test]
735    fn array_encode_and_decode() {
736        let json_abi = r#"
737        [
738            {
739                "type":"contract",
740                "inputs":[
741                    {
742                        "name":"arg",
743                        "type":"u16[3]"
744                    }
745                ],
746                "name":"takes_array",
747                "outputs":[
748                    {
749                        "name":"",
750                        "type":"u16[2]"
751                    }
752                ]
753            }
754        ]
755        "#;
756
757        let values: Vec<String> = vec!["[1,2,3]".to_string()];
758
759        let mut abi = ABIParser::new();
760
761        let function_name = "takes_array";
762
763        let encoded = abi
764            .encode_with_function_selector(json_abi, function_name, &values)
765            .unwrap();
766        println!("encoded: {:?}\n", encoded);
767
768        let expected_encode = "00000000f0b87864000000000000000100000000000000020000000000000003";
769        assert_eq!(encoded, expected_encode);
770
771        let return_value = [
772            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // 0
773            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // 1
774        ];
775
776        let decoded_return = abi.decode(json_abi, function_name, &return_value).unwrap();
777
778        let expected_return = vec![Token::Array(vec![Token::U16(0), Token::U16(1)])];
779
780        assert_eq!(decoded_return, expected_return);
781    }
782
783    #[test]
784    fn tokenize_array() {
785        let abi = ABIParser::new();
786
787        let value = "[[1,2],[3],4]";
788        let param = ParamType::U16;
789        let tokens = abi.tokenize_array(value, &param).unwrap();
790
791        let expected_tokens = Token::Array(vec![
792            Token::Array(vec![Token::U16(1), Token::U16(2)]), // First element, a sub-array with 2 elements
793            Token::Array(vec![Token::U16(3)]), // Second element, a sub-array with 1 element
794            Token::U16(4),                     // Third element
795        ]);
796
797        assert_eq!(tokens, expected_tokens);
798
799        let value = "[1,[2],[3],[4,5]]";
800        let param = ParamType::U16;
801        let tokens = abi.tokenize_array(value, &param).unwrap();
802
803        let expected_tokens = Token::Array(vec![
804            Token::U16(1),
805            Token::Array(vec![Token::U16(2)]),
806            Token::Array(vec![Token::U16(3)]),
807            Token::Array(vec![Token::U16(4), Token::U16(5)]),
808        ]);
809
810        assert_eq!(tokens, expected_tokens);
811
812        let value = "[1,2,3,4,5]";
813        let param = ParamType::U16;
814        let tokens = abi.tokenize_array(value, &param).unwrap();
815
816        let expected_tokens = Token::Array(vec![
817            Token::U16(1),
818            Token::U16(2),
819            Token::U16(3),
820            Token::U16(4),
821            Token::U16(5),
822        ]);
823
824        assert_eq!(tokens, expected_tokens);
825
826        let value = "[[1,2,3,[4,5]]]";
827        let param = ParamType::U16;
828        let tokens = abi.tokenize_array(value, &param).unwrap();
829
830        let expected_tokens = Token::Array(vec![Token::Array(vec![
831            Token::U16(1),
832            Token::U16(2),
833            Token::U16(3),
834            Token::Array(vec![Token::U16(4), Token::U16(5)]),
835        ])]);
836
837        assert_eq!(tokens, expected_tokens);
838    }
839
840    #[test]
841    fn nested_array_encode_and_decode() {
842        let json_abi = r#"
843        [
844            {
845                "type":"contract",
846                "inputs":[
847                    {
848                        "name":"arg",
849                        "type":"u16[3]"
850                    }
851                ],
852                "name":"takes_nested_array",
853                "outputs":[
854                    {
855                        "name":"",
856                        "type":"u16[2]"
857                    }
858                ]
859            }
860        ]
861        "#;
862
863        let values: Vec<String> = vec!["[[1,2],[3],[4]]".to_string()];
864
865        let mut abi = ABIParser::new();
866
867        let function_name = "takes_nested_array";
868
869        let encoded = abi
870            .encode_with_function_selector(json_abi, function_name, &values)
871            .unwrap();
872        println!("encoded: {:?}\n", encoded);
873
874        let expected_encode =
875            "00000000e5d521030000000000000001000000000000000200000000000000030000000000000004";
876        assert_eq!(encoded, expected_encode);
877
878        let return_value = [
879            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // 0
880            0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, // 1
881        ];
882
883        let decoded_return = abi.decode(json_abi, function_name, &return_value).unwrap();
884
885        let expected_return = vec![Token::Array(vec![Token::U16(0), Token::U16(1)])];
886
887        assert_eq!(decoded_return, expected_return);
888    }
889
890    #[test]
891    fn string_encode_and_decode() {
892        let json_abi = r#"
893        [
894            {
895                "type":"contract",
896                "inputs":[
897                    {
898                        "name":"foo",
899                        "type":"str[23]"
900                    }
901                ],
902                "name":"takes_string",
903                "outputs":[
904                    {
905                        "name":"",
906                        "type":"str[2]"
907                    }
908                ]
909            }
910        ]
911        "#;
912
913        let values: Vec<String> = vec!["This is a full sentence".to_string()];
914
915        let mut abi = ABIParser::new();
916
917        let function_name = "takes_string";
918
919        let encoded = abi
920            .encode_with_function_selector(json_abi, function_name, &values)
921            .unwrap();
922        println!("encoded: {:?}\n", encoded);
923
924        let expected_encode = "00000000d56e76515468697320697320612066756c6c2073656e74656e636500";
925        assert_eq!(encoded, expected_encode);
926
927        let return_value = [
928            0x4f, 0x4b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // "OK" encoded in utf8
929        ];
930
931        let decoded_return = abi.decode(json_abi, function_name, &return_value).unwrap();
932
933        let expected_return = vec![Token::String("OK".into())];
934
935        assert_eq!(decoded_return, expected_return);
936    }
937
938    #[test]
939    fn struct_encode_and_decode() {
940        let json_abi = r#"
941        [
942            {
943                "type":"contract",
944                "inputs":[
945                    {
946                        "name":"my_struct",
947                        "type":"struct MyStruct",
948                        "components": [
949                            {
950                                "name": "foo",
951                                "type": "u8"
952                            },
953                            {
954                                "name": "bar",
955                                "type": "bool"
956                            }
957                        ]
958                    }
959                ],
960                "name":"takes_struct",
961                "outputs":[]
962            }
963        ]
964        "#;
965
966        let values: Vec<String> = vec!["(42, true)".to_string()];
967
968        let mut abi = ABIParser::new();
969
970        let function_name = "takes_struct";
971
972        let encoded = abi
973            .encode_with_function_selector(json_abi, function_name, &values)
974            .unwrap();
975        println!("encoded: {:?}\n", encoded);
976
977        let expected_encode = "00000000cb0b2f05000000000000002a0000000000000001";
978        assert_eq!(encoded, expected_encode);
979    }
980
981    #[test]
982    fn struct_and_primitive_encode_and_decode() {
983        let json_abi = r#"
984        [
985            {
986                "type":"contract",
987                "inputs":[
988                    {
989                        "name":"my_struct",
990                        "type":"struct MyStruct",
991                        "components": [
992                            {
993                                "name": "foo",
994                                "type": "u8"
995                            },
996                            {
997                                "name": "bar",
998                                "type": "bool"
999                            }
1000                        ]
1001                    },
1002                    {
1003                        "name":"foo",
1004                        "type":"u32"
1005                    }
1006                ],
1007                "name":"takes_struct_and_primitive",
1008                "outputs":[]
1009            }
1010        ]
1011        "#;
1012
1013        let values: Vec<String> = vec!["(42, true)".to_string(), "10".to_string()];
1014
1015        let mut abi = ABIParser::new();
1016
1017        let function_name = "takes_struct_and_primitive";
1018
1019        let encoded = abi
1020            .encode_with_function_selector(json_abi, function_name, &values)
1021            .unwrap();
1022        println!("encoded: {:?}\n", encoded);
1023
1024        let expected_encode = "000000005c445838000000000000002a0000000000000001000000000000000a";
1025        assert_eq!(encoded, expected_encode);
1026    }
1027
1028    #[test]
1029    fn nested_struct_encode_and_decode() {
1030        let json_abi = r#"
1031        [
1032            {
1033                "type":"contract",
1034                "inputs":[
1035                    {
1036                        "name":"top_value",
1037                        "type":"struct MyNestedStruct",
1038                        "components": [
1039                            {
1040                                "name": "x",
1041                                "type": "u16"
1042                            },
1043                            {
1044                                "name": "inner",
1045                                "type": "struct Y",
1046                                "components": [
1047                                    {
1048                                        "name":"a",
1049                                        "type": "bool"
1050                                    },
1051                                    {
1052                                        "name":"b",
1053                                        "type": "u8[2]"
1054                                    }
1055                                ]
1056                            }
1057                        ]
1058                    }
1059                ],
1060                "name":"takes_nested_struct",
1061                "outputs":[]
1062            }
1063        ]
1064        "#;
1065
1066        let values: Vec<String> = vec!["(10, (true, [1,2]))".to_string()];
1067
1068        let mut abi = ABIParser::new();
1069
1070        let function_name = "takes_nested_struct";
1071
1072        let encoded = abi
1073            .encode_with_function_selector(json_abi, function_name, &values)
1074            .unwrap();
1075        println!("encoded: {:?}\n", encoded);
1076
1077        let expected_encode =
1078            "00000000ff25eb48000000000000000a000000000000000100000000000000010000000000000002";
1079        assert_eq!(encoded, expected_encode);
1080
1081        let json_abi = r#"
1082        [
1083            {
1084                "type":"contract",
1085                "inputs":[
1086                    {
1087                        "name":"top_value",
1088                        "type":"struct MyNestedStruct",
1089                        "components": [
1090                            {
1091                                "name": "inner",
1092                                "type": "struct X",
1093                                "components": [
1094                                    {
1095                                        "name":"a",
1096                                        "type": "bool"
1097                                    },
1098                                    {
1099                                        "name":"b",
1100                                        "type": "u8[2]"
1101                                    }
1102                                ]
1103                            },
1104                            {
1105                                "name": "y",
1106                                "type": "u16"
1107                            }
1108                        ]
1109                    }
1110                ],
1111                "name":"takes_nested_struct",
1112                "outputs":[]
1113            }
1114        ]
1115        "#;
1116
1117        let values: Vec<String> = vec!["((true, [1,2]), 10)".to_string()];
1118
1119        let encoded = abi
1120            .encode_with_function_selector(json_abi, function_name, &values)
1121            .unwrap();
1122        println!("encoded: {:?}\n", encoded);
1123
1124        let expected_encode =
1125            "000000007728cb9e000000000000000100000000000000010000000000000002000000000000000a";
1126        assert_eq!(encoded, expected_encode);
1127    }
1128
1129    #[test]
1130    fn enum_encode_and_decode() {
1131        let json_abi = r#"
1132        [
1133            {
1134                "type":"contract",
1135                "inputs":[
1136                    {
1137                        "name":"my_enum",
1138                        "type":"enum MyEnum",
1139                        "components": [
1140                            {
1141                                "name": "x",
1142                                "type": "u32"
1143                            },
1144                            {
1145                                "name": "y",
1146                                "type": "bool"
1147                            }
1148                        ]
1149                    }
1150                ],
1151                "name":"takes_enum",
1152                "outputs":[]
1153            }
1154        ]
1155        "#;
1156
1157        let values: Vec<String> = vec!["(0, 42)".to_string()];
1158
1159        let mut abi = ABIParser::new();
1160
1161        let function_name = "takes_enum";
1162
1163        let encoded = abi
1164            .encode_with_function_selector(json_abi, function_name, &values)
1165            .unwrap();
1166        println!("encoded: {:?}\n", encoded);
1167
1168        let expected_encode = "00000000082e0dfa0000000000000000000000000000002a";
1169        assert_eq!(encoded, expected_encode);
1170    }
1171
1172    #[test]
1173    fn fn_selector_single_primitive() {
1174        let abi = ABIParser::new();
1175        let p = Property {
1176            name: "foo".into(),
1177            type_field: "u64".into(),
1178            components: None,
1179        };
1180        let params = vec![p];
1181        let selector = abi.build_fn_selector("my_func", &params).unwrap();
1182
1183        assert_eq!(selector, "my_func(u64)");
1184    }
1185
1186    #[test]
1187    fn fn_selector_multiple_primitives() {
1188        let abi = ABIParser::new();
1189        let p1 = Property {
1190            name: "foo".into(),
1191            type_field: "u64".into(),
1192            components: None,
1193        };
1194        let p2 = Property {
1195            name: "bar".into(),
1196            type_field: "bool".into(),
1197            components: None,
1198        };
1199        let params = vec![p1, p2];
1200        let selector = abi.build_fn_selector("my_func", &params).unwrap();
1201
1202        assert_eq!(selector, "my_func(u64,bool)");
1203    }
1204
1205    #[test]
1206    fn fn_selector_custom_type() {
1207        let abi = ABIParser::new();
1208
1209        let inner_foo = Property {
1210            name: "foo".into(),
1211            type_field: "bool".into(),
1212            components: None,
1213        };
1214
1215        let inner_bar = Property {
1216            name: "bar".into(),
1217            type_field: "u64".into(),
1218            components: None,
1219        };
1220
1221        let p = Property {
1222            name: "my_struct".into(),
1223            type_field: "struct MyStruct".into(),
1224            components: Some(vec![inner_foo, inner_bar]),
1225        };
1226
1227        let params = vec![p];
1228        let selector = abi.build_fn_selector("my_func", &params).unwrap();
1229
1230        assert_eq!(selector, "my_func(s(bool,u64))");
1231    }
1232
1233    #[test]
1234    fn fn_selector_nested_custom_type() {
1235        let abi = ABIParser::new();
1236
1237        let inner_foo = Property {
1238            name: "foo".into(),
1239            type_field: "bool".into(),
1240            components: None,
1241        };
1242
1243        let inner_a = Property {
1244            name: "a".into(),
1245            type_field: "u64".into(),
1246            components: None,
1247        };
1248
1249        let inner_b = Property {
1250            name: "b".into(),
1251            type_field: "u32".into(),
1252            components: None,
1253        };
1254
1255        let inner_bar = Property {
1256            name: "bar".into(),
1257            type_field: "struct InnerStruct".into(),
1258            components: Some(vec![inner_a, inner_b]),
1259        };
1260
1261        let p = Property {
1262            name: "my_struct".into(),
1263            type_field: "struct MyStruct".into(),
1264            components: Some(vec![inner_foo, inner_bar]),
1265        };
1266
1267        let params = vec![p];
1268        println!("params: {:?}\n", params);
1269        let selector = abi.build_fn_selector("my_func", &params).unwrap();
1270
1271        assert_eq!(selector, "my_func(s(bool,s(u64,u32)))");
1272    }
1273
1274    #[test]
1275    fn compiler_generated_abi_test() {
1276        let json_abi = r#"
1277        [
1278            {
1279                "inputs": [
1280                    {
1281                        "components": null,
1282                        "name": "gas_",
1283                        "type": "u64"
1284                    },
1285                    {
1286                        "components": null,
1287                        "name": "amount_",
1288                        "type": "u64"
1289                    },
1290                    {
1291                        "components": null,
1292                        "name": "color_",
1293                        "type": "b256"
1294                    },
1295                    {
1296                        "components": null,
1297                        "name": "value",
1298                        "type": "u64"
1299                    }
1300                ],
1301                "name": "foo",
1302                "outputs": [
1303                    {
1304                        "components": null,
1305                        "name": "",
1306                        "type": "u64"
1307                    }
1308                ],
1309                "type": "function"
1310            },
1311            {
1312                "inputs": [
1313                    {
1314                        "components": null,
1315                        "name": "gas_",
1316                        "type": "u64"
1317                    },
1318                    {
1319                        "components": null,
1320                        "name": "amount_",
1321                        "type": "u64"
1322                    },
1323                    {
1324                        "components": null,
1325                        "name": "color_",
1326                        "type": "b256"
1327                    },
1328                    {
1329                        "components": [
1330                            {
1331                                "components": null,
1332                                "name": "a",
1333                                "type": "bool"
1334                            },
1335                            {
1336                                "components": null,
1337                                "name": "b",
1338                                "type": "u64"
1339                            }
1340                        ],
1341                        "name": "value",
1342                        "type": "struct TestStruct"
1343                    }
1344                ],
1345                "name": "boo",
1346                "outputs": [
1347                    {
1348                        "components": [
1349                            {
1350                                "components": null,
1351                                "name": "a",
1352                                "type": "bool"
1353                            },
1354                            {
1355                                "components": null,
1356                                "name": "b",
1357                                "type": "u64"
1358                            }
1359                        ],
1360                        "name": "",
1361                        "type": "struct TestStruct"
1362                    }
1363                ],
1364                "type": "function"
1365            }
1366        ]
1367                "#;
1368
1369        let gas = "1000000".to_string();
1370        let coins = "0".to_string();
1371        let color = "0000000000000000000000000000000000000000000000000000000000000000".to_string();
1372        let s = "(true, 42)".to_string();
1373
1374        let values: Vec<String> = vec![gas, coins, color, s];
1375
1376        let mut abi = ABIParser::new();
1377
1378        let function_name = "boo";
1379
1380        let encoded = abi
1381            .encode_with_function_selector(json_abi, function_name, &values)
1382            .unwrap();
1383        println!("encoded: {:?}\n", encoded);
1384
1385        let expected_encode = "0000000087f27a3900000000000f4240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000002a";
1386        assert_eq!(encoded, expected_encode);
1387    }
1388}