ccnext_query_builder/abi/
query_builder_for_function.rs1use alloy::{consensus::Transaction as _, dyn_abi::Specifier, rpc::types::Transaction};
2use alloy_json_abi::Function;
3
4use crate::abi::utils::compute_abi_offsets;
5
6use super::models::{FieldMetadata, QueryBuilderError};
7
8const FUNCTION_SIGNATURE_SIZE: usize = 4;
9
10pub struct QueryBuilderForFunction {
11 selected_offsets: Vec<(usize, usize)>,
12 matched_function: Function,
13 tx: Transaction,
14 data_field: FieldMetadata,
15}
16
17impl QueryBuilderForFunction {
18 pub(crate) fn new(
19 matched_function: Function,
20 tx: Transaction,
21 data_field: FieldMetadata,
22 ) -> Self {
23 Self {
24 selected_offsets: vec![],
25 matched_function,
26 tx,
27 data_field,
28 }
29 }
30
31 pub fn get_selected_offsets(self) -> Vec<(usize, usize)> {
32 self.selected_offsets.clone()
33 }
34
35 pub fn add_signature(&mut self) -> Result<&mut Self, QueryBuilderError> {
36 if let Some(size) = self.data_field.size {
37 if size >= FUNCTION_SIGNATURE_SIZE {
38 self.selected_offsets
39 .push((self.data_field.offset, FUNCTION_SIGNATURE_SIZE));
40 Ok(self)
41 } else {
42 Err(QueryBuilderError::DataFieldNotLongEnoughForSignatureExtraction)
43 }
44 } else {
45 Err(QueryBuilderError::DataFieldMissingSize)
46 }
47 }
48
49 pub fn add_argument(&mut self, name: String) -> Result<&mut Self, QueryBuilderError> {
50 let mut found_argument_index: Option<usize> = None;
51 for (argument_index, argument) in self.matched_function.inputs.iter().enumerate() {
52 if argument.name().eq(&name) {
53 found_argument_index = Some(argument_index);
54 break;
55 }
56 }
57
58 let data_size = match self.data_field.size {
59 Some(s) => s,
60 None => return Err(QueryBuilderError::DataFieldMissingSize),
61 };
62
63 let matched_argument_index = match found_argument_index {
64 Some(ma) => ma,
65 None => {
66 return Err(QueryBuilderError::CannotFindArgumentInFunction(
67 self.matched_function.clone(),
68 name,
69 ))
70 }
71 };
72
73 let mut calldata_sol_types = Vec::new();
75 for input in self.matched_function.inputs.clone() {
76 match input.resolve() {
77 Ok(st) => {
78 calldata_sol_types.push(st);
79 }
80 Err(_) => {
81 return Err(QueryBuilderError::FailedToResolveSolTypesOfMatchedFunction(
82 self.matched_function.clone(),
83 ));
84 }
85 }
86 }
87
88 let data = self.tx.inner.input().as_ref();
90 let sliced_data = &data[FUNCTION_SIGNATURE_SIZE..data_size];
91
92 let data_computed_offsets =
94 match compute_abi_offsets(calldata_sol_types, sliced_data.into()) {
95 Ok(offsets) => offsets,
96 Err(_) => return Err(QueryBuilderError::FailedToComputeOffsetsForCalldata),
97 };
98
99 match data_computed_offsets.get(matched_argument_index) {
100 Some(field) => match field.size {
101 Some(size) => {
102 self.selected_offsets.push((
103 self.data_field.offset + FUNCTION_SIGNATURE_SIZE + field.offset,
104 size,
105 ));
106 Ok(self)
107 }
108 None => Err(QueryBuilderError::TryingToGetSizeOfDynamicType),
109 },
110 None => Err(QueryBuilderError::MissingDataInCalldataOffsets),
111 }
112 }
113}