1#![cfg_attr(not(feature = "std"), no_std)]
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5
6#[cfg(feature = "alloc")]
7use alloc::vec::Vec;
8
9pub use bobcat_maths::U;
10
11pub type Address = [u8; 20];
12
13pub use bobcat_cd::read_words;
14
15#[cfg(target_arch = "wasm32")]
16mod impls {
17 #[link(wasm_import_module = "vm_hooks")]
18 unsafe extern "C" {
19 #[allow(unused)]
20 pub(crate) fn pay_for_memory_grow(pages: u16);
21 pub(crate) fn write_result(d: *const u8, l: usize);
22 pub(crate) fn read_args(out: *mut u8);
23 pub(crate) fn msg_sender(addr: *mut u8);
24 pub(crate) fn contract_address(addr: *mut u8);
25 pub(crate) fn msg_value(value: *mut u8);
26 pub fn chain_id() -> u64;
27 pub(crate) fn account_codehash(address: *const u8, dest: *mut u8);
28 pub(crate) fn block_timestamp() -> u64;
29 }
30}
31
32#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
33pub mod host {
34 use super::{Address, U};
35
36 use core::{ptr::copy_nonoverlapping, slice::from_raw_parts};
37
38 use std::cell::RefCell;
39
40 thread_local! {
41 static ARGS: RefCell<Vec<u8>> = RefCell::default();
42 static MSG_SENDER: RefCell<[u8; 20]> = RefCell::default();
43 static CONTRACT_ADDRESS: RefCell<Address> = RefCell::default();
44 static MSG_VALUE: RefCell<U> = RefCell::default();
45 static CHAIN_ID: RefCell<u64> = RefCell::default();
46 static BLOCK_TIMESTAMP: RefCell<u64> = RefCell::default();
47 }
48
49 #[allow(unused)]
50 pub(crate) unsafe fn pay_for_memory_grow(_: u16) {}
51
52 pub(crate) unsafe fn write_result(d: *const u8, l: usize) {
53 println!("{}", const_hex::encode(unsafe { from_raw_parts(d, l) }));
54 }
55
56 pub fn set_args(x: Vec<u8>) {
57 ARGS.with(|s| *s.borrow_mut() = x)
58 }
59
60 pub(crate) unsafe fn read_args(out: *mut u8) {
61 ARGS.with(|s| {
62 let b = s.borrow();
63 unsafe {
64 copy_nonoverlapping(b.as_ptr(), out, b.len());
65 }
66 })
67 }
68
69 pub fn set_msg_sender(x: Address) {
70 MSG_SENDER.with(|s| *s.borrow_mut() = x)
71 }
72
73 pub(crate) unsafe fn msg_sender(out: *mut u8) {
74 MSG_SENDER.with(|s| {
75 let b = s.borrow();
76 unsafe {
77 copy_nonoverlapping(b.as_ptr(), out, 20);
78 }
79 })
80 }
81
82 pub fn set_contract_address(x: Address) {
83 CONTRACT_ADDRESS.with(|s| {
84 *s.borrow_mut() = x;
85 })
86 }
87
88 pub(crate) unsafe fn contract_address(out: *mut u8) {
89 CONTRACT_ADDRESS.with(|s| {
90 let b = s.borrow();
91 unsafe {
92 copy_nonoverlapping(b.as_ptr(), out, 20);
93 }
94 })
95 }
96
97 pub(crate) unsafe fn msg_value(out: *mut u8) {
98 MSG_VALUE.with(|s| {
99 let b = s.borrow();
100 unsafe {
101 copy_nonoverlapping(b.as_ptr(), out, 32);
102 }
103 })
104 }
105
106 pub(crate) unsafe fn chain_id() -> u64 {
107 CHAIN_ID.with(|s| s.borrow().clone())
108 }
109
110 pub(crate) unsafe fn account_codehash(_: *const u8, _: *mut u8) {}
111
112 pub fn set_block_timestamp(n: u64) {
113 BLOCK_TIMESTAMP.with(|s| { *s.borrow_mut() = n })
114 }
115
116 pub(crate) unsafe fn block_timestamp() -> u64 {
117 BLOCK_TIMESTAMP.with(|s| *s.borrow())
118 }
119}
120
121#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
122pub use host as impls;
123
124#[cfg(all(not(target_arch = "wasm32"), not(feature = "std")))]
125mod impls {
126 pub(crate) unsafe fn pay_for_memory_grow(_: u16) {}
127
128 pub(crate) unsafe fn write_result(_: *const u8, _: usize) {}
129
130 pub(crate) unsafe fn read_args(_out: *mut u8) {}
131
132 pub(crate) unsafe fn msg_sender(_: *mut u8) {}
133
134 pub(crate) unsafe fn contract_address(_: *mut u8) {}
135
136 pub(crate) unsafe fn msg_value(_: *mut u8) {}
137
138 pub(crate) unsafe fn chain_id() -> u64 {
139 0
140 }
141
142 pub(crate) unsafe fn account_codehash(_: *const u8, _: *mut u8) {}
143
144 pub(crate) unsafe fn block_timestamp() -> u64 {
145 0
146 }
147}
148
149#[unsafe(no_mangle)]
150#[cfg(not(feature = "dont-define-symbols"))]
151pub unsafe fn mark_used() {
152 unsafe { impls::pay_for_memory_grow(0) }
153 panic!();
154}
155
156pub fn write_result_slice(s: &[u8]) {
157 unsafe { impls::write_result(s.as_ptr(), s.len()) }
158}
159
160pub fn write_result_word(s: &U) {
161 write_result_slice(&s.0)
162}
163
164pub fn write_result_bool(v: bool) {
165 write_result_slice(&U::from(v).0)
166}
167
168pub use bobcat_cd::leftpad_addr;
169
170#[macro_export]
174macro_rules! revert_if_bad_call_vec {
175 ($e:expr) => {{
176 let (rc, rd) = $e;
177 if !rc {
178 $crate::write_result_slice(&rd);
179 return 1;
180 }
181 rd
182 }};
183}
184
185#[macro_export]
188macro_rules! revert_if_bad_call_unit_vec {
189 ($e:expr) => {{
190 let (rc, revertdata) = $e;
191 match (rc, revertdata) {
192 (true, _) => (),
193 (false, Some(v)) => {
194 $crate::write_result_slice(&v);
195 return 1;
196 }
197 (false, _) => return 1,
198 }
199 }};
200}
201
202#[macro_export]
204macro_rules! revert_if_bad_call_slice_vec {
205 ($e:expr) => {{
206 let (rc, returndata, revertdata) = $e;
207 match (rc, revertdata) {
208 (true, _) => returndata,
209 (false, Some(v)) => {
210 $crate::write_result_slice(&v);
211 return 1;
212 }
213 (false, _) => return 1,
214 }
215 }};
216}
217
218#[macro_export]
219macro_rules! write_result_exit_res {
220 ($ident:expr) => {{
221 match $ident {
222 Ok(v) => {
223 $crate::write_result_slice(&v);
224 0
225 }
226 Err(v) => {
227 $crate::write_result_slice(&v);
228 1
229 }
230 }
231 }};
232}
233
234#[macro_export]
235macro_rules! write_result_exit_create {
236 ($ident:expr) => {{
237 let (addr, b, i) = $ident;
238 if addr != [0u8; 20] {
239 $crate::write_result_slice(&leftpad_addr(addr));
240 0
241 } else {
242 $crate::write_result_slice(&b[..i]);
243 1
244 }
245 }};
246}
247
248#[macro_export]
249macro_rules! write_result_exit_call {
250 ($ident:expr) => {{
251 let (rc, l, v) = $ident;
252 $crate::write_result_slice(&v[..l]);
253 if rc {
254 0
255 } else {
256 1
257 }
258 }};
259}
260
261pub fn read_args<const CAP: usize>(len: usize) -> ([u8; CAP], usize) {
262 assert!(CAP >= len, "cap not enough");
263 let mut b = [0u8; CAP];
264 unsafe { impls::read_args(b.as_mut_ptr()) };
265 (b, len)
266}
267
268#[macro_export]
269macro_rules! read_args_safe {
270 ($len:expr, $max_len:expr) => {{
271 assert!($max_len >= $len);
272 $crate::read_args::<$max_len>($len).0
273 }};
274}
275
276#[cfg(feature = "alloc")]
277pub fn read_args_vec(len: usize) -> Vec<u8> {
278 let mut b = Vec::with_capacity(len);
279 unsafe {
280 impls::read_args(b.as_mut_ptr());
281 b.set_len(len);
282 };
283 b
284}
285
286pub fn msg_sender() -> Address {
287 let mut b = [0u8; 20];
288 unsafe { impls::msg_sender(b.as_mut_ptr()) }
289 b
290}
291
292pub fn contract_address() -> Address {
293 let mut b = [0u8; 20];
294 unsafe { impls::contract_address(b.as_mut_ptr()) }
295 b
296}
297
298pub fn msg_value() -> U {
299 let mut b = [0u8; 32];
300 unsafe { impls::msg_value(b.as_mut_ptr()) }
301 U(b)
302}
303
304pub fn code_hash(addr: Address) -> [u8; 32] {
305 let mut b = [0u8; 32];
306 unsafe { impls::account_codehash(addr.as_ptr(), b.as_mut_ptr()) };
307 b
308}
309
310pub fn chain_id() -> u64 {
311 unsafe { impls::chain_id() }
312}
313
314pub fn block_timestamp() -> u64 {
315 unsafe { impls::block_timestamp() }
316}