Skip to main content

tycho_types/abi/
mod.rs

1//! Common ABI implementation.
2
3use std::hash::{BuildHasher, Hash};
4use std::str::FromStr;
5
6pub use tycho_types_abi_proc::{FromAbi, IntoAbi, WithAbiType};
7
8pub use self::contract::{
9    Contract, Event, EventBuilder, ExternalInput, Function, FunctionBuilder, UnsignedBody,
10    UnsignedExternalMessage,
11};
12pub use self::signature::{extend_signature_with_id, sign_with_signature_id};
13pub use self::traits::{
14    FromAbi, FromAbiIter, FromPlainAbi, IgnoreName, IntoAbi, IntoPlainAbi, WithAbiType,
15    WithPlainAbiType,
16};
17pub use self::ty::{
18    AbiHeaderType, AbiType, AbiTypeFlatten, NamedAbiType, NamedAbiTypeFlatten, PlainAbiType,
19};
20pub use self::value::{AbiHeader, AbiValue, NamedAbiValue, PlainAbiValue};
21
22pub mod error;
23
24mod contract;
25mod signature;
26mod traits;
27mod ty;
28mod value;
29
30#[cfg(test)]
31mod tests;
32
33#[doc(hidden)]
34pub mod __export {
35    pub use anyhow;
36}
37
38/// ABI version.
39#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
40pub struct AbiVersion {
41    /// Major version component.
42    pub major: u8,
43    /// Minor version component.
44    pub minor: u8,
45}
46
47impl AbiVersion {
48    /// A legacy ABI version.
49    pub const V1_0: Self = Self::new(1, 0);
50    /// A base version of an ABI 2.
51    pub const V2_0: Self = Self::new(2, 0);
52    /// A base version with strings and refs.
53    pub const V2_1: Self = Self::new(2, 1);
54    /// Same as 2.1 but with a more compact address serialization.
55    pub const V2_2: Self = Self::new(2, 2);
56    /// Same as 2.2 but uses an address during signing.
57    pub const V2_3: Self = Self::new(2, 3);
58    /// Same as 2.3 but init_data is replaced with init fields in abi
59    pub const V2_4: Self = Self::new(2, 4);
60
61    /// Same as 2.4 but [`AbiType::AddressStd`] is recommended to use to represent address.
62    /// Contract getters are added. Similar to functions but getters can not be called on-chain, only off-chain
63    ///
64    /// [`AbiType::AddressStd`]: crate::abi::AbiType::AddressStd
65    pub const V2_7: Self = Self::new(2, 7);
66
67    /// Creates an ABI version from components.
68    pub const fn new(major: u8, minor: u8) -> Self {
69        Self { major, minor }
70    }
71}
72
73impl FromStr for AbiVersion {
74    type Err = error::ParseAbiVersionError;
75
76    fn from_str(s: &str) -> Result<Self, Self::Err> {
77        let (major, minor) = ok!(s
78            .split_once('.')
79            .ok_or(error::ParseAbiVersionError::InvalidFormat));
80
81        Ok(Self {
82            major: ok!(major
83                .parse()
84                .map_err(error::ParseAbiVersionError::InvalidComponent)),
85            minor: ok!(minor
86                .parse()
87                .map_err(error::ParseAbiVersionError::InvalidComponent)),
88        })
89    }
90}
91
92impl std::fmt::Display for AbiVersion {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        write!(f, "{}.{}", self.major, self.minor)
95    }
96}
97
98/// A wrapper around [`AbiType`], [`NamedAbiType`], [`AbiValue`] and [`NamedAbiValue`]
99/// that implements hash/comparison traits without name.
100#[repr(transparent)]
101pub struct WithoutName<T>(pub T);
102
103impl<T> WithoutName<T> {
104    /// Wraps a reference of the inner type.
105    pub fn wrap(value: &T) -> &Self {
106        // SAFETY: HashWithoutName<T> is #[repr(transparent)]
107        unsafe { &*(value as *const T as *const Self) }
108    }
109
110    /// Wraps a slice of the inner type.
111    pub fn wrap_slice(value: &[T]) -> &[Self] {
112        // SAFETY: HashWithoutName<T> is #[repr(transparent)]
113        unsafe { &*(value as *const [T] as *const [Self]) }
114    }
115}
116
117impl<T: std::fmt::Debug> std::fmt::Debug for WithoutName<T> {
118    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119        f.debug_tuple("WithoutName").field(&self.0).finish()
120    }
121}
122
123impl<T: Clone> Clone for WithoutName<T> {
124    #[inline]
125    fn clone(&self) -> Self {
126        WithoutName(self.0.clone())
127    }
128}
129
130impl<T> Eq for WithoutName<T> where WithoutName<T>: PartialEq {}
131
132impl<T> PartialOrd for WithoutName<T>
133where
134    WithoutName<T>: Ord,
135{
136    #[inline]
137    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
138        Some(self.cmp(other))
139    }
140}
141
142impl<T> PartialEq for WithoutName<Vec<T>>
143where
144    WithoutName<T>: PartialEq,
145{
146    fn eq(&self, WithoutName(other): &Self) -> bool {
147        WithoutName::wrap_slice(self.0.as_slice()) == WithoutName::wrap_slice(other.as_slice())
148    }
149}
150
151impl<K, V> PartialEq for WithoutName<std::collections::BTreeMap<K, V>>
152where
153    K: PartialEq,
154    WithoutName<V>: PartialEq,
155{
156    fn eq(&self, WithoutName(other): &Self) -> bool {
157        self.0.len() == other.len()
158            && self.0.iter().zip(other).all(|((ak, av), (bk, bv))| {
159                (ak, WithoutName::wrap(av)) == (bk, WithoutName::wrap(bv))
160            })
161    }
162}
163
164impl<K, V, S> PartialEq for WithoutName<std::collections::HashMap<K, V, S>>
165where
166    K: Eq + Hash,
167    WithoutName<V>: PartialEq,
168    S: BuildHasher,
169{
170    fn eq(&self, WithoutName(other): &Self) -> bool {
171        if self.0.len() != other.len() {
172            return false;
173        }
174
175        self.0.iter().all(|(key, value)| {
176            other
177                .get(key)
178                .is_some_and(|v| WithoutName::wrap(value) == WithoutName::wrap(v))
179        })
180    }
181}