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