casper_contract_schema/
lib.rs

1//! Data structures for the Casper Contract Schema.
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6mod ty;
7pub use ty::NamedCLType;
8
9/// Contract definition.
10#[derive(Serialize, Deserialize, JsonSchema, Debug)]
11pub struct ContractSchema {
12    pub casper_contract_schema_version: u8,
13    pub toolchain: String,
14    pub authors: Vec<String>,
15    pub repository: Option<String>,
16    pub homepage: Option<String>,
17    pub contract_name: String,
18    pub contract_version: String,
19    pub types: Vec<CustomType>,
20    pub errors: Vec<UserError>,
21    pub entry_points: Vec<Entrypoint>,
22    pub events: Vec<Event>,
23    pub call: Option<CallMethod>,
24}
25
26impl ContractSchema {
27    /// Returns the JSON representation of the contract schema.
28    pub fn as_json(&self) -> Option<String> {
29        serde_json::to_string_pretty(self).ok()
30    }
31}
32
33/// Entrypoint definition.
34#[derive(Serialize, Deserialize, JsonSchema, Debug)]
35pub struct Entrypoint {
36    pub name: String,
37    pub description: Option<String>,
38    pub is_mutable: bool,
39    pub arguments: Vec<Argument>,
40    pub return_ty: Type,
41    pub is_contract_context: bool,
42    pub access: Access,
43}
44
45/// Entrypoint's argument definition.
46#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]
47pub struct Argument {
48    pub name: String,
49    pub description: Option<String>,
50    pub ty: Type,
51    pub optional: bool,
52}
53
54impl Argument {
55    pub fn new(name: &str, description: &str, ty: NamedCLType) -> Self {
56        Self {
57            name: String::from(name),
58            description: parse_description(description),
59            ty: ty.into(),
60            optional: false,
61        }
62    }
63
64    pub fn new_opt(name: &str, description: &str, ty: NamedCLType) -> Self {
65        Self {
66            name: String::from(name),
67            description: parse_description(description),
68            ty: ty.into(),
69            optional: true,
70        }
71    }
72}
73
74/// Access control definition.
75#[derive(Serialize, Deserialize, JsonSchema, Debug)]
76#[serde(rename_all = "snake_case")]
77pub enum Access {
78    Public,
79    Groups(Vec<String>),
80}
81
82/// Struct member definition.
83#[derive(
84    PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, JsonSchema, Debug, Clone, Hash,
85)]
86pub struct StructMember {
87    pub name: String,
88    pub description: Option<String>,
89    pub ty: Type,
90}
91
92impl StructMember {
93    /// Creates a new struct member.
94    pub fn new(name: &str, description: &str, ty: NamedCLType) -> Self {
95        Self {
96            name: String::from(name),
97            description: parse_description(description),
98            ty: ty.into(),
99        }
100    }
101}
102
103fn parse_description(description: &str) -> Option<String> {
104    if description.is_empty() {
105        None
106    } else {
107        Some(String::from(description))
108    }
109}
110
111/// Type definition.
112#[derive(
113    PartialEq, PartialOrd, Ord, Eq, Clone, Serialize, Deserialize, JsonSchema, Debug, Hash,
114)]
115#[serde(rename_all = "snake_case")]
116pub struct Type(pub NamedCLType);
117
118impl From<NamedCLType> for Type {
119    fn from(cl_type: NamedCLType) -> Self {
120        Self(cl_type)
121    }
122}
123
124/// Custom type name definition.
125#[derive(
126    PartialEq, PartialOrd, Ord, Eq, Clone, Serialize, Deserialize, JsonSchema, Debug, Hash,
127)]
128pub struct TypeName(pub String);
129
130impl From<&str> for TypeName {
131    fn from(name: &str) -> Self {
132        Self(String::from(name))
133    }
134}
135
136impl From<String> for TypeName {
137    fn from(name: String) -> Self {
138        Self(name)
139    }
140}
141
142impl TypeName {
143    /// Creates a new type name.
144    pub fn new(name: &str) -> Self {
145        Self(String::from(name))
146    }
147}
148
149/// Custom type definition. It covers structs and enums.
150#[derive(
151    PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, JsonSchema, Debug, Clone, Hash,
152)]
153#[serde(rename_all = "snake_case")]
154pub enum CustomType {
155    Struct {
156        name: TypeName,
157        description: Option<String>,
158        members: Vec<StructMember>,
159    },
160    Enum {
161        name: TypeName,
162        description: Option<String>,
163        variants: Vec<EnumVariant>,
164    },
165}
166
167impl CustomType {
168    /// Returns the name of the custom type.
169    pub fn name(&self) -> String {
170        match self {
171            CustomType::Struct { name, .. } => name.0.clone(),
172            CustomType::Enum { name, .. } => name.0.clone(),
173        }
174    }
175}
176
177/// Enum variant definition.
178#[derive(
179    PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, JsonSchema, Debug, Clone, Hash,
180)]
181pub struct EnumVariant {
182    pub name: String,
183    pub description: Option<String>,
184    pub discriminant: u16,
185    pub ty: Type,
186}
187
188/// Event definition.
189#[derive(PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, JsonSchema, Debug)]
190pub struct Event {
191    pub name: String,
192    pub ty: TypeName,
193}
194
195impl Event {
196    /// Creates a new event.
197    pub fn new(name: &str, ty: &str) -> Self {
198        Self {
199            name: String::from(name),
200            ty: ty.into(),
201        }
202    }
203}
204
205/// User error definition.
206#[derive(PartialEq, PartialOrd, Ord, Eq, Serialize, Deserialize, JsonSchema, Debug)]
207pub struct UserError {
208    pub name: String,
209    pub description: Option<String>,
210    pub discriminant: u16,
211}
212
213impl UserError {
214    /// Creates a new user error variant.
215    pub fn new(name: &str, desc: &str, discriminant: u16) -> Self {
216        Self {
217            name: String::from(name),
218            description: parse_description(desc),
219            discriminant,
220        }
221    }
222}
223
224/// Call method definition.
225#[derive(Serialize, Deserialize, JsonSchema, Debug)]
226pub struct CallMethod {
227    pub wasm_file_name: String,
228    pub description: Option<String>,
229    pub arguments: Vec<Argument>,
230}
231
232impl CallMethod {
233    /// Creates a new call method definition.
234    pub fn new(wasm_file_name: &str, description: &str, arguments: Vec<Argument>) -> Self {
235        Self {
236            wasm_file_name: String::from(wasm_file_name),
237            description: parse_description(description),
238            arguments,
239        }
240    }
241}