aztec_core/abi/
decoder.rs1use std::collections::BTreeMap;
2
3use super::checkers::{
4 abi_type_size, is_aztec_address_struct, is_bounded_vec_struct, is_eth_address_struct,
5 is_option_struct,
6};
7use super::types::AbiType;
8use crate::types::Fr;
9use crate::Error;
10
11#[derive(Clone, Debug, PartialEq)]
13pub enum AbiDecoded {
14 Field(Fr),
16 Boolean(bool),
18 Integer(i128),
20 Array(Vec<AbiDecoded>),
22 String(String),
24 Struct(BTreeMap<String, AbiDecoded>),
26 Tuple(Vec<AbiDecoded>),
28 Address(crate::types::AztecAddress),
30 None,
32}
33
34pub fn decode_from_abi(types: &[AbiType], fields: &[Fr]) -> Result<AbiDecoded, Error> {
39 let mut cursor = 0;
40 if types.len() == 1 {
41 return decode_next(&types[0], fields, &mut cursor);
42 }
43 let results: Vec<AbiDecoded> = types
44 .iter()
45 .map(|t| decode_next(t, fields, &mut cursor))
46 .collect::<Result<_, _>>()?;
47 Ok(AbiDecoded::Tuple(results))
48}
49
50fn take(fields: &[Fr], cursor: &mut usize) -> Result<Fr, Error> {
51 if *cursor >= fields.len() {
52 return Err(Error::Abi(format!(
53 "insufficient fields for decoding: cursor {} >= len {}",
54 cursor,
55 fields.len()
56 )));
57 }
58 let fr = fields[*cursor];
59 *cursor += 1;
60 Ok(fr)
61}
62
63fn decode_next(typ: &AbiType, fields: &[Fr], cursor: &mut usize) -> Result<AbiDecoded, Error> {
64 match typ {
65 AbiType::Field => {
66 let fr = take(fields, cursor)?;
67 Ok(AbiDecoded::Field(fr))
68 }
69 AbiType::Boolean => {
70 let fr = take(fields, cursor)?;
71 Ok(AbiDecoded::Boolean(!fr.is_zero()))
72 }
73 AbiType::Integer { sign, width } => {
74 let fr = take(fields, cursor)?;
75 let bytes = fr.to_be_bytes();
76 let raw = u128::from_be_bytes(bytes[16..].try_into().unwrap());
77 if sign == "signed" {
78 let value = if *width >= 128 {
79 raw as i128
82 } else if raw >= (1u128 << (*width - 1)) {
83 raw as i128 - (1i128 << *width)
84 } else {
85 raw as i128
86 };
87 Ok(AbiDecoded::Integer(value))
88 } else {
89 Ok(AbiDecoded::Integer(raw as i128))
90 }
91 }
92 AbiType::Array { element, length } => {
93 let mut items = Vec::with_capacity(*length);
94 for _ in 0..*length {
95 items.push(decode_next(element, fields, cursor)?);
96 }
97 Ok(AbiDecoded::Array(items))
98 }
99 AbiType::String { length } => {
100 let mut chars = Vec::with_capacity(*length);
101 for _ in 0..*length {
102 let fr = take(fields, cursor)?;
103 let byte = fr.to_usize() as u8;
104 if byte == 0 {
105 for _ in (chars.len() + 1)..*length {
107 take(fields, cursor)?;
108 }
109 break;
110 }
111 chars.push(char::from(byte));
112 }
113 Ok(AbiDecoded::String(chars.into_iter().collect()))
114 }
115 AbiType::Struct {
116 fields: struct_fields,
117 ..
118 } => {
119 if is_aztec_address_struct(typ) {
120 let fr = take(fields, cursor)?;
121 Ok(AbiDecoded::Address(crate::types::AztecAddress(fr)))
122 } else if is_eth_address_struct(typ) {
123 let fr = take(fields, cursor)?;
124 Ok(AbiDecoded::Field(fr))
125 } else if is_option_struct(typ) {
126 let is_some_fr = take(fields, cursor)?;
127 if is_some_fr.is_zero() {
128 let value_size = abi_type_size(&struct_fields[1].typ);
130 for _ in 0..value_size {
131 take(fields, cursor)?;
132 }
133 Ok(AbiDecoded::None)
134 } else {
135 let value = decode_next(&struct_fields[1].typ, fields, cursor)?;
136 Ok(value)
137 }
138 } else if is_bounded_vec_struct(typ) {
139 let (elem_type, max_len) = match &struct_fields[0].typ {
140 AbiType::Array { element, length } => (element.as_ref(), *length),
141 _ => return Err(Error::Abi("BoundedVec storage must be an Array".into())),
142 };
143 let mut items = Vec::with_capacity(max_len);
144 for _ in 0..max_len {
145 items.push(decode_next(elem_type, fields, cursor)?);
146 }
147 let len_fr = take(fields, cursor)?;
148 let actual_len = len_fr.to_usize();
149 items.truncate(actual_len);
150 Ok(AbiDecoded::Array(items))
151 } else {
152 let mut map = BTreeMap::new();
154 for field in struct_fields {
155 let value = decode_next(&field.typ, fields, cursor)?;
156 map.insert(field.name.clone(), value);
157 }
158 Ok(AbiDecoded::Struct(map))
159 }
160 }
161 AbiType::Tuple { elements } => {
162 let mut items = Vec::with_capacity(elements.len());
163 for elem in elements {
164 items.push(decode_next(elem, fields, cursor)?);
165 }
166 Ok(AbiDecoded::Tuple(items))
167 }
168 }
169}