Skip to main content

alloy_sol_types/types/
function.rs

1use crate::{
2    Result, SolType, Word,
3    abi::{AbiDecoderConfig, Token, TokenSeq},
4    private::SolTypeValue,
5};
6use alloc::vec::Vec;
7
8/// A Solidity function call.
9///
10/// # Implementer's Guide
11///
12/// It should not be necessary to implement this trait manually. Instead, use
13/// the [`sol!`](crate::sol!) procedural macro to parse Solidity syntax into
14/// types that implement this trait.
15pub trait SolCall: Sized {
16    /// The underlying tuple type which represents this type's arguments.
17    ///
18    /// If this type has no arguments, this will be the unit type `()`.
19    type Parameters<'a>: SolType<Token<'a> = Self::Token<'a>>;
20
21    /// The arguments' corresponding [TokenSeq] type.
22    type Token<'a>: TokenSeq<'a>;
23
24    /// The function's return struct.
25    type Return;
26
27    /// The underlying tuple type which represents this type's return values.
28    ///
29    /// If this type has no return values, this will be the unit type `()`.
30    type ReturnTuple<'a>: SolType<Token<'a> = Self::ReturnToken<'a>>;
31
32    /// The returns' corresponding [TokenSeq] type.
33    type ReturnToken<'a>: TokenSeq<'a>;
34
35    /// The function's ABI signature.
36    const SIGNATURE: &'static str;
37
38    /// The function selector: `keccak256(SIGNATURE)[0..4]`
39    const SELECTOR: [u8; 4];
40
41    /// Convert from the tuple type used for ABI encoding and decoding.
42    fn new(tuple: <Self::Parameters<'_> as SolType>::RustType) -> Self;
43
44    /// Tokenize the call's arguments.
45    fn tokenize(&self) -> Self::Token<'_>;
46
47    /// Tokenize the call's return values.
48    fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_>;
49
50    /// The size of the encoded data in bytes, **without** its selector.
51    #[inline]
52    fn abi_encoded_size(&self) -> usize {
53        if let Some(size) = <Self::Parameters<'_> as SolType>::ENCODED_SIZE {
54            return size;
55        }
56
57        // `total_words` includes the first dynamic offset which we ignore.
58        let offset = <<Self::Parameters<'_> as SolType>::Token<'_> as Token>::DYNAMIC as usize * 32;
59        (self.tokenize().total_words() * Word::len_bytes()).saturating_sub(offset)
60    }
61
62    /// ABI decode this call's arguments from the given slice, **without** its
63    /// selector.
64    #[inline]
65    fn abi_decode_raw(data: &[u8]) -> Result<Self> {
66        <Self::Parameters<'_> as SolType>::abi_decode_sequence(data).map(Self::new)
67    }
68
69    /// ABI-decodes this call's arguments with a custom decoder configuration,
70    /// without its selector.
71    #[inline]
72    fn abi_decode_raw_with_config(data: &[u8], config: AbiDecoderConfig) -> Result<Self> {
73        <Self::Parameters<'_> as SolType>::abi_decode_sequence_with_config(data, config)
74            .map(Self::new)
75    }
76
77    /// ABI decode this call's arguments from the given slice, **without** its
78    /// selector, with validation.
79    ///
80    /// This is the same as [`abi_decode_raw`](Self::abi_decode_raw), but performs
81    /// validation checks on the decoded parameters tuple.
82    #[inline]
83    // TODO: Deprecate in favor of a validating decoder configuration.
84    // #[deprecated(note = "use a validating decoder configuration")]
85    fn abi_decode_raw_validate(data: &[u8]) -> Result<Self> {
86        Self::abi_decode_raw_with_config(data, AbiDecoderConfig::new().validate(true))
87    }
88
89    /// ABI decode this call's arguments from the given slice, **with** the
90    /// selector.
91    #[inline]
92    fn abi_decode(data: &[u8]) -> Result<Self> {
93        let data = data
94            .strip_prefix(&Self::SELECTOR)
95            .ok_or_else(|| crate::Error::type_check_fail_sig(data, Self::SIGNATURE))?;
96        Self::abi_decode_raw(data)
97    }
98
99    /// ABI-decodes this call's arguments with a custom decoder configuration.
100    #[inline]
101    fn abi_decode_with_config(data: &[u8], config: AbiDecoderConfig) -> Result<Self> {
102        let data = data
103            .strip_prefix(&Self::SELECTOR)
104            .ok_or_else(|| crate::Error::type_check_fail_sig(data, Self::SIGNATURE))?;
105        Self::abi_decode_raw_with_config(data, config)
106    }
107
108    /// ABI decode this call's arguments from the given slice, **with** the
109    /// selector, with validation.
110    ///
111    /// This is the same as [`abi_decode`](Self::abi_decode), but performs
112    /// validation checks on the decoded parameters tuple.
113    #[inline]
114    // TODO: Deprecate in favor of a validating decoder configuration.
115    // #[deprecated(note = "use a validating decoder configuration")]
116    fn abi_decode_validate(data: &[u8]) -> Result<Self> {
117        Self::abi_decode_with_config(data, AbiDecoderConfig::new().validate(true))
118    }
119
120    /// ABI encode the call to the given buffer **without** its selector.
121    #[inline]
122    fn abi_encode_raw(&self, out: &mut Vec<u8>) {
123        out.reserve(self.abi_encoded_size());
124        out.extend(crate::abi::encode_sequence(&self.tokenize()));
125    }
126
127    /// ABI encode the call to the given buffer **with** its selector.
128    #[inline]
129    fn abi_encode(&self) -> Vec<u8> {
130        let mut out = Vec::with_capacity(4 + self.abi_encoded_size());
131        out.extend(&Self::SELECTOR);
132        self.abi_encode_raw(&mut out);
133        out
134    }
135
136    /// ABI decode this call's return values from the given slice.
137    fn abi_decode_returns(data: &[u8]) -> Result<Self::Return>;
138
139    /// ABI-decodes this call's return values with a custom decoder configuration.
140    ///
141    /// The default implementation does not support strict decoding.
142    fn abi_decode_returns_with_config(
143        data: &[u8],
144        config: AbiDecoderConfig,
145    ) -> Result<Self::Return> {
146        if config.get_strict() {
147            Err(crate::Error::custom(
148                "strict decoding is unsupported by this SolCall implementation",
149            ))
150        } else {
151            Self::abi_decode_returns(data)
152        }
153    }
154
155    /// ABI decode this call's return values from the given slice, with validation.
156    ///
157    /// This is the same as [`abi_decode_returns`](Self::abi_decode_returns), but performs
158    /// validation checks on the decoded return tuple.
159    // TODO: Deprecate in favor of a validating decoder configuration.
160    // #[deprecated(note = "use a validating decoder configuration")]
161    fn abi_decode_returns_validate(data: &[u8]) -> Result<Self::Return> {
162        Self::abi_decode_returns_with_config(data, AbiDecoderConfig::new().validate(true))
163    }
164
165    /// ABI encode the call's return value.
166    #[inline]
167    fn abi_encode_returns(ret: &Self::Return) -> Vec<u8> {
168        crate::abi::encode_sequence(&Self::tokenize_returns(ret))
169    }
170
171    /// ABI encode the call's return values.
172    #[inline]
173    fn abi_encode_returns_tuple<'a, E>(e: &'a E) -> Vec<u8>
174    where
175        E: SolTypeValue<Self::ReturnTuple<'a>>,
176    {
177        crate::abi::encode_sequence(&e.stv_to_tokens())
178    }
179}
180
181/// A Solidity constructor.
182pub trait SolConstructor: Sized {
183    /// The underlying tuple type which represents this type's arguments.
184    ///
185    /// If this type has no arguments, this will be the unit type `()`.
186    type Parameters<'a>: SolType<Token<'a> = Self::Token<'a>>;
187
188    /// The arguments' corresponding [TokenSeq] type.
189    type Token<'a>: TokenSeq<'a>;
190
191    /// Convert from the tuple type used for ABI encoding and decoding.
192    fn new(tuple: <Self::Parameters<'_> as SolType>::RustType) -> Self;
193
194    /// Tokenize the call's arguments.
195    fn tokenize(&self) -> Self::Token<'_>;
196
197    /// The size of the encoded data in bytes.
198    #[inline]
199    fn abi_encoded_size(&self) -> usize {
200        if let Some(size) = <Self::Parameters<'_> as SolType>::ENCODED_SIZE {
201            return size;
202        }
203
204        // `total_words` includes the first dynamic offset which we ignore.
205        let offset = <<Self::Parameters<'_> as SolType>::Token<'_> as Token>::DYNAMIC as usize * 32;
206        (self.tokenize().total_words() * Word::len_bytes()).saturating_sub(offset)
207    }
208
209    /// ABI encode the call to the given buffer.
210    #[inline]
211    fn abi_encode(&self) -> Vec<u8> {
212        crate::abi::encode_sequence(&self.tokenize())
213    }
214}