1use fe_common::utils::keccak;
2
3use serde::Serialize;
4
5use super::types::AbiType;
6
7#[derive(Serialize, Debug, PartialEq, Eq, Clone)]
9#[serde(rename_all = "lowercase")]
10pub enum StateMutability {
11 Pure,
12 View,
13 Nonpayable,
14 Payable,
15}
16
17pub enum SelfParam {
18 None,
19 Imm,
20 Mut,
21}
22pub enum CtxParam {
23 None,
24 Imm,
25 Mut,
26}
27
28impl StateMutability {
29 pub fn from_self_and_ctx_params(self_: SelfParam, ctx: CtxParam) -> Self {
30 match (self_, ctx) {
40 (SelfParam::None, CtxParam::None) => StateMutability::Pure,
41 (SelfParam::None, CtxParam::Imm) => StateMutability::View,
42 (SelfParam::None, CtxParam::Mut) => StateMutability::Payable,
43 (SelfParam::Imm, CtxParam::None) => StateMutability::View,
44 (SelfParam::Imm, CtxParam::Imm) => StateMutability::View,
45 (SelfParam::Imm, CtxParam::Mut) => StateMutability::Payable,
46 (SelfParam::Mut, _) => StateMutability::Payable,
47 }
48 }
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
52pub struct AbiFunction {
53 #[serde(rename = "type")]
54 func_type: AbiFunctionType,
55 name: String,
56 inputs: Vec<AbiFunctionParamInner>,
57 outputs: Vec<AbiFunctionParamInner>,
58 #[serde(rename = "stateMutability")]
59 state_mutability: StateMutability,
60}
61
62impl AbiFunction {
63 pub fn new(
64 func_type: AbiFunctionType,
65 name: String,
66 args: Vec<(String, AbiType)>,
67 ret_ty: Option<AbiType>,
68 state_mutability: StateMutability,
69 ) -> Self {
70 let inputs = args
71 .into_iter()
72 .map(|(arg_name, arg_ty)| AbiFunctionParamInner::new(arg_name, arg_ty))
73 .collect();
74 let outputs = ret_ty.map_or_else(Vec::new, |ret_ty| {
75 vec![AbiFunctionParamInner::new("".into(), ret_ty)]
76 });
77
78 Self {
79 func_type,
80 name,
81 inputs,
82 outputs,
83 state_mutability,
84 }
85 }
86
87 pub fn selector(&self) -> AbiFunctionSelector {
88 AbiFunctionSelector::new(self)
89 }
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
93#[serde(rename_all = "lowercase")]
94pub enum AbiFunctionType {
95 Function,
96 Constructor,
97 Receive,
98 Payable,
99 Fallback,
100}
101
102pub struct AbiFunctionSelector {
103 selector_sig: String,
104}
105
106impl AbiFunctionSelector {
107 fn new(func_sig: &AbiFunction) -> Self {
108 let selector_sig = format!(
109 "{}({})",
110 func_sig.name,
111 func_sig
112 .inputs
113 .iter()
114 .map(|param| param.ty.selector_type_name())
115 .collect::<Vec<_>>()
116 .join(",")
117 );
118
119 Self { selector_sig }
120 }
121
122 pub fn selector_signature(&self) -> &str {
123 &self.selector_sig
124 }
125
126 pub fn selector_raw(&self) -> [u8; 4] {
127 keccak::full_as_bytes(self.selector_sig.as_bytes())[..4]
128 .try_into()
129 .unwrap()
130 }
131
132 pub fn hex(&self) -> String {
134 keccak::partial(self.selector_sig.as_bytes(), 4)
135 }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
139struct AbiFunctionParamInner {
140 name: String,
141 #[serde(flatten)]
142 ty: AbiType,
143}
144
145impl AbiFunctionParamInner {
146 fn new(name: String, ty: AbiType) -> Self {
147 Self { name, ty }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use crate::types::AbiTupleField;
154
155 use super::*;
156 use serde_test::{assert_ser_tokens, Token};
157
158 fn simple_tuple() -> AbiType {
159 let u16_ty = AbiType::UInt(16);
160 let bool_ty = AbiType::Bool;
161 let field1 = AbiTupleField::new("field1".into(), u16_ty);
162 let field2 = AbiTupleField::new("field2".into(), bool_ty);
163
164 AbiType::Tuple(vec![field1, field2])
165 }
166
167 fn test_func(state_mutability: StateMutability) -> AbiFunction {
168 let i32_ty = AbiType::Int(32);
169 let tuple_ty = simple_tuple();
170 let u64_ty = AbiType::UInt(64);
171
172 AbiFunction::new(
173 AbiFunctionType::Function,
174 "test_func".into(),
175 vec![("arg1".into(), i32_ty), ("arg2".into(), tuple_ty)],
176 Some(u64_ty),
177 state_mutability,
178 )
179 }
180
181 #[test]
182 fn serialize_func() {
183 let func = test_func(StateMutability::Payable);
184
185 assert_ser_tokens(
186 &func,
187 &[
188 Token::Struct {
189 name: "AbiFunction",
190 len: 5,
191 },
192 Token::Str("type"),
193 Token::UnitVariant {
194 name: "AbiFunctionType",
195 variant: "function",
196 },
197 Token::String("name"),
198 Token::String("test_func"),
199 Token::Str("inputs"),
200 Token::Seq { len: Some(2) },
201 Token::Map { len: None },
202 Token::String("name"),
203 Token::String("arg1"),
204 Token::String("type"),
205 Token::String("int32"),
206 Token::MapEnd,
207 Token::Map { len: None },
208 Token::String("name"),
209 Token::String("arg2"),
210 Token::String("type"),
211 Token::String("tuple"),
212 Token::String("components"),
213 Token::Seq { len: Some(2) },
214 Token::Map { len: None },
215 Token::String("name"),
216 Token::String("field1"),
217 Token::String("type"),
218 Token::String("uint16"),
219 Token::MapEnd,
220 Token::Map { len: None },
221 Token::String("name"),
222 Token::String("field2"),
223 Token::String("type"),
224 Token::String("bool"),
225 Token::MapEnd,
226 Token::SeqEnd,
227 Token::MapEnd,
228 Token::SeqEnd,
229 Token::Str("outputs"),
230 Token::Seq { len: Some(1) },
231 Token::Map { len: None },
232 Token::String("name"),
233 Token::String(""),
234 Token::String("type"),
235 Token::String("uint64"),
236 Token::MapEnd,
237 Token::SeqEnd,
238 Token::Str("stateMutability"),
239 Token::UnitVariant {
240 name: "StateMutability",
241 variant: "payable",
242 },
243 Token::StructEnd,
244 ],
245 )
246 }
247
248 #[test]
249 fn test_state_mutability() {
250 assert_eq!(
251 StateMutability::from_self_and_ctx_params(SelfParam::None, CtxParam::None),
252 StateMutability::Pure
253 );
254 assert_eq!(
255 StateMutability::from_self_and_ctx_params(SelfParam::None, CtxParam::Imm),
256 StateMutability::View
257 );
258 assert_eq!(
259 StateMutability::from_self_and_ctx_params(SelfParam::None, CtxParam::Mut),
260 StateMutability::Payable
261 );
262
263 assert_eq!(
264 StateMutability::from_self_and_ctx_params(SelfParam::Imm, CtxParam::None),
265 StateMutability::View
266 );
267 assert_eq!(
268 StateMutability::from_self_and_ctx_params(SelfParam::Imm, CtxParam::Imm),
269 StateMutability::View
270 );
271 assert_eq!(
272 StateMutability::from_self_and_ctx_params(SelfParam::Imm, CtxParam::Mut),
273 StateMutability::Payable
274 );
275
276 assert_eq!(
277 StateMutability::from_self_and_ctx_params(SelfParam::Mut, CtxParam::None),
278 StateMutability::Payable
279 );
280 assert_eq!(
281 StateMutability::from_self_and_ctx_params(SelfParam::Mut, CtxParam::Imm),
282 StateMutability::Payable
283 );
284 assert_eq!(
285 StateMutability::from_self_and_ctx_params(SelfParam::Mut, CtxParam::Mut),
286 StateMutability::Payable
287 );
288
289 let pure_func = test_func(StateMutability::Pure);
290 assert_eq!(pure_func.state_mutability, StateMutability::Pure);
291
292 let impure_func = test_func(StateMutability::Payable);
293 assert_eq!(impure_func.state_mutability, StateMutability::Payable);
294 }
295
296 #[test]
297 fn func_selector() {
298 let func = test_func(StateMutability::Payable);
299 let selector = func.selector();
300
301 debug_assert_eq!(
302 selector.selector_signature(),
303 "test_func(int32,(uint16,bool))"
304 );
305 debug_assert_eq!(selector.hex(), "79c3c8b2");
306 }
307}