alloy_encode_packed/
lib.rs1use alloy::primitives::{Address, U256};
2
3pub struct TakeLastXBytes(pub usize);
4
5pub enum SolidityDataType<'a> {
6 String(&'a str),
7 Address(Address),
8 Bytes(&'a [u8]),
9 Bool(bool),
10 Number(U256),
11 NumberWithShift(U256, TakeLastXBytes),
12}
13
14pub mod abi {
15 use super::SolidityDataType;
16
17 fn pack<'a>(data_type: &'a SolidityDataType) -> Vec<u8> {
19 let mut res = Vec::new();
20 match data_type {
21 SolidityDataType::String(s) => {
22 res.extend(s.as_bytes());
23 }
24 SolidityDataType::Address(a) => {
25 res.extend(a.0);
26 }
27 SolidityDataType::Number(n) => {
28 res.extend(n.to_be_bytes::<32>());
29 }
30 SolidityDataType::Bytes(b) => {
31 res.extend(*b);
32 }
33 SolidityDataType::Bool(b) => {
34 if *b {
35 res.push(1);
36 } else {
37 res.push(0);
38 }
39 }
40 SolidityDataType::NumberWithShift(n, to_take) => {
41 let local_res = n.to_be_bytes::<32>().to_vec();
42
43 let to_skip = local_res.len() - (to_take.0 / 8);
44 let local_res = local_res.into_iter().skip(to_skip).collect::<Vec<u8>>();
45 res.extend(local_res);
46 }
47 };
48 return res;
49 }
50
51 pub fn encode_packed(items: &[SolidityDataType]) -> (Vec<u8>, String) {
52 let res = items.iter().fold(Vec::new(), |mut acc, i| {
53 let pack = pack(i);
54 acc.push(pack);
55 acc
56 });
57 let res = res.join(&[][..]);
58 let hexed = hex::encode(&res);
59 (res, hexed)
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use std::convert::TryInto;
66
67 use super::*;
68
69 #[test]
70 fn test_normal_use_case() {
71 let address = hex::decode("d8b934580fcE35a11B58C6D73aDeE468a2833fa8").unwrap();
72 let address: [u8; 20] = address.try_into().unwrap();
73 let input = vec![
74 SolidityDataType::NumberWithShift(U256::from(3838), TakeLastXBytes(24)),
75 SolidityDataType::Number(U256::from(4001)),
76 SolidityDataType::String("this-is-a-sample-string"),
77 SolidityDataType::Address(Address::from(address)),
78 SolidityDataType::Number(U256::from(1)),
79 ];
80 let (_bytes, hash) = abi::encode_packed(&input);
81 let hash = format!("0x{:}", hash);
82 let expected = "0x000efe0000000000000000000000000000000000000000000000000000000000000fa1746869732d69732d612d73616d706c652d737472696e67d8b934580fce35a11b58c6d73adee468a2833fa80000000000000000000000000000000000000000000000000000000000000001";
83 assert_eq!(hash, expected);
84 }
85
86 #[test]
87 fn test_uint24() {
88 let input = vec![SolidityDataType::NumberWithShift(
89 U256::from(4001),
90 TakeLastXBytes(24),
91 )];
92 let (_bytes, hash) = abi::encode_packed(&input);
93 let hash = format!("0x{:}", hash);
94 let expected = "0x000fa1";
95 assert_eq!(hash, expected);
96 }
97
98 #[test]
99 fn test_uint256() {
100 let input = vec![SolidityDataType::Number(U256::from(3838110))];
101 let (_bytes, hash) = abi::encode_packed(&input);
102 let hash = format!("0x{:}", hash);
103 let expected = "0x00000000000000000000000000000000000000000000000000000000003a909e";
104 assert_eq!(hash, expected);
105 }
106
107 #[test]
108 fn test_string() {
109 let input = vec![SolidityDataType::String("this-is-a-sample-string")];
110 let (_bytes, hash) = abi::encode_packed(&input);
111 let hash = format!("0x{:}", hash);
112 let expected = "0x746869732d69732d612d73616d706c652d737472696e67";
113 assert_eq!(hash, expected);
114 }
115
116 #[test]
117 fn test_address() {
118 let address = hex::decode("d8b934580fcE35a11B58C6D73aDeE468a2833fa8").unwrap();
119 let address: [u8; 20] = address.try_into().unwrap();
120 let input = vec![SolidityDataType::Address(Address::from(address))];
121 let (_bytes, hash) = abi::encode_packed(&input);
122 let hash = format!("0x{:}", hash);
123 let expected = "0xd8b934580fce35a11b58c6d73adee468a2833fa8";
124 assert_eq!(hash, expected);
125 }
126
127 #[test]
128 fn test_bool() {
129 let input = vec![SolidityDataType::Bool(false)];
130 let (_bytes, hash) = abi::encode_packed(&input);
131 let hash = format!("0x{:}", hash);
132 let expected = "0x00";
133 assert_eq!(hash, expected);
134 }
135 #[test]
136 fn test_normal_bytes() {
137 let bytes = "abababababababababababababababababababababababababababababab";
138 let bytes = hex::decode(bytes).unwrap();
139 let bytes: [u8; 30] = bytes.try_into().unwrap();
140
141 let input = vec![SolidityDataType::Bytes(&bytes)];
142 let (_bytes, hash) = abi::encode_packed(&input);
143 let hash = format!("0x{:}", hash);
144 let expected = "0xabababababababababababababababababababababababababababababab";
145 assert_eq!(hash, expected);
146 }
147}