1mod decode;
2mod encode;
3mod types;
4
5use tiny_keccak::{Hasher, Keccak};
6
7pub use crate::abi::decode::*;
8pub use crate::abi::encode::*;
9pub use crate::abi::types::{Address, FixedBytes, Int, ParamType, Token, Uint, Word, U256};
10use crate::{Bytes, Bytes32};
11
12pub fn encode_packed(items: &[Token]) -> (Bytes, String) {
14 let res = items.iter().fold(Vec::new(), |mut acc, i| {
15 let pack = pack(i);
16 acc.push(pack);
17 acc
18 });
19 let res = res.join(&[][..]);
20 let hexed = hex::encode(&res);
21 (res, hexed)
22}
23
24fn pack(t: &Token) -> Vec<u8> {
26 let mut res = Vec::new();
27 match t {
28 Token::String(s) => res.extend(s.as_bytes()),
29 Token::Address(a) => res.extend(a),
30 Token::Uint(n) => {
31 let mut v = vec![0u8; 32];
32 n.to_big_endian(&mut v);
33 res.extend(v);
34 }
35 Token::Int(n) => {
36 let mut v = vec![0u8; 32];
37 n.to_big_endian(&mut v);
38 res.extend(v);
39 }
40 Token::Bytes(b) | Token::FixedBytes(b) => res.extend(b),
41 };
42 res
43}
44
45pub fn keccak256(x: &[u8]) -> Bytes32 {
46 let mut keccak = Keccak::v256();
47 keccak.update(x);
48 let mut out = [0u8; 32];
49 keccak.finalize(&mut out);
50 out
51}
52
53pub fn to_eth_signed_message_hash(s: &[u8]) -> Bytes32 {
54 let (bytes, _) = encode_packed(&[
55 Token::String("\x19Ethereum Signed Message:\n".parse().unwrap()),
56 Token::String(s.len().to_string()),
57 Token::Bytes(s.to_vec()),
58 ]);
59 keccak256(&bytes)
60}
61
62#[cfg(test)]
63mod tests {
64 use crate::abi::{encode_packed, keccak256, to_eth_signed_message_hash, Token};
65 use crate::abi::{Address, Uint};
66 use hex_literal::hex;
67
68 #[test]
69 fn encode_packed_works() {
70 let (_, hex_str) = encode_packed(&[Token::String("hello_world".parse().unwrap())]);
71 assert_eq!(hex_str, "68656c6c6f5f776f726c64");
72
73 let mut u256 = [0u8; 32];
74 u256[0] = 8;
75 u256[1] = 10;
76 let (_, hex_str) = encode_packed(&[Token::Uint(Uint::from(u256))]);
77 assert_eq!(
78 hex_str,
79 "080a000000000000000000000000000000000000000000000000000000000000"
80 );
81
82 let mut h160 = [0u8; 20];
83 h160.copy_from_slice(&hex::decode("85B0c8b91707B68C0B23388001B9dC7aab3f6A81").unwrap());
84 let (_, hex_str) = encode_packed(&[
85 Token::String("hello_world".parse().unwrap()),
86 Token::Address(Address::from(h160)),
87 ]);
88 assert_eq!(
89 hex_str,
90 "68656c6c6f5f776f726c6485b0c8b91707b68c0b23388001b9dc7aab3f6a81"
91 );
92 }
93
94 #[test]
95 fn keccak_works() {
96 let bytes = keccak256(&vec![1, 2, 3]);
97 assert_eq!(
98 hex::encode(bytes),
99 "f1885eda54b7a053318cd41e2093220dab15d65381b1157a3633a83bfd5c9239"
100 );
101 }
102
103 #[test]
104 fn more_complex_test() {
105 let mut bytes32 = vec![0; 32];
106 bytes32[0] = 8;
107 bytes32[1] = 10;
108
109 let mut bytes = vec![0; 36];
110 bytes[0] = 18;
111 bytes[1] = 120;
112
113 let p1 = Token::FixedBytes(bytes32);
114 let p2 = Token::Uint(Uint::from(100));
115 let p3 = Token::Bytes(bytes);
116
117 let (b, _) = encode_packed(&[p1, p2, p3]);
118 assert_eq!(b, hex!("080a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064127800000000000000000000000000000000000000000000000000000000000000000000"));
119 assert_eq!(
120 keccak256(&b),
121 hex!("f3f0d971e5307ceec7ca3d9b762780778c4efe8383f0e17015a2cf8ac8dbc179")
122 );
123 }
124
125 #[test]
126 fn to_eth_signed_message_hash_works() {
127 let mut bytes32 = vec![0; 32];
128 bytes32[0] = 8;
129 bytes32[1] = 10;
130
131 let mut bytes = vec![0; 36];
132 bytes[0] = 18;
133 bytes[1] = 120;
134
135 let p1 = Token::FixedBytes(bytes32);
136 let p2 = Token::Uint(Uint::from(100));
137 let p3 = Token::Bytes(bytes);
138
139 let (b, _) = encode_packed(&[p1, p2, p3]);
140 assert_eq!(b, hex!("080a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064127800000000000000000000000000000000000000000000000000000000000000000000"));
141
142 let b = keccak256(&b);
143 assert_eq!(
144 b,
145 hex!("f3f0d971e5307ceec7ca3d9b762780778c4efe8383f0e17015a2cf8ac8dbc179")
146 );
147
148 let b = to_eth_signed_message_hash(&b);
149 assert_eq!(
150 b,
151 hex!("ff0d3be602bd7ed7c0454766464e6a1a9130a63cd505e629ae133db5c3b9f149")
152 );
153 }
154}