ccnext_query_builder/abi/
utils.rs1use alloy::{
2 dyn_abi::{Decoder, DynSolType},
3 sol_types::Error,
4};
5
6use super::models::FieldMetadata;
7
8const WORD_SIZE: usize = 32;
9
10#[derive(Debug)]
11pub enum ComputeAbiOffsetsError {
12 FailedToDecode(Error),
13}
14
15pub fn compute_abi_offsets(
16 types: Vec<DynSolType>,
17 abi: Vec<u8>,
18) -> Result<Vec<FieldMetadata>, ComputeAbiOffsetsError> {
19 let mut reader = Decoder::new(&abi, false);
20
21 match decode_offset_recursive(&mut reader, types, 0) {
22 Ok(result) => Ok(result),
23 Err(err) => Err(ComputeAbiOffsetsError::FailedToDecode(err)),
24 }
25}
26
27fn decode_offset_recursive(
28 reader: &mut Decoder,
29 types: Vec<DynSolType>,
30 base_offset: usize,
31) -> Result<Vec<FieldMetadata>, Error> {
32 let mut result = Vec::new();
33 for sol_type in types {
34 match sol_type.clone() {
35 DynSolType::Bool
36 | DynSolType::Int(_)
37 | DynSolType::Uint(_)
38 | DynSolType::FixedBytes(_)
39 | DynSolType::Address => {
40 let relative_offset = reader.offset();
41 let absolute_offset = base_offset + relative_offset;
42 let word = reader.take_word()?;
43 result.push(FieldMetadata {
44 offset: absolute_offset,
45 children: vec![],
46 is_dynamic: false,
47 size: Some(WORD_SIZE),
48 sol_type,
49 value: Some(word.0.to_vec()),
50 });
51 }
52 DynSolType::Bytes | DynSolType::String => {
53 let offset = reader.take_offset()?;
54 let mut sub_reader = reader.child(offset)?;
55 let size = sub_reader.take_offset()?; let data = sub_reader.take_slice(size)?;
57 let dynamic_field_absolute_offset = base_offset + offset + WORD_SIZE;
58 result.push(FieldMetadata {
59 offset: dynamic_field_absolute_offset,
60 children: vec![],
61 is_dynamic: true,
62 size: Some(size),
63 sol_type,
64 value: Some(data.to_vec()),
65 });
66 }
67 DynSolType::Array(array_element_sol_type_boxed) => {
68 let field_dynamic_offset = reader.take_offset()?; let absolute_offset = base_offset + field_dynamic_offset;
71 let mut sub_reader = reader.child(field_dynamic_offset)?; let number_of_elements = sub_reader.take_offset()?; let array_element_sol_type_unboxed = *array_element_sol_type_boxed;
77
78 let array_components: Vec<DynSolType> = match array_element_sol_type_unboxed.clone()
80 {
81 DynSolType::Tuple(dyn_sol_types) => dyn_sol_types,
84 other => {
85 let mut types = Vec::new();
86 for _ in 0..number_of_elements {
87 types.push(other.clone());
88 }
89 types
90 }
91 };
92
93 let mut children = Vec::new();
94 if is_dynamic(array_element_sol_type_unboxed.clone()) {
95 let mut dynamic_array_relative_offsets = Vec::new();
98 for _ in 0..number_of_elements {
99 let child_element_offset = sub_reader.take_offset()?;
100 dynamic_array_relative_offsets.push(child_element_offset);
101 }
102
103 for array_element_offset in dynamic_array_relative_offsets {
106 let semi_absolute_positon =
108 field_dynamic_offset + array_element_offset + WORD_SIZE;
109 let mut child_element_sub_reader = reader.child(semi_absolute_positon)?;
110
111 let position = base_offset + semi_absolute_positon;
113
114 let children_of_child = decode_offset_recursive(
116 &mut child_element_sub_reader,
117 array_components.clone(),
118 position,
119 )?;
120
121 children.push(FieldMetadata {
122 children: children_of_child,
123 is_dynamic: true,
124 offset: position,
125 size: None,
126 sol_type: array_element_sol_type_unboxed.clone(),
127 value: None,
128 });
129 }
130 } else {
131 children = decode_offset_recursive(
135 &mut sub_reader,
136 array_components,
137 absolute_offset,
138 )?;
139 }
140
141 result.push(FieldMetadata {
142 children,
143 is_dynamic: true,
144 offset: absolute_offset,
145 size: None,
146 sol_type,
147 value: None,
148 });
149 }
150 DynSolType::FixedArray(array_element_sol_type_boxed, number_of_elements) => {
151 let array_element_sol_type_unboxed = *array_element_sol_type_boxed;
154
155 let array_components: Vec<DynSolType> = match array_element_sol_type_unboxed.clone()
157 {
158 DynSolType::Tuple(dyn_sol_types) => dyn_sol_types,
160 other => {
161 let mut types = Vec::new();
162 for _ in 0..number_of_elements {
163 types.push(other.clone());
164 }
165 types
166 }
167 };
168
169 if is_dynamic(array_element_sol_type_unboxed.clone()) {
171 let offset = reader.take_offset()?;
173 let absolute_offset = base_offset + offset;
174
175 let mut sub_reader = reader.child(offset)?;
177 let children = decode_offset_recursive(
178 &mut sub_reader,
179 array_components,
180 absolute_offset,
181 )?;
182 result.push(FieldMetadata {
183 children,
184 is_dynamic: true,
185 offset: absolute_offset,
186 size: None,
187 value: None,
188 sol_type,
189 });
190 } else {
191 let absolute_offset = base_offset + reader.offset();
193 let children =
194 decode_offset_recursive(reader, array_components, absolute_offset)?;
195 result.push(FieldMetadata {
196 children,
197 is_dynamic: false,
198 offset: absolute_offset,
199 size: None,
200 value: None,
201 sol_type,
202 });
203 }
204 }
205 DynSolType::Tuple(tuple_components) => {
206 if is_dynamic(sol_type.clone()) {
207 let offset_of_tuple = base_offset + reader.offset();
208 let offset_of_dynamic_data = reader.take_offset()?;
209 let mut sub_reader = reader.child(offset_of_dynamic_data)?;
210 let children = decode_offset_recursive(
211 &mut sub_reader,
212 tuple_components,
213 offset_of_dynamic_data,
214 )?;
215 result.push(FieldMetadata {
216 offset: offset_of_tuple,
217 children,
218 is_dynamic: true,
219 size: None,
220 sol_type,
221 value: None,
222 });
223 } else {
224 let offset_of_tuple = base_offset + reader.offset();
225 let children = decode_offset_recursive(reader, tuple_components, base_offset)?;
226 result.push(FieldMetadata {
227 offset: offset_of_tuple,
228 children,
229 is_dynamic: false,
230 size: None,
231 sol_type,
232 value: None,
233 });
234 }
235 }
236 DynSolType::Function => {
237 return Err(Error::custom(
238 "Cannot decode functions, with this decoder..",
239 ));
240 }
241 }
242 }
243
244 Ok(result)
245}
246
247pub fn is_dynamic(sol_type: DynSolType) -> bool {
248 match sol_type {
270 DynSolType::Bool => false,
271 DynSolType::Int(_) => false,
272 DynSolType::Uint(_) => false,
273 DynSolType::FixedBytes(_) => false,
274 DynSolType::Address => false,
275 DynSolType::Function => todo!(),
276 DynSolType::Bytes => true,
277 DynSolType::String => true,
278 DynSolType::Array(_array_children) => true,
279 DynSolType::FixedArray(array_children, _array_size) => is_dynamic(*array_children),
280 DynSolType::Tuple(tuple_components) => {
281 for tuple_component in tuple_components {
282 if is_dynamic(tuple_component) {
283 return true;
284 }
285 }
286
287 false
288 }
289 }
290}