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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//! Data structures for the Casper Contract Schema.

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

mod ty;
pub use ty::NamedCLType;

/// Contract definition.
#[derive(Serialize, Deserialize, JsonSchema, Debug)]
pub struct ContractSchema {
    pub casper_contract_schema_version: u8,
    pub toolchain: String,
    pub authors: Vec<String>,
    pub repository: Option<String>,
    pub homepage: Option<String>,
    pub contract_name: String,
    pub contract_version: String,
    pub types: Vec<CustomType>,
    pub errors: Vec<UserError>,
    pub entry_points: Vec<Entrypoint>,
    pub events: Vec<Event>,
    pub call: Option<CallMethod>,
}

impl ContractSchema {
    /// Returns the JSON representation of the contract schema.
    pub fn as_json(&self) -> Option<String> {
        serde_json::to_string_pretty(self).ok()
    }
}

/// Entrypoint definition.
#[derive(Serialize, Deserialize, JsonSchema, Debug)]
pub struct Entrypoint {
    pub name: String,
    pub description: Option<String>,
    pub is_mutable: bool,
    pub arguments: Vec<Argument>,
    pub return_ty: Type,
    pub is_contract_context: bool,
    pub access: Access,
}

/// Entrypoint's argument definition.
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]
pub struct Argument {
    pub name: String,
    pub description: Option<String>,
    pub ty: Type,
    pub optional: bool,
}

impl Argument {
    pub fn new(name: &str, description: &str, ty: NamedCLType) -> Self {
        Self {
            name: String::from(name),
            description: parse_description(description),
            ty: ty.into(),
            optional: false,
        }
    }

    pub fn new_opt(name: &str, description: &str, ty: NamedCLType) -> Self {
        Self {
            name: String::from(name),
            description: parse_description(description),
            ty: ty.into(),
            optional: true,
        }
    }
}

/// Access control definition.
#[derive(Serialize, Deserialize, JsonSchema, Debug)]
#[serde(rename_all = "snake_case")]
pub enum Access {
    Public,
    Groups(Vec<String>),
}

/// Struct member definition.
#[derive(PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, JsonSchema, Debug)]
pub struct StructMember {
    pub name: String,
    pub description: Option<String>,
    pub ty: Type,
}

impl StructMember {
    /// Creates a new struct member.
    pub fn new(name: &str, description: &str, ty: NamedCLType) -> Self {
        Self {
            name: String::from(name),
            description: parse_description(description),
            ty: ty.into(),
        }
    }
}

fn parse_description(description: &str) -> Option<String> {
    if description.is_empty() {
        None
    } else {
        Some(String::from(description))
    }
}

/// Type definition.
#[derive(PartialEq, PartialOrd, Ord, Eq, Clone, Serialize, Deserialize, JsonSchema, Debug)]
#[serde(rename_all = "snake_case")]
pub struct Type(pub NamedCLType);

impl From<NamedCLType> for Type {
    fn from(cl_type: NamedCLType) -> Self {
        Self(cl_type)
    }
}

/// Custom type name definition.
#[derive(PartialEq, PartialOrd, Ord, Eq, Clone, Serialize, Deserialize, JsonSchema, Debug)]
pub struct TypeName(pub String);

impl From<&str> for TypeName {
    fn from(name: &str) -> Self {
        Self(String::from(name))
    }
}

impl From<String> for TypeName {
    fn from(name: String) -> Self {
        Self(name)
    }
}

impl TypeName {
    /// Creates a new type name.
    pub fn new(name: &str) -> Self {
        Self(String::from(name))
    }
}

/// Custom type definition. It covers structs and enums.
#[derive(PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, JsonSchema, Debug)]
#[serde(rename_all = "snake_case")]
pub enum CustomType {
    Struct {
        name: TypeName,
        description: Option<String>,
        members: Vec<StructMember>,
    },
    Enum {
        name: TypeName,
        description: Option<String>,
        variants: Vec<EnumVariant>,
    },
}

/// Enum variant definition.
#[derive(PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, JsonSchema, Debug)]
pub struct EnumVariant {
    pub name: String,
    pub description: Option<String>,
    pub discriminant: u16,
    pub ty: Type,
}

/// Event definition.
#[derive(PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, JsonSchema, Debug)]
pub struct Event {
    pub name: String,
    pub ty: TypeName,
}

impl Event {
    /// Creates a new event.
    pub fn new(name: &str, ty: &str) -> Self {
        Self {
            name: String::from(name),
            ty: ty.into(),
        }
    }
}

/// User error definition.
#[derive(PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, JsonSchema, Debug)]
pub struct UserError {
    pub name: String,
    pub description: Option<String>,
    pub discriminant: u16,
}

impl UserError {
    /// Creates a new user error variant.
    pub fn new(name: &str, desc: &str, discriminant: u16) -> Self {
        Self {
            name: String::from(name),
            description: parse_description(desc),
            discriminant,
        }
    }
}

/// Call method definition.
#[derive(Serialize, Deserialize, JsonSchema, Debug)]
pub struct CallMethod {
    pub wasm_file_name: String,
    pub description: Option<String>,
    pub arguments: Vec<Argument>,
}

impl CallMethod {
    /// Creates a new call method definition.
    pub fn new(wasm_file_name: &str, description: &str, arguments: Vec<Argument>) -> Self {
        Self {
            wasm_file_name: String::from(wasm_file_name),
            description: parse_description(description),
            arguments,
        }
    }
}