ccnext_query_builder/abi/
utils.rs1use crate::abi::models::FieldMetadata;
2use alloy::{
3 dyn_abi::{Decoder, DynSolType},
4 sol_types::Error,
5};
6
7pub(crate) const WORD_SIZE: usize = 32;
8
9#[derive(Debug)]
10pub enum ComputeAbiOffsetsError {
11 FailedToDecode(Error),
12}
13
14pub fn compute_abi_offsets(
15 types: Vec<DynSolType>,
16 abi: &[u8],
17) -> Result<Vec<FieldMetadata>, ComputeAbiOffsetsError> {
18 let mut reader = Decoder::new(abi, false);
19 match decode_offset_recursive(&mut reader, types, 0) {
20 Ok(result) => Ok(result),
21 Err(err) => Err(ComputeAbiOffsetsError::FailedToDecode(err)),
22 }
23}
24
25fn decode_offset_recursive(
26 reader: &mut Decoder,
27 types: Vec<DynSolType>,
28 base_offset: usize,
29) -> Result<Vec<FieldMetadata>, Error> {
30 let mut result = Vec::new();
31 for sol_type in types {
32 match sol_type.clone() {
33 DynSolType::Bool
34 | DynSolType::Int(_)
35 | DynSolType::Uint(_)
36 | DynSolType::FixedBytes(_)
37 | DynSolType::Address => {
38 let relative_offset = reader.offset();
39 let absolute_offset = base_offset + relative_offset;
40 let word = reader.take_word()?;
41 result.push(FieldMetadata {
42 sol_type: sol_type.clone(),
43 offset: absolute_offset,
44 size: Some(WORD_SIZE),
45 is_dynamic: false,
46 value: Some(word.0.to_vec()),
47 children: vec![],
48 });
49 }
50 DynSolType::Bytes | DynSolType::String => {
51 let offset = reader.take_offset()?;
52 let mut sub_reader = reader.child(offset)?;
53 let size = sub_reader.take_offset()?; let data = sub_reader.take_slice(size)?;
55 let dynamic_field_absolute_offset = base_offset + offset + WORD_SIZE;
56 result.push(FieldMetadata {
57 sol_type: sol_type.clone(),
58 offset: dynamic_field_absolute_offset,
59 size: Some(size),
60 is_dynamic: true,
61 value: Some(data.to_vec()),
62 children: vec![],
63 });
64 }
65 DynSolType::Array(array_element_sol_type_boxed) => {
66 let field_dynamic_offset = reader.take_offset()?; let absolute_offset = base_offset + field_dynamic_offset;
69 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;
74 let array_components: Vec<DynSolType> = match array_element_sol_type_unboxed.clone()
76 {
77 DynSolType::Tuple(dyn_sol_types) => dyn_sol_types,
80 other => {
81 let mut types = Vec::new();
82 for _ in 0..number_of_elements {
83 types.push(other.clone());
84 }
85 types
86 }
87 };
88
89 let mut children = Vec::new();
90 if is_dynamic(array_element_sol_type_unboxed.clone()) {
91 let mut dynamic_array_relative_offsets = Vec::new();
94 for _ in 0..number_of_elements {
95 let child_element_offset = sub_reader.take_offset()?;
96 dynamic_array_relative_offsets.push(child_element_offset);
97 }
98
99 let is_bytes_or_string = matches!(
101 array_element_sol_type_unboxed,
102 DynSolType::Bytes | DynSolType::String
103 );
104
105 for array_element_offset in dynamic_array_relative_offsets {
106 if is_bytes_or_string {
107 let absolute_data_offset = base_offset
111 + field_dynamic_offset
112 + WORD_SIZE
113 + array_element_offset;
114 let mut data_sub_reader = reader.child(absolute_data_offset)?;
115 let length = data_sub_reader.take_offset()?; let data = data_sub_reader.take_slice(length)?;
117
118 children.push(FieldMetadata {
119 sol_type: array_element_sol_type_unboxed.clone(),
120 offset: absolute_data_offset + WORD_SIZE, size: Some(length),
122 is_dynamic: true,
123 value: Some(data.to_vec()),
124 children: vec![],
125 });
126 } else {
127 let semi_absolute_positon =
133 field_dynamic_offset + array_element_offset + WORD_SIZE;
134 let mut child_element_sub_reader =
135 reader.child(semi_absolute_positon)?;
136
137 let position = base_offset + semi_absolute_positon;
139 let children_of_child = decode_offset_recursive(
141 &mut child_element_sub_reader,
142 array_components.clone(),
143 position,
144 )?;
145
146 children.push(FieldMetadata {
147 sol_type: array_element_sol_type_unboxed.clone(),
148 offset: position,
149 size: None,
150 is_dynamic: true,
151 value: None,
152 children: children_of_child,
153 });
154 }
155 }
156 } else {
157 children = decode_offset_recursive(
161 &mut sub_reader,
162 array_components,
163 absolute_offset,
164 )?;
165 }
166
167 result.push(FieldMetadata {
168 sol_type: sol_type.clone(),
169 offset: absolute_offset,
170 size: None,
171 is_dynamic: true,
172 value: None,
173 children,
174 });
175 }
176 DynSolType::FixedArray(array_element_sol_type_boxed, number_of_elements) => {
177 let array_element_sol_type_unboxed = *array_element_sol_type_boxed;
180 let array_components: Vec<DynSolType> = match array_element_sol_type_unboxed.clone()
182 {
183 DynSolType::Tuple(dyn_sol_types) => dyn_sol_types,
185 other => {
186 let mut types = Vec::new();
187 for _ in 0..number_of_elements {
188 types.push(other.clone());
189 }
190 types
191 }
192 };
193
194 if is_dynamic(array_element_sol_type_unboxed.clone()) {
196 let offset = reader.take_offset()?;
198 let absolute_offset = base_offset + offset;
199 let mut sub_reader = reader.child(offset)?;
201 let children = decode_offset_recursive(
202 &mut sub_reader,
203 array_components,
204 absolute_offset,
205 )?;
206 result.push(FieldMetadata {
207 sol_type: sol_type.clone(),
208 offset: absolute_offset,
209 size: None,
210 is_dynamic: true,
211 value: None,
212 children,
213 });
214 } else {
215 let absolute_offset = base_offset + reader.offset();
217 let children =
218 decode_offset_recursive(reader, array_components, absolute_offset)?;
219 result.push(FieldMetadata {
220 sol_type: sol_type.clone(),
221 offset: absolute_offset,
222 size: None,
223 is_dynamic: false,
224 value: None,
225 children,
226 });
227 }
228 }
229 DynSolType::Tuple(tuple_components) => {
230 if is_dynamic(sol_type.clone()) {
231 let offset_of_tuple = base_offset + reader.offset();
232 let offset_of_dynamic_data = reader.take_offset()?;
233 let mut sub_reader = reader.child(offset_of_dynamic_data)?;
234 let children = decode_offset_recursive(
235 &mut sub_reader,
236 tuple_components,
237 offset_of_dynamic_data,
238 )?;
239 result.push(FieldMetadata {
240 sol_type: sol_type.clone(),
241 offset: offset_of_tuple,
242 size: None,
243 is_dynamic: true,
244 value: None,
245 children,
246 });
247 } else {
248 let offset_of_tuple = base_offset + reader.offset();
249 let children = decode_offset_recursive(reader, tuple_components, base_offset)?;
250 result.push(FieldMetadata {
251 sol_type: sol_type.clone(),
252 offset: offset_of_tuple,
253 size: None,
254 is_dynamic: false,
255 value: None,
256 children,
257 });
258 }
259 }
260 DynSolType::Function => {
261 return Err(Error::custom(
262 "Cannot decode functions, with this decoder..",
263 ));
264 }
265 }
266 }
267 Ok(result)
268}
269
270pub fn is_dynamic(sol_type: DynSolType) -> bool {
271 match sol_type {
272 DynSolType::Bool => false,
273 DynSolType::Int(_) => false,
274 DynSolType::Uint(_) => false,
275 DynSolType::FixedBytes(_) => false,
276 DynSolType::Address => false,
277 DynSolType::Function => todo!(),
278 DynSolType::Bytes => true,
279 DynSolType::String => true,
280 DynSolType::Array(_array_children) => true,
281 DynSolType::FixedArray(array_children, _array_size) => is_dynamic(*array_children),
282 DynSolType::Tuple(tuple_components) => {
283 for tuple_component in tuple_components {
284 if is_dynamic(tuple_component) {
285 return true;
286 }
287 }
288 false
289 }
290 }
291}
292
293pub(crate) fn make_offsets_absolute(field: &mut FieldMetadata, base_offset: usize) {
295 field.offset += base_offset;
296 for child in &mut field.children {
297 make_offsets_absolute(child, base_offset);
298 }
299}