testnumbat_wasm/macros.rs
1// Note: Simple macros cannot be placed in testnumbat-wasm-derive,
2// because Rust "cannot export macro_rules! macros from a `proc-macro` crate type currently".
3
4/// Getting all imports needed for a smart contract.
5#[macro_export]
6macro_rules! imports {
7 () => {
8 use core::ops::{
9 Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div,
10 DivAssign, Mul, MulAssign, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub,
11 SubAssign,
12 };
13 use testnumbat_wasm::{
14 api::{
15 BigIntApi, BlockchainApi, CallValueApi, CryptoApi, EllipticCurveApi, ErrorApi,
16 LogApi, ManagedTypeApi, SendApi,
17 },
18 contract_base::{ContractBase, ProxyObjBase},
19 testnumbat_codec::{DecodeError, NestedDecode, NestedEncode, TopDecode},
20 err_msg,
21 dcdt::*,
22 io::*,
23 non_zero_usize,
24 non_zero_util::*,
25 only_owner, require, sc_error,
26 storage::mappers::*,
27 types::{
28 SCResult::{Err, Ok},
29 *,
30 },
31 Box, Vec,
32 }; // TODO: remove at some point, they shouldn't be public
33 };
34}
35
36/// Imports required for deriving serialization and TypeAbi.
37#[macro_export]
38macro_rules! derive_imports {
39 () => {
40 use testnumbat_wasm::{
41 derive::TypeAbi,
42 testnumbat_codec,
43 testnumbat_codec::testnumbat_codec_derive::{
44 NestedDecode, NestedEncode, TopDecode, TopDecodeOrDefault, TopEncode,
45 TopEncodeOrDefault,
46 },
47 };
48 };
49}
50
51/// Compact way of returning a static error message.
52#[macro_export]
53macro_rules! sc_error {
54 ($s:expr) => {
55 testnumbat_wasm::types::SCResult::Err(testnumbat_wasm::types::StaticSCError::from($s)).into()
56 };
57}
58
59/// Equivalent to the `?` operator for SCResult.
60#[deprecated(
61 since = "0.16.0",
62 note = "The `?` operator can now be used on `SCResult`, please use it instead."
63)]
64#[macro_export]
65macro_rules! sc_try {
66 ($s:expr) => {
67 match $s {
68 testnumbat_wasm::types::SCResult::Ok(t) => t,
69 testnumbat_wasm::types::SCResult::Err(e) => {
70 return testnumbat_wasm::types::SCResult::Err(e);
71 },
72 }
73 };
74}
75
76/// Allows us to write Solidity style `require!(<condition>, <error_msg>)` and avoid if statements.
77///
78/// It can only be used in a function that returns `SCResult<_>` where _ can be any type.
79///
80/// ```rust
81/// # use testnumbat_wasm::*;
82/// # use testnumbat_wasm::api::BlockchainApi;
83/// # use testnumbat_wasm::types::{*, SCResult::Ok};
84/// # pub trait ExampleContract: testnumbat_wasm::contract_base::ContractBase
85/// # {
86/// fn only_callable_by_owner(&self) -> SCResult<()> {
87/// require!(self.blockchain().get_caller() == self.blockchain().get_owner_address(), "Caller must be owner");
88/// Ok(())
89/// }
90/// # }
91/// ```
92#[macro_export]
93macro_rules! require {
94 ($expression:expr, $error_msg:expr) => {
95 if (!($expression)) {
96 return sc_error!($error_msg);
97 }
98 };
99}
100
101/// Very compact way of not allowing anyone but the owner to call a function.
102///
103/// It can only be used in a function that returns `SCResult<_>` where _ can be any type.
104///
105/// ```rust
106/// # use testnumbat_wasm::*;
107/// # use testnumbat_wasm::api::BlockchainApi;
108/// # use testnumbat_wasm::types::{*, SCResult::Ok};
109/// # pub trait ExampleContract: testnumbat_wasm::contract_base::ContractBase
110/// # {
111/// fn only_callable_by_owner(&self) -> SCResult<()> {
112/// only_owner!(self, "Caller must be owner");
113/// Ok(())
114/// }
115/// # }
116/// ```
117#[macro_export]
118macro_rules! only_owner {
119 ($trait_self: expr, $error_msg:expr) => {
120 if ($trait_self.blockchain().get_caller() != $trait_self.blockchain().get_owner_address()) {
121 return sc_error!($error_msg);
122 }
123 };
124}
125
126/// Converts usize to NonZeroUsize or returns SCError.
127#[macro_export]
128macro_rules! non_zero_usize {
129 ($input: expr, $error_msg:expr) => {
130 if let Some(nz) = NonZeroUsize::new($input) {
131 nz
132 } else {
133 return sc_error!($error_msg);
134 }
135 };
136}