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
17use array_concat::concat_arrays;
18
19pub fn balance(addr: Address) -> U {
20 let mut out = U::ZERO;
21 unsafe { host::account_balance(addr.as_ptr(), out.as_mut_ptr()) }
22 out
23}
24
25#[unsafe(no_mangle)]
26#[cfg(all(
27 target_family = "wasm",
28 target_os = "unknown",
29 not(feature = "dont-define-symbols")
30))]
31pub unsafe fn mark_used() {
32 unsafe { host::pay_for_memory_grow(0) }
33 panic!();
34}
35
36pub fn write_result_slice(s: &[u8]) {
38 unsafe { host::write_result(s.as_ptr(), s.len()) }
39}
40
41pub fn write_result_word(s: &U) {
42 write_result_slice(&s.0)
43}
44
45pub fn write_result_bool(v: bool) {
46 write_result_slice(&U::from(v).0)
47}
48
49const OFFSET_ARR: [u8; 32] = U::from_u32(32).0;
50
51pub fn write_result_array_slice<const ARR_LEN: usize, const CD_LEN: usize>(arr: [u8; ARR_LEN]) {
54 assert!(
55 ARR_LEN + 32 * 2 == CD_LEN,
56 "bad array length, need: {}",
57 ARR_LEN + 32 * 2
58 );
59 let U(len_arr) = U::from_usize(ARR_LEN);
60 let x: [u8; ARR_LEN] = concat_arrays!(OFFSET_ARR, len_arr, arr);
61 write_result_slice(&x)
62}
63
64#[cfg(feature = "alloc")]
65pub fn write_result_array_vec(arr: Vec<u8>) {
66 let mut v = Vec::with_capacity(32 * 2 + arr.len());
67 v.extend_from_slice(&U::from_usize(32).0);
68 v.extend_from_slice(&U::from_usize(arr.len()).0);
69 v.extend(arr);
70 write_result_slice(&v)
71}
72
73pub fn return_data_size() -> usize {
74 unsafe { host::return_data_size() }
75}
76
77pub use bobcat_cd::leftpad_addr;
78
79#[macro_export]
83macro_rules! revert_if_bad_call_vec {
84 ($e:expr) => {{
85 let (rc, rd) = $e;
86 if !rc {
87 $crate::write_result_slice(&rd);
88 return 1;
89 }
90 rd
91 }};
92}
93
94#[macro_export]
97macro_rules! revert_if_bad_call_unit_vec {
98 ($e:expr) => {{
99 let (rc, revertdata) = $e;
100 match (rc, revertdata) {
101 (true, _) => (),
102 (false, Some(v)) => {
103 $crate::write_result_slice(&v);
104 return 1;
105 }
106 (false, _) => return 1,
107 }
108 }};
109}
110
111#[macro_export]
113macro_rules! revert_if_bad_call_slice_vec {
114 ($e:expr) => {{
115 let (rc, returndata, revertdata) = $e;
116 match (rc, revertdata) {
117 (true, _) => returndata,
118 (false, Some(v)) => {
119 $crate::write_result_slice(&v);
120 return 1;
121 }
122 (false, _) => return 1,
123 }
124 }};
125}
126
127#[macro_export]
128macro_rules! write_result_exit_res {
129 ($ident:expr) => {{
130 match $ident {
131 Ok(v) => {
132 $crate::write_result_slice(&v);
133 0
134 }
135 Err(v) => {
136 $crate::write_result_slice(&v);
137 1
138 }
139 }
140 }};
141}
142
143#[macro_export]
144macro_rules! write_result_exit_create {
145 ($ident:expr) => {{
146 let (addr, b, i) = $ident;
147 if addr != [0u8; 20] {
148 $crate::write_result_slice(&leftpad_addr(addr));
149 0
150 } else {
151 $crate::write_result_slice(&b[..i]);
152 1
153 }
154 }};
155}
156
157#[macro_export]
158macro_rules! write_result_exit_call {
159 ($ident:expr) => {{
160 let (rc, l, v) = $ident;
161 $crate::write_result_slice(&v[..l]);
162 if rc { 0 } else { 1 }
163 }};
164}
165
166pub fn read_args<const CAP: usize>(len: usize) -> ([u8; CAP], usize) {
170 assert!(CAP >= len, "cap not enough");
171 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
174 let mut b = unsafe { core::mem::MaybeUninit::<[u8; CAP]>::uninit().assume_init() };
175 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
177 let mut b = [0u8; CAP];
178 unsafe { host::read_args(b.as_mut_ptr()) };
179 (b, len)
180}
181
182#[cfg(all(target_arch = "riscv32", target_os = "none"))]
183pub fn args_len() -> usize {
184 unsafe { host::args_len() }
185}
186
187#[macro_export]
188macro_rules! read_args_safe {
189 ($len:expr, $max_len:expr) => {{
190 core::assert!($max_len >= $len, "{} < {}", $max_len, $len);
191 $crate::read_args::<$max_len>($len).0
192 }};
193}
194
195#[cfg(feature = "alloc")]
196pub fn read_args_vec(len: usize) -> Vec<u8> {
197 let mut b = Vec::with_capacity(len);
198 unsafe {
199 host::read_args(b.as_mut_ptr());
200 b.set_len(len);
201 };
202 b
203}
204
205pub fn msg_sender() -> Address {
206 let mut b = [0u8; 20];
207 unsafe { host::msg_sender(b.as_mut_ptr()) }
208 b
209}
210
211pub fn contract_address() -> Address {
212 let mut b = [0u8; 20];
213 unsafe { host::contract_address(b.as_mut_ptr()) }
214 b
215}
216
217pub fn msg_value() -> U {
218 let mut b = [0u8; 32];
219 unsafe { host::msg_value(b.as_mut_ptr()) }
220 U(b)
221}
222
223pub fn code_size(addr: Address) -> usize {
224 unsafe { host::account_code_size(addr.as_ptr()) }
225}
226
227pub fn code_slice<const CAP: usize>(
228 addr: Address,
229 size: usize,
230 offset: usize,
231) -> ([u8; CAP], usize) {
232 let mut b = [0u8; CAP];
233 assert!(CAP >= size, "not enough size: {size}, capacity: {CAP}");
234 let rd = unsafe { host::account_code(addr.as_ptr(), offset, size, b.as_mut_ptr()) };
235 (b, rd)
236}
237
238#[cfg(feature = "alloc")]
239pub fn code_vec_size(addr: Address, offset: usize, size: usize) -> Vec<u8> {
240 let mut b = Vec::with_capacity(size);
241 let rd = unsafe { host::account_code(addr.as_ptr(), offset, size, b.as_mut_ptr()) };
242 unsafe { b.set_len(rd) };
243 b
244}
245
246#[cfg(feature = "alloc")]
247pub fn code_vec(addr: Address, offset: usize) -> Vec<u8> {
248 code_vec_size(addr, offset, code_size(addr))
249}
250
251pub fn code_hash(addr: Address) -> U {
252 let mut b = U::ZERO;
253 unsafe { host::account_codehash(addr.as_ptr(), b.as_mut_ptr()) };
254 b
255}
256
257pub fn chain_id() -> u64 {
258 unsafe { host::chainid() }
259}
260
261pub fn block_timestamp() -> u64 {
262 unsafe { host::block_timestamp() }
263}
264
265pub fn block_basefee() -> U {
266 let mut out = U::ZERO;
267 unsafe { host::block_basefee(out.as_mut_ptr()) }
268 out
269}
270
271pub fn evm_gas_left() -> u64 {
272 unsafe { host::evm_gas_left() }
273}
274
275pub fn evm_ink_left() -> u64 {
276 unsafe { host::evm_ink_left() }
277}
278
279pub unsafe fn exit_early(code: usize) -> ! {
280 unsafe { host::exit_early(code as i32) }
281}
282
283pub unsafe fn storage_flush_cache(clear: bool) {
284 unsafe { host::storage_flush_cache(clear) }
285}