ethers_core/abi/
packed.rs

1use ethabi::Token;
2use thiserror::Error;
3use Token::*;
4
5/// An error thrown by [`encode_packed`].
6#[derive(Debug, Error)]
7pub enum EncodePackedError {
8    #[error("This token cannot be encoded in packed mode: {0:?}")]
9    InvalidToken(Token),
10
11    #[error("FixedBytes token length > 32")]
12    InvalidBytesLength,
13}
14
15/// Encodes the given tokens into an ABI compliant vector of bytes.
16///
17/// This function uses [non-standard packed mode][ref], where:
18/// - types shorter than 32 bytes are concatenated directly, without padding or sign extension;
19/// - dynamic types are encoded in-place and without the length;
20/// - array elements are padded, but still encoded in-place.
21///
22/// Since this encoding is ambiguous, there is no decoding function.
23///
24/// Note that this function has the same behaviour as its [Solidity counterpart][ref], and
25/// thus structs as well as nested arrays are not supported.
26///
27/// `Uint` and `Int` tokens will be encoded using the least number of bits, so no padding will be
28/// added by default.
29///
30/// [ref]: https://docs.soliditylang.org/en/latest/abi-spec.html#non-standard-packed-mode
31///
32/// # Examples
33///
34/// Calculate the UniswapV2 pair address for two ERC20 tokens:
35///
36/// ```
37/// # use ethers_core::abi::{self, Token};
38/// # use ethers_core::types::{Address, H256};
39/// # use ethers_core::utils;
40/// let factory: Address = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f".parse()?;
41///
42/// let token_a: Address = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48".parse()?;
43/// let token_b: Address = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2".parse()?;
44/// let encoded = abi::encode_packed(&[Token::Address(token_a), Token::Address(token_b)])?;
45/// let salt = utils::keccak256(encoded);
46///
47/// let init_code_hash: H256 = "0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f".parse()?;
48///
49/// let pair = utils::get_create2_address_from_hash(factory, salt, init_code_hash);
50/// let weth_usdc = "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc".parse()?;
51/// assert_eq!(pair, weth_usdc);
52/// # Ok::<(), Box<dyn std::error::Error>>(())
53/// ```
54pub fn encode_packed(tokens: &[Token]) -> Result<Vec<u8>, EncodePackedError> {
55    // Get vec capacity and find invalid tokens
56    let mut max = 0;
57    for token in tokens {
58        check(token)?;
59        max += max_encoded_length(token);
60    }
61
62    // Encode the tokens
63    let mut bytes = Vec::with_capacity(max);
64    for token in tokens {
65        encode_token(token, &mut bytes, false);
66    }
67    Ok(bytes)
68}
69
70/// The maximum byte length of the token encoded using packed mode.
71fn max_encoded_length(token: &Token) -> usize {
72    match token {
73        Int(_) | Uint(_) | FixedBytes(_) => 32,
74        Address(_) => 20,
75        Bool(_) => 1,
76        // account for padding
77        Array(vec) | FixedArray(vec) | Tuple(vec) => {
78            vec.iter().map(|token| max_encoded_length(token).max(32)).sum()
79        }
80        Bytes(b) => b.len(),
81        String(s) => s.len(),
82    }
83}
84
85/// Tuples and nested arrays are invalid in packed encoding.
86fn check(token: &Token) -> Result<(), EncodePackedError> {
87    match token {
88        FixedBytes(vec) if vec.len() > 32 => Err(EncodePackedError::InvalidBytesLength),
89
90        Tuple(_) => Err(EncodePackedError::InvalidToken(token.clone())),
91        Array(vec) | FixedArray(vec) => {
92            for t in vec.iter() {
93                if t.is_dynamic() || matches!(t, Array(_)) {
94                    return Err(EncodePackedError::InvalidToken(token.clone()))
95                }
96                check(t)?;
97            }
98            Ok(())
99        }
100
101        _ => Ok(()),
102    }
103}
104
105/// Encodes `token` as bytes into `out`.
106fn encode_token(token: &Token, out: &mut Vec<u8>, in_array: bool) {
107    match token {
108        // Padded to 32 bytes if in_array
109        Address(addr) => {
110            if in_array {
111                out.extend_from_slice(&[0; 12]);
112            }
113            out.extend_from_slice(&addr.0)
114        }
115        Int(n) | Uint(n) => {
116            let mut buf = [0; 32];
117            n.to_big_endian(&mut buf);
118            let start = if in_array { 0 } else { 32 - ((n.bits() + 7) / 8) };
119            out.extend_from_slice(&buf[start..32]);
120        }
121        Bool(b) => {
122            if in_array {
123                out.extend_from_slice(&[0; 31]);
124            }
125            out.push((*b) as u8);
126        }
127        FixedBytes(bytes) => {
128            out.extend_from_slice(bytes);
129            if in_array {
130                let mut remaining = vec![0; 32 - bytes.len()];
131                out.append(&mut remaining);
132            }
133        }
134
135        // Encode dynamic types in-place, without their length
136        Bytes(bytes) => out.extend_from_slice(bytes),
137        String(s) => out.extend_from_slice(s.as_bytes()),
138        Array(vec) | FixedArray(vec) => {
139            for token in vec {
140                encode_token(token, out, true);
141            }
142        }
143
144        // Should never happen
145        token => unreachable!("Uncaught invalid token: {token:?}"),
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152    use hex_literal::hex;
153
154    fn encode(tokens: &[Token]) -> Vec<u8> {
155        encode_packed(tokens).unwrap()
156    }
157
158    fn string(s: &str) -> Token {
159        Token::String(s.into())
160    }
161
162    fn bytes(b: &[u8]) -> Token {
163        Token::Bytes(b.into())
164    }
165
166    #[test]
167    fn encode_bytes0() {
168        let expected = b"hello world";
169        assert_eq!(encode_packed(&[string("hello world")]).unwrap(), expected);
170        assert_eq!(encode_packed(&[bytes(b"hello world")]).unwrap(), expected);
171        assert_eq!(
172            encode_packed(&[string("hello"), string(" "), string("world")]).unwrap(),
173            expected
174        );
175        assert_eq!(
176            encode_packed(&[bytes(b"hello"), bytes(b" "), bytes(b"world")]).unwrap(),
177            expected
178        );
179    }
180
181    // modified from: ethabi::encoder::tests
182    // https://github.com/rust-ethereum/ethabi/blob/4e14ff83bf27de56555cc2ae0ece9ed2fe28fa0f/ethabi/src/encoder.rs#L181
183
184    #[test]
185    fn encode_address() {
186        let address = Token::Address([0x11u8; 20].into());
187        let encoded = encode(&[address]);
188        let expected = hex!("1111111111111111111111111111111111111111");
189        assert_eq!(encoded, expected);
190    }
191
192    #[test]
193    fn encode_dynamic_array_of_addresses() {
194        let address1 = Token::Address([0x11u8; 20].into());
195        let address2 = Token::Address([0x22u8; 20].into());
196        let addresses = Token::Array(vec![address1, address2]);
197        let encoded = encode(&[addresses]);
198        let expected = hex!(
199            "
200			0000000000000000000000001111111111111111111111111111111111111111
201			0000000000000000000000002222222222222222222222222222222222222222
202		"
203        )
204        .to_vec();
205        assert_eq!(encoded, expected);
206    }
207
208    #[test]
209    fn encode_fixed_array_of_addresses() {
210        let address1 = Token::Address([0x11u8; 20].into());
211        let address2 = Token::Address([0x22u8; 20].into());
212        let addresses = Token::FixedArray(vec![address1, address2]);
213        let encoded = encode(&[addresses]);
214        let expected = hex!(
215            "
216			0000000000000000000000001111111111111111111111111111111111111111
217			0000000000000000000000002222222222222222222222222222222222222222
218		"
219        )
220        .to_vec();
221        assert_eq!(encoded, expected);
222    }
223
224    #[test]
225    fn encode_two_addresses() {
226        let address1 = Token::Address([0x11u8; 20].into());
227        let address2 = Token::Address([0x22u8; 20].into());
228        let encoded = encode(&[address1, address2]);
229        let expected = hex!(
230            "
231			1111111111111111111111111111111111111111
232			2222222222222222222222222222222222222222
233		"
234        )
235        .to_vec();
236        assert_eq!(encoded, expected);
237    }
238
239    #[test]
240    fn encode_empty_array() {
241        let encoded = encode(&[Token::Array(vec![]), Token::Array(vec![])]);
242        assert_eq!(encoded, b"");
243    }
244
245    #[test]
246    fn encode_bytes() {
247        let bytes = Token::Bytes(hex!("1234").to_vec());
248        let encoded = encode(&[bytes]);
249        let expected = hex!("1234");
250        assert_eq!(encoded, expected);
251    }
252
253    #[test]
254    fn encode_bytes2() {
255        let bytes = Token::Bytes(
256            hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec(),
257        );
258        let encoded = encode(&[bytes]);
259        let expected =
260            hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec();
261        assert_eq!(encoded, expected);
262    }
263
264    #[test]
265    fn encode_bytes3() {
266        let bytes = Token::Bytes(
267            hex!(
268                "
269                    1000000000000000000000000000000000000000000000000000000000000000
270                    1000000000000000000000000000000000000000000000000000000000000000
271		        "
272            )
273            .to_vec(),
274        );
275        let encoded = encode(&[bytes]);
276        let expected = hex!(
277            "
278            1000000000000000000000000000000000000000000000000000000000000000
279            1000000000000000000000000000000000000000000000000000000000000000
280		    "
281        )
282        .to_vec();
283        assert_eq!(encoded, expected);
284    }
285
286    #[test]
287    fn encode_string() {
288        let s = Token::String("gavofyork".to_owned());
289        let encoded = encode(&[s]);
290        assert_eq!(encoded, b"gavofyork");
291    }
292
293    #[test]
294    fn encode_two_bytes() {
295        let bytes1 = Token::Bytes(
296            hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec(),
297        );
298        let bytes2 = Token::Bytes(
299            hex!("0010000000000000000000000000000000000000000000000000000000000002").to_vec(),
300        );
301        let encoded = encode(&[bytes1, bytes2]);
302        let expected = hex!(
303            "
304			10000000000000000000000000000000000000000000000000000000000002
305			0010000000000000000000000000000000000000000000000000000000000002
306		"
307        )
308        .to_vec();
309        assert_eq!(encoded, expected);
310    }
311
312    #[test]
313    fn encode_fixed_bytes() {
314        let bytes = Token::FixedBytes(vec![0x12, 0x34]);
315        let encoded = encode(&[bytes]);
316        let expected = hex!("1234");
317        assert_eq!(encoded, expected);
318    }
319
320    #[test]
321    fn encode_array_of_fixed_bytes() {
322        let array = Token::FixedArray(vec![
323            Token::FixedBytes(vec![0x12, 0x34]),
324            Token::FixedBytes(vec![0x56, 0x78]),
325        ]);
326        let encoded = encode(&[array]);
327        let expected = hex!(
328            "
329            1234000000000000000000000000000000000000000000000000000000000000
330            5678000000000000000000000000000000000000000000000000000000000000
331        "
332        );
333        assert_eq!(encoded, expected);
334    }
335
336    #[test]
337    fn encode_uint() {
338        let mut uint = [0u8; 32];
339        uint[31] = 4;
340        let encoded = encode(&[Token::Uint(uint.into())]);
341        let expected = hex!("04");
342        assert_eq!(encoded, expected);
343    }
344
345    #[test]
346    fn encode_int() {
347        let mut int = [0u8; 32];
348        int[31] = 4;
349        let encoded = encode(&[Token::Int(int.into())]);
350        let expected = hex!("04");
351        assert_eq!(encoded, expected);
352    }
353
354    #[test]
355    fn encode_bool() {
356        let encoded = encode(&[Token::Bool(true)]);
357        let expected = hex!("01");
358        assert_eq!(encoded, expected);
359    }
360
361    #[test]
362    fn encode_bool2() {
363        let encoded = encode(&[Token::Bool(false)]);
364        let expected = hex!("00");
365        assert_eq!(encoded, expected);
366    }
367
368    #[test]
369    fn comprehensive_test() {
370        let bytes = hex!(
371            "
372			131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
373			131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
374		"
375        )
376        .to_vec();
377        let encoded = encode(&[
378            Token::Int(5.into()),
379            Token::Bytes(bytes.clone()),
380            Token::Int(3.into()),
381            Token::Bytes(bytes),
382        ]);
383
384        let expected = hex!(
385            "
386			05
387            131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
388			131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
389			03
390            131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
391			131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
392		"
393        )
394        .to_vec();
395        assert_eq!(encoded, expected);
396    }
397
398    #[test]
399    fn comprehensive_test2() {
400        let encoded = encode(&vec![
401            Token::Int(1.into()),
402            Token::String("gavofyork".to_owned()),
403            Token::Int(2.into()),
404            Token::Int(3.into()),
405            Token::Int(4.into()),
406            Token::Array(vec![Token::Int(5.into()), Token::Int(6.into()), Token::Int(7.into())]),
407        ]);
408
409        let expected = hex!(
410            "
411			01
412			6761766f66796f726b
413			02
414			03
415			04
416			0000000000000000000000000000000000000000000000000000000000000005
417			0000000000000000000000000000000000000000000000000000000000000006
418			0000000000000000000000000000000000000000000000000000000000000007
419		"
420        )
421        .to_vec();
422        assert_eq!(encoded, expected);
423    }
424}