1use crate::{
2 abi::{Token, TokenSeq},
3 private::SolTypeValue,
4Result, SolType, Word,
5};
6use alloc::vec::Vec;
78/// 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 `()`.
19type Parameters<'a>: SolType<Token<'a> = Self::Token<'a>>;
2021/// The arguments' corresponding [TokenSeq] type.
22type Token<'a>: TokenSeq<'a>;
2324/// The function's return struct.
25type Return;
2627/// 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 `()`.
30type ReturnTuple<'a>: SolType<Token<'a> = Self::ReturnToken<'a>>;
3132/// The returns' corresponding [TokenSeq] type.
33type ReturnToken<'a>: TokenSeq<'a>;
3435/// The function's ABI signature.
36const SIGNATURE: &'static str;
3738/// The function selector: `keccak256(SIGNATURE)[0..4]`
39const SELECTOR: [u8; 4];
4041/// Convert from the tuple type used for ABI encoding and decoding.
42fn new(tuple: <Self::Parameters<'_> as SolType>::RustType) -> Self;
4344/// Tokenize the call's arguments.
45fn tokenize(&self) -> Self::Token<'_>;
4647/// The size of the encoded data in bytes, **without** its selector.
48#[inline]
49fn abi_encoded_size(&self) -> usize {
50if let Some(size) = <Self::Parameters<'_> as SolType>::ENCODED_SIZE {
51return size;
52 }
5354// `total_words` includes the first dynamic offset which we ignore.
55let offset = <<Self::Parameters<'_> as SolType>::Token<'_> as Token>::DYNAMIC as usize * 32;
56 (self.tokenize().total_words() * Word::len_bytes()).saturating_sub(offset)
57 }
5859/// ABI decode this call's arguments from the given slice, **without** its
60 /// selector.
61#[inline]
62fn abi_decode_raw(data: &[u8], validate: bool) -> Result<Self> {
63 <Self::Parameters<'_> as SolType>::abi_decode_sequence(data, validate).map(Self::new)
64 }
6566/// ABI decode this call's arguments from the given slice, **with** the
67 /// selector.
68#[inline]
69fn abi_decode(data: &[u8], validate: bool) -> Result<Self> {
70let data = data
71 .strip_prefix(&Self::SELECTOR)
72 .ok_or_else(|| crate::Error::type_check_fail_sig(data, Self::SIGNATURE))?;
73Self::abi_decode_raw(data, validate)
74 }
7576/// ABI encode the call to the given buffer **without** its selector.
77#[inline]
78fn abi_encode_raw(&self, out: &mut Vec<u8>) {
79 out.reserve(self.abi_encoded_size());
80 out.extend(crate::abi::encode_sequence(&self.tokenize()));
81 }
8283/// ABI encode the call to the given buffer **with** its selector.
84#[inline]
85fn abi_encode(&self) -> Vec<u8> {
86let mut out = Vec::with_capacity(4 + self.abi_encoded_size());
87 out.extend(&Self::SELECTOR);
88self.abi_encode_raw(&mut out);
89 out
90 }
9192/// ABI decode this call's return values from the given slice.
93fn abi_decode_returns(data: &[u8], validate: bool) -> Result<Self::Return>;
9495/// ABI encode the call's return values.
96#[inline]
97fn abi_encode_returns<'a, E>(e: &'a E) -> Vec<u8>
98where
99E: SolTypeValue<Self::ReturnTuple<'a>>,
100 {
101crate::abi::encode_sequence(&e.stv_to_tokens())
102 }
103}
104105/// A Solidity constructor.
106pub trait SolConstructor: Sized {
107/// The underlying tuple type which represents this type's arguments.
108 ///
109 /// If this type has no arguments, this will be the unit type `()`.
110type Parameters<'a>: SolType<Token<'a> = Self::Token<'a>>;
111112/// The arguments' corresponding [TokenSeq] type.
113type Token<'a>: TokenSeq<'a>;
114115/// Convert from the tuple type used for ABI encoding and decoding.
116fn new(tuple: <Self::Parameters<'_> as SolType>::RustType) -> Self;
117118/// Tokenize the call's arguments.
119fn tokenize(&self) -> Self::Token<'_>;
120121/// The size of the encoded data in bytes.
122#[inline]
123fn abi_encoded_size(&self) -> usize {
124if let Some(size) = <Self::Parameters<'_> as SolType>::ENCODED_SIZE {
125return size;
126 }
127128// `total_words` includes the first dynamic offset which we ignore.
129let offset = <<Self::Parameters<'_> as SolType>::Token<'_> as Token>::DYNAMIC as usize * 32;
130 (self.tokenize().total_words() * Word::len_bytes()).saturating_sub(offset)
131 }
132133/// ABI encode the call to the given buffer.
134#[inline]
135fn abi_encode(&self) -> Vec<u8> {
136crate::abi::encode_sequence(&self.tokenize())
137 }
138}