fuels_core/codec/
abi_formatter.rs1use std::{collections::HashMap, io::Read};
2
3use fuel_abi_types::abi::unified_program::UnifiedProgramABI;
4use itertools::Itertools;
5
6use crate::{error, types::param_types::ParamType, Result};
7
8use super::{ABIDecoder, DecoderConfig};
9
10pub struct ABIFormatter {
11 functions: HashMap<String, Vec<ParamType>>,
12 configurables: Vec<(String, ParamType)>,
13 decoder: ABIDecoder,
14}
15
16impl ABIFormatter {
17 pub fn has_fn(&self, fn_name: &str) -> bool {
18 self.functions.contains_key(fn_name)
19 }
20
21 pub fn with_decoder_config(mut self, config: DecoderConfig) -> Self {
22 self.decoder = ABIDecoder::new(config);
23 self
24 }
25
26 pub fn from_abi(abi: UnifiedProgramABI) -> Result<Self> {
27 let functions = abi
28 .functions
29 .iter()
30 .map(|fun| (fun.name.clone(), fun.clone()))
31 .collect::<HashMap<_, _>>();
32
33 let type_lookup = abi
34 .types
35 .iter()
36 .map(|decl| (decl.type_id, decl.clone()))
37 .collect::<HashMap<_, _>>();
38
39 let functions = functions
40 .into_iter()
41 .map(|(name, fun)| {
42 let args = fun
43 .inputs
44 .iter()
45 .map(|type_application| {
46 ParamType::try_from_type_application(type_application, &type_lookup)
47 })
48 .collect::<Result<Vec<_>>>()?;
49 Ok((name.clone(), args))
50 })
51 .collect::<Result<HashMap<_, _>>>()?;
52
53 let configurables = abi
54 .configurables
55 .into_iter()
56 .flatten()
57 .sorted_by_key(|c| c.offset)
58 .map(|c| {
59 let param_type =
60 ParamType::try_from_type_application(&c.application, &type_lookup)?;
61
62 Ok((c.name, param_type))
63 })
64 .collect::<Result<Vec<_>>>()?;
65
66 Ok(Self {
67 functions,
68 decoder: ABIDecoder::default(),
69 configurables,
70 })
71 }
72
73 pub fn from_json_abi(abi: impl AsRef<str>) -> Result<Self> {
74 let parsed_abi = UnifiedProgramABI::from_json_abi(abi.as_ref())?;
75 Self::from_abi(parsed_abi)
76 }
77
78 pub fn decode_fn_args<R: Read>(&self, fn_name: &str, data: R) -> Result<Vec<String>> {
79 let args = self
80 .functions
81 .get(fn_name)
82 .ok_or_else(|| error!(Codec, "Function '{}' not found in the ABI", fn_name))?;
83
84 self.decoder.decode_multiple_as_debug_str(args, data)
85 }
86
87 pub fn decode_configurables<R: Read>(
88 &self,
89 configurable_data: R,
90 ) -> Result<Vec<(String, String)>> {
91 let param_types = self
92 .configurables
93 .iter()
94 .map(|(_, param_type)| param_type)
95 .cloned()
96 .collect::<Vec<_>>();
97
98 let decoded = self
99 .decoder
100 .decode_multiple_as_debug_str(¶m_types, configurable_data)?
101 .into_iter()
102 .zip(&self.configurables)
103 .map(|(value, (name, _))| (name.clone(), value))
104 .collect();
105
106 Ok(decoded)
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use crate::types::errors::Error;
113
114 use super::*;
115
116 #[test]
117 fn gracefully_handles_missing_fn() {
118 let decoder = ABIFormatter::from_abi(UnifiedProgramABI::default()).unwrap();
120
121 let err = decoder
123 .decode_fn_args("non_existent_fn", [].as_slice())
124 .unwrap_err();
125
126 let Error::Codec(err) = err else {
128 panic!("Expected Codec error, got {:?}", err);
129 };
130
131 assert_eq!(err, "Function 'non_existent_fn' not found in the ABI");
132 }
133}