numbat_wasm/
lib.rs

1#![no_std]
2
3// re-export basic heap types
4extern crate alloc;
5pub use alloc::boxed::Box;
6pub use alloc::string::String;
7pub use alloc::vec::Vec;
8
9pub use numbat_codec;
10
11pub mod abi;
12pub mod err_msg;
13pub mod hex_call_data;
14pub mod io;
15pub mod non_zero_util;
16mod proxy;
17pub mod storage;
18pub mod types;
19
20pub use hex_call_data::*;
21pub use io::*;
22pub use proxy::OtherContractHandle;
23pub use storage::{storage_get, storage_set};
24pub use types::*;
25
26use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
27use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
28use core::ops::{BitAnd, BitOr, BitXor, Shl, Shr};
29use core::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
30
31/// Interface to be used by the actual smart contract code.
32///
33/// Note: contracts and the api are not mutable.
34/// They simply pass on/retrieve data to/from the protocol.
35/// When mocking the blockchain state, we use the Rc/RefCell pattern
36/// to isolate mock state mutability from the contract interface.
37pub trait ContractHookApi<BigInt, BigUint>: Sized
38where
39	BigInt: numbat_codec::NestedEncode + 'static,
40	BigUint: numbat_codec::NestedEncode + 'static,
41{
42	fn get_sc_address(&self) -> Address;
43
44	fn get_owner_address(&self) -> Address;
45
46	fn get_caller(&self) -> Address;
47
48	fn get_balance(&self, address: &Address) -> BigUint;
49
50	fn get_sc_balance(&self) -> BigUint {
51		self.get_balance(&self.get_sc_address())
52	}
53
54	fn storage_store_slice_u8(&self, key: &[u8], value: &[u8]);
55
56	fn storage_load_len(&self, key: &[u8]) -> usize;
57
58	fn storage_load_vec_u8(&self, key: &[u8]) -> Vec<u8>;
59
60	fn storage_load_boxed_bytes(&self, key: &[u8]) -> BoxedBytes {
61		self.storage_load_vec_u8(key).into()
62	}
63
64	fn storage_store_bytes32(&self, key: &[u8], value: &[u8; 32]);
65
66	fn storage_load_bytes32(&self, key: &[u8]) -> [u8; 32];
67
68	fn storage_store_big_uint(&self, key: &[u8], value: &BigUint);
69
70	fn storage_load_big_uint(&self, key: &[u8]) -> BigUint;
71
72	fn storage_store_big_uint_raw(&self, key: &[u8], handle: i32);
73
74	fn storage_load_big_uint_raw(&self, key: &[u8]) -> i32;
75
76	fn storage_store_big_int(&self, key: &[u8], value: &BigInt);
77
78	fn storage_load_big_int(&self, key: &[u8]) -> BigInt;
79
80	fn storage_store_u64(&self, key: &[u8], value: u64);
81
82	fn storage_store_i64(&self, key: &[u8], value: i64);
83
84	fn storage_load_u64(&self, key: &[u8]) -> u64;
85
86	fn storage_load_i64(&self, key: &[u8]) -> i64;
87
88	#[inline]
89	fn storage_load_cumulated_validator_reward(&self) -> BigUint {
90		self.storage_load_big_uint(storage::protected_keys::NUMBAT_REWARD_KEY)
91	}
92
93	fn get_call_value_big_uint(&self) -> BigUint;
94
95	fn get_dcdt_value_big_uint(&self) -> BigUint;
96
97	fn get_dcdt_token_name(&self) -> Vec<u8>;
98
99	fn send_tx(&self, to: &Address, amount: &BigUint, data: &[u8]);
100
101	fn async_call(&self, to: &Address, amount: &BigUint, data: &[u8]);
102
103	fn deploy_contract(
104		&self,
105		gas: u64,
106		amount: &BigUint,
107		code: &BoxedBytes,
108		code_metadata: CodeMetadata,
109		arg_buffer: &ArgBuffer,
110	) -> Address;
111
112	fn get_tx_hash(&self) -> H256;
113
114	fn get_gas_left(&self) -> u64;
115
116	fn get_block_timestamp(&self) -> u64;
117
118	fn get_block_nonce(&self) -> u64;
119
120	fn get_block_round(&self) -> u64;
121
122	fn get_block_epoch(&self) -> u64;
123
124	fn get_block_random_seed(&self) -> Box<[u8; 48]>;
125
126	fn get_prev_block_timestamp(&self) -> u64;
127
128	fn get_prev_block_nonce(&self) -> u64;
129
130	fn get_prev_block_round(&self) -> u64;
131
132	fn get_prev_block_epoch(&self) -> u64;
133
134	fn get_prev_block_random_seed(&self) -> Box<[u8; 48]>;
135
136	fn sha256(&self, data: &[u8]) -> H256;
137
138	fn keccak256(&self, data: &[u8]) -> H256;
139}
140
141/// Interface to only be used by code generated by the macros.
142/// The smart contract code doesn't have access to these methods directly.
143pub trait ContractIOApi<BigInt, BigUint>: Clone {
144	fn get_num_arguments(&self) -> i32;
145
146	#[inline(never)] // prevent inline intentinally
147	fn check_num_arguments(&self, expected: i32) {
148		let nr_args = self.get_num_arguments();
149		if nr_args != expected {
150			self.signal_error(err_msg::ARG_WRONG_NUMBER);
151		}
152	}
153
154	fn check_not_payable(&self);
155
156	fn get_argument_len(&self, arg_index: i32) -> usize;
157
158	fn copy_argument_to_slice(&self, arg_index: i32, slice: &mut [u8]);
159
160	fn get_argument_vec_u8(&self, arg_index: i32) -> Vec<u8>;
161
162	fn get_argument_boxed_bytes(&self, arg_index: i32) -> BoxedBytes {
163		self.get_argument_vec_u8(arg_index).into()
164	}
165
166	fn get_argument_big_int(&self, arg_id: i32) -> BigInt;
167
168	fn get_argument_big_uint(&self, arg_id: i32) -> BigUint;
169
170	fn get_argument_big_int_raw(&self, arg_id: i32) -> i32;
171
172	fn get_argument_big_uint_raw(&self, arg_id: i32) -> i32;
173
174	fn get_argument_u64(&self, arg_id: i32) -> u64;
175
176	fn get_argument_i64(&self, arg_id: i32) -> i64;
177
178	fn finish_slice_u8(&self, slice: &[u8]);
179
180	fn finish_big_int(&self, b: &BigInt);
181
182	fn finish_big_uint(&self, b: &BigUint);
183
184	fn finish_big_int_raw(&self, handle: i32);
185
186	fn finish_big_uint_raw(&self, handle: i32);
187
188	fn finish_u64(&self, value: u64);
189
190	fn finish_i64(&self, value: i64);
191
192	fn signal_error(&self, message: &[u8]) -> !;
193
194	fn write_log(&self, topics: &[[u8; 32]], data: &[u8]);
195}
196
197/// Definition of the BigUint type required by the API.
198/// The API doesn't care about the actual BigInt implementation.
199/// The Andes VM provides an implementation directly in the protocol.
200/// For debugging we use a different implementation, based on Rust's BigInt.
201///
202/// Since most values in smart contracts will not be signed, as well as for safety,
203/// most of the functionality if provided for unsigned integers.
204pub trait BigUintApi:
205	Sized
206	+ From<u64>
207	+ From<u32>
208	+ From<usize>
209	+ Clone
210	+ Add<Output = Self>
211	+ AddAssign
212	+ Sub<Output = Self>
213	+ SubAssign
214	+ Mul<Output = Self>
215	+ MulAssign
216	+ Div<Output = Self>
217	+ DivAssign
218	+ Rem<Output = Self>
219	+ RemAssign
220	+ BitAnd<Output = Self>
221	+ BitAndAssign
222	+ BitOr<Output = Self>
223	+ BitOrAssign
224	+ BitXor<Output = Self>
225	+ BitXorAssign
226	+ Shr<usize, Output = Self>
227	+ ShrAssign<usize>
228	+ Shl<usize, Output = Self>
229	+ ShlAssign<usize>
230	+ PartialEq<Self>
231	+ Eq
232	+ PartialOrd<Self>
233	+ Ord
234	+ PartialEq<u64>
235	+ PartialOrd<u64>
236	+ numbat_codec::NestedEncode
237	+ numbat_codec::TopEncode
238	+ numbat_codec::NestedDecode
239	+ numbat_codec::TopDecode
240	+ abi::TypeAbi
241{
242	fn zero() -> Self {
243		0u64.into()
244	}
245
246	fn byte_length(&self) -> i32;
247
248	fn copy_to_slice_big_endian(&self, slice: &mut [u8]) -> i32;
249
250	fn copy_to_array_big_endian_pad_right(&self, target: &mut [u8; 32]);
251
252	fn to_bytes_be(&self) -> Vec<u8>;
253
254	fn to_bytes_be_pad_right(&self, nr_bytes: usize) -> Option<Vec<u8>>;
255
256	fn from_bytes_be(bytes: &[u8]) -> Self;
257}
258
259// BigInt sign.
260pub enum Sign {
261	Minus,
262	NoSign,
263	Plus,
264}
265
266/// Definition of the BigInt type required by the API.
267pub trait BigIntApi<BigUint>:
268	Sized
269	+ From<BigUint>
270	+ From<i64>
271	+ From<i32>
272	+ Clone
273	+ Add<Output = Self>
274	+ AddAssign
275	+ Sub<Output = Self>
276	+ SubAssign
277	+ Mul<Output = Self>
278	+ MulAssign
279	+ Div<Output = Self>
280	+ DivAssign
281	+ Rem<Output = Self>
282	+ RemAssign
283	+ Neg
284	+ PartialEq<Self>
285	+ Eq
286	+ PartialOrd<Self>
287	+ Ord
288	+ PartialEq<i64>
289	+ PartialOrd<i64>
290	+ numbat_codec::NestedEncode
291	+ numbat_codec::TopEncode
292	+ numbat_codec::NestedDecode
293	+ numbat_codec::TopDecode
294	+ abi::TypeAbi
295{
296	fn zero() -> Self {
297		0i64.into()
298	}
299
300	fn abs_uint(&self) -> BigUint;
301
302	fn sign(&self) -> Sign;
303
304	fn to_signed_bytes_be(&self) -> Vec<u8>;
305
306	fn from_signed_bytes_be(bytes: &[u8]) -> Self;
307}
308
309/// CallableContract is the means by which the debugger calls methods in the contract.
310pub trait CallableContract<A> {
311	fn call(&self, fn_name: &[u8]) -> bool;
312
313	fn abi(&self, include_modules: bool) -> abi::ContractAbi;
314
315	fn clone_contract(&self) -> Box<dyn CallableContract<A>>;
316
317	fn into_api(self: Box<Self>) -> A;
318}
319
320/// Handy way of casting to a contract proxy trait.
321/// Would make more sense to be in numbat-wasm-derive, but Rust "cannot export macro_rules! macros from a `proc-macro` crate type currently".
322#[macro_export]
323macro_rules! contract_proxy {
324	($s:expr, $address:expr, $proxy_trait:ident) => {
325		$s.contract_proxy($address) as Box<dyn $proxy_trait<BigInt, BigUint>>
326	};
327}
328
329/// Getting all imports needed for a smart contract.
330#[macro_export]
331macro_rules! imports {
332	() => {
333		use core::ops::{Add, Div, Mul, Rem, Sub};
334		use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign};
335		use core::ops::{BitAnd, BitOr, BitXor, Shl, Shr};
336		use core::ops::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign};
337		use numbat_wasm::numbat_codec::{DecodeError, NestedDecode, NestedEncode, TopDecode};
338		use numbat_wasm::err_msg;
339		use numbat_wasm::io::*;
340		use numbat_wasm::non_zero_util::*;
341		use numbat_wasm::types::*;
342		use numbat_wasm::{Address, H256};
343		use numbat_wasm::{
344			AsyncCallError, AsyncCallResult, BigIntApi, BigUintApi, ContractHookApi, ContractIOApi,
345			OtherContractHandle,
346		};
347		use numbat_wasm::{BorrowedMutStorage, Box, BoxedBytes, Queue, VarArgs, Vec};
348		use numbat_wasm::{SCError, SCResult, SCResult::Err, SCResult::Ok};
349	};
350}
351
352/// Imports required for deriving serialization and TypeAbi.
353#[macro_export]
354macro_rules! derive_imports {
355	() => {
356		use numbat_wasm::numbat_codec;
357		use numbat_wasm::numbat_codec::numbat_codec_derive::{
358			NestedDecode, NestedEncode, TopDecode, TopEncode,
359		};
360		use numbat_wasm_derive::TypeAbi;
361	};
362}
363
364/// Compact way of returning a static error message.
365#[macro_export]
366macro_rules! sc_error {
367	($s:expr) => {
368		numbat_wasm::SCResult::Err(numbat_wasm::SCError::from($s.as_bytes()))
369	};
370}
371
372/// Equivalent of the ? operator for SCResult.
373#[macro_export]
374macro_rules! sc_try {
375	($s:expr) => {
376		match $s {
377			numbat_wasm::SCResult::Ok(t) => t,
378			numbat_wasm::SCResult::Err(e) => {
379				return numbat_wasm::SCResult::Err(e);
380			},
381		}
382	};
383}
384
385/// Allows us to write Solidity style `require!(<condition>, <error_msg>)` and avoid if statements.
386///
387/// It can only be used in a function that returns `SCResult<_>` where _ can be any type.
388///
389/// ```rust
390/// # use numbat_wasm::{*, SCResult::Ok};
391/// # pub trait ExampleContract<BigInt, BigUint>: ContractHookApi<BigInt, BigUint>
392/// # where
393/// #     BigInt: numbat_codec::NestedEncode + 'static,
394/// #     BigUint: numbat_codec::NestedEncode + 'static,
395/// # {
396/// fn only_callable_by_owner(&self) -> SCResult<()> {
397///     require!(self.get_caller() == self.get_owner_address(), "Caller must be owner");
398///     Ok(())
399/// }
400/// # }
401/// ```
402#[macro_export]
403macro_rules! require {
404	($expression:expr, $error_msg:expr) => {
405		if (!($expression)) {
406			return sc_error!($error_msg);
407		}
408	};
409}
410
411/// Very compact way of not allowing anyone but the owner to call a function.
412///
413/// It can only be used in a function that returns `SCResult<_>` where _ can be any type.
414///
415/// ```rust
416/// # use numbat_wasm::{*, SCResult::Ok};
417/// # pub trait ExampleContract<BigInt, BigUint>: ContractHookApi<BigInt, BigUint>
418/// # where
419/// #     BigInt: numbat_codec::NestedEncode + 'static,
420/// #     BigUint: numbat_codec::NestedEncode + 'static,
421/// # {
422/// fn only_callable_by_owner(&self) -> SCResult<()> {
423///     only_owner!(self, "Caller must be owner");
424///     Ok(())
425/// }
426/// # }
427/// ```
428#[macro_export]
429macro_rules! only_owner {
430	($trait_self: expr, $error_msg:expr) => {
431		if ($trait_self.get_caller() != $trait_self.get_owner_address()) {
432			return sc_error!($error_msg);
433		}
434	};
435}
436
437/// Compact way to represent the BorrowedMutStorage type.
438#[macro_export]
439macro_rules! mut_storage (
440    ($t:ty) => (
441        BorrowedMutStorage<T, BigInt, BigUint, $t>
442    )
443);
444
445/// Converts usize to NonZeroUsize or returns SCError.
446#[macro_export]
447macro_rules! non_zero_usize {
448	($input: expr, $error_msg:expr) => {
449		if let Some(nz) = NonZeroUsize::new($input) {
450			nz
451		} else {
452			return sc_error!($error_msg);
453		}
454	};
455}