api3_common/abi/
mod.rs

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
12/// Rust implementation of solidity abi.encodePacked(...)
13pub 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
24/// Pack a single `Token` into bytes
25fn 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}