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