1use serde::{Deserialize, Serialize};
11use serde_json::Value;
12use soldb_core::{SoldbError, SoldbResult};
13
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15pub struct FunctionSignature {
16 pub name: String,
17 pub arg_types: Vec<String>,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub struct AbiInput {
22 #[serde(rename = "type")]
23 pub ty: String,
24 #[serde(default)]
25 pub components: Vec<AbiInput>,
26}
27
28pub fn match_abi_types(parsed_types: &[String], abi_types: &[String]) -> bool {
29 parsed_types.len() == abi_types.len()
30 && parsed_types
31 .iter()
32 .zip(abi_types)
33 .all(|(parsed_type, abi_type)| match_single_type(parsed_type, abi_type))
34}
35
36pub fn match_single_type(parsed_type: &str, abi_type: &str) -> bool {
37 if parsed_type == abi_type {
38 return true;
39 }
40
41 if parsed_type.starts_with('(') && parsed_type.ends_with(')') && abi_type == "tuple" {
42 return true;
43 }
44
45 if let (Some(parsed_base), Some(abi_base)) =
46 (parsed_type.strip_suffix("[]"), abi_type.strip_suffix("[]"))
47 {
48 return match_single_type(parsed_base, abi_base);
49 }
50
51 parsed_type.contains('(') && abi_type == "tuple"
52}
53
54pub fn parse_signature(signature: &str) -> Option<FunctionSignature> {
55 let open = signature.find('(')?;
56 if !signature.ends_with(')') {
57 return None;
58 }
59
60 let name = &signature[..open];
61 if name.is_empty() || !name.chars().all(|c| c == '_' || c.is_ascii_alphanumeric()) {
62 return None;
63 }
64
65 let args = &signature[open + 1..signature.len() - 1];
66 Some(FunctionSignature {
67 name: name.to_owned(),
68 arg_types: split_args(args)?,
69 })
70}
71
72pub fn parse_tuple_arg(value: &Value, abi_input: &AbiInput) -> SoldbResult<Value> {
73 let values = value
74 .as_array()
75 .ok_or_else(|| SoldbError::Message("Tuple argument must be an array".to_owned()))?;
76
77 if values.len() < abi_input.components.len() {
78 return Err(SoldbError::Message(format!(
79 "Tuple argument has {} values but ABI expects {}",
80 values.len(),
81 abi_input.components.len()
82 )));
83 }
84
85 let mut parsed = Vec::with_capacity(abi_input.components.len());
86 for (index, component) in abi_input.components.iter().enumerate() {
87 let component_value = &values[index];
88 if component.ty == "tuple" {
89 parsed.push(parse_tuple_arg(component_value, component)?);
90 } else if component.ty.starts_with("tuple") && component.ty.ends_with("[]") {
91 let tuple_array = component_value.as_array().ok_or_else(|| {
92 SoldbError::Message("Tuple array argument must be an array".to_owned())
93 })?;
94
95 let parsed_items = tuple_array
96 .iter()
97 .map(|item| parse_tuple_arg(item, component))
98 .collect::<SoldbResult<Vec<_>>>()?;
99 parsed.push(Value::Array(parsed_items));
100 } else {
101 parsed.push(component_value.clone());
102 }
103 }
104
105 Ok(Value::Array(parsed))
106}
107
108pub fn canonical_abi_input_type(input: &AbiInput) -> String {
109 if let Some(suffix) = input.ty.strip_prefix("tuple") {
110 let components = input
111 .components
112 .iter()
113 .map(canonical_abi_input_type)
114 .collect::<Vec<_>>()
115 .join(",");
116 return format!("({components}){suffix}");
117 }
118 input.ty.clone()
119}
120
121pub fn encode_abi_arguments(arg_types: &[String], args: &[String]) -> SoldbResult<String> {
122 if arg_types.len() != args.len() {
123 return Err(SoldbError::Message(format!(
124 "Wrong argument count: expected {}, got {}",
125 arg_types.len(),
126 args.len()
127 )));
128 }
129
130 let encoded_args = arg_types
131 .iter()
132 .zip(args)
133 .map(|(arg_type, arg_value)| encode_arg(arg_type, arg_value))
134 .collect::<SoldbResult<Vec<_>>>()?;
135 Ok(encode_tuple_payload(encoded_args))
136}
137
138pub fn encode_function_call(signature: &str, args: &[String]) -> SoldbResult<String> {
139 let parsed = parse_signature(signature)
140 .ok_or_else(|| SoldbError::Message(format!("Invalid function signature: {signature}")))?;
141
142 let selector = function_selector(signature)?;
143 let payload = encode_abi_arguments(&parsed.arg_types, args).map_err(|error| {
144 SoldbError::Message(format!(
145 "Failed to encode arguments for {signature}: {error}"
146 ))
147 })?;
148
149 let mut encoded = String::with_capacity(2 + 8 + payload.len());
150 encoded.push_str("0x");
151 encoded.push_str(&bytes_to_hex(&selector));
152 encoded.push_str(&payload);
153 Ok(encoded)
154}
155
156pub fn function_selector(signature: &str) -> SoldbResult<[u8; 4]> {
157 let parsed = parse_signature(signature)
158 .ok_or_else(|| SoldbError::Message(format!("Invalid function signature: {signature}")))?;
159 let canonical = format!("{}({})", parsed.name, parsed.arg_types.join(","));
160 let hash = keccak256(canonical.as_bytes());
161 Ok([hash[0], hash[1], hash[2], hash[3]])
162}
163
164pub fn keccak256(input: &[u8]) -> [u8; 32] {
165 const RATE: usize = 136;
166 let mut state = [0_u64; 25];
167 let (blocks, remainder) = input.as_chunks::<RATE>();
168
169 for block in blocks {
170 absorb_block(&mut state, block);
171 keccak_f1600(&mut state);
172 }
173
174 let mut final_block = [0_u8; RATE];
175 final_block[..remainder.len()].copy_from_slice(remainder);
176 final_block[remainder.len()] ^= 0x01;
177 final_block[RATE - 1] ^= 0x80;
178 absorb_block(&mut state, &final_block);
179 keccak_f1600(&mut state);
180
181 let mut output = [0_u8; 32];
182 for (index, chunk) in output.chunks_mut(8).enumerate() {
183 chunk.copy_from_slice(&state[index].to_le_bytes());
184 }
185 output
186}
187
188fn split_args(input: &str) -> Option<Vec<String>> {
189 if input.trim().is_empty() {
190 return Some(Vec::new());
191 }
192
193 let mut args = Vec::new();
194 let mut depth = 0_i64;
195 let mut current = String::new();
196
197 for ch in input.chars() {
198 match ch {
199 ',' if depth == 0 => {
200 let arg = current.trim();
201 if !arg.is_empty() {
202 args.push(arg.to_owned());
203 }
204 current.clear();
205 }
206 '(' => {
207 depth += 1;
208 current.push(ch);
209 }
210 ')' => {
211 depth -= 1;
212 if depth < 0 {
213 return None;
214 }
215 current.push(ch);
216 }
217 _ => current.push(ch),
218 }
219 }
220
221 if depth != 0 {
222 return None;
223 }
224
225 let arg = current.trim();
226 if !arg.is_empty() {
227 args.push(arg.to_owned());
228 }
229
230 Some(args)
231}
232
233enum EncodedArg {
234 Static(String),
235 Dynamic(String),
236}
237
238impl EncodedArg {
239 fn head_size_bytes(&self) -> usize {
240 match self {
241 Self::Static(words) => words.len() / 2,
242 Self::Dynamic(_) => 32,
243 }
244 }
245
246 fn is_dynamic(&self) -> bool {
247 matches!(self, Self::Dynamic(_))
248 }
249}
250
251fn encode_arg(arg_type: &str, value: &str) -> SoldbResult<EncodedArg> {
252 let arg_type = arg_type.trim();
253 if let Some((base_type, fixed_len)) = parse_array_type(arg_type)? {
254 return encode_array_arg(base_type, fixed_len, value);
255 }
256 if let Some(component_types) = parse_tuple_type(arg_type) {
257 return encode_tuple_arg(&component_types, value);
258 }
259 if arg_type == "string" {
260 return Ok(EncodedArg::Dynamic(encode_dynamic_bytes(value.as_bytes())));
261 }
262 if arg_type == "bytes" {
263 return Ok(EncodedArg::Dynamic(encode_dynamic_bytes(&parse_hex_bytes(
264 value,
265 )?)));
266 }
267
268 encode_static_arg(arg_type, value).map(EncodedArg::Static)
269}
270
271fn encode_tuple_payload(encoded_args: Vec<EncodedArg>) -> String {
272 let head_size_bytes = encoded_args
273 .iter()
274 .map(EncodedArg::head_size_bytes)
275 .sum::<usize>();
276 let tail_size = encoded_args
277 .iter()
278 .filter_map(|arg| match arg {
279 EncodedArg::Static(_) => None,
280 EncodedArg::Dynamic(tail) => Some(tail.len()),
281 })
282 .sum::<usize>();
283
284 let mut encoded = String::with_capacity(encoded_args.len() * 64 + tail_size);
285 let mut tails = String::with_capacity(tail_size);
286 let mut dynamic_offset = head_size_bytes;
287 for arg in encoded_args {
288 match arg {
289 EncodedArg::Static(word) => encoded.push_str(&word),
290 EncodedArg::Dynamic(tail) => {
291 encoded.push_str(&format!("{dynamic_offset:064x}"));
292 dynamic_offset += tail.len() / 2;
293 tails.push_str(&tail);
294 }
295 }
296 }
297 encoded.push_str(&tails);
298 encoded
299}
300
301fn parse_array_type(arg_type: &str) -> SoldbResult<Option<(&str, Option<usize>)>> {
302 if !arg_type.ends_with(']') {
303 return Ok(None);
304 }
305 let Some(open) = arg_type.rfind('[') else {
306 return Ok(None);
307 };
308 let base_type = arg_type[..open].trim();
309 if base_type.is_empty() {
310 return Err(SoldbError::Message(format!(
311 "Invalid array type: {arg_type}"
312 )));
313 }
314
315 let length = &arg_type[open + 1..arg_type.len() - 1];
316 if length.is_empty() {
317 return Ok(Some((base_type, None)));
318 }
319 let length = length.parse::<usize>().map_err(|error| {
320 SoldbError::Message(format!("Invalid fixed array length '{length}': {error}"))
321 })?;
322 Ok(Some((base_type, Some(length))))
323}
324
325fn parse_tuple_type(arg_type: &str) -> Option<Vec<String>> {
326 let inner = arg_type.strip_prefix('(')?.strip_suffix(')')?;
327 split_args(inner)
328}
329
330fn encode_tuple_arg(component_types: &[String], value: &str) -> SoldbResult<EncodedArg> {
331 let values = parse_json_array_arg(value, "tuple")?;
332 if values.len() != component_types.len() {
333 return Err(SoldbError::Message(format!(
334 "Tuple argument expects {} values, got {}",
335 component_types.len(),
336 values.len()
337 )));
338 }
339
340 let encoded_components = component_types
341 .iter()
342 .zip(&values)
343 .map(|(component_type, item)| encode_arg(component_type, &json_value_to_arg_string(item)?))
344 .collect::<SoldbResult<Vec<_>>>()?;
345 let is_dynamic = encoded_components.iter().any(EncodedArg::is_dynamic);
346 let encoded = encode_tuple_payload(encoded_components);
347 if is_dynamic {
348 Ok(EncodedArg::Dynamic(encoded))
349 } else {
350 Ok(EncodedArg::Static(encoded))
351 }
352}
353
354fn encode_array_arg(
355 base_type: &str,
356 fixed_len: Option<usize>,
357 value: &str,
358) -> SoldbResult<EncodedArg> {
359 let values = parse_json_array_arg(value, &format!("{base_type}[]"))?;
360 if let Some(expected) = fixed_len {
361 if values.len() != expected {
362 return Err(SoldbError::Message(format!(
363 "Fixed array argument expects {expected} values, got {}",
364 values.len()
365 )));
366 }
367 }
368
369 let encoded_elements = values
370 .iter()
371 .map(|item| encode_arg(base_type, &json_value_to_arg_string(item)?))
372 .collect::<SoldbResult<Vec<_>>>()?;
373 let has_dynamic_elements = encoded_elements.iter().any(EncodedArg::is_dynamic);
374 let payload = encode_tuple_payload(encoded_elements);
375
376 if fixed_len.is_some() {
377 if has_dynamic_elements {
378 Ok(EncodedArg::Dynamic(payload))
379 } else {
380 Ok(EncodedArg::Static(payload))
381 }
382 } else {
383 let mut encoded = format!("{:064x}", values.len());
384 encoded.push_str(&payload);
385 Ok(EncodedArg::Dynamic(encoded))
386 }
387}
388
389fn parse_json_array_arg(value: &str, label: &str) -> SoldbResult<Vec<Value>> {
390 let values = serde_json::from_str::<Value>(value).map_err(|error| {
391 SoldbError::Message(format!(
392 "Array argument for type '{label}' must be JSON: {error}"
393 ))
394 })?;
395 values.as_array().cloned().ok_or_else(|| {
396 SoldbError::Message(format!(
397 "Array argument for type '{label}' must be a JSON array"
398 ))
399 })
400}
401
402fn json_value_to_arg_string(value: &Value) -> SoldbResult<String> {
403 match value {
404 Value::String(value) => Ok(value.clone()),
405 Value::Number(value) => Ok(value.to_string()),
406 Value::Bool(value) => Ok(value.to_string()),
407 Value::Array(_) => serde_json::to_string(value)
408 .map_err(|error| SoldbError::Message(format!("Invalid array argument: {error}"))),
409 Value::Null => Err(SoldbError::Message(
410 "Null ABI array values are not supported".to_owned(),
411 )),
412 Value::Object(_) => Err(SoldbError::Message(
413 "Object ABI array values are not supported".to_owned(),
414 )),
415 }
416}
417
418fn encode_static_arg(arg_type: &str, value: &str) -> SoldbResult<String> {
419 let arg_type = arg_type.trim();
420 if arg_type.starts_with("uint") {
421 return encode_uint_arg(arg_type, value);
422 }
423 if arg_type.starts_with("int") {
424 return encode_int_arg(arg_type, value);
425 }
426 if arg_type == "address" {
427 return encode_address_arg(value);
428 }
429 if arg_type == "bool" {
430 return encode_bool_arg(value);
431 }
432 if arg_type == "bytes32" {
433 return encode_bytes32_arg(value);
434 }
435 if let Some(width) = arg_type.strip_prefix("bytes") {
436 return encode_fixed_bytes_arg(width, value);
437 }
438
439 Err(SoldbError::Message(format!(
440 "ABI encoding for type '{arg_type}' is not supported"
441 )))
442}
443
444fn encode_uint_arg(arg_type: &str, value: &str) -> SoldbResult<String> {
445 let bits = validate_uint_type(arg_type)?;
446 let encoded = parse_uint_word(value)?;
447 validate_uint_fits_bits(&encoded, bits, value)?;
448 Ok(encoded)
449}
450
451fn encode_int_arg(arg_type: &str, value: &str) -> SoldbResult<String> {
452 validate_int_type(arg_type)?;
453 let parsed = value
454 .parse::<i128>()
455 .map_err(|error| SoldbError::Message(format!("Invalid int value '{value}': {error}")))?;
456 Ok(format!("{:064x}", parsed as u128))
457}
458
459fn encode_address_arg(value: &str) -> SoldbResult<String> {
460 let address = value.trim_start_matches("0x");
461 if address.len() != 40 || !address.bytes().all(|byte| byte.is_ascii_hexdigit()) {
462 return Err(SoldbError::Message(format!(
463 "Invalid address value: {value}"
464 )));
465 }
466 Ok(format!("{address:0>64}").to_ascii_lowercase())
467}
468
469fn encode_bool_arg(value: &str) -> SoldbResult<String> {
470 match value {
471 "true" | "1" => Ok(format!("{:064x}", 1)),
472 "false" | "0" => Ok(format!("{:064x}", 0)),
473 _ => Err(SoldbError::Message(format!("Invalid bool value: {value}"))),
474 }
475}
476
477fn encode_bytes32_arg(value: &str) -> SoldbResult<String> {
478 encode_fixed_bytes_arg("32", value)
479}
480
481fn encode_fixed_bytes_arg(width: &str, value: &str) -> SoldbResult<String> {
482 let width = width.parse::<usize>().map_err(|error| {
483 SoldbError::Message(format!("Invalid fixed bytes width '{width}': {error}"))
484 })?;
485 if !(1..=32).contains(&width) {
486 return Err(SoldbError::Message(format!(
487 "Invalid fixed bytes width: {width}"
488 )));
489 }
490
491 let bytes = parse_hex_bytes(value)?;
492 if bytes.len() != width {
493 return Err(SoldbError::Message(format!(
494 "Invalid bytes{width} value: {value}"
495 )));
496 }
497 let mut encoded = bytes_to_hex(&bytes);
498 encoded.push_str(&"0".repeat((32 - width) * 2));
499 Ok(encoded)
500}
501
502fn encode_dynamic_bytes(bytes: &[u8]) -> String {
503 let mut encoded = format!("{:064x}", bytes.len());
504 encoded.push_str(&bytes_to_hex(bytes));
505 let padding_bytes = (32 - bytes.len() % 32) % 32;
506 encoded.push_str(&"0".repeat(padding_bytes * 2));
507 encoded
508}
509
510fn parse_hex_bytes(value: &str) -> SoldbResult<Vec<u8>> {
511 let bytes = value.trim_start_matches("0x");
512 if !bytes.len().is_multiple_of(2) || !bytes.bytes().all(|byte| byte.is_ascii_hexdigit()) {
513 return Err(SoldbError::Message(format!("Invalid bytes value: {value}")));
514 }
515
516 bytes
517 .as_bytes()
518 .chunks(2)
519 .map(|chunk| {
520 let pair = std::str::from_utf8(chunk)
521 .map_err(|error| SoldbError::Message(format!("Invalid bytes value: {error}")))?;
522 u8::from_str_radix(pair, 16)
523 .map_err(|error| SoldbError::Message(format!("Invalid bytes value: {error}")))
524 })
525 .collect()
526}
527
528fn validate_uint_type(arg_type: &str) -> SoldbResult<u16> {
529 validate_int_bit_width(arg_type.strip_prefix("uint").unwrap_or_default(), "uint")
530}
531
532fn validate_int_type(arg_type: &str) -> SoldbResult<()> {
533 validate_int_bit_width(arg_type.strip_prefix("int").unwrap_or_default(), "int")?;
534 Ok(())
535}
536
537fn validate_int_bit_width(width: &str, label: &str) -> SoldbResult<u16> {
538 if width.is_empty() {
539 return Ok(256);
540 }
541
542 let bits = width.parse::<u16>().map_err(|error| {
543 SoldbError::Message(format!("Invalid {label} bit width '{width}': {error}"))
544 })?;
545 if bits == 0 || bits > 256 || bits % 8 != 0 {
546 return Err(SoldbError::Message(format!(
547 "Invalid {label} bit width: {bits}"
548 )));
549 }
550 Ok(bits)
551}
552
553fn parse_uint_word(value: &str) -> SoldbResult<String> {
554 let value = value.trim();
555 if value.is_empty() {
556 return Err(SoldbError::Message("Invalid uint value: empty".to_owned()));
557 }
558
559 if let Some(hex) = value.strip_prefix("0x") {
560 if hex.is_empty() || hex.len() > 64 || !hex.bytes().all(|byte| byte.is_ascii_hexdigit()) {
561 return Err(SoldbError::Message(format!("Invalid uint value: {value}")));
562 }
563 return Ok(format!("{:0>64}", hex.to_ascii_lowercase()));
564 }
565
566 if !value.bytes().all(|byte| byte.is_ascii_digit()) {
567 return Err(SoldbError::Message(format!("Invalid uint value: {value}")));
568 }
569
570 let mut bytes = [0_u8; 32];
571 for digit in value.bytes().map(|byte| byte - b'0') {
572 let mut carry = u16::from(digit);
573 for byte in bytes.iter_mut().rev() {
574 let next = u16::from(*byte) * 10 + carry;
575 *byte = (next & 0xff) as u8;
576 carry = next >> 8;
577 }
578 if carry != 0 {
579 return Err(SoldbError::Message(format!(
580 "Uint value exceeds 256 bits: {value}"
581 )));
582 }
583 }
584 Ok(bytes_to_hex(&bytes))
585}
586
587fn validate_uint_fits_bits(encoded_word: &str, bits: u16, value: &str) -> SoldbResult<()> {
588 let unused_hex_digits = usize::from(256 - bits) / 4;
589 if encoded_word[..unused_hex_digits]
590 .bytes()
591 .any(|byte| byte != b'0')
592 {
593 return Err(SoldbError::Message(format!(
594 "Uint value does not fit uint{bits}: {value}"
595 )));
596 }
597 Ok(())
598}
599
600fn bytes_to_hex(bytes: &[u8]) -> String {
601 bytes.iter().map(|byte| format!("{byte:02x}")).collect()
602}
603
604fn absorb_block(state: &mut [u64; 25], block: &[u8]) {
605 for (lane, chunk) in block.as_chunks::<8>().0.iter().enumerate() {
606 state[lane] ^= u64::from_le_bytes(*chunk);
607 }
608}
609
610fn keccak_f1600(state: &mut [u64; 25]) {
611 const RHO: [u32; 25] = [
612 0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56,
613 14,
614 ];
615 const RC: [u64; 24] = [
616 0x0000_0000_0000_0001,
617 0x0000_0000_0000_8082,
618 0x8000_0000_0000_808a,
619 0x8000_0000_8000_8000,
620 0x0000_0000_0000_808b,
621 0x0000_0000_8000_0001,
622 0x8000_0000_8000_8081,
623 0x8000_0000_0000_8009,
624 0x0000_0000_0000_008a,
625 0x0000_0000_0000_0088,
626 0x0000_0000_8000_8009,
627 0x0000_0000_8000_000a,
628 0x0000_0000_8000_808b,
629 0x8000_0000_0000_008b,
630 0x8000_0000_0000_8089,
631 0x8000_0000_0000_8003,
632 0x8000_0000_0000_8002,
633 0x8000_0000_0000_0080,
634 0x0000_0000_0000_800a,
635 0x8000_0000_8000_000a,
636 0x8000_0000_8000_8081,
637 0x8000_0000_0000_8080,
638 0x0000_0000_8000_0001,
639 0x8000_0000_8000_8008,
640 ];
641
642 for round_constant in RC {
643 let mut c = [0_u64; 5];
644 for x in 0..5 {
645 c[x] = state[x] ^ state[x + 5] ^ state[x + 10] ^ state[x + 15] ^ state[x + 20];
646 }
647
648 let mut d = [0_u64; 5];
649 for x in 0..5 {
650 d[x] = c[(x + 4) % 5] ^ c[(x + 1) % 5].rotate_left(1);
651 }
652 for y in 0..5 {
653 for x in 0..5 {
654 state[x + 5 * y] ^= d[x];
655 }
656 }
657
658 let mut b = [0_u64; 25];
659 for y in 0..5 {
660 for x in 0..5 {
661 let index = x + 5 * y;
662 b[y + 5 * ((2 * x + 3 * y) % 5)] = state[index].rotate_left(RHO[index]);
663 }
664 }
665
666 for y in 0..5 {
667 for x in 0..5 {
668 state[x + 5 * y] =
669 b[x + 5 * y] ^ ((!b[((x + 1) % 5) + 5 * y]) & b[((x + 2) % 5) + 5 * y]);
670 }
671 }
672
673 state[0] ^= round_constant;
674 }
675}
676
677#[cfg(test)]
678mod tests {
679 use super::{
680 canonical_abi_input_type, encode_abi_arguments, encode_function_call, function_selector,
681 keccak256, match_abi_types, match_single_type, parse_signature, parse_tuple_arg, AbiInput,
682 };
683 use serde_json::json;
684
685 #[test]
686 fn parses_nested_function_signatures() {
687 let signature = parse_signature("foo((uint256,address),uint8[])").expect("valid");
688 assert_eq!(signature.name, "foo");
689 assert_eq!(signature.arg_types, ["(uint256,address)", "uint8[]"]);
690
691 let noop = parse_signature("noop()").expect("valid");
692 assert_eq!(noop.name, "noop");
693 assert!(noop.arg_types.is_empty());
694
695 assert!(parse_signature("not a signature").is_none());
696 assert!(parse_signature("broken(uint256").is_none());
697 }
698
699 #[test]
700 fn matches_tuple_and_array_types() {
701 let parsed = vec![
702 "uint256".to_owned(),
703 "(address,uint256)".to_owned(),
704 "uint256[]".to_owned(),
705 ];
706 let abi = vec![
707 "uint256".to_owned(),
708 "tuple".to_owned(),
709 "uint256[]".to_owned(),
710 ];
711
712 assert!(match_abi_types(&parsed, &abi));
713 assert!(match_single_type("tuple(uint256)", "tuple"));
714 assert!(!match_single_type("uint8[]", "uint256[]"));
715 assert!(!match_abi_types(&["uint256".to_owned()], &abi));
716 }
717
718 #[test]
719 fn parses_tuple_arguments_recursively() {
720 let abi_input: AbiInput = serde_json::from_value(json!({
721 "type": "tuple",
722 "components": [
723 {"type": "uint256"},
724 {"type": "tuple", "components": [{"type": "address"}]},
725 {"type": "tuple[]", "components": [{"type": "uint256"}]}
726 ]
727 }))
728 .expect("abi input");
729
730 let parsed =
731 parse_tuple_arg(&json!([1, ["0xabc"], [[2], [3]]]), &abi_input).expect("tuple parses");
732 assert_eq!(parsed, json!([1, ["0xabc"], [[2], [3]]]));
733
734 assert!(parse_tuple_arg(&json!("bad"), &abi_input).is_err());
735 }
736
737 #[test]
738 fn canonicalizes_tuple_abi_input_types() {
739 let abi_input: AbiInput = serde_json::from_value(json!({
740 "type": "tuple[]",
741 "components": [
742 {"type": "uint256"},
743 {"type": "tuple", "components": [{"type": "address"}]}
744 ]
745 }))
746 .expect("abi input");
747
748 assert_eq!(
749 canonical_abi_input_type(&abi_input),
750 "(uint256,(address))[]"
751 );
752 }
753
754 #[test]
755 fn computes_ethereum_keccak256_selectors() {
756 assert_eq!(
757 hex(keccak256(b"").as_ref()),
758 "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
759 );
760 assert_eq!(
761 hex(function_selector("transfer(address,uint256)")
762 .expect("selector")
763 .as_ref()),
764 "a9059cbb"
765 );
766 assert_eq!(
767 hex(function_selector("increment(uint256)")
768 .expect("selector")
769 .as_ref()),
770 "7cf5dab0"
771 );
772 }
773
774 #[test]
775 fn hashes_inputs_spanning_the_keccak_rate() {
776 fn pattern(len: usize) -> Vec<u8> {
781 (0..len)
782 .map(|index| u8::try_from((index * 7 + 3) % 256).expect("value fits a byte"))
783 .collect()
784 }
785
786 for (len, expected) in [
787 (
788 135,
789 "00ef96af9cf4b24c7f269d922294444a197d0a33638c2e56634c57e892103a8f",
790 ),
791 (
792 136,
793 "742061bcad767ed4c4f5883b1dcb1aad11afdcc140dc469d953759b127b9f9ed",
794 ),
795 (
796 137,
797 "e3371f61e770abf254c34239c3b0099ad90594507415bc81dd0a10b9692bbf2a",
798 ),
799 (
800 272,
801 "ac141fd7b0a0ffcd2e967254d508da3ec616596493c36fa304425647d90e6de5",
802 ),
803 (
804 300,
805 "fa75f2293be9f9a14dcdeeff53f7b91ff6a2b1331b13886e69077ab1cf8252a9",
806 ),
807 ] {
808 assert_eq!(
809 hex(keccak256(&pattern(len)).as_ref()),
810 expected,
811 "len {len}"
812 );
813 }
814 }
815
816 #[test]
817 fn encodes_static_function_calls() {
818 assert_eq!(
819 encode_function_call("increment(uint256)", &["4".to_owned()]).expect("calldata"),
820 "0x7cf5dab00000000000000000000000000000000000000000000000000000000000000004"
821 );
822 assert_eq!(
823 encode_function_call(
824 "transfer(address,uint256)",
825 &[
826 "0x0000000000000000000000000000000000000002".to_owned(),
827 "0x2a".to_owned(),
828 ],
829 )
830 .expect("calldata"),
831 "0xa9059cbb0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002a"
832 );
833 assert_eq!(
834 encode_function_call(
835 "set(uint256)",
836 &["1606938044258990275541962092341162602522202993782792835301376".to_owned()],
837 )
838 .expect("calldata"),
839 "0x60fe47b10000000000000100000000000000000000000000000000000000000000000000"
840 );
841 }
842
843 #[test]
844 fn encodes_dynamic_function_calls() {
845 let selector = hex(function_selector("set(string)").expect("selector").as_ref());
846 assert_eq!(
847 encode_function_call("set(string)", &["hi".to_owned()]).expect("calldata"),
848 format!(
849 "0x{selector}\
850 0000000000000000000000000000000000000000000000000000000000000020\
851 0000000000000000000000000000000000000000000000000000000000000002\
852 6869{}",
853 "0".repeat(60)
854 )
855 );
856
857 let selector = hex(function_selector("processOrder(uint256,string,string)")
858 .expect("selector")
859 .as_ref());
860 assert_eq!(
861 encode_function_call(
862 "processOrder(uint256,string,string)",
863 &[
864 "10".to_owned(),
865 "express".to_owned(),
866 "electronic".to_owned()
867 ],
868 )
869 .expect("calldata"),
870 format!(
871 "0x{selector}\
872 000000000000000000000000000000000000000000000000000000000000000a\
873 0000000000000000000000000000000000000000000000000000000000000060\
874 00000000000000000000000000000000000000000000000000000000000000a0\
875 0000000000000000000000000000000000000000000000000000000000000007\
876 65787072657373{}\
877 000000000000000000000000000000000000000000000000000000000000000a\
878 656c656374726f6e6963{}",
879 "0".repeat(50),
880 "0".repeat(44)
881 )
882 );
883
884 let selector = hex(function_selector("set(bytes)").expect("selector").as_ref());
885 assert_eq!(
886 encode_function_call("set(bytes)", &["0xabcd".to_owned()]).expect("calldata"),
887 format!(
888 "0x{selector}\
889 0000000000000000000000000000000000000000000000000000000000000020\
890 0000000000000000000000000000000000000000000000000000000000000002\
891 abcd{}",
892 "0".repeat(60)
893 )
894 );
895 }
896
897 #[test]
898 fn encodes_fixed_bytes_function_calls() {
899 let selector = hex(function_selector("set(bytes2)").expect("selector").as_ref());
900 assert_eq!(
901 encode_function_call("set(bytes2)", &["0xabcd".to_owned()]).expect("calldata"),
902 format!("0x{selector}abcd{}", "0".repeat(60))
903 );
904 }
905
906 #[test]
907 fn encodes_abi_argument_payload_without_selector() {
908 let arg_types = vec!["uint256".to_owned(), "string".to_owned()];
909 let args = vec!["7".to_owned(), "hi".to_owned()];
910
911 assert_eq!(
912 encode_abi_arguments(&arg_types, &args).expect("payload"),
913 format!(
914 "\
915 0000000000000000000000000000000000000000000000000000000000000007\
916 0000000000000000000000000000000000000000000000000000000000000040\
917 0000000000000000000000000000000000000000000000000000000000000002\
918 6869{}",
919 "0".repeat(60)
920 )
921 );
922 }
923
924 #[test]
925 fn encodes_dynamic_array_function_calls() {
926 assert_eq!(
927 encode_function_call("set(uint256[])", &["[1,2,3]".to_owned()]).expect("calldata"),
928 "0x6ea9bfc500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003"
929 );
930
931 assert_eq!(
932 encode_function_call("set(string[])", &["[\"a\",\"bb\"]".to_owned()])
933 .expect("calldata"),
934 "0x52e66db800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000026262000000000000000000000000000000000000000000000000000000000000"
935 );
936
937 assert_eq!(
938 encode_function_call(
939 "mix(uint256[],string)",
940 &["[1,2]".to_owned(), "ok".to_owned()],
941 )
942 .expect("calldata"),
943 "0xb613ef8d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026f6b000000000000000000000000000000000000000000000000000000000000"
944 );
945 }
946
947 #[test]
948 fn encodes_fixed_array_and_tuple_function_calls() {
949 assert_eq!(
950 encode_function_call("set(uint256[3])", &["[1,2,3]".to_owned()]).expect("calldata"),
951 "0xcf1d72d1000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003"
952 );
953
954 assert_eq!(
955 encode_function_call(
956 "mix(uint256[2],string)",
957 &["[1,2]".to_owned(), "ok".to_owned()],
958 )
959 .expect("calldata"),
960 "0x48ec1f2c00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000026f6b000000000000000000000000000000000000000000000000000000000000"
961 );
962
963 assert_eq!(
964 encode_function_call(
965 "set((uint256,address))",
966 &["[5,\"0x0000000000000000000000000000000000000002\"]".to_owned()],
967 )
968 .expect("calldata"),
969 "0x0193c8b800000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000002"
970 );
971
972 assert_eq!(
973 encode_function_call("set((uint256,string))", &["[5,\"hi\"]".to_owned()])
974 .expect("calldata"),
975 "0xa16fc8d400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000026869000000000000000000000000000000000000000000000000000000000000"
976 );
977
978 assert_eq!(
979 encode_function_call("set(string[2])", &["[\"a\",\"bb\"]".to_owned()])
980 .expect("calldata"),
981 "0x74d379540000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000026262000000000000000000000000000000000000000000000000000000000000"
982 );
983 }
984
985 #[test]
986 fn rejects_unsupported_or_invalid_encoding() {
987 assert!(encode_function_call("set(uint256)", &[]).is_err());
988 assert!(encode_function_call("set(uint8)", &["256".to_owned()]).is_err());
989 assert!(encode_function_call("set(address)", &["0x1".to_owned()]).is_err());
990 assert!(encode_function_call("set(bool)", &["maybe".to_owned()]).is_err());
991 assert!(encode_function_call("set(bytes)", &["0xabc".to_owned()]).is_err());
992 assert!(encode_function_call("set(bytes)", &["0xzz".to_owned()]).is_err());
993 assert!(encode_function_call("set(bytes2)", &["0xab".to_owned()]).is_err());
994 assert!(encode_function_call("set(bytes33)", &["0xab".to_owned()]).is_err());
995 assert!(encode_function_call("set(uint256[])", &["1,2".to_owned()]).is_err());
996 assert!(encode_function_call("set(address[])", &["[\"0x1\"]".to_owned()]).is_err());
997 assert!(encode_function_call("set(uint256[2])", &["[1]".to_owned()]).is_err());
998 assert!(encode_function_call("set((uint256,bool))", &["[1]".to_owned()]).is_err());
999 }
1000
1001 fn hex(bytes: &[u8]) -> String {
1002 bytes.iter().map(|byte| format!("{byte:02x}")).collect()
1003 }
1004}