1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use casper_types::CLType;
use odra_types::{
    contract_def::{Argument, Entrypoint, Event},
    Type
};
use serde::{Deserialize, Serialize};

pub fn gen_schema(
    contract_ident: &str,
    contract_entrypoints: &[Entrypoint],
    events: &[Event]
) -> String {
    let schema = Schema {
        name: contract_ident.to_owned(),
        entrypoints: contract_entrypoints.iter().map(Into::into).collect(),
        events: events.iter().map(Into::into).collect()
    };
    serde_json::to_string_pretty(&schema).expect("Failed to serialize schema")
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Schema {
    name: String,
    entrypoints: Vec<EntrypointDef>,
    events: Vec<EventDef>
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct EntrypointDef {
    name: String,
    is_mutable: bool,
    args: Vec<ElemDef>,
    return_ty: CLType
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct EventDef {
    name: String,
    fields: Vec<ElemDef>
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct ElemDef {
    name: String,
    ty: CLType
}

impl From<&Entrypoint> for EntrypointDef {
    fn from(ep: &Entrypoint) -> Self {
        EntrypointDef {
            name: ep.ident.clone(),
            is_mutable: ep.is_mut,
            args: ep.args.iter().map(Into::into).collect(),
            return_ty: type_to_cl_type(&ep.ret)
        }
    }
}

impl From<&Argument> for ElemDef {
    fn from(arg: &Argument) -> Self {
        ElemDef {
            name: arg.ident.clone(),
            ty: type_to_cl_type(&arg.ty)
        }
    }
}

impl From<&Event> for EventDef {
    fn from(event: &Event) -> Self {
        EventDef {
            name: event.ident.clone(),
            fields: event.args.iter().map(Into::into).collect()
        }
    }
}

fn type_to_cl_type(ty: &Type) -> CLType {
    match ty {
        Type::Address => CLType::Key,
        Type::Bool => CLType::Bool,
        Type::I32 => CLType::I32,
        Type::I64 => CLType::I64,
        Type::U8 => CLType::U8,
        Type::U32 => CLType::U32,
        Type::U64 => CLType::U64,
        Type::U128 => CLType::U128,
        Type::U256 => CLType::U256,
        Type::U512 => CLType::U512,
        Type::Unit => CLType::Unit,
        Type::String => CLType::String,
        Type::Option(v) => CLType::Option(Box::new(type_to_cl_type(v))),
        Type::Result { ok, err } => CLType::Result {
            ok: Box::new(type_to_cl_type(ok)),
            err: Box::new(type_to_cl_type(err))
        },
        Type::Map { key, value } => CLType::Map {
            key: Box::new(type_to_cl_type(key)),
            value: Box::new(type_to_cl_type(value))
        },
        Type::Tuple1(v) => CLType::Tuple1(v.clone().map(|v| Box::new(type_to_cl_type(&v)))),
        Type::Tuple2(v) => CLType::Tuple2(v.clone().map(|v| Box::new(type_to_cl_type(&v)))),
        Type::Tuple3(v) => CLType::Tuple3(v.clone().map(|v| Box::new(type_to_cl_type(&v)))),
        Type::Any => CLType::Any,
        Type::Vec(v) => CLType::List(Box::new(type_to_cl_type(v))),
        Type::ByteArray(v) => CLType::ByteArray(*v),
        Type::Slice(ty) => CLType::List(Box::new(type_to_cl_type(ty)))
    }
}