ccnext_query_builder/abi/
query_builder_for_function.rs

1use 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(matched_function: Function, tx: Transaction, data_field: FieldMetadata) -> Self {
19        Self { 
20            selected_offsets: vec![],
21            matched_function,
22            tx,
23            data_field
24        }
25    }
26
27    pub fn get_selected_offsets(self) -> Vec<(usize, usize)> {
28        self.selected_offsets.clone()
29    }
30
31    pub fn add_signature(&mut self) -> Result<&mut Self, QueryBuilderError> {
32        
33        if let Some(size) = self.data_field.size {
34            if size >= FUNCTION_SIGNATURE_SIZE {
35                self.selected_offsets.push((self.data_field.offset, FUNCTION_SIGNATURE_SIZE));
36                Ok(self)
37            } else {
38                Err(QueryBuilderError::DataFieldNotLongEnoughForSignatureExtraction)
39            }
40        } else {
41            Err(QueryBuilderError::DataFieldMissingSize)
42        }
43    }
44
45    pub fn add_argument(&mut self, name: String)  -> Result<&mut Self, QueryBuilderError> {
46
47
48        let mut argument_index: usize = 0;
49        let mut found_argument_index: Option<usize> = None;
50        for argument in self.matched_function.inputs.clone() {
51            if argument.name().eq(&name) {
52                found_argument_index = Some(argument_index);
53                break;
54            }
55            
56            argument_index += 1;
57        }
58
59        let data_size = match self.data_field.size {
60            Some(s) => s,
61            None => return Err(QueryBuilderError::DataFieldMissingSize)
62        };
63
64        let matched_argument_index = match found_argument_index {
65            Some(ma) => ma,
66            None => return Err(QueryBuilderError::CannotFindArgumentInFunction(self.matched_function.clone(), name))
67        };
68
69        // we have the types :)
70        let mut calldata_sol_types = Vec::new();
71        for input in self.matched_function.inputs.clone() {
72            match input.resolve() {
73                Ok(st) => {
74                    calldata_sol_types.push(st);
75                }
76                Err(_) => {
77                    return Err(QueryBuilderError::FailedToResolveSolTypesOfMatchedFunction(self.matched_function.clone()));
78                }
79            }
80        }
81
82        // now we need to decode the contract call, but only from the slice of FUNCTION_SIGNITURE_SIZE...onwards..
83        let data = self.tx.inner.input().as_ref();
84        let sliced_data = &data[FUNCTION_SIGNATURE_SIZE..data_size];
85
86        // compute the offsets :)
87        let data_computed_offsets = match compute_abi_offsets(calldata_sol_types, sliced_data.into()) {
88            Ok(offsets) => offsets,
89            Err(_) => return Err(QueryBuilderError::FailedToComputeOffsetsForCalldata),
90        };
91
92        match data_computed_offsets.get(matched_argument_index) {
93            Some(field) => {
94                match field.size {
95                    Some(size) => {
96                        self.selected_offsets.push((self.data_field.offset + FUNCTION_SIGNATURE_SIZE + field.offset, size));
97                        Ok(self)
98                    }
99                    None => Err(QueryBuilderError::TryingToGetSizeOfDynamicType)
100                }
101            }
102            None => Err(QueryBuilderError::MissingDataInCalldataOffsets)
103        }
104    }
105
106}