fvm_abi/
lib.rs

1mod info;
2
3use serde::Serialize;
4use serde::Deserialize;
5use scale_info::{IntoPortable, Registry, form::PortableForm, TypeDefPrimitive};
6use scale_info::form::{Form, MetaForm};
7use serde::de::DeserializeOwned;
8use strum::{EnumString, Display, EnumIter, IntoEnumIterator};
9use crate::info::generate_abi_type;
10
11/// ABI represent the contract abi
12#[derive(Serialize, Deserialize)]
13pub struct ABI {
14    pub contract: ContractMeta<PortableForm>,
15    pub methods: Vec<MethodInfo<PortableForm>>,
16    pub types: Vec<ABIType<PortableForm>>,
17}
18
19impl ABI {
20    pub fn new(meta: ContractMeta, methods: Vec<MethodInfo>) -> ABI {
21        let mut registry = Registry::new();
22        // registry go to other type
23        ABI {
24            contract: meta.into_portable(&mut registry),
25            methods: methods
26                .into_iter()
27                .map(|method| method.into_portable(&mut registry))
28                .collect::<Vec<_>>(),
29            types: generate_abi_type(registry),
30        }
31    }
32}
33
34
35#[derive(Serialize, Deserialize)]
36#[serde(bound(
37serialize = "F::Type: Serialize, F::String: Serialize",
38deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
39))]
40pub struct ContractMeta<F: Form = MetaForm> {
41    pub name: String,
42    pub constructor: ConstructorSpec<F>,
43}
44
45impl IntoPortable for ContractMeta {
46    type Output = ContractMeta<PortableForm>;
47
48    fn into_portable(self, registry: &mut Registry) -> Self::Output {
49        ContractMeta {
50            name: self.name,
51            constructor: ConstructorSpec {
52                input: self
53                    .constructor
54                    .input
55                    .into_iter()
56                    .map(|info| info.into_portable(registry))
57                    .collect::<Vec<_>>()
58            },
59        }
60    }
61}
62
63#[derive(Serialize, Deserialize)]
64pub struct MutexField {
65    pub field_name: String,
66    pub field_id: i32,
67    pub parallel_index: Vec<i32>,
68}
69
70#[derive(Serialize, Deserialize)]
71pub struct MutexCall {
72    pub address_index: i32,
73    pub address: String,
74    pub methods: Vec<String>,
75    pub cns_name: String,
76    pub cns_index: i32,
77}
78
79#[derive(Serialize, Deserialize)]
80#[serde(bound(
81serialize = "F::Type: Serialize, F::String: Serialize",
82deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
83))]
84pub struct MethodInfo<F: Form = MetaForm> {
85    pub name: String,
86    pub input: Vec<TypeInfo<F>>,
87    pub output: Vec<TypeInfo<F>>,
88    pub parallel_level: i32,
89    pub mutex_fields: Vec<MutexField>,
90    pub mutex_calls: Vec<MutexCall>,
91    pub method_calls: Vec<String>,
92}
93
94impl IntoPortable for MethodInfo {
95    type Output = MethodInfo<PortableForm>;
96
97    fn into_portable(self, registry: &mut Registry) -> Self::Output {
98        MethodInfo {
99            name: self.name,
100            input: self
101                .input
102                .into_iter()
103                .map(|info| info.into_portable(registry))
104                .collect::<Vec<_>>(),
105            output: self
106                .output
107                .into_iter()
108                .map(|info| info.into_portable(registry))
109                .collect::<Vec<_>>(),
110            parallel_level: self.parallel_level,
111            mutex_fields: self.mutex_fields
112                .into_iter()
113                .map(|x| { x.into() })
114                .collect::<Vec<_>>(),
115            mutex_calls: self.mutex_calls
116                .into_iter()
117                .map(|x| { x.into() })
118                .collect::<Vec<_>>(),
119            method_calls: self.method_calls,
120        }
121    }
122}
123
124#[derive(Serialize, Deserialize)]
125#[serde(bound(
126serialize = "F::Type: Serialize, F::String: Serialize",
127deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
128))]
129pub struct ConstructorSpec<F: Form = MetaForm> {
130    pub input: Vec<TypeInfo<F>>,
131}
132
133//todo: check cycle type
134#[derive(Serialize, Deserialize)]
135#[serde(bound(
136serialize = "F::Type: Serialize, F::String: Serialize",
137deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
138))]
139pub struct TypeInfo<F: Form = MetaForm> {
140    pub type_id: F::Type,
141}
142
143impl IntoPortable for TypeInfo {
144    type Output = TypeInfo<PortableForm>;
145
146    fn into_portable(self, registry: &mut Registry) -> Self::Output {
147        TypeInfo {
148            type_id: registry.register_type(&self.type_id),
149        }
150    }
151}
152
153#[derive(Serialize, Deserialize)]
154#[serde(bound(
155serialize = "F::Type: Serialize, F::String: Serialize",
156deserialize = "F::Type: DeserializeOwned, F::String: DeserializeOwned"
157))]
158#[serde(rename(serialize = "types"))]
159pub struct ABIType<F: Form = MetaForm> {
160    #[serde(rename(serialize = "id"))]
161    pub type_id: u32,
162    #[serde(rename(serialize = "type"))]
163    pub tp: TypeEnum,
164    #[serde(skip_serializing_if = "Option::is_none")]
165    pub fields: Option<Vec<TypeInfo<F>>>,
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub primitive: Option<String>,
168    #[serde(skip_serializing_if = "Option::is_none")]
169    pub array_len: Option<u32>,
170    #[serde(skip_serializing_if = "Option::is_none")]
171    pub variants: Option<Vec<Vec<TypeInfo<F>>>>,
172}
173
174#[derive(Serialize, Deserialize)]
175#[serde(rename_all(serialize = "lowercase"))]
176pub enum TypeEnum {
177    Primitive,
178    Struct,
179    Vec,
180    Array,
181    Tuple,
182    Enum,
183}
184
185#[derive(EnumString, Display, EnumIter, Debug, PartialEq)]
186pub enum PrimitiveType {
187    /// `bool` type
188    #[strum(serialize = "bool")]
189    Bool,
190    /// `char` type
191    #[strum(serialize = "char")]
192    Char,
193    /// `str` type
194    #[strum(serialize = "str")]
195    Str,
196    /// `u8`
197    #[strum(serialize = "u8")]
198    U8,
199    /// `u16`
200    #[strum(serialize = "u16")]
201    U16,
202    /// `u32`
203    #[strum(serialize = "u32")]
204    U32,
205    /// `u64`
206    #[strum(serialize = "u64")]
207    U64,
208    /// `u128`
209    #[strum(serialize = "u128")]
210    U128,
211    /// 256 bits unsigned int (no rust equivalent)
212    #[strum(serialize = "u256")]
213    U256,
214    /// `i8`
215    #[strum(serialize = "i8")]
216    I8,
217    /// `i16`
218    #[strum(serialize = "i16")]
219    I16,
220    /// `i32`
221    #[strum(serialize = "i32")]
222    I32,
223    /// `i64`
224    #[strum(serialize = "i64")]
225    I64,
226    /// `i128`
227    #[strum(serialize = "i128")]
228    I128,
229    /// 256 bits signed int (no rust equivalent)
230    #[strum(serialize = "i256")]
231    I256,
232}
233
234impl PrimitiveType {
235    pub fn to_primitive_type(tp: &TypeDefPrimitive) -> Self {
236        match tp {
237            TypeDefPrimitive::Bool => PrimitiveType::Bool,
238            TypeDefPrimitive::Char => PrimitiveType::Char,
239            TypeDefPrimitive::Str => PrimitiveType::Str,
240            TypeDefPrimitive::U8 => PrimitiveType::U8,
241            TypeDefPrimitive::U16 => PrimitiveType::U16,
242            TypeDefPrimitive::U32 => PrimitiveType::U32,
243            TypeDefPrimitive::U64 => PrimitiveType::U64,
244            TypeDefPrimitive::U128 => PrimitiveType::U128,
245            TypeDefPrimitive::U256 => PrimitiveType::U256,
246            TypeDefPrimitive::I8 => PrimitiveType::I8,
247            TypeDefPrimitive::I16 => PrimitiveType::I16,
248            TypeDefPrimitive::I32 => PrimitiveType::I32,
249            TypeDefPrimitive::I64 => PrimitiveType::I64,
250            TypeDefPrimitive::I128 => PrimitiveType::I128,
251            TypeDefPrimitive::I256 => PrimitiveType::I256,
252        }
253    }
254
255    pub fn is_primitive_type(type_name: &str) -> bool {
256        for tp in PrimitiveType::iter() {
257            if tp.to_string() == type_name {
258                return true;
259            }
260        }
261        false
262    }
263}
264
265#[cfg(test)]
266mod tests {
267    #![allow(dead_code)]
268
269    use crate::{ContractMeta, ConstructorSpec, MethodInfo, TypeInfo as ABITypeInfo, ABI, MutexField};
270    use scale_info::meta_type;
271    use scale_info::TypeInfo;
272
273    #[derive(TypeInfo)]
274    pub struct Student {
275        id: u32,
276        name: String,
277        list: Vec<Vec<String>>,
278    }
279
280
281    #[derive(TypeInfo)]
282    pub struct Info {
283        ages: Vec<[Student; 10]>,
284    }
285
286    #[test]
287    fn test_abi_serialized_null() {
288        let meta = ContractMeta {
289            name: "MyContract".to_string(),
290            constructor: ConstructorSpec {
291                input: vec![]
292            },
293        };
294        let methods = vec![];
295        let abi = ABI::new(meta, methods);
296        let json = serde_json::to_string_pretty(&abi).unwrap();
297        println!("{}", json);
298        assert_eq!(
299            json,
300            r#"{
301  "contract": {
302    "name": "MyContract",
303    "constructor": {
304      "input": []
305    }
306  },
307  "methods": [],
308  "types": []
309}"#);
310    }
311
312    #[derive(TypeInfo)]
313    enum IpAddr {
314        V4(u32, (u32, u32)),
315        V6(u32),
316    }
317
318    #[test]
319    fn test_abi_serialized_normal() {
320        let meta = ContractMeta {
321            name: "MyContract".to_string(),
322            constructor: ConstructorSpec {
323                input: vec![]
324            },
325        };
326
327        let methods = vec![
328            MethodInfo {
329                name: "add".to_string(),
330                input: vec![
331                    ABITypeInfo {
332                        // type_name: "u64".to_string(),
333                        type_id: meta_type::<u64>(),
334                    }
335                ],
336                output: vec![
337                    ABITypeInfo {
338                        // type_name: "u64".to_string(),
339                        type_id: meta_type::<u64>(),
340                    }
341                ],
342                parallel_level: 0,
343                mutex_fields: vec![],
344                method_calls: vec![],
345                mutex_calls: vec![],
346
347            },
348            MethodInfo {
349                name: "make_student".to_string(),
350                input: vec![
351                    ABITypeInfo {
352                        // type_name: "Student".to_string(),
353                        type_id: meta_type::<Student>(),
354                    },
355                    ABITypeInfo {
356                        // type_name: "Student".to_string(),
357                        type_id: meta_type::<Info>(),
358                    },
359                ],
360                output: vec![
361                    ABITypeInfo {
362                        // type_name: "u64".to_string(),
363                        type_id: meta_type::<u64>(),
364                    }
365                ],
366                parallel_level: 0,
367                mutex_fields: vec![],
368                method_calls: vec![],
369                mutex_calls: vec![],
370
371            },
372            MethodInfo {
373                name: "testTuple".to_string(),
374                input: vec![
375                    ABITypeInfo {
376                        type_id: meta_type::<(u32, u32)>()
377                    }
378                ],
379                output: vec![
380                    ABITypeInfo {
381                        type_id: meta_type::<IpAddr>()
382                    },
383                    ABITypeInfo {
384                        type_id: meta_type::<Option<u32>>()
385                    },
386                ],
387                parallel_level: 0,
388                mutex_fields: vec![
389                    MutexField { field_name: "".to_string(), parallel_index: vec![1, 2], field_id: 1 }
390                ],
391                method_calls: vec![],
392                mutex_calls: vec![],
393
394            },
395        ];
396
397        let abi = ABI::new(meta, methods);
398        let json = serde_json::to_string_pretty(&abi);
399        println!("{}", json.unwrap())
400    }
401
402    #[test]
403    fn test_meta_type() {
404        use scale_info::TypeInfo as Tp2;
405
406        let a = vec![
407            meta_type::<String>(),
408            meta_type::<&String>(),
409            meta_type::<&str>(),
410            meta_type::<&'static str>(),
411            meta_type::<bool>(),
412            meta_type::<&bool>(),
413            meta_type::<Box<bool>>(),
414            meta_type::<i128>(),
415            meta_type::<Student>(),
416            meta_type::<&Student>(),
417        ];
418
419        for tp in a {
420            println!("{:?}", tp.type_info().type_def())
421        }
422        println!("{:?}", <u32 as Tp2>::type_info().type_def())
423    }
424
425    #[test]
426    fn test1() {
427        let a = "Hello, world";
428        a.to_string().trim().trim_matches('\"').split(',').for_each(|x| {
429            println!("{}", x.trim())
430        })
431    }
432}