use ethabi::Token;
use thiserror::Error;
use Token::*;
#[derive(Debug, Error)]
pub enum EncodePackedError {
#[error("This token cannot be encoded in packed mode: {0:?}")]
InvalidToken(Token),
#[error("FixedBytes token length > 32")]
InvalidBytesLength,
}
pub fn encode_packed(tokens: &[Token]) -> Result<Vec<u8>, EncodePackedError> {
let mut max = 0;
for token in tokens {
check(token)?;
max += max_encoded_length(token);
}
let mut bytes = Vec::with_capacity(max);
for token in tokens {
encode_token(token, &mut bytes, false);
}
Ok(bytes)
}
fn max_encoded_length(token: &Token) -> usize {
match token {
Int(_) | Uint(_) | FixedBytes(_) => 32,
Address(_) => 20,
Bool(_) => 1,
Array(vec) | FixedArray(vec) | Tuple(vec) => {
vec.iter().map(|token| max_encoded_length(token).max(32)).sum()
}
Bytes(b) => b.len(),
String(s) => s.len(),
}
}
fn check(token: &Token) -> Result<(), EncodePackedError> {
match token {
FixedBytes(vec) if vec.len() > 32 => Err(EncodePackedError::InvalidBytesLength),
Tuple(_) => Err(EncodePackedError::InvalidToken(token.clone())),
Array(vec) | FixedArray(vec) => {
for t in vec.iter() {
if t.is_dynamic() || matches!(t, Array(_)) {
return Err(EncodePackedError::InvalidToken(token.clone()))
}
check(t)?;
}
Ok(())
}
_ => Ok(()),
}
}
fn encode_token(token: &Token, out: &mut Vec<u8>, in_array: bool) {
match token {
Address(addr) => {
if in_array {
out.extend_from_slice(&[0; 12]);
}
out.extend_from_slice(&addr.0)
}
Int(n) | Uint(n) => {
let mut buf = [0; 32];
n.to_big_endian(&mut buf);
let start = if in_array { 0 } else { 32 - ((n.bits() + 7) / 8) };
out.extend_from_slice(&buf[start..32]);
}
Bool(b) => {
if in_array {
out.extend_from_slice(&[0; 31]);
}
out.push((*b) as u8);
}
FixedBytes(bytes) => {
out.extend_from_slice(bytes);
if in_array {
let mut remaining = vec![0; 32 - bytes.len()];
out.append(&mut remaining);
}
}
Bytes(bytes) => out.extend_from_slice(bytes),
String(s) => out.extend_from_slice(s.as_bytes()),
Array(vec) | FixedArray(vec) => {
for token in vec {
encode_token(token, out, true);
}
}
token => unreachable!("Uncaught invalid token: {token:?}"),
}
}
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
fn encode(tokens: &[Token]) -> Vec<u8> {
encode_packed(tokens).unwrap()
}
fn string(s: &str) -> Token {
Token::String(s.into())
}
fn bytes(b: &[u8]) -> Token {
Token::Bytes(b.into())
}
#[test]
fn encode_bytes0() {
let expected = b"hello world";
assert_eq!(encode_packed(&[string("hello world")]).unwrap(), expected);
assert_eq!(encode_packed(&[bytes(b"hello world")]).unwrap(), expected);
assert_eq!(
encode_packed(&[string("hello"), string(" "), string("world")]).unwrap(),
expected
);
assert_eq!(
encode_packed(&[bytes(b"hello"), bytes(b" "), bytes(b"world")]).unwrap(),
expected
);
}
#[test]
fn encode_address() {
let address = Token::Address([0x11u8; 20].into());
let encoded = encode(&[address]);
let expected = hex!("1111111111111111111111111111111111111111");
assert_eq!(encoded, expected);
}
#[test]
fn encode_dynamic_array_of_addresses() {
let address1 = Token::Address([0x11u8; 20].into());
let address2 = Token::Address([0x22u8; 20].into());
let addresses = Token::Array(vec![address1, address2]);
let encoded = encode(&[addresses]);
let expected = hex!(
"
0000000000000000000000001111111111111111111111111111111111111111
0000000000000000000000002222222222222222222222222222222222222222
"
)
.to_vec();
assert_eq!(encoded, expected);
}
#[test]
fn encode_fixed_array_of_addresses() {
let address1 = Token::Address([0x11u8; 20].into());
let address2 = Token::Address([0x22u8; 20].into());
let addresses = Token::FixedArray(vec![address1, address2]);
let encoded = encode(&[addresses]);
let expected = hex!(
"
0000000000000000000000001111111111111111111111111111111111111111
0000000000000000000000002222222222222222222222222222222222222222
"
)
.to_vec();
assert_eq!(encoded, expected);
}
#[test]
fn encode_two_addresses() {
let address1 = Token::Address([0x11u8; 20].into());
let address2 = Token::Address([0x22u8; 20].into());
let encoded = encode(&[address1, address2]);
let expected = hex!(
"
1111111111111111111111111111111111111111
2222222222222222222222222222222222222222
"
)
.to_vec();
assert_eq!(encoded, expected);
}
#[test]
fn encode_empty_array() {
let encoded = encode(&[Token::Array(vec![]), Token::Array(vec![])]);
assert_eq!(encoded, b"");
}
#[test]
fn encode_bytes() {
let bytes = Token::Bytes(hex!("1234").to_vec());
let encoded = encode(&[bytes]);
let expected = hex!("1234");
assert_eq!(encoded, expected);
}
#[test]
fn encode_bytes2() {
let bytes = Token::Bytes(
hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec(),
);
let encoded = encode(&[bytes]);
let expected =
hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec();
assert_eq!(encoded, expected);
}
#[test]
fn encode_bytes3() {
let bytes = Token::Bytes(
hex!(
"
1000000000000000000000000000000000000000000000000000000000000000
1000000000000000000000000000000000000000000000000000000000000000
"
)
.to_vec(),
);
let encoded = encode(&[bytes]);
let expected = hex!(
"
1000000000000000000000000000000000000000000000000000000000000000
1000000000000000000000000000000000000000000000000000000000000000
"
)
.to_vec();
assert_eq!(encoded, expected);
}
#[test]
fn encode_string() {
let s = Token::String("gavofyork".to_owned());
let encoded = encode(&[s]);
assert_eq!(encoded, b"gavofyork");
}
#[test]
fn encode_two_bytes() {
let bytes1 = Token::Bytes(
hex!("10000000000000000000000000000000000000000000000000000000000002").to_vec(),
);
let bytes2 = Token::Bytes(
hex!("0010000000000000000000000000000000000000000000000000000000000002").to_vec(),
);
let encoded = encode(&[bytes1, bytes2]);
let expected = hex!(
"
10000000000000000000000000000000000000000000000000000000000002
0010000000000000000000000000000000000000000000000000000000000002
"
)
.to_vec();
assert_eq!(encoded, expected);
}
#[test]
fn encode_fixed_bytes() {
let bytes = Token::FixedBytes(vec![0x12, 0x34]);
let encoded = encode(&[bytes]);
let expected = hex!("1234");
assert_eq!(encoded, expected);
}
#[test]
fn encode_array_of_fixed_bytes() {
let array = Token::FixedArray(vec![
Token::FixedBytes(vec![0x12, 0x34]),
Token::FixedBytes(vec![0x56, 0x78]),
]);
let encoded = encode(&[array]);
let expected = hex!(
"
1234000000000000000000000000000000000000000000000000000000000000
5678000000000000000000000000000000000000000000000000000000000000
"
);
assert_eq!(encoded, expected);
}
#[test]
fn encode_uint() {
let mut uint = [0u8; 32];
uint[31] = 4;
let encoded = encode(&[Token::Uint(uint.into())]);
let expected = hex!("04");
assert_eq!(encoded, expected);
}
#[test]
fn encode_int() {
let mut int = [0u8; 32];
int[31] = 4;
let encoded = encode(&[Token::Int(int.into())]);
let expected = hex!("04");
assert_eq!(encoded, expected);
}
#[test]
fn encode_bool() {
let encoded = encode(&[Token::Bool(true)]);
let expected = hex!("01");
assert_eq!(encoded, expected);
}
#[test]
fn encode_bool2() {
let encoded = encode(&[Token::Bool(false)]);
let expected = hex!("00");
assert_eq!(encoded, expected);
}
#[test]
fn comprehensive_test() {
let bytes = hex!(
"
131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
"
)
.to_vec();
let encoded = encode(&[
Token::Int(5.into()),
Token::Bytes(bytes.clone()),
Token::Int(3.into()),
Token::Bytes(bytes),
]);
let expected = hex!(
"
05
131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
03
131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
131a3afc00d1b1e3461b955e53fc866dcf303b3eb9f4c16f89e388930f48134b
"
)
.to_vec();
assert_eq!(encoded, expected);
}
#[test]
fn comprehensive_test2() {
let encoded = encode(&vec![
Token::Int(1.into()),
Token::String("gavofyork".to_owned()),
Token::Int(2.into()),
Token::Int(3.into()),
Token::Int(4.into()),
Token::Array(vec![Token::Int(5.into()), Token::Int(6.into()), Token::Int(7.into())]),
]);
let expected = hex!(
"
01
6761766f66796f726b
02
03
04
0000000000000000000000000000000000000000000000000000000000000005
0000000000000000000000000000000000000000000000000000000000000006
0000000000000000000000000000000000000000000000000000000000000007
"
)
.to_vec();
assert_eq!(encoded, expected);
}
}