zabi_rs/
types.rs

1use crate::ZError;
2use core::cmp::Ordering;
3use core::fmt;
4use core::hash::{Hash, Hasher};
5use core::marker::PhantomData;
6#[cfg(feature = "serde")]
7use serde::{Serialize, Serializer};
8
9#[cfg(feature = "alloy")]
10use alloy_primitives::{Address as AlloyAddress, U256 as AlloyU256};
11
12// We need to refer to ZDecode trait.
13// Since we are in a submodule, we can use crate::ZDecode
14use crate::ZDecode;
15
16/// Wrapper for EVM Arrays (fixed or dynamic).
17/// Provides zero-copy access to elements.
18#[cfg_attr(feature = "serde", derive(Serialize))]
19#[cfg_attr(feature = "serde", serde(bound = "T: Serialize + ZDecode<'a>"))]
20pub struct ZArray<'a, T> {
21    pub data: &'a [u8],
22    pub start_offset: usize,
23    pub length: usize,
24    pub _marker: PhantomData<T>,
25}
26
27impl<'a, T> Clone for ZArray<'a, T> {
28    fn clone(&self) -> Self {
29        *self
30    }
31}
32
33impl<'a, T> Copy for ZArray<'a, T> {}
34
35impl<'a, T> ZArray<'a, T> {
36    pub fn new(data: &'a [u8], start_offset: usize, length: usize) -> Self {
37        Self {
38            data,
39            start_offset,
40            length,
41            _marker: PhantomData,
42        }
43    }
44
45    pub fn len(&self) -> usize {
46        self.length
47    }
48
49    pub fn is_empty(&self) -> bool {
50        self.length == 0
51    }
52
53    pub fn get(&self, index: usize) -> Result<T, ZError>
54    where
55        T: ZDecode<'a>,
56    {
57        if index >= self.length {
58            return Err(ZError::OutOfBounds(index, self.length));
59        }
60        let offset = self.start_offset + index * 32;
61        T::decode(self.data, offset)
62    }
63}
64
65impl<'a, T: fmt::Debug> fmt::Debug for ZArray<'a, T> {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "ZArray(len={})", self.length)
68    }
69}
70
71/// Iterator for ZArray.
72pub struct ZArrayIterator<'a, T> {
73    array: ZArray<'a, T>,
74    index: usize,
75}
76
77impl<'a, T: ZDecode<'a>> Iterator for ZArrayIterator<'a, T> {
78    type Item = Result<T, ZError>;
79
80    fn next(&mut self) -> Option<Self::Item> {
81        if self.index >= self.array.len() {
82            None
83        } else {
84            let res = self.array.get(self.index);
85            self.index += 1;
86            Some(res)
87        }
88    }
89}
90
91impl<'a, T: ZDecode<'a>> IntoIterator for ZArray<'a, T> {
92    type Item = Result<T, ZError>;
93    type IntoIter = ZArrayIterator<'a, T>;
94
95    fn into_iter(self) -> Self::IntoIter {
96        ZArrayIterator {
97            array: self,
98            index: 0,
99        }
100    }
101}
102
103impl<'a, T> ZArray<'a, T> {
104    /// Create an iterator over the array elements.
105    pub fn iter(&self) -> ZArrayIterator<'a, T> {
106        ZArrayIterator {
107            array: *self,
108            index: 0,
109        }
110    }
111}
112
113/// Wrapper around a 20-byte Ethereum address reference.
114#[derive(Clone, Copy, PartialEq, Eq)]
115pub struct ZAddress<'a>(pub &'a [u8; 20]);
116
117impl<'a> fmt::Debug for ZAddress<'a> {
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        write!(f, "ZAddress(0x")?;
120        for byte in self.0 {
121            write!(f, "{:02x}", byte)?;
122        }
123        write!(f, ")")
124    }
125}
126
127impl<'a> fmt::Display for ZAddress<'a> {
128    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129        write!(f, "0x")?;
130        for byte in self.0 {
131            write!(f, "{:02x}", byte)?;
132        }
133        Ok(())
134    }
135}
136
137impl<'a> ZAddress<'a> {
138    /// Copy the address bytes to a new [u8; 20] array.
139    #[inline]
140    pub fn to_bytes(&self) -> [u8; 20] {
141        *self.0
142    }
143
144    /// Returns the inner byte array reference.
145    #[inline]
146    pub fn as_bytes(&self) -> &[u8; 20] {
147        self.0
148    }
149
150    /// Convert to `alloy_primitives::Address` (requires `alloy` feature).
151    #[cfg(feature = "alloy")]
152    #[inline]
153    pub fn to_alloy(&self) -> AlloyAddress {
154        AlloyAddress::from(*self.0)
155    }
156}
157
158#[cfg(feature = "alloy")]
159impl<'a> From<ZAddress<'a>> for AlloyAddress {
160    #[inline]
161    fn from(value: ZAddress<'a>) -> Self {
162        value.to_alloy()
163    }
164}
165
166impl<'a> PartialOrd for ZAddress<'a> {
167    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
168        Some(self.cmp(other))
169    }
170}
171
172impl<'a> Ord for ZAddress<'a> {
173    fn cmp(&self, other: &Self) -> Ordering {
174        self.0.cmp(other.0)
175    }
176}
177
178impl<'a> Hash for ZAddress<'a> {
179    fn hash<H: Hasher>(&self, state: &mut H) {
180        self.0.hash(state);
181    }
182}
183
184#[cfg(feature = "serde")]
185impl<'a> Serialize for ZAddress<'a> {
186    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
187    where
188        S: Serializer,
189    {
190        // Serialize as "0x..." string
191        let mut hex_str = alloc::string::String::with_capacity(42);
192        hex_str.push_str("0x");
193        for byte in self.0 {
194            use core::fmt::Write;
195            write!(hex_str, "{:02x}", byte).unwrap();
196        }
197        serializer.serialize_str(&hex_str)
198    }
199}
200
201/// Wrapper around a 32-byte EVM word (uint256) reference.
202#[derive(Clone, Copy, PartialEq, Eq)]
203pub struct ZU256<'a>(pub &'a [u8; 32]);
204
205impl<'a> fmt::Debug for ZU256<'a> {
206    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207        write!(f, "ZU256(0x")?;
208        for byte in self.0 {
209            write!(f, "{:02x}", byte)?;
210        }
211        write!(f, ")")
212    }
213}
214
215impl<'a> fmt::Display for ZU256<'a> {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        write!(f, "0x")?;
218        for byte in self.0 {
219            write!(f, "{:02x}", byte)?;
220        }
221        Ok(())
222    }
223}
224
225impl<'a> ZU256<'a> {
226    /// Convert to u128 if the value fits (upper 16 bytes are zero).
227    /// Returns None if the value overflows u128.
228    #[inline]
229    pub fn to_u128(&self) -> Option<u128> {
230        // Check if upper 16 bytes are zero
231        for i in 0..16 {
232            if self.0[i] != 0 {
233                return None;
234            }
235        }
236        let mut bytes = [0u8; 16];
237        bytes.copy_from_slice(&self.0[16..32]);
238        Some(u128::from_be_bytes(bytes))
239    }
240
241    /// Convert to u64 if the value fits (upper 24 bytes are zero).
242    /// Returns None if the value overflows u64.
243    #[inline]
244    pub fn to_u64(&self) -> Option<u64> {
245        // Check if upper 24 bytes are zero
246        for i in 0..24 {
247            if self.0[i] != 0 {
248                return None;
249            }
250        }
251        let mut bytes = [0u8; 8];
252        bytes.copy_from_slice(&self.0[24..32]);
253        Some(u64::from_be_bytes(bytes))
254    }
255
256    /// Returns the inner byte array reference.
257    #[inline]
258    pub fn as_bytes(&self) -> &[u8; 32] {
259        self.0
260    }
261
262    /// Copy the bytes to a new [u8; 32] array.
263    #[inline]
264    pub fn to_bytes(&self) -> [u8; 32] {
265        *self.0
266    }
267
268    /// Check if the value is zero.
269    #[inline]
270    pub fn is_zero(&self) -> bool {
271        self.0.iter().all(|&b| b == 0)
272    }
273
274    /// Convert to u32 if the value fits (upper 28 bytes are zero).
275    /// Returns None if the value overflows u32.
276    #[inline]
277    pub fn to_u32(&self) -> Option<u32> {
278        // Check if upper 28 bytes are zero
279        for i in 0..28 {
280            if self.0[i] != 0 {
281                return None;
282            }
283        }
284        let mut bytes = [0u8; 4];
285        bytes.copy_from_slice(&self.0[28..32]);
286        Some(u32::from_be_bytes(bytes))
287    }
288
289    /// Convert to u16 if the value fits.
290    #[inline]
291    pub fn to_u16(&self) -> Option<u16> {
292        self.to_u32().and_then(|v| v.try_into().ok())
293    }
294
295    /// Convert to u8 if the value fits.
296    #[inline]
297    pub fn to_u8(&self) -> Option<u8> {
298        self.to_u32().and_then(|v| v.try_into().ok())
299    }
300
301    /// Check if the value is all ones (max uint256).
302    #[inline]
303    pub fn is_max(&self) -> bool {
304        self.0.iter().all(|&b| b == 0xff)
305    }
306
307    /// Convert to `alloy_primitives::U256` (requires `alloy` feature).
308    #[cfg(feature = "alloy")]
309    #[inline]
310    pub fn to_alloy(&self) -> AlloyU256 {
311        AlloyU256::from_be_bytes(*self.0)
312    }
313}
314
315#[cfg(feature = "alloy")]
316impl<'a> From<ZU256<'a>> for AlloyU256 {
317    #[inline]
318    fn from(value: ZU256<'a>) -> Self {
319        value.to_alloy()
320    }
321}
322
323impl<'a> PartialOrd for ZU256<'a> {
324    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
325        Some(self.cmp(other))
326    }
327}
328
329impl<'a> Ord for ZU256<'a> {
330    fn cmp(&self, other: &Self) -> Ordering {
331        self.0.cmp(other.0)
332    }
333}
334
335impl<'a> Hash for ZU256<'a> {
336    fn hash<H: Hasher>(&self, state: &mut H) {
337        self.0.hash(state);
338    }
339}
340
341#[cfg(feature = "serde")]
342impl<'a> Serialize for ZU256<'a> {
343    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
344    where
345        S: Serializer,
346    {
347        let mut hex_str = alloc::string::String::with_capacity(66);
348        hex_str.push_str("0x");
349        for byte in self.0 {
350            use core::fmt::Write;
351            write!(hex_str, "{:02x}", byte).unwrap();
352        }
353        serializer.serialize_str(&hex_str)
354    }
355}
356
357/// Wrapper around a 32-byte EVM word (int256) reference.
358/// Semantically represents a signed integer.
359#[derive(Clone, Copy, PartialEq, Eq)]
360pub struct ZInt256<'a>(pub &'a [u8; 32]);
361
362impl<'a> fmt::Debug for ZInt256<'a> {
363    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
364        write!(f, "ZInt256(0x")?;
365        for byte in self.0 {
366            write!(f, "{:02x}", byte)?;
367        }
368        write!(f, ")")
369    }
370}
371
372impl<'a> fmt::Display for ZInt256<'a> {
373    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374        // We display hex for now, interpreting as signed decimal would require big logic
375        write!(f, "0x")?;
376        for byte in self.0 {
377            write!(f, "{:02x}", byte)?;
378        }
379        Ok(())
380    }
381}
382
383impl<'a> ZInt256<'a> {
384    /// Convert to i128 if the value fits.
385    /// Returns None if the value overflows i128.
386    #[inline]
387    pub fn to_i128(&self) -> Option<i128> {
388        // For signed, check sign extension
389        let is_negative = self.0[0] & 0x80 != 0;
390        let expected_padding = if is_negative { 0xff } else { 0x00 };
391
392        // Check if upper 16 bytes are proper sign extension
393        for i in 0..16 {
394            if self.0[i] != expected_padding {
395                return None;
396            }
397        }
398        let mut bytes = [0u8; 16];
399        bytes.copy_from_slice(&self.0[16..32]);
400        Some(i128::from_be_bytes(bytes))
401    }
402
403    /// Convert to i64 if the value fits.
404    /// Returns None if the value overflows i64.
405    #[inline]
406    pub fn to_i64(&self) -> Option<i64> {
407        let is_negative = self.0[0] & 0x80 != 0;
408        let expected_padding = if is_negative { 0xff } else { 0x00 };
409
410        // Check if upper 24 bytes are proper sign extension
411        for i in 0..24 {
412            if self.0[i] != expected_padding {
413                return None;
414            }
415        }
416        let mut bytes = [0u8; 8];
417        bytes.copy_from_slice(&self.0[24..32]);
418        Some(i64::from_be_bytes(bytes))
419    }
420
421    /// Returns the inner byte array reference.
422    #[inline]
423    pub fn as_bytes(&self) -> &[u8; 32] {
424        self.0
425    }
426
427    /// Check if the value is negative (MSB is set).
428    #[inline]
429    pub fn is_negative(&self) -> bool {
430        self.0[0] & 0x80 != 0
431    }
432
433    /// Convert to i32 if the value fits.
434    #[inline]
435    pub fn to_i32(&self) -> Option<i32> {
436        let is_negative = self.is_negative();
437        let expected_padding = if is_negative { 0xff } else { 0x00 };
438        for i in 0..28 {
439            if self.0[i] != expected_padding {
440                return None;
441            }
442        }
443        let mut bytes = [0u8; 4];
444        bytes.copy_from_slice(&self.0[28..32]);
445        Some(i32::from_be_bytes(bytes))
446    }
447
448    /// Convert to i16 if the value fits.
449    #[inline]
450    pub fn to_i16(&self) -> Option<i16> {
451        self.to_i32().and_then(|v| v.try_into().ok())
452    }
453
454    /// Convert to i8 if the value fits.
455    #[inline]
456    pub fn to_i8(&self) -> Option<i8> {
457        self.to_i32().and_then(|v| v.try_into().ok())
458    }
459
460    /// Check if the value is positive (not zero and MSB is 0).
461    #[inline]
462    pub fn is_positive(&self) -> bool {
463        !self.is_negative() && !self.0.iter().all(|&b| b == 0)
464    }
465
466    /// Get the absolute value (returns a new array since we can't easily return a slice of a computed value).
467    /// Note: This violates the zero-copy principle slightly by returning a value, but ZU256 normally wraps a slice.
468    /// For absolute value, we might want to return `[u8; 32]`.
469    #[inline]
470    pub fn abs_bytes(&self) -> [u8; 32] {
471        if !self.is_negative() {
472            *self.0
473        } else {
474            let mut res = [0u8; 32];
475            let mut carry = 1u16;
476            for i in (0..32).rev() {
477                let val = (!self.0[i]) as u16 + carry;
478                res[i] = val as u8;
479                carry = val >> 8;
480            }
481            res
482        }
483    }
484
485    /// Returns the signum of the number (-1, 0, or 1).
486    #[inline]
487    pub fn signum(&self) -> i8 {
488        if self.0.iter().all(|&b| b == 0) {
489            0
490        } else if self.is_negative() {
491            -1
492        } else {
493            1
494        }
495    }
496}
497
498// Note: ZInt256 comparison is tricky because it's stored as bytes (raw two's complement).
499// Normal byte comparison works for positive numbers, but negative numbers (high bit set)
500// will look "larger" than positive numbers if compared as unsigned bytes.
501// So we must implement Ord carefully for signed comparison.
502impl<'a> PartialOrd for ZInt256<'a> {
503    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
504        Some(self.cmp(other))
505    }
506}
507
508impl<'a> Ord for ZInt256<'a> {
509    fn cmp(&self, other: &Self) -> Ordering {
510        let self_neg = self.is_negative();
511        let other_neg = other.is_negative();
512
513        match (self_neg, other_neg) {
514            (true, true) => {
515                // Both negative: larger unsigned value is "closer to zero" (larger) in two's complement?
516                // e.g. -1 is 0xFF, -2 is 0xFE. 0xFF > 0xFE. So -1 > -2.
517                // Yes, byte comparison is correct for two negatives.
518                self.0.cmp(other.0)
519            }
520            (false, false) => {
521                // Both positive: byte comparison is correct.
522                self.0.cmp(other.0)
523            }
524            (true, false) => {
525                // Self is negative, Other is positive. Self < Other.
526                Ordering::Less
527            }
528            (false, true) => {
529                // Self is positive, Other is negative. Self > Other.
530                Ordering::Greater
531            }
532        }
533    }
534}
535
536impl<'a> Hash for ZInt256<'a> {
537    fn hash<H: Hasher>(&self, state: &mut H) {
538        self.0.hash(state);
539    }
540}
541
542#[cfg(feature = "serde")]
543impl<'a> Serialize for ZInt256<'a> {
544    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
545    where
546        S: Serializer,
547    {
548        // For simple serialization, we can just use the hex representation
549        let mut hex_str = alloc::string::String::with_capacity(66);
550        hex_str.push_str("0x");
551        for byte in self.0 {
552            use core::fmt::Write;
553            write!(hex_str, "{:02x}", byte).unwrap();
554        }
555        serializer.serialize_str(&hex_str)
556    }
557}
558
559/// Wrapper around a variable-length byte array reference.
560#[derive(Clone, Copy, PartialEq, Eq)]
561pub struct ZBytes<'a>(pub &'a [u8]);
562
563impl<'a> fmt::Debug for ZBytes<'a> {
564    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
565        write!(f, "ZBytes(len={}, data=0x", self.0.len())?;
566        for (i, byte) in self.0.iter().enumerate() {
567            if i >= 32 {
568                // Truncate for debug
569                write!(f, "...")?;
570                break;
571            }
572            write!(f, "{:02x}", byte)?;
573        }
574        write!(f, ")")
575    }
576}
577
578impl<'a> fmt::Display for ZBytes<'a> {
579    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
580        write!(f, "0x")?;
581        for byte in self.0 {
582            write!(f, "{:02x}", byte)?;
583        }
584        Ok(())
585    }
586}
587
588impl<'a> ZBytes<'a> {
589    /// Returns the length of the bytes.
590    #[inline]
591    pub fn len(&self) -> usize {
592        self.0.len()
593    }
594
595    /// Returns true if the bytes are empty.
596    #[inline]
597    pub fn is_empty(&self) -> bool {
598        self.0.is_empty()
599    }
600
601    /// Returns the inner byte slice.
602    #[inline]
603    pub fn as_slice(&self) -> &[u8] {
604        self.0
605    }
606}
607
608impl<'a> PartialOrd for ZBytes<'a> {
609    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
610        Some(self.cmp(other))
611    }
612}
613
614impl<'a> Ord for ZBytes<'a> {
615    fn cmp(&self, other: &Self) -> Ordering {
616        self.0.cmp(other.0)
617    }
618}
619
620impl<'a> Hash for ZBytes<'a> {
621    fn hash<H: Hasher>(&self, state: &mut H) {
622        self.0.hash(state);
623    }
624}
625
626#[cfg(feature = "serde")]
627impl<'a> Serialize for ZBytes<'a> {
628    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
629    where
630        S: Serializer,
631    {
632        let mut hex_str = alloc::string::String::with_capacity(2 + self.0.len() * 2);
633        hex_str.push_str("0x");
634        for byte in self.0 {
635            use core::fmt::Write;
636            write!(hex_str, "{:02x}", byte).unwrap();
637        }
638        serializer.serialize_str(&hex_str)
639    }
640}
641
642/// Wrapper around a boolean value.
643/// Note: EVM booleans are uint256 (0 or 1).
644#[derive(Clone, Copy, PartialEq, Eq)]
645#[cfg_attr(feature = "serde", derive(Serialize))]
646pub struct ZBool(pub bool);
647
648impl fmt::Debug for ZBool {
649    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
650        write!(f, "ZBool({})", self.0)
651    }
652}
653
654impl fmt::Display for ZBool {
655    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
656        write!(f, "{}", self.0)
657    }
658}
659
660impl ZBool {
661    /// Returns the inner boolean value.
662    #[inline]
663    pub fn as_bool(&self) -> bool {
664        self.0
665    }
666}
667
668/// Wrapper around a UTF-8 string slice reference.
669#[derive(Clone, Copy, PartialEq, Eq)]
670#[cfg_attr(feature = "serde", derive(Serialize))]
671pub struct ZString<'a>(pub &'a str);
672
673impl<'a> PartialOrd for ZString<'a> {
674    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
675        Some(self.cmp(other))
676    }
677}
678
679impl<'a> Ord for ZString<'a> {
680    fn cmp(&self, other: &Self) -> Ordering {
681        self.0.cmp(other.0)
682    }
683}
684
685impl<'a> Hash for ZString<'a> {
686    fn hash<H: Hasher>(&self, state: &mut H) {
687        self.0.hash(state);
688    }
689}
690
691impl<'a> fmt::Debug for ZString<'a> {
692    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
693        write!(f, "ZString({:?})", self.0)
694    }
695}
696
697impl<'a> fmt::Display for ZString<'a> {
698    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
699        write!(f, "{}", self.0)
700    }
701}
702
703impl<'a> ZString<'a> {
704    /// Returns the length of the string in bytes.
705    #[inline]
706    pub fn len(&self) -> usize {
707        self.0.len()
708    }
709
710    /// Returns true if the string is empty.
711    #[inline]
712    pub fn is_empty(&self) -> bool {
713        self.0.is_empty()
714    }
715
716    /// Returns the inner string slice.
717    #[inline]
718    pub fn as_str(&self) -> &str {
719        self.0
720    }
721}
722
723/// Represents an Ethereum revert reason.
724#[derive(Debug, Clone, Copy, PartialEq)]
725pub enum ZRevert<'a> {
726    /// Standard error string: Error(string)
727    Error(ZString<'a>),
728    /// Solidity panic: Panic(uint256)
729    Panic(ZU256<'a>),
730    /// Custom error (selector and raw encoded data)
731    Custom(&'a [u8; 4], &'a [u8]),
732    /// Unknown or empty revert
733    Unknown,
734}
735
736impl<'a> fmt::Display for ZRevert<'a> {
737    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
738        match self {
739            ZRevert::Error(s) => write!(f, "Revert: {}", s.0),
740            ZRevert::Panic(p) => write!(f, "Panic: {}", p),
741            ZRevert::Custom(sel, _) => write!(
742                f,
743                "CustomError(0x{:02x}{:02x}{:02x}{:02x})",
744                sel[0], sel[1], sel[2], sel[3]
745            ),
746            ZRevert::Unknown => write!(f, "Unknown Revert"),
747        }
748    }
749}
750
751/// Result of a function call, either success or revert.
752#[derive(Debug, Clone, Copy, PartialEq)]
753pub enum ZCallResult<'a, T> {
754    Success(T),
755    Revert(ZRevert<'a>),
756}
757
758impl<'a, T> ZCallResult<'a, T> {
759    pub fn is_success(&self) -> bool {
760        matches!(self, ZCallResult::Success(_))
761    }
762
763    pub fn is_revert(&self) -> bool {
764        matches!(self, ZCallResult::Revert(_))
765    }
766
767    pub fn unwrap(self) -> T {
768        match self {
769            ZCallResult::Success(val) => val,
770            ZCallResult::Revert(e) => panic!("Called unwrap on a Revert: {:?}", e),
771        }
772    }
773}