fuels_core/codec/
abi_encoder.rs

1mod bounded_encoder;
2
3use std::default::Default;
4
5use crate::{
6    codec::abi_encoder::bounded_encoder::BoundedEncoder,
7    types::{errors::Result, Token},
8};
9
10#[derive(Debug, Clone, Copy)]
11pub struct EncoderConfig {
12    /// Entering a struct, array, tuple, enum or vector increases the depth. Encoding will fail if
13    /// the current depth becomes greater than `max_depth` configured here.
14    pub max_depth: usize,
15    /// Every encoded argument will increase the token count. Encoding will fail if the current
16    /// token count becomes greater than `max_tokens` configured here.
17    pub max_tokens: usize,
18}
19
20// ANCHOR: default_encoder_config
21impl Default for EncoderConfig {
22    fn default() -> Self {
23        Self {
24            max_depth: 45,
25            max_tokens: 10_000,
26        }
27    }
28}
29// ANCHOR_END: default_encoder_config
30
31#[derive(Default, Clone, Debug)]
32pub struct ABIEncoder {
33    pub config: EncoderConfig,
34}
35
36impl ABIEncoder {
37    pub fn new(config: EncoderConfig) -> Self {
38        Self { config }
39    }
40
41    /// Encodes `Token`s following the ABI specs defined
42    /// [here](https://github.com/FuelLabs/fuel-specs/blob/master/specs/protocol/abi.md)
43    pub fn encode(&self, tokens: &[Token]) -> Result<Vec<u8>> {
44        BoundedEncoder::new(self.config).encode(tokens)
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use std::slice;
51
52    use super::*;
53    use crate::{
54        to_named,
55        types::{
56            errors::Error,
57            param_types::{EnumVariants, ParamType},
58            StaticStringToken, U256,
59        },
60    };
61
62    #[test]
63    fn encode_multiple_uint() -> Result<()> {
64        let tokens = [
65            Token::U8(u8::MAX),
66            Token::U16(u16::MAX),
67            Token::U32(u32::MAX),
68            Token::U64(u64::MAX),
69            Token::U128(u128::MAX),
70            Token::U256(U256::MAX),
71        ];
72
73        let result = ABIEncoder::default().encode(&tokens)?;
74
75        let expected = [
76            255, // u8
77            255, 255, // u16
78            255, 255, 255, 255, // u32
79            255, 255, 255, 255, 255, 255, 255, 255, // u64
80            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
81            255, // u128
82            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
83            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // u256
84        ];
85
86        assert_eq!(result, expected);
87
88        Ok(())
89    }
90
91    #[test]
92    fn encode_bool() -> Result<()> {
93        let token = Token::Bool(true);
94
95        let result = ABIEncoder::default().encode(&[token])?;
96
97        let expected = [1];
98
99        assert_eq!(result, expected);
100
101        Ok(())
102    }
103
104    #[test]
105    fn encode_b256() -> Result<()> {
106        let data = [
107            213, 87, 156, 70, 223, 204, 127, 24, 32, 112, 19, 230, 91, 68, 228, 203, 78, 44, 34,
108            152, 244, 172, 69, 123, 168, 248, 39, 67, 243, 30, 147, 11,
109        ];
110        let token = Token::B256(data);
111
112        let result = ABIEncoder::default().encode(&[token])?;
113
114        assert_eq!(result, data);
115
116        Ok(())
117    }
118
119    #[test]
120    fn encode_bytes() -> Result<()> {
121        let token = Token::Bytes([255, 0, 1, 2, 3, 4, 5].to_vec());
122
123        let result = ABIEncoder::default().encode(&[token])?;
124
125        let expected = [
126            0, 0, 0, 0, 0, 0, 0, 7, // len
127            255, 0, 1, 2, 3, 4, 5, // data
128        ];
129
130        assert_eq!(result, expected);
131
132        Ok(())
133    }
134
135    #[test]
136    fn encode_string() -> Result<()> {
137        let token = Token::String("This is a full sentence".to_string());
138
139        let result = ABIEncoder::default().encode(&[token])?;
140
141        let expected = [
142            0, 0, 0, 0, 0, 0, 0, 23, // len
143            84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 117, 108, 108, 32, 115, 101, 110,
144            116, 101, 110, 99, 101, //This is a full sentence
145        ];
146
147        assert_eq!(result, expected);
148
149        Ok(())
150    }
151
152    #[test]
153    fn encode_raw_slice() -> Result<()> {
154        let token = Token::RawSlice([255, 0, 1, 2, 3, 4, 5].to_vec());
155
156        let result = ABIEncoder::default().encode(&[token])?;
157
158        let expected = [
159            0, 0, 0, 0, 0, 0, 0, 7, // len
160            255, 0, 1, 2, 3, 4, 5, // data
161        ];
162
163        assert_eq!(result, expected);
164
165        Ok(())
166    }
167
168    #[test]
169    fn encode_string_array() -> Result<()> {
170        let token = Token::StringArray(StaticStringToken::new(
171            "This is a full sentence".into(),
172            Some(23),
173        ));
174
175        let result = ABIEncoder::default().encode(&[token])?;
176
177        let expected = [
178            84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 117, 108, 108, 32, 115, 101, 110,
179            116, 101, 110, 99, 101, //This is a full sentence
180        ];
181
182        assert_eq!(result, expected);
183
184        Ok(())
185    }
186
187    #[test]
188    fn encode_string_slice() -> Result<()> {
189        let token = Token::StringSlice(StaticStringToken::new(
190            "This is a full sentence".into(),
191            None,
192        ));
193
194        let result = ABIEncoder::default().encode(&[token])?;
195
196        let expected = [
197            0, 0, 0, 0, 0, 0, 0, 23, // len
198            84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 117, 108, 108, 32, 115, 101, 110,
199            116, 101, 110, 99, 101, //This is a full sentence
200        ];
201
202        assert_eq!(result, expected);
203
204        Ok(())
205    }
206
207    #[test]
208    fn encode_tuple() -> Result<()> {
209        let token = Token::Tuple(vec![Token::U32(255), Token::Bool(true)]);
210
211        let result = ABIEncoder::default().encode(&[token])?;
212
213        let expected = [
214            0, 0, 0, 255, //u32
215            1,   //bool
216        ];
217
218        assert_eq!(result, expected);
219
220        Ok(())
221    }
222
223    #[test]
224    fn encode_array() -> Result<()> {
225        let token = Token::Tuple(vec![Token::U32(255), Token::U32(128)]);
226
227        let result = ABIEncoder::default().encode(&[token])?;
228
229        let expected = [
230            0, 0, 0, 255, //u32
231            0, 0, 0, 128, //u32
232        ];
233
234        assert_eq!(result, expected);
235
236        Ok(())
237    }
238
239    #[test]
240    fn encode_enum_with_deeply_nested_types() -> Result<()> {
241        /*
242        enum DeeperEnum {
243            v1: bool,
244            v2: str[10]
245        }
246         */
247        let types = to_named(&[ParamType::Bool, ParamType::StringArray(10)]);
248        let deeper_enum_variants = EnumVariants::new(types)?;
249        let deeper_enum_token =
250            Token::StringArray(StaticStringToken::new("0123456789".into(), Some(10)));
251
252        /*
253        struct StructA {
254            some_enum: DeeperEnum
255            some_number: u32
256        }
257         */
258
259        let fields = to_named(&[
260            ParamType::Enum {
261                name: "".to_string(),
262                enum_variants: deeper_enum_variants.clone(),
263                generics: vec![],
264            },
265            ParamType::Bool,
266        ]);
267        let struct_a_type = ParamType::Struct {
268            name: "".to_string(),
269            fields,
270            generics: vec![],
271        };
272
273        let struct_a_token = Token::Struct(vec![
274            Token::Enum(Box::new((1, deeper_enum_token, deeper_enum_variants))),
275            Token::U32(11332),
276        ]);
277
278        /*
279         enum TopLevelEnum {
280            v1: StructA,
281            v2: bool,
282            v3: u64
283        }
284        */
285
286        let types = to_named(&[struct_a_type, ParamType::Bool, ParamType::U64]);
287        let top_level_enum_variants = EnumVariants::new(types)?;
288        let top_level_enum_token =
289            Token::Enum(Box::new((0, struct_a_token, top_level_enum_variants)));
290
291        let result = ABIEncoder::default().encode(slice::from_ref(&top_level_enum_token))?;
292
293        let expected = [
294            0, 0, 0, 0, 0, 0, 0, 0, // TopLevelEnum::v1 discriminant
295            0, 0, 0, 0, 0, 0, 0, 1, // DeeperEnum::v2 discriminant
296            48, 49, 50, 51, 52, 53, 54, 55, 56, 57, // str[10]
297            0, 0, 44, 68, // StructA.some_number
298        ];
299
300        assert_eq!(result, expected);
301
302        Ok(())
303    }
304
305    #[test]
306    fn encode_nested_structs() -> Result<()> {
307        let token = Token::Struct(vec![
308            Token::U16(10),
309            Token::Struct(vec![
310                Token::Bool(true),
311                Token::Array(vec![Token::U8(1), Token::U8(2)]),
312            ]),
313        ]);
314
315        let result = ABIEncoder::default().encode(&[token])?;
316
317        let expected = [
318            0, 10, // u16
319            1,  // bool
320            1, 2, // [u8, u8]
321        ];
322
323        assert_eq!(result, expected);
324
325        Ok(())
326    }
327
328    #[test]
329    fn encode_comprehensive() -> Result<()> {
330        let foo = Token::Struct(vec![
331            Token::U16(10),
332            Token::Struct(vec![
333                Token::Bool(true),
334                Token::Array(vec![Token::U8(1), Token::U8(2)]),
335            ]),
336        ]);
337        let arr_u8 = Token::Array(vec![Token::U8(1), Token::U8(2)]);
338        let b256 = Token::B256([255; 32]);
339        let str_arr = Token::StringArray(StaticStringToken::new(
340            "This is a full sentence".into(),
341            Some(23),
342        ));
343        let tokens = vec![foo, arr_u8, b256, str_arr];
344
345        let result = ABIEncoder::default().encode(&tokens)?;
346
347        let expected = [
348            0, 10, // foo.x == 10u16
349            1,  // foo.y.a == true
350            1,  // foo.y.b.0 == 1u8
351            2,  // foo.y.b.1 == 2u8
352            1,  // u8[2].0 == 1u8
353            2,  // u8[2].0 == 2u8
354            255, 255, 255, 255, 255, 255, 255, 255, // b256
355            255, 255, 255, 255, 255, 255, 255, 255, // b256
356            255, 255, 255, 255, 255, 255, 255, 255, // b256
357            255, 255, 255, 255, 255, 255, 255, 255, // b256
358            84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 102, 117, 108, 108, 32, 115, 101, 110,
359            116, 101, 110, 99, 101, // str[23]
360        ];
361
362        assert_eq!(result, expected);
363
364        Ok(())
365    }
366
367    #[test]
368    fn enums_with_only_unit_variants_are_encoded_in_one_word() -> Result<()> {
369        let expected = [0, 0, 0, 0, 0, 0, 0, 1];
370
371        let types = to_named(&[ParamType::Unit, ParamType::Unit]);
372        let enum_selector = Box::new((1, Token::Unit, EnumVariants::new(types)?));
373
374        let actual = ABIEncoder::default().encode(&[Token::Enum(enum_selector)])?;
375
376        assert_eq!(actual, expected);
377
378        Ok(())
379    }
380
381    #[test]
382    fn vec_in_enum() -> Result<()> {
383        // arrange
384        let types = to_named(&[ParamType::B256, ParamType::Vector(Box::new(ParamType::U64))]);
385        let variants = EnumVariants::new(types)?;
386        let selector = (1, Token::Vector(vec![Token::U64(5)]), variants);
387        let token = Token::Enum(Box::new(selector));
388
389        // act
390        let result = ABIEncoder::default().encode(&[token])?;
391
392        // assert
393        let expected = [
394            0, 0, 0, 0, 0, 0, 0, 1, // enum dicsriminant
395            0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, // vec[len, u64]
396        ];
397
398        assert_eq!(result, expected);
399
400        Ok(())
401    }
402
403    #[test]
404    fn enum_in_vec() -> Result<()> {
405        // arrange
406        let types = to_named(&[ParamType::B256, ParamType::U8]);
407        let variants = EnumVariants::new(types)?;
408        let selector = (1, Token::U8(8), variants);
409        let enum_token = Token::Enum(Box::new(selector));
410
411        let vec_token = Token::Vector(vec![enum_token]);
412
413        // act
414        let result = ABIEncoder::default().encode(&[vec_token])?;
415
416        // assert
417        let expected = [
418            0, 0, 0, 0, 0, 0, 0, 1, // vec len
419            0, 0, 0, 0, 0, 0, 0, 1, 8, // enum discriminant and u8 value
420        ];
421
422        assert_eq!(result, expected);
423
424        Ok(())
425    }
426
427    #[test]
428    fn vec_in_struct() -> Result<()> {
429        // arrange
430        let token = Token::Struct(vec![Token::Vector(vec![Token::U64(5)]), Token::U8(9)]);
431
432        // act
433        let result = ABIEncoder::default().encode(&[token])?;
434
435        // assert
436        let expected = [
437            0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 5, // vec[len, u64]
438            9, // u8
439        ];
440
441        assert_eq!(result, expected);
442
443        Ok(())
444    }
445
446    #[test]
447    fn vec_in_vec() -> Result<()> {
448        // arrange
449        let token = Token::Vector(vec![Token::Vector(vec![Token::U8(5), Token::U8(6)])]);
450
451        // act
452        let result = ABIEncoder::default().encode(&[token])?;
453
454        // assert
455        let expected = [
456            0, 0, 0, 0, 0, 0, 0, 1, // vec1 len
457            0, 0, 0, 0, 0, 0, 0, 2, 5, 6, // vec2 [len, u8, u8]
458        ];
459
460        assert_eq!(result, expected);
461
462        Ok(())
463    }
464
465    #[test]
466    fn max_depth_surpassed() {
467        const MAX_DEPTH: usize = 2;
468        let config = EncoderConfig {
469            max_depth: MAX_DEPTH,
470            ..Default::default()
471        };
472        let msg = "depth limit `2` reached while encoding. Try increasing it".to_string();
473
474        [nested_struct, nested_enum, nested_tuple, nested_array]
475            .iter()
476            .map(|fun| fun(MAX_DEPTH + 1))
477            .for_each(|token| {
478                assert_encoding_failed(config, token, &msg);
479            });
480    }
481
482    fn assert_encoding_failed(config: EncoderConfig, token: Token, msg: &str) {
483        let encoder = ABIEncoder::new(config);
484
485        let err = encoder.encode(&[token]);
486
487        let Err(Error::Codec(actual_msg)) = err else {
488            panic!("expected a Codec error. Got: `{err:?}`");
489        };
490        assert_eq!(actual_msg, msg);
491    }
492
493    fn nested_struct(depth: usize) -> Token {
494        let fields = if depth == 1 {
495            vec![Token::U8(255), Token::String("bloopblip".to_string())]
496        } else {
497            vec![nested_struct(depth - 1)]
498        };
499
500        Token::Struct(fields)
501    }
502
503    fn nested_enum(depth: usize) -> Token {
504        if depth == 0 {
505            return Token::U8(255);
506        }
507
508        let inner_enum = nested_enum(depth - 1);
509
510        // Create a basic EnumSelector for the current level (the `EnumVariants` is not
511        // actually accurate but it's not used for encoding)
512        let selector = (
513            0u64,
514            inner_enum,
515            EnumVariants::new(to_named(&[ParamType::U64])).unwrap(),
516        );
517
518        Token::Enum(Box::new(selector))
519    }
520
521    fn nested_array(depth: usize) -> Token {
522        if depth == 1 {
523            Token::Array(vec![Token::U8(255)])
524        } else {
525            Token::Array(vec![nested_array(depth - 1)])
526        }
527    }
528
529    fn nested_tuple(depth: usize) -> Token {
530        let fields = if depth == 1 {
531            vec![Token::U8(255), Token::String("bloopblip".to_string())]
532        } else {
533            vec![nested_tuple(depth - 1)]
534        };
535
536        Token::Tuple(fields)
537    }
538}