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