bobcat_entry/
lib.rs

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"))]
33mod impls {
34    use core::{ptr::copy_nonoverlapping, slice::from_raw_parts};
35
36    #[allow(unused)]
37    pub(crate) unsafe fn pay_for_memory_grow(_: u16) {}
38
39    pub(crate) unsafe fn write_result(d: *const u8, l: usize) {
40        println!("{}", const_hex::encode(unsafe { from_raw_parts(d, l) }));
41    }
42
43    pub(crate) unsafe fn read_args(_out: *mut u8) {
44        unimplemented!("read from stdin separately. todo");
45    }
46
47    pub(crate) unsafe fn msg_sender(out: *mut u8) {
48        unsafe { copy_nonoverlapping([0u8; 32].as_ptr(), out, 32) }
49    }
50
51    pub(crate) unsafe fn contract_address(out: *mut u8) {
52        unsafe { copy_nonoverlapping([0u8; 32].as_ptr(), out, 32) }
53    }
54
55    pub(crate) unsafe fn msg_value(out: *mut u8) {
56        unsafe { copy_nonoverlapping([0u8; 32].as_ptr(), out, 32) }
57    }
58
59    pub(crate) unsafe fn chain_id() -> u64 {
60        0
61    }
62
63    pub(crate) unsafe fn account_codehash(_: *const u8, _: *mut u8) {
64    }
65
66    pub(crate) unsafe fn block_timestamp() -> u64 {
67        0
68    }
69}
70
71#[cfg(all(not(target_arch = "wasm32"), not(feature = "std")))]
72mod impls {
73    pub(crate) unsafe fn pay_for_memory_grow(_: u16) {}
74
75    pub(crate) unsafe fn write_result(_: *const u8, _: usize) {}
76
77    pub(crate) unsafe fn read_args(_out: *mut u8) {}
78
79    pub(crate) unsafe fn msg_sender(_: *mut u8) {}
80
81    pub(crate) unsafe fn contract_address(_: *mut u8) {}
82
83    pub(crate) unsafe fn msg_value(_: *mut u8) {}
84
85    pub(crate) unsafe fn chain_id() -> u64 {
86        0
87    }
88
89    pub(crate) unsafe fn account_codehash(_: *const u8, _: *mut u8) {
90    }
91
92    pub(crate) unsafe fn block_timestamp() -> u64 {
93        0
94    }
95}
96
97#[unsafe(no_mangle)]
98#[cfg(not(feature = "dont-define-symbols"))]
99pub unsafe fn mark_used() {
100    unsafe { impls::pay_for_memory_grow(0) }
101    panic!();
102}
103
104pub fn write_result_slice(s: &[u8]) {
105    unsafe { impls::write_result(s.as_ptr(), s.len()) }
106}
107
108pub fn write_result_word(s: &U) {
109    write_result_slice(&s.0)
110}
111
112pub fn write_result_bool(v: bool) {
113    write_result_slice(&U::from(v).0)
114}
115
116pub use bobcat_cd::leftpad_addr;
117
118/// Like write_result_exit_call, except it only reverts with the
119/// returndata if the underlying call reverted. If it doesn't, then it
120/// just returns the slice.
121#[macro_export]
122macro_rules! revert_if_bad_call_vec {
123    ($e:expr) => {{
124        let (rc, rd) = $e;
125        if !rc {
126            $crate::write_result_slice(&rd);
127            return 1;
128        }
129        rd
130    }};
131}
132
133/// Reverts if the underlying call failed, using the vector that was
134/// returned as the third argument as slice.
135#[macro_export]
136macro_rules! revert_if_bad_call_unit_vec {
137    ($e:expr) => {{
138        let (rc, revertdata) = $e;
139        match (rc, revertdata) {
140            (true, _) => (),
141            (false, Some(v)) => {
142                $crate::write_result_slice(&v);
143                return 1;
144            }
145            (false, _) => return 1,
146        }
147    }};
148}
149
150/// Reverts with a message if the revertdata is Some, and if the rc is false.
151#[macro_export]
152macro_rules! revert_if_bad_call_slice_vec {
153    ($e:expr) => {{
154        let (rc, returndata, revertdata) = $e;
155        match (rc, revertdata) {
156            (true, _) => returndata,
157            (false, Some(v)) => {
158                $crate::write_result_slice(&v);
159                return 1;
160            }
161            (false, _) => return 1,
162        }
163    }};
164}
165
166#[macro_export]
167macro_rules! write_result_exit_res {
168    ($ident:expr) => {{
169        match $ident {
170            Ok(v) => {
171                $crate::write_result_slice(&v);
172                0
173            }
174            Err(v) => {
175                $crate::write_result_slice(&v);
176                1
177            }
178        }
179    }};
180}
181
182#[macro_export]
183macro_rules! write_result_exit_create {
184    ($ident:expr) => {{
185        let (addr, b, i) = $ident;
186        if addr != [0u8; 20] {
187            $crate::write_result_slice(&leftpad_addr(addr));
188            0
189        } else {
190            $crate::write_result_slice(&b[..i]);
191            1
192        }
193    }};
194}
195
196#[macro_export]
197macro_rules! write_result_exit_call {
198    ($ident:expr) => {{
199        let (rc, l, v) = $ident;
200        $crate::write_result_slice(&v[..l]);
201        if rc {
202            0
203        } else {
204            1
205        }
206    }};
207}
208
209pub fn read_args<const CAP: usize>(len: usize) -> ([u8; CAP], usize) {
210    assert!(CAP >= len, "cap not enough");
211    let mut b = [0u8; CAP];
212    unsafe { impls::read_args(b.as_mut_ptr()) };
213    (b, len)
214}
215
216#[macro_export]
217macro_rules! read_args_safe {
218    ($len:expr, $max_len:expr) => {{
219        assert!($max_len >= $len);
220        $crate::read_args::<$max_len>($len).0
221    }};
222}
223
224#[cfg(feature = "alloc")]
225pub fn read_args_vec(len: usize) -> Vec<u8> {
226    let mut b = Vec::with_capacity(len);
227    unsafe {
228        impls::read_args(b.as_mut_ptr());
229        b.set_len(len);
230    };
231    b
232}
233
234pub fn msg_sender() -> Address {
235    let mut b = [0u8; 20];
236    unsafe { impls::msg_sender(b.as_mut_ptr()) }
237    b
238}
239
240pub fn contract_address() -> Address {
241    let mut b = [0u8; 20];
242    unsafe { impls::contract_address(b.as_mut_ptr()) }
243    b
244}
245
246pub fn msg_value() -> U {
247    let mut b = [0u8; 32];
248    unsafe { impls::msg_value(b.as_mut_ptr()) }
249    U(b)
250}
251
252pub fn code_hash(addr: Address) -> [u8; 32] {
253    let mut b = [0u8; 32];
254    unsafe { impls::account_codehash(addr.as_ptr(), b.as_mut_ptr()) };
255    b
256}
257
258pub fn chain_id() -> u64 {
259    unsafe { impls::chain_id() }
260}
261
262pub fn block_timestamp() -> u64 {
263    unsafe { impls::block_timestamp() }
264}