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 inner_value = 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 match inner_value {
138 AbiValue::Field(f) => {
139 out.push(*f);
140 Ok(())
141 }
142 AbiValue::Integer(v) => {
143 out.push(Fr::from(*v as u64));
144 Ok(())
145 }
146 _ => Err(Error::Abi(
147 "FunctionSelector inner must be Field or Integer".into(),
148 )),
149 }
150 }
151 _ => Err(Error::Abi(
152 "expected Integer, Field, or Struct for FunctionSelector".into(),
153 )),
154 }
155 } else if is_wrapped_field_struct(typ) {
156 match value {
157 AbiValue::Field(f) => {
158 out.push(*f);
159 Ok(())
160 }
161 AbiValue::Struct(map) => {
162 let f = map.get("inner").ok_or_else(|| {
163 Error::Abi("wrapped field struct must have 'inner' field".into())
164 })?;
165 encode_value(&AbiType::Field, f, out)
166 }
167 _ => Err(Error::Abi(
168 "expected Field or Struct for wrapped field type".into(),
169 )),
170 }
171 } else if is_bounded_vec_struct(typ) {
172 let items = match value {
173 AbiValue::Array(items) => items,
174 AbiValue::Struct(map) => {
175 if let Some(AbiValue::Array(items)) = map.get("storage") {
176 items
177 } else {
178 return Err(Error::Abi(
179 "BoundedVec struct must have 'storage' array field".into(),
180 ));
181 }
182 }
183 _ => return Err(Error::Abi("expected Array or Struct for BoundedVec".into())),
184 };
185 let (elem_type, max_len) = match &fields[0].typ {
186 AbiType::Array { element, length } => (element.as_ref(), *length),
187 _ => return Err(Error::Abi("BoundedVec storage must be an Array".into())),
188 };
189 if items.len() > max_len {
190 return Err(Error::Abi(format!(
191 "BoundedVec has {} items but max capacity is {}",
192 items.len(),
193 max_len
194 )));
195 }
196 for item in items {
197 encode_value(elem_type, item, out)?;
198 }
199 let elem_size = abi_type_size(elem_type);
200 for _ in 0..(max_len - items.len()) * elem_size {
201 out.push(Fr::zero());
202 }
203 out.push(Fr::from(items.len() as u64));
204 Ok(())
205 } else if is_option_struct(typ) {
206 match value {
207 AbiValue::Struct(map) => {
208 let is_some = map.get("_is_some");
209 let val = map.get("_value");
210 match (is_some, val) {
211 (Some(is_some_val), Some(value_val)) => {
212 encode_value(&fields[0].typ, is_some_val, out)?;
213 encode_value(&fields[1].typ, value_val, out)?;
214 Ok(())
215 }
216 _ => Err(Error::Abi(
217 "Option struct must have '_is_some' and '_value' fields".into(),
218 )),
219 }
220 }
221 _ => {
222 out.push(Fr::one()); encode_value(&fields[1].typ, value, out)?;
225 Ok(())
226 }
227 }
228 } else if let AbiValue::Struct(values) = value {
229 for field in fields {
231 let field_value = values.get(&field.name).ok_or_else(|| {
232 Error::Abi(format!("missing struct field '{}'", field.name))
233 })?;
234 encode_value(&field.typ, field_value, out)?;
235 }
236 Ok(())
237 } else {
238 Err(Error::Abi("argument type/value mismatch".to_owned()))
239 }
240 }
241 (AbiType::Tuple { elements }, AbiValue::Tuple(values)) => {
242 if elements.len() != values.len() {
243 return Err(Error::Abi(format!(
244 "expected tuple of length {}, got {}",
245 elements.len(),
246 values.len()
247 )));
248 }
249 for (element, value) in elements.iter().zip(values) {
250 encode_value(element, value, out)?;
251 }
252 Ok(())
253 }
254 _ => Err(Error::Abi("argument type/value mismatch".to_owned())),
255 }
256}