Skip to main content

aztec_core/abi/
mod.rs

1mod buffer;
2mod checkers;
3mod decoder;
4mod encoder;
5mod selectors;
6mod storage_layout;
7mod types;
8
9// Re-export everything for the public API
10pub use buffer::{buffer_as_fields, buffer_from_fields};
11pub use checkers::{
12    abi_checker, abi_type_size, count_arguments_size, is_address_struct, is_aztec_address_struct,
13    is_bounded_vec_struct, is_eth_address_struct, is_function_selector_struct, is_option_struct,
14    is_public_keys_struct, is_wrapped_field_struct,
15};
16pub use decoder::{decode_from_abi, AbiDecoded};
17pub use encoder::{encode_arguments, encode_value};
18pub use selectors::{AuthorizationSelector, EventSelector, FunctionSelector, NoteSelector};
19pub use storage_layout::{ContractStorageLayout, FieldLayout};
20pub use types::{
21    abi_type_signature, AbiParameter, AbiType, AbiValue, ContractArtifact, FunctionArtifact,
22    FunctionType,
23};
24
25#[cfg(test)]
26#[allow(clippy::expect_used, clippy::panic)]
27mod tests {
28    use super::*;
29    use std::collections::BTreeMap;
30
31    use crate::types::Fr;
32
33    const MINIMAL_ARTIFACT: &str = r#"
34    {
35      "name": "TestContract",
36      "functions": [
37        {
38          "name": "increment",
39          "function_type": "public",
40          "is_initializer": false,
41          "is_static": false,
42          "parameters": [
43            { "name": "value", "type": { "kind": "field" } }
44          ],
45          "return_types": []
46        }
47      ]
48    }
49    "#;
50
51    const MULTI_FUNCTION_ARTIFACT: &str = r#"
52    {
53      "name": "TokenContract",
54      "functions": [
55        {
56          "name": "constructor",
57          "function_type": "private",
58          "is_initializer": true,
59          "is_static": false,
60          "parameters": [
61            { "name": "admin", "type": { "kind": "field" } },
62            { "name": "name", "type": { "kind": "string", "length": 31 } }
63          ],
64          "return_types": []
65        },
66        {
67          "name": "transfer",
68          "function_type": "private",
69          "is_initializer": false,
70          "is_static": false,
71          "parameters": [
72            { "name": "from", "type": { "kind": "field" } },
73            { "name": "to", "type": { "kind": "field" } },
74            { "name": "amount", "type": { "kind": "integer", "sign": "unsigned", "width": 64 } }
75          ],
76          "return_types": []
77        },
78        {
79          "name": "balance_of",
80          "function_type": "utility",
81          "is_initializer": false,
82          "is_static": true,
83          "parameters": [
84            { "name": "owner", "type": { "kind": "field" } }
85          ],
86          "return_types": [
87            { "kind": "integer", "sign": "unsigned", "width": 64 }
88          ]
89        },
90        {
91          "name": "total_supply",
92          "function_type": "public",
93          "is_initializer": false,
94          "is_static": true,
95          "parameters": [],
96          "return_types": [
97            { "kind": "integer", "sign": "unsigned", "width": 64 }
98          ]
99        }
100      ]
101    }
102    "#;
103
104    #[test]
105    fn function_type_roundtrip() {
106        for (ft, expected) in [
107            (FunctionType::Private, "\"private\""),
108            (FunctionType::Public, "\"public\""),
109            (FunctionType::Utility, "\"utility\""),
110        ] {
111            let json = serde_json::to_string(&ft).expect("serialize FunctionType");
112            assert_eq!(json, expected);
113            let decoded: FunctionType =
114                serde_json::from_str(&json).expect("deserialize FunctionType");
115            assert_eq!(decoded, ft);
116        }
117    }
118
119    #[test]
120    fn function_selector_hex_roundtrip() {
121        let selector = FunctionSelector::from_hex("0xaabbccdd").expect("valid hex");
122        assert_eq!(selector.0, [0xaa, 0xbb, 0xcc, 0xdd]);
123        assert_eq!(selector.to_string(), "0xaabbccdd");
124
125        let json = serde_json::to_string(&selector).expect("serialize selector");
126        let decoded: FunctionSelector = serde_json::from_str(&json).expect("deserialize selector");
127        assert_eq!(decoded, selector);
128    }
129
130    #[test]
131    fn authorization_selector_hex_roundtrip() {
132        let selector = AuthorizationSelector::from_hex("0x01020304").expect("valid hex");
133        assert_eq!(selector.0, [0x01, 0x02, 0x03, 0x04]);
134        assert_eq!(selector.to_string(), "0x01020304");
135
136        let json = serde_json::to_string(&selector).expect("serialize selector");
137        let decoded: AuthorizationSelector =
138            serde_json::from_str(&json).expect("deserialize selector");
139        assert_eq!(decoded, selector);
140    }
141
142    #[test]
143    fn function_selector_rejects_too_long() {
144        let result = FunctionSelector::from_hex("0xaabbccddee");
145        assert!(result.is_err());
146    }
147
148    #[test]
149    fn event_selector_roundtrip() {
150        let selector = EventSelector(Fr::from(42u64));
151        let json = serde_json::to_string(&selector).expect("serialize EventSelector");
152        let decoded: EventSelector =
153            serde_json::from_str(&json).expect("deserialize EventSelector");
154        assert_eq!(decoded, selector);
155    }
156
157    #[test]
158    fn load_minimal_artifact() {
159        let artifact = ContractArtifact::from_json(MINIMAL_ARTIFACT).expect("parse artifact");
160        assert_eq!(artifact.name, "TestContract");
161        assert_eq!(artifact.functions.len(), 1);
162        assert_eq!(artifact.functions[0].name, "increment");
163        assert_eq!(artifact.functions[0].function_type, FunctionType::Public);
164        assert!(!artifact.functions[0].is_initializer);
165        assert_eq!(artifact.functions[0].parameters.len(), 1);
166        assert_eq!(artifact.functions[0].parameters[0].name, "value");
167    }
168
169    #[test]
170    fn load_multi_function_artifact() {
171        let artifact =
172            ContractArtifact::from_json(MULTI_FUNCTION_ARTIFACT).expect("parse artifact");
173        assert_eq!(artifact.name, "TokenContract");
174        assert_eq!(artifact.functions.len(), 4);
175
176        let constructor = &artifact.functions[0];
177        assert_eq!(constructor.name, "constructor");
178        assert_eq!(constructor.function_type, FunctionType::Private);
179        assert!(constructor.is_initializer);
180        assert_eq!(constructor.parameters.len(), 2);
181
182        let transfer = &artifact.functions[1];
183        assert_eq!(transfer.name, "transfer");
184        assert_eq!(transfer.function_type, FunctionType::Private);
185        assert!(!transfer.is_static);
186
187        let balance = &artifact.functions[2];
188        assert_eq!(balance.name, "balance_of");
189        assert_eq!(balance.function_type, FunctionType::Utility);
190        assert!(balance.is_static);
191        assert_eq!(balance.return_types.len(), 1);
192
193        let supply = &artifact.functions[3];
194        assert_eq!(supply.name, "total_supply");
195        assert_eq!(supply.function_type, FunctionType::Public);
196        assert!(supply.is_static);
197    }
198
199    #[test]
200    fn find_function_by_name() {
201        let artifact =
202            ContractArtifact::from_json(MULTI_FUNCTION_ARTIFACT).expect("parse artifact");
203
204        let transfer = artifact.find_function("transfer").expect("find transfer");
205        assert_eq!(transfer.name, "transfer");
206        assert_eq!(transfer.function_type, FunctionType::Private);
207    }
208
209    #[test]
210    fn find_function_not_found() {
211        let artifact =
212            ContractArtifact::from_json(MULTI_FUNCTION_ARTIFACT).expect("parse artifact");
213
214        let result = artifact.find_function("nonexistent");
215        assert!(result.is_err());
216    }
217
218    #[test]
219    fn find_function_by_type() {
220        let artifact =
221            ContractArtifact::from_json(MULTI_FUNCTION_ARTIFACT).expect("parse artifact");
222
223        let balance = artifact
224            .find_function_by_type("balance_of", &FunctionType::Utility)
225            .expect("find balance_of as utility");
226        assert_eq!(balance.name, "balance_of");
227
228        let wrong_type = artifact.find_function_by_type("balance_of", &FunctionType::Public);
229        assert!(wrong_type.is_err());
230    }
231
232    #[test]
233    fn abi_value_field_roundtrip() {
234        let value = AbiValue::Field(Fr::from(1u64));
235        let json = serde_json::to_string(&value).expect("serialize AbiValue::Field");
236        assert!(json.contains("field"));
237        let decoded: AbiValue = serde_json::from_str(&json).expect("deserialize AbiValue");
238        assert_eq!(decoded, value);
239    }
240
241    #[test]
242    fn abi_value_boolean_roundtrip() {
243        let value = AbiValue::Boolean(true);
244        let json = serde_json::to_string(&value).expect("serialize");
245        let decoded: AbiValue = serde_json::from_str(&json).expect("deserialize");
246        assert_eq!(decoded, value);
247    }
248
249    #[test]
250    fn abi_value_integer_roundtrip() {
251        let value = AbiValue::Integer(42);
252        let json = serde_json::to_string(&value).expect("serialize");
253        let decoded: AbiValue = serde_json::from_str(&json).expect("deserialize");
254        assert_eq!(decoded, value);
255    }
256
257    #[test]
258    fn abi_value_array_roundtrip() {
259        let value = AbiValue::Array(vec![
260            AbiValue::Field(Fr::from(1u64)),
261            AbiValue::Field(Fr::from(2u64)),
262        ]);
263        let json = serde_json::to_string(&value).expect("serialize");
264        let decoded: AbiValue = serde_json::from_str(&json).expect("deserialize");
265        assert_eq!(decoded, value);
266    }
267
268    #[test]
269    fn abi_value_struct_roundtrip() {
270        let mut fields = BTreeMap::new();
271        fields.insert("x".to_owned(), AbiValue::Field(Fr::from(1u64)));
272        fields.insert("y".to_owned(), AbiValue::Integer(2));
273        let value = AbiValue::Struct(fields);
274        let json = serde_json::to_string(&value).expect("serialize");
275        let decoded: AbiValue = serde_json::from_str(&json).expect("deserialize");
276        assert_eq!(decoded, value);
277    }
278
279    #[test]
280    fn abi_type_struct_roundtrip() {
281        let typ = AbiType::Struct {
282            name: "Point".to_owned(),
283            fields: vec![
284                AbiParameter {
285                    name: "x".to_owned(),
286                    typ: AbiType::Field,
287                    visibility: None,
288                },
289                AbiParameter {
290                    name: "y".to_owned(),
291                    typ: AbiType::Field,
292                    visibility: None,
293                },
294            ],
295        };
296        let json = serde_json::to_string(&typ).expect("serialize AbiType::Struct");
297        let decoded: AbiType = serde_json::from_str(&json).expect("deserialize AbiType::Struct");
298        assert_eq!(decoded, typ);
299    }
300
301    #[test]
302    fn abi_type_array_roundtrip() {
303        let typ = AbiType::Array {
304            element: Box::new(AbiType::Field),
305            length: 10,
306        };
307        let json = serde_json::to_string(&typ).expect("serialize");
308        let decoded: AbiType = serde_json::from_str(&json).expect("deserialize");
309        assert_eq!(decoded, typ);
310    }
311
312    #[test]
313    fn artifact_from_invalid_json_fails() {
314        let result = ContractArtifact::from_json("not json");
315        assert!(result.is_err());
316    }
317
318    #[test]
319    fn from_signature_is_deterministic() {
320        let a = FunctionSelector::from_signature("sponsor_unconditionally()");
321        let b = FunctionSelector::from_signature("sponsor_unconditionally()");
322        assert_eq!(a, b);
323    }
324
325    #[test]
326    fn from_signature_different_inputs_differ() {
327        let a = FunctionSelector::from_signature("sponsor_unconditionally()");
328        let b = FunctionSelector::from_signature("claim_and_end_setup((Field),u128,Field,Field)");
329        assert_ne!(a, b);
330    }
331
332    #[test]
333    fn from_signature_empty_string() {
334        let a = FunctionSelector::from_signature("");
335        let b = FunctionSelector::from_signature("");
336        assert_eq!(a, b);
337    }
338
339    #[test]
340    fn from_signature_produces_4_bytes() {
341        let selector = FunctionSelector::from_signature("transfer(Field,Field,u64)");
342        assert_eq!(selector.0.len(), 4);
343    }
344
345    #[test]
346    fn function_selector_roundtrips_through_field() {
347        let selector = FunctionSelector::from_signature("set_authorized(Field,bool)");
348        assert_eq!(FunctionSelector::from_field(selector.to_field()), selector);
349    }
350
351    #[test]
352    fn authorization_selector_roundtrips_through_field() {
353        let selector =
354            AuthorizationSelector::from_signature("CallAuthorization((Field),(u32),Field)");
355        assert_eq!(
356            AuthorizationSelector::from_field(selector.to_field()),
357            selector
358        );
359    }
360
361    // -- Substep 6.1: Type checkers --
362
363    #[test]
364    fn type_checker_aztec_address() {
365        let typ = AbiType::Struct {
366            name: "aztec::protocol_types::address::AztecAddress".to_owned(),
367            fields: vec![AbiParameter {
368                name: "inner".to_owned(),
369                typ: AbiType::Field,
370                visibility: None,
371            }],
372        };
373        assert!(is_aztec_address_struct(&typ));
374        assert!(is_address_struct(&typ));
375        assert!(!is_eth_address_struct(&typ));
376    }
377
378    #[test]
379    fn type_checker_eth_address() {
380        let typ = AbiType::Struct {
381            name: "protocol_types::address::EthAddress".to_owned(),
382            fields: vec![AbiParameter {
383                name: "inner".to_owned(),
384                typ: AbiType::Field,
385                visibility: None,
386            }],
387        };
388        assert!(is_eth_address_struct(&typ));
389        assert!(is_address_struct(&typ));
390        assert!(!is_aztec_address_struct(&typ));
391    }
392
393    #[test]
394    fn type_checker_function_selector() {
395        let typ = AbiType::Struct {
396            name: "types::abis::function_selector::FunctionSelector".to_owned(),
397            fields: vec![AbiParameter {
398                name: "inner".to_owned(),
399                typ: AbiType::Field,
400                visibility: None,
401            }],
402        };
403        assert!(is_function_selector_struct(&typ));
404    }
405
406    #[test]
407    fn type_checker_wrapped_field() {
408        let yes = AbiType::Struct {
409            name: "SomeWrapped".to_owned(),
410            fields: vec![AbiParameter {
411                name: "inner".to_owned(),
412                typ: AbiType::Field,
413                visibility: None,
414            }],
415        };
416        assert!(is_wrapped_field_struct(&yes));
417
418        let no = AbiType::Struct {
419            name: "NotWrapped".to_owned(),
420            fields: vec![AbiParameter {
421                name: "value".to_owned(),
422                typ: AbiType::Field,
423                visibility: None,
424            }],
425        };
426        assert!(!is_wrapped_field_struct(&no));
427    }
428
429    #[test]
430    fn type_checker_bounded_vec() {
431        let typ = AbiType::Struct {
432            name: "std::collections::bounded_vec::BoundedVec".to_owned(),
433            fields: vec![
434                AbiParameter {
435                    name: "storage".to_owned(),
436                    typ: AbiType::Array {
437                        element: Box::new(AbiType::Field),
438                        length: 10,
439                    },
440                    visibility: None,
441                },
442                AbiParameter {
443                    name: "len".to_owned(),
444                    typ: AbiType::Integer {
445                        sign: "unsigned".to_owned(),
446                        width: 64,
447                    },
448                    visibility: None,
449                },
450            ],
451        };
452        assert!(is_bounded_vec_struct(&typ));
453    }
454
455    #[test]
456    fn type_checker_option() {
457        let typ = AbiType::Struct {
458            name: "std::option::Option".to_owned(),
459            fields: vec![
460                AbiParameter {
461                    name: "_is_some".to_owned(),
462                    typ: AbiType::Boolean,
463                    visibility: None,
464                },
465                AbiParameter {
466                    name: "_value".to_owned(),
467                    typ: AbiType::Field,
468                    visibility: None,
469                },
470            ],
471        };
472        assert!(is_option_struct(&typ));
473    }
474
475    #[test]
476    fn type_checker_non_matching() {
477        let typ = AbiType::Field;
478        assert!(!is_address_struct(&typ));
479        assert!(!is_function_selector_struct(&typ));
480        assert!(!is_wrapped_field_struct(&typ));
481        assert!(!is_bounded_vec_struct(&typ));
482        assert!(!is_option_struct(&typ));
483        assert!(!is_public_keys_struct(&typ));
484    }
485
486    // -- Substep 6.2: type_size --
487
488    #[test]
489    fn type_size_scalars() {
490        assert_eq!(abi_type_size(&AbiType::Field), 1);
491        assert_eq!(abi_type_size(&AbiType::Boolean), 1);
492        assert_eq!(
493            abi_type_size(&AbiType::Integer {
494                sign: "unsigned".to_owned(),
495                width: 64
496            }),
497            1
498        );
499    }
500
501    #[test]
502    fn type_size_string() {
503        assert_eq!(abi_type_size(&AbiType::String { length: 31 }), 31);
504    }
505
506    #[test]
507    fn type_size_array() {
508        assert_eq!(
509            abi_type_size(&AbiType::Array {
510                element: Box::new(AbiType::Field),
511                length: 5
512            }),
513            5
514        );
515    }
516
517    #[test]
518    fn type_size_nested_struct() {
519        let typ = AbiType::Struct {
520            name: "Point".to_owned(),
521            fields: vec![
522                AbiParameter {
523                    name: "x".to_owned(),
524                    typ: AbiType::Field,
525                    visibility: None,
526                },
527                AbiParameter {
528                    name: "y".to_owned(),
529                    typ: AbiType::Field,
530                    visibility: None,
531                },
532            ],
533        };
534        assert_eq!(abi_type_size(&typ), 2);
535    }
536
537    #[test]
538    fn count_arguments_size_works() {
539        let func = FunctionArtifact {
540            name: "test".to_owned(),
541            function_type: FunctionType::Public,
542            is_initializer: false,
543            is_static: false,
544            is_only_self: None,
545            parameters: vec![
546                AbiParameter {
547                    name: "a".to_owned(),
548                    typ: AbiType::Field,
549                    visibility: None,
550                },
551                AbiParameter {
552                    name: "b".to_owned(),
553                    typ: AbiType::Array {
554                        element: Box::new(AbiType::Field),
555                        length: 3,
556                    },
557                    visibility: None,
558                },
559            ],
560            return_types: vec![],
561            error_types: None,
562            selector: None,
563            bytecode: None,
564            verification_key_hash: None,
565            verification_key: None,
566            custom_attributes: None,
567            is_unconstrained: None,
568            debug_symbols: None,
569        };
570        assert_eq!(count_arguments_size(&func), 4);
571    }
572
573    // -- Substep 6.3: Enhanced encoder --
574
575    #[test]
576    fn encode_aztec_address_as_field() {
577        let typ = AbiType::Struct {
578            name: "aztec::protocol_types::address::AztecAddress".to_owned(),
579            fields: vec![AbiParameter {
580                name: "inner".to_owned(),
581                typ: AbiType::Field,
582                visibility: None,
583            }],
584        };
585        let value = AbiValue::Field(Fr::from(42u64));
586        let mut out = Vec::new();
587        encode_value(&typ, &value, &mut out).expect("encode address");
588        assert_eq!(out, vec![Fr::from(42u64)]);
589    }
590
591    #[test]
592    fn encode_bounded_vec() {
593        let typ = AbiType::Struct {
594            name: "std::collections::bounded_vec::BoundedVec".to_owned(),
595            fields: vec![
596                AbiParameter {
597                    name: "storage".to_owned(),
598                    typ: AbiType::Array {
599                        element: Box::new(AbiType::Field),
600                        length: 5,
601                    },
602                    visibility: None,
603                },
604                AbiParameter {
605                    name: "len".to_owned(),
606                    typ: AbiType::Integer {
607                        sign: "unsigned".to_owned(),
608                        width: 64,
609                    },
610                    visibility: None,
611                },
612            ],
613        };
614        let value = AbiValue::Array(vec![
615            AbiValue::Field(Fr::from(1u64)),
616            AbiValue::Field(Fr::from(2u64)),
617            AbiValue::Field(Fr::from(3u64)),
618        ]);
619        let mut out = Vec::new();
620        encode_value(&typ, &value, &mut out).expect("encode bounded vec");
621        assert_eq!(out.len(), 6);
622        assert_eq!(out[0], Fr::from(1u64));
623        assert_eq!(out[1], Fr::from(2u64));
624        assert_eq!(out[2], Fr::from(3u64));
625        assert_eq!(out[3], Fr::zero());
626        assert_eq!(out[4], Fr::zero());
627        assert_eq!(out[5], Fr::from(3u64));
628    }
629
630    #[test]
631    fn encode_option_some() {
632        let typ = AbiType::Struct {
633            name: "std::option::Option".to_owned(),
634            fields: vec![
635                AbiParameter {
636                    name: "_is_some".to_owned(),
637                    typ: AbiType::Boolean,
638                    visibility: None,
639                },
640                AbiParameter {
641                    name: "_value".to_owned(),
642                    typ: AbiType::Field,
643                    visibility: None,
644                },
645            ],
646        };
647        let value = AbiValue::Struct({
648            let mut m = BTreeMap::new();
649            m.insert("_is_some".to_owned(), AbiValue::Boolean(true));
650            m.insert("_value".to_owned(), AbiValue::Field(Fr::from(99u64)));
651            m
652        });
653        let mut out = Vec::new();
654        encode_value(&typ, &value, &mut out).expect("encode option some");
655        assert_eq!(out.len(), 2);
656        assert_eq!(out[0], Fr::one());
657        assert_eq!(out[1], Fr::from(99u64));
658    }
659
660    #[test]
661    fn encode_option_none() {
662        let typ = AbiType::Struct {
663            name: "std::option::Option".to_owned(),
664            fields: vec![
665                AbiParameter {
666                    name: "_is_some".to_owned(),
667                    typ: AbiType::Boolean,
668                    visibility: None,
669                },
670                AbiParameter {
671                    name: "_value".to_owned(),
672                    typ: AbiType::Field,
673                    visibility: None,
674                },
675            ],
676        };
677        let value = AbiValue::Struct({
678            let mut m = BTreeMap::new();
679            m.insert("_is_some".to_owned(), AbiValue::Boolean(false));
680            m.insert("_value".to_owned(), AbiValue::Field(Fr::zero()));
681            m
682        });
683        let mut out = Vec::new();
684        encode_value(&typ, &value, &mut out).expect("encode option none");
685        assert_eq!(out.len(), 2);
686        assert_eq!(out[0], Fr::zero());
687        assert_eq!(out[1], Fr::zero());
688    }
689
690    #[test]
691    fn encode_signed_negative_integer() {
692        let typ = AbiType::Integer {
693            sign: "signed".to_owned(),
694            width: 8,
695        };
696        let value = AbiValue::Integer(-1);
697        let mut out = Vec::new();
698        encode_value(&typ, &value, &mut out).expect("encode signed int");
699        assert_eq!(out.len(), 1);
700        let bytes = out[0].to_be_bytes();
701        let raw = u128::from_be_bytes(bytes[16..].try_into().unwrap());
702        assert_eq!(raw, 255);
703    }
704
705    #[test]
706    fn encode_signed_positive_integer() {
707        let typ = AbiType::Integer {
708            sign: "signed".to_owned(),
709            width: 8,
710        };
711        let value = AbiValue::Integer(42);
712        let mut out = Vec::new();
713        encode_value(&typ, &value, &mut out).expect("encode signed int");
714        let bytes = out[0].to_be_bytes();
715        let raw = u128::from_be_bytes(bytes[16..].try_into().unwrap());
716        assert_eq!(raw, 42);
717    }
718
719    // -- Substep 6.4: Decoder --
720
721    #[test]
722    fn decode_single_field() {
723        let fields = vec![Fr::from(42u64)];
724        let result = decode_from_abi(&[AbiType::Field], &fields).expect("decode");
725        assert_eq!(result, AbiDecoded::Field(Fr::from(42u64)));
726    }
727
728    #[test]
729    fn decode_boolean() {
730        let fields = vec![Fr::one()];
731        let result = decode_from_abi(&[AbiType::Boolean], &fields).expect("decode");
732        assert_eq!(result, AbiDecoded::Boolean(true));
733
734        let fields = vec![Fr::zero()];
735        let result = decode_from_abi(&[AbiType::Boolean], &fields).expect("decode");
736        assert_eq!(result, AbiDecoded::Boolean(false));
737    }
738
739    #[test]
740    fn decode_unsigned_integer() {
741        let typ = AbiType::Integer {
742            sign: "unsigned".to_owned(),
743            width: 64,
744        };
745        let mut encoded = Vec::new();
746        encode_value(&typ, &AbiValue::Integer(42), &mut encoded).expect("encode");
747        let result = decode_from_abi(&[typ], &encoded).expect("decode");
748        assert_eq!(result, AbiDecoded::Integer(42));
749    }
750
751    #[test]
752    fn decode_signed_negative_integer() {
753        let typ = AbiType::Integer {
754            sign: "signed".to_owned(),
755            width: 32,
756        };
757        let mut encoded = Vec::new();
758        encode_value(&typ, &AbiValue::Integer(-100), &mut encoded).expect("encode");
759        let result = decode_from_abi(&[typ], &encoded).expect("decode");
760        assert_eq!(result, AbiDecoded::Integer(-100));
761    }
762
763    #[test]
764    fn decode_array() {
765        let typ = AbiType::Array {
766            element: Box::new(AbiType::Field),
767            length: 3,
768        };
769        let fields = vec![Fr::from(1u64), Fr::from(2u64), Fr::from(3u64)];
770        let result = decode_from_abi(&[typ], &fields).expect("decode");
771        assert_eq!(
772            result,
773            AbiDecoded::Array(vec![
774                AbiDecoded::Field(Fr::from(1u64)),
775                AbiDecoded::Field(Fr::from(2u64)),
776                AbiDecoded::Field(Fr::from(3u64)),
777            ])
778        );
779    }
780
781    #[test]
782    fn decode_struct() {
783        let typ = AbiType::Struct {
784            name: "Point".to_owned(),
785            fields: vec![
786                AbiParameter {
787                    name: "x".to_owned(),
788                    typ: AbiType::Field,
789                    visibility: None,
790                },
791                AbiParameter {
792                    name: "y".to_owned(),
793                    typ: AbiType::Field,
794                    visibility: None,
795                },
796            ],
797        };
798        let fields = vec![Fr::from(10u64), Fr::from(20u64)];
799        let result = decode_from_abi(&[typ], &fields).expect("decode");
800        let mut expected = BTreeMap::new();
801        expected.insert("x".to_owned(), AbiDecoded::Field(Fr::from(10u64)));
802        expected.insert("y".to_owned(), AbiDecoded::Field(Fr::from(20u64)));
803        assert_eq!(result, AbiDecoded::Struct(expected));
804    }
805
806    #[test]
807    fn decode_aztec_address() {
808        let typ = AbiType::Struct {
809            name: "aztec::protocol_types::address::AztecAddress".to_owned(),
810            fields: vec![AbiParameter {
811                name: "inner".to_owned(),
812                typ: AbiType::Field,
813                visibility: None,
814            }],
815        };
816        let fields = vec![Fr::from(42u64)];
817        let result = decode_from_abi(&[typ], &fields).expect("decode");
818        assert_eq!(
819            result,
820            AbiDecoded::Address(crate::types::AztecAddress(Fr::from(42u64)))
821        );
822    }
823
824    #[test]
825    fn decode_option_some() {
826        let typ = AbiType::Struct {
827            name: "std::option::Option".to_owned(),
828            fields: vec![
829                AbiParameter {
830                    name: "_is_some".to_owned(),
831                    typ: AbiType::Boolean,
832                    visibility: None,
833                },
834                AbiParameter {
835                    name: "_value".to_owned(),
836                    typ: AbiType::Field,
837                    visibility: None,
838                },
839            ],
840        };
841        let fields = vec![Fr::one(), Fr::from(99u64)];
842        let result = decode_from_abi(&[typ], &fields).expect("decode");
843        assert_eq!(result, AbiDecoded::Field(Fr::from(99u64)));
844    }
845
846    #[test]
847    fn decode_option_none() {
848        let typ = AbiType::Struct {
849            name: "std::option::Option".to_owned(),
850            fields: vec![
851                AbiParameter {
852                    name: "_is_some".to_owned(),
853                    typ: AbiType::Boolean,
854                    visibility: None,
855                },
856                AbiParameter {
857                    name: "_value".to_owned(),
858                    typ: AbiType::Field,
859                    visibility: None,
860                },
861            ],
862        };
863        let fields = vec![Fr::zero(), Fr::zero()];
864        let result = decode_from_abi(&[typ], &fields).expect("decode");
865        assert_eq!(result, AbiDecoded::None);
866    }
867
868    #[test]
869    fn decode_string() {
870        let typ = AbiType::String { length: 5 };
871        let fields = vec![
872            Fr::from(b'H' as u64),
873            Fr::from(b'e' as u64),
874            Fr::from(b'l' as u64),
875            Fr::from(b'l' as u64),
876            Fr::from(b'o' as u64),
877        ];
878        let result = decode_from_abi(&[typ], &fields).expect("decode");
879        assert_eq!(result, AbiDecoded::String("Hello".to_owned()));
880    }
881
882    #[test]
883    fn decode_insufficient_fields_errors() {
884        let typ = AbiType::Array {
885            element: Box::new(AbiType::Field),
886            length: 5,
887        };
888        let fields = vec![Fr::from(1u64), Fr::from(2u64)];
889        let result = decode_from_abi(&[typ], &fields);
890        assert!(result.is_err());
891    }
892
893    #[test]
894    fn encode_decode_roundtrip_complex() {
895        let bv_typ = AbiType::Struct {
896            name: "std::collections::bounded_vec::BoundedVec".to_owned(),
897            fields: vec![
898                AbiParameter {
899                    name: "storage".to_owned(),
900                    typ: AbiType::Array {
901                        element: Box::new(AbiType::Field),
902                        length: 5,
903                    },
904                    visibility: None,
905                },
906                AbiParameter {
907                    name: "len".to_owned(),
908                    typ: AbiType::Integer {
909                        sign: "unsigned".to_owned(),
910                        width: 64,
911                    },
912                    visibility: None,
913                },
914            ],
915        };
916        let value = AbiValue::Array(vec![
917            AbiValue::Field(Fr::from(10u64)),
918            AbiValue::Field(Fr::from(20u64)),
919            AbiValue::Field(Fr::from(30u64)),
920        ]);
921        let mut encoded = Vec::new();
922        encode_value(&bv_typ, &value, &mut encoded).expect("encode");
923        let decoded = decode_from_abi(&[bv_typ], &encoded).expect("decode");
924        assert_eq!(
925            decoded,
926            AbiDecoded::Array(vec![
927                AbiDecoded::Field(Fr::from(10u64)),
928                AbiDecoded::Field(Fr::from(20u64)),
929                AbiDecoded::Field(Fr::from(30u64)),
930            ])
931        );
932    }
933
934    // -- Substep 6.5: NoteSelector --
935
936    #[test]
937    fn note_selector_valid() {
938        let ns = NoteSelector::new(0).expect("valid");
939        assert_eq!(ns.0, 0);
940        let ns = NoteSelector::new(127).expect("valid");
941        assert_eq!(ns.0, 127);
942    }
943
944    #[test]
945    fn note_selector_rejects_128() {
946        assert!(NoteSelector::new(128).is_err());
947        assert!(NoteSelector::new(255).is_err());
948    }
949
950    #[test]
951    fn note_selector_field_roundtrip() {
952        let ns = NoteSelector::new(42).expect("valid");
953        let field = ns.to_field();
954        let ns2 = NoteSelector::from_field(field).expect("from_field");
955        assert_eq!(ns, ns2);
956    }
957
958    #[test]
959    fn note_selector_hex_roundtrip() {
960        let ns = NoteSelector::from_hex("0x1a").expect("valid");
961        assert_eq!(ns.0, 0x1a);
962        assert_eq!(ns.to_string(), "0x1a");
963    }
964
965    #[test]
966    fn note_selector_serde_roundtrip() {
967        let ns = NoteSelector::new(42).expect("valid");
968        let json = serde_json::to_string(&ns).expect("serialize");
969        assert_eq!(json, "42");
970        let decoded: NoteSelector = serde_json::from_str(&json).expect("deserialize");
971        assert_eq!(decoded, ns);
972    }
973
974    #[test]
975    fn note_selector_serde_rejects_invalid() {
976        let result: Result<NoteSelector, _> = serde_json::from_str("200");
977        assert!(result.is_err());
978    }
979
980    // -- Substep 6.7: Contract artifact serialization --
981
982    #[test]
983    fn artifact_to_buffer_from_buffer_roundtrip() {
984        let artifact = ContractArtifact::from_json(MINIMAL_ARTIFACT).expect("parse artifact");
985        let buffer = artifact.to_buffer().expect("to_buffer");
986        let decoded = ContractArtifact::from_buffer(&buffer).expect("from_buffer");
987        assert_eq!(decoded, artifact);
988    }
989
990    #[test]
991    fn artifact_to_json_from_json_roundtrip() {
992        let artifact = ContractArtifact::from_json(MINIMAL_ARTIFACT).expect("parse artifact");
993        let json = artifact.to_json().expect("to_json");
994        let decoded = ContractArtifact::from_json(&json).expect("from_json");
995        assert_eq!(decoded, artifact);
996    }
997
998    #[test]
999    fn artifact_from_buffer_rejects_invalid() {
1000        let result = ContractArtifact::from_buffer(b"not json");
1001        assert!(result.is_err());
1002    }
1003
1004    // -- Substep 6.8: Buffer <-> Fields --
1005
1006    #[test]
1007    fn buffer_fields_roundtrip() {
1008        let data = b"Hello, Aztec! This is a test of buffer encoding.";
1009        let fields = buffer_as_fields(data, 100).expect("encode");
1010        let decoded = buffer_from_fields(&fields).expect("decode");
1011        assert_eq!(decoded, data);
1012    }
1013
1014    #[test]
1015    fn buffer_fields_empty() {
1016        let fields = buffer_as_fields(&[], 10).expect("encode");
1017        assert_eq!(fields.len(), 10);
1018        assert_eq!(fields[0], Fr::from(0u64));
1019        let decoded = buffer_from_fields(&fields).expect("decode");
1020        assert!(decoded.is_empty());
1021    }
1022
1023    #[test]
1024    fn buffer_fields_exactly_31_bytes() {
1025        let data = [0xABu8; 31];
1026        let fields = buffer_as_fields(&data, 10).expect("encode");
1027        assert_eq!(fields[0], Fr::from(31u64));
1028        let decoded = buffer_from_fields(&fields).expect("decode");
1029        assert_eq!(decoded, data);
1030    }
1031
1032    #[test]
1033    fn buffer_fields_62_bytes() {
1034        let data = [0xFFu8; 62];
1035        let fields = buffer_as_fields(&data, 10).expect("encode");
1036        assert_eq!(fields[0], Fr::from(62u64));
1037        let decoded = buffer_from_fields(&fields).expect("decode");
1038        assert_eq!(decoded, data);
1039    }
1040
1041    #[test]
1042    fn buffer_fields_exceeds_max() {
1043        let data = [0u8; 100];
1044        let result = buffer_as_fields(&data, 3);
1045        assert!(result.is_err());
1046    }
1047
1048    #[test]
1049    fn buffer_from_fields_empty_errors() {
1050        let result = buffer_from_fields(&[]);
1051        assert!(result.is_err());
1052    }
1053}