alloy_sol_types/types/
ty.rs

1use crate::{
2    Result, Word,
3    abi::{self, Token, TokenSeq},
4    private::SolTypeValue,
5};
6use alloc::vec::Vec;
7
8/// A Solidity type.
9///
10/// This trait is implemented by types that contain ABI encoding and decoding
11/// info for Solidity types. Types may be combined to express arbitrarily
12/// complex Solidity types.
13///
14/// These types are zero cost representations of Solidity types. They do not
15/// exist at runtime. They **only** contain information about the type, they do
16/// not carry any data.
17///
18/// # Implementer's Guide
19///
20/// It should not be necessary to implement this trait manually. Instead, use
21/// the [`sol!`] procedural macro to parse Solidity syntax into types that
22/// implement this trait.
23///
24/// # Examples
25///
26/// Basic usage:
27///
28/// ```
29/// use alloy_sol_types::{SolType, sol_data::*};
30///
31/// type Uint256DynamicArray = Array<Uint<256>>;
32/// assert_eq!(Uint256DynamicArray::SOL_NAME, "uint256[]");
33///
34/// type Erc20FunctionArgs = (Address, Uint<256>);
35/// assert_eq!(Erc20FunctionArgs::SOL_NAME, "(address,uint256)");
36///
37/// type LargeComplexType = (FixedArray<Array<Bool>, 2>, (FixedBytes<13>, String));
38/// assert_eq!(LargeComplexType::SOL_NAME, "(bool[][2],(bytes13,string))");
39/// ```
40///
41/// The previous example can be entirely replicated with the [`sol!`] macro:
42///
43/// ```
44/// use alloy_sol_types::{SolType, sol};
45///
46/// type Uint256DynamicArray = sol!(uint256[]);
47/// assert_eq!(Uint256DynamicArray::SOL_NAME, "uint256[]");
48///
49/// type Erc20FunctionArgs = sol!((address, uint256));
50/// assert_eq!(Erc20FunctionArgs::SOL_NAME, "(address,uint256)");
51///
52/// type LargeComplexType = sol!((bool[][2],(bytes13,string)));
53/// assert_eq!(LargeComplexType::SOL_NAME, "(bool[][2],(bytes13,string))");
54/// ```
55///
56/// For more complex usage, it's recommended to use the
57/// [`SolValue`](crate::SolValue) trait for primitive types, and the `Sol*`
58/// traits for other types created with [`sol!`]:
59///
60/// ```
61/// use alloy_primitives::Address;
62/// use alloy_sol_types::{SolCall, SolStruct, SolValue, sol};
63///
64/// sol! {
65///     struct MyStruct {
66///         bool a;
67///         uint64 b;
68///         address c;
69///     }
70///
71///     enum MyEnum {
72///         A,
73///         B,
74///         C,
75///     }
76///
77///     function myFunction(MyStruct my_struct, MyEnum my_enum);
78/// }
79///
80/// // `SolValue`
81/// let my_bool = true;
82/// let _ = my_bool.abi_encode();
83///
84/// let my_struct = MyStruct { a: true, b: 1, c: Address::ZERO };
85/// let _ = my_struct.abi_encode();
86///
87/// let my_enum = MyEnum::A;
88/// let _ = my_enum.abi_encode();
89///
90/// // `SolCall`
91/// let my_function_call = myFunctionCall { my_struct, my_enum };
92/// let _ = my_function_call.abi_encode();
93/// ```
94///
95/// [`sol!`]: crate::sol
96pub trait SolType: Sized {
97    /// The corresponding Rust type.
98    type RustType: SolTypeValue<Self> + 'static;
99
100    /// The corresponding [ABI token type](Token).
101    ///
102    /// This is the intermediate representation of the type that is used for
103    /// ABI encoding and decoding.
104    type Token<'a>: Token<'a>;
105
106    /// The name of this type in Solidity.
107    const SOL_NAME: &'static str;
108
109    /// The statically-known ABI-encoded size of the type.
110    ///
111    /// If this is not known at compile time, this should be `None`, which indicates that the
112    /// encoded size is dynamic.
113    const ENCODED_SIZE: Option<usize>;
114
115    /// The statically-known Non-standard Packed Mode ABI-encoded size of the type.
116    ///
117    /// If this is not known at compile time, this should be `None`, which indicates that the
118    /// encoded size is dynamic.
119    const PACKED_ENCODED_SIZE: Option<usize>;
120
121    /// Whether the ABI-encoded size is dynamic.
122    ///
123    /// There should be no need to override the default implementation.
124    const DYNAMIC: bool = Self::ENCODED_SIZE.is_none();
125
126    /// Calculate the ABI-encoded size of the data, counting both head and tail
127    /// words. For a single-word type this will always be 32.
128    #[inline]
129    fn abi_encoded_size<E: ?Sized + SolTypeValue<Self>>(rust: &E) -> usize {
130        rust.stv_abi_encoded_size()
131    }
132
133    /// Returns `true` if the given token can be detokenized with this type.
134    fn valid_token(token: &Self::Token<'_>) -> bool;
135
136    /// Returns an error if the given token cannot be detokenized with this
137    /// type.
138    #[inline]
139    fn type_check(token: &Self::Token<'_>) -> Result<()> {
140        if Self::valid_token(token) {
141            Ok(())
142        } else {
143            Err(crate::Error::type_check_fail_token::<Self>(token))
144        }
145    }
146
147    /// Detokenize this type's value from the given token.
148    ///
149    /// See the [`abi::token`] module for more information.
150    fn detokenize(token: Self::Token<'_>) -> Self::RustType;
151
152    /// Tokenizes the given value into this type's token.
153    ///
154    /// See the [`abi::token`] module for more information.
155    #[inline]
156    fn tokenize<E: ?Sized + SolTypeValue<Self>>(rust: &E) -> Self::Token<'_> {
157        rust.stv_to_tokens()
158    }
159
160    /// Encode this data according to EIP-712 `encodeData` rules, and hash it
161    /// if necessary.
162    ///
163    /// Implementer's note: All single-word types are encoded as their word.
164    /// All multi-word types are encoded as the hash the concatenated data
165    /// words for each element
166    ///
167    /// <https://eips.ethereum.org/EIPS/eip-712#definition-of-encodedata>
168    #[inline]
169    fn eip712_data_word<E: ?Sized + SolTypeValue<Self>>(rust: &E) -> Word {
170        rust.stv_eip712_data_word()
171    }
172
173    /// Returns the length of this value when ABI-encoded in Non-standard Packed Mode.
174    ///
175    /// See [`abi_encode_packed`][SolType::abi_encode_packed] for more details.
176    #[inline]
177    fn abi_packed_encoded_size<E: ?Sized + SolTypeValue<Self>>(rust: &E) -> usize {
178        rust.stv_abi_packed_encoded_size()
179    }
180
181    /// Non-standard Packed Mode ABI encoding.
182    ///
183    /// See [`abi_encode_packed`][SolType::abi_encode_packed] for more details.
184    #[inline]
185    fn abi_encode_packed_to<E: ?Sized + SolTypeValue<Self>>(rust: &E, out: &mut Vec<u8>) {
186        rust.stv_abi_encode_packed_to(out)
187    }
188
189    /// Non-standard Packed Mode ABI encoding.
190    ///
191    /// This is different from normal ABI encoding:
192    /// - types shorter than 32 bytes are concatenated directly, without padding or sign extension;
193    /// - dynamic types are encoded in-place and without the length;
194    /// - array elements are padded, but still encoded in-place.
195    ///
196    /// More information can be found in the [Solidity docs](https://docs.soliditylang.org/en/latest/abi-spec.html#non-standard-packed-mode).
197    #[inline]
198    fn abi_encode_packed<E: ?Sized + SolTypeValue<Self>>(rust: &E) -> Vec<u8> {
199        let mut out = Vec::with_capacity(Self::abi_packed_encoded_size(rust));
200        Self::abi_encode_packed_to(rust, &mut out);
201        out
202    }
203
204    /// Tokenizes and ABI-encodes the given value by wrapping it in a
205    /// single-element sequence.
206    ///
207    /// See the [`abi`] module for more information.
208    #[inline]
209    fn abi_encode<E: ?Sized + SolTypeValue<Self>>(rust: &E) -> Vec<u8> {
210        abi::encode(&rust.stv_to_tokens())
211    }
212
213    /// Tokenizes and ABI-encodes the given value as function parameters.
214    ///
215    /// See the [`abi`] module for more information.
216    #[inline]
217    fn abi_encode_params<E: ?Sized + SolTypeValue<Self>>(rust: &E) -> Vec<u8>
218    where
219        for<'a> Self::Token<'a>: TokenSeq<'a>,
220    {
221        abi::encode_params(&rust.stv_to_tokens())
222    }
223
224    /// Tokenizes and ABI-encodes the given value as a sequence.
225    ///
226    /// See the [`abi`] module for more information.
227    #[inline]
228    fn abi_encode_sequence<E: ?Sized + SolTypeValue<Self>>(rust: &E) -> Vec<u8>
229    where
230        for<'a> Self::Token<'a>: TokenSeq<'a>,
231    {
232        abi::encode_sequence(&rust.stv_to_tokens())
233    }
234
235    /// Decodes this type's value from an ABI blob by interpreting it as a
236    /// single-element sequence.
237    ///
238    /// See the [`abi`] module for more information.
239    #[inline]
240    fn abi_decode(data: &[u8]) -> Result<Self::RustType> {
241        abi::decode::<Self::Token<'_>>(data).map(Self::detokenize)
242    }
243
244    /// Decodes this type's value from an ABI blob by interpreting it as
245    /// single-element sequence, with validation.
246    ///
247    /// This is the same as [`abi_decode`](Self::abi_decode), but performs
248    /// validation checks on the decoded token.
249    ///
250    /// See the [`abi`] module for more information.
251    #[inline]
252    fn abi_decode_validate(data: &[u8]) -> Result<Self::RustType> {
253        let token = abi::decode::<Self::Token<'_>>(data)?;
254        Self::type_check(&token)?;
255        Ok(Self::detokenize(token))
256    }
257
258    /// Decodes this type's value from an ABI blob by interpreting it as
259    /// function parameters.
260    ///
261    /// See the [`abi`] module for more information.
262    #[inline]
263    fn abi_decode_params<'de>(data: &'de [u8]) -> Result<Self::RustType>
264    where
265        Self::Token<'de>: TokenSeq<'de>,
266    {
267        abi::decode_params::<Self::Token<'_>>(data).map(Self::detokenize)
268    }
269
270    /// Decodes this type's value from an ABI blob by interpreting it as
271    /// function parameters, with validation.
272    ///
273    /// This is the same as [`abi_decode_params`](Self::abi_decode_params), but performs
274    /// validation checks on the decoded token.
275    ///
276    /// See the [`abi`] module for more information.
277    #[inline]
278    fn abi_decode_params_validate<'de>(data: &'de [u8]) -> Result<Self::RustType>
279    where
280        Self::Token<'de>: TokenSeq<'de>,
281    {
282        let token = abi::decode_params::<Self::Token<'_>>(data)?;
283        Self::type_check(&token)?;
284        Ok(Self::detokenize(token))
285    }
286
287    /// Decodes this type's value from an ABI blob by interpreting it as a
288    /// sequence.
289    ///
290    /// See the [`abi`] module for more information.
291    #[inline]
292    fn abi_decode_sequence<'de>(data: &'de [u8]) -> Result<Self::RustType>
293    where
294        Self::Token<'de>: TokenSeq<'de>,
295    {
296        abi::decode_sequence::<Self::Token<'_>>(data).map(Self::detokenize)
297    }
298
299    /// Decodes this type's value from an ABI blob by interpreting it as
300    /// sequence, with validation.
301    ///
302    /// This is the same as [`abi_decode_sequence`](Self::abi_decode_sequence), but performs
303    /// validation checks on the decoded token.
304    ///
305    /// See the [`abi`] module for more information.
306    #[inline]
307    fn abi_decode_sequence_validate<'de>(data: &'de [u8]) -> Result<Self::RustType>
308    where
309        Self::Token<'de>: TokenSeq<'de>,
310    {
311        let token = abi::decode_sequence::<Self::Token<'_>>(data)?;
312        Self::type_check(&token)?;
313        Ok(Self::detokenize(token))
314    }
315}