1#![no_std]
2
3extern crate alloc;
4#[cfg(test)]
5extern crate std;
6
7pub mod decoder;
8pub mod encoder;
9pub mod error;
10pub mod event;
11pub mod types;
12pub mod zbytes_fixed;
13
14pub use decoder::{
15 decode_call_result, decode_revert, read_address_from_word, read_array_dyn, read_array_fixed,
16 read_bool, read_bytes, read_i128, read_i16, read_i32, read_i64, read_i8, read_int256,
17 read_selector, read_string, read_u128, read_u16, read_u256, read_u32, read_u64, read_u8,
18 skip_selector,
19};
20pub use encoder::{encode_address, encode_bool, encode_bytes_data, encode_u256};
21pub use error::ZError;
22pub use event::{
23 read_topic_address, read_topic_bool, read_topic_int256, read_topic_u256, ZEventLog,
24};
25pub use types::{ZAddress, ZArray, ZBool, ZBytes, ZCallResult, ZInt256, ZRevert, ZString, ZU256};
26pub use zbytes_fixed::{
27 read_bytes1, read_bytes16, read_bytes2, read_bytes20, read_bytes3, read_bytes32, read_bytes4,
28 read_bytes8, read_bytes_n, ZBytesN,
29};
30
31#[cfg(feature = "derive")]
32pub use zabi_derive::ZDecode;
33
34#[macro_export]
51macro_rules! decode_tuple {
52 ($data:expr, $($T:ty),+ $(,)?) => {{
53 let data: &[u8] = $data;
54 let mut offset: usize = 0;
55 (|| -> Result<($($T,)+), $crate::ZError> {
56 Ok((
57 $(
58 {
59 let val = <$T as $crate::ZDecode>::decode(data, offset)?;
60 offset += <$T as $crate::ZDecode>::HEAD_SIZE;
61 val
62 }
63 ,)+
64 ))
65 })()
66 }};
67}
68
69#[macro_export]
89macro_rules! decode_call {
90 ($data:expr, $($T:ty),+ $(,)?) => {{
91 let data: &[u8] = $data;
92 (|| -> Result<($($T,)+), $crate::ZError> {
93 let params = $crate::skip_selector(data)?;
94 let mut offset: usize = 0;
95 Ok((
96 $({
97 let val = <$T as $crate::ZDecode>::decode(params, offset)?;
98 offset += <$T as $crate::ZDecode>::HEAD_SIZE;
99 val
100 },)+
101 ))
102 })()
103 }};
104}
105
106#[macro_export]
108macro_rules! revert_to_string {
109 ($revert:expr) => {
110 match $revert {
111 $crate::ZRevert::Error(s) => s.0,
112 $crate::ZRevert::Panic(p) => {
113 let code = p.to_u32().unwrap_or(0);
114 match code {
115 0x01 => "Assertion violation",
116 0x11 => "Arithmetic overflow/underflow",
117 0x12 => "Division by zero",
118 0x21 => "Invalid enum value",
119 0x22 => "Invalid storage byte array",
120 0x31 => "Pop on empty array",
121 0x32 => "Index out of bounds",
122 0x41 => "Out of memory",
123 0x51 => "Invalid internal function",
124 _ => "Unknown Panic",
125 }
126 }
127 $crate::ZRevert::Custom(sel, _) => "Custom Error",
128 $crate::ZRevert::Unknown => "Unknown Error",
129 }
130 };
131}
132
133pub trait ZDecode<'a>: Sized {
136 const HEAD_SIZE: usize = 32; fn decode(data: &'a [u8], offset: usize) -> Result<Self, ZError>;
138}
139
140impl<'a> ZDecode<'a> for ZU256<'a> {
141 const HEAD_SIZE: usize = 32;
142 fn decode(data: &'a [u8], offset: usize) -> Result<Self, ZError> {
143 decoder::read_u256(data, offset)
144 }
145}
146
147impl<'a> ZDecode<'a> for ZAddress<'a> {
148 const HEAD_SIZE: usize = 32;
149 fn decode(data: &'a [u8], offset: usize) -> Result<Self, ZError> {
150 decoder::read_address_from_word(data, offset)
151 }
152}
153
154impl<'a> ZDecode<'a> for ZBool {
155 const HEAD_SIZE: usize = 32;
156 fn decode(data: &'a [u8], offset: usize) -> Result<Self, ZError> {
157 decoder::read_bool(data, offset)
158 }
159}
160
161impl<'a> ZDecode<'a> for ZInt256<'a> {
162 const HEAD_SIZE: usize = 32;
163 fn decode(data: &'a [u8], offset: usize) -> Result<Self, ZError> {
164 decoder::read_int256(data, offset)
165 }
166}
167
168macro_rules! impl_zdecode_primitive {
169 ($t:ty, $func:path) => {
170 impl<'a> ZDecode<'a> for $t {
171 const HEAD_SIZE: usize = 32;
172 fn decode(data: &'a [u8], offset: usize) -> Result<Self, ZError> {
173 $func(data, offset)
174 }
175 }
176 };
177}
178
179impl_zdecode_primitive!(u8, decoder::read_u8);
180impl_zdecode_primitive!(u16, decoder::read_u16);
181impl_zdecode_primitive!(u32, decoder::read_u32);
182impl_zdecode_primitive!(u64, decoder::read_u64);
183impl_zdecode_primitive!(u128, decoder::read_u128);
184
185impl_zdecode_primitive!(i8, decoder::read_i8);
186impl_zdecode_primitive!(i16, decoder::read_i16);
187impl_zdecode_primitive!(i32, decoder::read_i32);
188impl_zdecode_primitive!(i64, decoder::read_i64);
189impl_zdecode_primitive!(i128, decoder::read_i128);
190
191impl<'a, T: ZDecode<'a>> ZDecode<'a> for ZArray<'a, T> {
192 const HEAD_SIZE: usize = 32;
193 fn decode(data: &'a [u8], offset: usize) -> Result<Self, ZError> {
194 decoder::read_array_dyn(data, offset)
195 }
196}
197
198impl<'a, const N: usize> ZDecode<'a> for ZBytesN<'a, N> {
199 const HEAD_SIZE: usize = 32;
200 fn decode(data: &'a [u8], offset: usize) -> Result<Self, ZError> {
201 zbytes_fixed::read_bytes_n(data, offset)
202 }
203}
204
205macro_rules! impl_zdecode_tuple {
206 ($($T:ident),+) => {
207 impl<'a, $($T: ZDecode<'a>),+> ZDecode<'a> for ($($T,)+) {
208 const HEAD_SIZE: usize = 0 $(+ <$T as ZDecode>::HEAD_SIZE)*;
209 fn decode(data: &'a [u8], offset: usize) -> Result<Self, ZError> {
210 if offset > data.len() {
211 return Err(ZError::OutOfBounds(offset, data.len()));
212 }
213 let data = &data[offset..];
214
215 let mut offset: usize = 0;
216 #[allow(unused_assignments)]
217 Ok((
218 $({
219 let val = <$T as ZDecode>::decode(data, offset)?;
220 offset += <$T as ZDecode>::HEAD_SIZE;
221 val
222 },)+
223 ))
224 }
225 }
226 };
227}
228
229impl_zdecode_tuple!(T1);
230impl_zdecode_tuple!(T1, T2);
231impl_zdecode_tuple!(T1, T2, T3);
232impl_zdecode_tuple!(T1, T2, T3, T4);
233impl_zdecode_tuple!(T1, T2, T3, T4, T5);
234impl_zdecode_tuple!(T1, T2, T3, T4, T5, T6);
235impl_zdecode_tuple!(T1, T2, T3, T4, T5, T6, T7);
236impl_zdecode_tuple!(T1, T2, T3, T4, T5, T6, T7, T8);
237impl_zdecode_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
238impl_zdecode_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
239impl_zdecode_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
240impl_zdecode_tuple!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
241
242impl<'a> ZDecode<'a> for ZString<'a> {
243 const HEAD_SIZE: usize = 32;
244 fn decode(data: &'a [u8], offset: usize) -> Result<Self, ZError> {
245 decoder::read_string(data, offset)
246 }
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252 use alloc::vec::Vec;
253
254 #[test]
255 fn test_zero_copy_decode_manual() {
256 let mut data = Vec::new();
262
263 let mut p1 = [0u8; 32];
265 p1[31] = 1;
266 data.extend_from_slice(&p1);
267
268 let mut p2 = [0u8; 32];
270 let addr_bytes = [
271 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44,
272 0x55, 0x66, 0x77, 0x88, 0x99, 0x00,
273 ];
274 p2[12..32].copy_from_slice(&addr_bytes);
275 data.extend_from_slice(&p2);
276
277 let decoded_u256 = read_u256(&data, 0).expect("failed to decode u256");
279 let decoded_addr = read_address_from_word(&data, 32).expect("failed to decode address");
280
281 assert_eq!(decoded_u256.0[31], 1);
283 assert_eq!(decoded_u256.0[0], 0);
284
285 assert_eq!(decoded_addr.0, &addr_bytes);
286
287 }
291
292 #[test]
293 fn test_extended_types() {
294 use crate::decoder::{read_bool, read_string};
295
296 let mut data = Vec::new();
297
298 let mut p1 = [0u8; 32];
301 p1[31] = 1;
302 data.extend_from_slice(&p1);
303
304 let mut p2_offset = [0u8; 32];
318 p2_offset[31] = 64;
319 data.extend_from_slice(&p2_offset);
320
321 let mut string_len = [0u8; 32];
324 string_len[31] = 5;
325 data.extend_from_slice(&string_len);
326
327 let mut string_content = [0u8; 32];
329 let s_bytes = b"Hello";
330 string_content[0..5].copy_from_slice(s_bytes);
331 data.extend_from_slice(&string_content);
332
333 let val_bool = read_bool(&data, 0).expect("failed bool");
335 let val_str = read_string(&data, 32).expect("failed string");
336
337 assert_eq!(val_bool.0, true);
338 assert_eq!(val_str.0, "Hello");
339 }
340
341 #[test]
342 fn test_array_decoding() {
343 use crate::decoder::{read_array_dyn, read_array_fixed};
344 use crate::types::ZU256;
345
346 let mut data = Vec::new();
348 let mut p0 = [0u8; 32];
350 p0[31] = 1;
351 data.extend_from_slice(&p0);
352 let mut p1 = [0u8; 32];
354 p1[31] = 2;
355 data.extend_from_slice(&p1);
356
357 let arr_fixed: crate::types::ZArray<ZU256> =
359 read_array_fixed(&data, 0, 2).expect("fixed array");
360 assert_eq!(arr_fixed.len(), 2);
361 assert_eq!(arr_fixed.get(0).unwrap().0[31], 1);
362 assert_eq!(arr_fixed.get(1).unwrap().0[31], 2);
363
364 let mut dyn_data = Vec::new();
367
368 let mut offset_word = [0u8; 32];
370 offset_word[31] = 32; dyn_data.extend_from_slice(&offset_word);
372
373 let mut len_word = [0u8; 32];
375 len_word[31] = 2;
376 dyn_data.extend_from_slice(&len_word);
377
378 let mut p2 = [0u8; 32];
380 p2[31] = 3;
381 dyn_data.extend_from_slice(&p2);
382
383 let mut p3 = [0u8; 32];
385 p3[31] = 4;
386 dyn_data.extend_from_slice(&p3);
387
388 let arr_dyn: crate::types::ZArray<ZU256> = read_array_dyn(&dyn_data, 0).expect("dyn array");
390 assert_eq!(arr_dyn.len(), 2);
391 assert_eq!(arr_dyn.get(0).unwrap().0[31], 3);
392 assert_eq!(arr_dyn.get(1).unwrap().0[31], 4);
393 }
394
395 #[test]
396 fn test_integers() {
397 use crate::decoder::*;
398 use alloc::vec::Vec;
399
400 let mut data = Vec::new();
401
402 let mut w1 = [0u8; 32];
404 w1[31] = 0xFF;
405 data.extend_from_slice(&w1);
406
407 let mut w2 = [0u8; 32];
409 let val_u64: u64 = 0xDEADBEEF;
411 let bytes_u64 = val_u64.to_be_bytes();
412 w2[24..32].copy_from_slice(&bytes_u64);
413 data.extend_from_slice(&w2);
414
415 let w3 = [0xff; 32];
417 data.extend_from_slice(&w3);
418
419 let mut w4 = [0u8; 32];
421 w4[31] = 1;
422 data.extend_from_slice(&w4);
423
424 let mut w5 = [0u8; 32];
426 w5[30] = 1; w5[31] = 1;
428 data.extend_from_slice(&w5);
429
430 assert_eq!(read_u8(&data, 0).unwrap(), 0xFF);
432 assert_eq!(read_u64(&data, 32).unwrap(), 0xDEADBEEF);
433
434 assert_eq!(read_i8(&data, 64).unwrap(), -1);
435 assert_eq!(read_i8(&data, 96).unwrap(), 1);
436
437 assert!(read_u8(&data, 128).is_err());
439 }
440}