1pub use ethabi; pub use hex; use ethabi::ethereum_types::{Address, U256};
5
6pub struct TakeLastXBytes(pub usize);
7
8pub enum SolidityDataType<'a> {
27 String(&'a str),
28 Address(Address),
29 Bytes(&'a [u8]),
30 Bool(bool),
31 Number(U256),
32 NumberWithShift(U256, TakeLastXBytes),
33}
34
35pub mod abi {
36
37 use crate::SolidityDataType;
38
39 fn pack<'a>(data_type: &'a SolidityDataType) -> Vec<u8> {
41 let mut res = Vec::new();
42 match data_type {
43 SolidityDataType::String(s) => {
44 res.extend(s.as_bytes());
45 }
46 SolidityDataType::Address(a) => {
47 res.extend(a.0);
48 }
49 SolidityDataType::Number(n) => {
50 for b in n.0.iter().rev() {
51 let bytes = b.to_be_bytes();
52 res.extend(bytes);
53 }
54 }
55 SolidityDataType::Bytes(b) => {
56 res.extend(*b);
57 }
58 SolidityDataType::Bool(b) => {
59 if *b {
60 res.push(1);
61 } else {
62 res.push(0);
63 }
64 }
65 SolidityDataType::NumberWithShift(n, to_take) => {
66 let local_res = n.0.iter().rev().fold(vec![], |mut acc, i| {
67 let bytes = i.to_be_bytes();
68 acc.extend(bytes);
69 acc
70 });
71
72 let to_skip = local_res.len() - (to_take.0 / 8);
73 let local_res = local_res.into_iter().skip(to_skip).collect::<Vec<u8>>();
74 res.extend(local_res);
75 }
76 };
77 return res;
78 }
79
80
81 pub fn encode_packed(items: &[SolidityDataType]) -> (Vec<u8>, String) {
104 let res = items.iter().fold(Vec::new(), |mut acc, i| {
105 let pack = pack(i);
106 acc.push(pack);
107 acc
108 });
109 let res = res.join(&[][..]);
110 let hexed = hex::encode(&res);
111 (res, hexed)
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use std::convert::TryInto;
118
119 use super::*;
120
121 #[test]
122 fn test_normal_use_case() {
123 let address = hex::decode("d8b934580fcE35a11B58C6D73aDeE468a2833fa8").unwrap();
124 let address: [u8; 20] = address.try_into().unwrap();
125 let input = vec![
126 SolidityDataType::NumberWithShift(U256::from(3838), TakeLastXBytes(24)),
127 SolidityDataType::Number(U256::from(4001)),
128 SolidityDataType::String("this-is-a-sample-string"),
129 SolidityDataType::Address(Address::from(address)),
130 SolidityDataType::Number(U256::from(1)),
131 ];
132 let (_bytes, hash) = abi::encode_packed(&input);
133 let hash = format!("0x{:}", hash);
134 let expected = "0x000efe0000000000000000000000000000000000000000000000000000000000000fa1746869732d69732d612d73616d706c652d737472696e67d8b934580fce35a11b58c6d73adee468a2833fa80000000000000000000000000000000000000000000000000000000000000001";
135 assert_eq!(hash, expected);
136 }
137
138 #[test]
139 fn test_uint24() {
140 let input = vec![SolidityDataType::NumberWithShift(
141 U256::from(4001),
142 TakeLastXBytes(24),
143 )];
144 let (_bytes, hash) = abi::encode_packed(&input);
145 let hash = format!("0x{:}", hash);
146 let expected = "0x000fa1";
147 assert_eq!(hash, expected);
148 }
149
150 #[test]
151 fn test_uint256() {
152 let input = vec![SolidityDataType::Number(U256::from(3838110))];
153 let (_bytes, hash) = abi::encode_packed(&input);
154 let hash = format!("0x{:}", hash);
155 let expected = "0x00000000000000000000000000000000000000000000000000000000003a909e";
156 assert_eq!(hash, expected);
157 }
158
159 #[test]
160 fn test_string() {
161 let input = vec![SolidityDataType::String("this-is-a-sample-string")];
162 let (_bytes, hash) = abi::encode_packed(&input);
163 let hash = format!("0x{:}", hash);
164 let expected = "0x746869732d69732d612d73616d706c652d737472696e67";
165 assert_eq!(hash, expected);
166 }
167
168 #[test]
169 fn test_address() {
170 let address = hex::decode("d8b934580fcE35a11B58C6D73aDeE468a2833fa8").unwrap();
171 let address: [u8; 20] = address.try_into().unwrap();
172 let input = vec![SolidityDataType::Address(Address::from(address))];
173 let (_bytes, hash) = abi::encode_packed(&input);
174 let hash = format!("0x{:}", hash);
175 let expected = "0xd8b934580fce35a11b58c6d73adee468a2833fa8";
176 assert_eq!(hash, expected);
177 }
178
179 #[test]
180 fn test_bool() {
181 let input = vec![SolidityDataType::Bool(false)];
182 let (_bytes, hash) = abi::encode_packed(&input);
183 let hash = format!("0x{:}", hash);
184 let expected = "0x00";
185 assert_eq!(hash, expected);
186 }
187 #[test]
188 fn test_normal_bytes() {
189 let bytes = "abababababababababababababababababababababababababababababab";
190 let bytes = hex::decode(bytes).unwrap();
191 let bytes: [u8; 30] = bytes.try_into().unwrap();
192
193 let input = vec![SolidityDataType::Bytes(&bytes)];
194 let (_bytes, hash) = abi::encode_packed(&input);
195 let hash = format!("0x{:}", hash);
196 let expected = "0xabababababababababababababababababababababababababababababab";
197 assert_eq!(hash, expected);
198 }
199}