odra_core/
contract_def.rs

1//! Encapsulates a set of structures that abstract out a smart contract layout.
2
3use crate::prelude::*;
4use casper_event_standard::EventInstance;
5use casper_types::{
6    bytesrepr::{FromBytes, ToBytes},
7    CLType, Key, PublicKey, URef, U128, U256, U512
8};
9use serde::{Deserialize, Serialize};
10
11/// Contract's entrypoint.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct Entrypoint {
14    /// The entrypoint's ident.
15    pub name: String,
16    /// The entrypoint's arguments.
17    pub args: Vec<Argument>,
18    /// `true` if the entrypoint is mutable.
19    pub is_mutable: bool,
20    /// The entrypoint's return type.
21    pub return_ty: CLType,
22    /// The entrypoint's type.
23    pub ty: EntrypointType,
24    /// The entrypoint's attributes.
25    pub attributes: Vec<EntrypointAttribute>
26}
27
28/// Defines an argument passed to an entrypoint.
29#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
30pub struct Argument {
31    /// The argument's ident.
32    pub name: String,
33    /// The argument's type.
34    pub ty: CLType,
35    /// `true` if the argument is a reference.
36    pub is_ref: bool,
37    /// `true` if the argument is a slice.
38    pub is_slice: bool,
39    /// `true` if the argument is required.
40    pub is_required: bool
41}
42
43/// Defines an event.
44#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
45pub struct Event {
46    /// The event's ident.
47    pub name: String,
48    /// The event's arguments.
49    pub args: Vec<Argument>
50}
51
52impl Event {
53    /// Returns `true` if the event has any argument of `CLType::Any` type.
54    pub fn has_any(&self) -> bool {
55        self.args.iter().any(|arg| arg.ty == CLType::Any)
56    }
57}
58
59/// Defines an entrypoint type.
60#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
61pub enum EntrypointType {
62    /// A special entrypoint that can be called just once on the contract initialization.
63    Constructor,
64    /// A regular entrypoint.
65    Public
66}
67
68/// Defines an entrypoint attribute.
69#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
70pub enum EntrypointAttribute {
71    /// A non-reentrant entrypoint.
72    NonReentrant,
73    /// A payable entrypoint.
74    Payable
75}
76
77/// A trait that should be implemented by each smart contract to allow the backend.
78pub trait HasIdent {
79    /// Returns the contract's ident.
80    fn ident() -> String;
81}
82
83/// A trait that should be implemented by each smart contract to allow the backend
84/// to generate blockchain-specific code.
85pub trait HasEntrypoints {
86    /// Returns the list of contract's entrypoints.
87    fn entrypoints() -> Vec<Entrypoint>;
88}
89
90/// A trait that should be implemented by each smart contract to allow the backend.
91pub trait HasEvents {
92    /// Returns a list of Events used by the contract.
93    fn events() -> Vec<Event>;
94
95    /// Returns a map of event schemas used by the contract.
96    fn event_schemas() -> crate::prelude::BTreeMap<String, casper_event_standard::Schema> {
97        crate::prelude::BTreeMap::new()
98    }
99}
100
101/// Represents a contract blueprint.
102///
103/// A contract blueprint is a set of events and entrypoints defined in a smart contract.
104/// It is used to generate the contract's ABI.
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct ContractBlueprint {
107    /// The name of the contract.
108    pub name: String,
109    /// The events defined in the contract.
110    pub events: Vec<Event>,
111    /// The entrypoints defined in the contract.
112    pub entrypoints: Vec<Entrypoint>
113}
114
115impl ContractBlueprint {
116    /// Creates a new instance of `ContractBlueprint` using the provided type parameters.
117    ///
118    /// # Type Parameters
119    ///
120    /// - `T`: A type that implements the `HasIdent`, `HasEvents`, and `HasEntrypoints` traits.
121    ///
122    /// # Returns
123    ///
124    /// A new instance of `ContractBlueprint` with the name, events, and entrypoints
125    /// obtained from the type `T`.
126    pub fn new<T: HasIdent + HasEvents + HasEntrypoints>() -> Self {
127        Self {
128            name: T::ident(),
129            events: T::events(),
130            entrypoints: T::entrypoints()
131        }
132    }
133
134    /// Converts the `ContractBlueprint` instance to a JSON string representation.
135    ///
136    /// # Returns
137    ///
138    /// A `Result` containing the JSON string if the conversion is successful,
139    /// or a `serde_json::Error` if an error occurs during serialization.
140    pub fn as_json(self) -> Result<String, serde_json::Error> {
141        serde_json::to_string_pretty(&self)
142    }
143}
144
145/// A trait for converting a type into an [Event].
146pub trait IntoEvent {
147    /// Converts the type into an [Event].
148    fn into_event() -> Event;
149}
150
151impl<T: EventInstance> IntoEvent for T {
152    fn into_event() -> Event {
153        let mut schemas = casper_event_standard::Schemas::new();
154        schemas.add::<T>();
155        let name = <T as EventInstance>::name();
156        let schema = <T as EventInstance>::schema();
157        let args = schema
158            .to_vec()
159            .iter()
160            .map(|(name, ty)| Argument {
161                name: name.clone(),
162                ty: ty.clone().downcast(),
163                is_ref: false,
164                is_slice: false,
165                is_required: true
166            })
167            .collect::<Vec<_>>();
168        Event { name, args }
169    }
170}
171
172macro_rules! impl_has_events {
173    ($($t:ty),*) => {
174        impl HasEvents for () {
175            fn events() -> Vec<Event> {
176                vec![]
177            }
178        }
179
180        $(
181            impl HasEvents for $t {
182                fn events() -> Vec<Event> {
183                    vec![]
184                }
185            }
186        )*
187    };
188}
189
190impl_has_events!(
191    u8, u16, u32, u64, i8, i16, i32, i64, U128, U256, U512, Address, String, bool, Key, URef,
192    PublicKey
193);
194
195impl<T: ToBytes + FromBytes, const N: usize> HasEvents for [T; N] {
196    fn events() -> Vec<Event> {
197        vec![]
198    }
199}
200
201impl<T: ToBytes + FromBytes> HasEvents for Option<T> {
202    fn events() -> Vec<Event> {
203        vec![]
204    }
205}
206
207impl<T: ToBytes + FromBytes, E: ToBytes + FromBytes> HasEvents for Result<T, E> {
208    fn events() -> Vec<Event> {
209        vec![]
210    }
211}
212
213impl<T: ToBytes + FromBytes, E: ToBytes + FromBytes> HasEvents for BTreeMap<T, E> {
214    fn events() -> Vec<Event> {
215        vec![]
216    }
217}
218
219impl<T: ToBytes + FromBytes> HasEvents for Vec<T> {
220    fn events() -> Vec<Event> {
221        vec![]
222    }
223}
224
225impl<T1: ToBytes + FromBytes> HasEvents for (T1,) {
226    fn events() -> Vec<Event> {
227        vec![]
228    }
229}
230
231impl<T1: ToBytes + FromBytes, T2: ToBytes + FromBytes> HasEvents for (T1, T2) {
232    fn events() -> Vec<Event> {
233        vec![]
234    }
235}
236
237impl<T1: ToBytes + FromBytes, T2: ToBytes + FromBytes, T3: ToBytes + FromBytes> HasEvents
238    for (T1, T2, T3)
239{
240    fn events() -> Vec<Event> {
241        vec![]
242    }
243}