Skip to main content

aztec_core/
abi.rs

1use ark_ff::{BigInteger, PrimeField};
2use serde::{Deserialize, Deserializer, Serialize, Serializer};
3use std::collections::BTreeMap;
4use std::fmt;
5
6use crate::hash::poseidon2_hash_bytes;
7use crate::types::Fr;
8use crate::Error;
9
10fn strip_0x(s: &str) -> &str {
11    s.strip_prefix("0x").unwrap_or(s)
12}
13
14fn decode_selector_hex(s: &str) -> Result<[u8; 4], Error> {
15    let raw = strip_0x(s);
16    if raw.len() > 8 {
17        return Err(Error::InvalidData(
18            "function selector must fit in 4 bytes".to_owned(),
19        ));
20    }
21    let padded = format!("{raw:0>8}");
22    let bytes = hex::decode(padded).map_err(|e| Error::InvalidData(e.to_string()))?;
23    let mut out = [0u8; 4];
24    out.copy_from_slice(&bytes);
25    Ok(out)
26}
27
28fn field_to_selector_bytes(field: Fr) -> [u8; 4] {
29    let raw = field.0.into_bigint().to_bytes_be();
30    let mut padded = [0u8; 32];
31    padded[32 - raw.len()..].copy_from_slice(&raw);
32    let mut out = [0u8; 4];
33    out.copy_from_slice(&padded[28..]);
34    out
35}
36
37fn selector_bytes_to_field(bytes: [u8; 4]) -> Fr {
38    Fr::from(u64::from(u32::from_be_bytes(bytes)))
39}
40
41fn selector_from_signature(signature: &str) -> [u8; 4] {
42    let hash = poseidon2_hash_bytes(signature.as_bytes());
43    field_to_selector_bytes(hash)
44}
45
46/// Convert an ABI type to its canonical Noir signature representation.
47pub fn abi_type_signature(typ: &AbiType) -> String {
48    match typ {
49        AbiType::Field => "Field".to_owned(),
50        AbiType::Boolean => "bool".to_owned(),
51        AbiType::Integer { sign, width } => {
52            let prefix = if sign == "signed" { "i" } else { "u" };
53            format!("{prefix}{width}")
54        }
55        AbiType::Array { element, length } => {
56            format!("[{};{length}]", abi_type_signature(element))
57        }
58        AbiType::String { length } => format!("str<{length}>"),
59        AbiType::Struct { fields, .. } => {
60            let inner: Vec<String> = fields.iter().map(|f| abi_type_signature(&f.typ)).collect();
61            format!("({})", inner.join(","))
62        }
63        AbiType::Tuple { elements } => {
64            let inner: Vec<String> = elements.iter().map(abi_type_signature).collect();
65            format!("({})", inner.join(","))
66        }
67    }
68}
69
70/// A 4-byte function selector used to identify contract functions.
71#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
72pub struct FunctionSelector(pub [u8; 4]);
73
74impl FunctionSelector {
75    /// Parse a function selector from a hex string (e.g. `"0xaabbccdd"`).
76    pub fn from_hex(value: &str) -> Result<Self, Error> {
77        Ok(Self(decode_selector_hex(value)?))
78    }
79
80    /// Convert a field element to a function selector using its low 32 bits.
81    pub fn from_field(field: Fr) -> Self {
82        Self(field_to_selector_bytes(field))
83    }
84
85    /// Compute a function selector from a Noir function signature string.
86    ///
87    /// Aztec computes selectors by Poseidon2-hashing the raw signature bytes and
88    /// taking the low 32 bits of the resulting field element.
89    ///
90    /// # Example
91    /// ```
92    /// # use aztec_core::abi::FunctionSelector;
93    /// let selector = FunctionSelector::from_signature("sponsor_unconditionally()");
94    /// ```
95    pub fn from_signature(signature: &str) -> Self {
96        Self(selector_from_signature(signature))
97    }
98
99    /// Derive a function selector from a function name and its ABI parameters.
100    ///
101    /// Constructs the canonical Noir signature (e.g., `transfer(Field,Field,u64)`)
102    /// and computes the Poseidon2-based selector from it.
103    pub fn from_name_and_parameters(name: &str, params: &[AbiParameter]) -> Self {
104        let param_sigs: Vec<String> = params.iter().map(|p| abi_type_signature(&p.typ)).collect();
105        let sig = format!("{}({})", name, param_sigs.join(","));
106        Self::from_signature(&sig)
107    }
108
109    /// Convert this selector to its field representation.
110    pub fn to_field(self) -> Fr {
111        selector_bytes_to_field(self.0)
112    }
113}
114
115impl fmt::Display for FunctionSelector {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        write!(f, "0x{}", hex::encode(self.0))
118    }
119}
120
121impl Serialize for FunctionSelector {
122    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
123    where
124        S: Serializer,
125    {
126        serializer.serialize_str(&self.to_string())
127    }
128}
129
130impl<'de> Deserialize<'de> for FunctionSelector {
131    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
132    where
133        D: Deserializer<'de>,
134    {
135        let s = String::deserialize(deserializer)?;
136        Self::from_hex(&s).map_err(serde::de::Error::custom)
137    }
138}
139
140/// A 4-byte authorization selector used to identify authwit request types.
141#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
142pub struct AuthorizationSelector(pub [u8; 4]);
143
144impl AuthorizationSelector {
145    /// Parse an authorization selector from a hex string.
146    pub fn from_hex(value: &str) -> Result<Self, Error> {
147        Ok(Self(decode_selector_hex(value)?))
148    }
149
150    /// Convert a field element to an authorization selector using its low 32 bits.
151    pub fn from_field(field: Fr) -> Self {
152        Self(field_to_selector_bytes(field))
153    }
154
155    /// Compute an authorization selector from an authorization signature.
156    pub fn from_signature(signature: &str) -> Self {
157        Self(selector_from_signature(signature))
158    }
159
160    /// Convert this selector to its field representation.
161    pub fn to_field(self) -> Fr {
162        selector_bytes_to_field(self.0)
163    }
164}
165
166impl fmt::Display for AuthorizationSelector {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        write!(f, "0x{}", hex::encode(self.0))
169    }
170}
171
172impl Serialize for AuthorizationSelector {
173    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
174    where
175        S: Serializer,
176    {
177        serializer.serialize_str(&self.to_string())
178    }
179}
180
181impl<'de> Deserialize<'de> for AuthorizationSelector {
182    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
183    where
184        D: Deserializer<'de>,
185    {
186        let s = String::deserialize(deserializer)?;
187        Self::from_hex(&s).map_err(serde::de::Error::custom)
188    }
189}
190
191/// A field-element event selector used to identify contract events.
192#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
193pub struct EventSelector(pub Fr);
194
195/// The type of a contract function.
196#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
197#[serde(rename_all = "lowercase")]
198pub enum FunctionType {
199    /// A private function executed in the user's PXE.
200    Private,
201    /// A public function executed by the sequencer.
202    Public,
203    /// A utility (view/unconstrained) function for read-only queries.
204    Utility,
205}
206
207/// ABI type representation for function parameters and return values.
208#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
209#[serde(tag = "kind", rename_all = "snake_case")]
210pub enum AbiType {
211    /// A BN254 field element.
212    Field,
213    /// A boolean value.
214    Boolean,
215    /// A signed or unsigned integer with a specific bit width.
216    Integer {
217        /// `"signed"` or `"unsigned"`.
218        sign: String,
219        /// Bit width of the integer.
220        width: u16,
221    },
222    /// A fixed-length array of elements.
223    Array {
224        /// Element type.
225        #[serde(rename = "type", alias = "element")]
226        element: Box<Self>,
227        /// Fixed array length.
228        length: usize,
229    },
230    /// A fixed-length string.
231    String {
232        /// Maximum string length.
233        length: usize,
234    },
235    /// A named struct with typed fields.
236    Struct {
237        /// Struct type name / path.
238        #[serde(alias = "path")]
239        name: String,
240        /// Struct fields.
241        fields: Vec<AbiParameter>,
242    },
243    /// An anonymous tuple of types.
244    Tuple {
245        /// Element types.
246        #[serde(alias = "fields")]
247        elements: Vec<Self>,
248    },
249}
250
251/// A concrete ABI value used as a function argument or return value.
252#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
253#[serde(tag = "kind", content = "value", rename_all = "snake_case")]
254pub enum AbiValue {
255    /// A BN254 field element value.
256    Field(Fr),
257    /// A boolean value.
258    Boolean(bool),
259    /// An integer value.
260    Integer(i128),
261    /// An array of values.
262    Array(Vec<Self>),
263    /// A string value.
264    String(String),
265    /// A struct value with named fields.
266    Struct(BTreeMap<String, Self>),
267    /// A tuple of values.
268    Tuple(Vec<Self>),
269}
270
271/// A named, typed parameter in a function ABI.
272#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
273pub struct AbiParameter {
274    /// Parameter name.
275    pub name: String,
276    /// Parameter type.
277    #[serde(rename = "type")]
278    pub typ: AbiType,
279    /// Visibility (e.g. `"private"`, `"public"`).
280    #[serde(default)]
281    pub visibility: Option<String>,
282}
283
284/// Metadata for a single function within a contract artifact.
285#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
286pub struct FunctionArtifact {
287    /// Function name.
288    pub name: String,
289    /// Whether this is a private, public, or utility function.
290    #[serde(alias = "functionType")]
291    pub function_type: FunctionType,
292    /// Whether this function is a contract initializer (constructor).
293    #[serde(default, alias = "isInitializer")]
294    pub is_initializer: bool,
295    /// Whether this function is a static (read-only) call.
296    #[serde(default, alias = "isStatic")]
297    pub is_static: bool,
298    /// Whether this function is only callable by the contract itself.
299    #[serde(default, skip_serializing_if = "Option::is_none", alias = "isOnlySelf")]
300    pub is_only_self: Option<bool>,
301    /// Function parameters.
302    #[serde(default)]
303    pub parameters: Vec<AbiParameter>,
304    /// Return types.
305    #[serde(default, alias = "returnTypes")]
306    pub return_types: Vec<AbiType>,
307    /// Error types thrown by the function.
308    #[serde(default, skip_serializing_if = "Option::is_none", alias = "errorTypes")]
309    pub error_types: Option<serde_json::Value>,
310    /// Pre-computed function selector.
311    #[serde(default)]
312    pub selector: Option<FunctionSelector>,
313    /// Compiled bytecode (base64 or hex encoded).
314    #[serde(default, skip_serializing_if = "Option::is_none")]
315    pub bytecode: Option<String>,
316    /// Hash of the verification key.
317    #[serde(default, skip_serializing_if = "Option::is_none")]
318    pub verification_key_hash: Option<Fr>,
319    /// Raw verification key (base64 or hex encoded).
320    #[serde(default, skip_serializing_if = "Option::is_none")]
321    pub verification_key: Option<String>,
322    /// Custom attributes / annotations from the Noir source.
323    #[serde(
324        default,
325        skip_serializing_if = "Option::is_none",
326        alias = "customAttributes"
327    )]
328    pub custom_attributes: Option<Vec<String>>,
329    /// Whether this is an unconstrained function.
330    #[serde(
331        default,
332        skip_serializing_if = "Option::is_none",
333        alias = "isUnconstrained"
334    )]
335    pub is_unconstrained: Option<bool>,
336    /// Debug symbols (opaque JSON).
337    #[serde(
338        default,
339        skip_serializing_if = "Option::is_none",
340        alias = "debugSymbols"
341    )]
342    pub debug_symbols: Option<serde_json::Value>,
343}
344
345/// A deserialized contract artifact containing function metadata.
346#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
347pub struct ContractArtifact {
348    /// Contract name.
349    pub name: String,
350    /// Functions defined in the contract.
351    #[serde(default)]
352    pub functions: Vec<FunctionArtifact>,
353    /// Compiler output metadata (opaque JSON).
354    #[serde(default, skip_serializing_if = "Option::is_none")]
355    pub outputs: Option<serde_json::Value>,
356    /// Source file map (opaque JSON).
357    #[serde(default, skip_serializing_if = "Option::is_none", alias = "fileMap")]
358    pub file_map: Option<serde_json::Value>,
359}
360
361impl ContractArtifact {
362    /// Deserialize a contract artifact from a JSON string.
363    pub fn from_json(json: &str) -> Result<Self, Error> {
364        serde_json::from_str(json).map_err(Error::from)
365    }
366
367    /// Find a function by name, returning an error if not found.
368    pub fn find_function(&self, name: &str) -> Result<&FunctionArtifact, Error> {
369        self.functions
370            .iter()
371            .find(|f| f.name == name)
372            .ok_or_else(|| {
373                Error::Abi(format!(
374                    "function '{}' not found in artifact '{}'",
375                    name, self.name
376                ))
377            })
378    }
379
380    /// Find a function by name and type, returning an error if not found.
381    pub fn find_function_by_type(
382        &self,
383        name: &str,
384        function_type: &FunctionType,
385    ) -> Result<&FunctionArtifact, Error> {
386        self.functions
387            .iter()
388            .find(|f| f.name == name && &f.function_type == function_type)
389            .ok_or_else(|| {
390                Error::Abi(format!(
391                    "{:?} function '{}' not found in artifact '{}'",
392                    function_type, name, self.name
393                ))
394            })
395    }
396}
397
398/// ABI-encode a function's arguments into field elements.
399pub fn encode_arguments(function: &FunctionArtifact, args: &[AbiValue]) -> Result<Vec<Fr>, Error> {
400    if function.parameters.len() != args.len() {
401        return Err(Error::Abi(format!(
402            "function '{}' expects {} argument(s), got {}",
403            function.name,
404            function.parameters.len(),
405            args.len()
406        )));
407    }
408
409    let mut out = Vec::new();
410    for (param, value) in function.parameters.iter().zip(args) {
411        encode_value(&param.typ, value, &mut out)?;
412    }
413    Ok(out)
414}
415
416fn encode_value(typ: &AbiType, value: &AbiValue, out: &mut Vec<Fr>) -> Result<(), Error> {
417    match (typ, value) {
418        (AbiType::Field, AbiValue::Field(field)) => {
419            out.push(*field);
420            Ok(())
421        }
422        (AbiType::Boolean, AbiValue::Boolean(boolean)) => {
423            out.push(if *boolean { Fr::one() } else { Fr::zero() });
424            Ok(())
425        }
426        (AbiType::Integer { .. }, AbiValue::Integer(integer)) => {
427            out.push(Fr::from(*integer as u64));
428            Ok(())
429        }
430        (AbiType::Array { element, length }, AbiValue::Array(items)) => {
431            if items.len() != *length {
432                return Err(Error::Abi(format!(
433                    "expected array of length {}, got {}",
434                    length,
435                    items.len()
436                )));
437            }
438            for item in items {
439                encode_value(element, item, out)?;
440            }
441            Ok(())
442        }
443        (AbiType::String { length }, AbiValue::String(string)) => {
444            let bytes = string.as_bytes();
445            if bytes.len() > *length {
446                return Err(Error::Abi(format!(
447                    "string exceeds fixed ABI length {}",
448                    length
449                )));
450            }
451            for byte in bytes {
452                out.push(Fr::from(u64::from(*byte)));
453            }
454            for _ in bytes.len()..*length {
455                out.push(Fr::zero());
456            }
457            Ok(())
458        }
459        (AbiType::Struct { fields, .. }, AbiValue::Struct(values)) => {
460            for field in fields {
461                let field_value = values
462                    .get(&field.name)
463                    .ok_or_else(|| Error::Abi(format!("missing struct field '{}'", field.name)))?;
464                encode_value(&field.typ, field_value, out)?;
465            }
466            Ok(())
467        }
468        (AbiType::Tuple { elements }, AbiValue::Tuple(values)) => {
469            if elements.len() != values.len() {
470                return Err(Error::Abi(format!(
471                    "expected tuple of length {}, got {}",
472                    elements.len(),
473                    values.len()
474                )));
475            }
476            for (element, value) in elements.iter().zip(values) {
477                encode_value(element, value, out)?;
478            }
479            Ok(())
480        }
481        _ => Err(Error::Abi("argument type/value mismatch".to_owned())),
482    }
483}
484
485#[cfg(test)]
486#[allow(clippy::expect_used, clippy::panic)]
487mod tests {
488    use super::*;
489
490    const MINIMAL_ARTIFACT: &str = r#"
491    {
492      "name": "TestContract",
493      "functions": [
494        {
495          "name": "increment",
496          "function_type": "public",
497          "is_initializer": false,
498          "is_static": false,
499          "parameters": [
500            { "name": "value", "type": { "kind": "field" } }
501          ],
502          "return_types": []
503        }
504      ]
505    }
506    "#;
507
508    const MULTI_FUNCTION_ARTIFACT: &str = r#"
509    {
510      "name": "TokenContract",
511      "functions": [
512        {
513          "name": "constructor",
514          "function_type": "private",
515          "is_initializer": true,
516          "is_static": false,
517          "parameters": [
518            { "name": "admin", "type": { "kind": "field" } },
519            { "name": "name", "type": { "kind": "string", "length": 31 } }
520          ],
521          "return_types": []
522        },
523        {
524          "name": "transfer",
525          "function_type": "private",
526          "is_initializer": false,
527          "is_static": false,
528          "parameters": [
529            { "name": "from", "type": { "kind": "field" } },
530            { "name": "to", "type": { "kind": "field" } },
531            { "name": "amount", "type": { "kind": "integer", "sign": "unsigned", "width": 64 } }
532          ],
533          "return_types": []
534        },
535        {
536          "name": "balance_of",
537          "function_type": "utility",
538          "is_initializer": false,
539          "is_static": true,
540          "parameters": [
541            { "name": "owner", "type": { "kind": "field" } }
542          ],
543          "return_types": [
544            { "kind": "integer", "sign": "unsigned", "width": 64 }
545          ]
546        },
547        {
548          "name": "total_supply",
549          "function_type": "public",
550          "is_initializer": false,
551          "is_static": true,
552          "parameters": [],
553          "return_types": [
554            { "kind": "integer", "sign": "unsigned", "width": 64 }
555          ]
556        }
557      ]
558    }
559    "#;
560
561    #[test]
562    fn function_type_roundtrip() {
563        for (ft, expected) in [
564            (FunctionType::Private, "\"private\""),
565            (FunctionType::Public, "\"public\""),
566            (FunctionType::Utility, "\"utility\""),
567        ] {
568            let json = serde_json::to_string(&ft).expect("serialize FunctionType");
569            assert_eq!(json, expected);
570            let decoded: FunctionType =
571                serde_json::from_str(&json).expect("deserialize FunctionType");
572            assert_eq!(decoded, ft);
573        }
574    }
575
576    #[test]
577    fn function_selector_hex_roundtrip() {
578        let selector = FunctionSelector::from_hex("0xaabbccdd").expect("valid hex");
579        assert_eq!(selector.0, [0xaa, 0xbb, 0xcc, 0xdd]);
580        assert_eq!(selector.to_string(), "0xaabbccdd");
581
582        let json = serde_json::to_string(&selector).expect("serialize selector");
583        let decoded: FunctionSelector = serde_json::from_str(&json).expect("deserialize selector");
584        assert_eq!(decoded, selector);
585    }
586
587    #[test]
588    fn authorization_selector_hex_roundtrip() {
589        let selector = AuthorizationSelector::from_hex("0x01020304").expect("valid hex");
590        assert_eq!(selector.0, [0x01, 0x02, 0x03, 0x04]);
591        assert_eq!(selector.to_string(), "0x01020304");
592
593        let json = serde_json::to_string(&selector).expect("serialize selector");
594        let decoded: AuthorizationSelector =
595            serde_json::from_str(&json).expect("deserialize selector");
596        assert_eq!(decoded, selector);
597    }
598
599    #[test]
600    fn function_selector_rejects_too_long() {
601        let result = FunctionSelector::from_hex("0xaabbccddee");
602        assert!(result.is_err());
603    }
604
605    #[test]
606    fn event_selector_roundtrip() {
607        let selector = EventSelector(Fr::from(42u64));
608        let json = serde_json::to_string(&selector).expect("serialize EventSelector");
609        let decoded: EventSelector =
610            serde_json::from_str(&json).expect("deserialize EventSelector");
611        assert_eq!(decoded, selector);
612    }
613
614    #[test]
615    fn load_minimal_artifact() {
616        let artifact = ContractArtifact::from_json(MINIMAL_ARTIFACT).expect("parse artifact");
617        assert_eq!(artifact.name, "TestContract");
618        assert_eq!(artifact.functions.len(), 1);
619        assert_eq!(artifact.functions[0].name, "increment");
620        assert_eq!(artifact.functions[0].function_type, FunctionType::Public);
621        assert!(!artifact.functions[0].is_initializer);
622        assert_eq!(artifact.functions[0].parameters.len(), 1);
623        assert_eq!(artifact.functions[0].parameters[0].name, "value");
624    }
625
626    #[test]
627    fn load_multi_function_artifact() {
628        let artifact =
629            ContractArtifact::from_json(MULTI_FUNCTION_ARTIFACT).expect("parse artifact");
630        assert_eq!(artifact.name, "TokenContract");
631        assert_eq!(artifact.functions.len(), 4);
632
633        let constructor = &artifact.functions[0];
634        assert_eq!(constructor.name, "constructor");
635        assert_eq!(constructor.function_type, FunctionType::Private);
636        assert!(constructor.is_initializer);
637        assert_eq!(constructor.parameters.len(), 2);
638
639        let transfer = &artifact.functions[1];
640        assert_eq!(transfer.name, "transfer");
641        assert_eq!(transfer.function_type, FunctionType::Private);
642        assert!(!transfer.is_static);
643
644        let balance = &artifact.functions[2];
645        assert_eq!(balance.name, "balance_of");
646        assert_eq!(balance.function_type, FunctionType::Utility);
647        assert!(balance.is_static);
648        assert_eq!(balance.return_types.len(), 1);
649
650        let supply = &artifact.functions[3];
651        assert_eq!(supply.name, "total_supply");
652        assert_eq!(supply.function_type, FunctionType::Public);
653        assert!(supply.is_static);
654    }
655
656    #[test]
657    fn find_function_by_name() {
658        let artifact =
659            ContractArtifact::from_json(MULTI_FUNCTION_ARTIFACT).expect("parse artifact");
660
661        let transfer = artifact.find_function("transfer").expect("find transfer");
662        assert_eq!(transfer.name, "transfer");
663        assert_eq!(transfer.function_type, FunctionType::Private);
664    }
665
666    #[test]
667    fn find_function_not_found() {
668        let artifact =
669            ContractArtifact::from_json(MULTI_FUNCTION_ARTIFACT).expect("parse artifact");
670
671        let result = artifact.find_function("nonexistent");
672        assert!(result.is_err());
673    }
674
675    #[test]
676    fn find_function_by_type() {
677        let artifact =
678            ContractArtifact::from_json(MULTI_FUNCTION_ARTIFACT).expect("parse artifact");
679
680        let balance = artifact
681            .find_function_by_type("balance_of", &FunctionType::Utility)
682            .expect("find balance_of as utility");
683        assert_eq!(balance.name, "balance_of");
684
685        let wrong_type = artifact.find_function_by_type("balance_of", &FunctionType::Public);
686        assert!(wrong_type.is_err());
687    }
688
689    #[test]
690    fn abi_value_field_roundtrip() {
691        let value = AbiValue::Field(Fr::from(1u64));
692        let json = serde_json::to_string(&value).expect("serialize AbiValue::Field");
693        assert!(json.contains("field"));
694        let decoded: AbiValue = serde_json::from_str(&json).expect("deserialize AbiValue");
695        assert_eq!(decoded, value);
696    }
697
698    #[test]
699    fn abi_value_boolean_roundtrip() {
700        let value = AbiValue::Boolean(true);
701        let json = serde_json::to_string(&value).expect("serialize");
702        let decoded: AbiValue = serde_json::from_str(&json).expect("deserialize");
703        assert_eq!(decoded, value);
704    }
705
706    #[test]
707    fn abi_value_integer_roundtrip() {
708        let value = AbiValue::Integer(42);
709        let json = serde_json::to_string(&value).expect("serialize");
710        let decoded: AbiValue = serde_json::from_str(&json).expect("deserialize");
711        assert_eq!(decoded, value);
712    }
713
714    #[test]
715    fn abi_value_array_roundtrip() {
716        let value = AbiValue::Array(vec![
717            AbiValue::Field(Fr::from(1u64)),
718            AbiValue::Field(Fr::from(2u64)),
719        ]);
720        let json = serde_json::to_string(&value).expect("serialize");
721        let decoded: AbiValue = serde_json::from_str(&json).expect("deserialize");
722        assert_eq!(decoded, value);
723    }
724
725    #[test]
726    fn abi_value_struct_roundtrip() {
727        let mut fields = BTreeMap::new();
728        fields.insert("x".to_owned(), AbiValue::Field(Fr::from(1u64)));
729        fields.insert("y".to_owned(), AbiValue::Integer(2));
730        let value = AbiValue::Struct(fields);
731        let json = serde_json::to_string(&value).expect("serialize");
732        let decoded: AbiValue = serde_json::from_str(&json).expect("deserialize");
733        assert_eq!(decoded, value);
734    }
735
736    #[test]
737    fn abi_type_struct_roundtrip() {
738        let typ = AbiType::Struct {
739            name: "Point".to_owned(),
740            fields: vec![
741                AbiParameter {
742                    name: "x".to_owned(),
743                    typ: AbiType::Field,
744                    visibility: None,
745                },
746                AbiParameter {
747                    name: "y".to_owned(),
748                    typ: AbiType::Field,
749                    visibility: None,
750                },
751            ],
752        };
753        let json = serde_json::to_string(&typ).expect("serialize AbiType::Struct");
754        let decoded: AbiType = serde_json::from_str(&json).expect("deserialize AbiType::Struct");
755        assert_eq!(decoded, typ);
756    }
757
758    #[test]
759    fn abi_type_array_roundtrip() {
760        let typ = AbiType::Array {
761            element: Box::new(AbiType::Field),
762            length: 10,
763        };
764        let json = serde_json::to_string(&typ).expect("serialize");
765        let decoded: AbiType = serde_json::from_str(&json).expect("deserialize");
766        assert_eq!(decoded, typ);
767    }
768
769    #[test]
770    fn artifact_from_invalid_json_fails() {
771        let result = ContractArtifact::from_json("not json");
772        assert!(result.is_err());
773    }
774
775    #[test]
776    fn from_signature_is_deterministic() {
777        let a = FunctionSelector::from_signature("sponsor_unconditionally()");
778        let b = FunctionSelector::from_signature("sponsor_unconditionally()");
779        assert_eq!(a, b);
780    }
781
782    #[test]
783    fn from_signature_different_inputs_differ() {
784        let a = FunctionSelector::from_signature("sponsor_unconditionally()");
785        let b = FunctionSelector::from_signature("claim_and_end_setup((Field),u128,Field,Field)");
786        assert_ne!(a, b);
787    }
788
789    #[test]
790    fn from_signature_empty_string() {
791        // Should not panic and should produce a deterministic result
792        let a = FunctionSelector::from_signature("");
793        let b = FunctionSelector::from_signature("");
794        assert_eq!(a, b);
795    }
796
797    #[test]
798    fn from_signature_produces_4_bytes() {
799        let selector = FunctionSelector::from_signature("transfer(Field,Field,u64)");
800        assert_eq!(selector.0.len(), 4);
801    }
802
803    #[test]
804    fn function_selector_roundtrips_through_field() {
805        let selector = FunctionSelector::from_signature("set_authorized(Field,bool)");
806        assert_eq!(FunctionSelector::from_field(selector.to_field()), selector);
807    }
808
809    #[test]
810    fn authorization_selector_roundtrips_through_field() {
811        let selector =
812            AuthorizationSelector::from_signature("CallAuthorization((Field),(u32),Field)");
813        assert_eq!(
814            AuthorizationSelector::from_field(selector.to_field()),
815            selector
816        );
817    }
818}