1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(not(feature = "std"))]
4#[macro_use]
5extern crate alloc;
6
7pub mod abi;
8pub mod prelude;
9pub mod serializers;
10#[cfg(not(target_arch = "wasm32"))]
11pub use linkme;
12
13#[cfg(not(target_arch = "wasm32"))]
14pub mod abi_generator;
15pub mod casper;
16pub mod collections;
17pub mod contrib;
18#[cfg(feature = "std")]
19pub mod schema;
20pub mod types;
21
22use crate::prelude::{marker::PhantomData, ptr::NonNull};
23
24use crate::serializers::borsh::{BorshDeserialize, BorshSerialize};
25use casper::{CallResult, Entity};
26pub use casper_contract_macros as macros;
27pub use casper_contract_sdk_sys as sys;
28pub use casper_executor_wasm_common;
29use types::{Address, CallError};
30
31cfg_if::cfg_if! {
32 if #[cfg(feature = "std")] {
33 #[inline]
34 pub fn set_panic_hook() {
35 static SET_HOOK: std::sync::Once = std::sync::Once::new();
36 SET_HOOK.call_once(|| {
37 std::panic::set_hook(Box::new(|panic_info| {
38 let msg = panic_info.to_string();
39 casper::print(&msg);
40 }));
41 });
42 }
43 }
44 else {
45 pub fn set_panic_hook() {
46 }
48 }
49}
50
51pub fn reserve_vec_space(vec: &mut Vec<u8>, size: usize) -> Option<NonNull<u8>> {
52 if size == 0 {
53 None
54 } else {
55 *vec = Vec::with_capacity(size);
56 unsafe {
57 vec.set_len(size);
58 }
59 NonNull::new(vec.as_mut_ptr())
60 }
61}
62
63pub trait ContractRef {
64 fn new() -> Self;
65}
66
67pub trait ToCallData {
68 type Return<'a>;
69
70 fn entry_point(&self) -> &str;
71
72 fn input_data(&self) -> Option<crate::prelude::Vec<u8>>;
73}
74
75pub trait Contract {
79 type Ref: ContractRef;
80
81 fn name() -> &'static str;
82 fn create<T: ToCallData>(
83 value: u64,
84 call_data: T,
85 ) -> Result<ContractHandle<Self::Ref>, CallError>;
86 fn default_create() -> Result<ContractHandle<Self::Ref>, CallError>;
87 fn upgrade<T: ToCallData>(code: Option<&[u8]>, call_data: T) -> Result<(), CallError>;
88}
89
90#[derive(Debug)]
91pub enum Access {
92 Private,
93 Public,
94}
95
96#[cfg(target_arch = "wasm32")]
98#[macro_export]
99macro_rules! log {
100 ($($arg:tt)*) => ({
101 $crate::prelude::casper::print(&$crate::prelude::format!($($arg)*));
102 })
103}
104
105#[cfg(not(target_arch = "wasm32"))]
106#[macro_export]
107macro_rules! log {
108 ($($arg:tt)*) => ({
109 eprintln!("📝 {}", &$crate::prelude::format!($($arg)*));
110 })
111}
112
113#[macro_export]
114macro_rules! revert {
115 () => {{
116 $crate::casper::ret(
117 $crate::casper_executor_wasm_common::flags::ReturnFlags::REVERT,
118 None,
119 );
120 unreachable!()
121 }};
122 ($arg:expr) => {{
123 let value = $arg;
124 let data =
125 $crate::serializers::borsh::to_vec(&value).expect("Revert value should serialize");
126 $crate::casper::ret(
127 $crate::casper_executor_wasm_common::flags::ReturnFlags::REVERT,
128 Some(data.as_slice()),
129 );
130 #[allow(unreachable_code)]
131 value
132 }};
133}
134
135pub trait UnwrapOrRevert<T> {
136 fn unwrap_or_revert(self) -> T;
139}
140
141impl<T, E> UnwrapOrRevert<T> for Result<T, E>
142where
143 E: BorshSerialize,
144{
145 fn unwrap_or_revert(self) -> T {
146 self.unwrap_or_else(|error| {
147 let error_data = borsh::to_vec(&error).expect("Revert value should serialize");
148 casper::ret(
149 casper_executor_wasm_common::flags::ReturnFlags::REVERT,
150 Some(error_data.as_slice()),
151 );
152 unreachable!("Support for unwrap_or_revert")
153 })
154 }
155}
156
157#[derive(Debug)]
158pub struct ContractHandle<T: ContractRef> {
159 contract_address: Address,
160 marker: PhantomData<T>,
161}
162
163impl<T: ContractRef> ContractHandle<T> {
164 #[must_use]
165 pub const fn from_address(contract_address: Address) -> Self {
166 ContractHandle {
167 contract_address,
168 marker: PhantomData,
169 }
170 }
171
172 pub fn build_call(&self) -> CallBuilder<T> {
173 CallBuilder {
174 address: self.contract_address,
175 marker: PhantomData,
176 transferred_value: None,
177 }
178 }
179
180 #[inline]
182 pub fn call<'a, CallData: ToCallData>(
183 &self,
184 func: impl FnOnce(T) -> CallData,
185 ) -> Result<CallData::Return<'a>, CallError>
186 where
187 CallData::Return<'a>: BorshDeserialize,
188 {
189 self.build_call().call(func)
190 }
191
192 #[inline]
194 pub fn try_call<CallData: ToCallData>(
195 &self,
196 func: impl FnOnce(T) -> CallData,
197 ) -> Result<CallResult<CallData>, CallError> {
198 self.build_call().try_call(func)
199 }
200
201 #[must_use]
202 pub fn contract_address(&self) -> Address {
203 self.contract_address
204 }
205
206 #[must_use]
207 pub fn entity(&self) -> Entity {
208 Entity::Contract(self.contract_address)
209 }
210
211 #[must_use]
213 pub fn balance(&self) -> u64 {
214 casper::get_balance_of(&Entity::Contract(self.contract_address))
215 }
216}
217
218pub struct CallBuilder<T: ContractRef> {
219 address: Address,
220 transferred_value: Option<u64>,
221 marker: PhantomData<T>,
222}
223
224impl<T: ContractRef> CallBuilder<T> {
225 #[must_use]
226 pub fn new(address: Address) -> Self {
227 CallBuilder {
228 address,
229 transferred_value: None,
230 marker: PhantomData,
231 }
232 }
233
234 #[must_use]
235 pub fn with_transferred_value(mut self, transferred_value: u64) -> Self {
236 self.transferred_value = Some(transferred_value);
237 self
238 }
239
240 #[must_use]
242 pub fn cast<U: ContractRef>(self) -> CallBuilder<U> {
243 CallBuilder {
244 address: self.address,
245 transferred_value: self.transferred_value,
246 marker: PhantomData,
247 }
248 }
249
250 pub fn try_call<CallData: ToCallData>(
251 &self,
252 func: impl FnOnce(T) -> CallData,
253 ) -> Result<CallResult<CallData>, CallError> {
254 let inst = T::new();
255 let call_data = func(inst);
256 casper::call(
257 &self.address,
258 self.transferred_value.unwrap_or(0),
259 call_data,
260 )
261 }
262
263 pub fn call<'a, CallData: ToCallData>(
264 &self,
265 func: impl FnOnce(T) -> CallData,
266 ) -> Result<CallData::Return<'a>, CallError>
267 where
268 CallData::Return<'a>: BorshDeserialize,
269 {
270 let inst = T::new();
271 let call_data = func(inst);
272 let call_result = casper::call(
273 &self.address,
274 self.transferred_value.unwrap_or(0),
275 call_data,
276 )?;
277 call_result.into_result()
278 }
279}
280
281pub struct ContractBuilder<'a, T: ContractRef> {
282 transferred_value: Option<u64>,
283 code: Option<&'a [u8]>,
284 seed: Option<&'a [u8; 32]>,
285 marker: PhantomData<T>,
286}
287
288impl<T: ContractRef> Default for ContractBuilder<'_, T> {
289 fn default() -> Self {
290 Self::new()
291 }
292}
293
294impl<'a, T: ContractRef> ContractBuilder<'a, T> {
295 #[must_use]
296 pub fn new() -> Self {
297 ContractBuilder {
298 transferred_value: None,
299 code: None,
300 seed: None,
301 marker: PhantomData,
302 }
303 }
304
305 #[must_use]
306 pub fn with_transferred_value(mut self, transferred_value: u64) -> Self {
307 self.transferred_value = Some(transferred_value);
308 self
309 }
310
311 #[must_use]
312 pub fn with_code(mut self, code: &'a [u8]) -> Self {
313 self.code = Some(code);
314 self
315 }
316
317 #[must_use]
318 pub fn with_seed(mut self, seed: &'a [u8; 32]) -> Self {
319 self.seed = Some(seed);
320 self
321 }
322
323 pub fn create<CallData: ToCallData>(
324 &self,
325 func: impl FnOnce() -> CallData,
326 ) -> Result<ContractHandle<T>, CallError>
327 where
328 CallData::Return<'a>: BorshDeserialize,
329 {
330 let value = self.transferred_value.unwrap_or(0);
331 let call_data = func();
332 let input_data = call_data.input_data();
333 let seed = self.seed;
334 let create_result = casper::create(
335 self.code,
336 value,
337 Some(call_data.entry_point()),
338 input_data.as_deref(),
339 seed,
340 )?;
341 Ok(ContractHandle::from_address(create_result.contract_address))
342 }
343
344 pub fn default_create(&self) -> Result<ContractHandle<T>, CallError> {
345 if self.transferred_value.is_some() {
346 panic!("Value should not be set for default create");
347 }
348
349 let value = self.transferred_value.unwrap_or(0);
350 let seed = self.seed;
351 let create_result = casper::create(self.code, value, None, None, seed)?;
352 Ok(ContractHandle::from_address(create_result.contract_address))
353 }
354}
355
356pub trait Message: BorshSerialize {
358 const TOPIC: &'static str;
359 fn payload(&self) -> Vec<u8>;
361}
362
363#[cfg(test)]
364mod tests {
365 #[test]
366 fn test_call_builder() {}
367}