1use 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::Integer { .. }, AbiValue::Field(field)) => {
60 out.push(*field);
61 Ok(())
62 }
63 (AbiType::Array { element, length }, AbiValue::Array(items)) => {
64 if items.len() != *length {
65 return Err(Error::Abi(format!(
66 "expected array of length {}, got {}",
67 length,
68 items.len()
69 )));
70 }
71 for item in items {
72 encode_value(element, item, out)?;
73 }
74 Ok(())
75 }
76 (AbiType::String { length }, AbiValue::String(string)) => {
77 let bytes = string.as_bytes();
78 if bytes.len() > *length {
79 return Err(Error::Abi(format!(
80 "string exceeds fixed ABI length {}",
81 length
82 )));
83 }
84 for byte in bytes {
85 out.push(Fr::from(u64::from(*byte)));
86 }
87 for _ in bytes.len()..*length {
88 out.push(Fr::zero());
89 }
90 Ok(())
91 }
92 (AbiType::Struct { fields, .. }, _) => {
93 if is_address_struct(typ) {
95 match value {
96 AbiValue::Field(f) => {
97 out.push(*f);
98 Ok(())
99 }
100 AbiValue::Struct(map) => {
101 let f =
102 map.get("inner")
103 .or_else(|| map.get("address"))
104 .ok_or_else(|| {
105 Error::Abi(
106 "address struct must have 'inner' or 'address' field"
107 .into(),
108 )
109 })?;
110 encode_value(&AbiType::Field, f, out)
111 }
112 _ => Err(Error::Abi(
113 "expected Field or Struct for address type".into(),
114 )),
115 }
116 } else if is_function_selector_struct(typ) {
117 match value {
118 AbiValue::Integer(v) => {
119 out.push(Fr::from(*v as u64));
120 Ok(())
121 }
122 AbiValue::Field(f) => {
123 out.push(*f);
124 Ok(())
125 }
126 AbiValue::Struct(map) => {
127 let f = map
128 .get("value")
129 .or_else(|| map.get("inner"))
130 .ok_or_else(|| {
131 Error::Abi(
132 "FunctionSelector struct must have 'value' or 'inner' field"
133 .into(),
134 )
135 })?;
136 encode_value(&AbiType::Field, f, out)
137 }
138 _ => Err(Error::Abi(
139 "expected Integer, Field, or Struct for FunctionSelector".into(),
140 )),
141 }
142 } else if is_wrapped_field_struct(typ) {
143 match value {
144 AbiValue::Field(f) => {
145 out.push(*f);
146 Ok(())
147 }
148 AbiValue::Struct(map) => {
149 let f = map.get("inner").ok_or_else(|| {
150 Error::Abi("wrapped field struct must have 'inner' field".into())
151 })?;
152 encode_value(&AbiType::Field, f, out)
153 }
154 _ => Err(Error::Abi(
155 "expected Field or Struct for wrapped field type".into(),
156 )),
157 }
158 } else if is_bounded_vec_struct(typ) {
159 let items = match value {
160 AbiValue::Array(items) => items,
161 AbiValue::Struct(map) => {
162 if let Some(AbiValue::Array(items)) = map.get("storage") {
163 items
164 } else {
165 return Err(Error::Abi(
166 "BoundedVec struct must have 'storage' array field".into(),
167 ));
168 }
169 }
170 _ => return Err(Error::Abi("expected Array or Struct for BoundedVec".into())),
171 };
172 let (elem_type, max_len) = match &fields[0].typ {
173 AbiType::Array { element, length } => (element.as_ref(), *length),
174 _ => return Err(Error::Abi("BoundedVec storage must be an Array".into())),
175 };
176 if items.len() > max_len {
177 return Err(Error::Abi(format!(
178 "BoundedVec has {} items but max capacity is {}",
179 items.len(),
180 max_len
181 )));
182 }
183 for item in items {
184 encode_value(elem_type, item, out)?;
185 }
186 let elem_size = abi_type_size(elem_type);
187 for _ in 0..(max_len - items.len()) * elem_size {
188 out.push(Fr::zero());
189 }
190 out.push(Fr::from(items.len() as u64));
191 Ok(())
192 } else if is_option_struct(typ) {
193 match value {
194 AbiValue::Struct(map) => {
195 let is_some = map.get("_is_some");
196 let val = map.get("_value");
197 match (is_some, val) {
198 (Some(is_some_val), Some(value_val)) => {
199 encode_value(&fields[0].typ, is_some_val, out)?;
200 encode_value(&fields[1].typ, value_val, out)?;
201 Ok(())
202 }
203 _ => Err(Error::Abi(
204 "Option struct must have '_is_some' and '_value' fields".into(),
205 )),
206 }
207 }
208 _ => {
209 out.push(Fr::one()); encode_value(&fields[1].typ, value, out)?;
212 Ok(())
213 }
214 }
215 } else if let AbiValue::Struct(values) = value {
216 for field in fields {
218 let field_value = values.get(&field.name).ok_or_else(|| {
219 Error::Abi(format!("missing struct field '{}'", field.name))
220 })?;
221 encode_value(&field.typ, field_value, out)?;
222 }
223 Ok(())
224 } else {
225 Err(Error::Abi("argument type/value mismatch".to_owned()))
226 }
227 }
228 (AbiType::Tuple { elements }, AbiValue::Tuple(values)) => {
229 if elements.len() != values.len() {
230 return Err(Error::Abi(format!(
231 "expected tuple of length {}, got {}",
232 elements.len(),
233 values.len()
234 )));
235 }
236 for (element, value) in elements.iter().zip(values) {
237 encode_value(element, value, out)?;
238 }
239 Ok(())
240 }
241 _ => Err(Error::Abi("argument type/value mismatch".to_owned())),
242 }
243}