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(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 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 let data = self.tx.inner.input().as_ref();
84 let sliced_data = &data[FUNCTION_SIGNATURE_SIZE..data_size];
85
86 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}