aztec_core/abi/
encoder.rs1use super::checkers::{
2 abi_type_size, is_address_struct, is_bounded_vec_struct, is_function_selector_struct,
3 is_option_struct, is_wrapped_field_struct,
4};
5use super::types::{AbiType, AbiValue, FunctionArtifact};
6use crate::types::Fr;
7use crate::Error;
8
9pub fn encode_arguments(function: &FunctionArtifact, args: &[AbiValue]) -> Result<Vec<Fr>, Error> {
11 if function.parameters.len() != args.len() {
12 return Err(Error::Abi(format!(
13 "function '{}' expects {} argument(s), got {}",
14 function.name,
15 function.parameters.len(),
16 args.len()
17 )));
18 }
19
20 let mut out = Vec::new();
21 for (param, value) in function.parameters.iter().zip(args) {
22 encode_value(¶m.typ, value, &mut out)?;
23 }
24 Ok(out)
25}
26
27pub fn encode_value(typ: &AbiType, value: &AbiValue, out: &mut Vec<Fr>) -> Result<(), Error> {
28 match (typ, value) {
29 (AbiType::Field, AbiValue::Field(field)) => {
30 out.push(*field);
31 Ok(())
32 }
33 (AbiType::Boolean, AbiValue::Boolean(boolean)) => {
34 out.push(if *boolean { Fr::one() } else { Fr::zero() });
35 Ok(())
36 }
37 (AbiType::Integer { sign, width }, AbiValue::Integer(integer)) => {
38 if sign == "signed" && *integer < 0 {
39 let encoded = if *width >= 128 {
40 *integer as u128
41 } else {
42 (*integer + (1i128 << *width)) as u128
43 };
44 let bytes = encoded.to_be_bytes();
45 let mut padded = [0u8; 32];
46 padded[16..].copy_from_slice(&bytes);
47 out.push(Fr::from(padded));
48 } else {
49 let bytes = (*integer as u128).to_be_bytes();
50 let mut padded = [0u8; 32];
51 padded[16..].copy_from_slice(&bytes);
52 out.push(Fr::from(padded));
53 }
54 Ok(())
55 }
56 (AbiType::Array { element, length }, AbiValue::Array(items)) => {
57 if items.len() != *length {
58 return Err(Error::Abi(format!(
59 "expected array of length {}, got {}",
60 length,
61 items.len()
62 )));
63 }
64 for item in items {
65 encode_value(element, item, out)?;
66 }
67 Ok(())
68 }
69 (AbiType::String { length }, AbiValue::String(string)) => {
70 let bytes = string.as_bytes();
71 if bytes.len() > *length {
72 return Err(Error::Abi(format!(
73 "string exceeds fixed ABI length {}",
74 length
75 )));
76 }
77 for byte in bytes {
78 out.push(Fr::from(u64::from(*byte)));
79 }
80 for _ in bytes.len()..*length {
81 out.push(Fr::zero());
82 }
83 Ok(())
84 }
85 (AbiType::Struct { fields, .. }, _) => {
86 if is_address_struct(typ) {
88 match value {
89 AbiValue::Field(f) => {
90 out.push(*f);
91 Ok(())
92 }
93 AbiValue::Struct(map) => {
94 let f =
95 map.get("inner")
96 .or_else(|| map.get("address"))
97 .ok_or_else(|| {
98 Error::Abi(
99 "address struct must have 'inner' or 'address' field"
100 .into(),
101 )
102 })?;
103 encode_value(&AbiType::Field, f, out)
104 }
105 _ => Err(Error::Abi(
106 "expected Field or Struct for address type".into(),
107 )),
108 }
109 } else if is_function_selector_struct(typ) {
110 match value {
111 AbiValue::Integer(v) => {
112 out.push(Fr::from(*v as u64));
113 Ok(())
114 }
115 AbiValue::Field(f) => {
116 out.push(*f);
117 Ok(())
118 }
119 AbiValue::Struct(map) => {
120 let f = map
121 .get("value")
122 .or_else(|| map.get("inner"))
123 .ok_or_else(|| {
124 Error::Abi(
125 "FunctionSelector struct must have 'value' or 'inner' field"
126 .into(),
127 )
128 })?;
129 encode_value(&AbiType::Field, f, out)
130 }
131 _ => Err(Error::Abi(
132 "expected Integer, Field, or Struct for FunctionSelector".into(),
133 )),
134 }
135 } else if is_wrapped_field_struct(typ) {
136 match value {
137 AbiValue::Field(f) => {
138 out.push(*f);
139 Ok(())
140 }
141 AbiValue::Struct(map) => {
142 let f = map.get("inner").ok_or_else(|| {
143 Error::Abi("wrapped field struct must have 'inner' field".into())
144 })?;
145 encode_value(&AbiType::Field, f, out)
146 }
147 _ => Err(Error::Abi(
148 "expected Field or Struct for wrapped field type".into(),
149 )),
150 }
151 } else if is_bounded_vec_struct(typ) {
152 let items = match value {
153 AbiValue::Array(items) => items,
154 AbiValue::Struct(map) => {
155 if let Some(AbiValue::Array(items)) = map.get("storage") {
156 items
157 } else {
158 return Err(Error::Abi(
159 "BoundedVec struct must have 'storage' array field".into(),
160 ));
161 }
162 }
163 _ => return Err(Error::Abi("expected Array or Struct for BoundedVec".into())),
164 };
165 let (elem_type, max_len) = match &fields[0].typ {
166 AbiType::Array { element, length } => (element.as_ref(), *length),
167 _ => return Err(Error::Abi("BoundedVec storage must be an Array".into())),
168 };
169 if items.len() > max_len {
170 return Err(Error::Abi(format!(
171 "BoundedVec has {} items but max capacity is {}",
172 items.len(),
173 max_len
174 )));
175 }
176 for item in items {
177 encode_value(elem_type, item, out)?;
178 }
179 let elem_size = abi_type_size(elem_type);
180 for _ in 0..(max_len - items.len()) * elem_size {
181 out.push(Fr::zero());
182 }
183 out.push(Fr::from(items.len() as u64));
184 Ok(())
185 } else if is_option_struct(typ) {
186 match value {
187 AbiValue::Struct(map) => {
188 let is_some = map.get("_is_some");
189 let val = map.get("_value");
190 match (is_some, val) {
191 (Some(is_some_val), Some(value_val)) => {
192 encode_value(&fields[0].typ, is_some_val, out)?;
193 encode_value(&fields[1].typ, value_val, out)?;
194 Ok(())
195 }
196 _ => Err(Error::Abi(
197 "Option struct must have '_is_some' and '_value' fields".into(),
198 )),
199 }
200 }
201 _ => {
202 out.push(Fr::one()); encode_value(&fields[1].typ, value, out)?;
205 Ok(())
206 }
207 }
208 } else if let AbiValue::Struct(values) = value {
209 for field in fields {
211 let field_value = values.get(&field.name).ok_or_else(|| {
212 Error::Abi(format!("missing struct field '{}'", field.name))
213 })?;
214 encode_value(&field.typ, field_value, out)?;
215 }
216 Ok(())
217 } else {
218 Err(Error::Abi("argument type/value mismatch".to_owned()))
219 }
220 }
221 (AbiType::Tuple { elements }, AbiValue::Tuple(values)) => {
222 if elements.len() != values.len() {
223 return Err(Error::Abi(format!(
224 "expected tuple of length {}, got {}",
225 elements.len(),
226 values.len()
227 )));
228 }
229 for (element, value) in elements.iter().zip(values) {
230 encode_value(element, value, out)?;
231 }
232 Ok(())
233 }
234 _ => Err(Error::Abi("argument type/value mismatch".to_owned())),
235 }
236}