1use crate::{DynSolValue, Error as CrateError, Result, Specifier};
2use alloc::vec::Vec;
3use alloy_json_abi::{Constructor, Error, Function, Param};
4use alloy_primitives::Selector;
5use alloy_sol_types::abi::Decoder;
6
7#[allow(unknown_lints, unnameable_types)]
8mod sealed {
9 pub trait Sealed {}
10 impl Sealed for super::Constructor {}
11 impl Sealed for super::Error {}
12 impl Sealed for super::Function {}
13}
14use sealed::Sealed;
15
16pub trait JsonAbiExt: Sealed {
24 fn abi_encode_input(&self, values: &[DynSolValue]) -> Result<Vec<u8>>;
40
41 fn abi_encode_input_raw(&self, values: &[DynSolValue]) -> Result<Vec<u8>>;
52
53 fn abi_decode_input(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>>;
60}
61
62pub trait FunctionExt: JsonAbiExt + Sealed {
67 fn abi_encode_output(&self, values: &[DynSolValue]) -> Result<Vec<u8>>;
78
79 fn abi_decode_output(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>>;
83}
84
85impl JsonAbiExt for Constructor {
86 #[inline]
87 fn abi_encode_input(&self, values: &[DynSolValue]) -> Result<Vec<u8>> {
88 encode_typeck(&self.inputs, values)
89 }
90
91 #[inline]
92 fn abi_encode_input_raw(&self, values: &[DynSolValue]) -> Result<Vec<u8>> {
93 encode_typeck(&self.inputs, values)
94 }
95
96 #[inline]
97 fn abi_decode_input(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
98 abi_decode(data, &self.inputs, validate)
99 }
100}
101
102impl JsonAbiExt for Error {
103 #[inline]
104 fn abi_encode_input(&self, values: &[DynSolValue]) -> Result<Vec<u8>> {
105 encode_typeck(&self.inputs, values).map(prefix_selector(self.selector()))
106 }
107
108 #[inline]
109 fn abi_encode_input_raw(&self, values: &[DynSolValue]) -> Result<Vec<u8>> {
110 encode_typeck(&self.inputs, values)
111 }
112
113 #[inline]
114 fn abi_decode_input(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
115 abi_decode(data, &self.inputs, validate)
116 }
117}
118
119impl JsonAbiExt for Function {
120 #[inline]
121 fn abi_encode_input(&self, values: &[DynSolValue]) -> Result<Vec<u8>> {
122 encode_typeck(&self.inputs, values).map(prefix_selector(self.selector()))
123 }
124
125 #[inline]
126 fn abi_encode_input_raw(&self, values: &[DynSolValue]) -> Result<Vec<u8>> {
127 encode_typeck(&self.inputs, values)
128 }
129
130 #[inline]
131 fn abi_decode_input(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
132 abi_decode(data, &self.inputs, validate)
133 }
134}
135
136impl FunctionExt for Function {
137 #[inline]
138 fn abi_encode_output(&self, values: &[DynSolValue]) -> Result<Vec<u8>> {
139 encode_typeck(&self.outputs, values)
140 }
141
142 #[inline]
143 fn abi_decode_output(&self, data: &[u8], validate: bool) -> Result<Vec<DynSolValue>> {
144 abi_decode(data, &self.outputs, validate)
145 }
146}
147
148#[inline]
149fn prefix_selector(selector: Selector) -> impl FnOnce(Vec<u8>) -> Vec<u8> {
150 move |data| {
151 let mut new = Vec::with_capacity(data.len() + 4);
152 new.extend_from_slice(&selector[..]);
153 new.extend_from_slice(&data[..]);
154 new
155 }
156}
157
158fn encode_typeck(params: &[Param], values: &[DynSolValue]) -> Result<Vec<u8>> {
159 if values.len() != params.len() {
160 return Err(CrateError::EncodeLengthMismatch {
161 expected: params.len(),
162 actual: values.len(),
163 });
164 }
165 for (value, param) in core::iter::zip(values, params) {
166 let ty = param.resolve()?;
167 if !ty.matches(value) {
168 return Err(CrateError::TypeMismatch {
169 expected: ty.sol_type_name().into_owned(),
170 actual: value.sol_type_name().unwrap_or_else(|| "<none>".into()).into_owned(),
171 });
172 }
173 }
174
175 Ok(abi_encode(values))
176}
177
178#[inline]
179fn abi_encode(values: &[DynSolValue]) -> Vec<u8> {
180 DynSolValue::encode_seq(values)
181}
182
183fn abi_decode(data: &[u8], params: &[Param], validate: bool) -> Result<Vec<DynSolValue>> {
184 let mut values = Vec::with_capacity(params.len());
185 let mut decoder = Decoder::new(data, validate);
186 for param in params {
187 let ty = param.resolve()?;
188 let value = ty.abi_decode_inner(&mut decoder, crate::DynToken::decode_single_populate)?;
189 values.push(value);
190 }
191 Ok(values)
192}
193
194#[cfg(test)]
195mod tests {
196 use super::*;
197 use alloy_primitives::{address, bytes, hex, Address, U256};
198
199 #[test]
200 fn can_encode_decode_functions() {
201 let json = r#"{
202 "inputs": [
203 {
204 "internalType": "address",
205 "name": "",
206 "type": "address"
207 },
208 {
209 "internalType": "address",
210 "name": "",
211 "type": "address"
212 }
213 ],
214 "name": "allowance",
215 "outputs": [
216 {
217 "internalType": "uint256",
218 "name": "",
219 "type": "uint256"
220 }
221 ],
222 "stateMutability": "view",
223 "type": "function"
224 }"#;
225
226 let func: Function = serde_json::from_str(json).unwrap();
227 assert_eq!(2, func.inputs.len());
228 assert_eq!(1, func.outputs.len());
229 assert_eq!(func.signature(), "allowance(address,address)");
230
231 let expected = alloy_primitives::hex!(
233 "dd62ed3e"
234 "0000000000000000000000001111111111111111111111111111111111111111"
235 "0000000000000000000000002222222222222222222222222222222222222222"
236 );
237 let input = [
238 DynSolValue::Address(Address::repeat_byte(0x11)),
239 DynSolValue::Address(Address::repeat_byte(0x22)),
240 ];
241 let result = func.abi_encode_input(&input).unwrap();
242 assert_eq!(expected[..], result);
243
244 let wrong_input = [
246 DynSolValue::Uint(U256::from(10u8), 256),
247 DynSolValue::Address(Address::repeat_byte(2u8)),
248 ];
249 assert!(func.abi_encode_input(&wrong_input).is_err());
250
251 let response = U256::from(1u8).to_be_bytes_vec();
253 let decoded = func.abi_decode_output(&response, true).unwrap();
254 assert_eq!(decoded, [DynSolValue::Uint(U256::from(1u8), 256)]);
255
256 let bad_response = Address::repeat_byte(3u8).to_vec();
258 assert!(func.abi_decode_output(&bad_response, true).is_err());
259 assert!(func.abi_decode_output(&bad_response, false).is_err());
260 }
261
262 #[test]
265 fn empty_bytes_array() {
266 let func = Function::parse("register(bytes,address,bytes[])").unwrap();
267 let input = [
268 DynSolValue::Bytes(bytes!("09736b79736b79736b79026f7300").into()),
269 DynSolValue::Address(address!("0xB7b54cd129e6D8B24e6AE652a473449B273eE3E4")),
270 DynSolValue::Array(vec![]),
271 ];
272 let result = func.abi_encode_input(&input).unwrap();
273
274 let expected = hex!(
275 "
276 d123f99a
277 0000000000000000000000000000000000000000000000000000000000000060
278 000000000000000000000000B7b54cd129e6D8B24e6AE652a473449B273eE3E4
279 00000000000000000000000000000000000000000000000000000000000000a0
280 000000000000000000000000000000000000000000000000000000000000000e
281 09736b79736b79736b79026f7300000000000000000000000000000000000000
282 0000000000000000000000000000000000000000000000000000000000000000
283 "
284 );
285 assert_eq!(hex::encode(expected), hex::encode(result));
286 }
287}