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
11type Address = [u8; 20];
12
13pub use bobcat_cd::read_words;
14
15pub use bobcat_host as host;
16
17pub fn balance(addr: Address) -> U {
18    let mut out = U::ZERO;
19    unsafe { host::account_balance(addr.as_ptr(), out.as_mut_ptr()) }
20    out
21}
22
23#[unsafe(no_mangle)]
24#[cfg(all(
25    target_family = "wasm",
26    target_os = "unknown",
27    not(feature = "dont-define-symbols")
28))]
29pub unsafe fn mark_used() {
30    unsafe { host::pay_for_memory_grow(0) }
31    panic!();
32}
33
34pub fn write_result_slice(s: &[u8]) {
35    unsafe { host::write_result(s.as_ptr(), s.len()) }
36}
37
38pub fn write_result_word(s: &U) {
39    write_result_slice(&s.0)
40}
41
42pub fn write_result_bool(v: bool) {
43    write_result_slice(&U::from(v).0)
44}
45
46pub fn return_data_size() -> usize {
47    unsafe { host::return_data_size() }
48}
49
50pub use bobcat_cd::leftpad_addr;
51
52/// Like write_result_exit_call, except it only reverts with the
53/// returndata if the underlying call reverted. If it doesn't, then it
54/// just returns the slice.
55#[macro_export]
56macro_rules! revert_if_bad_call_vec {
57    ($e:expr) => {{
58        let (rc, rd) = $e;
59        if !rc {
60            $crate::write_result_slice(&rd);
61            return 1;
62        }
63        rd
64    }};
65}
66
67/// Reverts if the underlying call failed, using the vector that was
68/// returned as the third argument as slice.
69#[macro_export]
70macro_rules! revert_if_bad_call_unit_vec {
71    ($e:expr) => {{
72        let (rc, revertdata) = $e;
73        match (rc, revertdata) {
74            (true, _) => (),
75            (false, Some(v)) => {
76                $crate::write_result_slice(&v);
77                return 1;
78            }
79            (false, _) => return 1,
80        }
81    }};
82}
83
84/// Reverts with a message if the revertdata is Some, and if the rc is false.
85#[macro_export]
86macro_rules! revert_if_bad_call_slice_vec {
87    ($e:expr) => {{
88        let (rc, returndata, revertdata) = $e;
89        match (rc, revertdata) {
90            (true, _) => returndata,
91            (false, Some(v)) => {
92                $crate::write_result_slice(&v);
93                return 1;
94            }
95            (false, _) => return 1,
96        }
97    }};
98}
99
100#[macro_export]
101macro_rules! write_result_exit_res {
102    ($ident:expr) => {{
103        match $ident {
104            Ok(v) => {
105                $crate::write_result_slice(&v);
106                0
107            }
108            Err(v) => {
109                $crate::write_result_slice(&v);
110                1
111            }
112        }
113    }};
114}
115
116#[macro_export]
117macro_rules! write_result_exit_create {
118    ($ident:expr) => {{
119        let (addr, b, i) = $ident;
120        if addr != [0u8; 20] {
121            $crate::write_result_slice(&leftpad_addr(addr));
122            0
123        } else {
124            $crate::write_result_slice(&b[..i]);
125            1
126        }
127    }};
128}
129
130#[macro_export]
131macro_rules! write_result_exit_call {
132    ($ident:expr) => {{
133        let (rc, l, v) = $ident;
134        $crate::write_result_slice(&v[..l]);
135        if rc { 0 } else { 1 }
136    }};
137}
138
139pub fn read_args<const CAP: usize>(len: usize) -> ([u8; CAP], usize) {
140    assert!(CAP >= len, "cap not enough");
141    let mut b = [0u8; CAP];
142    unsafe { host::read_args(b.as_mut_ptr()) };
143    (b, len)
144}
145
146#[cfg(all(target_arch = "riscv32", target_os = "none"))]
147pub fn args_len() -> usize {
148    unsafe { host::args_len() }
149}
150
151#[macro_export]
152macro_rules! read_args_safe {
153    ($len:expr, $max_len:expr) => {{
154        assert!($max_len >= $len, "{} < {}", $max_len, $len);
155        $crate::read_args::<$max_len>($len).0
156    }};
157}
158
159#[cfg(feature = "alloc")]
160pub fn read_args_vec(len: usize) -> Vec<u8> {
161    let mut b = Vec::with_capacity(len);
162    unsafe {
163        host::read_args(b.as_mut_ptr());
164        b.set_len(len);
165    };
166    b
167}
168
169pub fn msg_sender() -> Address {
170    let mut b = [0u8; 20];
171    unsafe { host::msg_sender(b.as_mut_ptr()) }
172    b
173}
174
175pub fn contract_address() -> Address {
176    let mut b = [0u8; 20];
177    unsafe { host::contract_address(b.as_mut_ptr()) }
178    b
179}
180
181pub fn msg_value() -> U {
182    let mut b = [0u8; 32];
183    unsafe { host::msg_value(b.as_mut_ptr()) }
184    U(b)
185}
186
187pub fn code_size(addr: Address) -> usize {
188    unsafe { host::account_code_size(addr.as_ptr()) }
189}
190
191pub fn code_slice<const CAP: usize>(
192    addr: Address,
193    size: usize,
194    offset: usize,
195) -> ([u8; CAP], usize) {
196    let mut b = [0u8; CAP];
197    assert!(CAP >= size, "not enough size: {size}, capacity: {CAP}");
198    let rd = unsafe { host::account_code(addr.as_ptr(), offset, size, b.as_mut_ptr()) };
199    (b, rd)
200}
201
202#[cfg(feature = "alloc")]
203pub fn code_vec_size(addr: Address, offset: usize, size: usize) -> Vec<u8> {
204    let mut b = Vec::with_capacity(size);
205    let rd = unsafe { host::account_code(addr.as_ptr(), offset, size, b.as_mut_ptr()) };
206    unsafe { b.set_len(rd) };
207    b
208}
209
210#[cfg(feature = "alloc")]
211pub fn code_vec(addr: Address, offset: usize) -> Vec<u8> {
212    code_vec_size(addr, offset, code_size(addr))
213}
214
215pub fn code_hash(addr: Address) -> U {
216    let mut b = U::ZERO;
217    unsafe { host::account_codehash(addr.as_ptr(), b.as_mut_ptr()) };
218    b
219}
220
221pub fn chain_id() -> u64 {
222    unsafe { host::chainid() }
223}
224
225pub fn block_timestamp() -> u64 {
226    unsafe { host::block_timestamp() }
227}
228
229pub fn block_basefee() -> U {
230    let mut out = U::ZERO;
231    unsafe { host::block_basefee(out.as_mut_ptr()) }
232    out
233}
234
235pub fn evm_gas_left() -> u64 {
236    unsafe { host::evm_gas_left() }
237}
238
239pub fn evm_ink_left() -> u64 {
240    unsafe { host::evm_ink_left() }
241}
242
243pub unsafe fn exit_early(code: usize) -> ! {
244    unsafe { host::exit_early(code as i32) }
245}