1use crate::error::{Error, Result};
10
11pub const STORAGE_KEY_BYTES: usize = 32;
13
14pub const STORAGE_VALUE_BYTES: usize = 32;
16
17pub const MAX_CALLDATA_SIZE: usize = 262_144;
19
20pub const MAX_RETURN_DATA_SIZE: usize = 262_144;
22
23pub const MAX_LOG_DATA_SIZE: usize = 65_536;
25
26pub const MAX_LOG_TOPICS: usize = 8;
28
29pub mod oracle_rc {
31 pub const MEM_ERR: i32 = -1;
33 pub const ENCODING_ERR: i32 = -2;
35 pub const URL_NOT_APPROVED: i32 = -3;
37 pub const PENDING: i32 = -5;
39 pub const EXPIRED: i32 = -6;
41 pub const RESPONSE_TOO_LARGE: i32 = -7;
43 pub const DEPTH_LIMIT_EXCEEDED: i32 = -8;
45}
46
47#[cfg(target_arch = "wasm32")]
48#[link(wasm_import_module = "env")]
49extern "C" {
50 fn storage_read(key_ptr: i32, key_len: i32, val_ptr: i32, val_len: i32) -> i32;
51 fn storage_write(key_ptr: i32, key_len: i32, val_ptr: i32, val_len: i32) -> i32;
52
53 fn get_caller(ptr: i32) -> i32;
54 fn get_owner(ptr: i32) -> i32;
55 fn get_contract_id(ptr: i32) -> i32;
56 fn get_height(ptr: i32) -> i32;
57 fn get_timestamp(ptr: i32) -> i32;
58 fn get_value(ptr: i32) -> i32;
59 fn get_calldata(ptr: i32) -> i32;
60
61 fn set_return_data(ptr: i32, len: i32) -> i32;
62 fn emit_log(topics_ptr: i32, topics_len: i32, data_ptr: i32, data_len: i32) -> i32;
63
64 fn call_contract(
65 contract_ptr: i32,
66 calldata_ptr: i32,
67 calldata_len: i32,
68 result_ptr: i32,
69 ) -> i32;
70 fn call_contract_v2(
71 contract_ptr: i32,
72 calldata_ptr: i32,
73 calldata_len: i32,
74 value_lo: i64,
75 value_hi: i64,
76 result_ptr: i32,
77 result_len: i32,
78 ) -> i32;
79
80 fn http_call(
81 url_ptr: i32,
82 url_len: i32,
83 method_ptr: i32,
84 method_len: i32,
85 body_ptr: i32,
86 body_len: i32,
87 result_ptr: i32,
88 ) -> i32;
89}
90
91#[cfg(not(target_arch = "wasm32"))]
92mod host_stub {
93 pub unsafe fn storage_read(_: i32, _: i32, _: i32, _: i32) -> i32 {
95 -127
96 }
97 pub unsafe fn storage_write(_: i32, _: i32, _: i32, _: i32) -> i32 {
98 -127
99 }
100
101 pub unsafe fn get_caller(_: i32) -> i32 {
102 -127
103 }
104 pub unsafe fn get_owner(_: i32) -> i32 {
105 -127
106 }
107 pub unsafe fn get_contract_id(_: i32) -> i32 {
108 -127
109 }
110 pub unsafe fn get_height(_: i32) -> i32 {
111 -127
112 }
113 pub unsafe fn get_timestamp(_: i32) -> i32 {
114 -127
115 }
116 pub unsafe fn get_value(_: i32) -> i32 {
117 -127
118 }
119 pub unsafe fn get_calldata(_: i32) -> i32 {
120 -127
121 }
122
123 pub unsafe fn set_return_data(_: i32, _: i32) -> i32 {
124 -127
125 }
126 pub unsafe fn emit_log(_: i32, _: i32, _: i32, _: i32) -> i32 {
127 -127
128 }
129
130 pub unsafe fn call_contract(_: i32, _: i32, _: i32, _: i32) -> i32 {
131 -127
132 }
133 pub unsafe fn call_contract_v2(_: i32, _: i32, _: i32, _: i64, _: i64, _: i32, _: i32) -> i32 {
134 -127
135 }
136
137 pub unsafe fn http_call(_: i32, _: i32, _: i32, _: i32, _: i32, _: i32, _: i32) -> i32 {
138 -127
139 }
140}
141
142#[cfg(not(target_arch = "wasm32"))]
143use host_stub::*;
144
145#[inline]
149fn check_rc(rc: i32) -> Result<i32> {
150 if rc < 0 {
151 return Err(Error::new(rc));
152 }
153 Ok(rc)
154}
155
156pub fn storage_read_32(key: &[u8; STORAGE_KEY_BYTES]) -> Result<[u8; STORAGE_VALUE_BYTES]> {
158 let mut out = [0u8; STORAGE_VALUE_BYTES];
159 let rc = unsafe {
160 storage_read(
161 key.as_ptr() as i32,
162 STORAGE_KEY_BYTES as i32,
163 out.as_mut_ptr() as i32,
164 STORAGE_VALUE_BYTES as i32,
165 )
166 };
167 check_rc(rc)?;
168 Ok(out)
169}
170
171pub fn storage_write_32(
173 key: &[u8; STORAGE_KEY_BYTES],
174 value: &[u8; STORAGE_VALUE_BYTES],
175) -> Result<()> {
176 let rc = unsafe {
177 storage_write(
178 key.as_ptr() as i32,
179 STORAGE_KEY_BYTES as i32,
180 value.as_ptr() as i32,
181 STORAGE_VALUE_BYTES as i32,
182 )
183 };
184 check_rc(rc)?;
185 Ok(())
186}
187
188pub fn get_caller_32() -> Result<[u8; STORAGE_KEY_BYTES]> {
190 let mut out = [0u8; STORAGE_KEY_BYTES];
191 let rc = unsafe { get_caller(out.as_mut_ptr() as i32) };
192 check_rc(rc)?;
193 Ok(out)
194}
195
196pub fn get_owner_32() -> Result<[u8; STORAGE_KEY_BYTES]> {
198 let mut out = [0u8; STORAGE_KEY_BYTES];
199 let rc = unsafe { get_owner(out.as_mut_ptr() as i32) };
200 check_rc(rc)?;
201 Ok(out)
202}
203
204pub fn get_contract_id_32() -> Result<[u8; STORAGE_KEY_BYTES]> {
206 let mut out = [0u8; STORAGE_KEY_BYTES];
207 let rc = unsafe { get_contract_id(out.as_mut_ptr() as i32) };
208 check_rc(rc)?;
209 Ok(out)
210}
211
212pub fn get_height_u64() -> Result<u64> {
214 let mut bytes = [0u8; 8];
215 let rc = unsafe { get_height(bytes.as_mut_ptr() as i32) };
216 check_rc(rc)?;
217 Ok(u64::from_le_bytes(bytes))
218}
219
220pub fn get_timestamp_u64() -> Result<u64> {
222 let mut bytes = [0u8; 8];
223 let rc = unsafe { get_timestamp(bytes.as_mut_ptr() as i32) };
224 check_rc(rc)?;
225 Ok(u64::from_le_bytes(bytes))
226}
227
228pub fn get_value_u128() -> Result<u128> {
230 let mut bytes = [0u8; 16];
231 let rc = unsafe { get_value(bytes.as_mut_ptr() as i32) };
232 check_rc(rc)?;
233 Ok(u128::from_le_bytes(bytes))
234}
235
236pub fn read_calldata(buf: &mut [u8]) -> Result<usize> {
240 if buf.len() > MAX_CALLDATA_SIZE {
241 return Err(Error::new(-2));
242 }
243 let rc = unsafe { get_calldata(buf.as_mut_ptr() as i32) };
244 let len = check_rc(rc)? as usize;
245 Ok(len.min(buf.len()))
246}
247
248pub fn set_return_data_bytes(bytes: &[u8]) -> Result<()> {
250 if bytes.len() > MAX_RETURN_DATA_SIZE {
251 return Err(Error::new(-2));
252 }
253 let rc = unsafe { set_return_data(bytes.as_ptr() as i32, bytes.len() as i32) };
254 check_rc(rc)?;
255 Ok(())
256}
257
258pub fn emit_log_bytes(flat_topics: &[u8], data: &[u8]) -> Result<()> {
260 if data.len() > MAX_LOG_DATA_SIZE {
261 return Err(Error::new(-2));
262 }
263 if flat_topics.len() > MAX_LOG_TOPICS * STORAGE_KEY_BYTES
264 || flat_topics.len() % STORAGE_KEY_BYTES != 0
265 {
266 return Err(Error::new(-2));
267 }
268 let rc = unsafe {
269 emit_log(
270 flat_topics.as_ptr() as i32,
271 flat_topics.len() as i32,
272 data.as_ptr() as i32,
273 data.len() as i32,
274 )
275 };
276 check_rc(rc)?;
277 Ok(())
278}
279
280pub fn call_contract_legacy(
282 contract_id: &[u8; STORAGE_KEY_BYTES],
283 calldata: &[u8],
284 out: &mut [u8],
285) -> Result<usize> {
286 let rc = unsafe {
287 call_contract(
288 contract_id.as_ptr() as i32,
289 calldata.as_ptr() as i32,
290 calldata.len() as i32,
291 out.as_mut_ptr() as i32,
292 )
293 };
294 Ok(check_rc(rc)? as usize)
295}
296
297pub fn call_contract_v2_with_value(
299 contract_id: &[u8; STORAGE_KEY_BYTES],
300 calldata: &[u8],
301 value: u128,
302 out: &mut [u8],
303) -> Result<usize> {
304 let lo = value as u64 as i64;
305 let hi = (value >> 64) as u64 as i64;
306 let rc = unsafe {
307 call_contract_v2(
308 contract_id.as_ptr() as i32,
309 calldata.as_ptr() as i32,
310 calldata.len() as i32,
311 lo,
312 hi,
313 out.as_mut_ptr() as i32,
314 out.len() as i32,
315 )
316 };
317 Ok(check_rc(rc)? as usize)
318}
319
320pub fn http_call_bytes(url: &[u8], method: &[u8], body: &[u8], out: &mut [u8]) -> Result<usize> {
324 let rc = unsafe {
325 http_call(
326 url.as_ptr() as i32,
327 url.len() as i32,
328 method.as_ptr() as i32,
329 method.len() as i32,
330 body.as_ptr() as i32,
331 body.len() as i32,
332 out.as_mut_ptr() as i32,
333 )
334 };
335 Ok(check_rc(rc)? as usize)
336}