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}