1#![no_std]
2
3extern crate alloc;
4
5pub mod error;
6pub mod rrc721;
7pub mod traits;
8pub mod types;
9
10pub use rootchain_core::types::{Address, Hash};
11pub use rootchain_macros::rootchain_contract;
12pub use traits::{Ownable, RRC20, RRC721};
13
14#[cfg(not(feature = "test-utils"))]
16extern "C" {
17 pub fn state_get(
18 key_ptr: *const u8,
19 key_len: usize,
20 value_ptr: *mut u8,
21 value_len: usize,
22 ) -> i32;
23 pub fn state_set(
24 key_ptr: *const u8,
25 key_len: usize,
26 value_ptr: *const u8,
27 value_len: usize,
28 ) -> i32;
29 pub fn get_caller(addr_ptr: *mut u8) -> i32;
30 pub fn host_input_len() -> u32;
31 pub fn host_read_input(ptr: *mut u8) -> u32;
32 pub fn host_write_output(ptr: *const u8, len: usize) -> i32;
33 pub fn host_log(ptr: *const u8, len: usize, level: u32) -> i32;
34 pub fn host_log_event(
35 topics_ptr: *const u8,
36 topics_count: usize,
37 data_ptr: *const u8,
38 data_len: usize,
39 ) -> i32;
40 pub fn host_set_metadata(ptr: *const u8, len: usize) -> i32;
41 pub fn host_hash(ptr: *const u8, len: usize, out_ptr: *mut u8) -> i32;
42}
43
44#[cfg(feature = "test-utils")]
45pub use mock::*;
46
47#[cfg(feature = "test-utils")]
48mod mock {
49 extern crate std;
50 use core::cell::RefCell;
51 use std::collections::HashMap;
52 use std::vec::Vec;
53
54 std::thread_local! {
55 static STATE: RefCell<HashMap<Vec<u8>, Vec<u8>>> = RefCell::new(HashMap::new());
56 static CALLER: RefCell<[u8; 32]> = const { RefCell::new([0u8; 32]) };
57 }
58
59 pub unsafe fn state_get(
63 key_ptr: *const u8,
64 key_len: usize,
65 value_ptr: *mut u8,
66 value_len: usize,
67 ) -> i32 {
68 let key = core::slice::from_raw_parts(key_ptr, key_len).to_vec();
69 STATE.with(|s| {
70 if let Some(val) = s.borrow().get(&key) {
71 let len = core::cmp::min(val.len(), value_len);
72 core::ptr::copy_nonoverlapping(val.as_ptr(), value_ptr, len);
73 0
74 } else {
75 -1
76 }
77 })
78 }
79
80 pub unsafe fn state_set(
84 key_ptr: *const u8,
85 key_len: usize,
86 value_ptr: *const u8,
87 value_len: usize,
88 ) -> i32 {
89 let key = core::slice::from_raw_parts(key_ptr, key_len).to_vec();
90 let val = core::slice::from_raw_parts(value_ptr, value_len).to_vec();
91 STATE.with(|s| {
92 s.borrow_mut().insert(key, val);
93 0
94 })
95 }
96
97 pub unsafe fn get_caller(addr_ptr: *mut u8) -> i32 {
101 CALLER.with(|c| {
102 core::ptr::copy_nonoverlapping(c.borrow().as_ptr(), addr_ptr, 32);
103 0
104 })
105 }
106
107 pub unsafe fn host_input_len() -> u32 {
110 0
111 }
112
113 pub unsafe fn host_read_input(_ptr: *mut u8) -> u32 {
116 0
117 }
118
119 pub unsafe fn host_write_output(_ptr: *const u8, _len: usize) -> i32 {
122 0
123 }
124
125 pub unsafe fn host_log(_ptr: *const u8, _len: usize, _level: u32) -> i32 {
128 0
129 }
130
131 pub unsafe fn host_log_event(
134 _topics_ptr: *const u8,
135 _topics_count: usize,
136 _data_ptr: *const u8,
137 _data_len: usize,
138 ) -> i32 {
139 0
140 }
141
142 pub unsafe fn host_set_metadata(_ptr: *const u8, _len: usize) -> i32 {
145 0
146 }
147
148 pub unsafe fn host_hash(_ptr: *const u8, _len: usize, _out_ptr: *mut u8) -> i32 {
151 0
152 }
153
154 pub fn set_mock_caller(addr: [u8; 32]) {
155 CALLER.with(|c| *c.borrow_mut() = addr);
156 }
157}
158
159#[cfg(all(not(feature = "std"), target_arch = "wasm32"))]
160#[global_allocator]
161static ALLOC: lol_alloc::AssumeSingleThreaded<lol_alloc::LeakingPageAllocator> =
162 unsafe { lol_alloc::AssumeSingleThreaded::new(lol_alloc::LeakingPageAllocator) };
163
164#[cfg(all(not(feature = "std"), target_arch = "wasm32"))]
165#[panic_handler]
166fn panic(_info: &core::panic::PanicInfo) -> ! {
167 loop {}
168}
169
170pub fn read_input() -> alloc::vec::Vec<u8> {
171 #[cfg(not(feature = "test-utils"))]
172 {
173 let len = unsafe { host_input_len() } as usize;
174 let mut buf = alloc::vec::Vec::with_capacity(len);
175 buf.resize(len, 0);
176 unsafe { host_read_input(buf.as_mut_ptr()) };
177 buf
178 }
179 #[cfg(feature = "test-utils")]
180 {
181 alloc::vec::Vec::new()
182 }
183}
184
185pub fn hash_bytes(data: &[u8]) -> Hash {
186 let mut hash = [0u8; 32];
187 unsafe { host_hash(data.as_ptr(), data.len(), hash.as_mut_ptr()) };
188 Hash(hash)
189}
190
191pub fn write_output(data: &[u8]) {
192 unsafe { host_write_output(data.as_ptr(), data.len()) };
193}
194
195pub fn log(msg: &str, level: u32) {
196 unsafe { host_log(msg.as_ptr(), msg.len(), level) };
197}
198
199pub fn log_event(topics: &[Hash], data: &[u8]) {
200 unsafe {
201 host_log_event(
202 topics.as_ptr() as *const u8,
203 topics.len(),
204 data.as_ptr(),
205 data.len(),
206 )
207 };
208}
209
210pub fn set_metadata(metadata: &[u8]) {
211 unsafe { host_set_metadata(metadata.as_ptr(), metadata.len()) };
212}
213
214#[macro_export]
215macro_rules! log_event {
216 ($topic:expr, $data:expr) => {
217 $crate::log_event(&[$topic], &$data);
218 };
219 ($topics:expr, $data:expr) => {
220 $crate::log_event(&$topics, &$data);
221 };
222}